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}
}
}
rdr := dbp.DwarfReader()
rdr.Seek(0)
entry, err := rdr.SeekToTypeNamed("runtime.g")
if err != nil {
return nil, err
if gaddr == 0 {
return nil, NoGError{}
}
if gtype, err := dbp.dwarf.Type(entry.Offset); err == nil {
mem = cacheMemory(mem, uintptr(gaddr), int(gtype.Size()))
gvar.loadValue()
if gvar.Unreadable != nil {
return nil, gvar.Unreadable
}
// Parse defer
deferAddr, err := rdr.AddrForMember("_defer", initialInstructions)
if err != nil {
return nil, err
schedVar := gvar.toFieldNamed("sched")
pc, _ := constant.Int64Val(schedVar.toFieldNamed("pc").Value)
sp, _ := constant.Int64Val(schedVar.toFieldNamed("sp").Value)
id, _ := constant.Int64Val(gvar.toFieldNamed("goid").Value)
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
// Dereference *defer pointer
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)
status, _ := constant.Int64Val(gvar.toFieldNamed("atomicstatus").Value)
f, l, fn := gvar.dbp.goSymTable.PCToLine(uint64(pc))
g := &G{
ID: int(goid),
GoPC: gopc,
PC: pc,
SP: sp,
CurrentLoc: Location{PC: pc, File: f, Line: l, Fn: fn},
WaitReason: waitreason,
DeferPC: deferPC,
Status: atomicStatus,
dbp: dbp,
ID: int(id),
GoPC: uint64(gopc),
PC: uint64(pc),
SP: uint64(sp),
WaitReason: waitReason,
DeferPC: uint64(deferPC),
Status: uint64(status),
CurrentLoc: Location{PC: uint64(pc), File: f, Line: l, Fn: fn},
dbp: gvar.dbp,
}
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
// isExportedRuntime reports whether name is an exported runtime function.
// It is only for runtime functions, so ASCII A-Z is fine.