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

proc/tests: testing apparatus for complex location expressions

上级 25b19c77
// Package dwarfbuilder provides a way to build DWARF sections with
// arbitrary contents.
package dwarfbuilder
import (
"bytes"
"debug/dwarf"
"encoding/binary"
"fmt"
)
type Builder struct {
info bytes.Buffer
loc bytes.Buffer
abbrevs []tagDescr
tagStack []*tagState
}
// New creates a new DWARF builder.
func New() *Builder {
b := &Builder{}
b.info.Write([]byte{
0x0, 0x0, 0x0, 0x0, // length
0x4, 0x0, // version
0x0, 0x0, 0x0, 0x0, // debug_abbrev_offset
0x8, // address_size
})
b.TagOpen(dwarf.TagCompileUnit, "go")
b.Attr(dwarf.AttrLanguage, uint8(22))
return b
}
// Build closes b and returns all the dwarf sections.
func (b *Builder) Build() (abbrev, aranges, frame, info, line, pubnames, ranges, str []byte, err error) {
b.TagClose()
if len(b.tagStack) > 0 {
err = fmt.Errorf("unbalanced TagOpen/TagClose %d", len(b.tagStack))
return
}
abbrev = b.makeAbbrevTable()
info = b.info.Bytes()
binary.LittleEndian.PutUint32(info, uint32(len(info)-4))
return
}
package dwarfbuilder
import (
"bytes"
"debug/dwarf"
"encoding/binary"
"github.com/derekparker/delve/pkg/dwarf/util"
)
// Form represents a DWARF form kind (see Figure 20, page 160 and following,
// DWARF v4)
type Form uint16
const (
DW_FORM_addr Form = 0x01 // address
DW_FORM_block2 Form = 0x03 // block
DW_FORM_block4 Form = 0x04 // block
DW_FORM_data2 Form = 0x05 // constant
DW_FORM_data4 Form = 0x06 // constant
DW_FORM_data8 Form = 0x07 // constant
DW_FORM_string Form = 0x08 // string
DW_FORM_block Form = 0x09 // block
DW_FORM_block1 Form = 0x0a // block
DW_FORM_data1 Form = 0x0b // constant
DW_FORM_flag Form = 0x0c // flag
DW_FORM_sdata Form = 0x0d // constant
DW_FORM_strp Form = 0x0e // string
DW_FORM_udata Form = 0x0f // constant
DW_FORM_ref_addr Form = 0x10 // reference
DW_FORM_ref1 Form = 0x11 // reference
DW_FORM_ref2 Form = 0x12 // reference
DW_FORM_ref4 Form = 0x13 // reference
DW_FORM_ref8 Form = 0x14 // reference
DW_FORM_ref_udata Form = 0x15 // reference
DW_FORM_indirect Form = 0x16 // (see Section 7.5.3)
DW_FORM_sec_offset Form = 0x17 // lineptr, loclistptr, macptr, rangelistptr
DW_FORM_exprloc Form = 0x18 // exprloc
DW_FORM_flag_present Form = 0x19 // flag
DW_FORM_ref_sig8 Form = 0x20 // reference
)
// Encoding represents a DWARF base type encoding (see section 7.8, page 168
// and following, DWARF v4).
type Encoding uint16
const (
DW_ATE_address Encoding = 0x01
DW_ATE_boolean Encoding = 0x02
DW_ATE_complex_float Encoding = 0x03
DW_ATE_float Encoding = 0x04
DW_ATE_signed Encoding = 0x05
DW_ATE_signed_char Encoding = 0x06
DW_ATE_unsigned Encoding = 0x07
DW_ATE_unsigned_char Encoding = 0x08
DW_ATE_imaginary_float Encoding = 0x09
DW_ATE_packed_decimal Encoding = 0x0a
DW_ATE_numeric_string Encoding = 0x0b
DW_ATE_edited Encoding = 0x0c
DW_ATE_signed_fixed Encoding = 0x0d
DW_ATE_unsigned_fixed Encoding = 0x0e
DW_ATE_decimal_float Encoding = 0x0f
DW_ATE_UTF Encoding = 0x10
DW_ATE_lo_user Encoding = 0x80
DW_ATE_hi_user Encoding = 0xff
)
// Address represents a machine address.
type Address uint64
type tagDescr struct {
tag dwarf.Tag
attr []dwarf.Attr
form []Form
children bool
}
type tagState struct {
off dwarf.Offset
tagDescr
}
// TagOpen starts a new DIE, call TagClose after adding all attributes and
// children elements.
func (b *Builder) TagOpen(tag dwarf.Tag, name string) dwarf.Offset {
if len(b.tagStack) > 0 {
b.tagStack[len(b.tagStack)-1].children = true
}
ts := &tagState{off: dwarf.Offset(b.info.Len())}
ts.tag = tag
b.info.WriteByte(0)
b.tagStack = append(b.tagStack, ts)
b.Attr(dwarf.AttrName, name)
return ts.off
}
// SetHasChildren sets the current DIE as having children (even if none are added).
func (b *Builder) SetHasChildren() {
if len(b.tagStack) <= 0 {
panic("NoChildren with no open tags")
}
b.tagStack[len(b.tagStack)-1].children = true
}
// TagClose closes the current DIE.
func (b *Builder) TagClose() {
if len(b.tagStack) <= 0 {
panic("TagClose with no open tags")
}
tag := b.tagStack[len(b.tagStack)-1]
abbrev := b.abbrevFor(tag.tagDescr)
b.info.Bytes()[tag.off] = abbrev
if tag.children {
b.info.WriteByte(0)
}
b.tagStack = b.tagStack[:len(b.tagStack)-1]
return
}
// Attr adds an attribute to the current DIE.
func (b *Builder) Attr(attr dwarf.Attr, val interface{}) {
if len(b.tagStack) < 0 {
panic("Attr with no open tags")
}
tag := b.tagStack[len(b.tagStack)-1]
if tag.children {
panic("Can't add attributes after adding children")
}
tag.attr = append(tag.attr, attr)
switch x := val.(type) {
case string:
tag.form = append(tag.form, DW_FORM_string)
b.info.Write([]byte(x))
b.info.WriteByte(0)
case uint8:
tag.form = append(tag.form, DW_FORM_data1)
binary.Write(&b.info, binary.LittleEndian, x)
case uint16:
tag.form = append(tag.form, DW_FORM_data2)
binary.Write(&b.info, binary.LittleEndian, x)
case Address:
tag.form = append(tag.form, DW_FORM_addr)
binary.Write(&b.info, binary.LittleEndian, x)
case dwarf.Offset:
tag.form = append(tag.form, DW_FORM_ref_addr)
binary.Write(&b.info, binary.LittleEndian, x)
case []byte:
tag.form = append(tag.form, DW_FORM_block4)
binary.Write(&b.info, binary.LittleEndian, uint32(len(x)))
b.info.Write(x)
case []LocEntry:
tag.form = append(tag.form, DW_FORM_sec_offset)
binary.Write(&b.info, binary.LittleEndian, uint32(b.loc.Len()))
// base address
binary.Write(&b.loc, binary.LittleEndian, ^uint64(0))
binary.Write(&b.loc, binary.LittleEndian, uint64(0))
for _, locentry := range x {
binary.Write(&b.loc, binary.LittleEndian, uint64(locentry.Lowpc))
binary.Write(&b.loc, binary.LittleEndian, uint64(locentry.Highpc))
binary.Write(&b.loc, binary.LittleEndian, uint16(len(locentry.Loc)))
b.loc.Write(locentry.Loc)
}
// end of loclist
binary.Write(&b.loc, binary.LittleEndian, uint64(0))
binary.Write(&b.loc, binary.LittleEndian, uint64(0))
default:
panic("unknown value type")
}
}
func sameTagDescr(a, b tagDescr) bool {
if a.tag != b.tag {
return false
}
if len(a.attr) != len(b.attr) {
return false
}
if a.children != b.children {
return false
}
for i := range a.attr {
if a.attr[i] != b.attr[i] {
return false
}
if a.form[i] != b.form[i] {
return false
}
}
return true
}
// abbrevFor returns an abbrev for the given entry description. If no abbrev
// for tag already exist a new one is created.
func (b *Builder) abbrevFor(tag tagDescr) byte {
for abbrev, descr := range b.abbrevs {
if sameTagDescr(descr, tag) {
return byte(abbrev + 1)
}
}
b.abbrevs = append(b.abbrevs, tag)
return byte(len(b.abbrevs))
}
func (b *Builder) makeAbbrevTable() []byte {
var abbrev bytes.Buffer
for i := range b.abbrevs {
util.EncodeULEB128(&abbrev, uint64(i+1))
util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].tag))
if b.abbrevs[i].children {
abbrev.WriteByte(0x01)
} else {
abbrev.WriteByte(0x00)
}
for j := range b.abbrevs[i].attr {
util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].attr[j]))
util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].form[j]))
}
util.EncodeULEB128(&abbrev, 0)
util.EncodeULEB128(&abbrev, 0)
}
return abbrev.Bytes()
}
// AddSubprogram adds a subprogram declaration to debug_info, must call
// TagClose after adding all local variables and parameters.
// Will write an abbrev corresponding to a DW_TAG_subprogram, followed by a
// DW_AT_lowpc and a DW_AT_highpc.
func (b *Builder) AddSubprogram(fnname string, lowpc, highpc uint64) dwarf.Offset {
r := b.TagOpen(dwarf.TagSubprogram, fnname)
b.Attr(dwarf.AttrLowpc, Address(lowpc))
b.Attr(dwarf.AttrHighpc, Address(highpc))
return r
}
// AddVariable adds a new variable entry to debug_info.
// Will write a DW_TAG_variable, followed by a DW_AT_type and a
// DW_AT_location.
func (b *Builder) AddVariable(varname string, typ dwarf.Offset, loc interface{}) dwarf.Offset {
r := b.TagOpen(dwarf.TagVariable, varname)
b.Attr(dwarf.AttrType, typ)
b.Attr(dwarf.AttrLocation, loc)
b.TagClose()
return r
}
// AddBaseType adds a new base type entry to debug_info.
// Will write a DW_TAG_base_type, followed by a DW_AT_encoding and a
// DW_AT_byte_size.
func (b *Builder) AddBaseType(typename string, encoding Encoding, byteSz uint16) dwarf.Offset {
r := b.TagOpen(dwarf.TagBaseType, typename)
b.Attr(dwarf.AttrEncoding, uint16(encoding))
b.Attr(dwarf.AttrByteSize, byteSz)
b.TagClose()
return r
}
// AddStructType adds a new structure type to debug_info. Call TagClose to
// finish adding fields.
// Will write a DW_TAG_struct_type, followed by a DW_AT_byte_size.
func (b *Builder) AddStructType(typename string, byteSz uint16) dwarf.Offset {
r := b.TagOpen(dwarf.TagStructType, typename)
b.Attr(dwarf.AttrByteSize, byteSz)
return r
}
// AddMember adds a new member entry to debug_info.
// Writes a DW_TAG_member followed by DW_AT_type and DW_AT_data_member_loc.
func (b *Builder) AddMember(fieldname string, typ dwarf.Offset, memberLoc []byte) dwarf.Offset {
r := b.TagOpen(dwarf.TagMember, fieldname)
b.Attr(dwarf.AttrType, typ)
b.Attr(dwarf.AttrDataMemberLoc, memberLoc)
b.TagClose()
return r
}
package dwarfbuilder
import (
"bytes"
"github.com/derekparker/delve/pkg/dwarf/op"
"github.com/derekparker/delve/pkg/dwarf/util"
)
// LocEntry represents one entry of debug_loc.
type LocEntry struct {
Lowpc uint64
Highpc uint64
Loc []byte
}
// LocationBlock returns a DWARF expression corresponding to the list of
// arguments.
func LocationBlock(args ...interface{}) []byte {
var buf bytes.Buffer
for _, arg := range args {
switch x := arg.(type) {
case op.Opcode:
buf.WriteByte(byte(x))
case int:
util.EncodeSLEB128(&buf, int64(x))
case uint:
util.EncodeULEB128(&buf, uint64(x))
default:
panic("unsupported value type")
}
}
return buf.Bytes()
}
......@@ -625,16 +625,16 @@ func readType(d *dwarf.Data, name string, r *dwarf.Reader, off dwarf.Offset, typ
break
}
b := util.MakeBuf(d, util.UnknownFormat{}, "location", 0, loc)
op_ := b.Uint8()
op_ := op.Opcode(b.Uint8())
switch op_ {
case op.DW_OP_plus_uconsts:
case op.DW_OP_plus_uconst:
// Handle opcode sequence [DW_OP_plus_uconst <uleb128>]
f.ByteOffset = int64(b.Uint())
b.AssertEmpty()
case op.DW_OP_consts:
// Handle opcode sequence [DW_OP_consts <sleb128> DW_OP_plus]
f.ByteOffset = b.Int()
op_ = b.Uint8()
op_ = op.Opcode(b.Uint8())
if op_ != op.DW_OP_plus {
err = dwarf.DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op_)}
goto Error
......
......@@ -140,7 +140,7 @@ var NoSourceError = errors.New("no source available")
func (lineInfo *DebugLineInfo) AllPCsBetween(begin, end uint64) ([]uint64, error) {
if lineInfo == nil {
return nil, nil
return nil, NoSourceError
}
var (
......
......@@ -26,12 +26,14 @@ type context struct {
DwarfRegisters
}
var oplut = map[byte]stackfn{
type Opcode byte
var oplut = map[Opcode]stackfn{
DW_OP_call_frame_cfa: callframecfa,
DW_OP_plus: plus,
DW_OP_consts: consts,
DW_OP_addr: addr,
DW_OP_plus_uconsts: plusuconsts,
DW_OP_plus_uconst: plusuconsts,
}
func ExecuteStackProgram(regs DwarfRegisters, instructions []byte) (int64, error) {
......
package op
const (
DW_OP_addr Opcode = 0x03 // implemented
DW_OP_deref Opcode = 0x06
DW_OP_const1u Opcode = 0x08
DW_OP_const1s Opcode = 0x09
DW_OP_const2u Opcode = 0x0a
DW_OP_const2s Opcode = 0x0b
DW_OP_const4u Opcode = 0x0c
DW_OP_const4s Opcode = 0x0d
DW_OP_const8u Opcode = 0x0e
DW_OP_const8s Opcode = 0x0f
DW_OP_constu Opcode = 0x10
DW_OP_consts Opcode = 0x11 // implemented
DW_OP_dup Opcode = 0x12
DW_OP_drop Opcode = 0x13
DW_OP_over Opcode = 0x14
DW_OP_pick Opcode = 0x15
DW_OP_swap Opcode = 0x16
DW_OP_rot Opcode = 0x17
DW_OP_xderef Opcode = 0x18
DW_OP_abs Opcode = 0x19
DW_OP_and Opcode = 0x1a
DW_OP_div Opcode = 0x1b
DW_OP_minus Opcode = 0x1c
DW_OP_mod Opcode = 0x1d
DW_OP_mul Opcode = 0x1e
DW_OP_neg Opcode = 0x1f
DW_OP_not Opcode = 0x20
DW_OP_or Opcode = 0x21
DW_OP_plus Opcode = 0x22 // implemented
DW_OP_plus_uconst Opcode = 0x23 // implemented
DW_OP_shl Opcode = 0x24
DW_OP_shr Opcode = 0x25
DW_OP_shra Opcode = 0x26
DW_OP_xor Opcode = 0x27
DW_OP_bra Opcode = 0x28
DW_OP_eq Opcode = 0x29
DW_OP_ge Opcode = 0x2a
DW_OP_gt Opcode = 0x2b
DW_OP_le Opcode = 0x2c
DW_OP_lt Opcode = 0x2d
DW_OP_ne Opcode = 0x2e
DW_OP_skip Opcode = 0x2f
DW_OP_lit0 Opcode = 0x30
DW_OP_lit1 Opcode = 0x31
DW_OP_lit2 Opcode = 0x32
DW_OP_lit3 Opcode = 0x33
DW_OP_lit4 Opcode = 0x34
DW_OP_lit5 Opcode = 0x35
DW_OP_lit6 Opcode = 0x36
DW_OP_lit7 Opcode = 0x37
DW_OP_lit8 Opcode = 0x38
DW_OP_lit9 Opcode = 0x39
DW_OP_lit10 Opcode = 0x3a
DW_OP_lit11 Opcode = 0x3b
DW_OP_lit12 Opcode = 0x3c
DW_OP_lit13 Opcode = 0x3d
DW_OP_lit14 Opcode = 0x3e
DW_OP_lit15 Opcode = 0x3f
DW_OP_lit16 Opcode = 0x40
DW_OP_lit17 Opcode = 0x41
DW_OP_lit18 Opcode = 0x42
DW_OP_lit19 Opcode = 0x43
DW_OP_lit20 Opcode = 0x44
DW_OP_lit21 Opcode = 0x45
DW_OP_lit22 Opcode = 0x46
DW_OP_lit23 Opcode = 0x47
DW_OP_lit24 Opcode = 0x48
DW_OP_lit25 Opcode = 0x49
DW_OP_lit26 Opcode = 0x4a
DW_OP_lit27 Opcode = 0x4b
DW_OP_lit28 Opcode = 0x4c
DW_OP_lit29 Opcode = 0x4d
DW_OP_lit30 Opcode = 0x4e
DW_OP_lit31 Opcode = 0x4f
DW_OP_reg0 Opcode = 0x50
DW_OP_reg1 Opcode = 0x51
DW_OP_reg2 Opcode = 0x52
DW_OP_reg3 Opcode = 0x53
DW_OP_reg4 Opcode = 0x54
DW_OP_reg5 Opcode = 0x55
DW_OP_reg6 Opcode = 0x56
DW_OP_reg7 Opcode = 0x57
DW_OP_reg8 Opcode = 0x58
DW_OP_reg9 Opcode = 0x59
DW_OP_reg10 Opcode = 0x5a
DW_OP_reg11 Opcode = 0x5b
DW_OP_reg12 Opcode = 0x5c
DW_OP_reg13 Opcode = 0x5d
DW_OP_reg14 Opcode = 0x5e
DW_OP_reg15 Opcode = 0x5f
DW_OP_reg16 Opcode = 0x60
DW_OP_reg17 Opcode = 0x61
DW_OP_reg18 Opcode = 0x62
DW_OP_reg19 Opcode = 0x63
DW_OP_reg20 Opcode = 0x64
DW_OP_reg21 Opcode = 0x65
DW_OP_reg22 Opcode = 0x66
DW_OP_reg23 Opcode = 0x67
DW_OP_reg24 Opcode = 0x68
DW_OP_reg25 Opcode = 0x69
DW_OP_reg26 Opcode = 0x6a
DW_OP_reg27 Opcode = 0x6b
DW_OP_reg28 Opcode = 0x6c
DW_OP_reg29 Opcode = 0x6d
DW_OP_reg30 Opcode = 0x6e
DW_OP_reg31 Opcode = 0x6f
DW_OP_breg0 Opcode = 0x70
DW_OP_breg1 Opcode = 0x71
DW_OP_breg2 Opcode = 0x72
DW_OP_breg3 Opcode = 0x73
DW_OP_breg4 Opcode = 0x74
DW_OP_breg5 Opcode = 0x75
DW_OP_breg6 Opcode = 0x76
DW_OP_breg7 Opcode = 0x77
DW_OP_breg8 Opcode = 0x78
DW_OP_breg9 Opcode = 0x79
DW_OP_breg10 Opcode = 0x7a
DW_OP_breg11 Opcode = 0x7b
DW_OP_breg12 Opcode = 0x7c
DW_OP_breg13 Opcode = 0x7d
DW_OP_breg14 Opcode = 0x7e
DW_OP_breg15 Opcode = 0x7f
DW_OP_breg16 Opcode = 0x80
DW_OP_breg17 Opcode = 0x81
DW_OP_breg18 Opcode = 0x82
DW_OP_breg19 Opcode = 0x83
DW_OP_breg20 Opcode = 0x84
DW_OP_breg21 Opcode = 0x85
DW_OP_breg22 Opcode = 0x86
DW_OP_breg23 Opcode = 0x87
DW_OP_breg24 Opcode = 0x88
DW_OP_breg25 Opcode = 0x89
DW_OP_breg26 Opcode = 0x8a
DW_OP_breg27 Opcode = 0x8b
DW_OP_breg28 Opcode = 0x8c
DW_OP_breg29 Opcode = 0x8d
DW_OP_breg30 Opcode = 0x8e
DW_OP_breg31 Opcode = 0x8f
DW_OP_regx Opcode = 0x90
DW_OP_fbreg Opcode = 0x91
DW_OP_bregx Opcode = 0x92
DW_OP_piece Opcode = 0x93
DW_OP_deref_size Opcode = 0x94
DW_OP_xderef_size Opcode = 0x95
DW_OP_nop Opcode = 0x96
// DWARF 3 extensions.
DW_OP_push_object_address Opcode = 0x97
DW_OP_call2 Opcode = 0x98
DW_OP_call4 Opcode = 0x99
DW_OP_call_ref Opcode = 0x9a
DW_OP_form_tls_address Opcode = 0x9b
DW_OP_call_frame_cfa Opcode = 0x9c // implemented
DW_OP_bit_piece Opcode = 0x9d
// DWARF 4 extensions.
DW_OP_implicit_value Opcode = 0x9e
DW_OP_stack_value Opcode = 0x9f
)
package util
import "bytes"
import (
"bytes"
"io"
)
// The Little Endian Base 128 format is defined in the DWARF v4 standard,
// section 7.6, page 161 and following.
// DecodeULEB128 decodes an unsigned Little Endian Base 128
// represented number.
......@@ -71,6 +77,45 @@ func DecodeSLEB128(buf *bytes.Buffer) (int64, uint32) {
return result, length
}
// EncodeULEB128 encodes x to the unsigned Little Endian Base 128 format
// into out.
func EncodeULEB128(out io.ByteWriter, x uint64) {
for {
b := byte(x & 0x7f)
x = x >> 7
if x != 0 {
b = b | 0x80
}
out.WriteByte(b)
if x == 0 {
break
}
}
}
// EncodeSLEB128 encodes x to the signed Little Endian Base 128 format
// into out.
func EncodeSLEB128(out io.ByteWriter, x int64) {
for {
b := byte(x & 0x7f)
x >>= 7
signb := b & 0x40
last := false
if (x == 0 && signb == 0) || (x == -1 && signb != 0) {
last = true
} else {
b = b | 0x80
}
out.WriteByte(b)
if last {
break
}
}
}
func ParseString(data *bytes.Buffer) (string, uint32) {
str, err := data.ReadString(0x0)
if err != nil {
......
......@@ -27,6 +27,42 @@ func TestDecodeSLEB128(t *testing.T) {
}
}
func TestEncodeULEB128(t *testing.T) {
tc := []uint64{0x00, 0x7f, 0x80, 0x8f, 0xffff, 0xfffffff7}
for i := range tc {
var buf bytes.Buffer
EncodeULEB128(&buf, tc[i])
enc := append([]byte{}, buf.Bytes()...)
buf.Write([]byte{0x1, 0x2, 0x3})
out, c := DecodeULEB128(&buf)
t.Logf("input %x output %x encoded %x", tc[i], out, enc)
if c != uint32(len(enc)) {
t.Errorf("wrong encode")
}
if out != tc[i] {
t.Errorf("wrong encode")
}
}
}
func TestEncodeSLEB128(t *testing.T) {
tc := []int64{2, -2, 127, -127, 128, -128, 129, -129}
for i := range tc {
var buf bytes.Buffer
EncodeSLEB128(&buf, tc[i])
enc := append([]byte{}, buf.Bytes()...)
buf.Write([]byte{0x1, 0x2, 0x3})
out, c := DecodeSLEB128(&buf)
t.Logf("input %x output %x encoded %x", tc[i], out, enc)
if c != uint32(len(enc)) {
t.Errorf("wrong encode")
}
if out != tc[i] {
t.Errorf("wrong encode")
}
}
}
func TestParseString(t *testing.T) {
bstr := bytes.NewBuffer([]byte{'h', 'i', 0x0, 0xFF, 0xCC})
str, _ := ParseString(bstr)
......
......@@ -224,6 +224,25 @@ func (bi *BinaryInfo) LoadError() error {
return bi.loadErr
}
type nilCloser struct{}
func (c *nilCloser) Close() error { return nil }
// New creates a new BinaryInfo object using the specified data. Use LoadBinary instead.
func (bi *BinaryInfo) LoadFromData(dwdata *dwarf.Data, debugFrameBytes []byte, debugLineBytes []byte) {
bi.closer = (*nilCloser)(nil)
bi.dwarf = dwdata
if debugFrameBytes != nil {
bi.frameEntries = frame.Parse(debugFrameBytes, frame.DwarfEndian(debugFrameBytes))
}
var wg sync.WaitGroup
wg.Add(1)
go bi.loadDebugInfoMaps(debugLineBytes, &wg)
wg.Wait()
}
// ELF ///////////////////////////////////////////////////////////////
func (bi *BinaryInfo) LoadBinaryInfoElf(path string, wg *sync.WaitGroup) error {
......
// Tests for loading variables that have complex location expressions. They
// are only produced for optimized code (for both Go and C) therefore we can
// not get the compiler to produce them reliably enough for tests.
package proc_test
import (
"bytes"
"debug/dwarf"
"encoding/binary"
"fmt"
"go/constant"
"testing"
"github.com/derekparker/delve/pkg/dwarf/dwarfbuilder"
"github.com/derekparker/delve/pkg/dwarf/godwarf"
"github.com/derekparker/delve/pkg/dwarf/op"
"github.com/derekparker/delve/pkg/proc"
)
const defaultCFA = 0xc420051d00
func fakeBinaryInfo(t *testing.T, dwb *dwarfbuilder.Builder) *proc.BinaryInfo {
abbrev, aranges, frame, info, line, pubnames, ranges, str, err := dwb.Build()
assertNoError(err, t, "dwarbuilder.Build")
dwdata, err := dwarf.New(abbrev, aranges, frame, info, line, pubnames, ranges, str)
assertNoError(err, t, "creating dwarf")
bi := proc.NewBinaryInfo("linux", "amd64")
bi.LoadFromData(dwdata, frame, line)
return &bi
}
// fakeMemory implements proc.MemoryReadWriter by reading from a byte slice.
// Byte 0 of "data" is at address "base".
type fakeMemory struct {
base uint64
data []byte
}
func newFakeMemory(base uint64, contents ...interface{}) *fakeMemory {
mem := &fakeMemory{base: base}
var buf bytes.Buffer
for _, x := range contents {
binary.Write(&buf, binary.LittleEndian, x)
}
mem.data = buf.Bytes()
return mem
}
func (mem *fakeMemory) ReadMemory(data []byte, addr uintptr) (int, error) {
if uint64(addr) < mem.base {
return 0, fmt.Errorf("read out of bounds %d %#x", len(data), addr)
}
start := uint64(addr) - mem.base
end := uint64(len(data)) + start
if end > uint64(len(mem.data)) {
panic(fmt.Errorf("read out of bounds %d %#x", len(data), addr))
}
copy(data, mem.data[start:end])
return len(data), nil
}
func (mem *fakeMemory) WriteMemory(uintptr, []byte) (int, error) {
return 0, fmt.Errorf("not implemented")
}
// fakeRegisters implements op.DwarfRegisters with arbitrary values for each
// register.
type fakeRegisters struct {
regs [32]uint64
}
func (regs *fakeRegisters) Set(i int, val uint64) {
regs.regs[i] = val
}
func (regs *fakeRegisters) Get(i int) []byte {
var out bytes.Buffer
binary.Write(&out, binary.LittleEndian, regs.regs[i])
return out.Bytes()
}
func uintExprCheck(t *testing.T, scope *proc.EvalScope, expr string, tgt uint64) {
thevar, err := scope.EvalExpression(expr, normalLoadConfig)
assertNoError(err, t, fmt.Sprintf("EvalExpression(%s)", expr))
if thevar.Unreadable != nil {
t.Errorf("variable %q unreadable: %v", expr, thevar.Unreadable)
} else {
if v, _ := constant.Uint64Val(thevar.Value); v != tgt {
t.Errorf("expected value %x got %x for %q", tgt, v, expr)
}
}
}
func dwarfExprCheck(t *testing.T, mem proc.MemoryReadWriter, regs op.DwarfRegisters, bi *proc.BinaryInfo, testCases map[string]uint16) *proc.EvalScope {
scope := &proc.EvalScope{PC: 0x40100, CFA: defaultCFA, Mem: mem, Gvar: nil, BinInfo: bi}
for name, value := range testCases {
uintExprCheck(t, scope, name, uint64(value))
}
return scope
}
func TestDwarfExprRegisters(t *testing.T) {
testCases := map[string]uint16{
"a": 0x1234,
"b": 0x4321,
"c": 0x2143,
}
dwb := dwarfbuilder.New()
uint16off := dwb.BaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
dwb.Subprogram("main.main", 0x40100, 0x41000)
dwb.Attr(dwarf.AttrFrameBase, dwarfbuilder.LocationBlock(op.DW_OP_call_frame_cfa))
dwb.Variable("a", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_reg0))
dwb.Variable("b", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_fbreg, int(8)))
dwb.Variable("c", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_regx, int(1)))
dwb.TagClose()
bi := fakeBinaryInfo(t, dwb)
mem := newFakeMemory(defaultCFA, uint64(0), uint64(testCases["b"]), uint16(testCases["pair.v"]))
var regs fakeRegisters
regs.Set(0, uint64(testCases["a"]))
regs.Set(1, uint64(testCases["c"]))
dwarfExprCheck(t, mem, &regs, bi, testCases)
}
func TestDwarfExprComposite(t *testing.T) {
testCases := map[string]uint16{
"pair.k": 0x8765,
"pair.v": 0x5678,
}
const stringVal = "this is a string"
dwb := dwarfbuilder.New()
uint16off := dwb.BaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
intoff := dwb.BaseType("int", dwarfbuilder.DW_ATE_signed, 8)
byteoff := dwb.BaseType("uint8", dwarfbuilder.DW_ATE_unsigned, 1)
byteptroff := dwb.TagOpen(dwarf.TagPointerType, "*uint8")
dwb.Attr(godwarf.AttrGoKind, uint8(22))
dwb.Attr(dwarf.AttrType, byteoff)
dwb.TagClose()
pairoff := dwb.StructType("main.pair", 4)
dwb.Attr(godwarf.AttrGoKind, uint8(25))
dwb.Member("k", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(0)))
dwb.Member("v", uint16off, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(2)))
dwb.TagClose()
stringoff := dwb.StructType("string", 16)
dwb.Attr(godwarf.AttrGoKind, uint8(24))
dwb.Member("str", byteptroff, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(0)))
dwb.Member("len", intoff, dwarfbuilder.LocationBlock(op.DW_OP_plus_uconst, uint(8)))
dwb.TagClose()
dwb.Subprogram("main.main", 0x40100, 0x41000)
dwb.Variable("pair", pairoff, dwarfbuilder.LocationBlock(
op.DW_OP_reg2, op.DW_OP_piece, uint(2),
op.DW_OP_call_frame_cfa, op.DW_OP_consts, int(16), op.DW_OP_plus, op.DW_OP_piece, uint(2)))
dwb.Variable("s", stringoff, dwarfbuilder.LocationBlock(
op.DW_OP_reg1, op.DW_OP_piece, uint(8),
op.DW_OP_reg0, op.DW_OP_piece, uint(8)))
dwb.TagClose()
bi := fakeBinaryInfo(t, dwb)
mem := newFakeMemory(defaultCFA, uint64(0), uint64(0), uint16(testCases["pair.v"]), stringVal)
var regs fakeRegisters
regs.Set(0, uint64(len(stringVal)))
regs.Set(1, defaultCFA+18)
regs.Set(2, uint64(testCases["pair.k"]))
scope := dwarfExprCheck(t, mem, &regs, bi, testCases)
thevar, err := scope.EvalExpression("s", normalLoadConfig)
assertNoError(err, t, fmt.Sprintf("EvalExpression(s)", "s"))
if thevar.Unreadable != nil {
t.Errorf("variable \"s\" unreadable: %v", thevar.Unreadable)
} else {
if v := constant.StringVal(thevar.Value); v != stringVal {
t.Errorf("expected value %q got %q", stringVal, v)
}
}
}
func TestDwarfExprLoclist(t *testing.T) {
const before = 0x1234
const after = 0x4321
dwb := dwarfbuilder.New()
uint16off := dwb.BaseType("uint16", dwarfbuilder.DW_ATE_unsigned, 2)
dwb.Subprogram("main.main", 0x40100, 0x41000)
dwb.Variable("a", uint16off, []dwarfbuilder.LocEntry{
{0x40100, 0x40700, dwarfbuilder.LocationBlock(op.DW_OP_call_frame_cfa)},
{0x40700, 0x41000, dwarfbuilder.LocationBlock(op.DW_OP_call_frame_cfa, op.DW_OP_consts, int(2), op.DW_OP_plus)},
})
dwb.TagClose()
bi := fakeBinaryInfo(t, dwb)
mem := newFakeMemory(defaultCFA, uint16(before), uint16(after))
scope := &proc.EvalScope{PC: 0x40100, CFA: defaultCFA, Mem: mem, Gvar: nil, BinInfo: bi}
uintExprCheck(t, scope, "a", before)
scope.PC = 0x40800
uintExprCheck(t, scope, "a", after)
}
......@@ -763,11 +763,12 @@ func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry) (*Variable,
}
addr, err := op.ExecuteStackProgram(op.DwarfRegisters{CFA: scope.CFA}, instructions)
v := scope.newVariable(n, uintptr(addr), t)
if err != nil {
return nil, err
v.Unreadable = err
}
return scope.newVariable(n, uintptr(addr), t), nil
return v, nil
}
// If v is a pointer a new variable is returned containing the value pointed by v.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册