debug/dwarf: Support DWARF versions 3 and 4.
From-SVN: r185126
This commit is contained in:
parent
9916d7ea44
commit
896977b38f
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -24,7 +24,6 @@ type Data struct {
|
||||
|
||||
// parsed data
|
||||
abbrevCache map[uint32]abbrevTable
|
||||
addrsize int
|
||||
order binary.ByteOrder
|
||||
typeCache map[Offset]Type
|
||||
unit []unit
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user