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

View File

@ -207,6 +207,11 @@ const (
formRef8 format = 0x14 formRef8 format = 0x14
formRefUdata format = 0x15 formRefUdata format = 0x15
formIndirect format = 0x16 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. // 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 { } else {
data = data[off:] 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 // 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.
@ -182,13 +182,37 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
case formUdata: case formUdata:
val = int64(b.uint()) val = int64(b.uint())
// exprloc
case formExprLoc:
val = b.bytes(int(b.uint()))
// flag // flag
case formFlag: case formFlag:
val = b.uint8() == 1 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 // reference to other entry
case formRefAddr: 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: case formRef1:
val = Offset(b.uint8()) + ubase val = Offset(b.uint8()) + ubase
case formRef2: case formRef2:
@ -199,6 +223,8 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
val = Offset(b.uint64()) + ubase val = Offset(b.uint64()) + ubase
case formRefUdata: case formRefUdata:
val = Offset(b.uint()) + ubase val = Offset(b.uint()) + ubase
case formRefSig8:
val = b.uint64()
// string // string
case formString: case formString:
@ -208,7 +234,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, b.u, "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 {
@ -251,7 +277,7 @@ func (d *Data) unitReader(i int) *Reader {
r := &Reader{d: d} r := &Reader{d: d}
r.unit = i r.unit = i
u := &d.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 return r
} }
@ -267,7 +293,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
} }
@ -278,7 +304,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
} }
} }
@ -290,7 +316,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

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

View File

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

View File

@ -435,7 +435,7 @@ 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) b := makeBuf(d, nil, "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

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