Commit 151c66b5 authored by Ian Lance Taylor's avatar Ian Lance Taylor

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.

Change-Id: Idc22e59ffb354d58e9973b62fdbd342acf695859
Reviewed-on: https://go-review.googlesource.com/71171Reviewed-by: default avatarAustin Clements <austin@google.com>
parent 4fe43f81
...@@ -33,13 +33,13 @@ type abbrevTable map[uint32]abbrev ...@@ -33,13 +33,13 @@ type abbrevTable map[uint32]abbrev
// ParseAbbrev returns the abbreviation table that starts at byte off // ParseAbbrev returns the abbreviation table that starts at byte off
// in the .debug_abbrev section. // 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 { if m, ok := d.abbrevCache[off]; ok {
return m, nil return m, nil
} }
data := d.abbrev data := d.abbrev
if off > uint32(len(data)) { if off > uint64(len(data)) {
data = nil data = nil
} else { } else {
data = data[off:] data = data[off:]
......
...@@ -135,3 +135,63 @@ func TestReaderRanges(t *testing.T) { ...@@ -135,3 +135,63 @@ func TestReaderRanges(t *testing.T) {
t.Errorf("saw only %d subprograms, expected %d", i, len(subprograms)) 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)
}
}
}
...@@ -23,7 +23,7 @@ type Data struct { ...@@ -23,7 +23,7 @@ type Data struct {
str []byte str []byte
// parsed data // parsed data
abbrevCache map[uint32]abbrevTable abbrevCache map[uint64]abbrevTable
order binary.ByteOrder order binary.ByteOrder
typeCache map[Offset]Type typeCache map[Offset]Type
typeSigs map[uint64]*typeUnit typeSigs map[uint64]*typeUnit
...@@ -48,17 +48,26 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat ...@@ -48,17 +48,26 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
pubnames: pubnames, pubnames: pubnames,
ranges: ranges, ranges: ranges,
str: str, str: str,
abbrevCache: make(map[uint32]abbrevTable), abbrevCache: make(map[uint64]abbrevTable),
typeCache: make(map[Offset]Type), typeCache: make(map[Offset]Type),
typeSigs: make(map[uint64]*typeUnit), typeSigs: make(map[uint64]*typeUnit),
} }
// Sniff .debug_info to figure out byte order. // 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 { if len(d.info) < 6 {
return nil, DecodeError{"info", Offset(len(d.info)), "too short"} 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 { switch {
case x == 0 && y == 0: case x == 0 && y == 0:
return nil, DecodeError{"info", 4, "unsupported version 0"} return nil, DecodeError{"info", 4, "unsupported version 0"}
......
...@@ -38,16 +38,11 @@ func (d *Data) parseTypes(name string, types []byte) error { ...@@ -38,16 +38,11 @@ func (d *Data) parseTypes(name string, types []byte) error {
b.error("unsupported DWARF version " + strconv.Itoa(vers)) b.error("unsupported DWARF version " + strconv.Itoa(vers))
return b.err return b.err
} }
var ao uint32 var ao uint64
if !dwarf64 { if !dwarf64 {
ao = b.uint32() ao = uint64(b.uint32())
} else { } else {
ao64 := b.uint64() ao = b.uint64()
if ao64 != uint64(uint32(ao64)) {
b.error("type unit abbrev offset overflow")
return b.err
}
ao = uint32(ao64)
} }
atable, err := d.parseAbbrev(ao, vers) atable, err := d.parseAbbrev(ao, vers)
if err != nil { if err != nil {
......
...@@ -61,13 +61,20 @@ func (d *Data) parseUnits() ([]unit, error) { ...@@ -61,13 +61,20 @@ func (d *Data) parseUnits() ([]unit, error) {
u.base = b.off u.base = b.off
var n Offset var n Offset
n, u.is64 = b.unitLength() n, u.is64 = b.unitLength()
dataOff := b.off
vers := b.uint16() vers := b.uint16()
if vers != 2 && vers != 3 && vers != 4 { if vers != 2 && vers != 3 && vers != 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break break
} }
u.vers = int(vers) 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 err != nil {
if b.err == nil { if b.err == nil {
b.err = err b.err = err
...@@ -77,7 +84,7 @@ func (d *Data) parseUnits() ([]unit, error) { ...@@ -77,7 +84,7 @@ func (d *Data) parseUnits() ([]unit, error) {
u.atable = atable u.atable = atable
u.asize = int(b.uint8()) u.asize = int(b.uint8())
u.off = b.off 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 { if b.err != nil {
return nil, b.err return nil, b.err
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment