Refactor parseG function
This commit is contained in:
parent
33088b93ab
commit
544f20992f
@ -2,7 +2,10 @@ package reader
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/op"
|
||||
)
|
||||
|
||||
type Reader struct {
|
||||
@ -60,6 +63,49 @@ func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) {
|
||||
return nil, fmt.Errorf("unable to find function context")
|
||||
}
|
||||
|
||||
// SeekToTypeNamed moves the reader to the type specified by the name.
|
||||
// If the reader is set to a struct type the NextMemberVariable call
|
||||
// can be used to walk all member data.
|
||||
func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
|
||||
// Walk the types to the base
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if n == name {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("no type entry found")
|
||||
}
|
||||
|
||||
// Returns the address for the named struct member.
|
||||
func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (uint64, error) {
|
||||
for {
|
||||
entry, err := reader.NextMemberVariable()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
name, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok || name != member {
|
||||
continue
|
||||
}
|
||||
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addr, err := op.ExecuteStackProgram(0, append(initialInstructions, instructions...))
|
||||
return uint64(addr), err
|
||||
}
|
||||
}
|
||||
|
||||
// SeekToType moves the reader to the type specified by the entry,
|
||||
// optionally resolving typedefs and pointer types. If the reader is set
|
||||
// to a struct type the NextMemberVariable call can be used to walk all member data.
|
||||
|
@ -410,7 +410,7 @@ func (dbp *DebuggedProcess) GoroutinesInfo() ([]*G, error) {
|
||||
allgptr := binary.LittleEndian.Uint64(faddr)
|
||||
|
||||
for i := uint64(0); i < allglen; i++ {
|
||||
g, err := parseG(dbp.CurrentThread, allgptr+(i*uint64(dbp.arch.PtrSize())), reader)
|
||||
g, err := parseG(dbp.CurrentThread, allgptr+(i*uint64(dbp.arch.PtrSize())))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -259,8 +259,7 @@ func (thread *ThreadContext) curG() (*G, error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reader := thread.Process.dwarf.Reader()
|
||||
g, err = parseG(thread, regs.SP()+uint64(thread.Process.arch.PtrSize()), reader)
|
||||
g, err = parseG(thread, regs.SP()+uint64(thread.Process.arch.PtrSize()))
|
||||
return err
|
||||
})
|
||||
return g, err
|
||||
|
@ -242,7 +242,7 @@ func (ng NoGError) Error() string {
|
||||
return fmt.Sprintf("no G executing on thread %d", ng.tid)
|
||||
}
|
||||
|
||||
func parseG(thread *ThreadContext, addr uint64, reader *dwarf.Reader) (*G, error) {
|
||||
func parseG(thread *ThreadContext, addr uint64) (*G, error) {
|
||||
gaddrbytes, err := thread.readMemory(uintptr(addr), thread.Process.arch.PtrSize())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error derefing *G %s", err)
|
||||
@ -253,57 +253,64 @@ func parseG(thread *ThreadContext, addr uint64, reader *dwarf.Reader) (*G, error
|
||||
return nil, NoGError{tid: thread.Id}
|
||||
}
|
||||
|
||||
reader.Seek(0)
|
||||
goidaddr, err := offsetFor("goid", reader, initialInstructions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
goidbytes, err := thread.readMemory(uintptr(goidaddr), thread.Process.arch.PtrSize())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading goid %s", err)
|
||||
}
|
||||
reader.Seek(0)
|
||||
gopcaddr, err := offsetFor("gopc", reader, initialInstructions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gopcbytes, err := thread.readMemory(uintptr(gopcaddr), thread.Process.arch.PtrSize())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading gopc %s", err)
|
||||
}
|
||||
reader.Seek(0)
|
||||
schedaddr, err := offsetFor("sched", reader, initialInstructions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reader.Seek(0)
|
||||
waitreasonaddr, err := offsetFor("waitreason", reader, initialInstructions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waitreason, err := thread.readString(uintptr(waitreasonaddr))
|
||||
rdr := thread.Process.DwarfReader()
|
||||
rdr.Seek(0)
|
||||
_, err = rdr.SeekToTypeNamed("runtime.g")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spbytes, err := thread.readMemory(uintptr(schedaddr), thread.Process.arch.PtrSize())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading goroutine SP %s", err)
|
||||
}
|
||||
gosp := binary.LittleEndian.Uint64(spbytes)
|
||||
// Let's parse all of the members we care about in order so that
|
||||
// we don't have to spend any extra time seeking.
|
||||
|
||||
pcbytes, err := thread.readMemory(uintptr(schedaddr+uint64(thread.Process.arch.PtrSize())), thread.Process.arch.PtrSize())
|
||||
// Parse sched
|
||||
schedAddr, err := rdr.AddrForMember("sched", initialInstructions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading goroutine PC %s", err)
|
||||
return nil, err
|
||||
}
|
||||
// From sched, let's parse PC and SP.
|
||||
sp, err := thread.readUintRaw(uintptr(schedAddr), 8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pc, err := thread.readUintRaw(uintptr(schedAddr+uint64(thread.Process.arch.PtrSize())), 8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Parse goid
|
||||
goidAddr, err := rdr.AddrForMember("goid", initialInstructions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
goid, err := thread.readIntRaw(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 := thread.readString(uintptr(waitReasonAddr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Parse gopc
|
||||
gopcAddr, err := rdr.AddrForMember("gopc", initialInstructions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gopc, err := thread.readUintRaw(uintptr(gopcAddr), 8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gopc := binary.LittleEndian.Uint64(pcbytes)
|
||||
|
||||
f, l, fn := thread.Process.goSymTable.PCToLine(gopc)
|
||||
g := &G{
|
||||
Id: int(binary.LittleEndian.Uint64(goidbytes)),
|
||||
GoPC: binary.LittleEndian.Uint64(gopcbytes),
|
||||
PC: gopc,
|
||||
SP: gosp,
|
||||
Id: int(goid),
|
||||
GoPC: gopc,
|
||||
PC: pc,
|
||||
SP: sp,
|
||||
File: f,
|
||||
Line: l,
|
||||
Func: fn,
|
||||
@ -351,23 +358,6 @@ func addressFor(dbp *DebuggedProcess, name string, reader *dwarf.Reader) (uint64
|
||||
return uint64(addr), nil
|
||||
}
|
||||
|
||||
func offsetFor(name string, reader *dwarf.Reader, parentinstr []byte) (uint64, error) {
|
||||
entry, err := findDwarfEntry(name, reader, true)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("type assertion failed")
|
||||
}
|
||||
offset, err := op.ExecuteStackProgram(0, append(parentinstr, instructions...))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uint64(offset), nil
|
||||
}
|
||||
|
||||
// Returns the value of the named symbol.
|
||||
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
||||
pc, err := thread.PC()
|
||||
@ -852,11 +842,19 @@ func (thread *ThreadContext) readArrayValues(addr uintptr, count int64, stride i
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readInt(addr uintptr, size int64) (string, error) {
|
||||
n, err := thread.readIntRaw(addr, size)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strconv.FormatInt(n, 10), nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readIntRaw(addr uintptr, size int64) (int64, error) {
|
||||
var n int64
|
||||
|
||||
val, err := thread.readMemory(addr, int(size))
|
||||
if err != nil {
|
||||
return "", err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch size {
|
||||
@ -870,15 +868,23 @@ func (thread *ThreadContext) readInt(addr uintptr, size int64) (string, error) {
|
||||
n = int64(binary.LittleEndian.Uint64(val))
|
||||
}
|
||||
|
||||
return strconv.FormatInt(n, 10), nil
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readUint(addr uintptr, size int64) (string, error) {
|
||||
n, err := thread.readUintRaw(addr, size)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strconv.FormatUint(n, 10), nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readUintRaw(addr uintptr, size int64) (uint64, error) {
|
||||
var n uint64
|
||||
|
||||
val, err := thread.readMemory(addr, int(size))
|
||||
if err != nil {
|
||||
return "", err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch size {
|
||||
@ -892,7 +898,7 @@ func (thread *ThreadContext) readUint(addr uintptr, size int64) (string, error)
|
||||
n = uint64(binary.LittleEndian.Uint64(val))
|
||||
}
|
||||
|
||||
return strconv.FormatUint(n, 10), nil
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readFloat(addr uintptr, size int64) (string, error) {
|
||||
|
Loading…
Reference in New Issue
Block a user