mirror of
https://github.com/beego/bee.git
synced 2025-07-03 10:10:18 +00:00
Update vendor folder (Delve support)
This commit is contained in:
203
vendor/golang.org/x/debug/dwarf/buf.go
generated
vendored
Normal file
203
vendor/golang.org/x/debug/dwarf/buf.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Buffered reading and decoding of DWARF data streams.
|
||||
|
||||
package dwarf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Data buffer being decoded.
|
||||
type buf struct {
|
||||
dwarf *Data
|
||||
order binary.ByteOrder
|
||||
format dataFormat
|
||||
name string
|
||||
off Offset
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
|
||||
// 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) slice(length int) buf {
|
||||
n := *b
|
||||
data := b.data
|
||||
b.skip(length) // Will validate length.
|
||||
n.data = data[:length]
|
||||
return n
|
||||
}
|
||||
|
||||
func (b *buf) uint8() uint8 {
|
||||
if len(b.data) < 1 {
|
||||
b.error("underflow")
|
||||
return 0
|
||||
}
|
||||
val := b.data[0]
|
||||
b.data = b.data[1:]
|
||||
b.off++
|
||||
return val
|
||||
}
|
||||
|
||||
func (b *buf) bytes(n int) []byte {
|
||||
if len(b.data) < n {
|
||||
b.error("underflow")
|
||||
return nil
|
||||
}
|
||||
data := b.data[0:n]
|
||||
b.data = b.data[n:]
|
||||
b.off += Offset(n)
|
||||
return data
|
||||
}
|
||||
|
||||
func (b *buf) skip(n int) { b.bytes(n) }
|
||||
|
||||
// string returns the NUL-terminated (C-like) string at the start of the buffer.
|
||||
// The terminal NUL is discarded.
|
||||
func (b *buf) string() string {
|
||||
for i := 0; i < len(b.data); i++ {
|
||||
if b.data[i] == 0 {
|
||||
s := string(b.data[0:i])
|
||||
b.data = b.data[i+1:]
|
||||
b.off += Offset(i + 1)
|
||||
return s
|
||||
}
|
||||
}
|
||||
b.error("underflow")
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *buf) uint16() uint16 {
|
||||
a := b.bytes(2)
|
||||
if a == nil {
|
||||
return 0
|
||||
}
|
||||
return b.order.Uint16(a)
|
||||
}
|
||||
|
||||
func (b *buf) uint32() uint32 {
|
||||
a := b.bytes(4)
|
||||
if a == nil {
|
||||
return 0
|
||||
}
|
||||
return b.order.Uint32(a)
|
||||
}
|
||||
|
||||
func (b *buf) uint64() uint64 {
|
||||
a := b.bytes(8)
|
||||
if a == nil {
|
||||
return 0
|
||||
}
|
||||
return b.order.Uint64(a)
|
||||
}
|
||||
|
||||
// Read a varint, which is 7 bits per byte, little endian.
|
||||
// the 0x80 bit means read another byte.
|
||||
func (b *buf) varint() (c uint64, bits uint) {
|
||||
for i := 0; i < len(b.data); i++ {
|
||||
byte := b.data[i]
|
||||
c |= uint64(byte&0x7F) << bits
|
||||
bits += 7
|
||||
if byte&0x80 == 0 {
|
||||
b.off += Offset(i + 1)
|
||||
b.data = b.data[i+1:]
|
||||
return c, bits
|
||||
}
|
||||
}
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Unsigned int is just a varint.
|
||||
func (b *buf) uint() uint64 {
|
||||
x, _ := b.varint()
|
||||
return x
|
||||
}
|
||||
|
||||
// Signed int is a sign-extended varint.
|
||||
func (b *buf) int() int64 {
|
||||
ux, bits := b.varint()
|
||||
x := int64(ux)
|
||||
if x&(1<<(bits-1)) != 0 {
|
||||
x |= -1 << bits
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Address-sized uint.
|
||||
func (b *buf) addr() 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
|
||||
}
|
||||
|
||||
// assertEmpty checks that everything has been read from b.
|
||||
func (b *buf) assertEmpty() {
|
||||
if len(b.data) == 0 {
|
||||
return
|
||||
}
|
||||
if len(b.data) > 5 {
|
||||
b.error(fmt.Sprintf("unexpected extra data: %x...", b.data[0:5]))
|
||||
}
|
||||
b.error(fmt.Sprintf("unexpected extra data: %x", b.data))
|
||||
}
|
||||
|
||||
func (b *buf) error(s string) {
|
||||
if b.err == nil {
|
||||
b.data = nil
|
||||
b.err = DecodeError{b.name, b.off, s}
|
||||
}
|
||||
}
|
||||
|
||||
type DecodeError struct {
|
||||
Name string
|
||||
Offset Offset
|
||||
Err string
|
||||
}
|
||||
|
||||
func (e DecodeError) Error() string {
|
||||
return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.FormatInt(int64(e.Offset), 16) + ": " + e.Err
|
||||
}
|
249
vendor/golang.org/x/debug/dwarf/cache.go
generated
vendored
Normal file
249
vendor/golang.org/x/debug/dwarf/cache.go
generated
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dwarf
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// pcToFuncEntries maps PC ranges to function entries.
|
||||
//
|
||||
// Each element contains a *Entry for a function and its corresponding start PC.
|
||||
// If we know the address one past the last instruction of a function, and it is
|
||||
// not equal to the start address of the next function, we mark that with
|
||||
// another element containing that address and a nil entry. The elements are
|
||||
// sorted by PC. Among elements with the same PC, those with non-nil *Entry
|
||||
// are put earlier.
|
||||
type pcToFuncEntries []pcToFuncEntry
|
||||
type pcToFuncEntry struct {
|
||||
pc uint64
|
||||
entry *Entry
|
||||
}
|
||||
|
||||
func (p pcToFuncEntries) Len() int { return len(p) }
|
||||
func (p pcToFuncEntries) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
func (p pcToFuncEntries) Less(i, j int) bool {
|
||||
if p[i].pc != p[j].pc {
|
||||
return p[i].pc < p[j].pc
|
||||
}
|
||||
return p[i].entry != nil && p[j].entry == nil
|
||||
}
|
||||
|
||||
// nameCache maps each symbol name to a linked list of the entries with that name.
|
||||
type nameCache map[string]*nameCacheEntry
|
||||
type nameCacheEntry struct {
|
||||
entry *Entry
|
||||
link *nameCacheEntry
|
||||
}
|
||||
|
||||
// pcToLineEntries maps PCs to line numbers.
|
||||
//
|
||||
// It is a slice of (PC, line, file number) triples, sorted by PC. The file
|
||||
// number is an index into the source files slice.
|
||||
// If (PC1, line1, file1) and (PC2, line2, file2) are two consecutive elements,
|
||||
// then the span of addresses [PC1, PC2) belongs to (line1, file1). If an
|
||||
// element's file number is zero, it only marks the end of a span.
|
||||
//
|
||||
// TODO: could save memory by changing pcToLineEntries and lineToPCEntries to use
|
||||
// interval trees containing references into .debug_line.
|
||||
type pcToLineEntries []pcToLineEntry
|
||||
type pcToLineEntry struct {
|
||||
pc uint64
|
||||
line uint64
|
||||
file uint64
|
||||
}
|
||||
|
||||
func (p pcToLineEntries) Len() int { return len(p) }
|
||||
func (p pcToLineEntries) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
func (p pcToLineEntries) Less(i, j int) bool {
|
||||
if p[i].pc != p[j].pc {
|
||||
return p[i].pc < p[j].pc
|
||||
}
|
||||
return p[i].file > p[j].file
|
||||
}
|
||||
|
||||
// byFileLine is used temporarily while building lineToPCEntries.
|
||||
type byFileLine []pcToLineEntry
|
||||
|
||||
func (b byFileLine) Len() int { return len(b) }
|
||||
func (b byFileLine) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||
func (b byFileLine) Less(i, j int) bool {
|
||||
if b[i].file != b[j].file {
|
||||
return b[i].file < b[j].file
|
||||
}
|
||||
return b[i].line < b[j].line
|
||||
}
|
||||
|
||||
// lineToPCEntries maps line numbers to breakpoint addresses.
|
||||
//
|
||||
// The slice contains, for each source file in Data, a slice of (line, PC)
|
||||
// pairs, sorted by line. Note that there may be more than one PC for a line.
|
||||
type lineToPCEntries [][]lineToPCEntry
|
||||
type lineToPCEntry struct {
|
||||
line uint64
|
||||
pc uint64
|
||||
}
|
||||
|
||||
func (d *Data) buildLineToPCCache(pclfs pcToLineEntries) {
|
||||
// TODO: only include lines where is_stmt is true
|
||||
sort.Sort(byFileLine(pclfs))
|
||||
// Make a slice of (line, PC) pairs for each (non-zero) file.
|
||||
var (
|
||||
c = make(lineToPCEntries, len(d.sourceFiles))
|
||||
curSlice []lineToPCEntry
|
||||
)
|
||||
for i, pclf := range pclfs {
|
||||
if pclf.file == 0 {
|
||||
// This entry indicated the end of an instruction sequence, not a breakpoint.
|
||||
continue
|
||||
}
|
||||
curSlice = append(curSlice, lineToPCEntry{line: pclf.line, pc: pclf.pc})
|
||||
if i+1 == len(pclfs) || pclf.file != pclfs[i+1].file {
|
||||
// curSlice now contains all of the entries for pclf.file.
|
||||
if pclf.file > 0 && pclf.file < uint64(len(c)) {
|
||||
c[pclf.file] = curSlice
|
||||
}
|
||||
curSlice = nil
|
||||
}
|
||||
}
|
||||
d.lineToPCEntries = c
|
||||
}
|
||||
|
||||
func (d *Data) buildPCToLineCache(cache pcToLineEntries) {
|
||||
// Sort cache by PC (in increasing order), then by file number (in decreasing order).
|
||||
sort.Sort(cache)
|
||||
|
||||
// Build a copy without redundant entries.
|
||||
var out pcToLineEntries
|
||||
for i, pclf := range cache {
|
||||
if i > 0 && pclf.pc == cache[i-1].pc {
|
||||
// This entry is for the same PC as the previous entry.
|
||||
continue
|
||||
}
|
||||
if i > 0 && pclf.file == cache[i-1].file && pclf.line == cache[i-1].line {
|
||||
// This entry is for the same file and line as the previous entry.
|
||||
continue
|
||||
}
|
||||
out = append(out, pclf)
|
||||
}
|
||||
d.pcToLineEntries = out
|
||||
}
|
||||
|
||||
// buildLineCaches constructs d.sourceFiles, d.lineToPCEntries, d.pcToLineEntries.
|
||||
func (d *Data) buildLineCaches() {
|
||||
if len(d.line) == 0 {
|
||||
return
|
||||
}
|
||||
var m lineMachine
|
||||
// Assume the address_size in the first unit applies to the whole program.
|
||||
// TODO: we could handle executables containing code for multiple address
|
||||
// sizes using DW_AT_stmt_list attributes.
|
||||
if len(d.unit) == 0 {
|
||||
return
|
||||
}
|
||||
buf := makeBuf(d, &d.unit[0], "line", 0, d.line)
|
||||
if err := m.parseHeader(&buf); err != nil {
|
||||
return
|
||||
}
|
||||
for _, f := range m.header.file {
|
||||
d.sourceFiles = append(d.sourceFiles, f.name)
|
||||
}
|
||||
var cache pcToLineEntries
|
||||
fn := func(m *lineMachine) bool {
|
||||
if m.endSequence {
|
||||
cache = append(cache, pcToLineEntry{
|
||||
pc: m.address,
|
||||
line: 0,
|
||||
file: 0,
|
||||
})
|
||||
} else {
|
||||
cache = append(cache, pcToLineEntry{
|
||||
pc: m.address,
|
||||
line: m.line,
|
||||
file: m.file,
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
m.evalCompilationUnit(&buf, fn)
|
||||
d.buildLineToPCCache(cache)
|
||||
d.buildPCToLineCache(cache)
|
||||
}
|
||||
|
||||
// buildInfoCaches initializes nameCache and pcToFuncEntries by walking the
|
||||
// top-level entries under each compile unit. It swallows any errors in parsing.
|
||||
func (d *Data) buildInfoCaches() {
|
||||
// TODO: record errors somewhere?
|
||||
d.nameCache = make(map[string]*nameCacheEntry)
|
||||
|
||||
var pcToFuncEntries pcToFuncEntries
|
||||
|
||||
r := d.Reader()
|
||||
loop:
|
||||
for {
|
||||
entry, err := r.Next()
|
||||
if entry == nil || err != nil {
|
||||
break loop
|
||||
}
|
||||
if entry.Tag != TagCompileUnit /* DW_TAG_compile_unit */ {
|
||||
r.SkipChildren()
|
||||
continue
|
||||
}
|
||||
for {
|
||||
entry, err := r.Next()
|
||||
if entry == nil || err != nil {
|
||||
break loop
|
||||
}
|
||||
if entry.Tag == 0 {
|
||||
// End of children of current compile unit.
|
||||
break
|
||||
}
|
||||
r.SkipChildren()
|
||||
// Update name-to-entry cache.
|
||||
if name, ok := entry.Val(AttrName).(string); ok {
|
||||
d.nameCache[name] = &nameCacheEntry{entry: entry, link: d.nameCache[name]}
|
||||
}
|
||||
|
||||
// If this entry is a function, update PC-to-containing-function cache.
|
||||
if entry.Tag != TagSubprogram /* DW_TAG_subprogram */ {
|
||||
continue
|
||||
}
|
||||
|
||||
// DW_AT_low_pc, if present, is the address of the first instruction of
|
||||
// the function.
|
||||
lowpc, ok := entry.Val(AttrLowpc).(uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
pcToFuncEntries = append(pcToFuncEntries, pcToFuncEntry{lowpc, entry})
|
||||
|
||||
// DW_AT_high_pc, if present (TODO: and of class address) is the address
|
||||
// one past the last instruction of the function.
|
||||
highpc, ok := entry.Val(AttrHighpc).(uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
pcToFuncEntries = append(pcToFuncEntries, pcToFuncEntry{highpc, nil})
|
||||
}
|
||||
}
|
||||
// Sort elements by PC. If there are multiple elements with the same PC,
|
||||
// those with non-nil *Entry are placed earlier.
|
||||
sort.Sort(pcToFuncEntries)
|
||||
|
||||
// Copy only the first element for each PC to out.
|
||||
n := 0
|
||||
for i, ce := range pcToFuncEntries {
|
||||
if i == 0 || ce.pc != pcToFuncEntries[i-1].pc {
|
||||
n++
|
||||
}
|
||||
}
|
||||
out := make([]pcToFuncEntry, 0, n)
|
||||
for i, ce := range pcToFuncEntries {
|
||||
if i == 0 || ce.pc != pcToFuncEntries[i-1].pc {
|
||||
out = append(out, ce)
|
||||
}
|
||||
}
|
||||
d.pcToFuncEntries = out
|
||||
}
|
467
vendor/golang.org/x/debug/dwarf/const.go
generated
vendored
Normal file
467
vendor/golang.org/x/debug/dwarf/const.go
generated
vendored
Normal file
@ -0,0 +1,467 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Constants
|
||||
|
||||
package dwarf
|
||||
|
||||
import "strconv"
|
||||
|
||||
// An Attr identifies the attribute type in a DWARF Entry's Field.
|
||||
type Attr uint32
|
||||
|
||||
const (
|
||||
AttrSibling Attr = 0x01
|
||||
AttrLocation Attr = 0x02
|
||||
AttrName Attr = 0x03
|
||||
AttrOrdering Attr = 0x09
|
||||
AttrByteSize Attr = 0x0B
|
||||
AttrBitOffset Attr = 0x0C
|
||||
AttrBitSize Attr = 0x0D
|
||||
AttrStmtList Attr = 0x10
|
||||
AttrLowpc Attr = 0x11
|
||||
AttrHighpc Attr = 0x12
|
||||
AttrLanguage Attr = 0x13
|
||||
AttrDiscr Attr = 0x15
|
||||
AttrDiscrValue Attr = 0x16
|
||||
AttrVisibility Attr = 0x17
|
||||
AttrImport Attr = 0x18
|
||||
AttrStringLength Attr = 0x19
|
||||
AttrCommonRef Attr = 0x1A
|
||||
AttrCompDir Attr = 0x1B
|
||||
AttrConstValue Attr = 0x1C
|
||||
AttrContainingType Attr = 0x1D
|
||||
AttrDefaultValue Attr = 0x1E
|
||||
AttrInline Attr = 0x20
|
||||
AttrIsOptional Attr = 0x21
|
||||
AttrLowerBound Attr = 0x22
|
||||
AttrProducer Attr = 0x25
|
||||
AttrPrototyped Attr = 0x27
|
||||
AttrReturnAddr Attr = 0x2A
|
||||
AttrStartScope Attr = 0x2C
|
||||
AttrStrideSize Attr = 0x2E
|
||||
AttrUpperBound Attr = 0x2F
|
||||
AttrAbstractOrigin Attr = 0x31
|
||||
AttrAccessibility Attr = 0x32
|
||||
AttrAddrClass Attr = 0x33
|
||||
AttrArtificial Attr = 0x34
|
||||
AttrBaseTypes Attr = 0x35
|
||||
AttrCalling Attr = 0x36
|
||||
AttrCount Attr = 0x37
|
||||
AttrDataMemberLoc Attr = 0x38
|
||||
AttrDeclColumn Attr = 0x39
|
||||
AttrDeclFile Attr = 0x3A
|
||||
AttrDeclLine Attr = 0x3B
|
||||
AttrDeclaration Attr = 0x3C
|
||||
AttrDiscrList Attr = 0x3D
|
||||
AttrEncoding Attr = 0x3E
|
||||
AttrExternal Attr = 0x3F
|
||||
AttrFrameBase Attr = 0x40
|
||||
AttrFriend Attr = 0x41
|
||||
AttrIdentifierCase Attr = 0x42
|
||||
AttrMacroInfo Attr = 0x43
|
||||
AttrNamelistItem Attr = 0x44
|
||||
AttrPriority Attr = 0x45
|
||||
AttrSegment Attr = 0x46
|
||||
AttrSpecification Attr = 0x47
|
||||
AttrStaticLink Attr = 0x48
|
||||
AttrType Attr = 0x49
|
||||
AttrUseLocation Attr = 0x4A
|
||||
AttrVarParam Attr = 0x4B
|
||||
AttrVirtuality Attr = 0x4C
|
||||
AttrVtableElemLoc Attr = 0x4D
|
||||
AttrAllocated Attr = 0x4E
|
||||
AttrAssociated Attr = 0x4F
|
||||
AttrDataLocation Attr = 0x50
|
||||
AttrStride Attr = 0x51
|
||||
AttrEntrypc Attr = 0x52
|
||||
AttrUseUTF8 Attr = 0x53
|
||||
AttrExtension Attr = 0x54
|
||||
AttrRanges Attr = 0x55
|
||||
AttrTrampoline Attr = 0x56
|
||||
AttrCallColumn Attr = 0x57
|
||||
AttrCallFile Attr = 0x58
|
||||
AttrCallLine Attr = 0x59
|
||||
AttrDescription Attr = 0x5A
|
||||
|
||||
// Go-specific attributes.
|
||||
AttrGoKind Attr = 0x2900
|
||||
AttrGoKey Attr = 0x2901
|
||||
AttrGoElem Attr = 0x2902
|
||||
)
|
||||
|
||||
var attrNames = [...]string{
|
||||
AttrSibling: "Sibling",
|
||||
AttrLocation: "Location",
|
||||
AttrName: "Name",
|
||||
AttrOrdering: "Ordering",
|
||||
AttrByteSize: "ByteSize",
|
||||
AttrBitOffset: "BitOffset",
|
||||
AttrBitSize: "BitSize",
|
||||
AttrStmtList: "StmtList",
|
||||
AttrLowpc: "Lowpc",
|
||||
AttrHighpc: "Highpc",
|
||||
AttrLanguage: "Language",
|
||||
AttrDiscr: "Discr",
|
||||
AttrDiscrValue: "DiscrValue",
|
||||
AttrVisibility: "Visibility",
|
||||
AttrImport: "Import",
|
||||
AttrStringLength: "StringLength",
|
||||
AttrCommonRef: "CommonRef",
|
||||
AttrCompDir: "CompDir",
|
||||
AttrConstValue: "ConstValue",
|
||||
AttrContainingType: "ContainingType",
|
||||
AttrDefaultValue: "DefaultValue",
|
||||
AttrInline: "Inline",
|
||||
AttrIsOptional: "IsOptional",
|
||||
AttrLowerBound: "LowerBound",
|
||||
AttrProducer: "Producer",
|
||||
AttrPrototyped: "Prototyped",
|
||||
AttrReturnAddr: "ReturnAddr",
|
||||
AttrStartScope: "StartScope",
|
||||
AttrStrideSize: "StrideSize",
|
||||
AttrUpperBound: "UpperBound",
|
||||
AttrAbstractOrigin: "AbstractOrigin",
|
||||
AttrAccessibility: "Accessibility",
|
||||
AttrAddrClass: "AddrClass",
|
||||
AttrArtificial: "Artificial",
|
||||
AttrBaseTypes: "BaseTypes",
|
||||
AttrCalling: "Calling",
|
||||
AttrCount: "Count",
|
||||
AttrDataMemberLoc: "DataMemberLoc",
|
||||
AttrDeclColumn: "DeclColumn",
|
||||
AttrDeclFile: "DeclFile",
|
||||
AttrDeclLine: "DeclLine",
|
||||
AttrDeclaration: "Declaration",
|
||||
AttrDiscrList: "DiscrList",
|
||||
AttrEncoding: "Encoding",
|
||||
AttrExternal: "External",
|
||||
AttrFrameBase: "FrameBase",
|
||||
AttrFriend: "Friend",
|
||||
AttrIdentifierCase: "IdentifierCase",
|
||||
AttrMacroInfo: "MacroInfo",
|
||||
AttrNamelistItem: "NamelistItem",
|
||||
AttrPriority: "Priority",
|
||||
AttrSegment: "Segment",
|
||||
AttrSpecification: "Specification",
|
||||
AttrStaticLink: "StaticLink",
|
||||
AttrType: "Type",
|
||||
AttrUseLocation: "UseLocation",
|
||||
AttrVarParam: "VarParam",
|
||||
AttrVirtuality: "Virtuality",
|
||||
AttrVtableElemLoc: "VtableElemLoc",
|
||||
AttrAllocated: "Allocated",
|
||||
AttrAssociated: "Associated",
|
||||
AttrDataLocation: "DataLocation",
|
||||
AttrStride: "Stride",
|
||||
AttrEntrypc: "Entrypc",
|
||||
AttrUseUTF8: "UseUTF8",
|
||||
AttrExtension: "Extension",
|
||||
AttrRanges: "Ranges",
|
||||
AttrTrampoline: "Trampoline",
|
||||
AttrCallColumn: "CallColumn",
|
||||
AttrCallFile: "CallFile",
|
||||
AttrCallLine: "CallLine",
|
||||
AttrDescription: "Description",
|
||||
}
|
||||
|
||||
func (a Attr) String() string {
|
||||
if int(a) < len(attrNames) {
|
||||
s := attrNames[a]
|
||||
if s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
switch a {
|
||||
case AttrGoKind:
|
||||
return "GoKind"
|
||||
case AttrGoKey:
|
||||
return "GoKey"
|
||||
case AttrGoElem:
|
||||
return "GoElem"
|
||||
}
|
||||
return strconv.Itoa(int(a))
|
||||
}
|
||||
|
||||
func (a Attr) GoString() string {
|
||||
if int(a) < len(attrNames) {
|
||||
s := attrNames[a]
|
||||
if s != "" {
|
||||
return "dwarf.Attr" + s
|
||||
}
|
||||
}
|
||||
return "dwarf.Attr(" + strconv.FormatInt(int64(a), 10) + ")"
|
||||
}
|
||||
|
||||
// A format is a DWARF data encoding format.
|
||||
type format uint32
|
||||
|
||||
const (
|
||||
// value formats
|
||||
formAddr format = 0x01
|
||||
formDwarfBlock2 format = 0x03
|
||||
formDwarfBlock4 format = 0x04
|
||||
formData2 format = 0x05
|
||||
formData4 format = 0x06
|
||||
formData8 format = 0x07
|
||||
formString format = 0x08
|
||||
formDwarfBlock format = 0x09
|
||||
formDwarfBlock1 format = 0x0A
|
||||
formData1 format = 0x0B
|
||||
formFlag format = 0x0C
|
||||
formSdata format = 0x0D
|
||||
formStrp format = 0x0E
|
||||
formUdata format = 0x0F
|
||||
formRefAddr format = 0x10
|
||||
formRef1 format = 0x11
|
||||
formRef2 format = 0x12
|
||||
formRef4 format = 0x13
|
||||
formRef8 format = 0x14
|
||||
formRefUdata format = 0x15
|
||||
formIndirect format = 0x16
|
||||
// The following are new in DWARF 4.
|
||||
formSecOffset format = 0x17
|
||||
formExprloc format = 0x18
|
||||
formFlagPresent format = 0x19
|
||||
formRefSig8 format = 0x20
|
||||
// Extensions for multi-file compression (.dwz)
|
||||
// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
|
||||
formGnuRefAlt format = 0x1f20
|
||||
formGnuStrpAlt format = 0x1f21
|
||||
)
|
||||
|
||||
// A Tag is the classification (the type) of an Entry.
|
||||
type Tag uint32
|
||||
|
||||
const (
|
||||
TagArrayType Tag = 0x01
|
||||
TagClassType Tag = 0x02
|
||||
TagEntryPoint Tag = 0x03
|
||||
TagEnumerationType Tag = 0x04
|
||||
TagFormalParameter Tag = 0x05
|
||||
TagImportedDeclaration Tag = 0x08
|
||||
TagLabel Tag = 0x0A
|
||||
TagLexDwarfBlock Tag = 0x0B
|
||||
TagMember Tag = 0x0D
|
||||
TagPointerType Tag = 0x0F
|
||||
TagReferenceType Tag = 0x10
|
||||
TagCompileUnit Tag = 0x11
|
||||
TagStringType Tag = 0x12
|
||||
TagStructType Tag = 0x13
|
||||
TagSubroutineType Tag = 0x15
|
||||
TagTypedef Tag = 0x16
|
||||
TagUnionType Tag = 0x17
|
||||
TagUnspecifiedParameters Tag = 0x18
|
||||
TagVariant Tag = 0x19
|
||||
TagCommonDwarfBlock Tag = 0x1A
|
||||
TagCommonInclusion Tag = 0x1B
|
||||
TagInheritance Tag = 0x1C
|
||||
TagInlinedSubroutine Tag = 0x1D
|
||||
TagModule Tag = 0x1E
|
||||
TagPtrToMemberType Tag = 0x1F
|
||||
TagSetType Tag = 0x20
|
||||
TagSubrangeType Tag = 0x21
|
||||
TagWithStmt Tag = 0x22
|
||||
TagAccessDeclaration Tag = 0x23
|
||||
TagBaseType Tag = 0x24
|
||||
TagCatchDwarfBlock Tag = 0x25
|
||||
TagConstType Tag = 0x26
|
||||
TagConstant Tag = 0x27
|
||||
TagEnumerator Tag = 0x28
|
||||
TagFileType Tag = 0x29
|
||||
TagFriend Tag = 0x2A
|
||||
TagNamelist Tag = 0x2B
|
||||
TagNamelistItem Tag = 0x2C
|
||||
TagPackedType Tag = 0x2D
|
||||
TagSubprogram Tag = 0x2E
|
||||
TagTemplateTypeParameter Tag = 0x2F
|
||||
TagTemplateValueParameter Tag = 0x30
|
||||
TagThrownType Tag = 0x31
|
||||
TagTryDwarfBlock Tag = 0x32
|
||||
TagVariantPart Tag = 0x33
|
||||
TagVariable Tag = 0x34
|
||||
TagVolatileType Tag = 0x35
|
||||
// The following are new in DWARF 3.
|
||||
TagDwarfProcedure Tag = 0x36
|
||||
TagRestrictType Tag = 0x37
|
||||
TagInterfaceType Tag = 0x38
|
||||
TagNamespace Tag = 0x39
|
||||
TagImportedModule Tag = 0x3A
|
||||
TagUnspecifiedType Tag = 0x3B
|
||||
TagPartialUnit Tag = 0x3C
|
||||
TagImportedUnit Tag = 0x3D
|
||||
TagMutableType Tag = 0x3E // Later removed from DWARF.
|
||||
TagCondition Tag = 0x3F
|
||||
TagSharedType Tag = 0x40
|
||||
// The following are new in DWARF 4.
|
||||
TagTypeUnit Tag = 0x41
|
||||
TagRvalueReferenceType Tag = 0x42
|
||||
TagTemplateAlias Tag = 0x43
|
||||
)
|
||||
|
||||
var tagNames = [...]string{
|
||||
TagArrayType: "ArrayType",
|
||||
TagClassType: "ClassType",
|
||||
TagEntryPoint: "EntryPoint",
|
||||
TagEnumerationType: "EnumerationType",
|
||||
TagFormalParameter: "FormalParameter",
|
||||
TagImportedDeclaration: "ImportedDeclaration",
|
||||
TagLabel: "Label",
|
||||
TagLexDwarfBlock: "LexDwarfBlock",
|
||||
TagMember: "Member",
|
||||
TagPointerType: "PointerType",
|
||||
TagReferenceType: "ReferenceType",
|
||||
TagCompileUnit: "CompileUnit",
|
||||
TagStringType: "StringType",
|
||||
TagStructType: "StructType",
|
||||
TagSubroutineType: "SubroutineType",
|
||||
TagTypedef: "Typedef",
|
||||
TagUnionType: "UnionType",
|
||||
TagUnspecifiedParameters: "UnspecifiedParameters",
|
||||
TagVariant: "Variant",
|
||||
TagCommonDwarfBlock: "CommonDwarfBlock",
|
||||
TagCommonInclusion: "CommonInclusion",
|
||||
TagInheritance: "Inheritance",
|
||||
TagInlinedSubroutine: "InlinedSubroutine",
|
||||
TagModule: "Module",
|
||||
TagPtrToMemberType: "PtrToMemberType",
|
||||
TagSetType: "SetType",
|
||||
TagSubrangeType: "SubrangeType",
|
||||
TagWithStmt: "WithStmt",
|
||||
TagAccessDeclaration: "AccessDeclaration",
|
||||
TagBaseType: "BaseType",
|
||||
TagCatchDwarfBlock: "CatchDwarfBlock",
|
||||
TagConstType: "ConstType",
|
||||
TagConstant: "Constant",
|
||||
TagEnumerator: "Enumerator",
|
||||
TagFileType: "FileType",
|
||||
TagFriend: "Friend",
|
||||
TagNamelist: "Namelist",
|
||||
TagNamelistItem: "NamelistItem",
|
||||
TagPackedType: "PackedType",
|
||||
TagSubprogram: "Subprogram",
|
||||
TagTemplateTypeParameter: "TemplateTypeParameter",
|
||||
TagTemplateValueParameter: "TemplateValueParameter",
|
||||
TagThrownType: "ThrownType",
|
||||
TagTryDwarfBlock: "TryDwarfBlock",
|
||||
TagVariantPart: "VariantPart",
|
||||
TagVariable: "Variable",
|
||||
TagVolatileType: "VolatileType",
|
||||
TagDwarfProcedure: "DwarfProcedure",
|
||||
TagRestrictType: "RestrictType",
|
||||
TagInterfaceType: "InterfaceType",
|
||||
TagNamespace: "Namespace",
|
||||
TagImportedModule: "ImportedModule",
|
||||
TagUnspecifiedType: "UnspecifiedType",
|
||||
TagPartialUnit: "PartialUnit",
|
||||
TagImportedUnit: "ImportedUnit",
|
||||
TagMutableType: "MutableType",
|
||||
TagCondition: "Condition",
|
||||
TagSharedType: "SharedType",
|
||||
TagTypeUnit: "TypeUnit",
|
||||
TagRvalueReferenceType: "RvalueReferenceType",
|
||||
TagTemplateAlias: "TemplateAlias",
|
||||
}
|
||||
|
||||
func (t Tag) String() string {
|
||||
if int(t) < len(tagNames) {
|
||||
s := tagNames[t]
|
||||
if s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return strconv.Itoa(int(t))
|
||||
}
|
||||
|
||||
func (t Tag) GoString() string {
|
||||
if int(t) < len(tagNames) {
|
||||
s := tagNames[t]
|
||||
if s != "" {
|
||||
return "dwarf.Tag" + s
|
||||
}
|
||||
}
|
||||
return "dwarf.Tag(" + strconv.FormatInt(int64(t), 10) + ")"
|
||||
}
|
||||
|
||||
// Location expression operators.
|
||||
// The debug info encodes value locations like 8(R3)
|
||||
// as a sequence of these op codes.
|
||||
// This package does not implement full expressions;
|
||||
// the opPlusUconst operator is expected by the type parser.
|
||||
const (
|
||||
opAddr = 0x03 /* 1 op, const addr */
|
||||
opDeref = 0x06
|
||||
opConst1u = 0x08 /* 1 op, 1 byte const */
|
||||
opConst1s = 0x09 /* " signed */
|
||||
opConst2u = 0x0A /* 1 op, 2 byte const */
|
||||
opConst2s = 0x0B /* " signed */
|
||||
opConst4u = 0x0C /* 1 op, 4 byte const */
|
||||
opConst4s = 0x0D /* " signed */
|
||||
opConst8u = 0x0E /* 1 op, 8 byte const */
|
||||
opConst8s = 0x0F /* " signed */
|
||||
opConstu = 0x10 /* 1 op, LEB128 const */
|
||||
opConsts = 0x11 /* " signed */
|
||||
opDup = 0x12
|
||||
opDrop = 0x13
|
||||
opOver = 0x14
|
||||
opPick = 0x15 /* 1 op, 1 byte stack index */
|
||||
opSwap = 0x16
|
||||
opRot = 0x17
|
||||
opXderef = 0x18
|
||||
opAbs = 0x19
|
||||
opAnd = 0x1A
|
||||
opDiv = 0x1B
|
||||
opMinus = 0x1C
|
||||
opMod = 0x1D
|
||||
opMul = 0x1E
|
||||
opNeg = 0x1F
|
||||
opNot = 0x20
|
||||
opOr = 0x21
|
||||
opPlus = 0x22
|
||||
opPlusUconst = 0x23 /* 1 op, ULEB128 addend */
|
||||
opShl = 0x24
|
||||
opShr = 0x25
|
||||
opShra = 0x26
|
||||
opXor = 0x27
|
||||
opSkip = 0x2F /* 1 op, signed 2-byte constant */
|
||||
opBra = 0x28 /* 1 op, signed 2-byte constant */
|
||||
opEq = 0x29
|
||||
opGe = 0x2A
|
||||
opGt = 0x2B
|
||||
opLe = 0x2C
|
||||
opLt = 0x2D
|
||||
opNe = 0x2E
|
||||
opLit0 = 0x30
|
||||
/* OpLitN = OpLit0 + N for N = 0..31 */
|
||||
opReg0 = 0x50
|
||||
/* OpRegN = OpReg0 + N for N = 0..31 */
|
||||
opBreg0 = 0x70 /* 1 op, signed LEB128 constant */
|
||||
/* OpBregN = OpBreg0 + N for N = 0..31 */
|
||||
opRegx = 0x90 /* 1 op, ULEB128 register */
|
||||
opFbreg = 0x91 /* 1 op, SLEB128 offset */
|
||||
opBregx = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */
|
||||
opPiece = 0x93 /* 1 op, ULEB128 size of piece */
|
||||
opDerefSize = 0x94 /* 1-byte size of data retrieved */
|
||||
opXderefSize = 0x95 /* 1-byte size of data retrieved */
|
||||
opNop = 0x96
|
||||
/* next four new in Dwarf v3 */
|
||||
opPushObjAddr = 0x97
|
||||
opCall2 = 0x98 /* 2-byte offset of DIE */
|
||||
opCall4 = 0x99 /* 4-byte offset of DIE */
|
||||
opCallRef = 0x9A /* 4- or 8- byte offset of DIE */
|
||||
/* 0xE0-0xFF reserved for user-specific */
|
||||
)
|
||||
|
||||
// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry.
|
||||
const (
|
||||
encAddress = 0x01
|
||||
encBoolean = 0x02
|
||||
encComplexFloat = 0x03
|
||||
encFloat = 0x04
|
||||
encSigned = 0x05
|
||||
encSignedChar = 0x06
|
||||
encUnsigned = 0x07
|
||||
encUnsignedChar = 0x08
|
||||
encImaginaryFloat = 0x09
|
||||
)
|
407
vendor/golang.org/x/debug/dwarf/entry.go
generated
vendored
Normal file
407
vendor/golang.org/x/debug/dwarf/entry.go
generated
vendored
Normal file
@ -0,0 +1,407 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// DWARF debug information entry parser.
|
||||
// An entry is a sequence of data items of a given format.
|
||||
// The first word in the entry is an index into what DWARF
|
||||
// calls the ``abbreviation table.'' An abbreviation is really
|
||||
// just a type descriptor: it's an array of attribute tag/value format pairs.
|
||||
|
||||
package dwarf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// a single entry's description: a sequence of attributes
|
||||
type abbrev struct {
|
||||
tag Tag
|
||||
children bool
|
||||
field []afield
|
||||
}
|
||||
|
||||
type afield struct {
|
||||
attr Attr
|
||||
fmt format
|
||||
}
|
||||
|
||||
// a map from entry format ids to their descriptions
|
||||
type abbrevTable map[uint32]abbrev
|
||||
|
||||
// ParseAbbrev returns the abbreviation table that starts at byte off
|
||||
// in the .debug_abbrev section.
|
||||
func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
|
||||
if m, ok := d.abbrevCache[off]; ok {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
data := d.abbrev
|
||||
if off > uint32(len(data)) {
|
||||
data = nil
|
||||
} else {
|
||||
data = data[off:]
|
||||
}
|
||||
b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
|
||||
|
||||
// Error handling is simplified by the buf getters
|
||||
// returning an endless stream of 0s after an error.
|
||||
m := make(abbrevTable)
|
||||
for {
|
||||
// Table ends with id == 0.
|
||||
id := uint32(b.uint())
|
||||
if id == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Walk over attributes, counting.
|
||||
n := 0
|
||||
b1 := b // Read from copy of b.
|
||||
b1.uint()
|
||||
b1.uint8()
|
||||
for {
|
||||
tag := b1.uint()
|
||||
fmt := b1.uint()
|
||||
if tag == 0 && fmt == 0 {
|
||||
break
|
||||
}
|
||||
n++
|
||||
}
|
||||
if b1.err != nil {
|
||||
return nil, b1.err
|
||||
}
|
||||
|
||||
// Walk over attributes again, this time writing them down.
|
||||
var a abbrev
|
||||
a.tag = Tag(b.uint())
|
||||
a.children = b.uint8() != 0
|
||||
a.field = make([]afield, n)
|
||||
for i := range a.field {
|
||||
a.field[i].attr = Attr(b.uint())
|
||||
a.field[i].fmt = format(b.uint())
|
||||
}
|
||||
b.uint()
|
||||
b.uint()
|
||||
|
||||
m[id] = a
|
||||
}
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
d.abbrevCache[off] = m
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// An entry is a sequence of attribute/value pairs.
|
||||
type Entry struct {
|
||||
Offset Offset // offset of Entry in DWARF info
|
||||
Tag Tag // tag (kind of Entry)
|
||||
Children bool // whether Entry is followed by children
|
||||
Field []Field
|
||||
}
|
||||
|
||||
// A Field is a single attribute/value pair in an Entry.
|
||||
type Field struct {
|
||||
Attr Attr
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
// Val returns the value associated with attribute Attr in Entry,
|
||||
// or nil if there is no such attribute.
|
||||
//
|
||||
// A common idiom is to merge the check for nil return with
|
||||
// the check that the value has the expected dynamic type, as in:
|
||||
// v, ok := e.Val(AttrSibling).(int64);
|
||||
//
|
||||
func (e *Entry) Val(a Attr) interface{} {
|
||||
for _, f := range e.Field {
|
||||
if f.Attr == a {
|
||||
return f.Val
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// An Offset represents the location of an Entry within the DWARF info.
|
||||
// (See Reader.Seek.)
|
||||
type Offset uint32
|
||||
|
||||
// Entry reads a single entry from buf, decoding
|
||||
// according to the given abbreviation table.
|
||||
func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
|
||||
off := b.off
|
||||
id := uint32(b.uint())
|
||||
if id == 0 {
|
||||
return &Entry{}
|
||||
}
|
||||
a, ok := atab[id]
|
||||
if !ok {
|
||||
b.error("unknown abbreviation table index")
|
||||
return nil
|
||||
}
|
||||
e := &Entry{
|
||||
Offset: off,
|
||||
Tag: a.tag,
|
||||
Children: a.children,
|
||||
Field: make([]Field, len(a.field)),
|
||||
}
|
||||
for i := range e.Field {
|
||||
e.Field[i].Attr = a.field[i].attr
|
||||
fmt := a.field[i].fmt
|
||||
if fmt == formIndirect {
|
||||
fmt = format(b.uint())
|
||||
}
|
||||
var val interface{}
|
||||
switch fmt {
|
||||
default:
|
||||
b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16))
|
||||
|
||||
// address
|
||||
case formAddr:
|
||||
val = b.addr()
|
||||
|
||||
// block
|
||||
case formDwarfBlock1:
|
||||
val = b.bytes(int(b.uint8()))
|
||||
case formDwarfBlock2:
|
||||
val = b.bytes(int(b.uint16()))
|
||||
case formDwarfBlock4:
|
||||
val = b.bytes(int(b.uint32()))
|
||||
case formDwarfBlock:
|
||||
val = b.bytes(int(b.uint()))
|
||||
|
||||
// constant
|
||||
case formData1:
|
||||
val = int64(b.uint8())
|
||||
case formData2:
|
||||
val = int64(b.uint16())
|
||||
case formData4:
|
||||
val = int64(b.uint32())
|
||||
case formData8:
|
||||
val = int64(b.uint64())
|
||||
case formSdata:
|
||||
val = int64(b.int())
|
||||
case formUdata:
|
||||
val = int64(b.uint())
|
||||
|
||||
// flag
|
||||
case formFlag:
|
||||
val = b.uint8() == 1
|
||||
// New in DWARF 4.
|
||||
case formFlagPresent:
|
||||
// The attribute is implicitly indicated as present, and no value is
|
||||
// encoded in the debugging information entry itself.
|
||||
val = true
|
||||
|
||||
// reference to other entry
|
||||
case formRefAddr:
|
||||
vers := b.format.version()
|
||||
if vers == 0 {
|
||||
b.error("unknown version for DW_FORM_ref_addr")
|
||||
} else if vers == 2 {
|
||||
val = Offset(b.addr())
|
||||
} else {
|
||||
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
|
||||
case formRef2:
|
||||
val = Offset(b.uint16()) + ubase
|
||||
case formRef4:
|
||||
val = Offset(b.uint32()) + ubase
|
||||
case formRef8:
|
||||
val = Offset(b.uint64()) + ubase
|
||||
case formRefUdata:
|
||||
val = Offset(b.uint()) + ubase
|
||||
|
||||
// string
|
||||
case formString:
|
||||
val = b.string()
|
||||
case formStrp:
|
||||
off := b.uint32() // offset into .debug_str
|
||||
if b.err != nil {
|
||||
return nil
|
||||
}
|
||||
b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
|
||||
b1.skip(int(off))
|
||||
val = b1.string()
|
||||
if b1.err != nil {
|
||||
b.err = b1.err
|
||||
return nil
|
||||
}
|
||||
|
||||
// lineptr, loclistptr, macptr, rangelistptr
|
||||
// New in DWARF 4, but clang can generate them with -gdwarf-2.
|
||||
// Section reference, replacing use of formData4 and formData8.
|
||||
case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
|
||||
is64, known := b.format.dwarf64()
|
||||
if !known {
|
||||
b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
|
||||
} else if is64 {
|
||||
val = int64(b.uint64())
|
||||
} else {
|
||||
val = int64(b.uint32())
|
||||
}
|
||||
|
||||
// exprloc
|
||||
// New in DWARF 4.
|
||||
case formExprloc:
|
||||
val = b.bytes(int(b.uint()))
|
||||
|
||||
// reference
|
||||
// New in DWARF 4.
|
||||
case formRefSig8:
|
||||
// 64-bit type signature.
|
||||
val = b.uint64()
|
||||
}
|
||||
e.Field[i].Val = val
|
||||
}
|
||||
if b.err != nil {
|
||||
return nil
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// A Reader allows reading Entry structures from a DWARF ``info'' section.
|
||||
// The Entry structures are arranged in a tree. The Reader's Next function
|
||||
// return successive entries from a pre-order traversal of the tree.
|
||||
// If an entry has children, its Children field will be true, and the children
|
||||
// follow, terminated by an Entry with Tag 0.
|
||||
type Reader struct {
|
||||
b buf
|
||||
d *Data
|
||||
err error
|
||||
unit int
|
||||
lastChildren bool // .Children of last entry returned by Next
|
||||
lastSibling Offset // .Val(AttrSibling) of last entry returned by Next
|
||||
}
|
||||
|
||||
// Reader returns a new Reader for Data.
|
||||
// The reader is positioned at byte offset 0 in the DWARF ``info'' section.
|
||||
func (d *Data) Reader() *Reader {
|
||||
r := &Reader{d: d}
|
||||
r.Seek(0)
|
||||
return r
|
||||
}
|
||||
|
||||
// AddressSize returns the size in bytes of addresses in the current compilation
|
||||
// unit.
|
||||
func (r *Reader) AddressSize() int {
|
||||
return r.d.unit[r.unit].asize
|
||||
}
|
||||
|
||||
// Seek positions the Reader at offset off in the encoded entry stream.
|
||||
// Offset 0 can be used to denote the first entry.
|
||||
func (r *Reader) Seek(off Offset) {
|
||||
d := r.d
|
||||
r.err = nil
|
||||
r.lastChildren = false
|
||||
if off == 0 {
|
||||
if len(d.unit) == 0 {
|
||||
return
|
||||
}
|
||||
u := &d.unit[0]
|
||||
r.unit = 0
|
||||
r.b = makeBuf(r.d, u, "info", u.off, u.data)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(rsc): binary search (maybe a new package)
|
||||
var i int
|
||||
var u *unit
|
||||
for i = range d.unit {
|
||||
u = &d.unit[i]
|
||||
if u.off <= off && off < u.off+Offset(len(u.data)) {
|
||||
r.unit = i
|
||||
r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
|
||||
return
|
||||
}
|
||||
}
|
||||
r.err = errors.New("offset out of range")
|
||||
}
|
||||
|
||||
// maybeNextUnit advances to the next unit if this one is finished.
|
||||
func (r *Reader) maybeNextUnit() {
|
||||
for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
|
||||
r.unit++
|
||||
u := &r.d.unit[r.unit]
|
||||
r.b = makeBuf(r.d, u, "info", u.off, u.data)
|
||||
}
|
||||
}
|
||||
|
||||
// Next reads the next entry from the encoded entry stream.
|
||||
// It returns nil, nil when it reaches the end of the section.
|
||||
// It returns an error if the current offset is invalid or the data at the
|
||||
// offset cannot be decoded as a valid Entry.
|
||||
func (r *Reader) Next() (*Entry, error) {
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
r.maybeNextUnit()
|
||||
if len(r.b.data) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
u := &r.d.unit[r.unit]
|
||||
e := r.b.entry(u.atable, u.base)
|
||||
if r.b.err != nil {
|
||||
r.err = r.b.err
|
||||
return nil, r.err
|
||||
}
|
||||
if e != nil {
|
||||
r.lastChildren = e.Children
|
||||
if r.lastChildren {
|
||||
r.lastSibling, _ = e.Val(AttrSibling).(Offset)
|
||||
}
|
||||
} else {
|
||||
r.lastChildren = false
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// SkipChildren skips over the child entries associated with
|
||||
// the last Entry returned by Next. If that Entry did not have
|
||||
// children or Next has not been called, SkipChildren is a no-op.
|
||||
func (r *Reader) SkipChildren() {
|
||||
if r.err != nil || !r.lastChildren {
|
||||
return
|
||||
}
|
||||
|
||||
// If the last entry had a sibling attribute,
|
||||
// that attribute gives the offset of the next
|
||||
// sibling, so we can avoid decoding the
|
||||
// child subtrees.
|
||||
if r.lastSibling >= r.b.off {
|
||||
r.Seek(r.lastSibling)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
e, err := r.Next()
|
||||
if err != nil || e == nil || e.Tag == 0 {
|
||||
break
|
||||
}
|
||||
if e.Children {
|
||||
r.SkipChildren()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clone returns a copy of the reader. This is used by the typeReader
|
||||
// interface.
|
||||
func (r *Reader) clone() typeReader {
|
||||
return r.d.Reader()
|
||||
}
|
||||
|
||||
// offset returns the current buffer offset. This is used by the
|
||||
// typeReader interface.
|
||||
func (r *Reader) offset() Offset {
|
||||
return r.b.off
|
||||
}
|
299
vendor/golang.org/x/debug/dwarf/frame.go
generated
vendored
Normal file
299
vendor/golang.org/x/debug/dwarf/frame.go
generated
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Mapping from PC to SP offset (called CFA - Canonical Frame Address - in DWARF).
|
||||
// This value is the offset from the stack pointer to the virtual frame pointer
|
||||
// (address of zeroth argument) at each PC value in the program.
|
||||
|
||||
package dwarf
|
||||
|
||||
import "fmt"
|
||||
|
||||
// http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.4 page 126
|
||||
// We implement only the CFA column of the table, not the location
|
||||
// information about other registers. In other words, we implement
|
||||
// only what we need to understand Go programs compiled by gc.
|
||||
|
||||
// PCToSPOffset returns the offset, at the specified PC, to add to the
|
||||
// SP to reach the virtual frame pointer, which corresponds to the
|
||||
// address of the zeroth argument of the function, the word on the
|
||||
// stack immediately above the return PC.
|
||||
func (d *Data) PCToSPOffset(pc uint64) (offset int64, err error) {
|
||||
if len(d.frame) == 0 {
|
||||
return 0, fmt.Errorf("PCToSPOffset: no frame table")
|
||||
}
|
||||
var m frameMachine
|
||||
// Assume the first info unit is the same as us. Extremely likely. TODO?
|
||||
if len(d.unit) == 0 {
|
||||
return 0, fmt.Errorf("PCToSPOffset: no info section")
|
||||
}
|
||||
buf := makeBuf(d, &d.unit[0], "frame", 0, d.frame)
|
||||
for len(buf.data) > 0 {
|
||||
offset, err := m.evalCompilationUnit(&buf, pc)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return offset, nil
|
||||
}
|
||||
return 0, fmt.Errorf("PCToSPOffset: no frame defined for PC %#x", pc)
|
||||
}
|
||||
|
||||
// Call Frame instructions. Figure 40, page 181.
|
||||
// Structure is high two bits plus low 6 bits specified by + in comment.
|
||||
// Some take one or two operands.
|
||||
const (
|
||||
frameNop = 0<<6 + 0x00
|
||||
frameAdvanceLoc = 1<<6 + 0x00 // + delta
|
||||
frameOffset = 2<<6 + 0x00 // + register op: ULEB128 offset
|
||||
frameRestore = 3<<6 + 0x00 // + register
|
||||
frameSetLoc = 0<<6 + 0x01 // op: address
|
||||
frameAdvanceLoc1 = 0<<6 + 0x02 // op: 1-byte delta
|
||||
frameAdvanceLoc2 = 0<<6 + 0x03 // op: 2-byte delta
|
||||
frameAdvanceLoc4 = 0<<6 + 0x04 // op: 4-byte delta
|
||||
frameOffsetExtended = 0<<6 + 0x05 // ops: ULEB128 register ULEB128 offset
|
||||
frameRestoreExtended = 0<<6 + 0x06 // op: ULEB128 register
|
||||
frameUndefined = 0<<6 + 0x07 // op: ULEB128 register
|
||||
frameSameValue = 0<<6 + 0x08 // op: ULEB128 register
|
||||
frameRegister = 0<<6 + 0x09 // op: ULEB128 register ULEB128 register
|
||||
frameRememberState = 0<<6 + 0x0a
|
||||
frameRestoreState = 0<<6 + 0x0b
|
||||
frameDefCFA = 0<<6 + 0x0c // op: ULEB128 register ULEB128 offset
|
||||
frameDefCFARegister = 0<<6 + 0x0d // op: ULEB128 register
|
||||
frameDefCFAOffset = 0<<6 + 0x0e // op: ULEB128 offset
|
||||
frameDefCFAExpression = 0<<6 + 0x0f // op: BLOCK
|
||||
frameExpression = 0<<6 + 0x10 // op: ULEB128 register BLOCK
|
||||
frameOffsetExtendedSf = 0<<6 + 0x11 // op: ULEB128 register SLEB128 offset
|
||||
frameDefCFASf = 0<<6 + 0x12 // op: ULEB128 register SLEB128 offset
|
||||
frameDefCFAOffsetSf = 0<<6 + 0x13 // op: SLEB128 offset
|
||||
frameValOffset = 0<<6 + 0x14 // op: ULEB128 ULEB128
|
||||
frameValOffsetSf = 0<<6 + 0x15 // op: ULEB128 SLEB128
|
||||
frameValExpression = 0<<6 + 0x16 // op: ULEB128 BLOCK
|
||||
frameLoUser = 0<<6 + 0x1c
|
||||
frameHiUser = 0<<6 + 0x3f
|
||||
)
|
||||
|
||||
// frameMachine represents the PC/SP engine.
|
||||
// Section 6.4, page 129.
|
||||
type frameMachine struct {
|
||||
// Initial values from CIE.
|
||||
version uint8 // Version number, "independent of DWARF version"
|
||||
augmentation string // Augmentation; treated as unexpected for now. TODO.
|
||||
addressSize uint8 // In DWARF v4 and above. Size of a target address.
|
||||
segmentSize uint8 // In DWARF v4 and above. Size of a segment selector.
|
||||
codeAlignmentFactor uint64 // Unit of code size in advance instructions.
|
||||
dataAlignmentFactor int64 // Unit of data size in certain offset instructions.
|
||||
returnAddressRegister int // Pseudo-register (actually data column) representing return address.
|
||||
returnRegisterOffset int64 // Offset to saved PC from CFA in bytes.
|
||||
// CFA definition.
|
||||
cfaRegister int // Which register represents the SP.
|
||||
cfaOffset int64 // CFA offset value.
|
||||
// Running machine.
|
||||
location uint64
|
||||
}
|
||||
|
||||
// evalCompilationUnit scans the frame data for one compilation unit to retrieve
|
||||
// the offset information for the specified pc.
|
||||
func (m *frameMachine) evalCompilationUnit(b *buf, pc uint64) (int64, error) {
|
||||
err := m.parseCIE(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for {
|
||||
offset, found, err := m.scanFDE(b, pc)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if found {
|
||||
return offset, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parseCIE assumes the incoming buffer starts with a CIE block and parses it
|
||||
// to initialize a frameMachine.
|
||||
func (m *frameMachine) parseCIE(allBuf *buf) error {
|
||||
length := int(allBuf.uint32())
|
||||
if len(allBuf.data) < length {
|
||||
return fmt.Errorf("CIE parse error: too short")
|
||||
}
|
||||
// Create buffer for just this section.
|
||||
b := allBuf.slice(length)
|
||||
cie := b.uint32()
|
||||
if cie != 0xFFFFFFFF {
|
||||
return fmt.Errorf("CIE parse error: not CIE: %x", cie)
|
||||
}
|
||||
m.version = b.uint8()
|
||||
if m.version != 3 && m.version != 4 {
|
||||
return fmt.Errorf("CIE parse error: unsupported version %d", m.version)
|
||||
}
|
||||
m.augmentation = b.string()
|
||||
if len(m.augmentation) > 0 {
|
||||
return fmt.Errorf("CIE: can't handled augmentation string %q", m.augmentation)
|
||||
}
|
||||
if m.version >= 4 {
|
||||
m.addressSize = b.uint8()
|
||||
m.segmentSize = b.uint8()
|
||||
} else {
|
||||
// Unused. Gc generates version 3, so these values will not be
|
||||
// set, but they are also not used so it's OK.
|
||||
}
|
||||
m.codeAlignmentFactor = b.uint()
|
||||
m.dataAlignmentFactor = b.int()
|
||||
m.returnAddressRegister = int(b.uint())
|
||||
|
||||
// Initial instructions. At least for Go, establishes SP register number
|
||||
// and initial value of CFA offset at start of function.
|
||||
_, err := m.run(&b, ^uint64(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// There's padding, but we can ignore it.
|
||||
return nil
|
||||
}
|
||||
|
||||
// scanFDE assumes the incoming buffer starts with a FDE block and parses it
|
||||
// to run a frameMachine and, if the PC is represented in its range, return
|
||||
// the CFA offset for that PC. The boolean returned reports whether the
|
||||
// PC is in range for this FDE.
|
||||
func (m *frameMachine) scanFDE(allBuf *buf, pc uint64) (int64, bool, error) {
|
||||
length := int(allBuf.uint32())
|
||||
if len(allBuf.data) < length {
|
||||
return 0, false, fmt.Errorf("FDE parse error: too short")
|
||||
}
|
||||
if length <= 0 {
|
||||
if length == 0 {
|
||||
// EOF.
|
||||
return 0, false, fmt.Errorf("PC %#x not found in PC/SP table", pc)
|
||||
}
|
||||
return 0, false, fmt.Errorf("bad FDE length %d", length)
|
||||
}
|
||||
// Create buffer for just this section.
|
||||
b := allBuf.slice(length)
|
||||
cieOffset := b.uint32() // TODO assumes 32 bits.
|
||||
// Expect 0: first CIE in this segment. TODO.
|
||||
if cieOffset != 0 {
|
||||
return 0, false, fmt.Errorf("FDE parse error: bad CIE offset: %.2x", cieOffset)
|
||||
}
|
||||
// Initial location.
|
||||
m.location = b.addr()
|
||||
addressRange := b.addr()
|
||||
// If the PC is not in this function, there's no point in executing the instructions.
|
||||
if pc < m.location || m.location+addressRange <= pc {
|
||||
return 0, false, nil
|
||||
}
|
||||
// The PC appears in this FDE. Scan to find the location.
|
||||
offset, err := m.run(&b, pc)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
|
||||
// There's padding, but we can ignore it.
|
||||
return offset, true, nil
|
||||
}
|
||||
|
||||
// run executes the instructions in the buffer, which has been sliced to contain
|
||||
// only the data for this block. When we run out of data, we return.
|
||||
// Since we are only called when we know the PC is in this block, reaching
|
||||
// EOF is not an error, it just means the final CFA definition matches the
|
||||
// tail of the block that holds the PC.
|
||||
// The return value is the CFA at the end of the block or the PC, whichever
|
||||
// comes first.
|
||||
func (m *frameMachine) run(b *buf, pc uint64) (int64, error) {
|
||||
// We run the machine at location == PC because if the PC is at the first
|
||||
// instruction of a block, the definition of its offset arrives as an
|
||||
// offset-defining operand after the PC is set to that location.
|
||||
for m.location <= pc && len(b.data) > 0 {
|
||||
op := b.uint8()
|
||||
// Ops with embedded operands
|
||||
switch op & 0xC0 {
|
||||
case frameAdvanceLoc: // (6.4.2.1)
|
||||
// delta in low bits
|
||||
m.location += uint64(op & 0x3F)
|
||||
continue
|
||||
case frameOffset: // (6.4.2.3)
|
||||
// Register in low bits; ULEB128 offset.
|
||||
// For Go binaries we only see this in the CIE for the return address register.
|
||||
if int(op&0x3F) != m.returnAddressRegister {
|
||||
return 0, fmt.Errorf("invalid frameOffset register R%d should be R%d", op&0x3f, m.returnAddressRegister)
|
||||
}
|
||||
m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor
|
||||
continue
|
||||
case frameRestore: // (6.4.2.3)
|
||||
// register in low bits
|
||||
return 0, fmt.Errorf("unimplemented frameRestore(R%d)\n", op&0x3F)
|
||||
}
|
||||
|
||||
// The remaining ops do not have embedded operands.
|
||||
|
||||
switch op {
|
||||
// Row creation instructions (6.4.2.1)
|
||||
case frameNop:
|
||||
case frameSetLoc: // op: address
|
||||
return 0, fmt.Errorf("unimplemented setloc") // what size is operand?
|
||||
case frameAdvanceLoc1: // op: 1-byte delta
|
||||
m.location += uint64(b.uint8())
|
||||
case frameAdvanceLoc2: // op: 2-byte delta
|
||||
m.location += uint64(b.uint16())
|
||||
case frameAdvanceLoc4: // op: 4-byte delta
|
||||
m.location += uint64(b.uint32())
|
||||
|
||||
// CFA definition instructions (6.4.2.2)
|
||||
case frameDefCFA: // op: ULEB128 register ULEB128 offset
|
||||
m.cfaRegister = int(b.int())
|
||||
m.cfaOffset = int64(b.uint())
|
||||
case frameDefCFASf: // op: ULEB128 register SLEB128 offset
|
||||
return 0, fmt.Errorf("unimplemented frameDefCFASf")
|
||||
case frameDefCFARegister: // op: ULEB128 register
|
||||
return 0, fmt.Errorf("unimplemented frameDefCFARegister")
|
||||
case frameDefCFAOffset: // op: ULEB128 offset
|
||||
return 0, fmt.Errorf("unimplemented frameDefCFAOffset")
|
||||
case frameDefCFAOffsetSf: // op: SLEB128 offset
|
||||
offset := b.int()
|
||||
m.cfaOffset = offset * m.dataAlignmentFactor
|
||||
// TODO: Verify we are using a factored offset.
|
||||
case frameDefCFAExpression: // op: BLOCK
|
||||
return 0, fmt.Errorf("unimplemented frameDefCFAExpression")
|
||||
|
||||
// Register Rule instructions (6.4.2.3)
|
||||
case frameOffsetExtended: // ops: ULEB128 register ULEB128 offset
|
||||
// The same as frameOffset, but with the register specified in an operand.
|
||||
reg := b.uint()
|
||||
// For Go binaries we only see this in the CIE for the return address register.
|
||||
if reg != uint64(m.returnAddressRegister) {
|
||||
return 0, fmt.Errorf("invalid frameOffsetExtended: register R%d should be R%d", reg, m.returnAddressRegister)
|
||||
}
|
||||
m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor
|
||||
case frameRestoreExtended: // op: ULEB128 register
|
||||
return 0, fmt.Errorf("unimplemented frameRestoreExtended")
|
||||
case frameUndefined: // op: ULEB128 register; unimplemented
|
||||
return 0, fmt.Errorf("unimplemented frameUndefined")
|
||||
case frameSameValue: // op: ULEB128 register
|
||||
return 0, fmt.Errorf("unimplemented frameSameValue")
|
||||
case frameRegister: // op: ULEB128 register ULEB128 register
|
||||
return 0, fmt.Errorf("unimplemented frameRegister")
|
||||
case frameRememberState:
|
||||
return 0, fmt.Errorf("unimplemented frameRememberState")
|
||||
case frameRestoreState:
|
||||
return 0, fmt.Errorf("unimplemented frameRestoreState")
|
||||
case frameExpression: // op: ULEB128 register BLOCK
|
||||
return 0, fmt.Errorf("unimplemented frameExpression")
|
||||
case frameOffsetExtendedSf: // op: ULEB128 register SLEB128 offset
|
||||
return 0, fmt.Errorf("unimplemented frameOffsetExtended_sf")
|
||||
case frameValOffset: // op: ULEB128 ULEB128
|
||||
return 0, fmt.Errorf("unimplemented frameValOffset")
|
||||
case frameValOffsetSf: // op: ULEB128 SLEB128
|
||||
return 0, fmt.Errorf("unimplemented frameValOffsetSf")
|
||||
case frameValExpression: // op: ULEB128 BLOCK
|
||||
return 0, fmt.Errorf("unimplemented frameValExpression")
|
||||
|
||||
default:
|
||||
if frameLoUser <= op && op <= frameHiUser {
|
||||
return 0, fmt.Errorf("unknown user-defined frame op %#x", op)
|
||||
}
|
||||
return 0, fmt.Errorf("unknown frame op %#x", op)
|
||||
}
|
||||
}
|
||||
return m.cfaOffset, nil
|
||||
}
|
448
vendor/golang.org/x/debug/dwarf/line.go
generated
vendored
Normal file
448
vendor/golang.org/x/debug/dwarf/line.go
generated
vendored
Normal file
@ -0,0 +1,448 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dwarf
|
||||
|
||||
// This file implements the mapping from PC to lines.
|
||||
// TODO: Find a way to test this properly.
|
||||
|
||||
// http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.2 page 108
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PCToLine returns the file and line number corresponding to the PC value.
|
||||
// It returns an error if a correspondence cannot be found.
|
||||
func (d *Data) PCToLine(pc uint64) (file string, line uint64, err error) {
|
||||
c := d.pcToLineEntries
|
||||
if len(c) == 0 {
|
||||
return "", 0, fmt.Errorf("PCToLine: no line table")
|
||||
}
|
||||
i := sort.Search(len(c), func(i int) bool { return c[i].pc > pc }) - 1
|
||||
// c[i] is now the entry in pcToLineEntries with the largest pc that is not
|
||||
// larger than the query pc.
|
||||
// The search has failed if:
|
||||
// - All pcs in c were larger than the query pc (i == -1).
|
||||
// - c[i] marked the end of a sequence of instructions (c[i].file == 0).
|
||||
// - c[i] is the last element of c, and isn't the end of a sequence of
|
||||
// instructions, and the search pc is much larger than c[i].pc. In this
|
||||
// case, we don't know the range of the last instruction, but the search
|
||||
// pc is probably past it.
|
||||
if i == -1 || c[i].file == 0 || (i+1 == len(c) && pc-c[i].pc > 1024) {
|
||||
return "", 0, fmt.Errorf("no source line defined for PC %#x", pc)
|
||||
}
|
||||
if c[i].file >= uint64(len(d.sourceFiles)) {
|
||||
return "", 0, fmt.Errorf("invalid file number in DWARF data")
|
||||
}
|
||||
return d.sourceFiles[c[i].file], c[i].line, nil
|
||||
}
|
||||
|
||||
// LineToBreakpointPCs returns the PCs that should be used as breakpoints
|
||||
// corresponding to the given file and line number.
|
||||
// It returns an empty slice if no PCs were found.
|
||||
func (d *Data) LineToBreakpointPCs(file string, line uint64) ([]uint64, error) {
|
||||
compDir := d.compilationDirectory()
|
||||
|
||||
// Find the closest match in the executable for the specified file.
|
||||
// We choose the file with the largest number of path components matching
|
||||
// at the end of the name. If there is a tie, we prefer files that are
|
||||
// under the compilation directory. If there is still a tie, we choose
|
||||
// the file with the shortest name.
|
||||
// TODO: handle duplicate file names in the DWARF?
|
||||
var bestFile struct {
|
||||
fileNum uint64 // Index of the file in the DWARF data.
|
||||
components int // Number of matching path components.
|
||||
length int // Length of the filename.
|
||||
underComp bool // File is under the compilation directory.
|
||||
}
|
||||
for filenum, filename := range d.sourceFiles {
|
||||
c := matchingPathComponentSuffixSize(filename, file)
|
||||
underComp := strings.HasPrefix(filename, compDir)
|
||||
better := false
|
||||
if c != bestFile.components {
|
||||
better = c > bestFile.components
|
||||
} else if underComp != bestFile.underComp {
|
||||
better = underComp
|
||||
} else {
|
||||
better = len(filename) < bestFile.length
|
||||
}
|
||||
if better {
|
||||
bestFile.fileNum = uint64(filenum)
|
||||
bestFile.components = c
|
||||
bestFile.length = len(filename)
|
||||
bestFile.underComp = underComp
|
||||
}
|
||||
}
|
||||
if bestFile.components == 0 {
|
||||
return nil, fmt.Errorf("couldn't find file %q", file)
|
||||
}
|
||||
|
||||
c := d.lineToPCEntries[bestFile.fileNum]
|
||||
// c contains all (pc, line) pairs for the appropriate file.
|
||||
start := sort.Search(len(c), func(i int) bool { return c[i].line >= line })
|
||||
end := sort.Search(len(c), func(i int) bool { return c[i].line > line })
|
||||
// c[i].line == line for all i in the range [start, end).
|
||||
pcs := make([]uint64, 0, end-start)
|
||||
for i := start; i < end; i++ {
|
||||
pcs = append(pcs, c[i].pc)
|
||||
}
|
||||
return pcs, nil
|
||||
}
|
||||
|
||||
// compilationDirectory finds the first compilation unit entry in d and returns
|
||||
// the compilation directory contained in it.
|
||||
// If it fails, it returns the empty string.
|
||||
func (d *Data) compilationDirectory() string {
|
||||
r := d.Reader()
|
||||
for {
|
||||
entry, err := r.Next()
|
||||
if entry == nil || err != nil {
|
||||
return ""
|
||||
}
|
||||
if entry.Tag == TagCompileUnit {
|
||||
name, _ := entry.Val(AttrCompDir).(string)
|
||||
return name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// matchingPathComponentSuffixSize returns the largest n such that the last n
|
||||
// components of the paths p1 and p2 are equal.
|
||||
// e.g. matchingPathComponentSuffixSize("a/b/x/y.go", "b/a/x/y.go") returns 2.
|
||||
func matchingPathComponentSuffixSize(p1, p2 string) int {
|
||||
// TODO: deal with other path separators.
|
||||
c1 := strings.Split(p1, "/")
|
||||
c2 := strings.Split(p2, "/")
|
||||
min := len(c1)
|
||||
if len(c2) < min {
|
||||
min = len(c2)
|
||||
}
|
||||
var n int
|
||||
for n = 0; n < min; n++ {
|
||||
if c1[len(c1)-1-n] != c2[len(c2)-1-n] {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Standard opcodes. Figure 37, page 178.
|
||||
// If an opcode >= lineMachine.prologue.opcodeBase, it is a special
|
||||
// opcode rather than the opcode defined in this table.
|
||||
const (
|
||||
lineStdCopy = 0x01
|
||||
lineStdAdvancePC = 0x02
|
||||
lineStdAdvanceLine = 0x03
|
||||
lineStdSetFile = 0x04
|
||||
lineStdSetColumn = 0x05
|
||||
lineStdNegateStmt = 0x06
|
||||
lineStdSetBasicBlock = 0x07
|
||||
lineStdConstAddPC = 0x08
|
||||
lineStdFixedAdvancePC = 0x09
|
||||
lineStdSetPrologueEnd = 0x0a
|
||||
lineStdSetEpilogueBegin = 0x0b
|
||||
lineStdSetISA = 0x0c
|
||||
)
|
||||
|
||||
// Extended opcodes. Figure 38, page 179.
|
||||
const (
|
||||
lineStartExtendedOpcode = 0x00 // Not defined as a named constant in the spec.
|
||||
lineExtEndSequence = 0x01
|
||||
lineExtSetAddress = 0x02
|
||||
lineExtDefineFile = 0x03
|
||||
lineExtSetDiscriminator = 0x04 // New in version 4.
|
||||
lineExtLoUser = 0x80
|
||||
lineExtHiUser = 0xff
|
||||
)
|
||||
|
||||
// lineHeader holds the information stored in the header of the line table for a
|
||||
// single compilation unit.
|
||||
// Section 6.2.4, page 112.
|
||||
type lineHeader struct {
|
||||
unitLength int
|
||||
version int
|
||||
headerLength int
|
||||
minInstructionLength int
|
||||
maxOpsPerInstruction int
|
||||
defaultIsStmt bool
|
||||
lineBase int
|
||||
lineRange int
|
||||
opcodeBase byte
|
||||
stdOpcodeLengths []byte
|
||||
include []string // entry 0 is empty; means current directory
|
||||
file []lineFile // entry 0 is empty.
|
||||
}
|
||||
|
||||
// lineFile represents a file name stored in the PC/line table, usually in the header.
|
||||
type lineFile struct {
|
||||
name string
|
||||
index int // index into include directories
|
||||
time int // implementation-defined time of last modification
|
||||
length int // length in bytes, 0 if not available.
|
||||
}
|
||||
|
||||
// lineMachine holds the registers evaluated during executing of the PC/line mapping engine.
|
||||
// Section 6.2.2, page 109.
|
||||
type lineMachine struct {
|
||||
// The program-counter value corresponding to a machine instruction generated by the compiler.
|
||||
address uint64
|
||||
|
||||
// An unsigned integer representing the index of an operation within a VLIW
|
||||
// instruction. The index of the first operation is 0. For non-VLIW
|
||||
// architectures, this register will always be 0.
|
||||
// The address and op_index registers, taken together, form an operation
|
||||
// pointer that can reference any individual operation with the instruction
|
||||
// stream.
|
||||
opIndex uint64
|
||||
|
||||
// An unsigned integer indicating the identity of the source file corresponding to a machine instruction.
|
||||
file uint64
|
||||
|
||||
// An unsigned integer indicating a source line number. Lines are numbered
|
||||
// beginning at 1. The compiler may emit the value 0 in cases where an
|
||||
// instruction cannot be attributed to any source line.
|
||||
line uint64
|
||||
|
||||
// An unsigned integer indicating a column number within a source line.
|
||||
// Columns are numbered beginning at 1. The value 0 is reserved to indicate
|
||||
// that a statement begins at the “left edge” of the line.
|
||||
column uint64
|
||||
|
||||
// A boolean indicating that the current instruction is a recommended
|
||||
// breakpoint location. A recommended breakpoint location is intended to
|
||||
// “represent” a line, a statement and/or a semantically distinct subpart of a
|
||||
// statement.
|
||||
isStmt bool
|
||||
|
||||
// A boolean indicating that the current instruction is the beginning of a basic
|
||||
// block.
|
||||
basicBlock bool
|
||||
|
||||
// A boolean indicating that the current address is that of the first byte after
|
||||
// the end of a sequence of target machine instructions. end_sequence
|
||||
// terminates a sequence of lines; therefore other information in the same
|
||||
// row is not meaningful.
|
||||
endSequence bool
|
||||
|
||||
// A boolean indicating that the current address is one (of possibly many)
|
||||
// where execution should be suspended for an entry breakpoint of a
|
||||
// function.
|
||||
prologueEnd bool
|
||||
|
||||
// A boolean indicating that the current address is one (of possibly many)
|
||||
// where execution should be suspended for an exit breakpoint of a function.
|
||||
epilogueBegin bool
|
||||
|
||||
// An unsigned integer whose value encodes the applicable instruction set
|
||||
// architecture for the current instruction.
|
||||
// The encoding of instruction sets should be shared by all users of a given
|
||||
// architecture. It is recommended that this encoding be defined by the ABI
|
||||
// authoring committee for each architecture.
|
||||
isa uint64
|
||||
|
||||
// An unsigned integer identifying the block to which the current instruction
|
||||
// belongs. Discriminator values are assigned arbitrarily by the DWARF
|
||||
// producer and serve to distinguish among multiple blocks that may all be
|
||||
// associated with the same source file, line, and column. Where only one
|
||||
// block exists for a given source position, the discriminator value should be
|
||||
// zero.
|
||||
discriminator uint64
|
||||
|
||||
// The header for the current compilation unit.
|
||||
// Not an actual register, but stored here for cleanliness.
|
||||
header lineHeader
|
||||
}
|
||||
|
||||
// parseHeader parses the header describing the compilation unit in the line
|
||||
// table starting at the specified offset.
|
||||
func (m *lineMachine) parseHeader(b *buf) error {
|
||||
m.header = lineHeader{}
|
||||
m.header.unitLength = int(b.uint32()) // Note: We are assuming 32-bit DWARF format.
|
||||
if m.header.unitLength > len(b.data) {
|
||||
return fmt.Errorf("DWARF: bad PC/line header length")
|
||||
}
|
||||
m.header.version = int(b.uint16())
|
||||
m.header.headerLength = int(b.uint32())
|
||||
m.header.minInstructionLength = int(b.uint8())
|
||||
if m.header.version >= 4 {
|
||||
m.header.maxOpsPerInstruction = int(b.uint8())
|
||||
} else {
|
||||
m.header.maxOpsPerInstruction = 1
|
||||
}
|
||||
m.header.defaultIsStmt = b.uint8() != 0
|
||||
m.header.lineBase = int(int8(b.uint8()))
|
||||
m.header.lineRange = int(b.uint8())
|
||||
m.header.opcodeBase = b.uint8()
|
||||
m.header.stdOpcodeLengths = make([]byte, m.header.opcodeBase-1)
|
||||
copy(m.header.stdOpcodeLengths, b.bytes(int(m.header.opcodeBase-1)))
|
||||
m.header.include = make([]string, 1) // First entry is empty; file index entries are 1-indexed.
|
||||
// Includes
|
||||
for {
|
||||
name := b.string()
|
||||
if name == "" {
|
||||
break
|
||||
}
|
||||
m.header.include = append(m.header.include, name)
|
||||
}
|
||||
// Files
|
||||
m.header.file = make([]lineFile, 1, 10) // entries are 1-indexed in line number program.
|
||||
for {
|
||||
name := b.string()
|
||||
if name == "" {
|
||||
break
|
||||
}
|
||||
index := b.uint()
|
||||
time := b.uint()
|
||||
length := b.uint()
|
||||
f := lineFile{
|
||||
name: name,
|
||||
index: int(index),
|
||||
time: int(time),
|
||||
length: int(length),
|
||||
}
|
||||
m.header.file = append(m.header.file, f)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Special opcodes, page 117.
|
||||
// There are seven steps to processing special opcodes. We break them up here
|
||||
// because the caller needs to output a row between steps 2 and 4, and because
|
||||
// we need to perform just step 2 for the opcode DW_LNS_const_add_pc.
|
||||
|
||||
func (m *lineMachine) specialOpcodeStep1(opcode byte) {
|
||||
adjustedOpcode := int(opcode - m.header.opcodeBase)
|
||||
lineAdvance := m.header.lineBase + (adjustedOpcode % m.header.lineRange)
|
||||
m.line += uint64(lineAdvance)
|
||||
}
|
||||
|
||||
func (m *lineMachine) specialOpcodeStep2(opcode byte) {
|
||||
adjustedOpcode := int(opcode - m.header.opcodeBase)
|
||||
advance := adjustedOpcode / m.header.lineRange
|
||||
delta := (int(m.opIndex) + advance) / m.header.maxOpsPerInstruction
|
||||
m.address += uint64(m.header.minInstructionLength * delta)
|
||||
m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction)
|
||||
}
|
||||
|
||||
func (m *lineMachine) specialOpcodeSteps4To7() {
|
||||
m.basicBlock = false
|
||||
m.prologueEnd = false
|
||||
m.epilogueBegin = false
|
||||
m.discriminator = 0
|
||||
}
|
||||
|
||||
// evalCompilationUnit reads the next compilation unit and calls f at each output row.
|
||||
// Line machine execution continues while f returns true.
|
||||
func (m *lineMachine) evalCompilationUnit(b *buf, f func(m *lineMachine) (cont bool)) error {
|
||||
m.reset()
|
||||
for len(b.data) > 0 {
|
||||
op := b.uint8()
|
||||
if op >= m.header.opcodeBase {
|
||||
m.specialOpcodeStep1(op)
|
||||
m.specialOpcodeStep2(op)
|
||||
// Step 3 is to output a row, so we call f here.
|
||||
if !f(m) {
|
||||
return nil
|
||||
}
|
||||
m.specialOpcodeSteps4To7()
|
||||
continue
|
||||
}
|
||||
switch op {
|
||||
case lineStartExtendedOpcode:
|
||||
if len(b.data) == 0 {
|
||||
return fmt.Errorf("DWARF: short extended opcode (1)")
|
||||
}
|
||||
size := b.uint()
|
||||
if uint64(len(b.data)) < size {
|
||||
return fmt.Errorf("DWARF: short extended opcode (2)")
|
||||
}
|
||||
op = b.uint8()
|
||||
switch op {
|
||||
case lineExtEndSequence:
|
||||
m.endSequence = true
|
||||
if !f(m) {
|
||||
return nil
|
||||
}
|
||||
if len(b.data) == 0 {
|
||||
return nil
|
||||
}
|
||||
m.reset()
|
||||
case lineExtSetAddress:
|
||||
m.address = b.addr()
|
||||
m.opIndex = 0
|
||||
case lineExtDefineFile:
|
||||
return fmt.Errorf("DWARF: unimplemented define_file op")
|
||||
case lineExtSetDiscriminator:
|
||||
discriminator := b.uint()
|
||||
m.discriminator = discriminator
|
||||
default:
|
||||
return fmt.Errorf("DWARF: unknown extended opcode %#x", op)
|
||||
}
|
||||
case lineStdCopy:
|
||||
if !f(m) {
|
||||
return nil
|
||||
}
|
||||
m.discriminator = 0
|
||||
m.basicBlock = false
|
||||
m.prologueEnd = false
|
||||
m.epilogueBegin = false
|
||||
case lineStdAdvancePC:
|
||||
advance := b.uint()
|
||||
delta := (int(m.opIndex) + int(advance)) / m.header.maxOpsPerInstruction
|
||||
m.address += uint64(m.header.minInstructionLength * delta)
|
||||
m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction)
|
||||
m.basicBlock = false
|
||||
m.prologueEnd = false
|
||||
m.epilogueBegin = false
|
||||
m.discriminator = 0
|
||||
case lineStdAdvanceLine:
|
||||
advance := b.int()
|
||||
m.line = uint64(int64(m.line) + advance)
|
||||
case lineStdSetFile:
|
||||
index := b.uint()
|
||||
m.file = index
|
||||
case lineStdSetColumn:
|
||||
column := b.uint()
|
||||
m.column = column
|
||||
case lineStdNegateStmt:
|
||||
m.isStmt = !m.isStmt
|
||||
case lineStdSetBasicBlock:
|
||||
m.basicBlock = true
|
||||
case lineStdFixedAdvancePC:
|
||||
m.address += uint64(b.uint16())
|
||||
m.opIndex = 0
|
||||
case lineStdSetPrologueEnd:
|
||||
m.prologueEnd = true
|
||||
case lineStdSetEpilogueBegin:
|
||||
m.epilogueBegin = true
|
||||
case lineStdSetISA:
|
||||
m.isa = b.uint()
|
||||
case lineStdConstAddPC:
|
||||
// Update the the address and op_index registers.
|
||||
m.specialOpcodeStep2(255)
|
||||
default:
|
||||
panic("not reached")
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("DWARF: unexpected end of line number information")
|
||||
}
|
||||
|
||||
// reset sets the machine's registers to the initial state. Page 111.
|
||||
func (m *lineMachine) reset() {
|
||||
m.address = 0
|
||||
m.opIndex = 0
|
||||
m.file = 1
|
||||
m.line = 1
|
||||
m.column = 0
|
||||
m.isStmt = m.header.defaultIsStmt
|
||||
m.basicBlock = false
|
||||
m.endSequence = false
|
||||
m.prologueEnd = false
|
||||
m.epilogueBegin = false
|
||||
m.isa = 0
|
||||
m.discriminator = 0
|
||||
}
|
94
vendor/golang.org/x/debug/dwarf/open.go
generated
vendored
Normal file
94
vendor/golang.org/x/debug/dwarf/open.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package dwarf provides access to DWARF debugging information loaded from
|
||||
// executable files, as defined in the DWARF 2.0 Standard at
|
||||
// http://dwarfstd.org/doc/dwarf-2.0.0.pdf
|
||||
package dwarf
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// Data represents the DWARF debugging information
|
||||
// loaded from an executable file (for example, an ELF or Mach-O executable).
|
||||
type Data struct {
|
||||
// raw data
|
||||
abbrev []byte
|
||||
aranges []byte
|
||||
frame []byte
|
||||
info []byte
|
||||
line []byte
|
||||
pubnames []byte
|
||||
ranges []byte
|
||||
str []byte
|
||||
|
||||
// parsed data
|
||||
abbrevCache map[uint32]abbrevTable
|
||||
order binary.ByteOrder
|
||||
typeCache map[Offset]Type
|
||||
typeSigs map[uint64]*typeUnit
|
||||
unit []unit
|
||||
sourceFiles []string // source files listed in .debug_line.
|
||||
nameCache // map from name to top-level entries in .debug_info.
|
||||
pcToFuncEntries // cache of .debug_info data for function bounds.
|
||||
pcToLineEntries // cache of .debug_line data, used for efficient PC-to-line mapping.
|
||||
lineToPCEntries // cache of .debug_line data, used for efficient line-to-[]PC mapping.
|
||||
}
|
||||
|
||||
// New returns a new Data object initialized from the given parameters.
|
||||
// Rather than calling this function directly, clients should typically use
|
||||
// the DWARF method of the File type of the appropriate package debug/elf,
|
||||
// debug/macho, or debug/pe.
|
||||
//
|
||||
// The []byte arguments are the data from the corresponding debug section
|
||||
// in the object file; for example, for an ELF object, abbrev is the contents of
|
||||
// the ".debug_abbrev" section.
|
||||
func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) {
|
||||
d := &Data{
|
||||
abbrev: abbrev,
|
||||
aranges: aranges,
|
||||
frame: frame,
|
||||
info: info,
|
||||
line: line,
|
||||
pubnames: pubnames,
|
||||
ranges: ranges,
|
||||
str: str,
|
||||
abbrevCache: make(map[uint32]abbrevTable),
|
||||
typeCache: make(map[Offset]Type),
|
||||
typeSigs: make(map[uint64]*typeUnit),
|
||||
}
|
||||
|
||||
// Sniff .debug_info to figure out byte order.
|
||||
// bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
|
||||
if len(d.info) < 6 {
|
||||
return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
|
||||
}
|
||||
x, y := d.info[4], d.info[5]
|
||||
switch {
|
||||
case x == 0 && y == 0:
|
||||
return nil, DecodeError{"info", 4, "unsupported version 0"}
|
||||
case x == 0:
|
||||
d.order = binary.BigEndian
|
||||
case y == 0:
|
||||
d.order = binary.LittleEndian
|
||||
default:
|
||||
return nil, DecodeError{"info", 4, "cannot determine byte order"}
|
||||
}
|
||||
|
||||
u, err := d.parseUnits()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.unit = u
|
||||
d.buildInfoCaches()
|
||||
d.buildLineCaches()
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// AddTypes will add one .debug_types section to the DWARF data. A
|
||||
// typical object with DWARF version 4 debug info will have multiple
|
||||
// .debug_types sections. The name is used for error reporting only,
|
||||
// and serves to distinguish one .debug_types section from another.
|
||||
func (d *Data) AddTypes(name string, types []byte) error {
|
||||
return d.parseTypes(name, types)
|
||||
}
|
119
vendor/golang.org/x/debug/dwarf/symbol.go
generated
vendored
Normal file
119
vendor/golang.org/x/debug/dwarf/symbol.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dwarf
|
||||
|
||||
// This file provides simple methods to access the symbol table by name and address.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// lookupEntry returns the first Entry for the name.
|
||||
// If tag is non-zero, only entries with that tag are considered.
|
||||
func (d *Data) lookupEntry(name string, tag Tag) (*Entry, error) {
|
||||
x, ok := d.nameCache[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("DWARF entry for %q not found", name)
|
||||
}
|
||||
for ; x != nil; x = x.link {
|
||||
if tag == 0 || x.entry.Tag == tag {
|
||||
return x.entry, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no DWARF entry for %q with tag %s", name, tag)
|
||||
}
|
||||
|
||||
// LookupMatchingSymbols returns the names of all top-level entries matching
|
||||
// the given regular expression.
|
||||
func (d *Data) LookupMatchingSymbols(nameRE *regexp.Regexp) (result []string, err error) {
|
||||
for name := range d.nameCache {
|
||||
if nameRE.MatchString(name) {
|
||||
result = append(result, name)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LookupEntry returns the Entry for the named symbol.
|
||||
func (d *Data) LookupEntry(name string) (*Entry, error) {
|
||||
return d.lookupEntry(name, 0)
|
||||
}
|
||||
|
||||
// LookupFunction returns the entry for a function.
|
||||
func (d *Data) LookupFunction(name string) (*Entry, error) {
|
||||
return d.lookupEntry(name, TagSubprogram)
|
||||
}
|
||||
|
||||
// LookupVariable returns the entry for a (global) variable.
|
||||
func (d *Data) LookupVariable(name string) (*Entry, error) {
|
||||
return d.lookupEntry(name, TagVariable)
|
||||
}
|
||||
|
||||
// EntryLocation returns the address of the object referred to by the given Entry.
|
||||
func (d *Data) EntryLocation(e *Entry) (uint64, error) {
|
||||
loc, _ := e.Val(AttrLocation).([]byte)
|
||||
if len(loc) == 0 {
|
||||
return 0, fmt.Errorf("DWARF entry has no Location attribute")
|
||||
}
|
||||
// TODO: implement the DWARF Location bytecode. What we have here only
|
||||
// recognizes a program with a single literal opAddr bytecode.
|
||||
if asize := d.unit[0].asize; loc[0] == opAddr && len(loc) == 1+asize {
|
||||
switch asize {
|
||||
case 1:
|
||||
return uint64(loc[1]), nil
|
||||
case 2:
|
||||
return uint64(d.order.Uint16(loc[1:])), nil
|
||||
case 4:
|
||||
return uint64(d.order.Uint32(loc[1:])), nil
|
||||
case 8:
|
||||
return d.order.Uint64(loc[1:]), nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("DWARF entry has an unimplemented Location op")
|
||||
}
|
||||
|
||||
// EntryType returns the Type for an Entry.
|
||||
func (d *Data) EntryType(e *Entry) (Type, error) {
|
||||
off, err := d.EntryTypeOffset(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.Type(off)
|
||||
}
|
||||
|
||||
// EntryTypeOffset returns the offset in the given Entry's type attribute.
|
||||
func (d *Data) EntryTypeOffset(e *Entry) (Offset, error) {
|
||||
v := e.Val(AttrType)
|
||||
if v == nil {
|
||||
return 0, fmt.Errorf("DWARF entry has no Type attribute")
|
||||
}
|
||||
off, ok := v.(Offset)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("DWARF entry has an invalid Type attribute")
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
|
||||
// PCToFunction returns the entry and address for the function containing the
|
||||
// specified PC.
|
||||
func (d *Data) PCToFunction(pc uint64) (entry *Entry, lowpc uint64, err error) {
|
||||
p := d.pcToFuncEntries
|
||||
if len(p) == 0 {
|
||||
return nil, 0, fmt.Errorf("no function addresses loaded")
|
||||
}
|
||||
i := sort.Search(len(p), func(i int) bool { return p[i].pc > pc }) - 1
|
||||
// The search failed if:
|
||||
// - pc was before the start of any function.
|
||||
// - The largest function bound not larger than pc was the end of a function,
|
||||
// not the start of one.
|
||||
// - The largest function bound not larger than pc was the start of a function
|
||||
// that we don't know the end of, and the PC is much larger than the start.
|
||||
if i == -1 || p[i].entry == nil || (i+1 == len(p) && pc-p[i].pc >= 1<<20) {
|
||||
return nil, 0, fmt.Errorf("no function at %x", pc)
|
||||
}
|
||||
return p[i].entry, p[i].pc, nil
|
||||
}
|
862
vendor/golang.org/x/debug/dwarf/type.go
generated
vendored
Normal file
862
vendor/golang.org/x/debug/dwarf/type.go
generated
vendored
Normal file
@ -0,0 +1,862 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// DWARF type information structures.
|
||||
// The format is heavily biased toward C, but for simplicity
|
||||
// the String methods use a pseudo-Go syntax.
|
||||
|
||||
package dwarf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// A Type conventionally represents a pointer to any of the
|
||||
// specific Type structures (CharType, StructType, etc.).
|
||||
type Type interface {
|
||||
Common() *CommonType
|
||||
String() string
|
||||
Size() int64
|
||||
}
|
||||
|
||||
// A CommonType holds fields common to multiple types.
|
||||
// If a field is not known or not applicable for a given type,
|
||||
// the zero value is used.
|
||||
type CommonType struct {
|
||||
ByteSize int64 // size of value of this type, in bytes
|
||||
Name string // name that can be used to refer to type
|
||||
ReflectKind reflect.Kind // the reflect kind of the type.
|
||||
Offset Offset // the offset at which this type was read
|
||||
}
|
||||
|
||||
func (c *CommonType) Common() *CommonType { return c }
|
||||
|
||||
func (c *CommonType) Size() int64 { return c.ByteSize }
|
||||
|
||||
// Basic types
|
||||
|
||||
// A BasicType holds fields common to all basic types.
|
||||
type BasicType struct {
|
||||
CommonType
|
||||
BitSize int64
|
||||
BitOffset int64
|
||||
}
|
||||
|
||||
func (b *BasicType) Basic() *BasicType { return b }
|
||||
|
||||
func (t *BasicType) String() string {
|
||||
if t.Name != "" {
|
||||
return t.Name
|
||||
}
|
||||
return "?"
|
||||
}
|
||||
|
||||
// A CharType represents a signed character type.
|
||||
type CharType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// A UcharType represents an unsigned character type.
|
||||
type UcharType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// An IntType represents a signed integer type.
|
||||
type IntType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// A UintType represents an unsigned integer type.
|
||||
type UintType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// A FloatType represents a floating point type.
|
||||
type FloatType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// A ComplexType represents a complex floating point type.
|
||||
type ComplexType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// A BoolType represents a boolean type.
|
||||
type BoolType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// An AddrType represents a machine address type.
|
||||
type AddrType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type.
|
||||
type UnspecifiedType struct {
|
||||
BasicType
|
||||
}
|
||||
|
||||
// qualifiers
|
||||
|
||||
// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier.
|
||||
type QualType struct {
|
||||
CommonType
|
||||
Qual string
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (t *QualType) String() string { return t.Qual + " " + t.Type.String() }
|
||||
|
||||
func (t *QualType) Size() int64 { return t.Type.Size() }
|
||||
|
||||
// An ArrayType represents a fixed size array type.
|
||||
type ArrayType struct {
|
||||
CommonType
|
||||
Type Type
|
||||
StrideBitSize int64 // if > 0, number of bits to hold each element
|
||||
Count int64 // if == -1, an incomplete array, like char x[].
|
||||
}
|
||||
|
||||
func (t *ArrayType) String() string {
|
||||
return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String()
|
||||
}
|
||||
|
||||
func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() }
|
||||
|
||||
// A VoidType represents the C void type.
|
||||
type VoidType struct {
|
||||
CommonType
|
||||
}
|
||||
|
||||
func (t *VoidType) String() string { return "void" }
|
||||
|
||||
// A PtrType represents a pointer type.
|
||||
type PtrType struct {
|
||||
CommonType
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (t *PtrType) String() string { return "*" + t.Type.String() }
|
||||
|
||||
// A StructType represents a struct, union, or C++ class type.
|
||||
type StructType struct {
|
||||
CommonType
|
||||
StructName string
|
||||
Kind string // "struct", "union", or "class".
|
||||
Field []*StructField
|
||||
Incomplete bool // if true, struct, union, class is declared but not defined
|
||||
}
|
||||
|
||||
// A StructField represents a field in a struct, union, or C++ class type.
|
||||
type StructField struct {
|
||||
Name string
|
||||
Type Type
|
||||
ByteOffset int64
|
||||
ByteSize int64
|
||||
BitOffset int64 // within the ByteSize bytes at ByteOffset
|
||||
BitSize int64 // zero if not a bit field
|
||||
}
|
||||
|
||||
func (t *StructType) String() string {
|
||||
if t.StructName != "" {
|
||||
return t.Kind + " " + t.StructName
|
||||
}
|
||||
return t.Defn()
|
||||
}
|
||||
|
||||
func (t *StructType) Defn() string {
|
||||
s := t.Kind
|
||||
if t.StructName != "" {
|
||||
s += " " + t.StructName
|
||||
}
|
||||
if t.Incomplete {
|
||||
s += " /*incomplete*/"
|
||||
return s
|
||||
}
|
||||
s += " {"
|
||||
for i, f := range t.Field {
|
||||
if i > 0 {
|
||||
s += "; "
|
||||
}
|
||||
s += f.Name + " " + f.Type.String()
|
||||
s += "@" + strconv.FormatInt(f.ByteOffset, 10)
|
||||
if f.BitSize > 0 {
|
||||
s += " : " + strconv.FormatInt(f.BitSize, 10)
|
||||
s += "@" + strconv.FormatInt(f.BitOffset, 10)
|
||||
}
|
||||
}
|
||||
s += "}"
|
||||
return s
|
||||
}
|
||||
|
||||
// A SliceType represents a Go slice type. It looks like a StructType, describing
|
||||
// the runtime-internal structure, with extra fields.
|
||||
type SliceType struct {
|
||||
StructType
|
||||
ElemType Type
|
||||
}
|
||||
|
||||
func (t *SliceType) String() string {
|
||||
if t.Name != "" {
|
||||
return t.Name
|
||||
}
|
||||
return "[]" + t.ElemType.String()
|
||||
}
|
||||
|
||||
// A StringType represents a Go string type. It looks like a StructType, describing
|
||||
// the runtime-internal structure, but we wrap it for neatness.
|
||||
type StringType struct {
|
||||
StructType
|
||||
}
|
||||
|
||||
func (t *StringType) String() string {
|
||||
if t.Name != "" {
|
||||
return t.Name
|
||||
}
|
||||
return "string"
|
||||
}
|
||||
|
||||
// An InterfaceType represents a Go interface.
|
||||
type InterfaceType struct {
|
||||
TypedefType
|
||||
}
|
||||
|
||||
func (t *InterfaceType) String() string {
|
||||
if t.Name != "" {
|
||||
return t.Name
|
||||
}
|
||||
return "Interface"
|
||||
}
|
||||
|
||||
// An EnumType represents an enumerated type.
|
||||
// The only indication of its native integer type is its ByteSize
|
||||
// (inside CommonType).
|
||||
type EnumType struct {
|
||||
CommonType
|
||||
EnumName string
|
||||
Val []*EnumValue
|
||||
}
|
||||
|
||||
// An EnumValue represents a single enumeration value.
|
||||
type EnumValue struct {
|
||||
Name string
|
||||
Val int64
|
||||
}
|
||||
|
||||
func (t *EnumType) String() string {
|
||||
s := "enum"
|
||||
if t.EnumName != "" {
|
||||
s += " " + t.EnumName
|
||||
}
|
||||
s += " {"
|
||||
for i, v := range t.Val {
|
||||
if i > 0 {
|
||||
s += "; "
|
||||
}
|
||||
s += v.Name + "=" + strconv.FormatInt(v.Val, 10)
|
||||
}
|
||||
s += "}"
|
||||
return s
|
||||
}
|
||||
|
||||
// A FuncType represents a function type.
|
||||
type FuncType struct {
|
||||
CommonType
|
||||
ReturnType Type
|
||||
ParamType []Type
|
||||
}
|
||||
|
||||
func (t *FuncType) String() string {
|
||||
s := "func("
|
||||
for i, t := range t.ParamType {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
}
|
||||
s += t.String()
|
||||
}
|
||||
s += ")"
|
||||
if t.ReturnType != nil {
|
||||
s += " " + t.ReturnType.String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// A DotDotDotType represents the variadic ... function parameter.
|
||||
type DotDotDotType struct {
|
||||
CommonType
|
||||
}
|
||||
|
||||
func (t *DotDotDotType) String() string { return "..." }
|
||||
|
||||
// A TypedefType represents a named type.
|
||||
type TypedefType struct {
|
||||
CommonType
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (t *TypedefType) String() string { return t.Name }
|
||||
|
||||
func (t *TypedefType) Size() int64 { return t.Type.Size() }
|
||||
|
||||
// A MapType represents a Go map type. It looks like a TypedefType, describing
|
||||
// the runtime-internal structure, with extra fields.
|
||||
type MapType struct {
|
||||
TypedefType
|
||||
KeyType Type
|
||||
ElemType Type
|
||||
}
|
||||
|
||||
func (t *MapType) String() string {
|
||||
if t.Name != "" {
|
||||
return t.Name
|
||||
}
|
||||
return "map[" + t.KeyType.String() + "]" + t.ElemType.String()
|
||||
}
|
||||
|
||||
// A ChanType represents a Go channel type.
|
||||
type ChanType struct {
|
||||
TypedefType
|
||||
ElemType Type
|
||||
}
|
||||
|
||||
func (t *ChanType) String() string {
|
||||
if t.Name != "" {
|
||||
return t.Name
|
||||
}
|
||||
return "chan " + t.ElemType.String()
|
||||
}
|
||||
|
||||
// typeReader is used to read from either the info section or the
|
||||
// types section.
|
||||
type typeReader interface {
|
||||
Seek(Offset)
|
||||
Next() (*Entry, error)
|
||||
clone() typeReader
|
||||
offset() Offset
|
||||
// AddressSize returns the size in bytes of addresses in the current
|
||||
// compilation unit.
|
||||
AddressSize() int
|
||||
}
|
||||
|
||||
// Type reads the type at off in the DWARF ``info'' section.
|
||||
func (d *Data) Type(off Offset) (Type, error) {
|
||||
return d.readType("info", d.Reader(), off, d.typeCache)
|
||||
}
|
||||
|
||||
func getKind(e *Entry) reflect.Kind {
|
||||
integer, _ := e.Val(AttrGoKind).(int64)
|
||||
return reflect.Kind(integer)
|
||||
}
|
||||
|
||||
// readType reads a type from r at off of name using and updating a
|
||||
// type cache.
|
||||
func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) {
|
||||
if t, ok := typeCache[off]; ok {
|
||||
return t, nil
|
||||
}
|
||||
r.Seek(off)
|
||||
e, err := r.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addressSize := r.AddressSize()
|
||||
if e == nil || e.Offset != off {
|
||||
return nil, DecodeError{name, off, "no type at offset"}
|
||||
}
|
||||
|
||||
// Parse type from Entry.
|
||||
// Must always set typeCache[off] before calling
|
||||
// d.Type recursively, to handle circular types correctly.
|
||||
var typ Type
|
||||
|
||||
nextDepth := 0
|
||||
|
||||
// Get next child; set err if error happens.
|
||||
next := func() *Entry {
|
||||
if !e.Children {
|
||||
return nil
|
||||
}
|
||||
// Only return direct children.
|
||||
// Skip over composite entries that happen to be nested
|
||||
// inside this one. Most DWARF generators wouldn't generate
|
||||
// such a thing, but clang does.
|
||||
// See golang.org/issue/6472.
|
||||
for {
|
||||
kid, err1 := r.Next()
|
||||
if err1 != nil {
|
||||
err = err1
|
||||
return nil
|
||||
}
|
||||
if kid == nil {
|
||||
err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"}
|
||||
return nil
|
||||
}
|
||||
if kid.Tag == 0 {
|
||||
if nextDepth > 0 {
|
||||
nextDepth--
|
||||
continue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if kid.Children {
|
||||
nextDepth++
|
||||
}
|
||||
if nextDepth > 0 {
|
||||
continue
|
||||
}
|
||||
return kid
|
||||
}
|
||||
}
|
||||
|
||||
// Get Type referred to by Entry's attr.
|
||||
// Set err if error happens. Not having a type is an error.
|
||||
typeOf := func(e *Entry, attr Attr) Type {
|
||||
tval := e.Val(attr)
|
||||
var t Type
|
||||
switch toff := tval.(type) {
|
||||
case Offset:
|
||||
if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil {
|
||||
return nil
|
||||
}
|
||||
case uint64:
|
||||
if t, err = d.sigToType(toff); err != nil {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
// It appears that no Type means "void".
|
||||
return new(VoidType)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
switch e.Tag {
|
||||
case TagArrayType:
|
||||
// Multi-dimensional array. (DWARF v2 §5.4)
|
||||
// Attributes:
|
||||
// AttrType:subtype [required]
|
||||
// AttrStrideSize: distance in bits between each element of the array
|
||||
// AttrStride: distance in bytes between each element of the array
|
||||
// AttrByteSize: size of entire array
|
||||
// Children:
|
||||
// TagSubrangeType or TagEnumerationType giving one dimension.
|
||||
// dimensions are in left to right order.
|
||||
t := new(ArrayType)
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
t.ReflectKind = getKind(e)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
if t.Type = typeOf(e, AttrType); err != nil {
|
||||
goto Error
|
||||
}
|
||||
if bytes, ok := e.Val(AttrStride).(int64); ok {
|
||||
t.StrideBitSize = 8 * bytes
|
||||
} else if bits, ok := e.Val(AttrStrideSize).(int64); ok {
|
||||
t.StrideBitSize = bits
|
||||
} else {
|
||||
// If there's no stride specified, assume it's the size of the
|
||||
// array's element type.
|
||||
t.StrideBitSize = 8 * t.Type.Size()
|
||||
}
|
||||
|
||||
// Accumulate dimensions,
|
||||
ndim := 0
|
||||
for kid := next(); kid != nil; kid = next() {
|
||||
// TODO(rsc): Can also be TagEnumerationType
|
||||
// but haven't seen that in the wild yet.
|
||||
switch kid.Tag {
|
||||
case TagSubrangeType:
|
||||
count, ok := kid.Val(AttrCount).(int64)
|
||||
if !ok {
|
||||
// Old binaries may have an upper bound instead.
|
||||
count, ok = kid.Val(AttrUpperBound).(int64)
|
||||
if ok {
|
||||
count++ // Length is one more than upper bound.
|
||||
} else {
|
||||
count = -1 // As in x[].
|
||||
}
|
||||
}
|
||||
if ndim == 0 {
|
||||
t.Count = count
|
||||
} else {
|
||||
// Multidimensional array.
|
||||
// Create new array type underneath this one.
|
||||
t.Type = &ArrayType{Type: t.Type, Count: count}
|
||||
}
|
||||
ndim++
|
||||
case TagEnumerationType:
|
||||
err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"}
|
||||
goto Error
|
||||
}
|
||||
}
|
||||
if ndim == 0 {
|
||||
// LLVM generates this for x[].
|
||||
t.Count = -1
|
||||
}
|
||||
|
||||
case TagBaseType:
|
||||
// Basic type. (DWARF v2 §5.1)
|
||||
// Attributes:
|
||||
// AttrName: name of base type in programming language of the compilation unit [required]
|
||||
// AttrEncoding: encoding value for type (encFloat etc) [required]
|
||||
// AttrByteSize: size of type in bytes [required]
|
||||
// AttrBitOffset: for sub-byte types, size in bits
|
||||
// AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes
|
||||
name, _ := e.Val(AttrName).(string)
|
||||
enc, ok := e.Val(AttrEncoding).(int64)
|
||||
if !ok {
|
||||
err = DecodeError{name, e.Offset, "missing encoding attribute for " + name}
|
||||
goto Error
|
||||
}
|
||||
switch enc {
|
||||
default:
|
||||
err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"}
|
||||
goto Error
|
||||
|
||||
case encAddress:
|
||||
typ = new(AddrType)
|
||||
case encBoolean:
|
||||
typ = new(BoolType)
|
||||
case encComplexFloat:
|
||||
typ = new(ComplexType)
|
||||
if name == "complex" {
|
||||
// clang writes out 'complex' instead of 'complex float' or 'complex double'.
|
||||
// clang also writes out a byte size that we can use to distinguish.
|
||||
// See issue 8694.
|
||||
switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize {
|
||||
case 8:
|
||||
name = "complex float"
|
||||
case 16:
|
||||
name = "complex double"
|
||||
}
|
||||
}
|
||||
case encFloat:
|
||||
typ = new(FloatType)
|
||||
case encSigned:
|
||||
typ = new(IntType)
|
||||
case encUnsigned:
|
||||
typ = new(UintType)
|
||||
case encSignedChar:
|
||||
typ = new(CharType)
|
||||
case encUnsignedChar:
|
||||
typ = new(UcharType)
|
||||
}
|
||||
typeCache[off] = typ
|
||||
t := typ.(interface {
|
||||
Basic() *BasicType
|
||||
}).Basic()
|
||||
t.Name = name
|
||||
t.BitSize, _ = e.Val(AttrBitSize).(int64)
|
||||
t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
|
||||
t.ReflectKind = getKind(e)
|
||||
|
||||
case TagClassType, TagStructType, TagUnionType:
|
||||
// Structure, union, or class type. (DWARF v2 §5.5)
|
||||
// Also Slices and Strings (Go-specific).
|
||||
// Attributes:
|
||||
// AttrName: name of struct, union, or class
|
||||
// AttrByteSize: byte size [required]
|
||||
// AttrDeclaration: if true, struct/union/class is incomplete
|
||||
// AttrGoElem: present for slices only.
|
||||
// Children:
|
||||
// TagMember to describe one member.
|
||||
// AttrName: name of member [required]
|
||||
// AttrType: type of member [required]
|
||||
// AttrByteSize: size in bytes
|
||||
// AttrBitOffset: bit offset within bytes for bit fields
|
||||
// AttrBitSize: bit size for bit fields
|
||||
// AttrDataMemberLoc: location within struct [required for struct, class]
|
||||
// There is much more to handle C++, all ignored for now.
|
||||
t := new(StructType)
|
||||
t.ReflectKind = getKind(e)
|
||||
switch t.ReflectKind {
|
||||
case reflect.Slice:
|
||||
slice := new(SliceType)
|
||||
slice.ElemType = typeOf(e, AttrGoElem)
|
||||
t = &slice.StructType
|
||||
typ = slice
|
||||
case reflect.String:
|
||||
str := new(StringType)
|
||||
t = &str.StructType
|
||||
typ = str
|
||||
default:
|
||||
typ = t
|
||||
}
|
||||
typeCache[off] = typ
|
||||
switch e.Tag {
|
||||
case TagClassType:
|
||||
t.Kind = "class"
|
||||
case TagStructType:
|
||||
t.Kind = "struct"
|
||||
case TagUnionType:
|
||||
t.Kind = "union"
|
||||
}
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
t.StructName, _ = e.Val(AttrName).(string)
|
||||
t.Incomplete = e.Val(AttrDeclaration) != nil
|
||||
t.Field = make([]*StructField, 0, 8)
|
||||
var lastFieldType Type
|
||||
var lastFieldBitOffset int64
|
||||
for kid := next(); kid != nil; kid = next() {
|
||||
if kid.Tag == TagMember {
|
||||
f := new(StructField)
|
||||
if f.Type = typeOf(kid, AttrType); err != nil {
|
||||
goto Error
|
||||
}
|
||||
switch loc := kid.Val(AttrDataMemberLoc).(type) {
|
||||
case []byte:
|
||||
// TODO: Should have original compilation
|
||||
// unit here, not unknownFormat.
|
||||
if len(loc) == 0 {
|
||||
// Empty exprloc. f.ByteOffset=0.
|
||||
break
|
||||
}
|
||||
b := makeBuf(d, unknownFormat{}, "location", 0, loc)
|
||||
op := b.uint8()
|
||||
switch op {
|
||||
case opPlusUconst:
|
||||
// Handle opcode sequence [DW_OP_plus_uconst <uleb128>]
|
||||
f.ByteOffset = int64(b.uint())
|
||||
b.assertEmpty()
|
||||
case opConsts:
|
||||
// Handle opcode sequence [DW_OP_consts <sleb128> DW_OP_plus]
|
||||
f.ByteOffset = b.int()
|
||||
op = b.uint8()
|
||||
if op != opPlus {
|
||||
err = DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op)}
|
||||
goto Error
|
||||
}
|
||||
b.assertEmpty()
|
||||
default:
|
||||
err = DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op)}
|
||||
goto Error
|
||||
}
|
||||
if b.err != nil {
|
||||
err = b.err
|
||||
goto Error
|
||||
}
|
||||
case int64:
|
||||
f.ByteOffset = loc
|
||||
}
|
||||
|
||||
haveBitOffset := false
|
||||
f.Name, _ = kid.Val(AttrName).(string)
|
||||
f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
|
||||
f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64)
|
||||
f.BitSize, _ = kid.Val(AttrBitSize).(int64)
|
||||
t.Field = append(t.Field, f)
|
||||
|
||||
bito := f.BitOffset
|
||||
if !haveBitOffset {
|
||||
bito = f.ByteOffset * 8
|
||||
}
|
||||
if bito == lastFieldBitOffset && t.Kind != "union" {
|
||||
// Last field was zero width. Fix array length.
|
||||
// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
|
||||
zeroArray(lastFieldType)
|
||||
}
|
||||
lastFieldType = f.Type
|
||||
lastFieldBitOffset = bito
|
||||
}
|
||||
}
|
||||
if t.Kind != "union" {
|
||||
b, ok := e.Val(AttrByteSize).(int64)
|
||||
if ok && b*8 == lastFieldBitOffset {
|
||||
// Final field must be zero width. Fix array length.
|
||||
zeroArray(lastFieldType)
|
||||
}
|
||||
}
|
||||
|
||||
case TagConstType, TagVolatileType, TagRestrictType:
|
||||
// Type modifier (DWARF v2 §5.2)
|
||||
// Attributes:
|
||||
// AttrType: subtype
|
||||
t := new(QualType)
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
t.ReflectKind = getKind(e)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
if t.Type = typeOf(e, AttrType); err != nil {
|
||||
goto Error
|
||||
}
|
||||
switch e.Tag {
|
||||
case TagConstType:
|
||||
t.Qual = "const"
|
||||
case TagRestrictType:
|
||||
t.Qual = "restrict"
|
||||
case TagVolatileType:
|
||||
t.Qual = "volatile"
|
||||
}
|
||||
|
||||
case TagEnumerationType:
|
||||
// Enumeration type (DWARF v2 §5.6)
|
||||
// Attributes:
|
||||
// AttrName: enum name if any
|
||||
// AttrByteSize: bytes required to represent largest value
|
||||
// Children:
|
||||
// TagEnumerator:
|
||||
// AttrName: name of constant
|
||||
// AttrConstValue: value of constant
|
||||
t := new(EnumType)
|
||||
t.ReflectKind = getKind(e)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
t.EnumName, _ = e.Val(AttrName).(string)
|
||||
t.Val = make([]*EnumValue, 0, 8)
|
||||
for kid := next(); kid != nil; kid = next() {
|
||||
if kid.Tag == TagEnumerator {
|
||||
f := new(EnumValue)
|
||||
f.Name, _ = kid.Val(AttrName).(string)
|
||||
f.Val, _ = kid.Val(AttrConstValue).(int64)
|
||||
n := len(t.Val)
|
||||
if n >= cap(t.Val) {
|
||||
val := make([]*EnumValue, n, n*2)
|
||||
copy(val, t.Val)
|
||||
t.Val = val
|
||||
}
|
||||
t.Val = t.Val[0 : n+1]
|
||||
t.Val[n] = f
|
||||
}
|
||||
}
|
||||
|
||||
case TagPointerType:
|
||||
// Type modifier (DWARF v2 §5.2)
|
||||
// Attributes:
|
||||
// AttrType: subtype [not required! void* has no AttrType]
|
||||
// AttrAddrClass: address class [ignored]
|
||||
t := new(PtrType)
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
t.ReflectKind = getKind(e)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
if e.Val(AttrType) == nil {
|
||||
t.Type = &VoidType{}
|
||||
break
|
||||
}
|
||||
t.Type = typeOf(e, AttrType)
|
||||
|
||||
case TagSubroutineType:
|
||||
// Subroutine type. (DWARF v2 §5.7)
|
||||
// Attributes:
|
||||
// AttrType: type of return value if any
|
||||
// AttrName: possible name of type [ignored]
|
||||
// AttrPrototyped: whether used ANSI C prototype [ignored]
|
||||
// Children:
|
||||
// TagFormalParameter: typed parameter
|
||||
// AttrType: type of parameter
|
||||
// TagUnspecifiedParameter: final ...
|
||||
t := new(FuncType)
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
t.ReflectKind = getKind(e)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
if t.ReturnType = typeOf(e, AttrType); err != nil {
|
||||
goto Error
|
||||
}
|
||||
t.ParamType = make([]Type, 0, 8)
|
||||
for kid := next(); kid != nil; kid = next() {
|
||||
var tkid Type
|
||||
switch kid.Tag {
|
||||
default:
|
||||
continue
|
||||
case TagFormalParameter:
|
||||
if tkid = typeOf(kid, AttrType); err != nil {
|
||||
goto Error
|
||||
}
|
||||
case TagUnspecifiedParameters:
|
||||
tkid = &DotDotDotType{}
|
||||
}
|
||||
t.ParamType = append(t.ParamType, tkid)
|
||||
}
|
||||
|
||||
case TagTypedef:
|
||||
// Typedef (DWARF v2 §5.3)
|
||||
// Also maps and channels (Go-specific).
|
||||
// Attributes:
|
||||
// AttrName: name [required]
|
||||
// AttrType: type definition [required]
|
||||
// AttrGoKey: present for maps.
|
||||
// AttrGoElem: present for maps and channels.
|
||||
t := new(TypedefType)
|
||||
t.ReflectKind = getKind(e)
|
||||
switch t.ReflectKind {
|
||||
case reflect.Map:
|
||||
m := new(MapType)
|
||||
m.KeyType = typeOf(e, AttrGoKey)
|
||||
m.ElemType = typeOf(e, AttrGoElem)
|
||||
t = &m.TypedefType
|
||||
typ = m
|
||||
case reflect.Chan:
|
||||
c := new(ChanType)
|
||||
c.ElemType = typeOf(e, AttrGoElem)
|
||||
t = &c.TypedefType
|
||||
typ = c
|
||||
case reflect.Interface:
|
||||
it := new(InterfaceType)
|
||||
t = &it.TypedefType
|
||||
typ = it
|
||||
default:
|
||||
typ = t
|
||||
}
|
||||
typeCache[off] = typ
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
t.Type = typeOf(e, AttrType)
|
||||
|
||||
case TagUnspecifiedType:
|
||||
// Unspecified type (DWARF v3 §5.2)
|
||||
// Attributes:
|
||||
// AttrName: name
|
||||
t := new(UnspecifiedType)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
goto Error
|
||||
}
|
||||
|
||||
typ.Common().Offset = off
|
||||
|
||||
{
|
||||
b, ok := e.Val(AttrByteSize).(int64)
|
||||
if !ok {
|
||||
b = -1
|
||||
switch t := typ.(type) {
|
||||
case *TypedefType:
|
||||
b = t.Type.Size()
|
||||
case *MapType:
|
||||
b = t.Type.Size()
|
||||
case *ChanType:
|
||||
b = t.Type.Size()
|
||||
case *InterfaceType:
|
||||
b = t.Type.Size()
|
||||
case *PtrType:
|
||||
b = int64(addressSize)
|
||||
}
|
||||
}
|
||||
typ.Common().ByteSize = b
|
||||
}
|
||||
return typ, nil
|
||||
|
||||
Error:
|
||||
// If the parse fails, take the type out of the cache
|
||||
// so that the next call with this offset doesn't hit
|
||||
// the cache and return success.
|
||||
delete(typeCache, off)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func zeroArray(t Type) {
|
||||
for {
|
||||
at, ok := t.(*ArrayType)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
at.Count = 0
|
||||
t = at.Type
|
||||
}
|
||||
}
|
171
vendor/golang.org/x/debug/dwarf/typeunit.go
generated
vendored
Normal file
171
vendor/golang.org/x/debug/dwarf/typeunit.go
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dwarf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Parse the type units stored in a DWARF4 .debug_types section. Each
|
||||
// type unit defines a single primary type and an 8-byte signature.
|
||||
// Other sections may then use formRefSig8 to refer to the type.
|
||||
|
||||
// The typeUnit format is a single type with a signature. It holds
|
||||
// the same data as a compilation unit.
|
||||
type typeUnit struct {
|
||||
unit
|
||||
toff Offset // Offset to signature type within data.
|
||||
name string // Name of .debug_type section.
|
||||
cache Type // Cache the type, nil to start.
|
||||
}
|
||||
|
||||
// Parse a .debug_types section.
|
||||
func (d *Data) parseTypes(name string, types []byte) error {
|
||||
b := makeBuf(d, unknownFormat{}, name, 0, types)
|
||||
for len(b.data) > 0 {
|
||||
base := b.off
|
||||
dwarf64 := false
|
||||
n := b.uint32()
|
||||
if n == 0xffffffff {
|
||||
n64 := b.uint64()
|
||||
if n64 != uint64(uint32(n64)) {
|
||||
b.error("type unit length overflow")
|
||||
return b.err
|
||||
}
|
||||
n = uint32(n64)
|
||||
dwarf64 = true
|
||||
}
|
||||
hdroff := b.off
|
||||
vers := b.uint16()
|
||||
if vers != 4 {
|
||||
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
|
||||
return b.err
|
||||
}
|
||||
var ao uint32
|
||||
if !dwarf64 {
|
||||
ao = b.uint32()
|
||||
} else {
|
||||
ao64 := b.uint64()
|
||||
if ao64 != uint64(uint32(ao64)) {
|
||||
b.error("type unit abbrev offset overflow")
|
||||
return b.err
|
||||
}
|
||||
ao = uint32(ao64)
|
||||
}
|
||||
atable, err := d.parseAbbrev(ao)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
asize := b.uint8()
|
||||
sig := b.uint64()
|
||||
|
||||
var toff uint32
|
||||
if !dwarf64 {
|
||||
toff = b.uint32()
|
||||
} else {
|
||||
to64 := b.uint64()
|
||||
if to64 != uint64(uint32(to64)) {
|
||||
b.error("type unit type offset overflow")
|
||||
return b.err
|
||||
}
|
||||
toff = uint32(to64)
|
||||
}
|
||||
|
||||
boff := b.off
|
||||
d.typeSigs[sig] = &typeUnit{
|
||||
unit: unit{
|
||||
base: base,
|
||||
off: boff,
|
||||
data: b.bytes(int(Offset(n) - (b.off - hdroff))),
|
||||
atable: atable,
|
||||
asize: int(asize),
|
||||
vers: int(vers),
|
||||
is64: dwarf64,
|
||||
},
|
||||
toff: Offset(toff),
|
||||
name: name,
|
||||
}
|
||||
if b.err != nil {
|
||||
return b.err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return the type for a type signature.
|
||||
func (d *Data) sigToType(sig uint64) (Type, error) {
|
||||
tu := d.typeSigs[sig]
|
||||
if tu == nil {
|
||||
return nil, fmt.Errorf("no type unit with signature %v", sig)
|
||||
}
|
||||
if tu.cache != nil {
|
||||
return tu.cache, nil
|
||||
}
|
||||
|
||||
b := makeBuf(d, tu, tu.name, tu.off, tu.data)
|
||||
r := &typeUnitReader{d: d, tu: tu, b: b}
|
||||
t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tu.cache = t
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// typeUnitReader is a typeReader for a tagTypeUnit.
|
||||
type typeUnitReader struct {
|
||||
d *Data
|
||||
tu *typeUnit
|
||||
b buf
|
||||
err error
|
||||
}
|
||||
|
||||
// Seek to a new position in the type unit.
|
||||
func (tur *typeUnitReader) Seek(off Offset) {
|
||||
tur.err = nil
|
||||
doff := off - tur.tu.off
|
||||
if doff < 0 || doff >= Offset(len(tur.tu.data)) {
|
||||
tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
|
||||
return
|
||||
}
|
||||
tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
|
||||
}
|
||||
|
||||
// AddressSize returns the size in bytes of addresses in the current type unit.
|
||||
func (tur *typeUnitReader) AddressSize() int {
|
||||
return tur.tu.unit.asize
|
||||
}
|
||||
|
||||
// Next reads the next Entry from the type unit.
|
||||
func (tur *typeUnitReader) Next() (*Entry, error) {
|
||||
if tur.err != nil {
|
||||
return nil, tur.err
|
||||
}
|
||||
if len(tur.tu.data) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
e := tur.b.entry(tur.tu.atable, tur.tu.base)
|
||||
if tur.b.err != nil {
|
||||
tur.err = tur.b.err
|
||||
return nil, tur.err
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// clone returns a new reader for the type unit.
|
||||
func (tur *typeUnitReader) clone() typeReader {
|
||||
return &typeUnitReader{
|
||||
d: tur.d,
|
||||
tu: tur.tu,
|
||||
b: makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data),
|
||||
}
|
||||
}
|
||||
|
||||
// offset returns the current offset.
|
||||
func (tur *typeUnitReader) offset() Offset {
|
||||
return tur.b.off
|
||||
}
|
90
vendor/golang.org/x/debug/dwarf/unit.go
generated
vendored
Normal file
90
vendor/golang.org/x/debug/dwarf/unit.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dwarf
|
||||
|
||||
import "strconv"
|
||||
|
||||
// DWARF debug info is split into a sequence of compilation units.
|
||||
// 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
|
||||
data []byte
|
||||
atable abbrevTable
|
||||
asize int
|
||||
vers int
|
||||
is64 bool // True for 64-bit DWARF format
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (d *Data) parseUnits() ([]unit, error) {
|
||||
// Count units.
|
||||
nunit := 0
|
||||
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(uint32(len64)) {
|
||||
b.error("unit length overflow")
|
||||
break
|
||||
}
|
||||
len = uint32(len64)
|
||||
}
|
||||
b.skip(int(len))
|
||||
nunit++
|
||||
}
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
|
||||
// Again, this time writing them down.
|
||||
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.is64 = true
|
||||
n = uint32(b.uint64())
|
||||
}
|
||||
vers := b.uint16()
|
||||
if vers != 2 && vers != 3 && vers != 4 {
|
||||
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 {
|
||||
b.err = err
|
||||
}
|
||||
break
|
||||
}
|
||||
u.atable = atable
|
||||
u.asize = int(b.uint8())
|
||||
u.off = b.off
|
||||
u.data = b.bytes(int(n - (2 + 4 + 1)))
|
||||
}
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
return units, nil
|
||||
}
|
Reference in New Issue
Block a user