From e1544d3bb68d56ebf43cc8828e3dce18fd5ef442 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 1 Dec 2015 22:55:28 -0500 Subject: [PATCH] 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/cmd/dist/deps.go | 7 +++-- src/debug/elf/file.go | 29 ++++++++++++++++-- src/debug/elf/file_test.go | 28 +++++++++++++++++ .../testdata/zdebug-test-gcc484-x86-64.obj | Bin 0 -> 3216 bytes src/go/build/deps_test.go | 2 +- 5 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 src/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj diff --git a/src/cmd/dist/deps.go b/src/cmd/dist/deps.go index c15ed8d465..9fd98173f3 100644 --- a/src/cmd/dist/deps.go +++ b/src/cmd/dist/deps.go @@ -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"}, } 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 0000000000000000000000000000000000000000..a595a01df45c31a5f266f71103eca7a835242996 GIT binary patch literal 3216 zcmbtWeN0ygjgYPu^dzA;$T{`#d0 z;e*CPUV|3*M`tLiJmm}2>21~X3Bmece=xzOwGdZ*&CGi%aV&rAd}i5^LsO=W> z3Po5S|2fa7Nen}8Oh-&BqHp*DHNC}g6TGgpFeV9Y>0KPkPWo-G9UacnEnd}{PrUj4 z*Bgd}<>mI@x1P!3eaHGfoA>uOTw8pmt@6=1T^EXeWiB=MT)~64`?n3(^*wvW@tt|L zIypTl{+y-n#zN~CM{nj|H(fhCF}1mKWY}Gj@X|jY4(z_-`((_*AL%+iI_79w436pp zCr5P42h!(nUpTwYE%+n8OuLys*|q6M?s#gY2kkPOxAFJaSiMek2c+Mm~WZKo?run?0fx zbB|l*jZ|{m9irf|`#eani5?LN*49=exLvX$S^YM<)!R_pb5_R9U+`z zZqeCbhiC=pXmZ*^QMf1)>Ripub|tO9P9u& z|7*Mv$3o69{3wamk5z(LX6x@z!62j&7EJXr3$1K?A-1UXuaWfcG6{hG!5Ojrdjw-_ zP7I+duwW8p7Ft=~T5Mr4aNb0~j8LR3u)g~+thRrHR`yq(|6Lej_wT_Nn-d}{2?+gF z66@>2Mz#7DQlHKl^luG**!rCqgPe4qSd<9v44@BW7Fub2%6qXzE&d@gP!EJ6Wr4;~ z{wj%Q+)xucki>z;QUB8oDLEH027;t-6h6GZ%XM74A3>bYV4d(!{Ib?5!sIaA@snXN+(NPJT6U(uu6Z zVJGp5{?OkKI6KuW(!V&N4mFESPSoP{w95IYFC3$?ONp{sni<&b(y~l&Hv)lwlqAUu z8Dj|t8+~(_TOh#T`34kBG(W|?GK^9PXXiDG;NY)31%mB?q~d4h~7as+n?7M|5HSNhrt(! Zt~^I7gNe=qn?IYxu{cj~xLcI>%fF{QORN9@ literal 0 HcmV?d00001 diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 45144a23bb..b16893861e 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -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"},