1
0
mirror of https://github.com/golang/go synced 2024-11-20 04:04:41 -07: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. // Data buffer being decoded.
type buf struct { type buf struct {
dwarf *Data dwarf *Data
order binary.ByteOrder order binary.ByteOrder
name string format dataFormat
off Offset name string
data []byte off Offset
addrsize int data []byte
err error err error
} }
func makeBuf(d *Data, name string, off Offset, data []byte, addrsize int) buf { // Data format, other than byte order. This affects the handling of
return buf{d, d.order, name, off, data, addrsize, nil} // 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 { func (b *buf) uint8() uint8 {
@ -121,7 +149,7 @@ func (b *buf) int() int64 {
// Address-sized uint. // Address-sized uint.
func (b *buf) addr() uint64 { func (b *buf) addr() uint64 {
switch b.addrsize { switch b.format.addrsize() {
case 1: case 1:
return uint64(b.uint8()) return uint64(b.uint8())
case 2: case 2:

View File

@ -40,7 +40,7 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
} else { } else {
data = data[off:] 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 // Error handling is simplified by the buf getters
// returning an endless stream of 0s after an error. // 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 // reference to other entry
case formRefAddr: 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: case formRef1:
val = Offset(b.uint8()) + ubase val = Offset(b.uint8()) + ubase
case formRef2: case formRef2:
@ -212,7 +226,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
if b.err != nil { if b.err != nil {
return 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)) b1.skip(int(off))
val = b1.string() val = b1.string()
if b1.err != nil { if b1.err != nil {
@ -262,7 +276,7 @@ func (r *Reader) Seek(off Offset) {
} }
u := &d.unit[0] u := &d.unit[0]
r.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 return
} }
@ -273,7 +287,7 @@ func (r *Reader) Seek(off Offset) {
u = &d.unit[i] u = &d.unit[i]
if u.off <= off && off < u.off+Offset(len(u.data)) { if u.off <= off && off < u.off+Offset(len(u.data)) {
r.unit = i 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 return
} }
} }
@ -285,7 +299,7 @@ func (r *Reader) maybeNextUnit() {
for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) { for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
r.unit++ r.unit++
u := &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 goto Error
} }
if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok { 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 { if b.uint8() != opPlusUconst {
err = DecodeError{"info", kid.Offset, "unexpected opcode"} err = DecodeError{"info", kid.Offset, "unexpected opcode"}
goto Error goto Error

View File

@ -10,19 +10,44 @@ import "strconv"
// Each unit has its own abbreviation table and address size. // Each unit has its own abbreviation table and address size.
type unit struct { type unit struct {
base Offset // byte offset of header within the aggregate info base Offset // byte offset of header within the aggregate info
off Offset // byte offset of data within the aggregate info off Offset // byte offset of data within the aggregate info
data []byte data []byte
atable abbrevTable atable abbrevTable
addrsize int 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) { func (d *Data) parseUnits() ([]unit, error) {
// Count units. // Count units.
nunit := 0 nunit := 0
b := makeBuf(d, "info", 0, d.info, 0) b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
for len(b.data) > 0 { 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++ nunit++
} }
if b.err != nil { if b.err != nil {
@ -30,16 +55,22 @@ func (d *Data) parseUnits() ([]unit, error) {
} }
// Again, this time writing them down. // 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) units := make([]unit, nunit)
for i := range units { for i := range units {
u := &units[i] u := &units[i]
u.base = b.off u.base = b.off
n := b.uint32() 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))) b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break break
} }
u.vers = int(vers)
atable, err := d.parseAbbrev(b.uint32()) atable, err := d.parseAbbrev(b.uint32())
if err != nil { if err != nil {
if b.err == nil { if b.err == nil {
@ -48,7 +79,7 @@ func (d *Data) parseUnits() ([]unit, error) {
break break
} }
u.atable = atable u.atable = atable
u.addrsize = int(b.uint8()) u.asize = int(b.uint8())
u.off = b.off u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1))) u.data = b.bytes(int(n - (2 + 4 + 1)))
} }