format.go (6904B)
1 package btf 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 ) 8 9 var errNestedTooDeep = errors.New("nested too deep") 10 11 // GoFormatter converts a Type to Go syntax. 12 // 13 // A zero GoFormatter is valid to use. 14 type GoFormatter struct { 15 w strings.Builder 16 17 // Types present in this map are referred to using the given name if they 18 // are encountered when outputting another type. 19 Names map[Type]string 20 21 // Identifier is called for each field of struct-like types. By default the 22 // field name is used as is. 23 Identifier func(string) string 24 25 // EnumIdentifier is called for each element of an enum. By default the 26 // name of the enum type is concatenated with Identifier(element). 27 EnumIdentifier func(name, element string) string 28 } 29 30 // TypeDeclaration generates a Go type declaration for a BTF type. 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 // writeTypeDecl outputs a declaration of the given type. 56 // 57 // It encodes https://golang.org/ref/spec#Type_declarations: 58 // 59 // type foo struct { bar uint32; } 60 // type bar int32 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 // writeType outputs the name of a named type or a literal describing the type. 102 // 103 // It encodes https://golang.org/ref/spec#Types. 104 // 105 // foo (if foo is a named type) 106 // uint32 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 // writeTypeLit outputs a literal describing the type. 120 // 121 // The function ignores named types. 122 // 123 // It encodes https://golang.org/ref/spec#TypeLit. 124 // 125 // struct { bar uint32; } 126 // uint32 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 // Always choose the first member to represent the union in Go. 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 // NB: Encoding.IsChar is ignored. 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 // Special case a nested anonymous union like 228 // struct foo { union { int bar; int baz }; } 229 // by replacing the whole union with its first member. 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 // Ignore static, extern, etc. for now. 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 }