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

27
vendor/golang.org/x/debug/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2014 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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
}

1521
vendor/golang.org/x/debug/elf/elf.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

829
vendor/golang.org/x/debug/elf/file.go generated vendored Normal file
View File

@ -0,0 +1,829 @@
// 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 elf implements access to ELF object files.
package elf
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"golang.org/x/debug/dwarf"
)
// TODO: error reporting detail
/*
* Internal ELF representation
*/
// A FileHeader represents an ELF file header.
type FileHeader struct {
Class Class
Data Data
Version Version
OSABI OSABI
ABIVersion uint8
ByteOrder binary.ByteOrder
Type Type
Machine Machine
Entry uint64
}
// A File represents an open ELF file.
type File struct {
FileHeader
Sections []*Section
Progs []*Prog
closer io.Closer
gnuNeed []verneed
gnuVersym []byte
}
// A SectionHeader represents a single ELF section header.
type SectionHeader struct {
Name string
Type SectionType
Flags SectionFlag
Addr uint64
Offset uint64
Size uint64
Link uint32
Info uint32
Addralign uint64
Entsize uint64
}
// A Section represents a single section in an ELF file.
type Section struct {
SectionHeader
// Embed ReaderAt for ReadAt method.
// Do not embed SectionReader directly
// to avoid having Read and Seek.
// If a client wants Read and Seek it must use
// Open() to avoid fighting over the seek offset
// with other clients.
io.ReaderAt
sr *io.SectionReader
}
// Data reads and returns the contents of the ELF section.
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
if n == len(dat) {
err = nil
}
return dat[0:n], err
}
// stringTable reads and returns the string table given by the
// specified link value.
func (f *File) stringTable(link uint32) ([]byte, error) {
if link <= 0 || link >= uint32(len(f.Sections)) {
return nil, errors.New("section has invalid string table link")
}
return f.Sections[link].Data()
}
// Open returns a new ReadSeeker reading the ELF section.
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
// A ProgHeader represents a single ELF program header.
type ProgHeader struct {
Type ProgType
Flags ProgFlag
Off uint64
Vaddr uint64
Paddr uint64
Filesz uint64
Memsz uint64
Align uint64
}
// A Prog represents a single ELF program header in an ELF binary.
type Prog struct {
ProgHeader
// Embed ReaderAt for ReadAt method.
// Do not embed SectionReader directly
// to avoid having Read and Seek.
// If a client wants Read and Seek it must use
// Open() to avoid fighting over the seek offset
// with other clients.
io.ReaderAt
sr *io.SectionReader
}
// Open returns a new ReadSeeker reading the ELF program body.
func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
// A Symbol represents an entry in an ELF symbol table section.
type Symbol struct {
Name string
Info, Other byte
Section SectionIndex
Value, Size uint64
}
/*
* ELF reader
*/
type FormatError struct {
off int64
msg string
val interface{}
}
func (e *FormatError) Error() string {
msg := e.msg
if e.val != nil {
msg += fmt.Sprintf(" '%v' ", e.val)
}
msg += fmt.Sprintf("in record at byte %#x", e.off)
return msg
}
// Open opens the named file using os.Open and prepares it for use as an ELF binary.
func Open(name string) (*File, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
ff, err := NewFile(f)
if err != nil {
f.Close()
return nil, err
}
ff.closer = f
return ff, nil
}
// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
func (f *File) Close() error {
var err error
if f.closer != nil {
err = f.closer.Close()
f.closer = nil
}
return err
}
// SectionByType returns the first section in f with the
// given type, or nil if there is no such section.
func (f *File) SectionByType(typ SectionType) *Section {
for _, s := range f.Sections {
if s.Type == typ {
return s
}
}
return nil
}
// NewFile creates a new File for accessing an ELF binary in an underlying reader.
// The ELF binary is expected to start at position 0 in the ReaderAt.
func NewFile(r io.ReaderAt) (*File, error) {
sr := io.NewSectionReader(r, 0, 1<<63-1)
// Read and decode ELF identifier
var ident [16]uint8
if _, err := r.ReadAt(ident[0:], 0); err != nil {
return nil, err
}
if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
return nil, &FormatError{0, "bad magic number", ident[0:4]}
}
f := new(File)
f.Class = Class(ident[EI_CLASS])
switch f.Class {
case ELFCLASS32:
case ELFCLASS64:
// ok
default:
return nil, &FormatError{0, "unknown ELF class", f.Class}
}
f.Data = Data(ident[EI_DATA])
switch f.Data {
case ELFDATA2LSB:
f.ByteOrder = binary.LittleEndian
case ELFDATA2MSB:
f.ByteOrder = binary.BigEndian
default:
return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
}
f.Version = Version(ident[EI_VERSION])
if f.Version != EV_CURRENT {
return nil, &FormatError{0, "unknown ELF version", f.Version}
}
f.OSABI = OSABI(ident[EI_OSABI])
f.ABIVersion = ident[EI_ABIVERSION]
// Read ELF file header
var phoff int64
var phentsize, phnum int
var shoff int64
var shentsize, shnum, shstrndx int
shstrndx = -1
switch f.Class {
case ELFCLASS32:
hdr := new(Header32)
sr.Seek(0, os.SEEK_SET)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err
}
f.Type = Type(hdr.Type)
f.Machine = Machine(hdr.Machine)
f.Entry = uint64(hdr.Entry)
if v := Version(hdr.Version); v != f.Version {
return nil, &FormatError{0, "mismatched ELF version", v}
}
phoff = int64(hdr.Phoff)
phentsize = int(hdr.Phentsize)
phnum = int(hdr.Phnum)
shoff = int64(hdr.Shoff)
shentsize = int(hdr.Shentsize)
shnum = int(hdr.Shnum)
shstrndx = int(hdr.Shstrndx)
case ELFCLASS64:
hdr := new(Header64)
sr.Seek(0, os.SEEK_SET)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err
}
f.Type = Type(hdr.Type)
f.Machine = Machine(hdr.Machine)
f.Entry = uint64(hdr.Entry)
if v := Version(hdr.Version); v != f.Version {
return nil, &FormatError{0, "mismatched ELF version", v}
}
phoff = int64(hdr.Phoff)
phentsize = int(hdr.Phentsize)
phnum = int(hdr.Phnum)
shoff = int64(hdr.Shoff)
shentsize = int(hdr.Shentsize)
shnum = int(hdr.Shnum)
shstrndx = int(hdr.Shstrndx)
}
if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) {
return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
}
// Read program headers
f.Progs = make([]*Prog, phnum)
for i := 0; i < phnum; i++ {
off := phoff + int64(i)*int64(phentsize)
sr.Seek(off, os.SEEK_SET)
p := new(Prog)
switch f.Class {
case ELFCLASS32:
ph := new(Prog32)
if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
return nil, err
}
p.ProgHeader = ProgHeader{
Type: ProgType(ph.Type),
Flags: ProgFlag(ph.Flags),
Off: uint64(ph.Off),
Vaddr: uint64(ph.Vaddr),
Paddr: uint64(ph.Paddr),
Filesz: uint64(ph.Filesz),
Memsz: uint64(ph.Memsz),
Align: uint64(ph.Align),
}
case ELFCLASS64:
ph := new(Prog64)
if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
return nil, err
}
p.ProgHeader = ProgHeader{
Type: ProgType(ph.Type),
Flags: ProgFlag(ph.Flags),
Off: uint64(ph.Off),
Vaddr: uint64(ph.Vaddr),
Paddr: uint64(ph.Paddr),
Filesz: uint64(ph.Filesz),
Memsz: uint64(ph.Memsz),
Align: uint64(ph.Align),
}
}
p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
p.ReaderAt = p.sr
f.Progs[i] = p
}
// Read section headers
f.Sections = make([]*Section, shnum)
names := make([]uint32, shnum)
for i := 0; i < shnum; i++ {
off := shoff + int64(i)*int64(shentsize)
sr.Seek(off, os.SEEK_SET)
s := new(Section)
switch f.Class {
case ELFCLASS32:
sh := new(Section32)
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
return nil, err
}
names[i] = sh.Name
s.SectionHeader = SectionHeader{
Type: SectionType(sh.Type),
Flags: SectionFlag(sh.Flags),
Addr: uint64(sh.Addr),
Offset: uint64(sh.Off),
Size: uint64(sh.Size),
Link: uint32(sh.Link),
Info: uint32(sh.Info),
Addralign: uint64(sh.Addralign),
Entsize: uint64(sh.Entsize),
}
case ELFCLASS64:
sh := new(Section64)
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
return nil, err
}
names[i] = sh.Name
s.SectionHeader = SectionHeader{
Type: SectionType(sh.Type),
Flags: SectionFlag(sh.Flags),
Offset: uint64(sh.Off),
Size: uint64(sh.Size),
Addr: uint64(sh.Addr),
Link: uint32(sh.Link),
Info: uint32(sh.Info),
Addralign: uint64(sh.Addralign),
Entsize: uint64(sh.Entsize),
}
}
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
s.ReaderAt = s.sr
f.Sections[i] = s
}
if len(f.Sections) == 0 {
return f, nil
}
// Load section header string table.
shstrtab, err := f.Sections[shstrndx].Data()
if err != nil {
return nil, err
}
for i, s := range f.Sections {
var ok bool
s.Name, ok = getString(shstrtab, int(names[i]))
if !ok {
return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
}
}
return f, nil
}
// getSymbols returns a slice of Symbols from parsing the symbol table
// with the given type, along with the associated string table.
func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
switch f.Class {
case ELFCLASS64:
return f.getSymbols64(typ)
case ELFCLASS32:
return f.getSymbols32(typ)
}
return nil, nil, errors.New("not implemented")
}
func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
return nil, nil, errors.New("no symbol section")
}
data, err := symtabSection.Data()
if err != nil {
return nil, nil, errors.New("cannot load symbol section")
}
symtab := bytes.NewReader(data)
if symtab.Len()%Sym32Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
}
strdata, err := f.stringTable(symtabSection.Link)
if err != nil {
return nil, nil, errors.New("cannot load string table section")
}
// The first entry is all zeros.
var skip [Sym32Size]byte
symtab.Read(skip[:])
symbols := make([]Symbol, symtab.Len()/Sym32Size)
i := 0
var sym Sym32
for symtab.Len() > 0 {
binary.Read(symtab, f.ByteOrder, &sym)
str, _ := getString(strdata, int(sym.Name))
symbols[i].Name = str
symbols[i].Info = sym.Info
symbols[i].Other = sym.Other
symbols[i].Section = SectionIndex(sym.Shndx)
symbols[i].Value = uint64(sym.Value)
symbols[i].Size = uint64(sym.Size)
i++
}
return symbols, strdata, nil
}
func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
return nil, nil, errors.New("no symbol section")
}
data, err := symtabSection.Data()
if err != nil {
return nil, nil, errors.New("cannot load symbol section")
}
symtab := bytes.NewReader(data)
if symtab.Len()%Sym64Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
}
strdata, err := f.stringTable(symtabSection.Link)
if err != nil {
return nil, nil, errors.New("cannot load string table section")
}
// The first entry is all zeros.
var skip [Sym64Size]byte
symtab.Read(skip[:])
symbols := make([]Symbol, symtab.Len()/Sym64Size)
i := 0
var sym Sym64
for symtab.Len() > 0 {
binary.Read(symtab, f.ByteOrder, &sym)
str, _ := getString(strdata, int(sym.Name))
symbols[i].Name = str
symbols[i].Info = sym.Info
symbols[i].Other = sym.Other
symbols[i].Section = SectionIndex(sym.Shndx)
symbols[i].Value = sym.Value
symbols[i].Size = sym.Size
i++
}
return symbols, strdata, nil
}
// getString extracts a string from an ELF string table.
func getString(section []byte, start int) (string, bool) {
if start < 0 || start >= len(section) {
return "", false
}
for end := start; end < len(section); end++ {
if section[end] == 0 {
return string(section[start:end]), true
}
}
return "", false
}
// Section returns a section with the given name, or nil if no such
// section exists.
func (f *File) Section(name string) *Section {
for _, s := range f.Sections {
if s.Name == name {
return s
}
}
return nil
}
// applyRelocations applies relocations to dst. rels is a relocations section
// in RELA format.
func (f *File) applyRelocations(dst []byte, rels []byte) error {
if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
return f.applyRelocationsAMD64(dst, rels)
}
return errors.New("not implemented")
}
func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
if len(rels)%Sym64Size != 0 {
return errors.New("length of relocation section is not a multiple of Sym64Size")
}
symbols, _, err := f.getSymbols(SHT_SYMTAB)
if err != nil {
return err
}
b := bytes.NewReader(rels)
var rela Rela64
for b.Len() > 0 {
binary.Read(b, f.ByteOrder, &rela)
symNo := rela.Info >> 32
t := R_X86_64(rela.Info & 0xffff)
if symNo == 0 || symNo > uint64(len(symbols)) {
continue
}
sym := &symbols[symNo-1]
if SymType(sym.Info&0xf) != STT_SECTION {
// We don't handle non-section relocations for now.
continue
}
switch t {
case R_X86_64_64:
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
continue
}
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
case R_X86_64_32:
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
continue
}
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
}
}
return nil
}
func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
// does not use the others, so don't bother loading them.
// r: added line.
var names = [...]string{"abbrev", "frame", "info", "line", "str"}
var dat [len(names)][]byte
for i, name := range names {
name = ".debug_" + name
s := f.Section(name)
if s == nil {
continue
}
b, err := s.Data()
if err != nil && uint64(len(b)) < s.Size {
return nil, err
}
dat[i] = b
}
// If there's a relocation table for .debug_info, we have to process it
// now otherwise the data in .debug_info is invalid for x86-64 objects.
rela := f.Section(".rela.debug_info")
if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
data, err := rela.Data()
if err != nil {
return nil, err
}
err = f.applyRelocations(dat[2], data)
if err != nil {
return nil, err
}
}
abbrev, frame, info, line, str := dat[0], dat[1], dat[2], dat[3], dat[4]
d, err := dwarf.New(abbrev, nil, frame, info, line, nil, nil, str)
if err != nil {
return nil, err
}
// Look for DWARF4 .debug_types sections.
for i, s := range f.Sections {
if s.Name == ".debug_types" {
b, err := s.Data()
if err != nil && uint64(len(b)) < s.Size {
return nil, err
}
for _, r := range f.Sections {
if r.Type != SHT_RELA && r.Type != SHT_REL {
continue
}
if int(r.Info) != i {
continue
}
rd, err := r.Data()
if err != nil {
return nil, err
}
err = f.applyRelocations(b, rd)
if err != nil {
return nil, err
}
}
err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
if err != nil {
return nil, err
}
}
}
return d, nil
}
// Symbols returns the symbol table for f.
//
// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
// After retrieving the symbols as symtab, an externally supplied index x
// corresponds to symtab[x-1], not symtab[x].
func (f *File) Symbols() ([]Symbol, error) {
sym, _, err := f.getSymbols(SHT_SYMTAB)
return sym, err
}
type ImportedSymbol struct {
Name string
Version string
Library string
}
// ImportedSymbols returns the names of all symbols
// referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time.
// It does not return weak symbols.
func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
sym, str, err := f.getSymbols(SHT_DYNSYM)
if err != nil {
return nil, err
}
f.gnuVersionInit(str)
var all []ImportedSymbol
for i, s := range sym {
if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
all = append(all, ImportedSymbol{Name: s.Name})
f.gnuVersion(i, &all[len(all)-1])
}
}
return all, nil
}
type verneed struct {
File string
Name string
}
// gnuVersionInit parses the GNU version tables
// for use by calls to gnuVersion.
func (f *File) gnuVersionInit(str []byte) {
// Accumulate verneed information.
vn := f.SectionByType(SHT_GNU_VERNEED)
if vn == nil {
return
}
d, _ := vn.Data()
var need []verneed
i := 0
for {
if i+16 > len(d) {
break
}
vers := f.ByteOrder.Uint16(d[i : i+2])
if vers != 1 {
break
}
cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
aux := f.ByteOrder.Uint32(d[i+8 : i+12])
next := f.ByteOrder.Uint32(d[i+12 : i+16])
file, _ := getString(str, int(fileoff))
var name string
j := i + int(aux)
for c := 0; c < int(cnt); c++ {
if j+16 > len(d) {
break
}
// hash := f.ByteOrder.Uint32(d[j:j+4])
// flags := f.ByteOrder.Uint16(d[j+4:j+6])
other := f.ByteOrder.Uint16(d[j+6 : j+8])
nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
next := f.ByteOrder.Uint32(d[j+12 : j+16])
name, _ = getString(str, int(nameoff))
ndx := int(other)
if ndx >= len(need) {
a := make([]verneed, 2*(ndx+1))
copy(a, need)
need = a
}
need[ndx] = verneed{file, name}
if next == 0 {
break
}
j += int(next)
}
if next == 0 {
break
}
i += int(next)
}
// Versym parallels symbol table, indexing into verneed.
vs := f.SectionByType(SHT_GNU_VERSYM)
if vs == nil {
return
}
d, _ = vs.Data()
f.gnuNeed = need
f.gnuVersym = d
}
// gnuVersion adds Library and Version information to sym,
// which came from offset i of the symbol table.
func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
// Each entry is two bytes.
i = (i + 1) * 2
if i >= len(f.gnuVersym) {
return
}
j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
if j < 2 || j >= len(f.gnuNeed) {
return
}
n := &f.gnuNeed[j]
sym.Library = n.File
sym.Version = n.Name
}
// ImportedLibraries returns the names of all libraries
// referred to by the binary f that are expected to be
// linked with the binary at dynamic link time.
func (f *File) ImportedLibraries() ([]string, error) {
return f.DynString(DT_NEEDED)
}
// DynString returns the strings listed for the given tag in the file's dynamic
// section.
//
// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
// DT_RUNPATH.
func (f *File) DynString(tag DynTag) ([]string, error) {
switch tag {
case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
default:
return nil, fmt.Errorf("non-string-valued tag %v", tag)
}
ds := f.SectionByType(SHT_DYNAMIC)
if ds == nil {
// not dynamic, so no libraries
return nil, nil
}
d, err := ds.Data()
if err != nil {
return nil, err
}
str, err := f.stringTable(ds.Link)
if err != nil {
return nil, err
}
var all []string
for len(d) > 0 {
var t DynTag
var v uint64
switch f.Class {
case ELFCLASS32:
t = DynTag(f.ByteOrder.Uint32(d[0:4]))
v = uint64(f.ByteOrder.Uint32(d[4:8]))
d = d[8:]
case ELFCLASS64:
t = DynTag(f.ByteOrder.Uint64(d[0:8]))
v = f.ByteOrder.Uint64(d[8:16])
d = d[16:]
}
if t == tag {
s, ok := getString(str, int(v))
if ok {
all = append(all, s)
}
}
}
return all, nil
}

