debug/dwarf: Support DWARF versions 3 and 4.

From-SVN: r185126
This commit is contained in:
Ian Lance Taylor 2012-03-09 06:35:00 +00:00
parent 9916d7ea44
commit 896977b38f
7 changed files with 108 additions and 40 deletions

View File

@ -13,17 +13,17 @@ 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
u *unit
order binary.ByteOrder
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}
func makeBuf(d *Data, u *unit, name string, off Offset, data []byte) buf {
return buf{d, u, d.order, name, off, data, nil}
}
func (b *buf) uint8() uint8 {
@ -121,15 +121,17 @@ func (b *buf) int() int64 {
// Address-sized uint.
func (b *buf) addr() uint64 {
switch b.addrsize {
case 1:
return uint64(b.uint8())
case 2:
return uint64(b.uint16())
case 4:
return uint64(b.uint32())
case 8:
return uint64(b.uint64())
if b.u != nil {
switch b.u.addrsize {
case 1:
return uint64(b.uint8())
case 2:
return uint64(b.uint16())
case 4:
return uint64(b.uint32())
case 8:
return uint64(b.uint64())
}
}
b.error("unknown address size")
return 0

View File

@ -207,6 +207,11 @@ const (
formRef8 format = 0x14
formRefUdata format = 0x15
formIndirect format = 0x16
// following are defined in DWARF 4
formSecOffset format = 0x17
formExprLoc format = 0x18
formFlagPresent format = 0x19
formRefSig8 format = 0x20
)
// A Tag is the classification (the type) of an Entry.

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, nil, "abbrev", 0, data)
// Error handling is simplified by the buf getters
// returning an endless stream of 0s after an error.
@ -182,13 +182,37 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
case formUdata:
val = int64(b.uint())
// exprloc
case formExprLoc:
val = b.bytes(int(b.uint()))
// flag
case formFlag:
val = b.uint8() == 1
case formFlagPresent:
val = true
// lineptr, loclistptr, macptr, rangelistptr
case formSecOffset:
if b.u == nil {
b.error("unknown size for DW_FORM_sec_offset")
} else if b.u.dwarf64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
}
// reference to other entry
case formRefAddr:
val = Offset(b.addr())
if b.u == nil {
b.error("unknown version for DW_FORM_ref_addr")
} else if b.u.version == 2 {
val = Offset(b.addr())
} else if b.u.dwarf64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
}
case formRef1:
val = Offset(b.uint8()) + ubase
case formRef2:
@ -199,6 +223,8 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
val = Offset(b.uint64()) + ubase
case formRefUdata:
val = Offset(b.uint()) + ubase
case formRefSig8:
val = b.uint64()
// string
case formString:
@ -208,7 +234,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, b.u, "str", 0, b.dwarf.str)
b1.skip(int(off))
val = b1.string()
if b1.err != nil {
@ -251,7 +277,7 @@ func (d *Data) unitReader(i int) *Reader {
r := &Reader{d: d}
r.unit = i
u := &d.unit[i]
r.b = makeBuf(d, "info", u.off, u.data, u.addrsize)
r.b = makeBuf(d, u, "info", u.off, u.data)
return r
}
@ -267,7 +293,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
}
@ -278,7 +304,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
}
}
@ -290,7 +316,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

