github.com/zeebo/goof@v0.0.0-20230907150950-e9457bc94477/troop_types.go (about) 1 package goof 2 3 import ( 4 "debug/dwarf" 5 "fmt" 6 "reflect" 7 "sort" 8 "strings" 9 "unsafe" 10 11 "github.com/zeebo/errs" 12 ) 13 14 //go:linkname typelinks reflect.typelinks 15 func typelinks() (sections []unsafe.Pointer, offset [][]int32) 16 17 func (t *Troop) addTypes() error { 18 sections, offset := typelinks() 19 for i, offs := range offset { 20 section := sections[i] 21 for _, off := range offs { 22 ptr := unsafe.Pointer(uintptr(section) + uintptr(off)) 23 typ := reflect.TypeOf(makeInterface(ptr, nil)) 24 t.addType(typ) 25 } 26 } 27 28 // special cased types 29 t.types["*void"] = unsafePointerType 30 t.types["**void"] = reflect.PtrTo(unsafePointerType) 31 32 return nil 33 } 34 35 func (t *Troop) addType(typ reflect.Type) { 36 name := dwarfName(typ) 37 if _, ok := t.types[name]; ok { 38 return 39 } 40 t.types[name] = typ 41 42 defer func() { 43 if r := recover(); r != nil { 44 t.failures[name] = fmt.Errorf("failed to add type %q (%v): %v", name, typ, r) 45 } 46 }() 47 48 switch typ.Kind() { 49 case reflect.Ptr, reflect.Chan, reflect.Slice, reflect.Array: 50 t.addType(typ.Elem()) 51 52 case reflect.Map: 53 t.addType(typ.Key()) 54 t.addType(typ.Elem()) 55 56 case reflect.Func: 57 for i := 0; i < typ.NumIn(); i++ { 58 t.addType(typ.In(i)) 59 } 60 for i := 0; i < typ.NumOut(); i++ { 61 t.addType(typ.Out(i)) 62 } 63 64 case reflect.Struct: 65 for i := 0; i < typ.NumField(); i++ { 66 t.addType(typ.Field(i).Type) 67 } 68 for i := 0; i < typ.NumMethod(); i++ { 69 t.addType(typ.Method(i).Type) 70 } 71 72 case reflect.Interface: 73 for i := 0; i < typ.NumMethod(); i++ { 74 t.addType(typ.Method(i).Type) 75 } 76 } 77 } 78 79 func (t *Troop) Types() ([]reflect.Type, error) { 80 if err := t.check(); err != nil { 81 return nil, err 82 } 83 out := make([]reflect.Type, 0, len(t.types)) 84 for _, typ := range t.types { 85 out = append(out, typ) 86 } 87 sort.Sort(typesByString(out)) 88 return out, nil 89 } 90 91 func (t *Troop) Type(name string) (reflect.Type, error) { 92 if err := t.check(); err != nil { 93 return nil, err 94 } 95 96 entry, ok := t.types[name] 97 if !ok { 98 return nil, errs.New("type %s: unknown type", name) 99 } 100 101 return entry, nil 102 } 103 104 func (t *Troop) findDwarfTypes(dtypes []dwarf.Type) ([]reflect.Type, error) { 105 out_types := make([]reflect.Type, 0, len(dtypes)) 106 for _, dtyp := range dtypes { 107 typ, err := t.findDwarfType(dtyp) 108 if err != nil { 109 return nil, err 110 } 111 out_types = append(out_types, typ) 112 } 113 return out_types, nil 114 } 115 116 func (t *Troop) findDwarfType(dtyp dwarf.Type) (reflect.Type, error) { 117 // TODO(jeff): we can synthesize some of these dwarf types at runtime, 118 // but hopefully we got enough of them when we loaded up all of the 119 // types. The problematic types are: 1. named types, 2. recursive types. 120 var dname string 121 switch dtyp := dtyp.(type) { 122 case *dwarf.StructType: 123 if dtyp.StructName != "" { 124 dname = dtyp.StructName 125 } else { 126 dname = dtyp.Defn() 127 } 128 default: 129 dname = dtyp.String() 130 } 131 132 // heh this is super hacky, but what isn't!? 133 if strings.HasPrefix(dname, "*struct ") && 134 !strings.HasPrefix(dname, "*struct {") { 135 136 dname = "*" + dname[len("*struct "):] 137 } 138 139 typ, ok := t.types[dname] 140 if !ok { 141 return nil, errs.New("dwarf type %q unknown", dname) 142 } 143 return typ, nil 144 }