提交 1758f852 编写于 作者: A aarzilli 提交者: Derek Parker

pkg/terminal: print DWARF location expression with whatis

Adds a configuration option (show-location-expr) that when activated
will cause the whatis command to also print the DWARF location
expression for a variable.
上级 926a6107
......@@ -39,6 +39,10 @@ type Config struct {
// MaxArrayValues is the maximum number of array items that the commands
// print, locals, args and vars should read (in verbose mode).
MaxArrayValues *int `yaml:"max-array-values,omitempty"`
// If ShowLocationExpr is true whatis will print the DWARF location
// expression for its argument.
ShowLocationExpr bool `yaml:"show-location-expr"`
}
// LoadConfig attempts to populate a Config object from the config.yml file.
......@@ -139,6 +143,15 @@ aliases:
# commands.
substitute-path:
# - {from: path, to: path}
# Maximum number of elements loaded from an array.
# max-array-values: 64
# Maximum loaded string length.
# max-string-len: 64
# Uncomment the following line to make the whatis command also print the DWARF location expression of its argument.
# show-location-expr: true
`)
return err
}
......
......@@ -5,6 +5,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"io"
"github.com/derekparker/delve/pkg/dwarf/util"
)
......@@ -73,6 +74,56 @@ func ExecuteStackProgram(regs DwarfRegisters, instructions []byte) (int64, []Pie
return ctxt.stack[len(ctxt.stack)-1], nil, nil
}
// PrettyPrint prints instructions to out.
func PrettyPrint(out io.Writer, instructions []byte) {
in := bytes.NewBuffer(instructions)
for {
opcode, err := in.ReadByte()
if err != nil {
break
}
if name, hasname := opcodeName[Opcode(opcode)]; hasname {
io.WriteString(out, name)
out.Write([]byte{' '})
} else {
fmt.Fprintf(out, "%#x ", opcode)
}
for _, arg := range opcodeArgs[Opcode(opcode)] {
switch arg {
case 's':
n, _ := util.DecodeSLEB128(in)
fmt.Fprintf(out, "%#x ", n)
case 'u':
n, _ := util.DecodeULEB128(in)
fmt.Fprintf(out, "%#x ", n)
case '1':
var x uint8
binary.Read(in, binary.LittleEndian, &x)
fmt.Fprintf(out, "%#x ", x)
case '2':
var x uint16
binary.Read(in, binary.LittleEndian, &x)
fmt.Fprintf(out, "%#x ", x)
case '4':
var x uint32
binary.Read(in, binary.LittleEndian, &x)
fmt.Fprintf(out, "%#x ", x)
case '8':
var x uint64
binary.Read(in, binary.LittleEndian, &x)
fmt.Fprintf(out, "%#x ", x)
case 'B':
sz, _ := util.DecodeULEB128(in)
data := make([]byte, sz)
sz2, _ := in.Read(data)
data = data[:sz2]
fmt.Fprintf(out, "%d [%x] ", sz, data)
}
}
}
}
func callframecfa(opcode Opcode, ctxt *context) error {
if ctxt.CFA == 0 {
return fmt.Errorf("Could not retrieve CFA for current PC")
......
package proc
import (
"bytes"
"debug/dwarf"
"debug/elf"
"debug/macho"
......@@ -341,26 +342,34 @@ func (bi *BinaryInfo) loclistInit(data []byte) {
// This will either be an int64 address or a slice of Pieces for locations
// that don't correspond to a single memory address (registers, composite
// locations).
func (bi *BinaryInfo) Location(entry *dwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, error) {
func (bi *BinaryInfo) Location(entry *dwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, string, error) {
a := entry.Val(attr)
if a == nil {
return 0, nil, fmt.Errorf("no location attribute %s", attr)
return 0, nil, "", fmt.Errorf("no location attribute %s", attr)
}
if instr, ok := a.([]byte); ok {
return op.ExecuteStackProgram(regs, instr)
var descr bytes.Buffer
fmt.Fprintf(&descr, "[block] ")
op.PrettyPrint(&descr, instr)
addr, pieces, err := op.ExecuteStackProgram(regs, instr)
return addr, pieces, descr.String(), err
}
off, ok := a.(int64)
if !ok {
return 0, nil, fmt.Errorf("could not interpret location attribute %s", attr)
return 0, nil, "", fmt.Errorf("could not interpret location attribute %s", attr)
}
if bi.loclist.data == nil {
return 0, nil, fmt.Errorf("could not find loclist entry at %#x for address %#x (no debug_loc section found)", off, pc)
return 0, nil, "", fmt.Errorf("could not find loclist entry at %#x for address %#x (no debug_loc section found)", off, pc)
}
instr := bi.loclistEntry(off, pc)
if instr == nil {
return 0, nil, fmt.Errorf("could not find loclist entry at %#x for address %#x", off, pc)
return 0, nil, "", fmt.Errorf("could not find loclist entry at %#x for address %#x", off, pc)
}
return op.ExecuteStackProgram(regs, instr)
var descr bytes.Buffer
fmt.Fprintf(&descr, "[%#x:%#x] ", off, pc)
op.PrettyPrint(&descr, instr)
addr, pieces, err := op.ExecuteStackProgram(regs, instr)
return addr, pieces, descr.String(), err
}
// loclistEntry returns the loclist entry in the loclist starting at off,
......
......@@ -332,7 +332,7 @@ func (it *stackIterator) frameBase(fn *Function) int64 {
if err != nil {
return 0
}
fb, _, _ := it.bi.Location(e, dwarf.AttrFrameBase, it.pc, it.regs)
fb, _, _, _ := it.bi.Location(e, dwarf.AttrFrameBase, it.pc, it.regs)
return fb
}
......
......@@ -95,6 +95,8 @@ type Variable struct {
loaded bool
Unreadable error
LocationExpr string // location expression
}
type LoadConfig struct {
......@@ -777,7 +779,7 @@ func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable,
return nil, err
}
addr, pieces, err := scope.BinInfo.Location(entry, dwarf.AttrLocation, scope.PC, scope.Regs)
addr, pieces, descr, err := scope.BinInfo.Location(entry, dwarf.AttrLocation, scope.PC, scope.Regs)
mem := scope.Mem
if pieces != nil {
addr = fakeAddress
......@@ -785,6 +787,7 @@ func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable,
}
v := scope.newVariable(n, uintptr(addr), t, mem)
v.LocationExpr = descr
if err != nil {
v.Unreadable = err
}
......
......@@ -981,6 +981,9 @@ func whatisCommand(t *Term, ctx callContext, args string) error {
if val.Kind == reflect.Interface && len(val.Children) > 0 {
fmt.Printf("Concrete type: %s\n", val.Children[0].Type)
}
if t.conf.ShowLocationExpr && val.LocationExpr != "" {
fmt.Printf("location: %s\n", val.LocationExpr)
}
return nil
}
......
......@@ -73,14 +73,14 @@ func configureList(t *Term) error {
continue
}
if !field.IsNil() {
if field.Kind() == reflect.Ptr {
if field.Kind() == reflect.Ptr {
if !field.IsNil() {
fmt.Fprintf(w, "%s\t%v\n", fieldName, field.Elem())
} else {
fmt.Fprintf(w, "%s\t%v\n", fieldName, field)
fmt.Fprintf(w, "%s\t<not defined>\n", fieldName)
}
} else {
fmt.Fprintf(w, "%s\t<not defined>\n", fieldName)
fmt.Fprintf(w, "%s\t%v\n", fieldName, field)
}
}
return w.Flush()
......@@ -116,6 +116,9 @@ func configureSet(t *Term, args string) error {
return reflect.ValueOf(nil), fmt.Errorf("argument to %q must be a number", cfgname)
}
return reflect.ValueOf(&n), nil
case reflect.Bool:
v := rest == "true"
return reflect.ValueOf(&v), nil
default:
return reflect.ValueOf(nil), fmt.Errorf("unsupported type for configuration key %q", cfgname)
}
......
......@@ -121,6 +121,8 @@ func ConvertVar(v *proc.Variable) *Variable {
Cap: v.Cap,
Flags: VariableFlags(v.Flags),
Base: v.Base,
LocationExpr: v.LocationExpr,
}
r.Type = prettyTypeName(v.DwarfType)
......
......@@ -213,6 +213,9 @@ type Variable struct {
// Unreadable addresses will have this field set
Unreadable string `json:"unreadable"`
// LocationExpr describes the location expression of this variable's address
LocationExpr string
}
// LoadConfig describes how to load values from target's memory
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册