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