mirror of
https://github.com/go-delve/delve.git
synced 2025-11-01 20:20:40 +08:00
proc,vendor: show global variables in disassembly
updates vendored version of x86asm, adds a symbol lookup function to pass to the disassembler. This will show global symbol names in the disassembly like go tool objdump does.
This commit is contained in:
@ -38,10 +38,10 @@ type BinaryInfo struct {
|
||||
loclist loclistReader
|
||||
compileUnits []*compileUnit
|
||||
types map[string]dwarf.Offset
|
||||
packageVars map[string]dwarf.Offset
|
||||
packageVars []packageVar // packageVars is a list of all global/package variables in debug_info, sorted by address
|
||||
gStructOffset uint64
|
||||
|
||||
// Functions is a list of all DW_TAG_subprogram entries in debug_info.
|
||||
// Functions is a list of all DW_TAG_subprogram entries in debug_info, sorted by entry point
|
||||
Functions []Function
|
||||
// Sources is a list of all source files found in debug_line.
|
||||
Sources []string
|
||||
@ -149,6 +149,15 @@ type constantValue struct {
|
||||
singleBit bool
|
||||
}
|
||||
|
||||
// packageVar represents a package-level variable (or a C global variable).
|
||||
// If a global variable does not have an address (for example it's stored in
|
||||
// a register, or non-contiguously) addr will be 0.
|
||||
type packageVar struct {
|
||||
name string
|
||||
offset dwarf.Offset
|
||||
addr uint64
|
||||
}
|
||||
|
||||
type loclistReader struct {
|
||||
data []byte
|
||||
cur int
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package proc
|
||||
|
||||
import "sort"
|
||||
|
||||
type AsmInstruction struct {
|
||||
Loc Location
|
||||
DestLoc *Location
|
||||
@ -14,6 +16,7 @@ type AssemblyFlavour int
|
||||
const (
|
||||
GNUFlavour = AssemblyFlavour(iota)
|
||||
IntelFlavour
|
||||
GoFlavour
|
||||
)
|
||||
|
||||
// Disassemble disassembles target memory between startPC and endPC, marking
|
||||
@ -83,3 +86,31 @@ func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *Breakpoint
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Looks up symbol (either functions or global variables) at address addr.
|
||||
// Used by disassembly formatter.
|
||||
func (bi *BinaryInfo) symLookup(addr uint64) (string, uint64) {
|
||||
fn := bi.PCToFunc(addr)
|
||||
if fn != nil {
|
||||
if fn.Entry == addr {
|
||||
// only report the function name if it's the exact address because it's
|
||||
// easier to read the absolute address than function_name+offset.
|
||||
return fn.Name, fn.Entry
|
||||
}
|
||||
return "", 0
|
||||
}
|
||||
i := sort.Search(len(bi.packageVars), func(i int) bool {
|
||||
return bi.packageVars[i].addr >= addr
|
||||
})
|
||||
if i >= len(bi.packageVars) {
|
||||
return "", 0
|
||||
}
|
||||
if bi.packageVars[i].addr > addr {
|
||||
// report previous variable + offset if i-th variable starts after addr
|
||||
i--
|
||||
}
|
||||
if i > 0 {
|
||||
return bi.packageVars[i].name, bi.packageVars[i].addr
|
||||
}
|
||||
return "", 0
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ func patchPCRel(pc uint64, inst *x86asm.Inst) {
|
||||
}
|
||||
}
|
||||
|
||||
func (inst *AsmInstruction) Text(flavour AssemblyFlavour) string {
|
||||
func (inst *AsmInstruction) Text(flavour AssemblyFlavour, bi *BinaryInfo) string {
|
||||
if inst.Inst == nil {
|
||||
return "?"
|
||||
}
|
||||
@ -43,15 +43,13 @@ func (inst *AsmInstruction) Text(flavour AssemblyFlavour) string {
|
||||
|
||||
switch flavour {
|
||||
case GNUFlavour:
|
||||
text = x86asm.GNUSyntax(x86asm.Inst(*inst.Inst))
|
||||
text = x86asm.GNUSyntax(x86asm.Inst(*inst.Inst), inst.Loc.PC, bi.symLookup)
|
||||
case GoFlavour:
|
||||
text = x86asm.GoSyntax(x86asm.Inst(*inst.Inst), inst.Loc.PC, bi.symLookup)
|
||||
case IntelFlavour:
|
||||
fallthrough
|
||||
default:
|
||||
text = x86asm.IntelSyntax(x86asm.Inst(*inst.Inst))
|
||||
}
|
||||
|
||||
if inst.IsCall() && inst.DestLoc != nil && inst.DestLoc.Fn != nil {
|
||||
text += " " + inst.DestLoc.Fn.Name
|
||||
text = x86asm.IntelSyntax(x86asm.Inst(*inst.Inst), inst.Loc.PC, bi.symLookup)
|
||||
}
|
||||
|
||||
return text
|
||||
|
||||
@ -3455,3 +3455,21 @@ func TestIssue1145(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDisassembleGlobalVars(t *testing.T) {
|
||||
withTestProcess("teststepconcurrent", t, func(p proc.Process, fixture protest.Fixture) {
|
||||
mainfn := p.BinInfo().LookupFunc["main.main"]
|
||||
text, err := proc.Disassemble(p, nil, mainfn.Entry, mainfn.End)
|
||||
assertNoError(err, t, "Disassemble")
|
||||
found := false
|
||||
for i := range text {
|
||||
if strings.Index(text[i].Text(proc.IntelFlavour, p.BinInfo()), "main.v") > 0 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("could not find main.v reference in disassembly")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package proc
|
||||
import (
|
||||
"bytes"
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
@ -18,6 +19,7 @@ import (
|
||||
|
||||
"github.com/derekparker/delve/pkg/dwarf/godwarf"
|
||||
"github.com/derekparker/delve/pkg/dwarf/line"
|
||||
"github.com/derekparker/delve/pkg/dwarf/op"
|
||||
"github.com/derekparker/delve/pkg/dwarf/reader"
|
||||
)
|
||||
|
||||
@ -169,12 +171,18 @@ func (v compileUnitsByLowpc) Len() int { return len(v) }
|
||||
func (v compileUnitsByLowpc) Less(i int, j int) bool { return v[i].LowPC < v[j].LowPC }
|
||||
func (v compileUnitsByLowpc) Swap(i int, j int) { v[i], v[j] = v[j], v[i] }
|
||||
|
||||
type packageVarsByAddr []packageVar
|
||||
|
||||
func (v packageVarsByAddr) Len() int { return len(v) }
|
||||
func (v packageVarsByAddr) Less(i int, j int) bool { return v[i].addr < v[j].addr }
|
||||
func (v packageVarsByAddr) Swap(i int, j int) { v[i], v[j] = v[j], v[i] }
|
||||
|
||||
func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGroup) {
|
||||
if wg != nil {
|
||||
defer wg.Done()
|
||||
}
|
||||
bi.types = make(map[string]dwarf.Offset)
|
||||
bi.packageVars = make(map[string]dwarf.Offset)
|
||||
bi.packageVars = []packageVar{}
|
||||
bi.Functions = []Function{}
|
||||
bi.compileUnits = []*compileUnit{}
|
||||
bi.consts = make(map[dwarf.Offset]*constantType)
|
||||
@ -226,7 +234,13 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou
|
||||
if !cu.isgo {
|
||||
n = "C." + n
|
||||
}
|
||||
bi.packageVars[n] = entry.Offset
|
||||
var addr uint64
|
||||
if loc, ok := entry.Val(dwarf.AttrLocation).([]byte); ok {
|
||||
if len(loc) == bi.Arch.PtrSize()+1 && op.Opcode(loc[0]) == op.DW_OP_addr {
|
||||
addr = binary.LittleEndian.Uint64(loc[1:])
|
||||
}
|
||||
}
|
||||
bi.packageVars = append(bi.packageVars, packageVar{n, entry.Offset, addr})
|
||||
}
|
||||
|
||||
case dwarf.TagConstant:
|
||||
@ -271,6 +285,7 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou
|
||||
}
|
||||
sort.Sort(compileUnitsByLowpc(bi.compileUnits))
|
||||
sort.Sort(functionsDebugInfoByEntry(bi.Functions))
|
||||
sort.Sort(packageVarsByAddr(bi.packageVars))
|
||||
|
||||
bi.LookupFunc = make(map[string]*Function)
|
||||
for i := range bi.Functions {
|
||||
|
||||
@ -653,10 +653,10 @@ func (scope *EvalScope) PackageVariables(cfg LoadConfig) ([]*Variable, error) {
|
||||
}
|
||||
|
||||
func (scope *EvalScope) findGlobal(name string) (*Variable, error) {
|
||||
for n, off := range scope.BinInfo.packageVars {
|
||||
if n == name || strings.HasSuffix(n, "/"+name) {
|
||||
for _, pkgvar := range scope.BinInfo.packageVars {
|
||||
if pkgvar.name == name || strings.HasSuffix(pkgvar.name, "/"+name) {
|
||||
reader := scope.DwarfReader()
|
||||
reader.Seek(off)
|
||||
reader.Seek(pkgvar.offset)
|
||||
entry, err := reader.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user