@@ -14,16 +14,16 @@
// Data buffer being decoded.
type buf struct {
dwarf *Data
+ u *unit
order binary.ByteOrder
name string
off Offset
data []byte
- addrsize int
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 @@
// 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 @@
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 @@
} 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 @@
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 @@
val = Offset(b.uint64()) + ubase
case formRefUdata:
val = Offset(b.uint()) + ubase
+ case formRefSig8:
+ val = b.uint64()
// string
case formString:
@@ -208,7 +234,7 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
// 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 @@
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 @@
}
// 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 @@
hdr.files = append(hdr.files, f)
}
+ if end > b.off {
+ b.bytes(int(end - b.off))
+ }
+
return
}
@@ -296,6 +314,7 @@
u.lines = append(u.lines, lines...)
lineInfo = resetLineInfo
lines = nil
+ newLineInfo = true
case LineExtSetAddress:
address = b.addr()
case LineExtDefineFile:
@@ -24,7 +24,6 @@
// parsed data
abbrevCache map[uint32]abbrevTable
- addrsize int
order binary.ByteOrder
typeCache map[Offset]Type
unit []unit
@@ -435,7 +435,7 @@
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 @@
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 @@
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 @@
}
// 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 @@
}
break
}
+ u.version = int(vers)
u.atable = atable
u.addrsize = int(b.uint8())
u.off = b.off