debug/dwarf: support 64-bit DWARF in byte order check

Also fix 64-bit DWARF to read a 64-bit abbrev offset in the
    compilation unit.
    
    This is a backport of https://golang.org/cl/71171, which will be in
    the Go 1.10 release, to the gofrontend copy. Doing it now because AIX
    is pretty much the only system that uses 64-bit DWARF.
    
    Reviewed-on: https://go-review.googlesource.com/72250

From-SVN: r253955
This commit is contained in:
Ian Lance Taylor 2017-10-20 18:34:36 +00:00
parent 9401eb0730
commit 001cbba0ef
6 changed files with 88 additions and 17 deletions

View File

@ -1,4 +1,4 @@
44132970e4b6c1186036bf8eda8982fb6e905d6f
a409ac2c78899e638a014c97891925bec93cb3ad
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -33,13 +33,13 @@ type abbrevTable map[uint32]abbrev
// ParseAbbrev returns the abbreviation table that starts at byte off
// in the .debug_abbrev section.
func (d *Data) parseAbbrev(off uint32, vers int) (abbrevTable, error) {
func (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) {
if m, ok := d.abbrevCache[off]; ok {
return m, nil
}
data := d.abbrev
if off > uint32(len(data)) {
if off > uint64(len(data)) {
data = nil
} else {
data = data[off:]

View File

@ -135,3 +135,63 @@ func TestReaderRanges(t *testing.T) {
t.Errorf("saw only %d subprograms, expected %d", i, len(subprograms))
}
}
func Test64Bit(t *testing.T) {
// I don't know how to generate a 64-bit DWARF debug
// compilation unit except by using XCOFF, so this is
// hand-written.
tests := []struct {
name string
info []byte
}{
{
"32-bit little",
[]byte{0x30, 0, 0, 0, // comp unit length
4, 0, // DWARF version 4
0, 0, 0, 0, // abbrev offset
8, // address size
0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
},
},
{
"64-bit little",
[]byte{0xff, 0xff, 0xff, 0xff, // 64-bit DWARF
0x30, 0, 0, 0, 0, 0, 0, 0, // comp unit length
4, 0, // DWARF version 4
0, 0, 0, 0, 0, 0, 0, 0, // abbrev offset
8, // address size
0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
},
},
{
"64-bit big",
[]byte{0xff, 0xff, 0xff, 0xff, // 64-bit DWARF
0, 0, 0, 0, 0, 0, 0, 0x30, // comp unit length
0, 4, // DWARF version 4
0, 0, 0, 0, 0, 0, 0, 0, // abbrev offset
8, // address size
0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
},
},
}
for _, test := range tests {
_, err := New(nil, nil, nil, test.info, nil, nil, nil, nil)
if err != nil {
t.Errorf("%s: %v", test.name, err)
}
}
}

View File

@ -23,7 +23,7 @@ type Data struct {
str []byte
// parsed data
abbrevCache map[uint32]abbrevTable
abbrevCache map[uint64]abbrevTable
order binary.ByteOrder
typeCache map[Offset]Type
typeSigs map[uint64]*typeUnit
@ -48,17 +48,26 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
pubnames: pubnames,
ranges: ranges,
str: str,
abbrevCache: make(map[uint32]abbrevTable),
abbrevCache: make(map[uint64]abbrevTable),
typeCache: make(map[Offset]Type),
typeSigs: make(map[uint64]*typeUnit),
}
// Sniff .debug_info to figure out byte order.
// bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
// 32-bit DWARF: 4 byte length, 2 byte version.
// 64-bit DWARf: 4 bytes of 0xff, 8 byte length, 2 byte version.
if len(d.info) < 6 {
return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
}
x, y := d.info[4], d.info[5]
offset := 4
if d.info[0] == 0xff && d.info[1] == 0xff && d.info[2] == 0xff && d.info[3] == 0xff {
if len(d.info) < 14 {
return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
}
offset = 12
}
// Fetch the version, a tiny 16-bit number (1, 2, 3, 4, 5).
x, y := d.info[offset], d.info[offset+1]
switch {
case x == 0 && y == 0:
return nil, DecodeError{"info", 4, "unsupported version 0"}

View File

@ -38,16 +38,11 @@ func (d *Data) parseTypes(name string, types []byte) error {
b.error("unsupported DWARF version " + strconv.Itoa(vers))
return b.err
}
var ao uint32
var ao uint64
if !dwarf64 {
ao = b.uint32()
ao = uint64(b.uint32())
} else {
ao64 := b.uint64()
if ao64 != uint64(uint32(ao64)) {
b.error("type unit abbrev offset overflow")
return b.err
}
ao = uint32(ao64)
ao = b.uint64()
}
atable, err := d.parseAbbrev(ao, vers)
if err != nil {

View File

@ -61,13 +61,20 @@ func (d *Data) parseUnits() ([]unit, error) {
u.base = b.off
var n Offset
n, u.is64 = b.unitLength()
dataOff := b.off
vers := b.uint16()
if vers != 2 && vers != 3 && vers != 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
u.vers = int(vers)
atable, err := d.parseAbbrev(b.uint32(), u.vers)
var abbrevOff uint64
if u.is64 {
abbrevOff = b.uint64()
} else {
abbrevOff = uint64(b.uint32())
}
atable, err := d.parseAbbrev(abbrevOff, u.vers)
if err != nil {
if b.err == nil {
b.err = err
@ -77,7 +84,7 @@ func (d *Data) parseUnits() ([]unit, error) {
u.atable = atable
u.asize = int(b.uint8())
u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1)))
u.data = b.bytes(int(n - (b.off - dataOff)))
}
if b.err != nil {
return nil, b.err