]> Cypherpunks repositories - gostls13.git/commitdiff
dwbug/elf: support old-style compressed DWARF
authorAustin Clements <austin@google.com>
Wed, 2 Dec 2015 03:55:28 +0000 (22:55 -0500)
committerAustin Clements <austin@google.com>
Thu, 3 Dec 2015 20:53:04 +0000 (20:53 +0000)
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 <iant@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/dist/deps.go
src/debug/elf/file.go
src/debug/elf/file_test.go
src/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj [new file with mode: 0644]
src/go/build/deps_test.go

index c15ed8d46559a51af93658257ff06275bb03d10d..9fd98173f315ac3fd00e4b713cc3e18b0c3b841a 100644 (file)
@@ -5,11 +5,13 @@ package main
 var builddeps = map[string][]string{
        "bufio":                             {"bytes", "errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
        "bytes":                             {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
+       "compress/flate":                    {"bufio", "bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "compress/zlib":                     {"bufio", "bytes", "compress/flate", "errors", "fmt", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "container/heap":                    {"runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort"},
        "crypto":                            {"errors", "hash", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
        "crypto/sha1":                       {"crypto", "errors", "hash", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
        "debug/dwarf":                       {"encoding/binary", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "debug/elf":                         {"bytes", "debug/dwarf", "encoding/binary", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "debug/elf":                         {"bufio", "bytes", "compress/flate", "compress/zlib", "debug/dwarf", "encoding/binary", "errors", "fmt", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "debug/macho":                       {"bytes", "debug/dwarf", "encoding/binary", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "encoding":                          {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "encoding/base64":                   {"errors", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
@@ -25,6 +27,7 @@ var builddeps = map[string][]string{
        "go/scanner":                        {"bytes", "errors", "fmt", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "go/token":                          {"errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
        "hash":                              {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
+       "hash/adler32":                      {"errors", "hash", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
        "internal/race":                     {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "internal/singleflight":             {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
        "internal/syscall/windows":          {"errors", "internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "unicode/utf16"},
@@ -57,5 +60,5 @@ var builddeps = map[string][]string{
        "unicode":                 {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "unicode/utf16":           {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "unicode/utf8":            {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
-       "cmd/go":                  {"bufio", "bytes", "container/heap", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "internal/race", "internal/singleflight", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go":                  {"bufio", "bytes", "compress/flate", "compress/zlib", "container/heap", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/singleflight", "internal/syscall/windows", "internal/syscall/windows/registry", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
 }
index 3e766afe15d464d1742d012c30f5d169458de21d..a42bde94f8f3a8a35fc17976eb6886c1ed30dac6 100644 (file)
@@ -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"])
index cd1a4577af262db19f859d38c4b91cbf1befb3a9..6864b6df79f8b10b94272e1356b4684bf369edc9 100644 (file)
@@ -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 (file)
index 0000000..a595a01
Binary files /dev/null and b/src/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj differ
index 45144a23bb7b8c70798af06a7ea8440652deaa26..b16893861eb3e324126c988d4c6bd2cbbe88ba52 100644 (file)
@@ -218,7 +218,7 @@ var pkgDeps = map[string][]string{
        "database/sql":             {"L4", "container/list", "database/sql/driver"},
        "database/sql/driver":      {"L4", "time"},
        "debug/dwarf":              {"L4"},
-       "debug/elf":                {"L4", "OS", "debug/dwarf"},
+       "debug/elf":                {"L4", "OS", "debug/dwarf", "compress/zlib"},
        "debug/gosym":              {"L4"},
        "debug/macho":              {"L4", "OS", "debug/dwarf"},
        "debug/pe":                 {"L4", "OS", "debug/dwarf"},