This patch to libgo fixes a couple of things in the DWARF line reader. It adds support for DW_AT_high_pc as a constant offset from DW_AT_low_pc. It adds support for DW_AT_ranges. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.7 branch.
This fixes some testsuite failures reported in PR gcc/52583, although that PR was originally just for Solaris issues. Ian
diff -r e4c5f4a31350 libgo/go/debug/dwarf/line.go --- a/libgo/go/debug/dwarf/line.go Wed Aug 22 21:54:46 2012 -0700 +++ b/libgo/go/debug/dwarf/line.go Wed Sep 05 22:20:02 2012 -0700 @@ -67,12 +67,22 @@ switch e.Tag { case TagCompileUnit, TagSubprogram, TagEntryPoint, TagInlinedSubroutine: low, lowok := e.Val(AttrLowpc).(uint64) - high, highok := e.Val(AttrHighpc).(uint64) + var high uint64 + var highok bool + switch v := e.Val(AttrHighpc).(type) { + case uint64: + high = v + highok = true + case int64: + high = low + uint64(v) + highok = true + } if lowok && highok { u.pc = append(u.pc, addrRange{low, high}) - } else if f, ok := e.Val(AttrRanges).(Offset); ok { - // TODO: Handle AttrRanges and .debug_ranges. - _ = f + } else if off, ok := e.Val(AttrRanges).(Offset); ok { + if err := d.readAddressRanges(off, low, u); err != nil { + return err + } } val := e.Val(AttrStmtList) if val != nil { @@ -98,6 +108,38 @@ return nil } +// readAddressRanges adds address ranges to a unit. +func (d *Data) readAddressRanges(off Offset, base uint64, u *unit) error { + b := makeBuf(d, u, "ranges", off, d.ranges[off:]) + var highest uint64 + switch u.addrsize { + case 1: + highest = 0xff + case 2: + highest = 0xffff + case 4: + highest = 0xffffffff + case 8: + highest = 0xffffffffffffffff + default: + return errors.New("unknown address size") + } + for { + if b.err != nil { + return b.err + } + low := b.addr() + high := b.addr() + if low == 0 && high == 0 { + return b.err + } else if low == highest { + base = high + } else { + u.pc = append(u.pc, addrRange{low + base, high + base}) + } + } +} + // findLine finds the line information for a PC value, given the unit // containing the information. func (d *Data) findLine(u *unit, pc uint64) ([]*Line, error) { diff -r e4c5f4a31350 libgo/go/debug/elf/file.go --- a/libgo/go/debug/elf/file.go Wed Aug 22 21:54:46 2012 -0700 +++ b/libgo/go/debug/elf/file.go Wed Sep 05 22:20:02 2012 -0700 @@ -563,7 +563,7 @@ // There are many other DWARF sections, but these // are the required ones, and the debug/dwarf package // does not use the others, so don't bother loading them. - var names = [...]string{"abbrev", "info", "line", "str"} + var names = [...]string{"abbrev", "info", "line", "ranges", "str"} var dat [len(names)][]byte for i, name := range names { name = ".debug_" + name @@ -592,8 +592,8 @@ } } - abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3] - return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str) + abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4] + return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str) } // Symbols returns the symbol table for f.