debug/dwarf: support 64-bit DWARF in byte order check
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 20 Oct 2017 18:34:36 +0000 (18:34 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 20 Oct 2017 18:34:36 +0000 (18:34 +0000)
    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

gcc/go/gofrontend/MERGE
libgo/go/debug/dwarf/entry.go
libgo/go/debug/dwarf/entry_test.go
libgo/go/debug/dwarf/open.go
libgo/go/debug/dwarf/typeunit.go
libgo/go/debug/dwarf/unit.go

index 418e1274fdfd15bd951affaa83bdcc6038471aab..8b1846d07c4f3c372aad80cc455875372df8e807 100644 (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.
index 80bf14cb22fd6ec6c23ce8192123dae64e40ed9e..ffa61c28d15b4f55f0cc3bfab9e514a1e54d946d 100644 (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:]
index 58a5d570be56da0a62b14ae5ef0e89ffcd7e59e3..58f3023d296796860bc72f668a4390785ddaa487 100644 (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)
+               }
+       }
+}
index 253a43cf579b331788162c24d995568ac819bad9..938186998ff5c2af2a9e68d342d0314739eb3df1 100644 (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"}
index 652e02d91725c7f5a419f710add28cf0701b996c..76b357ce28b3646ebd9bb5b7c7d8e6c70631f058 100644 (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 {
index e45aed7ad1d7727127473522f66b36a01cc540d7..98024ca1f8459fb1481a7a001528c3d09b65498a 100644 (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