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.
|
// 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
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user