From 896977b38f006cd69ace34097d1d2ee7e4cfa096 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 9 Mar 2012 06:35:00 +0000 Subject: [PATCH] debug/dwarf: Support DWARF versions 3 and 4. From-SVN: r185126 --- libgo/go/debug/dwarf/buf.go | 38 ++++++++++++++++++++------------------ libgo/go/debug/dwarf/const.go | 5 +++++ libgo/go/debug/dwarf/entry.go | 40 +++++++++++++++++++++++++++++++++------- libgo/go/debug/dwarf/line.go | 37 ++++++++++++++++++++++++++++--------- libgo/go/debug/dwarf/open.go | 1 - libgo/go/debug/dwarf/type.go | 2 +- libgo/go/debug/dwarf/unit.go | 25 +++++++++++++++++++++---- 7 files changed, 108 insertions(+), 40 deletions(-) diff --git a/libgo/go/debug/dwarf/buf.go b/libgo/go/debug/dwarf/buf.go index 6dc28d2..08e37be 100644 --- a/libgo/go/debug/dwarf/buf.go +++ b/libgo/go/debug/dwarf/buf.go @@ -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 diff --git a/libgo/go/debug/dwarf/const.go b/libgo/go/debug/dwarf/const.go index 5301edc..ebe9a71 100644 --- a/libgo/go/debug/dwarf/const.go +++ b/libgo/go/debug/dwarf/const.go @@ -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. diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go index f9a4c1b..4761d74 100644 --- a/libgo/go/debug/dwarf/entry.go +++ b/libgo/go/debug/dwarf/entry.go @@ -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) } } diff --git a/libgo/go/debug/dwarf/line.go b/libgo/go/debug/dwarf/line.go index 091ebe0..f9c77cc 100644 --- a/libgo/go/debug/dwarf/line.go +++ b/libgo/go/debug/dwarf/line.go @@ -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: diff --git a/libgo/go/debug/dwarf/open.go b/libgo/go/debug/dwarf/open.go index 37a518b..75798925 100644 --- a/libgo/go/debug/dwarf/open.go +++ b/libgo/go/debug/dwarf/open.go @@ -24,7 +24,6 @@ type Data struct { // parsed data abbrevCache map[uint32]abbrevTable - addrsize int order binary.ByteOrder typeCache map[Offset]Type unit []unit diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go index 4502355..2ef8ca0 100644 --- a/libgo/go/debug/dwarf/type.go +++ b/libgo/go/debug/dwarf/type.go @@ -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 diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go index 931468a..b190320 100644 --- a/libgo/go/debug/dwarf/unit.go +++ b/libgo/go/debug/dwarf/unit.go @@ -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 -- 2.7.4