提交 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 { ...@@ -39,6 +39,10 @@ type Config struct {
// MaxArrayValues is the maximum number of array items that the commands // MaxArrayValues is the maximum number of array items that the commands
// print, locals, args and vars should read (in verbose mode). // print, locals, args and vars should read (in verbose mode).
MaxArrayValues *int `yaml:"max-array-values,omitempty"` 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. // LoadConfig attempts to populate a Config object from the config.yml file.
...@@ -139,6 +143,15 @@ aliases: ...@@ -139,6 +143,15 @@ aliases:
# commands. # commands.
substitute-path: substitute-path:
# - {from: path, to: 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 return err
} }
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"io"
"github.com/derekparker/delve/pkg/dwarf/util" "github.com/derekparker/delve/pkg/dwarf/util"
) )
...@@ -73,6 +74,56 @@ func ExecuteStackProgram(regs DwarfRegisters, instructions []byte) (int64, []Pie ...@@ -73,6 +74,56 @@ func ExecuteStackProgram(regs DwarfRegisters, instructions []byte) (int64, []Pie
return ctxt.stack[len(ctxt.stack)-1], nil, nil 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 { func callframecfa(opcode Opcode, ctxt *context) error {
if ctxt.CFA == 0 { if ctxt.CFA == 0 {
return fmt.Errorf("Could not retrieve CFA for current PC") return fmt.Errorf("Could not retrieve CFA for current PC")
......
package proc package proc
import ( import (
"bytes"
"debug/dwarf" "debug/dwarf"
"debug/elf" "debug/elf"
"debug/macho" "debug/macho"
...@@ -341,26 +342,34 @@ func (bi *BinaryInfo) loclistInit(data []byte) { ...@@ -341,26 +342,34 @@ func (bi *BinaryInfo) loclistInit(data []byte) {
// This will either be an int64 address or a slice of Pieces for locations // 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 // that don't correspond to a single memory address (registers, composite
// locations). // 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) a := entry.Val(attr)
if a == nil { 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 { 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) off, ok := a.(int64)
if !ok { 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 { 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) instr := bi.loclistEntry(off, pc)
if instr == nil { 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, // loclistEntry returns the loclist entry in the loclist starting at off,
......
...@@ -332,7 +332,7 @@ func (it *stackIterator) frameBase(fn *Function) int64 { ...@@ -332,7 +332,7 @@ func (it *stackIterator) frameBase(fn *Function) int64 {
if err != nil { if err != nil {
return 0 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 return fb
} }
......
...@@ -95,6 +95,8 @@ type Variable struct { ...@@ -95,6 +95,8 @@ type Variable struct {
loaded bool loaded bool
Unreadable error Unreadable error
LocationExpr string // location expression
} }
type LoadConfig struct { type LoadConfig struct {
...@@ -777,7 +779,7 @@ func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable, ...@@ -777,7 +779,7 @@ func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable,
return nil, err 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 mem := scope.Mem
if pieces != nil { if pieces != nil {
addr = fakeAddress addr = fakeAddress
...@@ -785,6 +787,7 @@ func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable, ...@@ -785,6 +787,7 @@ func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable,
} }
v := scope.newVariable(n, uintptr(addr), t, mem) v := scope.newVariable(n, uintptr(addr), t, mem)
v.LocationExpr = descr
if err != nil { if err != nil {
v.Unreadable = err v.Unreadable = err
} }
......
...@@ -981,6 +981,9 @@ func whatisCommand(t *Term, ctx callContext, args string) error { ...@@ -981,6 +981,9 @@ func whatisCommand(t *Term, ctx callContext, args string) error {
if val.Kind == reflect.Interface && len(val.Children) > 0 { if val.Kind == reflect.Interface && len(val.Children) > 0 {
fmt.Printf("Concrete type: %s\n", val.Children[0].Type) 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 return nil
} }
......
...@@ -73,14 +73,14 @@ func configureList(t *Term) error { ...@@ -73,14 +73,14 @@ func configureList(t *Term) error {
continue 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()) fmt.Fprintf(w, "%s\t%v\n", fieldName, field.Elem())
} else { } else {
fmt.Fprintf(w, "%s\t%v\n", fieldName, field) fmt.Fprintf(w, "%s\t<not defined>\n", fieldName)
} }
} else { } else {
fmt.Fprintf(w, "%s\t<not defined>\n", fieldName) fmt.Fprintf(w, "%s\t%v\n", fieldName, field)
} }
} }
return w.Flush() return w.Flush()
...@@ -116,6 +116,9 @@ func configureSet(t *Term, args string) error { ...@@ -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(nil), fmt.Errorf("argument to %q must be a number", cfgname)
} }
return reflect.ValueOf(&n), nil return reflect.ValueOf(&n), nil
case reflect.Bool:
v := rest == "true"
return reflect.ValueOf(&v), nil
default: default:
return reflect.ValueOf(nil), fmt.Errorf("unsupported type for configuration key %q", cfgname) return reflect.ValueOf(nil), fmt.Errorf("unsupported type for configuration key %q", cfgname)
} }
......
...@@ -121,6 +121,8 @@ func ConvertVar(v *proc.Variable) *Variable { ...@@ -121,6 +121,8 @@ func ConvertVar(v *proc.Variable) *Variable {
Cap: v.Cap, Cap: v.Cap,
Flags: VariableFlags(v.Flags), Flags: VariableFlags(v.Flags),
Base: v.Base, Base: v.Base,
LocationExpr: v.LocationExpr,
} }
r.Type = prettyTypeName(v.DwarfType) r.Type = prettyTypeName(v.DwarfType)
......
...@@ -213,6 +213,9 @@ type Variable struct { ...@@ -213,6 +213,9 @@ type Variable struct {
// Unreadable addresses will have this field set // Unreadable addresses will have this field set
Unreadable string `json:"unreadable"` 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 // 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.
先完成此消息的编辑!
想要评论请 注册