diff options
| author | Heschi Kreinick <heschi@google.com> | 2018-06-19 15:41:45 -0400 |
|---|---|---|
| committer | Heschi Kreinick <heschi@google.com> | 2018-06-19 22:13:51 +0000 |
| commit | 2036f16247c6702a95d6c5e876a35c8ef484dbf8 (patch) | |
| tree | ea19351688d7dec0d13f199c900f929a7faaac21 /src/debug/macho | |
| parent | 83515df3f31cc70eab2ea4af77e675cabe1eefd5 (diff) | |
| download | go-2036f16247c6702a95d6c5e876a35c8ef484dbf8.tar.xz | |
debug/elf,macho,pe: support compressed DWARF
Since we're going to start compressing DWARF on Windows and maybe
Darwin, copy the ELF support for .zdebug sections to macho and pe. The
code is almost completely the same across the three.
While I was here I added support for compressed .debug_type sections,
which I presume were overlooked before.
Tests will come in a later CL once we can actually generate compressed
PE/Mach-O binaries, since there's no other good way to get test data.
Updates #25927, #11799
Change-Id: Ie920b6a16e9270bc3df214ce601a263837810376
Reviewed-on: https://go-review.googlesource.com/119815
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/debug/macho')
| -rw-r--r-- | src/debug/macho/file.go | 82 |
1 files changed, 71 insertions, 11 deletions
diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go index da5d9cad4c..16708e5247 100644 --- a/src/debug/macho/file.go +++ b/src/debug/macho/file.go @@ -9,11 +9,13 @@ package macho import ( "bytes" + "compress/zlib" "debug/dwarf" "encoding/binary" "fmt" "io" "os" + "strings" ) // A File represents an open Mach-O file. @@ -575,26 +577,84 @@ func (f *File) Section(name string) *Section { // DWARF returns the DWARF debug information for the Mach-O file. func (f *File) DWARF() (*dwarf.Data, error) { + dwarfSuffix := func(s *Section) string { + switch { + case strings.HasPrefix(s.Name, "__debug_"): + return s.Name[8:] + case strings.HasPrefix(s.Name, "__zdebug_"): + return s.Name[9:] + default: + return "" + } + + } + sectionData := func(s *Section) ([]byte, error) { + b, err := s.Data() + if err != nil && uint64(len(b)) < s.Size { + 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 + } + return b, nil + } + // There are many other DWARF sections, but these // are the ones the debug/dwarf package uses. // Don't bother loading others. - var names = [...]string{"abbrev", "info", "line", "ranges", "str"} - var dat [len(names)][]byte - for i, name := range names { - name = "__debug_" + name - s := f.Section(name) - if s == nil { + var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} + for _, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix == "" { continue } - b, err := s.Data() - if err != nil && uint64(len(b)) < s.Size { + if _, ok := dat[suffix]; !ok { + continue + } + b, err := sectionData(s) + if err != nil { + return nil, err + } + dat[suffix] = b + } + + d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) + if err != nil { + return nil, err + } + + // Look for DWARF4 .debug_types sections. + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix != "types" { + continue + } + + b, err := sectionData(s) + if err != nil { + return nil, err + } + + err = d.AddTypes(fmt.Sprintf("types-%d", i), b) + if err != nil { return nil, err } - dat[i] = b } - abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4] - return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str) + return d, nil } // ImportedSymbols returns the names of all symbols |
