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  }