Extracting common dwarf reader functionality into its own area
This commit is contained in:
parent
c0fd1a0295
commit
ed6d4049b6
85
dwarf/reader/reader.go
Executable file
85
dwarf/reader/reader.go
Executable file
@ -0,0 +1,85 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Reader struct {
|
||||
*dwarf.Reader
|
||||
depth int
|
||||
}
|
||||
|
||||
// New returns a reader for the specified dwarf data
|
||||
func New(data *dwarf.Data) *Reader {
|
||||
return &Reader{data.Reader(), 0}
|
||||
}
|
||||
|
||||
// Seek moves the reader to an arbitrary offset
|
||||
func (reader *Reader) Seek(off dwarf.Offset) {
|
||||
reader.depth = 0
|
||||
reader.Reader.Seek(off)
|
||||
}
|
||||
|
||||
// SeekToEntry moves the reader to an arbitrary entry
|
||||
func (reader *Reader) SeekToEntry(entry *dwarf.Entry) error {
|
||||
reader.Seek(entry.Offset)
|
||||
// Consume the current entry so .Next works as intended
|
||||
_, err := reader.Next()
|
||||
return err
|
||||
}
|
||||
|
||||
// SeekToFunctionEntry moves the reader to the function that includes the
|
||||
// specified program counter.
|
||||
func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) {
|
||||
reader.Seek(0)
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag != dwarf.TagSubprogram {
|
||||
continue
|
||||
}
|
||||
|
||||
lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
highpc, ok := entry.Val(dwarf.AttrHighpc).(uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if lowpc <= pc && highpc >= pc {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to find function context")
|
||||
}
|
||||
|
||||
// NextScopeVariable moves the reader to the next debug entry that describes a local variable
|
||||
func (reader *Reader) NextScopeVariable() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// All scope variables will be at the same depth
|
||||
reader.SkipChildren()
|
||||
|
||||
// End of the current depth
|
||||
if entry.Tag == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if entry.Tag == dwarf.TagVariable || entry.Tag == dwarf.TagFormalParameter {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
// No more items
|
||||
return nil, nil
|
||||
}
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/frame"
|
||||
"github.com/derekparker/delve/dwarf/reader"
|
||||
)
|
||||
|
||||
// Struct representing a debugged process. Holds onto pid, register values,
|
||||
@ -298,6 +299,11 @@ func (dbp *DebuggedProcess) EvalSymbol(name string) (*Variable, error) {
|
||||
return dbp.CurrentThread.EvalSymbol(name)
|
||||
}
|
||||
|
||||
// Returns a reader for the dwarf data
|
||||
func (dbp *DebuggedProcess) DwarfReader() *reader.Reader {
|
||||
return reader.New(dbp.Dwarf)
|
||||
}
|
||||
|
||||
type ProcessExitedError struct {
|
||||
pid int
|
||||
}
|
||||
|
||||
@ -302,48 +302,27 @@ func offsetFor(dbp *DebuggedProcess, name string, reader *dwarf.Reader, parentin
|
||||
|
||||
// Returns the value of the named symbol.
|
||||
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
||||
data := thread.Process.Dwarf
|
||||
|
||||
pc, err := thread.CurrentPC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fn := thread.Process.GoSymTable.PCToFunc(pc)
|
||||
if fn == nil {
|
||||
return nil, fmt.Errorf("could not find function scope")
|
||||
}
|
||||
reader := thread.Process.DwarfReader()
|
||||
|
||||
reader := data.Reader()
|
||||
if err = seekToFunctionEntry(fn.Name, reader); err != nil {
|
||||
_, err = reader.SeekToFunction(pc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strings.Contains(name, ".") {
|
||||
idx := strings.Index(name, ".")
|
||||
return evaluateStructMember(thread, data, reader, name[:idx], name[idx+1:])
|
||||
data := thread.Process.Dwarf
|
||||
return evaluateStructMember(thread, data, reader.Reader, name[:idx], name[idx+1:])
|
||||
}
|
||||
|
||||
entry, err := findDwarfEntry(name, reader, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return thread.extractVariableFromEntry(entry)
|
||||
}
|
||||
|
||||
// seekToFunctionEntry is basically used to seek the dwarf.Reader to
|
||||
// the function entry that represents our current scope. From there
|
||||
// we can find the first child entry that matches the var name and
|
||||
// use it to determine the value of the variable.
|
||||
func seekToFunctionEntry(name string, reader *dwarf.Reader) error {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if entry.Tag != dwarf.TagSubprogram {
|
||||
continue
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
@ -352,11 +331,11 @@ func seekToFunctionEntry(name string, reader *dwarf.Reader) error {
|
||||
}
|
||||
|
||||
if n == name {
|
||||
break
|
||||
return thread.extractVariableFromEntry(entry)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, fmt.Errorf("could not find symbol value for %s", name)
|
||||
}
|
||||
|
||||
func findDwarfEntry(name string, reader *dwarf.Reader, member bool) (*dwarf.Entry, error) {
|
||||
@ -656,35 +635,25 @@ func (thread *ThreadContext) readMemory(addr uintptr, size uintptr) ([]byte, err
|
||||
|
||||
// Fetches all variables of a specific type in the current function scope
|
||||
func (thread *ThreadContext) variablesByTag(tag dwarf.Tag) ([]*Variable, error) {
|
||||
data := thread.Process.Dwarf
|
||||
|
||||
pc, err := thread.CurrentPC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fn := thread.Process.GoSymTable.PCToFunc(pc)
|
||||
if fn == nil {
|
||||
return nil, fmt.Errorf("could not find function scope")
|
||||
}
|
||||
reader := thread.Process.DwarfReader()
|
||||
|
||||
reader := data.Reader()
|
||||
if err = seekToFunctionEntry(fn.Name, reader); err != nil {
|
||||
_, err = reader.SeekToFunction(pc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vars := make([]*Variable, 0)
|
||||
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// End of function
|
||||
if entry.Tag == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if entry.Tag == tag {
|
||||
val, err := thread.extractVariableFromEntry(entry)
|
||||
if err != nil {
|
||||
@ -693,9 +662,6 @@ func (thread *ThreadContext) variablesByTag(tag dwarf.Tag) ([]*Variable, error)
|
||||
|
||||
vars = append(vars, val)
|
||||
}
|
||||
|
||||
// Only care about top level
|
||||
reader.SkipChildren()
|
||||
}
|
||||
|
||||
return vars, nil
|
||||
|
||||
Loading…
Reference in New Issue
Block a user