summaryrefslogtreecommitdiff
path: root/libgo/go/debug
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/debug')
-rw-r--r--libgo/go/debug/dwarf/buf.go66
-rw-r--r--libgo/go/debug/dwarf/entry.go27
-rw-r--r--libgo/go/debug/dwarf/line.go2
-rw-r--r--libgo/go/debug/dwarf/type.go4
-rw-r--r--libgo/go/debug/dwarf/unit.go48
-rw-r--r--libgo/go/debug/elf/file.go18
-rw-r--r--libgo/go/debug/gosym/symtab.go123
-rw-r--r--libgo/go/debug/macho/file.go2
8 files changed, 224 insertions, 66 deletions
diff --git a/libgo/go/debug/dwarf/buf.go b/libgo/go/debug/dwarf/buf.go
index 08e37be4b38..53c46eb4b81 100644
--- a/libgo/go/debug/dwarf/buf.go
+++ b/libgo/go/debug/dwarf/buf.go
@@ -13,17 +13,45 @@ import (
// Data buffer being decoded.
type buf struct {
- dwarf *Data
- u *unit
- order binary.ByteOrder
- name string
- off Offset
- data []byte
- err error
+ dwarf *Data
+ order binary.ByteOrder
+ format dataFormat
+ name string
+ off Offset
+ data []byte
+ err error
}
-func makeBuf(d *Data, u *unit, name string, off Offset, data []byte) buf {
- return buf{d, u, d.order, name, off, data, nil}
+// Data format, other than byte order. This affects the handling of
+// certain field formats.
+type dataFormat interface {
+ // DWARF version number. Zero means unknown.
+ version() int
+
+ // 64-bit DWARF format?
+ dwarf64() (dwarf64 bool, isKnown bool)
+
+ // Size of an address, in bytes. Zero means unknown.
+ addrsize() int
+}
+
+// Some parts of DWARF have no data format, e.g., abbrevs.
+type unknownFormat struct{}
+
+func (u unknownFormat) version() int {
+ return 0
+}
+
+func (u unknownFormat) dwarf64() (bool, bool) {
+ return false, false
+}
+
+func (u unknownFormat) addrsize() int {
+ return 0
+}
+
+func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf {
+ return buf{d, d.order, format, name, off, data, nil}
}
func (b *buf) uint8() uint8 {
@@ -121,17 +149,15 @@ func (b *buf) int() int64 {
// Address-sized uint.
func (b *buf) addr() uint64 {
- if b.u != nil {
- switch b.u.addrsize {
- case 1:
- return uint64(b.uint8())
- case 2:
- return uint64(b.uint16())
- case 4:
- return uint64(b.uint32())
- case 8:
- return uint64(b.uint64())
- }
+ switch b.format.addrsize() {
+ case 1:
+ return uint64(b.uint8())
+ case 2:
+ return uint64(b.uint16())
+ case 4:
+ return uint64(b.uint32())
+ case 8:
+ return uint64(b.uint64())
}
b.error("unknown address size")
return 0
diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go
index 4761d74cd79..ada723163a4 100644
--- a/libgo/go/debug/dwarf/entry.go
+++ b/libgo/go/debug/dwarf/entry.go
@@ -40,7 +40,7 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
} else {
data = data[off:]
}
- b := makeBuf(d, nil, "abbrev", 0, data)
+ b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
// Error handling is simplified by the buf getters
// returning an endless stream of 0s after an error.
@@ -190,13 +190,16 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
case formFlag:
val = b.uint8() == 1
case formFlagPresent:
+ // The attribute is implicitly indicated as present, and no value is
+ // encoded in the debugging information entry itself.
val = true
// lineptr, loclistptr, macptr, rangelistptr
case formSecOffset:
- if b.u == nil {
+ is64, known := b.format.dwarf64()
+ if !known {
b.error("unknown size for DW_FORM_sec_offset")
- } else if b.u.dwarf64 {
+ } else if is64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
@@ -204,14 +207,20 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// reference to other entry
case formRefAddr:
- if b.u == nil {
+ vers := b.format.version()
+ if vers == 0 {
b.error("unknown version for DW_FORM_ref_addr")
- } else if b.u.version == 2 {
+ } else if vers == 2 {
val = Offset(b.addr())
- } else if b.u.dwarf64 {
- val = Offset(b.uint64())
} else {
- val = Offset(b.uint32())
+ is64, known := b.format.dwarf64()
+ if !known {
+ b.error("unknown size for DW_FORM_ref_addr")
+ } else if is64 {
+ val = Offset(b.uint64())
+ } else {
+ val = Offset(b.uint32())
+ }
}
case formRef1:
val = Offset(b.uint8()) + ubase
@@ -234,7 +243,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
if b.err != nil {
return nil
}
- b1 := makeBuf(b.dwarf, b.u, "str", 0, b.dwarf.str)
+ b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
b1.skip(int(off))
val = b1.string()
if b1.err != nil {
diff --git a/libgo/go/debug/dwarf/line.go b/libgo/go/debug/dwarf/line.go
index 3ab2f2b30cb..c463c3b0d8f 100644
--- a/libgo/go/debug/dwarf/line.go
+++ b/libgo/go/debug/dwarf/line.go
@@ -112,7 +112,7 @@ func (d *Data) readUnitLine(i int, u *unit) error {
func (d *Data) readAddressRanges(off Offset, base uint64, u *unit) error {
b := makeBuf(d, u, "ranges", off, d.ranges[off:])
var highest uint64
- switch u.addrsize {
+ switch u.addrsize() {
case 1:
highest = 0xff
case 2:
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
index 2ef8ca01bf8..54000fbd75e 100644
--- a/libgo/go/debug/dwarf/type.go
+++ b/libgo/go/debug/dwarf/type.go
@@ -435,7 +435,9 @@ func (d *Data) Type(off Offset) (Type, error) {
goto Error
}
if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
- b := makeBuf(d, nil, "location", 0, loc)
+ // TODO: Should have original compilation
+ // unit here, not unknownFormat.
+ b := makeBuf(d, unknownFormat{}, "location", 0, loc)
if b.uint8() != opPlusUconst {
err = DecodeError{"info", kid.Offset, "unexpected opcode"}
goto Error
diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go
index b1903208715..8e09298a8b4 100644
--- a/libgo/go/debug/dwarf/unit.go
+++ b/libgo/go/debug/dwarf/unit.go
@@ -10,17 +10,31 @@ import "strconv"
// Each unit has its own abbreviation table and address size.
type unit struct {
- base Offset // byte offset of header within the aggregate info
- off Offset // byte offset of data within the aggregate info
- lineoff Offset // byte offset of data within the line info
- data []byte
- atable abbrevTable
- addrsize int
- version int
- dwarf64 bool // True for 64-bit DWARF format
- dir string
- pc []addrRange // PC ranges in this compilation unit
- lines []mapLineInfo // PC -> line mapping
+ base Offset // byte offset of header within the aggregate info
+ off Offset // byte offset of data within the aggregate info
+ lineoff Offset // byte offset of data within the line info
+ data []byte
+ atable abbrevTable
+ asize int
+ vers int
+ is64 bool // True for 64-bit DWARF format
+ dir string
+ pc []addrRange // PC ranges in this compilation unit
+ lines []mapLineInfo // PC -> line mapping
+}
+
+// Implement the dataFormat interface.
+
+func (u *unit) version() int {
+ return u.vers
+}
+
+func (u *unit) dwarf64() (bool, bool) {
+ return u.is64, true
+}
+
+func (u *unit) addrsize() int {
+ return u.asize
}
// A range is an address range.
@@ -32,12 +46,12 @@ type addrRange struct {
func (d *Data) parseUnits() ([]unit, error) {
// Count units.
nunit := 0
- b := makeBuf(d, nil, "info", 0, d.info)
+ b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
for len(b.data) > 0 {
len := b.uint32()
if len == 0xffffffff {
len64 := b.uint64()
- if len64 != uint64(int(len64)) {
+ if len64 != uint64(uint32(len64)) {
b.error("unit length overflow")
break
}
@@ -51,14 +65,14 @@ func (d *Data) parseUnits() ([]unit, error) {
}
// Again, this time writing them down.
- b = makeBuf(d, nil, "info", 0, d.info)
+ b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
units := make([]unit, nunit)
for i := range units {
u := &units[i]
u.base = b.off
n := b.uint32()
if n == 0xffffffff {
- u.dwarf64 = true
+ u.is64 = true
n = uint32(b.uint64())
}
vers := b.uint16()
@@ -66,6 +80,7 @@ func (d *Data) parseUnits() ([]unit, error) {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
+ u.vers = int(vers)
atable, err := d.parseAbbrev(b.uint32())
if err != nil {
if b.err == nil {
@@ -73,9 +88,8 @@ func (d *Data) parseUnits() ([]unit, error) {
}
break
}
- u.version = int(vers)
u.atable = atable
- u.addrsize = int(b.uint8())
+ u.asize = int(b.uint8())
u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1)))
}
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index eb3d72f7126..8023eb0a0b7 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -422,6 +422,10 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
+ // The first entry is all zeros.
+ var skip [Sym32Size]byte
+ symtab.Read(skip[:])
+
symbols := make([]Symbol, symtab.Len()/Sym32Size)
i := 0
@@ -461,6 +465,10 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
+ // The first entry is all zeros.
+ var skip [Sym64Size]byte
+ symtab.Read(skip[:])
+
symbols := make([]Symbol, symtab.Len()/Sym64Size)
i := 0
@@ -533,10 +541,10 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
symNo := rela.Info >> 32
t := R_X86_64(rela.Info & 0xffff)
- if symNo >= uint64(len(symbols)) {
+ if symNo == 0 || symNo > uint64(len(symbols)) {
continue
}
- sym := &symbols[symNo]
+ sym := &symbols[symNo-1]
if SymType(sym.Info&0xf) != STT_SECTION {
// We don't handle non-section relocations for now.
continue
@@ -597,6 +605,10 @@ func (f *File) DWARF() (*dwarf.Data, error) {
}
// Symbols returns the symbol table for f.
+//
+// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
+// After retrieving the symbols as symtab, an externally supplied index x
+// corresponds to symtab[x-1], not symtab[x].
func (f *File) Symbols() ([]Symbol, error) {
sym, _, err := f.getSymbols(SHT_SYMTAB)
return sym, err
@@ -706,7 +718,7 @@ func (f *File) gnuVersionInit(str []byte) {
// which came from offset i of the symbol table.
func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
// Each entry is two bytes.
- i = i * 2
+ i = (i + 1) * 2
if i >= len(f.gnuVersym) {
return
}
diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go
index cc01e0b9d69..81ed4fb27dc 100644
--- a/libgo/go/debug/gosym/symtab.go
+++ b/libgo/go/debug/gosym/symtab.go
@@ -99,31 +99,116 @@ type Table struct {
}
type sym struct {
- value uint32
- gotype uint32
+ value uint64
+ gotype uint64
typ byte
name []byte
}
-var littleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
+var littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}
+var bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00}
+
+var oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
func walksymtab(data []byte, fn func(sym) error) error {
var order binary.ByteOrder = binary.BigEndian
- if bytes.HasPrefix(data, littleEndianSymtab) {
+ newTable := false
+ switch {
+ case bytes.HasPrefix(data, oldLittleEndianSymtab):
+ // Same as Go 1.0, but little endian.
+ // Format was used during interim development between Go 1.0 and Go 1.1.
+ // Should not be widespread, but easy to support.
data = data[6:]
order = binary.LittleEndian
+ case bytes.HasPrefix(data, bigEndianSymtab):
+ newTable = true
+ case bytes.HasPrefix(data, littleEndianSymtab):
+ newTable = true
+ order = binary.LittleEndian
+ }
+ var ptrsz int
+ if newTable {
+ if len(data) < 8 {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ ptrsz = int(data[7])
+ if ptrsz != 4 && ptrsz != 8 {
+ return &DecodingError{7, "invalid pointer size", ptrsz}
+ }
+ data = data[8:]
}
var s sym
p := data
- for len(p) >= 6 {
- s.value = order.Uint32(p[0:4])
- typ := p[4]
- if typ&0x80 == 0 {
- return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
+ for len(p) >= 4 {
+ var typ byte
+ if newTable {
+ // Symbol type, value, Go type.
+ typ = p[0] & 0x3F
+ wideValue := p[0]&0x40 != 0
+ goType := p[0]&0x80 != 0
+ if typ < 26 {
+ typ += 'A'
+ } else {
+ typ += 'a' - 26
+ }
+ s.typ = typ
+ p = p[1:]
+ if wideValue {
+ if len(p) < ptrsz {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ // fixed-width value
+ if ptrsz == 8 {
+ s.value = order.Uint64(p[0:8])
+ p = p[8:]
+ } else {
+ s.value = uint64(order.Uint32(p[0:4]))
+ p = p[4:]
+ }
+ } else {
+ // varint value
+ s.value = 0
+ shift := uint(0)
+ for len(p) > 0 && p[0]&0x80 != 0 {
+ s.value |= uint64(p[0]&0x7F) << shift
+ shift += 7
+ p = p[1:]
+ }
+ if len(p) == 0 {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ s.value |= uint64(p[0]) << shift
+ p = p[1:]
+ }
+ if goType {
+ if len(p) < ptrsz {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ // fixed-width go type
+ if ptrsz == 8 {
+ s.gotype = order.Uint64(p[0:8])
+ p = p[8:]
+ } else {
+ s.gotype = uint64(order.Uint32(p[0:4]))
+ p = p[4:]
+ }
+ }
+ } else {
+ // Value, symbol type.
+ s.value = uint64(order.Uint32(p[0:4]))
+ if len(p) < 5 {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ typ = p[4]
+ if typ&0x80 == 0 {
+ return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
+ }
+ typ &^= 0x80
+ s.typ = typ
+ p = p[5:]
}
- typ &^= 0x80
- s.typ = typ
- p = p[5:]
+
+ // Name.
var i int
var nnul int
for i = 0; i < len(p); i++ {
@@ -142,13 +227,21 @@ func walksymtab(data []byte, fn func(sym) error) error {
}
}
}
- if i+nnul+4 > len(p) {
+ if len(p) < i+nnul {
return &DecodingError{len(data), "unexpected EOF", nil}
}
s.name = p[0:i]
i += nnul
- s.gotype = order.Uint32(p[i : i+4])
- p = p[i+4:]
+ p = p[i:]
+
+ if !newTable {
+ if len(p) < 4 {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ // Go type.
+ s.gotype = uint64(order.Uint32(p[:4]))
+ p = p[4:]
+ }
fn(s)
}
return nil
diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go
index 6577803a075..9d912e7a087 100644
--- a/libgo/go/debug/macho/file.go
+++ b/libgo/go/debug/macho/file.go
@@ -142,6 +142,8 @@ type Dysymtab struct {
* Mach-O reader
*/
+// FormatError is returned by some operations if the data does
+// not have the correct format for an object file.
type FormatError struct {
off int64
msg string