146
vendor/golang.org/x/debug/macho/fat.go generated vendored Normal file
View File

@ -0,0 +1,146 @@
// 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 macho
import (
"encoding/binary"
"fmt"
"io"
"os"
)
// A FatFile is a Mach-O universal binary that contains at least one architecture.
type FatFile struct {
Magic uint32
Arches []FatArch
closer io.Closer
}
// A FatArchHeader represents a fat header for a specific image architecture.
type FatArchHeader struct {
Cpu Cpu
SubCpu uint32
Offset uint32
Size uint32
Align uint32
}
const fatArchHeaderSize = 5 * 4
// A FatArch is a Mach-O File inside a FatFile.
type FatArch struct {
FatArchHeader
*File
}
// ErrNotFat is returned from NewFatFile or OpenFat when the file is not a
// universal binary but may be a thin binary, based on its magic number.
var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil}
// NewFatFile creates a new FatFile for accessing all the Mach-O images in a
// universal binary. The Mach-O binary is expected to start at position 0 in
// the ReaderAt.
func NewFatFile(r io.ReaderAt) (*FatFile, error) {
var ff FatFile
sr := io.NewSectionReader(r, 0, 1<<63-1)
// Read the fat_header struct, which is always in big endian.
// Start with the magic number.
err := binary.Read(sr, binary.BigEndian, &ff.Magic)
if err != nil {
return nil, &FormatError{0, "error reading magic number", nil}
} else if ff.Magic != MagicFat {
// See if this is a Mach-O file via its magic number. The magic
// must be converted to little endian first though.
var buf [4]byte
binary.BigEndian.PutUint32(buf[:], ff.Magic)
leMagic := binary.LittleEndian.Uint32(buf[:])
if leMagic == Magic32 || leMagic == Magic64 {
return nil, ErrNotFat
} else {
return nil, &FormatError{0, "invalid magic number", nil}
}
}
offset := int64(4)
// Read the number of FatArchHeaders that come after the fat_header.
var narch uint32
err = binary.Read(sr, binary.BigEndian, &narch)
if err != nil {
return nil, &FormatError{offset, "invalid fat_header", nil}
}
offset += 4
if narch < 1 {
return nil, &FormatError{offset, "file contains no images", nil}
}
// Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
// there are not duplicate architectures.
seenArches := make(map[uint64]bool, narch)
// Make sure that all images are for the same MH_ type.
var machoType Type
// Following the fat_header comes narch fat_arch structs that index
// Mach-O images further in the file.
ff.Arches = make([]FatArch, narch)
for i := uint32(0); i < narch; i++ {
fa := &ff.Arches[i]
err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
if err != nil {
return nil, &FormatError{offset, "invalid fat_arch header", nil}
}
offset += fatArchHeaderSize
fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
fa.File, err = NewFile(fr)
if err != nil {
return nil, err
}
// Make sure the architecture for this image is not duplicate.
seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
if o, k := seenArches[seenArch]; o || k {
return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil}
}
seenArches[seenArch] = true
// Make sure the Mach-O type matches that of the first image.
if i == 0 {
machoType = fa.Type
} else {
if fa.Type != machoType {
return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil}
}
}
}
return &ff, nil
}
// OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
// universal binary.
func OpenFat(name string) (ff *FatFile, err error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
ff, err = NewFatFile(f)
if err != nil {
f.Close()
return nil, err
}
ff.closer = f
return
}
func (ff *FatFile) Close() error {
var err error
if ff.closer != nil {
err = ff.closer.Close()
ff.closer = nil
}
return err
}

