1
0
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:
Faissal Elamraoui
2017-03-19 23:45:54 +01:00
parent f9939bc286
commit 7811c335e9
146 changed files with 50012 additions and 0 deletions

203
vendor/golang.org/x/debug/dwarf/buf.go generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}