From e1544d3bb68d56ebf43cc8828e3dce18fd5ef442 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 1 Dec 2015 22:55:28 -0500 Subject: dwbug/elf: support old-style compressed DWARF GCC and LLVM support zlib-compressing DWARF debug sections (and there's some evidence that this may be happening by default in some circumstances now). Add support for reading compressed DWARF sections. Since ELF relocations apply to the decompressed data, decompression is done before applying relocations. Since relcations are applied by debug/elf, decompression must also be handled there. Note that this is different from compressed ELF sections, which is a more general mechanism used by very recent versions of GCC. Updates #11773. Change-Id: I3f4bf1b04d0802cc1e8fcb7c2a5fcf6c467c5089 Reviewed-on: https://go-review.googlesource.com/17340 Reviewed-by: Ian Lance Taylor Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/debug/elf/file.go | 29 ++++++++++++++++++--- src/debug/elf/file_test.go | 28 ++++++++++++++++++++ .../elf/testdata/zdebug-test-gcc484-x86-64.obj | Bin 0 -> 3216 bytes 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 src/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj (limited to 'src/debug/elf') diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go index 3e766afe15..a42bde94f8 100644 --- a/src/debug/elf/file.go +++ b/src/debug/elf/file.go @@ -7,6 +7,7 @@ package elf import ( "bytes" + "compress/zlib" "debug/dwarf" "encoding/binary" "errors" @@ -863,6 +864,22 @@ func (f *File) DWARF() (*dwarf.Data, error) { return nil, err } + if len(b) >= 12 && string(b[:4]) == "ZLIB" { + dlen := binary.BigEndian.Uint64(b[4:12]) + dbuf := make([]byte, dlen) + r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) + if err != nil { + return nil, err + } + if _, err := io.ReadFull(r, dbuf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } + b = dbuf + } + for _, r := range f.Sections { if r.Type != SHT_RELA && r.Type != SHT_REL { continue @@ -887,17 +904,23 @@ func (f *File) DWARF() (*dwarf.Data, error) { // Don't bother loading others. var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil} for i, s := range f.Sections { - if !strings.HasPrefix(s.Name, ".debug_") { + suffix := "" + switch { + case strings.HasPrefix(s.Name, ".debug_"): + suffix = s.Name[7:] + case strings.HasPrefix(s.Name, ".zdebug_"): + suffix = s.Name[8:] + default: continue } - if _, ok := dat[s.Name[7:]]; !ok { + if _, ok := dat[suffix]; !ok { continue } b, err := sectionData(i, s) if err != nil { return nil, err } - dat[s.Name[7:]] = b + dat[suffix] = b } d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, nil, dat["str"]) diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go index cd1a4577af..6864b6df79 100644 --- a/src/debug/elf/file_test.go +++ b/src/debug/elf/file_test.go @@ -514,6 +514,34 @@ func TestDWARFRelocations(t *testing.T) { } } +func TestCompressedDWARF(t *testing.T) { + // Test file built with GCC 4.8.4 and as 2.24 using: + // gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c + f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj") + if err != nil { + t.Fatal(err) + } + dwarf, err := f.DWARF() + if err != nil { + t.Fatal(err) + } + reader := dwarf.Reader() + n := 0 + for { + entry, err := reader.Next() + if err != nil { + t.Fatal(err) + } + if entry == nil { + break + } + n++ + } + if n != 18 { + t.Fatalf("want %d DWARF entries, got %d", 18, n) + } +} + func TestNoSectionOverlaps(t *testing.T) { // Ensure 6l outputs sections without overlaps. if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" { diff --git a/src/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj b/src/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj new file mode 100644 index 0000000000..a595a01df4 Binary files /dev/null and b/src/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj differ -- cgit v1.3