@ -74,9 +74,17 @@ func (d *Data) readUnitLine(i int, u *unit) error {
// TODO: Handle AttrRanges and .debug_ranges.
_ = f
}
if off, ok := e.Val(AttrStmtList).(int64); ok {
u.lineoff = Offset(off)
setLineOff = true
val := e.Val(AttrStmtList)
if val != nil {
if off, ok := val.(int64); ok {
u.lineoff = Offset(off)
setLineOff = true
} else if off, ok := val.(Offset); ok {
u.lineoff = off
setLineOff = true
} else {
return errors.New("unrecognized format for DW_ATTR_stmt_list")
}
}
if dir, ok := e.Val(AttrCompDir).(string); ok {
u.dir = dir
@ -177,15 +185,15 @@ func (d *Data) parseLine(u *unit) error {
if u.lineoff+1 == 0 {
return errors.New("unknown line offset")
}
b := makeBuf(d, "line", u.lineoff, d.line, u.addrsize)
b := makeBuf(d, u, "line", u.lineoff, d.line[u.lineoff:])
len := uint64(b.uint32())
offSize := 4
dwarf64 := false
if len == 0xffffffff {
len = b.uint64()
offSize = 8
dwarf64 = true
}
end := b.off + Offset(len)
hdr := d.parseLineHdr(u, &b, offSize)
hdr := d.parseLineHdr(u, &b, dwarf64)
if b.err == nil {
d.parseLineProgram(u, &b, hdr, end)
}
@ -193,14 +201,20 @@ func (d *Data) parseLine(u *unit) error {
}
// parseLineHdr parses a line number program header.
func (d *Data) parseLineHdr(u *unit, b *buf, offSize int) (hdr lineHdr) {
func (d *Data) parseLineHdr(u *unit, b *buf, dwarf64 bool) (hdr lineHdr) {
hdr.version = b.uint16()
if hdr.version < 2 || hdr.version > 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(hdr.version)))
return
}
b.bytes(offSize) // header length
var hlen Offset
if dwarf64 {
hlen = Offset(b.uint64())
} else {
hlen = Offset(b.uint32())
}
end := b.off + hlen
hdr.minInsnLen = b.uint8()
if hdr.version < 4 {
@ -241,6 +255,10 @@ func (d *Data) parseLineHdr(u *unit, b *buf, offSize int) (hdr lineHdr) {
hdr.files = append(hdr.files, f)
}
if end > b.off {
b.bytes(int(end - b.off))
}
return
}
@ -296,6 +314,7 @@ func (d *Data) parseLineProgram(u *unit, b *buf, hdr lineHdr, end Offset) {
u.lines = append(u.lines, lines...)
lineInfo = resetLineInfo
lines = nil
newLineInfo = true
case LineExtSetAddress:
address = b.addr()
case LineExtDefineFile:

View File

@ -24,7 +24,6 @@ type Data struct {
// parsed data
abbrevCache map[uint32]abbrevTable
addrsize int
order binary.ByteOrder
typeCache map[Offset]Type
unit []unit

View File

@ -435,7 +435,7 @@ 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)
b := makeBuf(d, nil, "location", 0, loc)
if b.uint8() != opPlusUconst {
err = DecodeError{"info", kid.Offset, "unexpected opcode"}
goto Error

View File

@ -16,6 +16,8 @@ type unit struct {
data []byte
atable abbrevTable
addrsize int
version int
dwarf64 bool // True for 64-bit DWARF format
dir string
pc []addrRange // PC ranges in this compilation unit
lines []mapLineInfo // PC -> line mapping
@ -30,9 +32,18 @@ type addrRange struct {
func (d *Data) parseUnits() ([]unit, error) {
// Count units.
nunit := 0
b := makeBuf(d, "info", 0, d.info, 0)
b := makeBuf(d, nil, "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(int(len64)) {
b.error("unit length overflow")
break
}
len = uint32(len64)
}
b.skip(int(len))
nunit++
}
if b.err != nil {
@ -40,13 +51,18 @@ func (d *Data) parseUnits() ([]unit, error) {
}
// Again, this time writing them down.
b = makeBuf(d, "info", 0, d.info, 0)
b = makeBuf(d, nil, "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.dwarf64 = true
n = uint32(b.uint64())
}
vers := b.uint16()
if vers < 2 || vers > 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
@ -57,6 +73,7 @@ func (d *Data) parseUnits() ([]unit, error) {
}
break
}
u.version = int(vers)
u.atable = atable
u.addrsize = int(b.uint8())
u.off = b.off