github.com/zeebo/goof@v0.0.0-20230907150950-e9457bc94477/dwarf_helpers.go (about)

     1  package goof
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"encoding/binary"
     6  	"unsafe"
     7  
     8  	"github.com/zeebo/errs"
     9  )
    10  
    11  func dwarfTypeName(dtyp dwarf.Type) string {
    12  	// for some reason the debug/dwarf package doesn't set the Name field
    13  	// on the common type for struct fields. what is this misery?
    14  	switch dtyp := dtyp.(type) {
    15  	case *dwarf.StructType:
    16  		return dtyp.StructName
    17  	default:
    18  		return dtyp.Common().Name
    19  	}
    20  }
    21  
    22  func getFunctionArgTypes(data *dwarf.Data, entry *dwarf.Entry) (
    23  	[]dwarf.Type, error) {
    24  
    25  	reader := data.Reader()
    26  
    27  	reader.Seek(entry.Offset)
    28  	_, err := reader.Next()
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	var args []dwarf.Type
    34  	for {
    35  		child, err := reader.Next()
    36  		if err != nil {
    37  			return nil, err
    38  		}
    39  		if child == nil || child.Tag == 0 {
    40  			break
    41  		}
    42  
    43  		if child.Tag != dwarf.TagFormalParameter {
    44  			continue
    45  		}
    46  
    47  		dtyp, err := entryType(data, child)
    48  		if err != nil {
    49  			return nil, err
    50  		}
    51  
    52  		args = append(args, dtyp)
    53  	}
    54  
    55  	return args, nil
    56  }
    57  
    58  func entryType(data *dwarf.Data, entry *dwarf.Entry) (dwarf.Type, error) {
    59  	off, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
    60  	if !ok {
    61  		return nil, errs.New("unable to find type offset for entry")
    62  	}
    63  	return data.Type(off)
    64  }
    65  
    66  func entryLocation(data *dwarf.Data, entry *dwarf.Entry) (uint64, error) {
    67  	loc, ok := entry.Val(dwarf.AttrLocation).([]byte)
    68  	if !ok {
    69  		return 0, errs.New("unable to find location for entry")
    70  	}
    71  	if len(loc) == 0 {
    72  		return 0, errs.New("location had no data")
    73  	}
    74  
    75  	// only support this opcode. did you know dwarf location information is
    76  	// a stack based programming language with opcodes and stuff? i wonder
    77  	// how many interpreters for that have code execution bugs in them.
    78  	if loc[0] != 0x03 {
    79  		return 0, errs.New("can't interpret location information")
    80  	}
    81  
    82  	// oh man let's also just assume that the dwarf info is written in the
    83  	// same order as the host! WHAT COULD GO WRONG?!
    84  	switch len(loc) - 1 {
    85  	case 4:
    86  		return uint64(hostOrder.Uint32(loc[1:])), nil
    87  	case 8:
    88  		return uint64(hostOrder.Uint64(loc[1:])), nil
    89  	default:
    90  		return 0, errs.New("what kind of computer is this?")
    91  	}
    92  }
    93  
    94  var hostOrder binary.ByteOrder
    95  
    96  func init() {
    97  	i := 1
    98  	data := (*[4]byte)(unsafe.Pointer(&i))
    99  
   100  	if data[0] == 0 {
   101  		hostOrder = binary.BigEndian
   102  	} else {
   103  		hostOrder = binary.LittleEndian
   104  	}
   105  }