// map from global address to Field at that address func globalsMap(d *Dump, w *dwarf.Data, t map[dwarf.Offset]dwarfType) *heap { h := new(heap) r := w.Reader() for { e, err := r.Next() if err != nil { log.Fatal(err) } if e == nil { break } if e.Tag != dwarf.TagVariable { continue } name := e.Val(dwarf.AttrName).(string) typ := t[e.Val(dwarf.AttrType).(dwarf.Offset)] locexpr := e.Val(dwarf.AttrLocation).([]uint8) if len(locexpr) == 0 || locexpr[0] != dw_op_addr { continue } loc := readPtr(d, locexpr[1:]) if typ == nil { // lots of non-Go global symbols hit here (rodata, reflect.cvtFloat·f, ...) h.Insert(loc, Field{FieldKindPtr, 0, "~" + name, ""}) continue } for _, f := range typ.Fields() { h.Insert(loc+f.Offset, Field{f.Kind, 0, joinNames(name, f.Name), f.BaseType}) } } return h }
//============================================================================ // main : Entry point. //---------------------------------------------------------------------------- func main() { var dwarfData *dwarf.Data var theFile *macho.File var theErr os.Error var relativeAddress uint64 var runtimeAddress uint64 var loadAddress uint64 var segmentAddress uint64 var pathMacho string var pathDsym string // Parse our arguments flag.Uint64Var(&runtimeAddress, "raddr", 0, "") flag.Uint64Var(&loadAddress, "laddr", 0, "") flag.StringVar(&pathMacho, "macho", "", "") flag.StringVar(&pathDsym, "dsym", "", "") flag.Parse() if runtimeAddress == 0 || loadAddress == 0 || pathMacho == "" || pathDsym == "" { printHelp() } // Find the text segment address theFile, theErr = macho.Open(pathMacho) if theErr != nil { fatalError("Can't open Mach-O file: " + theErr.String()) } segmentAddress = theFile.Segment("__TEXT").Addr theFile.Close() // Calculate the target address relativeAddress = runtimeAddress - loadAddress gTargetAddress = segmentAddress + relativeAddress // Find the target theFile, theErr = macho.Open(pathDsym) if theErr != nil { fatalError("Can't open .dsym file: " + theErr.String()) } dwarfData, theErr = theFile.DWARF() if theErr != nil { fatalError("Can't find DWARF info: " + theErr.String()) } processChildren(dwarfData.Reader(), 0, false) theFile.Close() }
func findVariable(d *dwarf.Data, name string) (*variable, error) { dr := d.Reader() for { e, err := dr.Next() if e == nil || err != nil { return nil, err } if e.Tag != dwarf.TagVariable { continue } aname, ok := e.Val(dwarf.AttrName).(string) if !ok || aname != name { continue } loc, ok := e.Val(dwarf.AttrLocation).([]uint8) if !ok { continue } if loc[0] != 3 { return nil, fmt.Errorf("can't determine variable addr") } addr := uint64(0) switch len(loc) { case 5: addr = uint64(binary.LittleEndian.Uint32(loc[1:])) case 9: addr = uint64(binary.LittleEndian.Uint64(loc[1:])) default: return nil, fmt.Errorf("unknown addr size") } off, ok := e.Val(dwarf.AttrType).(dwarf.Offset) if !ok { continue } typ, err := d.Type(off) if err != nil { return nil, err } return &variable{Addr: addr, Type: typ}, nil } return nil, nil }
// Makes a map from <function name, offset in arg area> to name of field. func argsMap(d *Dump, w *dwarf.Data, t map[dwarf.Offset]dwarfType) map[localKey]string { m := make(map[localKey]string, 0) r := w.Reader() var funcname string for { e, err := r.Next() if err != nil { log.Fatal(err) } if e == nil { break } switch e.Tag { case dwarf.TagSubprogram: funcname = e.Val(dwarf.AttrName).(string) case dwarf.TagFormalParameter: if e.Val(dwarf.AttrName) == nil { continue } name := e.Val(dwarf.AttrName).(string) typ := t[e.Val(dwarf.AttrType).(dwarf.Offset)] loc := e.Val(dwarf.AttrLocation).([]uint8) if len(loc) == 0 || loc[0] != dw_op_call_frame_cfa { break } var offset int64 if len(loc) == 1 { offset = 0 } else if len(loc) >= 3 && loc[1] == dw_op_consts && loc[len(loc)-1] == dw_op_plus { loc, offset = readSleb(loc[2 : len(loc)-1]) if len(loc) != 0 { break } } for _, f := range typ.Fields() { m[localKey{funcname, uint64(offset)}] = joinNames(name, f.Name) } } } return m }
// New returns a reader for the specified dwarf data. func New(data *dwarf.Data) *Reader { return &Reader{data.Reader(), 0} }
// load a map of all of the dwarf types func typeMap(d *Dump, w *dwarf.Data) map[dwarf.Offset]dwarfType { t := make(map[dwarf.Offset]dwarfType) // pass 1: make a dwarfType for all of the types in the file r := w.Reader() for { e, err := r.Next() if err != nil { log.Fatal(err) } if e == nil { break } if e.Val(dwarf.AttrName) == nil { // Dwarf info from non-go sources might be missing a name continue } switch e.Tag { case dwarf.TagBaseType: x := new(dwarfBaseType) x.name = e.Val(dwarf.AttrName).(string) x.size = uint64(e.Val(dwarf.AttrByteSize).(int64)) x.encoding = e.Val(dwarf.AttrEncoding).(int64) t[e.Offset] = x case dwarf.TagPointerType: x := new(dwarfPtrType) x.name = e.Val(dwarf.AttrName).(string) x.size = d.PtrSize t[e.Offset] = x case dwarf.TagStructType: x := new(dwarfStructType) x.name = e.Val(dwarf.AttrName).(string) x.size = uint64(e.Val(dwarf.AttrByteSize).(int64)) for _, a := range adjTypeNames { if k := a.matcher.FindStringSubmatch(x.name); k != nil { var i []interface{} for _, j := range k[1:] { i = append(i, j) } x.name = fmt.Sprintf(a.formatter, i...) } } t[e.Offset] = x case dwarf.TagArrayType: x := new(dwarfArrayType) x.name = e.Val(dwarf.AttrName).(string) x.size = uint64(e.Val(dwarf.AttrByteSize).(int64)) t[e.Offset] = x case dwarf.TagTypedef: x := new(dwarfTypedef) x.name = e.Val(dwarf.AttrName).(string) t[e.Offset] = x case dwarf.TagSubroutineType: x := new(dwarfFuncType) x.name = e.Val(dwarf.AttrName).(string) x.size = d.PtrSize t[e.Offset] = x } } // pass 2: fill in / link up the types r = w.Reader() var currentStruct *dwarfStructType for { e, err := r.Next() if err != nil { log.Fatal(err) } if e == nil { break } switch e.Tag { case dwarf.TagTypedef: t[e.Offset].(*dwarfTypedef).type_ = t[e.Val(dwarf.AttrType).(dwarf.Offset)] if t[e.Offset].(*dwarfTypedef).type_ == nil { log.Fatalf("can't find referent for %s %d\n", t[e.Offset].(*dwarfTypedef).name, e.Val(dwarf.AttrType).(dwarf.Offset)) } case dwarf.TagPointerType: i := e.Val(dwarf.AttrType) if i != nil { t[e.Offset].(*dwarfPtrType).elem = t[i.(dwarf.Offset)] } // The only nil cases are unsafe.Pointer and reflect.iword case dwarf.TagArrayType: t[e.Offset].(*dwarfArrayType).elem = t[e.Val(dwarf.AttrType).(dwarf.Offset)] case dwarf.TagStructType: currentStruct = t[e.Offset].(*dwarfStructType) case dwarf.TagMember: name := e.Val(dwarf.AttrName).(string) type_ := t[e.Val(dwarf.AttrType).(dwarf.Offset)] loc := e.Val(dwarf.AttrDataMemberLoc).([]uint8) var offset uint64 if len(loc) == 0 { offset = 0 } else if len(loc) >= 2 && loc[0] == dw_op_consts && loc[len(loc)-1] == dw_op_plus { loc, offset = readUleb(loc[1 : len(loc)-1]) if len(loc) != 0 { break } } currentStruct.members = append(currentStruct.members, dwarfTypeMember{name, offset, type_}) } } return t }