1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
package godwarf
import (
"bytes"
"compress/zlib"
"debug/elf"
"debug/macho"
"debug/pe"
"encoding/binary"
"fmt"
"io"
)
// GetDebugSectionElf returns the data contents of the specified debug
// section, decompressing it if it is compressed.
// For example GetDebugSectionElf("line") will return the contents of
// .debug_line, if .debug_line doesn't exist it will try to return the
// decompressed contents of .zdebug_line.
func GetDebugSectionElf(f *elf.File, name string) ([]byte, error) {
sec := f.Section(".debug_" + name)
if sec != nil {
return sec.Data()
}
sec = f.Section(".zdebug_" + name)
if sec == nil {
return nil, fmt.Errorf("could not find .debug_%s section", name)
}
b, err := sec.Data()
if err != nil {
return nil, err
}
return decompressMaybe(b)
}
// GetDebugSectionPE returns the data contents of the specified debug
// section, decompressing it if it is compressed.
// For example GetDebugSectionPE("line") will return the contents of
// .debug_line, if .debug_line doesn't exist it will try to return the
// decompressed contents of .zdebug_line.
func GetDebugSectionPE(f *pe.File, name string) ([]byte, error) {
sec := f.Section(".debug_" + name)
if sec != nil {
return peSectionData(sec)
}
sec = f.Section(".zdebug_" + name)
if sec == nil {
return nil, fmt.Errorf("could not find .debug_%s section", name)
}
b, err := peSectionData(sec)
if err != nil {
return nil, err
}
return decompressMaybe(b)
}
func peSectionData(sec *pe.Section) ([]byte, error) {
b, err := sec.Data()
if err != nil {
return nil, err
}
if 0 < sec.VirtualSize && sec.VirtualSize < sec.Size {
b = b[:sec.VirtualSize]
}
return b, nil
}
// GetDebugSectionMacho returns the data contents of the specified debug
// section, decompressing it if it is compressed.
// For example GetDebugSectionMacho("line") will return the contents of
// __debug_line, if __debug_line doesn't exist it will try to return the
// decompressed contents of __zdebug_line.
func GetDebugSectionMacho(f *macho.File, name string) ([]byte, error) {
sec := f.Section("__debug_" + name)
if sec != nil {
return sec.Data()
}
sec = f.Section("__zdebug_" + name)
if sec == nil {
return nil, fmt.Errorf("could not find .debug_%s section", name)
}
b, err := sec.Data()
if err != nil {
return nil, err
}
return decompressMaybe(b)
}
func decompressMaybe(b []byte) ([]byte, error) {
if len(b) < 12 || string(b[:4]) != "ZLIB" {
// not compressed
return b, nil
}
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
}
return dbuf, nil
}
|