proc: refactor parseg

Instead of doing a bunch of manual DWARF / memory parsing we instead can
just dogfood the internal Variable API to retrieve the G struct.
This commit is contained in:
Derek Parker 2016-01-20 13:30:47 -08:00 committed by aarzilli
parent d9a31dd598
commit afe77160b0

@ -366,117 +366,54 @@ func (gvar *Variable) parseG() (*G, error) {
return nil, NoGError{tid: id} return nil, NoGError{tid: id}
} }
} }
if gaddr == 0 {
rdr := dbp.DwarfReader() return nil, NoGError{}
rdr.Seek(0)
entry, err := rdr.SeekToTypeNamed("runtime.g")
if err != nil {
return nil, err
} }
gvar.loadValue()
if gtype, err := dbp.dwarf.Type(entry.Offset); err == nil { if gvar.Unreadable != nil {
mem = cacheMemory(mem, uintptr(gaddr), int(gtype.Size())) return nil, gvar.Unreadable
} }
schedVar := gvar.toFieldNamed("sched")
// Parse defer pc, _ := constant.Int64Val(schedVar.toFieldNamed("pc").Value)
deferAddr, err := rdr.AddrForMember("_defer", initialInstructions) sp, _ := constant.Int64Val(schedVar.toFieldNamed("sp").Value)
if err != nil { id, _ := constant.Int64Val(gvar.toFieldNamed("goid").Value)
return nil, err gopc, _ := constant.Int64Val(gvar.toFieldNamed("gopc").Value)
waitReason := constant.StringVal(gvar.toFieldNamed("waitreason").Value)
d := gvar.toFieldNamed("_defer")
deferPC := int64(0)
fnvar := d.toFieldNamed("fn")
if fnvar != nil {
fnvalvar := fnvar.toFieldNamed("fn")
deferPC, _ = constant.Int64Val(fnvalvar.Value)
} }
var deferPC uint64 status, _ := constant.Int64Val(gvar.toFieldNamed("atomicstatus").Value)
// Dereference *defer pointer f, l, fn := gvar.dbp.goSymTable.PCToLine(uint64(pc))
deferAddrBytes, err := mem.readMemory(uintptr(deferAddr), dbp.arch.PtrSize())
if err != nil {
return nil, fmt.Errorf("error derefing defer %s", err)
}
if binary.LittleEndian.Uint64(deferAddrBytes) != 0 {
initialDeferInstructions := append([]byte{op.DW_OP_addr}, deferAddrBytes...)
_, err = rdr.SeekToTypeNamed("runtime._defer")
if err != nil {
return nil, err
}
deferPCAddr, err := rdr.AddrForMember("fn", initialDeferInstructions)
deferPC, err = readUintRaw(mem, uintptr(deferPCAddr), 8)
if err != nil {
return nil, err
}
deferPC, err = readUintRaw(mem, uintptr(deferPC), 8)
if err != nil {
return nil, err
}
}
// Let's parse all of the members we care about in order so that
// we don't have to spend any extra time seeking.
err = rdr.SeekToEntry(entry)
if err != nil {
return nil, err
}
// Parse sched
schedAddr, err := rdr.AddrForMember("sched", initialInstructions)
if err != nil {
return nil, err
}
// From sched, let's parse PC and SP.
sp, err := readUintRaw(mem, uintptr(schedAddr), 8)
if err != nil {
return nil, err
}
pc, err := readUintRaw(mem, uintptr(schedAddr+uint64(dbp.arch.PtrSize())), 8)
if err != nil {
return nil, err
}
// Parse atomicstatus
atomicStatusAddr, err := rdr.AddrForMember("atomicstatus", initialInstructions)
if err != nil {
return nil, err
}
atomicStatus, err := readUintRaw(mem, uintptr(atomicStatusAddr), 4)
// Parse goid
goidAddr, err := rdr.AddrForMember("goid", initialInstructions)
if err != nil {
return nil, err
}
goid, err := readIntRaw(mem, uintptr(goidAddr), 8)
if err != nil {
return nil, err
}
// Parse waitreason
waitReasonAddr, err := rdr.AddrForMember("waitreason", initialInstructions)
if err != nil {
return nil, err
}
waitreason, _, err := readString(mem, dbp.arch, uintptr(waitReasonAddr))
if err != nil {
return nil, err
}
// Parse gopc
gopcAddr, err := rdr.AddrForMember("gopc", initialInstructions)
if err != nil {
return nil, err
}
gopc, err := readUintRaw(mem, uintptr(gopcAddr), 8)
if err != nil {
return nil, err
}
f, l, fn := dbp.goSymTable.PCToLine(pc)
g := &G{ g := &G{
ID: int(goid), ID: int(id),
GoPC: gopc, GoPC: uint64(gopc),
PC: pc, PC: uint64(pc),
SP: sp, SP: uint64(sp),
CurrentLoc: Location{PC: pc, File: f, Line: l, Fn: fn}, WaitReason: waitReason,
WaitReason: waitreason, DeferPC: uint64(deferPC),
DeferPC: deferPC, Status: uint64(status),
Status: atomicStatus, CurrentLoc: Location{PC: uint64(pc), File: f, Line: l, Fn: fn},
dbp: dbp, dbp: gvar.dbp,
} }
return g, nil return g, nil
} }
func (v *Variable) toFieldNamed(name string) *Variable {
v, err := v.structMember(name)
if err != nil {
return nil
}
v.loadValue()
if v.Unreadable != nil {
return nil
}
return v
}
// From $GOROOT/src/runtime/traceback.go:597 // From $GOROOT/src/runtime/traceback.go:597
// isExportedRuntime reports whether name is an exported runtime function. // isExportedRuntime reports whether name is an exported runtime function.
// It is only for runtime functions, so ASCII A-Z is fine. // It is only for runtime functions, so ASCII A-Z is fine.