525
vendor/golang.org/x/debug/macho/file.go generated vendored Normal file
View File

@ -0,0 +1,525 @@
// 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 macho implements access to Mach-O object files.
package macho
// High level access to low level data structures.
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"os"
"golang.org/x/debug/dwarf"
)
// A File represents an open Mach-O file.
type File struct {
FileHeader
ByteOrder binary.ByteOrder
Loads []Load
Sections []*Section
Symtab *Symtab
Dysymtab *Dysymtab
closer io.Closer
}
// A Load represents any Mach-O load command.
type Load interface {
Raw() []byte
}
// A LoadBytes is the uninterpreted bytes of a Mach-O load command.
type LoadBytes []byte
func (b LoadBytes) Raw() []byte { return b }
// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
type SegmentHeader struct {
Cmd LoadCmd
Len uint32
Name string
Addr uint64
Memsz uint64
Offset uint64
Filesz uint64
Maxprot uint32
Prot uint32
Nsect uint32
Flag uint32
}
// A Segment represents a Mach-O 32-bit or 64-bit load segment command.
type Segment struct {
LoadBytes
SegmentHeader
// Embed ReaderAt for ReadAt method.
// Do not embed SectionReader directly
// to avoid having Read and Seek.
// If a client wants Read and Seek it must use
// Open() to avoid fighting over the seek offset
// with other clients.
io.ReaderAt
sr *io.SectionReader
}
// Data reads and returns the contents of the segment.
func (s *Segment) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
if n == len(dat) {
err = nil
}
return dat[0:n], err
}
// Open returns a new ReadSeeker reading the segment.
func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
type SectionHeader struct {
Name string
Seg string
Addr uint64
Size uint64
Offset uint32
Align uint32
Reloff uint32
Nreloc uint32
Flags uint32
}
type Section struct {
SectionHeader
// Embed ReaderAt for ReadAt method.
// Do not embed SectionReader directly
// to avoid having Read and Seek.
// If a client wants Read and Seek it must use
// Open() to avoid fighting over the seek offset
// with other clients.
io.ReaderAt
sr *io.SectionReader
}
// Data reads and returns the contents of the Mach-O section.
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
if n == len(dat) {
err = nil
}
return dat[0:n], err
}
// Open returns a new ReadSeeker reading the Mach-O section.
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
// A Dylib represents a Mach-O load dynamic library command.
type Dylib struct {
LoadBytes
Name string
Time uint32
CurrentVersion uint32
CompatVersion uint32
}
// A Symtab represents a Mach-O symbol table command.
type Symtab struct {
LoadBytes
SymtabCmd
Syms []Symbol
}
// A Dysymtab represents a Mach-O dynamic symbol table command.
type Dysymtab struct {
LoadBytes
DysymtabCmd
IndirectSyms []uint32 // indices into Symtab.Syms
}
/*
* Mach-O reader
*/
// FormatError is returned by some operations if the data does
// not have the correct format for an object file.
type FormatError struct {
off int64
msg string
val interface{}
}
func (e *FormatError) Error() string {
msg := e.msg
if e.val != nil {
msg += fmt.Sprintf(" '%v'", e.val)
}
msg += fmt.Sprintf(" in record at byte %#x", e.off)
return msg
}
// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
func Open(name string) (*File, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
ff, err := NewFile(f)
if err != nil {
f.Close()
return nil, err
}
ff.closer = f
return ff, nil
}
// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
func (f *File) Close() error {
var err error
if f.closer != nil {
err = f.closer.Close()
f.closer = nil
}
return err
}
// NewFile creates a new File for accessing a Mach-O binary in an underlying reader.
// The Mach-O binary is expected to start at position 0 in the ReaderAt.
func NewFile(r io.ReaderAt) (*File, error) {
f := new(File)
sr := io.NewSectionReader(r, 0, 1<<63-1)
// Read and decode Mach magic to determine byte order, size.
// Magic32 and Magic64 differ only in the bottom bit.
var ident [4]byte
if _, err := r.ReadAt(ident[0:], 0); err != nil {
return nil, err
}
be := binary.BigEndian.Uint32(ident[0:])
le := binary.LittleEndian.Uint32(ident[0:])
switch Magic32 &^ 1 {
case be &^ 1:
f.ByteOrder = binary.BigEndian
f.Magic = be
case le &^ 1:
f.ByteOrder = binary.LittleEndian
f.Magic = le
default:
return nil, &FormatError{0, "invalid magic number", nil}
}
// Read entire file header.
if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
return nil, err
}
// Then load commands.
offset := int64(fileHeaderSize32)
if f.Magic == Magic64 {
offset = fileHeaderSize64
}
dat := make([]byte, f.Cmdsz)
if _, err := r.ReadAt(dat, offset); err != nil {
return nil, err
}
f.Loads = make([]Load, f.Ncmd)
bo := f.ByteOrder
for i := range f.Loads {
// Each load command begins with uint32 command and length.
if len(dat) < 8 {
return nil, &FormatError{offset, "command block too small", nil}
}
cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
if siz < 8 || siz > uint32(len(dat)) {
return nil, &FormatError{offset, "invalid command block size", nil}
}
var cmddat []byte
cmddat, dat = dat[0:siz], dat[siz:]
offset += int64(siz)
var s *Segment
switch cmd {
default:
f.Loads[i] = LoadBytes(cmddat)
case LoadCmdDylib:
var hdr DylibCmd
b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
l := new(Dylib)
if hdr.Name >= uint32(len(cmddat)) {
return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}
}
l.Name = cstring(cmddat[hdr.Name:])
l.Time = hdr.Time
l.CurrentVersion = hdr.CurrentVersion
l.CompatVersion = hdr.CompatVersion
l.LoadBytes = LoadBytes(cmddat)
f.Loads[i] = l
case LoadCmdSymtab:
var hdr SymtabCmd
b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
strtab := make([]byte, hdr.Strsize)
if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
return nil, err
}
var symsz int
if f.Magic == Magic64 {
symsz = 16
} else {
symsz = 12
}
symdat := make([]byte, int(hdr.Nsyms)*symsz)
if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
return nil, err
}
st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
if err != nil {
return nil, err
}
f.Loads[i] = st
f.Symtab = st
case LoadCmdDysymtab:
var hdr DysymtabCmd
b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
dat := make([]byte, hdr.Nindirectsyms*4)
if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
return nil, err
}
x := make([]uint32, hdr.Nindirectsyms)
if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
return nil, err
}
st := new(Dysymtab)
st.LoadBytes = LoadBytes(cmddat)
st.DysymtabCmd = hdr
st.IndirectSyms = x
f.Loads[i] = st
f.Dysymtab = st
case LoadCmdSegment:
var seg32 Segment32
b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &seg32); err != nil {
return nil, err
}
s = new(Segment)
s.LoadBytes = cmddat
s.Cmd = cmd
s.Len = siz
s.Name = cstring(seg32.Name[0:])
s.Addr = uint64(seg32.Addr)
s.Memsz = uint64(seg32.Memsz)
s.Offset = uint64(seg32.Offset)
s.Filesz = uint64(seg32.Filesz)
s.Maxprot = seg32.Maxprot
s.Prot = seg32.Prot
s.Nsect = seg32.Nsect
s.Flag = seg32.Flag
f.Loads[i] = s
for i := 0; i < int(s.Nsect); i++ {
var sh32 Section32
if err := binary.Read(b, bo, &sh32); err != nil {
return nil, err
}
sh := new(Section)
sh.Name = cstring(sh32.Name[0:])
sh.Seg = cstring(sh32.Seg[0:])
sh.Addr = uint64(sh32.Addr)
sh.Size = uint64(sh32.Size)
sh.Offset = sh32.Offset
sh.Align = sh32.Align
sh.Reloff = sh32.Reloff
sh.Nreloc = sh32.Nreloc
sh.Flags = sh32.Flags
f.pushSection(sh, r)
}
case LoadCmdSegment64:
var seg64 Segment64
b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &seg64); err != nil {
return nil, err
}
s = new(Segment)
s.LoadBytes = cmddat
s.Cmd = cmd
s.Len = siz
s.Name = cstring(seg64.Name[0:])
s.Addr = seg64.Addr
s.Memsz = seg64.Memsz
s.Offset = seg64.Offset
s.Filesz = seg64.Filesz
s.Maxprot = seg64.Maxprot
s.Prot = seg64.Prot
s.Nsect = seg64.Nsect
s.Flag = seg64.Flag
f.Loads[i] = s
for i := 0; i < int(s.Nsect); i++ {
var sh64 Section64
if err := binary.Read(b, bo, &sh64); err != nil {
return nil, err
}
sh := new(Section)
sh.Name = cstring(sh64.Name[0:])
sh.Seg = cstring(sh64.Seg[0:])
sh.Addr = sh64.Addr
sh.Size = sh64.Size
sh.Offset = sh64.Offset
sh.Align = sh64.Align
sh.Reloff = sh64.Reloff
sh.Nreloc = sh64.Nreloc
sh.Flags = sh64.Flags
f.pushSection(sh, r)
}
}
if s != nil {
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
s.ReaderAt = s.sr
}
}
return f, nil
}
func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
bo := f.ByteOrder
symtab := make([]Symbol, hdr.Nsyms)
b := bytes.NewReader(symdat)
for i := range symtab {
var n Nlist64
if f.Magic == Magic64 {
if err := binary.Read(b, bo, &n); err != nil {
return nil, err
}
} else {
var n32 Nlist32
if err := binary.Read(b, bo, &n32); err != nil {
return nil, err
}
n.Name = n32.Name
n.Type = n32.Type
n.Sect = n32.Sect
n.Desc = n32.Desc
n.Value = uint64(n32.Value)
}
sym := &symtab[i]
if n.Name >= uint32(len(strtab)) {
return nil, &FormatError{offset, "invalid name in symbol table", n.Name}
}
sym.Name = cstring(strtab[n.Name:])
sym.Type = n.Type
sym.Sect = n.Sect
sym.Desc = n.Desc
sym.Value = n.Value
}
st := new(Symtab)
st.LoadBytes = LoadBytes(cmddat)
st.Syms = symtab
return st, nil
}
func (f *File) pushSection(sh *Section, r io.ReaderAt) {
f.Sections = append(f.Sections, sh)
sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
sh.ReaderAt = sh.sr
}
func cstring(b []byte) string {
var i int
for i = 0; i < len(b) && b[i] != 0; i++ {
}
return string(b[0:i])
}
// Segment returns the first Segment with the given name, or nil if no such segment exists.
func (f *File) Segment(name string) *Segment {
for _, l := range f.Loads {
if s, ok := l.(*Segment); ok && s.Name == name {
return s
}
}
return nil
}
// Section returns the first section with the given name, or nil if no such
// section exists.
func (f *File) Section(name string) *Section {
for _, s := range f.Sections {
if s.Name == name {
return s
}
}
return nil
}
// DWARF returns the DWARF debug information for the Mach-O file.
func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
// does not use the others, so don't bother loading them.
var names = [...]string{"abbrev", "frame", "info", "line", "str"}
var dat [len(names)][]byte
for i, name := range names {
name = "__debug_" + name
s := f.Section(name)
if s == nil {
continue
}
b, err := s.Data()
if err != nil && uint64(len(b)) < s.Size {
return nil, err
}
dat[i] = b
}
abbrev, frame, info, line, str := dat[0], dat[1], dat[2], dat[3], dat[4]
return dwarf.New(abbrev, nil, frame, info, line, nil, nil, str)
}
// ImportedSymbols returns the names of all symbols
// referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time.
func (f *File) ImportedSymbols() ([]string, error) {
if f.Dysymtab == nil || f.Symtab == nil {
return nil, &FormatError{0, "missing symbol table", nil}
}
st := f.Symtab
dt := f.Dysymtab
var all []string
for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
all = append(all, s.Name)
}
return all, nil
}
// ImportedLibraries returns the paths of all libraries
// referred to by the binary f that are expected to be
// linked with the binary at dynamic link time.
func (f *File) ImportedLibraries() ([]string, error) {
var all []string
for _, l := range f.Loads {
if lib, ok := l.(*Dylib); ok {
all = append(all, lib.Name)
}
}
return all, nil
}

