1
0
mirror of https://github.com/golang/go synced 2024-10-03 05:11:21 -06:00

debug/dwarf: support for DWARF 3

R=rsc
CC=golang-dev
https://golang.org/cl/7662045
This commit is contained in:
Ian Lance Taylor 2013-03-19 13:59:37 -07:00
parent 47ce4bd353
commit b79afe1b71
4 changed files with 102 additions and 27 deletions

View File

@ -13,17 +13,45 @@ import (
// Data buffer being decoded.
type buf struct {
dwarf *Data
order binary.ByteOrder
name string
off Offset
data []byte
addrsize int
err error
dwarf *Data
order binary.ByteOrder
format dataFormat
name string
off Offset
data []byte
err error
}
func makeBuf(d *Data, name string, off Offset, data []byte, addrsize int) buf {
return buf{d, d.order, name, off, data, addrsize, nil}
// Data format, other than byte order. This affects the handling of
// certain field formats.
type dataFormat interface {
// DWARF version number. Zero means unknown.
version() int
// 64-bit DWARF format?
dwarf64() (dwarf64 bool, isKnown bool)
// Size of an address, in bytes. Zero means unknown.
addrsize() int
}
// Some parts of DWARF have no data format, e.g., abbrevs.
type unknownFormat struct{}
func (u unknownFormat) version() int {
return 0
}
func (u unknownFormat) dwarf64() (bool, bool) {
return false, false
}
func (u unknownFormat) addrsize() int {
return 0
}
func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf {
return buf{d, d.order, format, name, off, data, nil}
}
func (b *buf) uint8() uint8 {
@ -121,7 +149,7 @@ func (b *buf) int() int64 {
// Address-sized uint.
func (b *buf) addr() uint64 {
switch b.addrsize {
switch b.format.addrsize() {
case 1:
return uint64(b.uint8())
case 2:

View File

@ -40,7 +40,7 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
} else {
data = data[off:]
}
b := makeBuf(d, "abbrev", 0, data, 0)
b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
// Error handling is simplified by the buf getters
// returning an endless stream of 0s after an error.
@ -192,7 +192,21 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// reference to other entry
case formRefAddr:
val = Offset(b.addr())
vers := b.format.version()
if vers == 0 {
b.error("unknown version for DW_FORM_ref_addr")
} else if vers == 2 {
val = Offset(b.addr())
} else {
is64, known := b.format.dwarf64()
if !known {
b.error("unknown size for DW_FORM_ref_addr")
} else if is64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
}
}
case formRef1:
val = Offset(b.uint8()) + ubase
case formRef2:
@ -212,7 +226,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
if b.err != nil {
return nil
}
b1 := makeBuf(b.dwarf, "str", 0, b.dwarf.str, 0)
b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
b1.skip(int(off))
val = b1.string()
if b1.err != nil {
@ -262,7 +276,7 @@ func (r *Reader) Seek(off Offset) {
}
u := &d.unit[0]
r.unit = 0
r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
r.b = makeBuf(r.d, u, "info", u.off, u.data)
return
}
@ -273,7 +287,7 @@ func (r *Reader) Seek(off Offset) {
u = &d.unit[i]
if u.off <= off && off < u.off+Offset(len(u.data)) {
r.unit = i
r.b = makeBuf(r.d, "info", off, u.data[off-u.off:], u.addrsize)
r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
return
}
}
@ -285,7 +299,7 @@ func (r *Reader) maybeNextUnit() {
for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
r.unit++
u := &r.d.unit[r.unit]
r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
r.b = makeBuf(r.d, u, "info", u.off, u.data)
}
}

View File

@ -435,7 +435,9 @@ func (d *Data) Type(off Offset) (Type, error) {
goto Error
}
if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
b := makeBuf(d, "location", 0, loc, d.addrsize)
// TODO: Should have original compilation
// unit here, not unknownFormat.
b := makeBuf(d, unknownFormat{}, "location", 0, loc)
if b.uint8() != opPlusUconst {
err = DecodeError{"info", kid.Offset, "unexpected opcode"}
goto Error

View File

@ -10,19 +10,44 @@ import "strconv"
// Each unit has its own abbreviation table and address size.
type unit struct {
base Offset // byte offset of header within the aggregate info
off Offset // byte offset of data within the aggregate info
data []byte
atable abbrevTable
addrsize int
base Offset // byte offset of header within the aggregate info
off Offset // byte offset of data within the aggregate info
data []byte
atable abbrevTable
asize int
vers int
is64 bool // True for 64-bit DWARF format
}
// Implement the dataFormat interface.
func (u *unit) version() int {
return u.vers
}
func (u *unit) dwarf64() (bool, bool) {
return u.is64, true
}
func (u *unit) addrsize() int {
return u.asize
}
func (d *Data) parseUnits() ([]unit, error) {
// Count units.
nunit := 0
b := makeBuf(d, "info", 0, d.info, 0)
b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
for len(b.data) > 0 {
b.skip(int(b.uint32()))
len := b.uint32()
if len == 0xffffffff {
len64 := b.uint64()
if len64 != uint64(uint32(len64)) {
b.error("unit length overflow")
break
}
len = uint32(len64)
}
b.skip(int(len))
nunit++
}
if b.err != nil {
@ -30,16 +55,22 @@ func (d *Data) parseUnits() ([]unit, error) {
}
// Again, this time writing them down.
b = makeBuf(d, "info", 0, d.info, 0)
b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
units := make([]unit, nunit)
for i := range units {
u := &units[i]
u.base = b.off
n := b.uint32()
if vers := b.uint16(); vers != 2 {
if n == 0xffffffff {
u.is64 = true
n = uint32(b.uint64())
}
vers := b.uint16()
if vers != 2 && vers != 3 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
u.vers = int(vers)
atable, err := d.parseAbbrev(b.uint32())
if err != nil {
if b.err == nil {
@ -48,7 +79,7 @@ func (d *Data) parseUnits() ([]unit, error) {
break
}
u.atable = atable
u.addrsize = int(b.uint8())
u.asize = int(b.uint8())
u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1)))
}