tetragon
250 строк · 4.7 Кб
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Authors of Tetragon
3
4package tracepoint5
6import (7"fmt"8"strconv"9"strings"10)
11
12type IntTyBase int13
14const (15IntTyChar IntTyBase = iota16IntTyShort
17IntTyInt
18IntTyLong
19IntTyLongLong
20IntTyInt8
21IntTyInt16
22IntTyInt32
23IntTyInt64
24)
25
26// integer type
27type IntTy struct {28Base IntTyBase
29Unsigned bool30}
31
32type BoolTy struct{}33
34// pid_t type
35type PidTy struct{}36
37// pid_t type
38type SizeTy struct{}39
40// void type
41type VoidTy struct{}42
43// dma_addr_t
44type DmaAddrTy struct{}45
46type PointerTy struct {47Ty interface{}48Const bool49}
50
51type ArrayTy struct {52Ty interface{}53Size uint54}
55
56type Field struct {57Name string58Type interface{}59}
60
61type ParseError struct {62r string63}
64
65func (e *ParseError) Error() string {66return fmt.Sprintf("failed to parse field: %s", e.r)67}
68
69func parseTy(tyFields []string) (interface{}, error) {70
71fidx := 072nfields := len(tyFields)73isConst := false74nextField := func() string {75ret := tyFields[fidx]76fidx++77return ret78}79peekField := func() string {80return tyFields[fidx]81}82lastField := func() bool {83return fidx == nfields84}85
86if peekField() == "const" {87isConst = true88nextField()89}90
91ty := nextField()92unsigned := false93if ty == "unsigned" {94// type just contains unsigned95if lastField() {96return IntTy{97Base: IntTyInt,98Unsigned: true,99}, nil100}101// unsigned is a qualifier102unsigned = true103ty = nextField()104}105
106var retTy interface{}107switch {108case ty == "char":109retTy = IntTy{Base: IntTyChar, Unsigned: unsigned}110case ty == "short":111retTy = IntTy{Base: IntTyShort, Unsigned: unsigned}112case ty == "int":113retTy = IntTy{Base: IntTyInt, Unsigned: unsigned}114case ty == "long":115if !lastField() && peekField() == "long" {116retTy = IntTy{Base: IntTyLongLong, Unsigned: unsigned}117nextField()118} else {119retTy = IntTy{Base: IntTyLong, Unsigned: unsigned}120}121case unsigned:122// we are doing something wrong if we hit this because we are ignoring the unsigned qualifier123return nil, &ParseError{r: "unexpected unsigned"}124case ty == "u8":125retTy = IntTy{Base: IntTyInt8, Unsigned: true}126case ty == "u16":127retTy = IntTy{Base: IntTyInt16, Unsigned: true}128case ty == "u32":129retTy = IntTy{Base: IntTyInt32, Unsigned: true}130case ty == "u64":131retTy = IntTy{Base: IntTyInt64, Unsigned: true}132case ty == "bool":133retTy = BoolTy{}134case ty == "pid_t":135retTy = PidTy{}136case ty == "size_t":137retTy = SizeTy{}138case ty == "void":139retTy = VoidTy{}140case ty == "dma_addr_t":141retTy = DmaAddrTy{}142default:143return nil, &ParseError{r: fmt.Sprintf("unknown type:%s", ty)}144}145
146if lastField() {147return retTy, nil148}149
150// Linux 5.16 started placing attributes in tracepoint format definitions151// Let's just ignore them here for now152if strings.HasPrefix(peekField(), "__attribute__") {153nextField()154}155
156rest := nextField()157if rest == "*" {158retTy = PointerTy{Ty: retTy, Const: isConst}159} else {160return nil, &ParseError{r: "parsing failed"}161}162
163if !lastField() {164return nil, &ParseError{r: "did not process all fields"}165}166return retTy, nil167}
168
169func parseField(s string) (*Field, error) {170
171fields := strings.Fields(s)172nfields := len(fields)173if nfields < 2 {174return nil, &ParseError{r: "expecting at least two fields"}175}176
177tyFields := fields[0 : nfields-1]178retTy, err := parseTy(tyFields)179if err != nil {180return nil, err181}182
183name := fields[nfields-1]184if bOpen := strings.Index(name, "["); bOpen != -1 {185var size uint64186if !strings.HasSuffix(name, "]") {187return nil, &ParseError{r: "could not parse array structure"}188}189substrings := strings.Split(name, "[")190size_s := strings.TrimSuffix(substrings[1], "]")191size, err = strconv.ParseUint(size_s, 10, 32)192if err != nil {193return nil, &ParseError{r: fmt.Sprintf("failed to parse size: %s", err)}194}195retTy = ArrayTy{196Ty: retTy,197Size: uint(size),198}199name = substrings[0]200}201
202return &Field{203Name: name,204Type: retTy,205}, nil206}
207
208// NBytes retruns the number of bytes of an integer type
209func (ty *IntTy) NBytes() (int, error) {210var ret int211switch ty.Base {212case IntTyChar:213ret = 1214case IntTyShort:215ret = 2216case IntTyInt:217ret = 4218case IntTyLong:219ret = 8220case IntTyLongLong:221ret = 8222case IntTyInt8:223ret = 1224case IntTyInt16:225ret = 2226case IntTyInt32:227ret = 4228case IntTyInt64:229ret = 8230default:231return ret, fmt.Errorf("unknown base: %d", ty.Base)232}233
234return ret, nil235}
236
237// NBytes returns the number of bytes if an array type
238// TODO: expand for types other than Int as needed
239func (ty *ArrayTy) NBytes() (int, error) {240switch x := ty.Ty.(type) {241case IntTy:242intBytes, err := x.NBytes()243if err != nil {244return 0, err245}246return intBytes * int(ty.Size), nil247default:248return 0, fmt.Errorf("NBytes: unknown type: %T", ty)249}250}
251