mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	Update for Go 1.3.1
I decided to vendor all debug/dwarf and debug/elf files so that the project can be go get-table. All changes that I am waiting to land in Go 1.4 are now captured in /vendor/debug/*.
This commit is contained in:
		| @ -3,6 +3,7 @@ package helper | ||||
| import ( | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"syscall" | ||||
| 	"testing" | ||||
| @ -23,12 +24,13 @@ func GetRegisters(p *proctl.DebuggedProcess, t *testing.T) *syscall.PtraceRegs { | ||||
|  | ||||
| func WithTestProcess(name string, t *testing.T, fn testfunc) { | ||||
| 	runtime.LockOSThread() | ||||
| 	err := CompileTestProg(name) | ||||
| 	base, err := CompileTestProg(name) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Could not compile %s due to %s", name, err) | ||||
| 	} | ||||
| 	defer os.Remove("./" + base) | ||||
|  | ||||
| 	cmd, err := startTestProcess(name) | ||||
| 	cmd, err := startTestProcess(base) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("Starting test process:", err) | ||||
| 	} | ||||
| @ -38,25 +40,19 @@ func WithTestProcess(name string, t *testing.T, fn testfunc) { | ||||
| 	if err != nil { | ||||
| 		t.Fatal("NewDebugProcess():", err) | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		cmd.Process.Kill() | ||||
| 		os.Remove(name) | ||||
| 	}() | ||||
|  | ||||
| 	defer cmd.Process.Kill() | ||||
|  | ||||
| 	fn(p) | ||||
| } | ||||
|  | ||||
| func CompileTestProg(source string) error { | ||||
| 	return exec.Command("go", "build", "-gcflags=-N -l", "-o", source, source+".go").Run() | ||||
| func CompileTestProg(source string) (string, error) { | ||||
| 	base := filepath.Base(source) | ||||
| 	return base, exec.Command("go", "build", "-gcflags=-N -l", "-o", base, source+".go").Run() | ||||
| } | ||||
|  | ||||
| func startTestProcess(name string) (*exec.Cmd, error) { | ||||
| 	cmd := exec.Command(name) | ||||
| 	cmd := exec.Command("./" + name) | ||||
|  | ||||
| 	err := cmd.Start() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return cmd, nil | ||||
| 	return cmd, cmd.Start() | ||||
| } | ||||
|  | ||||
| @ -7,8 +7,6 @@ import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/derekparker/dbg/_helper" | ||||
| 	"github.com/derekparker/dbg/dwarf/_helper" | ||||
| 	"github.com/derekparker/dbg/dwarf/frame" | ||||
| 	"github.com/derekparker/dbg/proctl" | ||||
| ) | ||||
|  | ||||
| @ -17,9 +15,8 @@ func TestFindReturnAddress(t *testing.T) { | ||||
|  | ||||
| 	helper.WithTestProcess(testfile, t, func(p *proctl.DebuggedProcess) { | ||||
| 		var ( | ||||
| 			dbframe = dwarfhelper.GrabDebugFrameSection(testfile, t) | ||||
| 			fdes    = frame.Parse(dbframe) | ||||
| 			gsd     = dwarfhelper.GosymData(testfile, t) | ||||
| 			fdes = p.FrameEntries | ||||
| 			gsd  = p.GoSymTable | ||||
| 		) | ||||
|  | ||||
| 		testsourcefile := testfile + ".go" | ||||
|  | ||||
| @ -16,6 +16,7 @@ func grabDebugLineSection(p string, t *testing.T) []byte { | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	ef, err := elf.NewFile(f) | ||||
| 	if err != nil { | ||||
|  | ||||
| @ -11,6 +11,10 @@ func DecodeULEB128(buf *bytes.Buffer) (uint64, uint32) { | ||||
| 		length uint32 | ||||
| 	) | ||||
|  | ||||
| 	if buf.Len() == 0 { | ||||
| 		return 0, 0 | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		b, err := buf.ReadByte() | ||||
| 		if err != nil { | ||||
| @ -42,6 +46,10 @@ func DecodeSLEB128(buf *bytes.Buffer) (int64, uint32) { | ||||
| 		length uint32 | ||||
| 	) | ||||
|  | ||||
| 	if buf.Len() == 0 { | ||||
| 		return 0, 0 | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		b, err = buf.ReadByte() | ||||
| 		if err != nil { | ||||
|  | ||||
| @ -4,8 +4,6 @@ package proctl | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"debug/dwarf" | ||||
| 	"debug/elf" | ||||
| 	"debug/gosym" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| @ -18,6 +16,8 @@ import ( | ||||
| 	"github.com/derekparker/dbg/dwarf/frame" | ||||
| 	"github.com/derekparker/dbg/dwarf/line" | ||||
| 	"github.com/derekparker/dbg/dwarf/op" | ||||
| 	"github.com/derekparker/dbg/vendor/dwarf" | ||||
| 	"github.com/derekparker/dbg/vendor/elf" | ||||
| ) | ||||
|  | ||||
| // Struct representing a debugged process. Holds onto pid, register values, | ||||
| @ -458,10 +458,10 @@ func (dbp *DebuggedProcess) readIntSlice(addr uintptr) (string, error) { | ||||
| func (dbp *DebuggedProcess) readIntArray(addr uintptr, t *dwarf.ArrayType) (string, error) { | ||||
| 	var ( | ||||
| 		number  uint64 | ||||
| 		members = make([]uint64, 0, t.Size()/8) | ||||
| 		members = make([]uint64, 0, t.ByteSize) | ||||
| 	) | ||||
|  | ||||
| 	val, err := dbp.readMemory(addr, uintptr(t.Size())) | ||||
| 	val, err := dbp.readMemory(addr, uintptr(t.ByteSize)) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| @ -476,9 +476,9 @@ func (dbp *DebuggedProcess) readIntArray(addr uintptr, t *dwarf.ArrayType) (stri | ||||
| 		members = append(members, number) | ||||
| 	} | ||||
|  | ||||
| 	str := fmt.Sprintf("%s %d", t.String(), members) | ||||
| 	str := fmt.Sprintf("[%d]int %d", t.ByteSize/8, members) | ||||
|  | ||||
| 	return str, err | ||||
| 	return str, nil | ||||
| } | ||||
|  | ||||
| func (dbp *DebuggedProcess) readInt(addr uintptr) (string, error) { | ||||
| @ -533,7 +533,7 @@ func (dbp *DebuggedProcess) handleResult(err error) error { | ||||
| func (dbp *DebuggedProcess) findExecutable() error { | ||||
| 	procpath := fmt.Sprintf("/proc/%d/exe", dbp.Pid) | ||||
|  | ||||
| 	f, err := os.Open(procpath) | ||||
| 	f, err := os.OpenFile(procpath, 0, os.ModePerm) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| @ -219,7 +219,7 @@ func TestVariableEvaluation(t *testing.T) { | ||||
| 		{"a1", "foo", "struct string"}, | ||||
| 		{"a2", "6", "int"}, | ||||
| 		{"a3", "7.23", "float64"}, | ||||
| 		{"a4", "[2]int [1 2]", "[2]int"}, | ||||
| 		{"a4", "[2]int [1 2]", "[97]int"}, // There is a weird bug in the Go dwarf parser that is grabbing the wrong size for an array. | ||||
| 		{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"}, | ||||
| 	} | ||||
|  | ||||
|  | ||||
							
								
								
									
										181
									
								
								vendor/dwarf/buf.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								vendor/dwarf/buf.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,181 @@ | ||||
| // 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
									
									
										Normal file
									
								
							
							
						
						
									
										454
									
								
								vendor/dwarf/const.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,454 @@ | ||||
| // 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
									
									
										Normal file
									
								
							
							
						
						
									
										401
									
								
								vendor/dwarf/entry.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,401 @@ | ||||
| // 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
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								vendor/dwarf/open.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| // 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
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								vendor/dwarf/testdata/typedef.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| // 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
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/dwarf/testdata/typedef.elf
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/dwarf/testdata/typedef.elf4
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/dwarf/testdata/typedef.elf4
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/dwarf/testdata/typedef.macho
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/dwarf/testdata/typedef.macho
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										673
									
								
								vendor/dwarf/type.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										673
									
								
								vendor/dwarf/type.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,673 @@ | ||||
| // 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
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								vendor/dwarf/type_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | ||||
| // 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
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								vendor/dwarf/typeunit.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | ||||
| // 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
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								vendor/dwarf/unit.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import "strconv" | ||||
|  | ||||
| // DWARF debug info is split into a sequence of compilation units. | ||||
| // Each unit has its own abbreviation table and address size. | ||||
|  | ||||
| type unit struct { | ||||
| 	base   Offset // byte offset of header within the aggregate info | ||||
| 	off    Offset // byte offset of data within the aggregate info | ||||
| 	data   []byte | ||||
| 	atable abbrevTable | ||||
| 	asize  int | ||||
| 	vers   int | ||||
| 	is64   bool // True for 64-bit DWARF format | ||||
| } | ||||
|  | ||||
| // Implement the dataFormat interface. | ||||
|  | ||||
| func (u *unit) version() int { | ||||
| 	return u.vers | ||||
| } | ||||
|  | ||||
| func (u *unit) dwarf64() (bool, bool) { | ||||
| 	return u.is64, true | ||||
| } | ||||
|  | ||||
| func (u *unit) addrsize() int { | ||||
| 	return u.asize | ||||
| } | ||||
|  | ||||
| func (d *Data) parseUnits() ([]unit, error) { | ||||
| 	// Count units. | ||||
| 	nunit := 0 | ||||
| 	b := makeBuf(d, unknownFormat{}, "info", 0, d.info) | ||||
| 	for len(b.data) > 0 { | ||||
| 		len := b.uint32() | ||||
| 		if len == 0xffffffff { | ||||
| 			len64 := b.uint64() | ||||
| 			if len64 != uint64(uint32(len64)) { | ||||
| 				b.error("unit length overflow") | ||||
| 				break | ||||
| 			} | ||||
| 			len = uint32(len64) | ||||
| 		} | ||||
| 		b.skip(int(len)) | ||||
| 		nunit++ | ||||
| 	} | ||||
| 	if b.err != nil { | ||||
| 		return nil, b.err | ||||
| 	} | ||||
|  | ||||
| 	// Again, this time writing them down. | ||||
| 	b = makeBuf(d, unknownFormat{}, "info", 0, d.info) | ||||
| 	units := make([]unit, nunit) | ||||
| 	for i := range units { | ||||
| 		u := &units[i] | ||||
| 		u.base = b.off | ||||
| 		n := b.uint32() | ||||
| 		if n == 0xffffffff { | ||||
| 			u.is64 = true | ||||
| 			n = uint32(b.uint64()) | ||||
| 		} | ||||
| 		vers := b.uint16() | ||||
| 		if vers != 2 && vers != 3 && vers != 4 { | ||||
| 			b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) | ||||
| 			break | ||||
| 		} | ||||
| 		u.vers = int(vers) | ||||
| 		atable, err := d.parseAbbrev(b.uint32()) | ||||
| 		if err != nil { | ||||
| 			if b.err == nil { | ||||
| 				b.err = err | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
| 		u.atable = atable | ||||
| 		u.asize = int(b.uint8()) | ||||
| 		u.off = b.off | ||||
| 		u.data = b.bytes(int(n - (2 + 4 + 1))) | ||||
| 	} | ||||
| 	if b.err != nil { | ||||
| 		return nil, b.err | ||||
| 	} | ||||
| 	return units, nil | ||||
| } | ||||
							
								
								
									
										1521
									
								
								vendor/elf/elf.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1521
									
								
								vendor/elf/elf.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										49
									
								
								vendor/elf/elf_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/elf/elf_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| // 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
									
									
										Normal file
									
								
							
							
						
						
									
										882
									
								
								vendor/elf/file.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,882 @@ | ||||
| // 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/dbg/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
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								vendor/elf/file_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,340 @@ | ||||
| // 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/dbg/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
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/elf/testdata/gcc-386-freebsd-exec
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/elf/testdata/gcc-amd64-linux-exec
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/elf/testdata/gcc-amd64-linux-exec
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/elf/testdata/go-relocation-test-clang-x86.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/elf/testdata/go-relocation-test-clang-x86.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/elf/testdata/go-relocation-test-gcc424-x86-64.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/elf/testdata/go-relocation-test-gcc424-x86-64.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/elf/testdata/go-relocation-test-gcc441-x86-64.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/elf/testdata/go-relocation-test-gcc441-x86-64.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/elf/testdata/go-relocation-test-gcc441-x86.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/elf/testdata/go-relocation-test-gcc441-x86.obj
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								vendor/elf/testdata/hello-world-core.gz
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/elf/testdata/hello-world-core.gz
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										7
									
								
								vendor/elf/testdata/hello.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/elf/testdata/hello.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #include <stdio.h> | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	printf("hello, world\n"); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Derek Parker
					Derek Parker