316
vendor/golang.org/x/debug/macho/macho.go generated vendored Normal file
View File

@ -0,0 +1,316 @@
// 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.
// Mach-O header data structures
// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
package macho
import "strconv"
// A FileHeader represents a Mach-O file header.
type FileHeader struct {
Magic uint32
Cpu Cpu
SubCpu uint32
Type Type
Ncmd uint32
Cmdsz uint32
Flags uint32
}
const (
fileHeaderSize32 = 7 * 4
fileHeaderSize64 = 8 * 4
)
const (
Magic32 uint32 = 0xfeedface
Magic64 uint32 = 0xfeedfacf
MagicFat uint32 = 0xcafebabe
)
// A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library.
type Type uint32
const (
TypeObj Type = 1
TypeExec Type = 2
TypeDylib Type = 6
TypeBundle Type = 8
)
// A Cpu is a Mach-O cpu type.
type Cpu uint32
const cpuArch64 = 0x01000000
const (
Cpu386 Cpu = 7
CpuAmd64 Cpu = Cpu386 | cpuArch64
CpuArm Cpu = 12
CpuPpc Cpu = 18
CpuPpc64 Cpu = CpuPpc | cpuArch64
)
var cpuStrings = []intName{
{uint32(Cpu386), "Cpu386"},
{uint32(CpuAmd64), "CpuAmd64"},
{uint32(CpuArm), "CpuArm"},
{uint32(CpuPpc), "CpuPpc"},
{uint32(CpuPpc64), "CpuPpc64"},
}
func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) }
// A LoadCmd is a Mach-O load command.
type LoadCmd uint32
const (
LoadCmdSegment LoadCmd = 1
LoadCmdSymtab LoadCmd = 2
LoadCmdThread LoadCmd = 4
LoadCmdUnixThread LoadCmd = 5 // thread+stack
LoadCmdDysymtab LoadCmd = 11
LoadCmdDylib LoadCmd = 12
LoadCmdDylinker LoadCmd = 15
LoadCmdSegment64 LoadCmd = 25
)
var cmdStrings = []intName{
{uint32(LoadCmdSegment), "LoadCmdSegment"},
{uint32(LoadCmdThread), "LoadCmdThread"},
{uint32(LoadCmdUnixThread), "LoadCmdUnixThread"},
{uint32(LoadCmdDylib), "LoadCmdDylib"},
{uint32(LoadCmdSegment64), "LoadCmdSegment64"},
}
func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) }
func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) }
// A Segment64 is a 64-bit Mach-O segment load command.
type Segment64 struct {
Cmd LoadCmd
Len uint32
Name [16]byte
Addr uint64
Memsz uint64
Offset uint64
Filesz uint64
Maxprot uint32
Prot uint32
Nsect uint32
Flag uint32
}
// A Segment32 is a 32-bit Mach-O segment load command.
type Segment32 struct {
Cmd LoadCmd
Len uint32
Name [16]byte
Addr uint32
Memsz uint32
Offset uint32
Filesz uint32
Maxprot uint32
Prot uint32
Nsect uint32
Flag uint32
}
// A DylibCmd is a Mach-O load dynamic library command.
type DylibCmd struct {
Cmd LoadCmd
Len uint32
Name uint32
Time uint32
CurrentVersion uint32
CompatVersion uint32
}
// A Section32 is a 32-bit Mach-O section header.
type Section32 struct {
Name [16]byte
Seg [16]byte
Addr uint32
Size uint32
Offset uint32
Align uint32
Reloff uint32
Nreloc uint32
Flags uint32
Reserve1 uint32
Reserve2 uint32
}
// A Section32 is a 64-bit Mach-O section header.
type Section64 struct {
Name [16]byte
Seg [16]byte
Addr uint64
Size uint64
Offset uint32
Align uint32
Reloff uint32
Nreloc uint32
Flags uint32
Reserve1 uint32
Reserve2 uint32
Reserve3 uint32
}
// A SymtabCmd is a Mach-O symbol table command.
type SymtabCmd struct {
Cmd LoadCmd
Len uint32
Symoff uint32
Nsyms uint32
Stroff uint32
Strsize uint32
}
// A DysymtabCmd is a Mach-O dynamic symbol table command.
type DysymtabCmd struct {
Cmd LoadCmd
Len uint32
Ilocalsym uint32
Nlocalsym uint32
Iextdefsym uint32
Nextdefsym uint32
Iundefsym uint32
Nundefsym uint32
Tocoffset uint32
Ntoc uint32
Modtaboff uint32
Nmodtab uint32
Extrefsymoff uint32
Nextrefsyms uint32
Indirectsymoff uint32
Nindirectsyms uint32
Extreloff uint32
Nextrel uint32
Locreloff uint32
Nlocrel uint32
}
// An Nlist32 is a Mach-O 32-bit symbol table entry.
type Nlist32 struct {
Name uint32
Type uint8
Sect uint8
Desc uint16
Value uint32
}
// An Nlist64 is a Mach-O 64-bit symbol table entry.
type Nlist64 struct {
Name uint32
Type uint8
Sect uint8
Desc uint16
Value uint64
}
// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry.
type Symbol struct {
Name string
Type uint8
Sect uint8
Desc uint16
Value uint64
}
// A Thread is a Mach-O thread state command.
type Thread struct {
Cmd LoadCmd
Len uint32
Type uint32
Data []uint32
}
// Regs386 is the Mach-O 386 register structure.
type Regs386 struct {
AX uint32
BX uint32
CX uint32
DX uint32
DI uint32
SI uint32
BP uint32
SP uint32
SS uint32
FLAGS uint32
IP uint32
CS uint32
DS uint32
ES uint32
FS uint32
GS uint32
}
// RegsAMD64 is the Mach-O AMD64 register structure.
type RegsAMD64 struct {
AX uint64
BX uint64
CX uint64
DX uint64
DI uint64
SI uint64
BP uint64
SP uint64
R8 uint64
R9 uint64
R10 uint64
R11 uint64
R12 uint64
R13 uint64
R14 uint64
R15 uint64
IP uint64
FLAGS uint64
CS uint64
FS uint64
GS uint64
}
type intName struct {
i uint32
s string
}
func stringName(i uint32, names []intName, goSyntax bool) string {
for _, n := range names {
if n.i == i {
if goSyntax {
return "macho." + n.s
}
return n.s
}
}
return strconv.FormatUint(uint64(i), 10)
}
func flagName(i uint32, names []intName, goSyntax bool) string {
s := ""
for _, n := range names {
if n.i&i == n.i {
if len(s) > 0 {
s += "+"
}
if goSyntax {
s += "macho."
}
s += n.s
i -= n.i
}
}
if len(s) == 0 {
return "0x" + strconv.FormatUint(uint64(i), 16)
}
if i != 0 {
s += "+0x" + strconv.FormatUint(uint64(i), 16)
}
return s
}