mirror of
https://github.com/go-delve/delve.git
synced 2025-10-28 04:35:19 +08:00
Support Go1.4rc1
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
package proctl
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"debug/gosym"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -10,7 +11,6 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/frame"
|
||||
"github.com/derekparker/delve/vendor/dwarf"
|
||||
)
|
||||
|
||||
// Struct representing a debugged process. Holds onto pid, register values,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package proctl
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"debug/gosym"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -8,7 +9,6 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/frame"
|
||||
"github.com/derekparker/delve/vendor/elf"
|
||||
)
|
||||
|
||||
func (dbp *DebuggedProcess) addThread(tid int) (*ThreadContext, error) {
|
||||
|
||||
@ -315,7 +315,7 @@ func TestFindReturnAddress(t *testing.T) {
|
||||
readMemory(p.Pid, uintptr(addr), data)
|
||||
addr = binary.LittleEndian.Uint64(data)
|
||||
|
||||
expected := uint64(0x400f03)
|
||||
expected := uint64(0x400fbc)
|
||||
if addr != expected {
|
||||
t.Fatalf("return address not found correctly, expected %#v got %#v", expected, addr)
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package proctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
@ -9,7 +10,6 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/op"
|
||||
"github.com/derekparker/delve/vendor/dwarf"
|
||||
)
|
||||
|
||||
type Variable struct {
|
||||
|
||||
@ -21,7 +21,7 @@ func TestVariableEvaluation(t *testing.T) {
|
||||
{"a1", "foo", "struct string"},
|
||||
{"a2", "6", "int"},
|
||||
{"a3", "7.23", "float64"},
|
||||
{"a4", "[2]int [1 2]", "[65]int"},
|
||||
{"a4", "[2]int [1 2]", "[2]int"},
|
||||
{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"},
|
||||
{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar"},
|
||||
{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar"},
|
||||
|
||||
181
vendor/dwarf/buf.go
vendored
181
vendor/dwarf/buf.go
vendored
@ -1,181 +0,0 @@
|
||||
// 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"
|
||||
"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) 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) }
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
454
vendor/dwarf/const.go
vendored
454
vendor/dwarf/const.go
vendored
@ -1,454 +0,0 @@
|
||||
// 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
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
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
|
||||
)
|
||||
401
vendor/dwarf/entry.go
vendored
401
vendor/dwarf/entry.go
vendored
@ -1,401 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
87
vendor/dwarf/open.go
vendored
87
vendor/dwarf/open.go
vendored
@ -1,87 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
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)
|
||||
}
|
||||
85
vendor/dwarf/testdata/typedef.c
vendored
85
vendor/dwarf/testdata/typedef.c
vendored
@ -1,85 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
Linux ELF:
|
||||
gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o
|
||||
|
||||
OS X Mach-O:
|
||||
gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho
|
||||
*/
|
||||
#include <complex.h>
|
||||
|
||||
typedef volatile int* t_ptr_volatile_int;
|
||||
typedef const char *t_ptr_const_char;
|
||||
typedef long t_long;
|
||||
typedef unsigned short t_ushort;
|
||||
typedef int t_func_int_of_float_double(float, double);
|
||||
typedef int (*t_ptr_func_int_of_float_double)(float, double);
|
||||
typedef int (*t_ptr_func_int_of_float_complex)(float complex);
|
||||
typedef int (*t_ptr_func_int_of_double_complex)(double complex);
|
||||
typedef int (*t_ptr_func_int_of_long_double_complex)(long double complex);
|
||||
typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char);
|
||||
typedef void t_func_void_of_char(char);
|
||||
typedef void t_func_void_of_void(void);
|
||||
typedef void t_func_void_of_ptr_char_dots(char*, ...);
|
||||
typedef struct my_struct {
|
||||
volatile int vi;
|
||||
char x : 1;
|
||||
int y : 4;
|
||||
int z[0];
|
||||
long long array[40];
|
||||
int zz[0];
|
||||
} t_my_struct;
|
||||
typedef struct my_struct1 {
|
||||
int zz [1];
|
||||
} t_my_struct1;
|
||||
typedef union my_union {
|
||||
volatile int vi;
|
||||
char x : 1;
|
||||
int y : 4;
|
||||
long long array[40];
|
||||
} t_my_union;
|
||||
typedef enum my_enum {
|
||||
e1 = 1,
|
||||
e2 = 2,
|
||||
e3 = -5,
|
||||
e4 = 1000000000000000LL,
|
||||
} t_my_enum;
|
||||
|
||||
typedef struct list t_my_list;
|
||||
struct list {
|
||||
short val;
|
||||
t_my_list *next;
|
||||
};
|
||||
|
||||
typedef struct tree {
|
||||
struct tree *left, *right;
|
||||
unsigned long long val;
|
||||
} t_my_tree;
|
||||
|
||||
t_ptr_volatile_int *a2;
|
||||
t_ptr_const_char **a3a;
|
||||
t_long *a4;
|
||||
t_ushort *a5;
|
||||
t_func_int_of_float_double *a6;
|
||||
t_ptr_func_int_of_float_double *a7;
|
||||
t_func_ptr_int_of_char_schar_uchar *a8;
|
||||
t_func_void_of_char *a9;
|
||||
t_func_void_of_void *a10;
|
||||
t_func_void_of_ptr_char_dots *a11;
|
||||
t_my_struct *a12;
|
||||
t_my_struct1 *a12a;
|
||||
t_my_union *a12b;
|
||||
t_my_enum *a13;
|
||||
t_my_list *a14;
|
||||
t_my_tree *a15;
|
||||
t_ptr_func_int_of_float_complex *a16;
|
||||
t_ptr_func_int_of_double_complex *a17;
|
||||
t_ptr_func_int_of_long_double_complex *a18;
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
BIN
vendor/dwarf/testdata/typedef.elf
vendored
BIN
vendor/dwarf/testdata/typedef.elf
vendored
Binary file not shown.
BIN
vendor/dwarf/testdata/typedef.elf4
vendored
BIN
vendor/dwarf/testdata/typedef.elf4
vendored
Binary file not shown.
BIN
vendor/dwarf/testdata/typedef.macho
vendored
BIN
vendor/dwarf/testdata/typedef.macho
vendored
Binary file not shown.
673
vendor/dwarf/type.go
vendored
673
vendor/dwarf/type.go
vendored
@ -1,673 +0,0 @@
|
||||
// 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 "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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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() }
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
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 AttrType field.
|
||||
// Set err if error happens. Not having a type is an error.
|
||||
typeOf := func(e *Entry) Type {
|
||||
tval := e.Val(AttrType)
|
||||
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: size in bits of 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)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
if t.Type = typeOf(e); err != nil {
|
||||
goto Error
|
||||
}
|
||||
t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
|
||||
|
||||
// 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:
|
||||
max, ok := kid.Val(AttrUpperBound).(int64)
|
||||
if !ok {
|
||||
max = -2 // Count == -1, as in x[].
|
||||
}
|
||||
if ndim == 0 {
|
||||
t.Count = max + 1
|
||||
} else {
|
||||
// Multidimensional array.
|
||||
// Create new array type underneath this one.
|
||||
t.Type = &ArrayType{Type: t.Type, Count: max + 1}
|
||||
}
|
||||
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)
|
||||
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)
|
||||
|
||||
case TagClassType, TagStructType, TagUnionType:
|
||||
// Structure, union, or class type. (DWARF v2 §5.5)
|
||||
// Attributes:
|
||||
// AttrName: name of struct, union, or class
|
||||
// AttrByteSize: byte size [required]
|
||||
// AttrDeclaration: if true, struct/union/class is incomplete
|
||||
// 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)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
switch e.Tag {
|
||||
case TagClassType:
|
||||
t.Kind = "class"
|
||||
case TagStructType:
|
||||
t.Kind = "struct"
|
||||
case TagUnionType:
|
||||
t.Kind = "union"
|
||||
}
|
||||
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); err != nil {
|
||||
goto Error
|
||||
}
|
||||
switch loc := kid.Val(AttrDataMemberLoc).(type) {
|
||||
case []byte:
|
||||
// TODO: Should have original compilation
|
||||
// unit here, not unknownFormat.
|
||||
b := makeBuf(d, unknownFormat{}, "location", 0, loc)
|
||||
if len(loc) != 0 && b.uint8() != opConsts {
|
||||
err = DecodeError{name, kid.Offset, "unexpected opcode"}
|
||||
goto Error
|
||||
}
|
||||
f.ByteOffset = int64(b.uint())
|
||||
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)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
if t.Type = typeOf(e); 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)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
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)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
if e.Val(AttrType) == nil {
|
||||
t.Type = &VoidType{}
|
||||
break
|
||||
}
|
||||
t.Type = typeOf(e)
|
||||
|
||||
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)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
if t.ReturnType = typeOf(e); 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); err != nil {
|
||||
goto Error
|
||||
}
|
||||
case TagUnspecifiedParameters:
|
||||
tkid = &DotDotDotType{}
|
||||
}
|
||||
t.ParamType = append(t.ParamType, tkid)
|
||||
}
|
||||
|
||||
case TagTypedef:
|
||||
// Typedef (DWARF v2 §5.3)
|
||||
// Attributes:
|
||||
// AttrName: name [required]
|
||||
// AttrType: type definition [required]
|
||||
t := new(TypedefType)
|
||||
typ = t
|
||||
typeCache[off] = t
|
||||
t.Name, _ = e.Val(AttrName).(string)
|
||||
t.Type = typeOf(e)
|
||||
|
||||
case TagUnspecifiedType:
|
||||
// Typedef (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
|
||||
}
|
||||
|
||||
{
|
||||
b, ok := e.Val(AttrByteSize).(int64)
|
||||
if !ok {
|
||||
b = -1
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
122
vendor/dwarf/type_test.go
vendored
122
vendor/dwarf/type_test.go
vendored
@ -1,122 +0,0 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
. "debug/dwarf"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var typedefTests = map[string]string{
|
||||
"t_ptr_volatile_int": "*volatile int",
|
||||
"t_ptr_const_char": "*const char",
|
||||
"t_long": "long int",
|
||||
"t_ushort": "short unsigned int",
|
||||
"t_func_int_of_float_double": "func(float, double) int",
|
||||
"t_ptr_func_int_of_float_double": "*func(float, double) int",
|
||||
"t_ptr_func_int_of_float_complex": "*func(complex float) int",
|
||||
"t_ptr_func_int_of_double_complex": "*func(complex double) int",
|
||||
"t_ptr_func_int_of_long_double_complex": "*func(complex long double) int",
|
||||
"t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int",
|
||||
"t_func_void_of_char": "func(char) void",
|
||||
"t_func_void_of_void": "func() void",
|
||||
"t_func_void_of_ptr_char_dots": "func(*char, ...) void",
|
||||
"t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; z [0]int@8; array [40]long long int@8; zz [0]int@328}",
|
||||
"t_my_struct1": "struct my_struct1 {zz [1]int@0}",
|
||||
"t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
|
||||
"t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
|
||||
"t_my_list": "struct list {val short int@0; next *t_my_list@8}",
|
||||
"t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
|
||||
}
|
||||
|
||||
// As Apple converts gcc to a clang-based front end
|
||||
// they keep breaking the DWARF output. This map lists the
|
||||
// conversion from real answer to Apple answer.
|
||||
var machoBug = map[string]string{
|
||||
"func(*char, ...) void": "func(*char) void",
|
||||
"enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}": "enum my_enum {e1=1; e2=2; e3=-5; e4=-1530494976}",
|
||||
}
|
||||
|
||||
func elfData(t *testing.T, name string) *Data {
|
||||
f, err := elf.Open(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d, err := f.DWARF()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func machoData(t *testing.T, name string) *Data {
|
||||
f, err := macho.Open(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d, err := f.DWARF()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf") }
|
||||
|
||||
func TestTypedefsMachO(t *testing.T) {
|
||||
testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
|
||||
}
|
||||
|
||||
func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") }
|
||||
|
||||
func testTypedefs(t *testing.T, d *Data, kind string) {
|
||||
r := d.Reader()
|
||||
seen := make(map[string]bool)
|
||||
for {
|
||||
e, err := r.Next()
|
||||
if err != nil {
|
||||
t.Fatal("r.Next:", err)
|
||||
}
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
if e.Tag == TagTypedef {
|
||||
typ, err := d.Type(e.Offset)
|
||||
if err != nil {
|
||||
t.Fatal("d.Type:", err)
|
||||
}
|
||||
t1 := typ.(*TypedefType)
|
||||
var typstr string
|
||||
if ts, ok := t1.Type.(*StructType); ok {
|
||||
typstr = ts.Defn()
|
||||
} else {
|
||||
typstr = t1.Type.String()
|
||||
}
|
||||
|
||||
if want, ok := typedefTests[t1.Name]; ok {
|
||||
if seen[t1.Name] {
|
||||
t.Errorf("multiple definitions for %s", t1.Name)
|
||||
}
|
||||
seen[t1.Name] = true
|
||||
if typstr != want && (kind != "macho" || typstr != machoBug[want]) {
|
||||
t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
if e.Tag != TagCompileUnit {
|
||||
r.SkipChildren()
|
||||
}
|
||||
}
|
||||
|
||||
for k := range typedefTests {
|
||||
if !seen[k] {
|
||||
t.Errorf("missing %s", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
166
vendor/dwarf/typeunit.go
vendored
166
vendor/dwarf/typeunit.go
vendored
@ -1,166 +0,0 @@
|
||||
// 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:])
|
||||
}
|
||||
|
||||
// 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/dwarf/unit.go
vendored
90
vendor/dwarf/unit.go
vendored
@ -1,90 +0,0 @@
|
||||
// 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/elf/elf.go
vendored
1521
vendor/elf/elf.go
vendored
File diff suppressed because it is too large
Load Diff
49
vendor/elf/elf_test.go
vendored
49
vendor/elf/elf_test.go
vendored
@ -1,49 +0,0 @@
|
||||
// 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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type nameTest struct {
|
||||
val interface{}
|
||||
str string
|
||||
}
|
||||
|
||||
var nameTests = []nameTest{
|
||||
{ELFOSABI_LINUX, "ELFOSABI_LINUX"},
|
||||
{ET_EXEC, "ET_EXEC"},
|
||||
{EM_860, "EM_860"},
|
||||
{SHN_LOPROC, "SHN_LOPROC"},
|
||||
{SHT_PROGBITS, "SHT_PROGBITS"},
|
||||
{SHF_MERGE + SHF_TLS, "SHF_MERGE+SHF_TLS"},
|
||||
{PT_LOAD, "PT_LOAD"},
|
||||
{PF_W + PF_R + 0x50, "PF_W+PF_R+0x50"},
|
||||
{DT_SYMBOLIC, "DT_SYMBOLIC"},
|
||||
{DF_BIND_NOW, "DF_BIND_NOW"},
|
||||
{NT_FPREGSET, "NT_FPREGSET"},
|
||||
{STB_GLOBAL, "STB_GLOBAL"},
|
||||
{STT_COMMON, "STT_COMMON"},
|
||||
{STV_HIDDEN, "STV_HIDDEN"},
|
||||
{R_X86_64_PC32, "R_X86_64_PC32"},
|
||||
{R_ALPHA_OP_PUSH, "R_ALPHA_OP_PUSH"},
|
||||
{R_ARM_THM_ABS5, "R_ARM_THM_ABS5"},
|
||||
{R_386_GOT32, "R_386_GOT32"},
|
||||
{R_PPC_GOT16_HI, "R_PPC_GOT16_HI"},
|
||||
{R_SPARC_GOT22, "R_SPARC_GOT22"},
|
||||
{ET_LOOS + 5, "ET_LOOS+5"},
|
||||
{ProgFlag(0x50), "0x50"},
|
||||
}
|
||||
|
||||
func TestNames(t *testing.T) {
|
||||
for i, tt := range nameTests {
|
||||
s := fmt.Sprint(tt.val)
|
||||
if s != tt.str {
|
||||
t.Errorf("#%d: Sprint(%d) = %q, want %q", i, tt.val, s, tt.str)
|
||||
}
|
||||
}
|
||||
}
|
||||
882
vendor/elf/file.go
vendored
882
vendor/elf/file.go
vendored
@ -1,882 +0,0 @@
|
||||
// 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"
|
||||
|
||||
"github.com/derekparker/delve/vendor/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)
|
||||
}
|
||||
if f.Class == ELFCLASS32 && f.Machine == EM_386 {
|
||||
return f.applyRelocations386(dst, rels)
|
||||
}
|
||||
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
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) applyRelocations386(dst []byte, rels []byte) error {
|
||||
// 8 is the size of Rel32.
|
||||
if len(rels)%8 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 8")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rel Rel32
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rel)
|
||||
symNo := rel.Info >> 8
|
||||
t := R_386(rel.Info & 0xff)
|
||||
|
||||
if symNo == 0 || symNo > uint32(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
|
||||
if t == R_386_32 {
|
||||
if rel.Off+4 >= uint32(len(dst)) {
|
||||
continue
|
||||
}
|
||||
val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
|
||||
val += uint32(sym.Value)
|
||||
f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
var names = [...]string{"abbrev", "info", "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[1], data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// When using clang we need to process relocations even for 386.
|
||||
rel := f.Section(".rel.debug_info")
|
||||
if rel != nil && rel.Type == SHT_REL && f.Machine == EM_386 {
|
||||
data, err := rel.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = f.applyRelocations(dat[1], data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
abbrev, info, str := dat[0], dat[1], dat[2]
|
||||
d, err := dwarf.New(abbrev, nil, nil, info, nil, 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
|
||||
}
|
||||
340
vendor/elf/file_test.go
vendored
340
vendor/elf/file_test.go
vendored
@ -1,340 +0,0 @@
|
||||
// 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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/derekparker/delve/vendor/dwarf"
|
||||
)
|
||||
|
||||
type fileTest struct {
|
||||
file string
|
||||
hdr FileHeader
|
||||
sections []SectionHeader
|
||||
progs []ProgHeader
|
||||
needed []string
|
||||
}
|
||||
|
||||
var fileTests = []fileTest{
|
||||
{
|
||||
"testdata/gcc-386-freebsd-exec",
|
||||
FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
|
||||
[]SectionHeader{
|
||||
{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
|
||||
{".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
|
||||
{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
|
||||
{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
|
||||
{".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
|
||||
{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
|
||||
{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
|
||||
{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
|
||||
{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
|
||||
{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
|
||||
{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
|
||||
{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
|
||||
{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
|
||||
{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
|
||||
{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
|
||||
{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
|
||||
{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
|
||||
{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
|
||||
{".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
|
||||
{".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
|
||||
{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
|
||||
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
|
||||
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
|
||||
},
|
||||
[]ProgHeader{
|
||||
{PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
|
||||
{PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
|
||||
{PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
|
||||
{PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
|
||||
{PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
|
||||
},
|
||||
[]string{"libc.so.6"},
|
||||
},
|
||||
{
|
||||
"testdata/gcc-amd64-linux-exec",
|
||||
FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
|
||||
[]SectionHeader{
|
||||
{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
|
||||
{".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
|
||||
{".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
|
||||
{".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
|
||||
{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
|
||||
{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
|
||||
{".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
|
||||
{".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
|
||||
{".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
|
||||
{".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
|
||||
{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
|
||||
{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
|
||||
{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
|
||||
{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
|
||||
{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
|
||||
{".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
|
||||
{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
|
||||
{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
|
||||
{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
|
||||
{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
|
||||
{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
|
||||
{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
|
||||
{".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
|
||||
{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
|
||||
{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
|
||||
{".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
|
||||
{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
|
||||
{".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
|
||||
{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
|
||||
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
|
||||
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
|
||||
},
|
||||
[]ProgHeader{
|
||||
{PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
|
||||
{PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
|
||||
{PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
|
||||
{PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
|
||||
{PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
|
||||
{PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
|
||||
{PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
|
||||
{PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
|
||||
},
|
||||
[]string{"libc.so.6"},
|
||||
},
|
||||
{
|
||||
"testdata/hello-world-core.gz",
|
||||
FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_CORE, EM_X86_64, 0x0},
|
||||
[]SectionHeader{},
|
||||
[]ProgHeader{
|
||||
{Type: PT_NOTE, Flags: 0x0, Off: 0x3f8, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x8ac, Memsz: 0x0, Align: 0x0},
|
||||
{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x1000, Vaddr: 0x400000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_R, Off: 0x1000, Vaddr: 0x401000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x2000, Vaddr: 0x402000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3000, Vaddr: 0x7f54078b8000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1b5000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: 0x0, Off: 0x3000, Vaddr: 0x7f5407a6d000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1ff000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_R, Off: 0x3000, Vaddr: 0x7f5407c6c000, Paddr: 0x0, Filesz: 0x4000, Memsz: 0x4000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x7000, Vaddr: 0x7f5407c70000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x9000, Vaddr: 0x7f5407c72000, Paddr: 0x0, Filesz: 0x5000, Memsz: 0x5000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0xe000, Vaddr: 0x7f5407c77000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x22000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0xe000, Vaddr: 0x7f5407e81000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x11000, Vaddr: 0x7f5407e96000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_R, Off: 0x14000, Vaddr: 0x7f5407e99000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x15000, Vaddr: 0x7f5407e9a000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x17000, Vaddr: 0x7fff79972000, Paddr: 0x0, Filesz: 0x23000, Memsz: 0x23000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3a000, Vaddr: 0x7fff799f8000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
|
||||
{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3b000, Vaddr: 0xffffffffff600000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
for i := range fileTests {
|
||||
tt := &fileTests[i]
|
||||
|
||||
var f *File
|
||||
var err error
|
||||
if path.Ext(tt.file) == ".gz" {
|
||||
var r io.ReaderAt
|
||||
if r, err = decompress(tt.file); err == nil {
|
||||
f, err = NewFile(r)
|
||||
}
|
||||
} else {
|
||||
f, err = Open(tt.file)
|
||||
}
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
t.Errorf("cannot open file %s: %v", tt.file, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
|
||||
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
|
||||
continue
|
||||
}
|
||||
for i, s := range f.Sections {
|
||||
if i >= len(tt.sections) {
|
||||
break
|
||||
}
|
||||
sh := &tt.sections[i]
|
||||
if !reflect.DeepEqual(&s.SectionHeader, sh) {
|
||||
t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
|
||||
}
|
||||
}
|
||||
for i, p := range f.Progs {
|
||||
if i >= len(tt.progs) {
|
||||
break
|
||||
}
|
||||
ph := &tt.progs[i]
|
||||
if !reflect.DeepEqual(&p.ProgHeader, ph) {
|
||||
t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph)
|
||||
}
|
||||
}
|
||||
tn := len(tt.sections)
|
||||
fn := len(f.Sections)
|
||||
if tn != fn {
|
||||
t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
|
||||
}
|
||||
tn = len(tt.progs)
|
||||
fn = len(f.Progs)
|
||||
if tn != fn {
|
||||
t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
|
||||
}
|
||||
tl := tt.needed
|
||||
fl, err := f.ImportedLibraries()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !reflect.DeepEqual(tl, fl) {
|
||||
t.Errorf("open %s: DT_NEEDED = %v, want %v", tt.file, tl, fl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// elf.NewFile requires io.ReaderAt, which compress/gzip cannot
|
||||
// provide. Decompress the file to a bytes.Reader.
|
||||
func decompress(gz string) (io.ReaderAt, error) {
|
||||
in, err := os.Open(gz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer in.Close()
|
||||
r, err := gzip.NewReader(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out bytes.Buffer
|
||||
_, err = io.Copy(&out, r)
|
||||
return bytes.NewReader(out.Bytes()), err
|
||||
}
|
||||
|
||||
type relocationTestEntry struct {
|
||||
entryNumber int
|
||||
entry *dwarf.Entry
|
||||
}
|
||||
|
||||
type relocationTest struct {
|
||||
file string
|
||||
entries []relocationTestEntry
|
||||
}
|
||||
|
||||
var relocationTests = []relocationTest{
|
||||
{
|
||||
"testdata/go-relocation-test-gcc441-x86-64.obj",
|
||||
[]relocationTestEntry{
|
||||
{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"testdata/go-relocation-test-gcc441-x86.obj",
|
||||
[]relocationTestEntry{
|
||||
{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"testdata/go-relocation-test-gcc424-x86-64.obj",
|
||||
[]relocationTestEntry{
|
||||
{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"testdata/go-relocation-test-clang-x86.obj",
|
||||
[]relocationTestEntry{
|
||||
{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
|
||||
[]relocationTestEntry{
|
||||
{203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}},
|
||||
{204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(237)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestDWARFRelocations(t *testing.T) {
|
||||
for i, test := range relocationTests {
|
||||
f, err := Open(test.file)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
dwarf, err := f.DWARF()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
for _, testEntry := range test.entries {
|
||||
reader := dwarf.Reader()
|
||||
for j := 0; j < testEntry.entryNumber; j++ {
|
||||
entry, err := reader.Next()
|
||||
if entry == nil || err != nil {
|
||||
t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
entry, err := reader.Next()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(testEntry.entry, entry) {
|
||||
t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSectionOverlaps(t *testing.T) {
|
||||
// Ensure 6l outputs sections without overlaps.
|
||||
if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
|
||||
return // not ELF
|
||||
}
|
||||
_ = net.ResolveIPAddr // force dynamic linkage
|
||||
f, err := Open(os.Args[0])
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
for i, si := range f.Sections {
|
||||
sih := si.SectionHeader
|
||||
if sih.Type == SHT_NOBITS {
|
||||
continue
|
||||
}
|
||||
for j, sj := range f.Sections {
|
||||
sjh := sj.SectionHeader
|
||||
if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
|
||||
continue
|
||||
}
|
||||
if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
|
||||
t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
|
||||
sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
vendor/elf/testdata/gcc-386-freebsd-exec
vendored
BIN
vendor/elf/testdata/gcc-386-freebsd-exec
vendored
Binary file not shown.
BIN
vendor/elf/testdata/gcc-amd64-linux-exec
vendored
BIN
vendor/elf/testdata/gcc-amd64-linux-exec
vendored
Binary file not shown.
Binary file not shown.
BIN
vendor/elf/testdata/go-relocation-test-clang-x86.obj
vendored
BIN
vendor/elf/testdata/go-relocation-test-clang-x86.obj
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
vendor/elf/testdata/hello-world-core.gz
vendored
BIN
vendor/elf/testdata/hello-world-core.gz
vendored
Binary file not shown.
7
vendor/elf/testdata/hello.c
vendored
7
vendor/elf/testdata/hello.c
vendored
@ -1,7 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
printf("hello, world\n");
|
||||
}
|
||||
Reference in New Issue
Block a user