tetragon

Форк
0
/
fieldtype.go 
250 строк · 4.7 Кб
1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright Authors of Tetragon
3

4
package tracepoint
5

6
import (
7
	"fmt"
8
	"strconv"
9
	"strings"
10
)
11

12
type IntTyBase int
13

14
const (
15
	IntTyChar IntTyBase = iota
16
	IntTyShort
17
	IntTyInt
18
	IntTyLong
19
	IntTyLongLong
20
	IntTyInt8
21
	IntTyInt16
22
	IntTyInt32
23
	IntTyInt64
24
)
25

26
// integer type
27
type IntTy struct {
28
	Base     IntTyBase
29
	Unsigned bool
30
}
31

32
type BoolTy struct{}
33

34
// pid_t type
35
type PidTy struct{}
36

37
// pid_t type
38
type SizeTy struct{}
39

40
// void type
41
type VoidTy struct{}
42

43
// dma_addr_t
44
type DmaAddrTy struct{}
45

46
type PointerTy struct {
47
	Ty    interface{}
48
	Const bool
49
}
50

51
type ArrayTy struct {
52
	Ty   interface{}
53
	Size uint
54
}
55

56
type Field struct {
57
	Name string
58
	Type interface{}
59
}
60

61
type ParseError struct {
62
	r string
63
}
64

65
func (e *ParseError) Error() string {
66
	return fmt.Sprintf("failed to parse field: %s", e.r)
67
}
68

69
func parseTy(tyFields []string) (interface{}, error) {
70

71
	fidx := 0
72
	nfields := len(tyFields)
73
	isConst := false
74
	nextField := func() string {
75
		ret := tyFields[fidx]
76
		fidx++
77
		return ret
78
	}
79
	peekField := func() string {
80
		return tyFields[fidx]
81
	}
82
	lastField := func() bool {
83
		return fidx == nfields
84
	}
85

86
	if peekField() == "const" {
87
		isConst = true
88
		nextField()
89
	}
90

91
	ty := nextField()
92
	unsigned := false
93
	if ty == "unsigned" {
94
		// type just contains unsigned
95
		if lastField() {
96
			return IntTy{
97
				Base:     IntTyInt,
98
				Unsigned: true,
99
			}, nil
100
		}
101
		// unsigned is a qualifier
102
		unsigned = true
103
		ty = nextField()
104
	}
105

106
	var retTy interface{}
107
	switch {
108
	case ty == "char":
109
		retTy = IntTy{Base: IntTyChar, Unsigned: unsigned}
110
	case ty == "short":
111
		retTy = IntTy{Base: IntTyShort, Unsigned: unsigned}
112
	case ty == "int":
113
		retTy = IntTy{Base: IntTyInt, Unsigned: unsigned}
114
	case ty == "long":
115
		if !lastField() && peekField() == "long" {
116
			retTy = IntTy{Base: IntTyLongLong, Unsigned: unsigned}
117
			nextField()
118
		} else {
119
			retTy = IntTy{Base: IntTyLong, Unsigned: unsigned}
120
		}
121
	case unsigned:
122
		// we are doing something wrong if we hit this because we are ignoring the unsigned qualifier
123
		return nil, &ParseError{r: "unexpected unsigned"}
124
	case ty == "u8":
125
		retTy = IntTy{Base: IntTyInt8, Unsigned: true}
126
	case ty == "u16":
127
		retTy = IntTy{Base: IntTyInt16, Unsigned: true}
128
	case ty == "u32":
129
		retTy = IntTy{Base: IntTyInt32, Unsigned: true}
130
	case ty == "u64":
131
		retTy = IntTy{Base: IntTyInt64, Unsigned: true}
132
	case ty == "bool":
133
		retTy = BoolTy{}
134
	case ty == "pid_t":
135
		retTy = PidTy{}
136
	case ty == "size_t":
137
		retTy = SizeTy{}
138
	case ty == "void":
139
		retTy = VoidTy{}
140
	case ty == "dma_addr_t":
141
		retTy = DmaAddrTy{}
142
	default:
143
		return nil, &ParseError{r: fmt.Sprintf("unknown type:%s", ty)}
144
	}
145

146
	if lastField() {
147
		return retTy, nil
148
	}
149

150
	// Linux 5.16 started placing attributes in tracepoint format definitions
151
	// Let's just ignore them here for now
152
	if strings.HasPrefix(peekField(), "__attribute__") {
153
		nextField()
154
	}
155

156
	rest := nextField()
157
	if rest == "*" {
158
		retTy = PointerTy{Ty: retTy, Const: isConst}
159
	} else {
160
		return nil, &ParseError{r: "parsing failed"}
161
	}
162

163
	if !lastField() {
164
		return nil, &ParseError{r: "did not process all fields"}
165
	}
166
	return retTy, nil
167
}
168

169
func parseField(s string) (*Field, error) {
170

171
	fields := strings.Fields(s)
172
	nfields := len(fields)
173
	if nfields < 2 {
174
		return nil, &ParseError{r: "expecting at least two fields"}
175
	}
176

177
	tyFields := fields[0 : nfields-1]
178
	retTy, err := parseTy(tyFields)
179
	if err != nil {
180
		return nil, err
181
	}
182

183
	name := fields[nfields-1]
184
	if bOpen := strings.Index(name, "["); bOpen != -1 {
185
		var size uint64
186
		if !strings.HasSuffix(name, "]") {
187
			return nil, &ParseError{r: "could not parse array structure"}
188
		}
189
		substrings := strings.Split(name, "[")
190
		size_s := strings.TrimSuffix(substrings[1], "]")
191
		size, err = strconv.ParseUint(size_s, 10, 32)
192
		if err != nil {
193
			return nil, &ParseError{r: fmt.Sprintf("failed to parse size: %s", err)}
194
		}
195
		retTy = ArrayTy{
196
			Ty:   retTy,
197
			Size: uint(size),
198
		}
199
		name = substrings[0]
200
	}
201

202
	return &Field{
203
		Name: name,
204
		Type: retTy,
205
	}, nil
206
}
207

208
// NBytes retruns the number of bytes of an integer type
209
func (ty *IntTy) NBytes() (int, error) {
210
	var ret int
211
	switch ty.Base {
212
	case IntTyChar:
213
		ret = 1
214
	case IntTyShort:
215
		ret = 2
216
	case IntTyInt:
217
		ret = 4
218
	case IntTyLong:
219
		ret = 8
220
	case IntTyLongLong:
221
		ret = 8
222
	case IntTyInt8:
223
		ret = 1
224
	case IntTyInt16:
225
		ret = 2
226
	case IntTyInt32:
227
		ret = 4
228
	case IntTyInt64:
229
		ret = 8
230
	default:
231
		return ret, fmt.Errorf("unknown base: %d", ty.Base)
232
	}
233

234
	return ret, nil
235
}
236

237
// NBytes returns the number of bytes if an array type
238
// TODO: expand for types other than Int as needed
239
func (ty *ArrayTy) NBytes() (int, error) {
240
	switch x := ty.Ty.(type) {
241
	case IntTy:
242
		intBytes, err := x.NBytes()
243
		if err != nil {
244
			return 0, err
245
		}
246
		return intBytes * int(ty.Size), nil
247
	default:
248
		return 0, fmt.Errorf("NBytes: unknown type: %T", ty)
249
	}
250
}
251

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.