Refactor parseG function
This commit is contained in:
parent
33088b93ab
commit
544f20992f
@ -2,7 +2,10 @@ package reader
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"debug/dwarf"
|
"debug/dwarf"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/derekparker/delve/dwarf/op"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Reader struct {
|
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")
|
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,
|
// SeekToType moves the reader to the type specified by the entry,
|
||||||
// optionally resolving typedefs and pointer types. If the reader is set
|
// 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.
|
// 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)
|
allgptr := binary.LittleEndian.Uint64(faddr)
|
||||||
|
|
||||||
for i := uint64(0); i < allglen; i++ {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -259,8 +259,7 @@ func (thread *ThreadContext) curG() (*G, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
reader := thread.Process.dwarf.Reader()
|
g, err = parseG(thread, regs.SP()+uint64(thread.Process.arch.PtrSize()))
|
||||||
g, err = parseG(thread, regs.SP()+uint64(thread.Process.arch.PtrSize()), reader)
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
return g, err
|
return g, err
|
||||||
|
@ -242,7 +242,7 @@ func (ng NoGError) Error() string {
|
|||||||
return fmt.Sprintf("no G executing on thread %d", ng.tid)
|
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())
|
gaddrbytes, err := thread.readMemory(uintptr(addr), thread.Process.arch.PtrSize())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error derefing *G %s", err)
|
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}
|
return nil, NoGError{tid: thread.Id}
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.Seek(0)
|
rdr := thread.Process.DwarfReader()
|
||||||
goidaddr, err := offsetFor("goid", reader, initialInstructions)
|
rdr.Seek(0)
|
||||||
if err != nil {
|
_, err = rdr.SeekToTypeNamed("runtime.g")
|
||||||
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))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
spbytes, err := thread.readMemory(uintptr(schedaddr), thread.Process.arch.PtrSize())
|
// Let's parse all of the members we care about in order so that
|
||||||
if err != nil {
|
// we don't have to spend any extra time seeking.
|
||||||
return nil, fmt.Errorf("error reading goroutine SP %s", err)
|
|
||||||
}
|
|
||||||
gosp := binary.LittleEndian.Uint64(spbytes)
|
|
||||||
|
|
||||||
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 {
|
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)
|
f, l, fn := thread.Process.goSymTable.PCToLine(gopc)
|
||||||
g := &G{
|
g := &G{
|
||||||
Id: int(binary.LittleEndian.Uint64(goidbytes)),
|
Id: int(goid),
|
||||||
GoPC: binary.LittleEndian.Uint64(gopcbytes),
|
GoPC: gopc,
|
||||||
PC: gopc,
|
PC: pc,
|
||||||
SP: gosp,
|
SP: sp,
|
||||||
File: f,
|
File: f,
|
||||||
Line: l,
|
Line: l,
|
||||||
Func: fn,
|
Func: fn,
|
||||||
@ -351,23 +358,6 @@ func addressFor(dbp *DebuggedProcess, name string, reader *dwarf.Reader) (uint64
|
|||||||
return uint64(addr), nil
|
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.
|
// Returns the value of the named symbol.
|
||||||
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
||||||
pc, err := thread.PC()
|
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) {
|
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
|
var n int64
|
||||||
|
|
||||||
val, err := thread.readMemory(addr, int(size))
|
val, err := thread.readMemory(addr, int(size))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch size {
|
switch size {
|
||||||
@ -870,15 +868,23 @@ func (thread *ThreadContext) readInt(addr uintptr, size int64) (string, error) {
|
|||||||
n = int64(binary.LittleEndian.Uint64(val))
|
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) {
|
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
|
var n uint64
|
||||||
|
|
||||||
val, err := thread.readMemory(addr, int(size))
|
val, err := thread.readMemory(addr, int(size))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch size {
|
switch size {
|
||||||
@ -892,7 +898,7 @@ func (thread *ThreadContext) readUint(addr uintptr, size int64) (string, error)
|
|||||||
n = uint64(binary.LittleEndian.Uint64(val))
|
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) {
|
func (thread *ThreadContext) readFloat(addr uintptr, size int64) (string, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user