in internal/gocore/process.go [558:642]
func (p *Process) readG(r region) *Goroutine {
g := &Goroutine{r: r}
stk := r.Field("stack")
g.stackSize = int64(stk.Field("hi").Uintptr() - stk.Field("lo").Uintptr())
var osT *core.Thread // os thread working on behalf of this G (if any).
mp := r.Field("m")
if mp.Address() != 0 {
m := mp.Deref()
pid := m.Field("procid").Uint64()
// TODO check that m.curg points to g?
for _, t := range p.proc.Threads() {
if t.Pid() == pid {
osT = t
}
}
}
status := r.Field("atomicstatus").Uint32()
status &^= uint32(p.rtConstants["_Gscan"])
var sp, pc core.Address
switch status {
case uint32(p.rtConstants["_Gidle"]):
return g
case uint32(p.rtConstants["_Grunnable"]), uint32(p.rtConstants["_Gwaiting"]):
sched := r.Field("sched")
sp = core.Address(sched.Field("sp").Uintptr())
pc = core.Address(sched.Field("pc").Uintptr())
case uint32(p.rtConstants["_Grunning"]):
sp = osT.SP()
pc = osT.PC()
// TODO: back up to the calling frame?
case uint32(p.rtConstants["_Gsyscall"]):
sp = core.Address(r.Field("syscallsp").Uintptr())
pc = core.Address(r.Field("syscallpc").Uintptr())
// TODO: or should we use the osT registers?
case uint32(p.rtConstants["_Gdead"]):
return nil
// TODO: copystack, others?
default:
// Unknown state. We can't read the frames, so just bail now.
// TODO: make this switch complete and then panic here.
// TODO: or just return nil?
return g
}
for {
f, err := p.readFrame(sp, pc)
if err != nil {
fmt.Printf("warning: giving up on backtrace: %v\n", err)
break
}
if f.f.name == "runtime.goexit" {
break
}
if len(g.frames) > 0 {
g.frames[len(g.frames)-1].parent = f
}
g.frames = append(g.frames, f)
if f.f.name == "runtime.sigtrampgo" {
// Continue traceback at location where the signal
// interrupted normal execution.
ctxt := p.proc.ReadPtr(sp.Add(16)) // 3rd arg
//ctxt is a *ucontext
mctxt := ctxt.Add(5 * 8)
// mctxt is a *mcontext
sp = p.proc.ReadPtr(mctxt.Add(15 * 8))
pc = p.proc.ReadPtr(mctxt.Add(16 * 8))
// TODO: totally arch-dependent!
} else {
sp = f.max
pc = core.Address(p.proc.ReadUintptr(sp - 8)) // TODO:amd64 only
}
if pc == 0 {
// TODO: when would this happen?
break
}
if f.f.name == "runtime.systemstack" {
// switch over to goroutine stack
sched := r.Field("sched")
sp = core.Address(sched.Field("sp").Uintptr())
pc = core.Address(sched.Field("pc").Uintptr())
}
}
return g
}