...

Source file src/github.com/cilium/ebpf/btf/strings.go

Documentation: github.com/cilium/ebpf/btf

     1  package btf
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  )
    10  
    11  type stringTable struct {
    12  	base    *stringTable
    13  	offsets []uint32
    14  	strings []string
    15  }
    16  
    17  // sizedReader is implemented by bytes.Reader, io.SectionReader, strings.Reader, etc.
    18  type sizedReader interface {
    19  	io.Reader
    20  	Size() int64
    21  }
    22  
    23  func readStringTable(r sizedReader, base *stringTable) (*stringTable, error) {
    24  	// When parsing split BTF's string table, the first entry offset is derived
    25  	// from the last entry offset of the base BTF.
    26  	firstStringOffset := uint32(0)
    27  	if base != nil {
    28  		idx := len(base.offsets) - 1
    29  		firstStringOffset = base.offsets[idx] + uint32(len(base.strings[idx])) + 1
    30  	}
    31  
    32  	// Derived from vmlinux BTF.
    33  	const averageStringLength = 16
    34  
    35  	n := int(r.Size() / averageStringLength)
    36  	offsets := make([]uint32, 0, n)
    37  	strings := make([]string, 0, n)
    38  
    39  	offset := firstStringOffset
    40  	scanner := bufio.NewScanner(r)
    41  	scanner.Split(splitNull)
    42  	for scanner.Scan() {
    43  		str := scanner.Text()
    44  		offsets = append(offsets, offset)
    45  		strings = append(strings, str)
    46  		offset += uint32(len(str)) + 1
    47  	}
    48  	if err := scanner.Err(); err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	if len(strings) == 0 {
    53  		return nil, errors.New("string table is empty")
    54  	}
    55  
    56  	if firstStringOffset == 0 && strings[0] != "" {
    57  		return nil, errors.New("first item in string table is non-empty")
    58  	}
    59  
    60  	return &stringTable{base, offsets, strings}, nil
    61  }
    62  
    63  func splitNull(data []byte, atEOF bool) (advance int, token []byte, err error) {
    64  	i := bytes.IndexByte(data, 0)
    65  	if i == -1 {
    66  		if atEOF && len(data) > 0 {
    67  			return 0, nil, errors.New("string table isn't null terminated")
    68  		}
    69  		return 0, nil, nil
    70  	}
    71  
    72  	return i + 1, data[:i], nil
    73  }
    74  
    75  func (st *stringTable) Lookup(offset uint32) (string, error) {
    76  	if st.base != nil && offset <= st.base.offsets[len(st.base.offsets)-1] {
    77  		return st.base.lookup(offset)
    78  	}
    79  	return st.lookup(offset)
    80  }
    81  
    82  func (st *stringTable) lookup(offset uint32) (string, error) {
    83  	i := search(st.offsets, offset)
    84  	if i == len(st.offsets) || st.offsets[i] != offset {
    85  		return "", fmt.Errorf("offset %d isn't start of a string", offset)
    86  	}
    87  
    88  	return st.strings[i], nil
    89  }
    90  
    91  func (st *stringTable) Length() int {
    92  	last := len(st.offsets) - 1
    93  	return int(st.offsets[last]) + len(st.strings[last]) + 1
    94  }
    95  
    96  func (st *stringTable) Marshal(w io.Writer) error {
    97  	for _, str := range st.strings {
    98  		_, err := io.WriteString(w, str)
    99  		if err != nil {
   100  			return err
   101  		}
   102  		_, err = w.Write([]byte{0})
   103  		if err != nil {
   104  			return err
   105  		}
   106  	}
   107  	return nil
   108  }
   109  
   110  // search is a copy of sort.Search specialised for uint32.
   111  //
   112  // Licensed under https://go.dev/LICENSE
   113  func search(ints []uint32, needle uint32) int {
   114  	// Define f(-1) == false and f(n) == true.
   115  	// Invariant: f(i-1) == false, f(j) == true.
   116  	i, j := 0, len(ints)
   117  	for i < j {
   118  		h := int(uint(i+j) >> 1) // avoid overflow when computing h
   119  		// i ≤ h < j
   120  		if !(ints[h] >= needle) {
   121  			i = h + 1 // preserves f(i-1) == false
   122  		} else {
   123  			j = h // preserves f(j) == true
   124  		}
   125  	}
   126  	// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
   127  	return i
   128  }
   129  

View as plain text