1 package btf
2
3 import (
4 "errors"
5 "fmt"
6 "strings"
7 )
8
9 var errNestedTooDeep = errors.New("nested too deep")
10
11
12
13
14 type GoFormatter struct {
15 w strings.Builder
16
17
18
19 Names map[Type]string
20
21
22
23 Identifier func(string) string
24
25
26
27 EnumIdentifier func(name, element string) string
28 }
29
30
31 func (gf *GoFormatter) TypeDeclaration(name string, typ Type) (string, error) {
32 gf.w.Reset()
33 if err := gf.writeTypeDecl(name, typ); err != nil {
34 return "", err
35 }
36 return gf.w.String(), nil
37 }
38
39 func (gf *GoFormatter) identifier(s string) string {
40 if gf.Identifier != nil {
41 return gf.Identifier(s)
42 }
43
44 return s
45 }
46
47 func (gf *GoFormatter) enumIdentifier(name, element string) string {
48 if gf.EnumIdentifier != nil {
49 return gf.EnumIdentifier(name, element)
50 }
51
52 return name + gf.identifier(element)
53 }
54
55
56
57
58
59
60
61 func (gf *GoFormatter) writeTypeDecl(name string, typ Type) error {
62 if name == "" {
63 return fmt.Errorf("need a name for type %s", typ)
64 }
65
66 switch v := skipQualifiers(typ).(type) {
67 case *Enum:
68 fmt.Fprintf(&gf.w, "type %s ", name)
69 switch v.Size {
70 case 1:
71 gf.w.WriteString("int8")
72 case 2:
73 gf.w.WriteString("int16")
74 case 4:
75 gf.w.WriteString("int32")
76 case 8:
77 gf.w.WriteString("int64")
78 default:
79 return fmt.Errorf("%s: invalid enum size %d", typ, v.Size)
80 }
81
82 if len(v.Values) == 0 {
83 return nil
84 }
85
86 gf.w.WriteString("; const ( ")
87 for _, ev := range v.Values {
88 id := gf.enumIdentifier(name, ev.Name)
89 fmt.Fprintf(&gf.w, "%s %s = %d; ", id, name, ev.Value)
90 }
91 gf.w.WriteString(")")
92
93 return nil
94
95 default:
96 fmt.Fprintf(&gf.w, "type %s ", name)
97 return gf.writeTypeLit(v, 0)
98 }
99 }
100
101
102
103
104
105
106
107 func (gf *GoFormatter) writeType(typ Type, depth int) error {
108 typ = skipQualifiers(typ)
109
110 name := gf.Names[typ]
111 if name != "" {
112 gf.w.WriteString(name)
113 return nil
114 }
115
116 return gf.writeTypeLit(typ, depth)
117 }
118
119
120
121
122
123
124
125
126
127 func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
128 depth++
129 if depth > maxTypeDepth {
130 return errNestedTooDeep
131 }
132
133 var err error
134 switch v := skipQualifiers(typ).(type) {
135 case *Int:
136 gf.writeIntLit(v)
137
138 case *Enum:
139 gf.w.WriteString("int32")
140
141 case *Typedef:
142 err = gf.writeType(v.Type, depth)
143
144 case *Array:
145 fmt.Fprintf(&gf.w, "[%d]", v.Nelems)
146 err = gf.writeType(v.Type, depth)
147
148 case *Struct:
149 err = gf.writeStructLit(v.Size, v.Members, depth)
150
151 case *Union:
152
153 err = gf.writeStructLit(v.Size, v.Members[:1], depth)
154
155 case *Datasec:
156 err = gf.writeDatasecLit(v, depth)
157
158 default:
159 return fmt.Errorf("type %T: %w", v, ErrNotSupported)
160 }
161
162 if err != nil {
163 return fmt.Errorf("%s: %w", typ, err)
164 }
165
166 return nil
167 }
168
169 func (gf *GoFormatter) writeIntLit(i *Int) {
170
171 if i.Encoding.IsBool() && i.Size == 1 {
172 gf.w.WriteString("bool")
173 return
174 }
175
176 bits := i.Size * 8
177 if i.Encoding.IsSigned() {
178 fmt.Fprintf(&gf.w, "int%d", bits)
179 } else {
180 fmt.Fprintf(&gf.w, "uint%d", bits)
181 }
182 }
183
184 func (gf *GoFormatter) writeStructLit(size uint32, members []Member, depth int) error {
185 gf.w.WriteString("struct { ")
186
187 prevOffset := uint32(0)
188 skippedBitfield := false
189 for i, m := range members {
190 if m.BitfieldSize > 0 {
191 skippedBitfield = true
192 continue
193 }
194
195 offset := m.Offset.Bytes()
196 if n := offset - prevOffset; skippedBitfield && n > 0 {
197 fmt.Fprintf(&gf.w, "_ [%d]byte /* unsupported bitfield */; ", n)
198 } else {
199 gf.writePadding(n)
200 }
201
202 size, err := Sizeof(m.Type)
203 if err != nil {
204 return fmt.Errorf("field %d: %w", i, err)
205 }
206 prevOffset = offset + uint32(size)
207
208 if err := gf.writeStructField(m, depth); err != nil {
209 return fmt.Errorf("field %d: %w", i, err)
210 }
211 }
212
213 gf.writePadding(size - prevOffset)
214 gf.w.WriteString("}")
215 return nil
216 }
217
218 func (gf *GoFormatter) writeStructField(m Member, depth int) error {
219 if m.BitfieldSize > 0 {
220 return fmt.Errorf("bitfields are not supported")
221 }
222 if m.Offset%8 != 0 {
223 return fmt.Errorf("unsupported offset %d", m.Offset)
224 }
225
226 if m.Name == "" {
227
228
229
230 union, ok := m.Type.(*Union)
231 if !ok {
232 return fmt.Errorf("anonymous fields are not supported")
233
234 }
235
236 if len(union.Members) == 0 {
237 return errors.New("empty anonymous union")
238 }
239
240 depth++
241 if depth > maxTypeDepth {
242 return errNestedTooDeep
243 }
244
245 m := union.Members[0]
246 size, err := Sizeof(m.Type)
247 if err != nil {
248 return err
249 }
250
251 if err := gf.writeStructField(m, depth); err != nil {
252 return err
253 }
254
255 gf.writePadding(union.Size - uint32(size))
256 return nil
257
258 }
259
260 fmt.Fprintf(&gf.w, "%s ", gf.identifier(m.Name))
261
262 if err := gf.writeType(m.Type, depth); err != nil {
263 return err
264 }
265
266 gf.w.WriteString("; ")
267 return nil
268 }
269
270 func (gf *GoFormatter) writeDatasecLit(ds *Datasec, depth int) error {
271 gf.w.WriteString("struct { ")
272
273 prevOffset := uint32(0)
274 for i, vsi := range ds.Vars {
275 v := vsi.Type.(*Var)
276 if v.Linkage != GlobalVar {
277
278 continue
279 }
280
281 if v.Name == "" {
282 return fmt.Errorf("variable %d: empty name", i)
283 }
284
285 gf.writePadding(vsi.Offset - prevOffset)
286 prevOffset = vsi.Offset + vsi.Size
287
288 fmt.Fprintf(&gf.w, "%s ", gf.identifier(v.Name))
289
290 if err := gf.writeType(v.Type, depth); err != nil {
291 return fmt.Errorf("variable %d: %w", i, err)
292 }
293
294 gf.w.WriteString("; ")
295 }
296
297 gf.writePadding(ds.Size - prevOffset)
298 gf.w.WriteString("}")
299 return nil
300 }
301
302 func (gf *GoFormatter) writePadding(bytes uint32) {
303 if bytes > 0 {
304 fmt.Fprintf(&gf.w, "_ [%d]byte; ", bytes)
305 }
306 }
307
308 func skipQualifiers(typ Type) Type {
309 result := typ
310 for depth := 0; depth <= maxTypeDepth; depth++ {
311 switch v := (result).(type) {
312 case qualifier:
313 result = v.qualify()
314 default:
315 return result
316 }
317 }
318 return &cycle{typ}
319 }
320
View as plain text