Refactor parseG function

This commit is contained in:
Derek Parker 2015-05-09 10:27:06 -05:00
parent 33088b93ab
commit 544f20992f
4 changed files with 117 additions and 66 deletions

@ -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) {