delve/pkg/dwarf/op/regs.go
aarzilli 5372588c61 proc: support cgo stacktraces
When creating a stack trace we should switch between the goroutine
stack and the system stack (where cgo code is executed) as appropriate
to reconstruct the logical stacktrace.

Goroutines that are currently executing on the system stack will have
the SystemStack flag set, frames of the goroutine stack will have a
negative FrameOffset (like always) and frames of the system stack will
have a positive FrameOffset (which is actually just the CFA value for
the frame).

Updates #935
2017-11-28 11:00:53 -08:00

101 lines
2.0 KiB
Go

package op
import (
"bytes"
"encoding/binary"
)
type DwarfRegisters struct {
CFA int64
FrameBase int64
ObjBase int64
Regs []*DwarfRegister
ByteOrder binary.ByteOrder
PCRegNum uint64
SPRegNum uint64
BPRegNum uint64
}
type DwarfRegister struct {
Uint64Val uint64
Bytes []byte
}
// Uint64Val returns the uint64 value of register idx.
func (regs *DwarfRegisters) Uint64Val(idx uint64) uint64 {
reg := regs.Reg(idx)
if reg == nil {
return 0
}
return regs.Regs[idx].Uint64Val
}
// Bytes returns the bytes value of register idx, nil if the register is not
// defined.
func (regs *DwarfRegisters) Bytes(idx uint64) []byte {
reg := regs.Reg(idx)
if reg == nil {
return nil
}
if reg.Bytes == nil {
var buf bytes.Buffer
binary.Write(&buf, regs.ByteOrder, reg.Uint64Val)
reg.Bytes = buf.Bytes()
}
return reg.Bytes
}
// Reg returns register idx or nil if the register is not defined.
func (regs *DwarfRegisters) Reg(idx uint64) *DwarfRegister {
if idx >= uint64(len(regs.Regs)) {
return nil
}
return regs.Regs[idx]
}
func (regs *DwarfRegisters) PC() uint64 {
return regs.Uint64Val(regs.PCRegNum)
}
func (regs *DwarfRegisters) SP() uint64 {
return regs.Uint64Val(regs.SPRegNum)
}
func (regs *DwarfRegisters) BP() uint64 {
return regs.Uint64Val(regs.BPRegNum)
}
// AddReg adds register idx to regs.
func (regs *DwarfRegisters) AddReg(idx uint64, reg *DwarfRegister) {
if idx >= uint64(len(regs.Regs)) {
newRegs := make([]*DwarfRegister, idx+1)
copy(newRegs, regs.Regs)
regs.Regs = newRegs
}
regs.Regs[idx] = reg
}
func DwarfRegisterFromUint64(v uint64) *DwarfRegister {
return &DwarfRegister{Uint64Val: v}
}
func DwarfRegisterFromBytes(bytes []byte) *DwarfRegister {
var v uint64
switch len(bytes) {
case 1:
v = uint64(bytes[0])
case 2:
x := binary.LittleEndian.Uint16(bytes)
v = uint64(x)
case 4:
x := binary.LittleEndian.Uint32(bytes)
v = uint64(x)
default:
if len(bytes) >= 8 {
v = binary.LittleEndian.Uint64(bytes[:8])
}
}
return &DwarfRegister{Uint64Val: v, Bytes: bytes}
}