mirror of
				https://github.com/beego/bee.git
				synced 2025-10-31 17:33:26 +00:00 
			
		
		
		
	Update vendor folder (Delve support)
This commit is contained in:
		
							
								
								
									
										27
									
								
								vendor/golang.org/x/debug/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/debug/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2014 The Go Authors. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
|    * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
|    * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
|    * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										203
									
								
								vendor/golang.org/x/debug/dwarf/buf.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								vendor/golang.org/x/debug/dwarf/buf.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Buffered reading and decoding of DWARF data streams. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // Data buffer being decoded. | ||||
| type buf struct { | ||||
| 	dwarf  *Data | ||||
| 	order  binary.ByteOrder | ||||
| 	format dataFormat | ||||
| 	name   string | ||||
| 	off    Offset | ||||
| 	data   []byte | ||||
| 	err    error | ||||
| } | ||||
|  | ||||
| // Data format, other than byte order.  This affects the handling of | ||||
| // certain field formats. | ||||
| type dataFormat interface { | ||||
| 	// DWARF version number.  Zero means unknown. | ||||
| 	version() int | ||||
|  | ||||
| 	// 64-bit DWARF format? | ||||
| 	dwarf64() (dwarf64 bool, isKnown bool) | ||||
|  | ||||
| 	// Size of an address, in bytes.  Zero means unknown. | ||||
| 	addrsize() int | ||||
| } | ||||
|  | ||||
| // Some parts of DWARF have no data format, e.g., abbrevs. | ||||
| type unknownFormat struct{} | ||||
|  | ||||
| func (u unknownFormat) version() int { | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (u unknownFormat) dwarf64() (bool, bool) { | ||||
| 	return false, false | ||||
| } | ||||
|  | ||||
| func (u unknownFormat) addrsize() int { | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf { | ||||
| 	return buf{d, d.order, format, name, off, data, nil} | ||||
| } | ||||
|  | ||||
| func (b *buf) slice(length int) buf { | ||||
| 	n := *b | ||||
| 	data := b.data | ||||
| 	b.skip(length) // Will validate length. | ||||
| 	n.data = data[:length] | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| func (b *buf) uint8() uint8 { | ||||
| 	if len(b.data) < 1 { | ||||
| 		b.error("underflow") | ||||
| 		return 0 | ||||
| 	} | ||||
| 	val := b.data[0] | ||||
| 	b.data = b.data[1:] | ||||
| 	b.off++ | ||||
| 	return val | ||||
| } | ||||
|  | ||||
| func (b *buf) bytes(n int) []byte { | ||||
| 	if len(b.data) < n { | ||||
| 		b.error("underflow") | ||||
| 		return nil | ||||
| 	} | ||||
| 	data := b.data[0:n] | ||||
| 	b.data = b.data[n:] | ||||
| 	b.off += Offset(n) | ||||
| 	return data | ||||
| } | ||||
|  | ||||
| func (b *buf) skip(n int) { b.bytes(n) } | ||||
|  | ||||
| // string returns the NUL-terminated (C-like) string at the start of the buffer. | ||||
| // The terminal NUL is discarded. | ||||
| func (b *buf) string() string { | ||||
| 	for i := 0; i < len(b.data); i++ { | ||||
| 		if b.data[i] == 0 { | ||||
| 			s := string(b.data[0:i]) | ||||
| 			b.data = b.data[i+1:] | ||||
| 			b.off += Offset(i + 1) | ||||
| 			return s | ||||
| 		} | ||||
| 	} | ||||
| 	b.error("underflow") | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *buf) uint16() uint16 { | ||||
| 	a := b.bytes(2) | ||||
| 	if a == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return b.order.Uint16(a) | ||||
| } | ||||
|  | ||||
| func (b *buf) uint32() uint32 { | ||||
| 	a := b.bytes(4) | ||||
| 	if a == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return b.order.Uint32(a) | ||||
| } | ||||
|  | ||||
| func (b *buf) uint64() uint64 { | ||||
| 	a := b.bytes(8) | ||||
| 	if a == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return b.order.Uint64(a) | ||||
| } | ||||
|  | ||||
| // Read a varint, which is 7 bits per byte, little endian. | ||||
| // the 0x80 bit means read another byte. | ||||
| func (b *buf) varint() (c uint64, bits uint) { | ||||
| 	for i := 0; i < len(b.data); i++ { | ||||
| 		byte := b.data[i] | ||||
| 		c |= uint64(byte&0x7F) << bits | ||||
| 		bits += 7 | ||||
| 		if byte&0x80 == 0 { | ||||
| 			b.off += Offset(i + 1) | ||||
| 			b.data = b.data[i+1:] | ||||
| 			return c, bits | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, 0 | ||||
| } | ||||
|  | ||||
| // Unsigned int is just a varint. | ||||
| func (b *buf) uint() uint64 { | ||||
| 	x, _ := b.varint() | ||||
| 	return x | ||||
| } | ||||
|  | ||||
| // Signed int is a sign-extended varint. | ||||
| func (b *buf) int() int64 { | ||||
| 	ux, bits := b.varint() | ||||
| 	x := int64(ux) | ||||
| 	if x&(1<<(bits-1)) != 0 { | ||||
| 		x |= -1 << bits | ||||
| 	} | ||||
| 	return x | ||||
| } | ||||
|  | ||||
| // Address-sized uint. | ||||
| func (b *buf) addr() uint64 { | ||||
| 	switch b.format.addrsize() { | ||||
| 	case 1: | ||||
| 		return uint64(b.uint8()) | ||||
| 	case 2: | ||||
| 		return uint64(b.uint16()) | ||||
| 	case 4: | ||||
| 		return uint64(b.uint32()) | ||||
| 	case 8: | ||||
| 		return uint64(b.uint64()) | ||||
| 	} | ||||
| 	b.error("unknown address size") | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // assertEmpty checks that everything has been read from b. | ||||
| func (b *buf) assertEmpty() { | ||||
| 	if len(b.data) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	if len(b.data) > 5 { | ||||
| 		b.error(fmt.Sprintf("unexpected extra data: %x...", b.data[0:5])) | ||||
| 	} | ||||
| 	b.error(fmt.Sprintf("unexpected extra data: %x", b.data)) | ||||
| } | ||||
|  | ||||
| func (b *buf) error(s string) { | ||||
| 	if b.err == nil { | ||||
| 		b.data = nil | ||||
| 		b.err = DecodeError{b.name, b.off, s} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type DecodeError struct { | ||||
| 	Name   string | ||||
| 	Offset Offset | ||||
| 	Err    string | ||||
| } | ||||
|  | ||||
| func (e DecodeError) Error() string { | ||||
| 	return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.FormatInt(int64(e.Offset), 16) + ": " + e.Err | ||||
| } | ||||
							
								
								
									
										249
									
								
								vendor/golang.org/x/debug/dwarf/cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								vendor/golang.org/x/debug/dwarf/cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,249 @@ | ||||
| // Copyright 2016 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
| ) | ||||
|  | ||||
| // pcToFuncEntries maps PC ranges to function entries. | ||||
| // | ||||
| // Each element contains a *Entry for a function and its corresponding start PC. | ||||
| // If we know the address one past the last instruction of a function, and it is | ||||
| // not equal to the start address of the next function, we mark that with | ||||
| // another element containing that address and a nil entry.  The elements are | ||||
| // sorted by PC.  Among elements with the same PC, those with non-nil *Entry | ||||
| // are put earlier. | ||||
| type pcToFuncEntries []pcToFuncEntry | ||||
| type pcToFuncEntry struct { | ||||
| 	pc    uint64 | ||||
| 	entry *Entry | ||||
| } | ||||
|  | ||||
| func (p pcToFuncEntries) Len() int      { return len(p) } | ||||
| func (p pcToFuncEntries) Swap(i, j int) { p[i], p[j] = p[j], p[i] } | ||||
| func (p pcToFuncEntries) Less(i, j int) bool { | ||||
| 	if p[i].pc != p[j].pc { | ||||
| 		return p[i].pc < p[j].pc | ||||
| 	} | ||||
| 	return p[i].entry != nil && p[j].entry == nil | ||||
| } | ||||
|  | ||||
| // nameCache maps each symbol name to a linked list of the entries with that name. | ||||
| type nameCache map[string]*nameCacheEntry | ||||
| type nameCacheEntry struct { | ||||
| 	entry *Entry | ||||
| 	link  *nameCacheEntry | ||||
| } | ||||
|  | ||||
| // pcToLineEntries maps PCs to line numbers. | ||||
| // | ||||
| // It is a slice of (PC, line, file number) triples, sorted by PC.  The file | ||||
| // number is an index into the source files slice. | ||||
| // If (PC1, line1, file1) and (PC2, line2, file2) are two consecutive elements, | ||||
| // then the span of addresses [PC1, PC2) belongs to (line1, file1).  If an | ||||
| // element's file number is zero, it only marks the end of a span. | ||||
| // | ||||
| // TODO: could save memory by changing pcToLineEntries and lineToPCEntries to use | ||||
| // interval trees containing references into .debug_line. | ||||
| type pcToLineEntries []pcToLineEntry | ||||
| type pcToLineEntry struct { | ||||
| 	pc   uint64 | ||||
| 	line uint64 | ||||
| 	file uint64 | ||||
| } | ||||
|  | ||||
| func (p pcToLineEntries) Len() int      { return len(p) } | ||||
| func (p pcToLineEntries) Swap(i, j int) { p[i], p[j] = p[j], p[i] } | ||||
| func (p pcToLineEntries) Less(i, j int) bool { | ||||
| 	if p[i].pc != p[j].pc { | ||||
| 		return p[i].pc < p[j].pc | ||||
| 	} | ||||
| 	return p[i].file > p[j].file | ||||
| } | ||||
|  | ||||
| // byFileLine is used temporarily while building lineToPCEntries. | ||||
| type byFileLine []pcToLineEntry | ||||
|  | ||||
| func (b byFileLine) Len() int      { return len(b) } | ||||
| func (b byFileLine) Swap(i, j int) { b[i], b[j] = b[j], b[i] } | ||||
| func (b byFileLine) Less(i, j int) bool { | ||||
| 	if b[i].file != b[j].file { | ||||
| 		return b[i].file < b[j].file | ||||
| 	} | ||||
| 	return b[i].line < b[j].line | ||||
| } | ||||
|  | ||||
| // lineToPCEntries maps line numbers to breakpoint addresses. | ||||
| // | ||||
| // The slice contains, for each source file in Data, a slice of (line, PC) | ||||
| // pairs, sorted by line.  Note that there may be more than one PC for a line. | ||||
| type lineToPCEntries [][]lineToPCEntry | ||||
| type lineToPCEntry struct { | ||||
| 	line uint64 | ||||
| 	pc   uint64 | ||||
| } | ||||
|  | ||||
| func (d *Data) buildLineToPCCache(pclfs pcToLineEntries) { | ||||
| 	// TODO: only include lines where is_stmt is true | ||||
| 	sort.Sort(byFileLine(pclfs)) | ||||
| 	// Make a slice of (line, PC) pairs for each (non-zero) file. | ||||
| 	var ( | ||||
| 		c        = make(lineToPCEntries, len(d.sourceFiles)) | ||||
| 		curSlice []lineToPCEntry | ||||
| 	) | ||||
| 	for i, pclf := range pclfs { | ||||
| 		if pclf.file == 0 { | ||||
| 			// This entry indicated the end of an instruction sequence, not a breakpoint. | ||||
| 			continue | ||||
| 		} | ||||
| 		curSlice = append(curSlice, lineToPCEntry{line: pclf.line, pc: pclf.pc}) | ||||
| 		if i+1 == len(pclfs) || pclf.file != pclfs[i+1].file { | ||||
| 			// curSlice now contains all of the entries for pclf.file. | ||||
| 			if pclf.file > 0 && pclf.file < uint64(len(c)) { | ||||
| 				c[pclf.file] = curSlice | ||||
| 			} | ||||
| 			curSlice = nil | ||||
| 		} | ||||
| 	} | ||||
| 	d.lineToPCEntries = c | ||||
| } | ||||
|  | ||||
| func (d *Data) buildPCToLineCache(cache pcToLineEntries) { | ||||
| 	// Sort cache by PC (in increasing order), then by file number (in decreasing order). | ||||
| 	sort.Sort(cache) | ||||
|  | ||||
| 	// Build a copy without redundant entries. | ||||
| 	var out pcToLineEntries | ||||
| 	for i, pclf := range cache { | ||||
| 		if i > 0 && pclf.pc == cache[i-1].pc { | ||||
| 			// This entry is for the same PC as the previous entry. | ||||
| 			continue | ||||
| 		} | ||||
| 		if i > 0 && pclf.file == cache[i-1].file && pclf.line == cache[i-1].line { | ||||
| 			// This entry is for the same file and line as the previous entry. | ||||
| 			continue | ||||
| 		} | ||||
| 		out = append(out, pclf) | ||||
| 	} | ||||
| 	d.pcToLineEntries = out | ||||
| } | ||||
|  | ||||
| // buildLineCaches constructs d.sourceFiles, d.lineToPCEntries, d.pcToLineEntries. | ||||
| func (d *Data) buildLineCaches() { | ||||
| 	if len(d.line) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	var m lineMachine | ||||
| 	// Assume the address_size in the first unit applies to the whole program. | ||||
| 	// TODO: we could handle executables containing code for multiple address | ||||
| 	// sizes using DW_AT_stmt_list attributes. | ||||
| 	if len(d.unit) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	buf := makeBuf(d, &d.unit[0], "line", 0, d.line) | ||||
| 	if err := m.parseHeader(&buf); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, f := range m.header.file { | ||||
| 		d.sourceFiles = append(d.sourceFiles, f.name) | ||||
| 	} | ||||
| 	var cache pcToLineEntries | ||||
| 	fn := func(m *lineMachine) bool { | ||||
| 		if m.endSequence { | ||||
| 			cache = append(cache, pcToLineEntry{ | ||||
| 				pc:   m.address, | ||||
| 				line: 0, | ||||
| 				file: 0, | ||||
| 			}) | ||||
| 		} else { | ||||
| 			cache = append(cache, pcToLineEntry{ | ||||
| 				pc:   m.address, | ||||
| 				line: m.line, | ||||
| 				file: m.file, | ||||
| 			}) | ||||
| 		} | ||||
| 		return true | ||||
| 	} | ||||
| 	m.evalCompilationUnit(&buf, fn) | ||||
| 	d.buildLineToPCCache(cache) | ||||
| 	d.buildPCToLineCache(cache) | ||||
| } | ||||
|  | ||||
| // buildInfoCaches initializes nameCache and pcToFuncEntries by walking the | ||||
| // top-level entries under each compile unit. It swallows any errors in parsing. | ||||
| func (d *Data) buildInfoCaches() { | ||||
| 	// TODO: record errors somewhere? | ||||
| 	d.nameCache = make(map[string]*nameCacheEntry) | ||||
|  | ||||
| 	var pcToFuncEntries pcToFuncEntries | ||||
|  | ||||
| 	r := d.Reader() | ||||
| loop: | ||||
| 	for { | ||||
| 		entry, err := r.Next() | ||||
| 		if entry == nil || err != nil { | ||||
| 			break loop | ||||
| 		} | ||||
| 		if entry.Tag != TagCompileUnit /* DW_TAG_compile_unit */ { | ||||
| 			r.SkipChildren() | ||||
| 			continue | ||||
| 		} | ||||
| 		for { | ||||
| 			entry, err := r.Next() | ||||
| 			if entry == nil || err != nil { | ||||
| 				break loop | ||||
| 			} | ||||
| 			if entry.Tag == 0 { | ||||
| 				// End of children of current compile unit. | ||||
| 				break | ||||
| 			} | ||||
| 			r.SkipChildren() | ||||
| 			// Update name-to-entry cache. | ||||
| 			if name, ok := entry.Val(AttrName).(string); ok { | ||||
| 				d.nameCache[name] = &nameCacheEntry{entry: entry, link: d.nameCache[name]} | ||||
| 			} | ||||
|  | ||||
| 			// If this entry is a function, update PC-to-containing-function cache. | ||||
| 			if entry.Tag != TagSubprogram /* DW_TAG_subprogram */ { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			// DW_AT_low_pc, if present, is the address of the first instruction of | ||||
| 			// the function. | ||||
| 			lowpc, ok := entry.Val(AttrLowpc).(uint64) | ||||
| 			if !ok { | ||||
| 				continue | ||||
| 			} | ||||
| 			pcToFuncEntries = append(pcToFuncEntries, pcToFuncEntry{lowpc, entry}) | ||||
|  | ||||
| 			// DW_AT_high_pc, if present (TODO: and of class address) is the address | ||||
| 			// one past the last instruction of the function. | ||||
| 			highpc, ok := entry.Val(AttrHighpc).(uint64) | ||||
| 			if !ok { | ||||
| 				continue | ||||
| 			} | ||||
| 			pcToFuncEntries = append(pcToFuncEntries, pcToFuncEntry{highpc, nil}) | ||||
| 		} | ||||
| 	} | ||||
| 	// Sort elements by PC.  If there are multiple elements with the same PC, | ||||
| 	// those with non-nil *Entry are placed earlier. | ||||
| 	sort.Sort(pcToFuncEntries) | ||||
|  | ||||
| 	// Copy only the first element for each PC to out. | ||||
| 	n := 0 | ||||
| 	for i, ce := range pcToFuncEntries { | ||||
| 		if i == 0 || ce.pc != pcToFuncEntries[i-1].pc { | ||||
| 			n++ | ||||
| 		} | ||||
| 	} | ||||
| 	out := make([]pcToFuncEntry, 0, n) | ||||
| 	for i, ce := range pcToFuncEntries { | ||||
| 		if i == 0 || ce.pc != pcToFuncEntries[i-1].pc { | ||||
| 			out = append(out, ce) | ||||
| 		} | ||||
| 	} | ||||
| 	d.pcToFuncEntries = out | ||||
| } | ||||
							
								
								
									
										467
									
								
								vendor/golang.org/x/debug/dwarf/const.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										467
									
								
								vendor/golang.org/x/debug/dwarf/const.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,467 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Constants | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import "strconv" | ||||
|  | ||||
| // An Attr identifies the attribute type in a DWARF Entry's Field. | ||||
| type Attr uint32 | ||||
|  | ||||
| const ( | ||||
| 	AttrSibling        Attr = 0x01 | ||||
| 	AttrLocation       Attr = 0x02 | ||||
| 	AttrName           Attr = 0x03 | ||||
| 	AttrOrdering       Attr = 0x09 | ||||
| 	AttrByteSize       Attr = 0x0B | ||||
| 	AttrBitOffset      Attr = 0x0C | ||||
| 	AttrBitSize        Attr = 0x0D | ||||
| 	AttrStmtList       Attr = 0x10 | ||||
| 	AttrLowpc          Attr = 0x11 | ||||
| 	AttrHighpc         Attr = 0x12 | ||||
| 	AttrLanguage       Attr = 0x13 | ||||
| 	AttrDiscr          Attr = 0x15 | ||||
| 	AttrDiscrValue     Attr = 0x16 | ||||
| 	AttrVisibility     Attr = 0x17 | ||||
| 	AttrImport         Attr = 0x18 | ||||
| 	AttrStringLength   Attr = 0x19 | ||||
| 	AttrCommonRef      Attr = 0x1A | ||||
| 	AttrCompDir        Attr = 0x1B | ||||
| 	AttrConstValue     Attr = 0x1C | ||||
| 	AttrContainingType Attr = 0x1D | ||||
| 	AttrDefaultValue   Attr = 0x1E | ||||
| 	AttrInline         Attr = 0x20 | ||||
| 	AttrIsOptional     Attr = 0x21 | ||||
| 	AttrLowerBound     Attr = 0x22 | ||||
| 	AttrProducer       Attr = 0x25 | ||||
| 	AttrPrototyped     Attr = 0x27 | ||||
| 	AttrReturnAddr     Attr = 0x2A | ||||
| 	AttrStartScope     Attr = 0x2C | ||||
| 	AttrStrideSize     Attr = 0x2E | ||||
| 	AttrUpperBound     Attr = 0x2F | ||||
| 	AttrAbstractOrigin Attr = 0x31 | ||||
| 	AttrAccessibility  Attr = 0x32 | ||||
| 	AttrAddrClass      Attr = 0x33 | ||||
| 	AttrArtificial     Attr = 0x34 | ||||
| 	AttrBaseTypes      Attr = 0x35 | ||||
| 	AttrCalling        Attr = 0x36 | ||||
| 	AttrCount          Attr = 0x37 | ||||
| 	AttrDataMemberLoc  Attr = 0x38 | ||||
| 	AttrDeclColumn     Attr = 0x39 | ||||
| 	AttrDeclFile       Attr = 0x3A | ||||
| 	AttrDeclLine       Attr = 0x3B | ||||
| 	AttrDeclaration    Attr = 0x3C | ||||
| 	AttrDiscrList      Attr = 0x3D | ||||
| 	AttrEncoding       Attr = 0x3E | ||||
| 	AttrExternal       Attr = 0x3F | ||||
| 	AttrFrameBase      Attr = 0x40 | ||||
| 	AttrFriend         Attr = 0x41 | ||||
| 	AttrIdentifierCase Attr = 0x42 | ||||
| 	AttrMacroInfo      Attr = 0x43 | ||||
| 	AttrNamelistItem   Attr = 0x44 | ||||
| 	AttrPriority       Attr = 0x45 | ||||
| 	AttrSegment        Attr = 0x46 | ||||
| 	AttrSpecification  Attr = 0x47 | ||||
| 	AttrStaticLink     Attr = 0x48 | ||||
| 	AttrType           Attr = 0x49 | ||||
| 	AttrUseLocation    Attr = 0x4A | ||||
| 	AttrVarParam       Attr = 0x4B | ||||
| 	AttrVirtuality     Attr = 0x4C | ||||
| 	AttrVtableElemLoc  Attr = 0x4D | ||||
| 	AttrAllocated      Attr = 0x4E | ||||
| 	AttrAssociated     Attr = 0x4F | ||||
| 	AttrDataLocation   Attr = 0x50 | ||||
| 	AttrStride         Attr = 0x51 | ||||
| 	AttrEntrypc        Attr = 0x52 | ||||
| 	AttrUseUTF8        Attr = 0x53 | ||||
| 	AttrExtension      Attr = 0x54 | ||||
| 	AttrRanges         Attr = 0x55 | ||||
| 	AttrTrampoline     Attr = 0x56 | ||||
| 	AttrCallColumn     Attr = 0x57 | ||||
| 	AttrCallFile       Attr = 0x58 | ||||
| 	AttrCallLine       Attr = 0x59 | ||||
| 	AttrDescription    Attr = 0x5A | ||||
|  | ||||
| 	// Go-specific attributes. | ||||
| 	AttrGoKind Attr = 0x2900 | ||||
| 	AttrGoKey  Attr = 0x2901 | ||||
| 	AttrGoElem Attr = 0x2902 | ||||
| ) | ||||
|  | ||||
| var attrNames = [...]string{ | ||||
| 	AttrSibling:        "Sibling", | ||||
| 	AttrLocation:       "Location", | ||||
| 	AttrName:           "Name", | ||||
| 	AttrOrdering:       "Ordering", | ||||
| 	AttrByteSize:       "ByteSize", | ||||
| 	AttrBitOffset:      "BitOffset", | ||||
| 	AttrBitSize:        "BitSize", | ||||
| 	AttrStmtList:       "StmtList", | ||||
| 	AttrLowpc:          "Lowpc", | ||||
| 	AttrHighpc:         "Highpc", | ||||
| 	AttrLanguage:       "Language", | ||||
| 	AttrDiscr:          "Discr", | ||||
| 	AttrDiscrValue:     "DiscrValue", | ||||
| 	AttrVisibility:     "Visibility", | ||||
| 	AttrImport:         "Import", | ||||
| 	AttrStringLength:   "StringLength", | ||||
| 	AttrCommonRef:      "CommonRef", | ||||
| 	AttrCompDir:        "CompDir", | ||||
| 	AttrConstValue:     "ConstValue", | ||||
| 	AttrContainingType: "ContainingType", | ||||
| 	AttrDefaultValue:   "DefaultValue", | ||||
| 	AttrInline:         "Inline", | ||||
| 	AttrIsOptional:     "IsOptional", | ||||
| 	AttrLowerBound:     "LowerBound", | ||||
| 	AttrProducer:       "Producer", | ||||
| 	AttrPrototyped:     "Prototyped", | ||||
| 	AttrReturnAddr:     "ReturnAddr", | ||||
| 	AttrStartScope:     "StartScope", | ||||
| 	AttrStrideSize:     "StrideSize", | ||||
| 	AttrUpperBound:     "UpperBound", | ||||
| 	AttrAbstractOrigin: "AbstractOrigin", | ||||
| 	AttrAccessibility:  "Accessibility", | ||||
| 	AttrAddrClass:      "AddrClass", | ||||
| 	AttrArtificial:     "Artificial", | ||||
| 	AttrBaseTypes:      "BaseTypes", | ||||
| 	AttrCalling:        "Calling", | ||||
| 	AttrCount:          "Count", | ||||
| 	AttrDataMemberLoc:  "DataMemberLoc", | ||||
| 	AttrDeclColumn:     "DeclColumn", | ||||
| 	AttrDeclFile:       "DeclFile", | ||||
| 	AttrDeclLine:       "DeclLine", | ||||
| 	AttrDeclaration:    "Declaration", | ||||
| 	AttrDiscrList:      "DiscrList", | ||||
| 	AttrEncoding:       "Encoding", | ||||
| 	AttrExternal:       "External", | ||||
| 	AttrFrameBase:      "FrameBase", | ||||
| 	AttrFriend:         "Friend", | ||||
| 	AttrIdentifierCase: "IdentifierCase", | ||||
| 	AttrMacroInfo:      "MacroInfo", | ||||
| 	AttrNamelistItem:   "NamelistItem", | ||||
| 	AttrPriority:       "Priority", | ||||
| 	AttrSegment:        "Segment", | ||||
| 	AttrSpecification:  "Specification", | ||||
| 	AttrStaticLink:     "StaticLink", | ||||
| 	AttrType:           "Type", | ||||
| 	AttrUseLocation:    "UseLocation", | ||||
| 	AttrVarParam:       "VarParam", | ||||
| 	AttrVirtuality:     "Virtuality", | ||||
| 	AttrVtableElemLoc:  "VtableElemLoc", | ||||
| 	AttrAllocated:      "Allocated", | ||||
| 	AttrAssociated:     "Associated", | ||||
| 	AttrDataLocation:   "DataLocation", | ||||
| 	AttrStride:         "Stride", | ||||
| 	AttrEntrypc:        "Entrypc", | ||||
| 	AttrUseUTF8:        "UseUTF8", | ||||
| 	AttrExtension:      "Extension", | ||||
| 	AttrRanges:         "Ranges", | ||||
| 	AttrTrampoline:     "Trampoline", | ||||
| 	AttrCallColumn:     "CallColumn", | ||||
| 	AttrCallFile:       "CallFile", | ||||
| 	AttrCallLine:       "CallLine", | ||||
| 	AttrDescription:    "Description", | ||||
| } | ||||
|  | ||||
| func (a Attr) String() string { | ||||
| 	if int(a) < len(attrNames) { | ||||
| 		s := attrNames[a] | ||||
| 		if s != "" { | ||||
| 			return s | ||||
| 		} | ||||
| 	} | ||||
| 	switch a { | ||||
| 	case AttrGoKind: | ||||
| 		return "GoKind" | ||||
| 	case AttrGoKey: | ||||
| 		return "GoKey" | ||||
| 	case AttrGoElem: | ||||
| 		return "GoElem" | ||||
| 	} | ||||
| 	return strconv.Itoa(int(a)) | ||||
| } | ||||
|  | ||||
| func (a Attr) GoString() string { | ||||
| 	if int(a) < len(attrNames) { | ||||
| 		s := attrNames[a] | ||||
| 		if s != "" { | ||||
| 			return "dwarf.Attr" + s | ||||
| 		} | ||||
| 	} | ||||
| 	return "dwarf.Attr(" + strconv.FormatInt(int64(a), 10) + ")" | ||||
| } | ||||
|  | ||||
| // A format is a DWARF data encoding format. | ||||
| type format uint32 | ||||
|  | ||||
| const ( | ||||
| 	// value formats | ||||
| 	formAddr        format = 0x01 | ||||
| 	formDwarfBlock2 format = 0x03 | ||||
| 	formDwarfBlock4 format = 0x04 | ||||
| 	formData2       format = 0x05 | ||||
| 	formData4       format = 0x06 | ||||
| 	formData8       format = 0x07 | ||||
| 	formString      format = 0x08 | ||||
| 	formDwarfBlock  format = 0x09 | ||||
| 	formDwarfBlock1 format = 0x0A | ||||
| 	formData1       format = 0x0B | ||||
| 	formFlag        format = 0x0C | ||||
| 	formSdata       format = 0x0D | ||||
| 	formStrp        format = 0x0E | ||||
| 	formUdata       format = 0x0F | ||||
| 	formRefAddr     format = 0x10 | ||||
| 	formRef1        format = 0x11 | ||||
| 	formRef2        format = 0x12 | ||||
| 	formRef4        format = 0x13 | ||||
| 	formRef8        format = 0x14 | ||||
| 	formRefUdata    format = 0x15 | ||||
| 	formIndirect    format = 0x16 | ||||
| 	// The following are new in DWARF 4. | ||||
| 	formSecOffset   format = 0x17 | ||||
| 	formExprloc     format = 0x18 | ||||
| 	formFlagPresent format = 0x19 | ||||
| 	formRefSig8     format = 0x20 | ||||
| 	// Extensions for multi-file compression (.dwz) | ||||
| 	// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1 | ||||
| 	formGnuRefAlt  format = 0x1f20 | ||||
| 	formGnuStrpAlt format = 0x1f21 | ||||
| ) | ||||
|  | ||||
| // A Tag is the classification (the type) of an Entry. | ||||
| type Tag uint32 | ||||
|  | ||||
| const ( | ||||
| 	TagArrayType              Tag = 0x01 | ||||
| 	TagClassType              Tag = 0x02 | ||||
| 	TagEntryPoint             Tag = 0x03 | ||||
| 	TagEnumerationType        Tag = 0x04 | ||||
| 	TagFormalParameter        Tag = 0x05 | ||||
| 	TagImportedDeclaration    Tag = 0x08 | ||||
| 	TagLabel                  Tag = 0x0A | ||||
| 	TagLexDwarfBlock          Tag = 0x0B | ||||
| 	TagMember                 Tag = 0x0D | ||||
| 	TagPointerType            Tag = 0x0F | ||||
| 	TagReferenceType          Tag = 0x10 | ||||
| 	TagCompileUnit            Tag = 0x11 | ||||
| 	TagStringType             Tag = 0x12 | ||||
| 	TagStructType             Tag = 0x13 | ||||
| 	TagSubroutineType         Tag = 0x15 | ||||
| 	TagTypedef                Tag = 0x16 | ||||
| 	TagUnionType              Tag = 0x17 | ||||
| 	TagUnspecifiedParameters  Tag = 0x18 | ||||
| 	TagVariant                Tag = 0x19 | ||||
| 	TagCommonDwarfBlock       Tag = 0x1A | ||||
| 	TagCommonInclusion        Tag = 0x1B | ||||
| 	TagInheritance            Tag = 0x1C | ||||
| 	TagInlinedSubroutine      Tag = 0x1D | ||||
| 	TagModule                 Tag = 0x1E | ||||
| 	TagPtrToMemberType        Tag = 0x1F | ||||
| 	TagSetType                Tag = 0x20 | ||||
| 	TagSubrangeType           Tag = 0x21 | ||||
| 	TagWithStmt               Tag = 0x22 | ||||
| 	TagAccessDeclaration      Tag = 0x23 | ||||
| 	TagBaseType               Tag = 0x24 | ||||
| 	TagCatchDwarfBlock        Tag = 0x25 | ||||
| 	TagConstType              Tag = 0x26 | ||||
| 	TagConstant               Tag = 0x27 | ||||
| 	TagEnumerator             Tag = 0x28 | ||||
| 	TagFileType               Tag = 0x29 | ||||
| 	TagFriend                 Tag = 0x2A | ||||
| 	TagNamelist               Tag = 0x2B | ||||
| 	TagNamelistItem           Tag = 0x2C | ||||
| 	TagPackedType             Tag = 0x2D | ||||
| 	TagSubprogram             Tag = 0x2E | ||||
| 	TagTemplateTypeParameter  Tag = 0x2F | ||||
| 	TagTemplateValueParameter Tag = 0x30 | ||||
| 	TagThrownType             Tag = 0x31 | ||||
| 	TagTryDwarfBlock          Tag = 0x32 | ||||
| 	TagVariantPart            Tag = 0x33 | ||||
| 	TagVariable               Tag = 0x34 | ||||
| 	TagVolatileType           Tag = 0x35 | ||||
| 	// The following are new in DWARF 3. | ||||
| 	TagDwarfProcedure  Tag = 0x36 | ||||
| 	TagRestrictType    Tag = 0x37 | ||||
| 	TagInterfaceType   Tag = 0x38 | ||||
| 	TagNamespace       Tag = 0x39 | ||||
| 	TagImportedModule  Tag = 0x3A | ||||
| 	TagUnspecifiedType Tag = 0x3B | ||||
| 	TagPartialUnit     Tag = 0x3C | ||||
| 	TagImportedUnit    Tag = 0x3D | ||||
| 	TagMutableType     Tag = 0x3E // Later removed from DWARF. | ||||
| 	TagCondition       Tag = 0x3F | ||||
| 	TagSharedType      Tag = 0x40 | ||||
| 	// The following are new in DWARF 4. | ||||
| 	TagTypeUnit            Tag = 0x41 | ||||
| 	TagRvalueReferenceType Tag = 0x42 | ||||
| 	TagTemplateAlias       Tag = 0x43 | ||||
| ) | ||||
|  | ||||
| var tagNames = [...]string{ | ||||
| 	TagArrayType:              "ArrayType", | ||||
| 	TagClassType:              "ClassType", | ||||
| 	TagEntryPoint:             "EntryPoint", | ||||
| 	TagEnumerationType:        "EnumerationType", | ||||
| 	TagFormalParameter:        "FormalParameter", | ||||
| 	TagImportedDeclaration:    "ImportedDeclaration", | ||||
| 	TagLabel:                  "Label", | ||||
| 	TagLexDwarfBlock:          "LexDwarfBlock", | ||||
| 	TagMember:                 "Member", | ||||
| 	TagPointerType:            "PointerType", | ||||
| 	TagReferenceType:          "ReferenceType", | ||||
| 	TagCompileUnit:            "CompileUnit", | ||||
| 	TagStringType:             "StringType", | ||||
| 	TagStructType:             "StructType", | ||||
| 	TagSubroutineType:         "SubroutineType", | ||||
| 	TagTypedef:                "Typedef", | ||||
| 	TagUnionType:              "UnionType", | ||||
| 	TagUnspecifiedParameters:  "UnspecifiedParameters", | ||||
| 	TagVariant:                "Variant", | ||||
| 	TagCommonDwarfBlock:       "CommonDwarfBlock", | ||||
| 	TagCommonInclusion:        "CommonInclusion", | ||||
| 	TagInheritance:            "Inheritance", | ||||
| 	TagInlinedSubroutine:      "InlinedSubroutine", | ||||
| 	TagModule:                 "Module", | ||||
| 	TagPtrToMemberType:        "PtrToMemberType", | ||||
| 	TagSetType:                "SetType", | ||||
| 	TagSubrangeType:           "SubrangeType", | ||||
| 	TagWithStmt:               "WithStmt", | ||||
| 	TagAccessDeclaration:      "AccessDeclaration", | ||||
| 	TagBaseType:               "BaseType", | ||||
| 	TagCatchDwarfBlock:        "CatchDwarfBlock", | ||||
| 	TagConstType:              "ConstType", | ||||
| 	TagConstant:               "Constant", | ||||
| 	TagEnumerator:             "Enumerator", | ||||
| 	TagFileType:               "FileType", | ||||
| 	TagFriend:                 "Friend", | ||||
| 	TagNamelist:               "Namelist", | ||||
| 	TagNamelistItem:           "NamelistItem", | ||||
| 	TagPackedType:             "PackedType", | ||||
| 	TagSubprogram:             "Subprogram", | ||||
| 	TagTemplateTypeParameter:  "TemplateTypeParameter", | ||||
| 	TagTemplateValueParameter: "TemplateValueParameter", | ||||
| 	TagThrownType:             "ThrownType", | ||||
| 	TagTryDwarfBlock:          "TryDwarfBlock", | ||||
| 	TagVariantPart:            "VariantPart", | ||||
| 	TagVariable:               "Variable", | ||||
| 	TagVolatileType:           "VolatileType", | ||||
| 	TagDwarfProcedure:         "DwarfProcedure", | ||||
| 	TagRestrictType:           "RestrictType", | ||||
| 	TagInterfaceType:          "InterfaceType", | ||||
| 	TagNamespace:              "Namespace", | ||||
| 	TagImportedModule:         "ImportedModule", | ||||
| 	TagUnspecifiedType:        "UnspecifiedType", | ||||
| 	TagPartialUnit:            "PartialUnit", | ||||
| 	TagImportedUnit:           "ImportedUnit", | ||||
| 	TagMutableType:            "MutableType", | ||||
| 	TagCondition:              "Condition", | ||||
| 	TagSharedType:             "SharedType", | ||||
| 	TagTypeUnit:               "TypeUnit", | ||||
| 	TagRvalueReferenceType:    "RvalueReferenceType", | ||||
| 	TagTemplateAlias:          "TemplateAlias", | ||||
| } | ||||
|  | ||||
| func (t Tag) String() string { | ||||
| 	if int(t) < len(tagNames) { | ||||
| 		s := tagNames[t] | ||||
| 		if s != "" { | ||||
| 			return s | ||||
| 		} | ||||
| 	} | ||||
| 	return strconv.Itoa(int(t)) | ||||
| } | ||||
|  | ||||
| func (t Tag) GoString() string { | ||||
| 	if int(t) < len(tagNames) { | ||||
| 		s := tagNames[t] | ||||
| 		if s != "" { | ||||
| 			return "dwarf.Tag" + s | ||||
| 		} | ||||
| 	} | ||||
| 	return "dwarf.Tag(" + strconv.FormatInt(int64(t), 10) + ")" | ||||
| } | ||||
|  | ||||
| // Location expression operators. | ||||
| // The debug info encodes value locations like 8(R3) | ||||
| // as a sequence of these op codes. | ||||
| // This package does not implement full expressions; | ||||
| // the opPlusUconst operator is expected by the type parser. | ||||
| const ( | ||||
| 	opAddr       = 0x03 /* 1 op, const addr */ | ||||
| 	opDeref      = 0x06 | ||||
| 	opConst1u    = 0x08 /* 1 op, 1 byte const */ | ||||
| 	opConst1s    = 0x09 /*	" signed */ | ||||
| 	opConst2u    = 0x0A /* 1 op, 2 byte const  */ | ||||
| 	opConst2s    = 0x0B /*	" signed */ | ||||
| 	opConst4u    = 0x0C /* 1 op, 4 byte const */ | ||||
| 	opConst4s    = 0x0D /*	" signed */ | ||||
| 	opConst8u    = 0x0E /* 1 op, 8 byte const */ | ||||
| 	opConst8s    = 0x0F /*	" signed */ | ||||
| 	opConstu     = 0x10 /* 1 op, LEB128 const */ | ||||
| 	opConsts     = 0x11 /*	" signed */ | ||||
| 	opDup        = 0x12 | ||||
| 	opDrop       = 0x13 | ||||
| 	opOver       = 0x14 | ||||
| 	opPick       = 0x15 /* 1 op, 1 byte stack index */ | ||||
| 	opSwap       = 0x16 | ||||
| 	opRot        = 0x17 | ||||
| 	opXderef     = 0x18 | ||||
| 	opAbs        = 0x19 | ||||
| 	opAnd        = 0x1A | ||||
| 	opDiv        = 0x1B | ||||
| 	opMinus      = 0x1C | ||||
| 	opMod        = 0x1D | ||||
| 	opMul        = 0x1E | ||||
| 	opNeg        = 0x1F | ||||
| 	opNot        = 0x20 | ||||
| 	opOr         = 0x21 | ||||
| 	opPlus       = 0x22 | ||||
| 	opPlusUconst = 0x23 /* 1 op, ULEB128 addend */ | ||||
| 	opShl        = 0x24 | ||||
| 	opShr        = 0x25 | ||||
| 	opShra       = 0x26 | ||||
| 	opXor        = 0x27 | ||||
| 	opSkip       = 0x2F /* 1 op, signed 2-byte constant */ | ||||
| 	opBra        = 0x28 /* 1 op, signed 2-byte constant */ | ||||
| 	opEq         = 0x29 | ||||
| 	opGe         = 0x2A | ||||
| 	opGt         = 0x2B | ||||
| 	opLe         = 0x2C | ||||
| 	opLt         = 0x2D | ||||
| 	opNe         = 0x2E | ||||
| 	opLit0       = 0x30 | ||||
| 	/* OpLitN = OpLit0 + N for N = 0..31 */ | ||||
| 	opReg0 = 0x50 | ||||
| 	/* OpRegN = OpReg0 + N for N = 0..31 */ | ||||
| 	opBreg0 = 0x70 /* 1 op, signed LEB128 constant */ | ||||
| 	/* OpBregN = OpBreg0 + N for N = 0..31 */ | ||||
| 	opRegx       = 0x90 /* 1 op, ULEB128 register */ | ||||
| 	opFbreg      = 0x91 /* 1 op, SLEB128 offset */ | ||||
| 	opBregx      = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */ | ||||
| 	opPiece      = 0x93 /* 1 op, ULEB128 size of piece */ | ||||
| 	opDerefSize  = 0x94 /* 1-byte size of data retrieved */ | ||||
| 	opXderefSize = 0x95 /* 1-byte size of data retrieved */ | ||||
| 	opNop        = 0x96 | ||||
| 	/* next four new in Dwarf v3 */ | ||||
| 	opPushObjAddr = 0x97 | ||||
| 	opCall2       = 0x98 /* 2-byte offset of DIE */ | ||||
| 	opCall4       = 0x99 /* 4-byte offset of DIE */ | ||||
| 	opCallRef     = 0x9A /* 4- or 8- byte offset of DIE */ | ||||
| 	/* 0xE0-0xFF reserved for user-specific */ | ||||
| ) | ||||
|  | ||||
| // Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry. | ||||
| const ( | ||||
| 	encAddress        = 0x01 | ||||
| 	encBoolean        = 0x02 | ||||
| 	encComplexFloat   = 0x03 | ||||
| 	encFloat          = 0x04 | ||||
| 	encSigned         = 0x05 | ||||
| 	encSignedChar     = 0x06 | ||||
| 	encUnsigned       = 0x07 | ||||
| 	encUnsignedChar   = 0x08 | ||||
| 	encImaginaryFloat = 0x09 | ||||
| ) | ||||
							
								
								
									
										407
									
								
								vendor/golang.org/x/debug/dwarf/entry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								vendor/golang.org/x/debug/dwarf/entry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,407 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // DWARF debug information entry parser. | ||||
| // An entry is a sequence of data items of a given format. | ||||
| // The first word in the entry is an index into what DWARF | ||||
| // calls the ``abbreviation table.''  An abbreviation is really | ||||
| // just a type descriptor: it's an array of attribute tag/value format pairs. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // a single entry's description: a sequence of attributes | ||||
| type abbrev struct { | ||||
| 	tag      Tag | ||||
| 	children bool | ||||
| 	field    []afield | ||||
| } | ||||
|  | ||||
| type afield struct { | ||||
| 	attr Attr | ||||
| 	fmt  format | ||||
| } | ||||
|  | ||||
| // a map from entry format ids to their descriptions | ||||
| type abbrevTable map[uint32]abbrev | ||||
|  | ||||
| // ParseAbbrev returns the abbreviation table that starts at byte off | ||||
| // in the .debug_abbrev section. | ||||
| func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) { | ||||
| 	if m, ok := d.abbrevCache[off]; ok { | ||||
| 		return m, nil | ||||
| 	} | ||||
|  | ||||
| 	data := d.abbrev | ||||
| 	if off > uint32(len(data)) { | ||||
| 		data = nil | ||||
| 	} else { | ||||
| 		data = data[off:] | ||||
| 	} | ||||
| 	b := makeBuf(d, unknownFormat{}, "abbrev", 0, data) | ||||
|  | ||||
| 	// Error handling is simplified by the buf getters | ||||
| 	// returning an endless stream of 0s after an error. | ||||
| 	m := make(abbrevTable) | ||||
| 	for { | ||||
| 		// Table ends with id == 0. | ||||
| 		id := uint32(b.uint()) | ||||
| 		if id == 0 { | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		// Walk over attributes, counting. | ||||
| 		n := 0 | ||||
| 		b1 := b // Read from copy of b. | ||||
| 		b1.uint() | ||||
| 		b1.uint8() | ||||
| 		for { | ||||
| 			tag := b1.uint() | ||||
| 			fmt := b1.uint() | ||||
| 			if tag == 0 && fmt == 0 { | ||||
| 				break | ||||
| 			} | ||||
| 			n++ | ||||
| 		} | ||||
| 		if b1.err != nil { | ||||
| 			return nil, b1.err | ||||
| 		} | ||||
|  | ||||
| 		// Walk over attributes again, this time writing them down. | ||||
| 		var a abbrev | ||||
| 		a.tag = Tag(b.uint()) | ||||
| 		a.children = b.uint8() != 0 | ||||
| 		a.field = make([]afield, n) | ||||
| 		for i := range a.field { | ||||
| 			a.field[i].attr = Attr(b.uint()) | ||||
| 			a.field[i].fmt = format(b.uint()) | ||||
| 		} | ||||
| 		b.uint() | ||||
| 		b.uint() | ||||
|  | ||||
| 		m[id] = a | ||||
| 	} | ||||
| 	if b.err != nil { | ||||
| 		return nil, b.err | ||||
| 	} | ||||
| 	d.abbrevCache[off] = m | ||||
| 	return m, nil | ||||
| } | ||||
|  | ||||
| // An entry is a sequence of attribute/value pairs. | ||||
| type Entry struct { | ||||
| 	Offset   Offset // offset of Entry in DWARF info | ||||
| 	Tag      Tag    // tag (kind of Entry) | ||||
| 	Children bool   // whether Entry is followed by children | ||||
| 	Field    []Field | ||||
| } | ||||
|  | ||||
| // A Field is a single attribute/value pair in an Entry. | ||||
| type Field struct { | ||||
| 	Attr Attr | ||||
| 	Val  interface{} | ||||
| } | ||||
|  | ||||
| // Val returns the value associated with attribute Attr in Entry, | ||||
| // or nil if there is no such attribute. | ||||
| // | ||||
| // A common idiom is to merge the check for nil return with | ||||
| // the check that the value has the expected dynamic type, as in: | ||||
| //	v, ok := e.Val(AttrSibling).(int64); | ||||
| // | ||||
| func (e *Entry) Val(a Attr) interface{} { | ||||
| 	for _, f := range e.Field { | ||||
| 		if f.Attr == a { | ||||
| 			return f.Val | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // An Offset represents the location of an Entry within the DWARF info. | ||||
| // (See Reader.Seek.) | ||||
| type Offset uint32 | ||||
|  | ||||
| // Entry reads a single entry from buf, decoding | ||||
| // according to the given abbreviation table. | ||||
| func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { | ||||
| 	off := b.off | ||||
| 	id := uint32(b.uint()) | ||||
| 	if id == 0 { | ||||
| 		return &Entry{} | ||||
| 	} | ||||
| 	a, ok := atab[id] | ||||
| 	if !ok { | ||||
| 		b.error("unknown abbreviation table index") | ||||
| 		return nil | ||||
| 	} | ||||
| 	e := &Entry{ | ||||
| 		Offset:   off, | ||||
| 		Tag:      a.tag, | ||||
| 		Children: a.children, | ||||
| 		Field:    make([]Field, len(a.field)), | ||||
| 	} | ||||
| 	for i := range e.Field { | ||||
| 		e.Field[i].Attr = a.field[i].attr | ||||
| 		fmt := a.field[i].fmt | ||||
| 		if fmt == formIndirect { | ||||
| 			fmt = format(b.uint()) | ||||
| 		} | ||||
| 		var val interface{} | ||||
| 		switch fmt { | ||||
| 		default: | ||||
| 			b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16)) | ||||
|  | ||||
| 		// address | ||||
| 		case formAddr: | ||||
| 			val = b.addr() | ||||
|  | ||||
| 		// block | ||||
| 		case formDwarfBlock1: | ||||
| 			val = b.bytes(int(b.uint8())) | ||||
| 		case formDwarfBlock2: | ||||
| 			val = b.bytes(int(b.uint16())) | ||||
| 		case formDwarfBlock4: | ||||
| 			val = b.bytes(int(b.uint32())) | ||||
| 		case formDwarfBlock: | ||||
| 			val = b.bytes(int(b.uint())) | ||||
|  | ||||
| 		// constant | ||||
| 		case formData1: | ||||
| 			val = int64(b.uint8()) | ||||
| 		case formData2: | ||||
| 			val = int64(b.uint16()) | ||||
| 		case formData4: | ||||
| 			val = int64(b.uint32()) | ||||
| 		case formData8: | ||||
| 			val = int64(b.uint64()) | ||||
| 		case formSdata: | ||||
| 			val = int64(b.int()) | ||||
| 		case formUdata: | ||||
| 			val = int64(b.uint()) | ||||
|  | ||||
| 		// flag | ||||
| 		case formFlag: | ||||
| 			val = b.uint8() == 1 | ||||
| 		// New in DWARF 4. | ||||
| 		case formFlagPresent: | ||||
| 			// The attribute is implicitly indicated as present, and no value is | ||||
| 			// encoded in the debugging information entry itself. | ||||
| 			val = true | ||||
|  | ||||
| 		// reference to other entry | ||||
| 		case formRefAddr: | ||||
| 			vers := b.format.version() | ||||
| 			if vers == 0 { | ||||
| 				b.error("unknown version for DW_FORM_ref_addr") | ||||
| 			} else if vers == 2 { | ||||
| 				val = Offset(b.addr()) | ||||
| 			} else { | ||||
| 				is64, known := b.format.dwarf64() | ||||
| 				if !known { | ||||
| 					b.error("unknown size for DW_FORM_ref_addr") | ||||
| 				} else if is64 { | ||||
| 					val = Offset(b.uint64()) | ||||
| 				} else { | ||||
| 					val = Offset(b.uint32()) | ||||
| 				} | ||||
| 			} | ||||
| 		case formRef1: | ||||
| 			val = Offset(b.uint8()) + ubase | ||||
| 		case formRef2: | ||||
| 			val = Offset(b.uint16()) + ubase | ||||
| 		case formRef4: | ||||
| 			val = Offset(b.uint32()) + ubase | ||||
| 		case formRef8: | ||||
| 			val = Offset(b.uint64()) + ubase | ||||
| 		case formRefUdata: | ||||
| 			val = Offset(b.uint()) + ubase | ||||
|  | ||||
| 		// string | ||||
| 		case formString: | ||||
| 			val = b.string() | ||||
| 		case formStrp: | ||||
| 			off := b.uint32() // offset into .debug_str | ||||
| 			if b.err != nil { | ||||
| 				return nil | ||||
| 			} | ||||
| 			b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str) | ||||
| 			b1.skip(int(off)) | ||||
| 			val = b1.string() | ||||
| 			if b1.err != nil { | ||||
| 				b.err = b1.err | ||||
| 				return nil | ||||
| 			} | ||||
|  | ||||
| 		// lineptr, loclistptr, macptr, rangelistptr | ||||
| 		// New in DWARF 4, but clang can generate them with -gdwarf-2. | ||||
| 		// Section reference, replacing use of formData4 and formData8. | ||||
| 		case formSecOffset, formGnuRefAlt, formGnuStrpAlt: | ||||
| 			is64, known := b.format.dwarf64() | ||||
| 			if !known { | ||||
| 				b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16)) | ||||
| 			} else if is64 { | ||||
| 				val = int64(b.uint64()) | ||||
| 			} else { | ||||
| 				val = int64(b.uint32()) | ||||
| 			} | ||||
|  | ||||
| 		// exprloc | ||||
| 		// New in DWARF 4. | ||||
| 		case formExprloc: | ||||
| 			val = b.bytes(int(b.uint())) | ||||
|  | ||||
| 		// reference | ||||
| 		// New in DWARF 4. | ||||
| 		case formRefSig8: | ||||
| 			// 64-bit type signature. | ||||
| 			val = b.uint64() | ||||
| 		} | ||||
| 		e.Field[i].Val = val | ||||
| 	} | ||||
| 	if b.err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return e | ||||
| } | ||||
|  | ||||
| // A Reader allows reading Entry structures from a DWARF ``info'' section. | ||||
| // The Entry structures are arranged in a tree.  The Reader's Next function | ||||
| // return successive entries from a pre-order traversal of the tree. | ||||
| // If an entry has children, its Children field will be true, and the children | ||||
| // follow, terminated by an Entry with Tag 0. | ||||
| type Reader struct { | ||||
| 	b            buf | ||||
| 	d            *Data | ||||
| 	err          error | ||||
| 	unit         int | ||||
| 	lastChildren bool   // .Children of last entry returned by Next | ||||
| 	lastSibling  Offset // .Val(AttrSibling) of last entry returned by Next | ||||
| } | ||||
|  | ||||
| // Reader returns a new Reader for Data. | ||||
| // The reader is positioned at byte offset 0 in the DWARF ``info'' section. | ||||
| func (d *Data) Reader() *Reader { | ||||
| 	r := &Reader{d: d} | ||||
| 	r.Seek(0) | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // AddressSize returns the size in bytes of addresses in the current compilation | ||||
| // unit. | ||||
| func (r *Reader) AddressSize() int { | ||||
| 	return r.d.unit[r.unit].asize | ||||
| } | ||||
|  | ||||
| // Seek positions the Reader at offset off in the encoded entry stream. | ||||
| // Offset 0 can be used to denote the first entry. | ||||
| func (r *Reader) Seek(off Offset) { | ||||
| 	d := r.d | ||||
| 	r.err = nil | ||||
| 	r.lastChildren = false | ||||
| 	if off == 0 { | ||||
| 		if len(d.unit) == 0 { | ||||
| 			return | ||||
| 		} | ||||
| 		u := &d.unit[0] | ||||
| 		r.unit = 0 | ||||
| 		r.b = makeBuf(r.d, u, "info", u.off, u.data) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// TODO(rsc): binary search (maybe a new package) | ||||
| 	var i int | ||||
| 	var u *unit | ||||
| 	for i = range d.unit { | ||||
| 		u = &d.unit[i] | ||||
| 		if u.off <= off && off < u.off+Offset(len(u.data)) { | ||||
| 			r.unit = i | ||||
| 			r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:]) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	r.err = errors.New("offset out of range") | ||||
| } | ||||
|  | ||||
| // maybeNextUnit advances to the next unit if this one is finished. | ||||
| func (r *Reader) maybeNextUnit() { | ||||
| 	for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) { | ||||
| 		r.unit++ | ||||
| 		u := &r.d.unit[r.unit] | ||||
| 		r.b = makeBuf(r.d, u, "info", u.off, u.data) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Next reads the next entry from the encoded entry stream. | ||||
| // It returns nil, nil when it reaches the end of the section. | ||||
| // It returns an error if the current offset is invalid or the data at the | ||||
| // offset cannot be decoded as a valid Entry. | ||||
| func (r *Reader) Next() (*Entry, error) { | ||||
| 	if r.err != nil { | ||||
| 		return nil, r.err | ||||
| 	} | ||||
| 	r.maybeNextUnit() | ||||
| 	if len(r.b.data) == 0 { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 	u := &r.d.unit[r.unit] | ||||
| 	e := r.b.entry(u.atable, u.base) | ||||
| 	if r.b.err != nil { | ||||
| 		r.err = r.b.err | ||||
| 		return nil, r.err | ||||
| 	} | ||||
| 	if e != nil { | ||||
| 		r.lastChildren = e.Children | ||||
| 		if r.lastChildren { | ||||
| 			r.lastSibling, _ = e.Val(AttrSibling).(Offset) | ||||
| 		} | ||||
| 	} else { | ||||
| 		r.lastChildren = false | ||||
| 	} | ||||
| 	return e, nil | ||||
| } | ||||
|  | ||||
| // SkipChildren skips over the child entries associated with | ||||
| // the last Entry returned by Next.  If that Entry did not have | ||||
| // children or Next has not been called, SkipChildren is a no-op. | ||||
| func (r *Reader) SkipChildren() { | ||||
| 	if r.err != nil || !r.lastChildren { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// If the last entry had a sibling attribute, | ||||
| 	// that attribute gives the offset of the next | ||||
| 	// sibling, so we can avoid decoding the | ||||
| 	// child subtrees. | ||||
| 	if r.lastSibling >= r.b.off { | ||||
| 		r.Seek(r.lastSibling) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		e, err := r.Next() | ||||
| 		if err != nil || e == nil || e.Tag == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 		if e.Children { | ||||
| 			r.SkipChildren() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // clone returns a copy of the reader.  This is used by the typeReader | ||||
| // interface. | ||||
| func (r *Reader) clone() typeReader { | ||||
| 	return r.d.Reader() | ||||
| } | ||||
|  | ||||
| // offset returns the current buffer offset.  This is used by the | ||||
| // typeReader interface. | ||||
| func (r *Reader) offset() Offset { | ||||
| 	return r.b.off | ||||
| } | ||||
							
								
								
									
										299
									
								
								vendor/golang.org/x/debug/dwarf/frame.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								vendor/golang.org/x/debug/dwarf/frame.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,299 @@ | ||||
| // Copyright 2014 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Mapping from PC to SP offset (called CFA - Canonical Frame Address - in DWARF). | ||||
| // This value is the offset from the stack pointer to the virtual frame pointer | ||||
| // (address of zeroth argument) at each PC value in the program. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| // http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.4 page 126 | ||||
| // We implement only the CFA column of the table, not the location | ||||
| // information about other registers. In other words, we implement | ||||
| // only what we need to understand Go programs compiled by gc. | ||||
|  | ||||
| // PCToSPOffset returns the offset, at the specified PC, to add to the | ||||
| // SP to reach the virtual frame pointer, which corresponds to the | ||||
| // address of the zeroth argument of the function, the word on the | ||||
| // stack immediately above the return PC. | ||||
| func (d *Data) PCToSPOffset(pc uint64) (offset int64, err error) { | ||||
| 	if len(d.frame) == 0 { | ||||
| 		return 0, fmt.Errorf("PCToSPOffset: no frame table") | ||||
| 	} | ||||
| 	var m frameMachine | ||||
| 	// Assume the first info unit is the same as us. Extremely likely. TODO? | ||||
| 	if len(d.unit) == 0 { | ||||
| 		return 0, fmt.Errorf("PCToSPOffset: no info section") | ||||
| 	} | ||||
| 	buf := makeBuf(d, &d.unit[0], "frame", 0, d.frame) | ||||
| 	for len(buf.data) > 0 { | ||||
| 		offset, err := m.evalCompilationUnit(&buf, pc) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 		return offset, nil | ||||
| 	} | ||||
| 	return 0, fmt.Errorf("PCToSPOffset: no frame defined for PC %#x", pc) | ||||
| } | ||||
|  | ||||
| // Call Frame instructions. Figure 40, page 181. | ||||
| // Structure is high two bits plus low 6 bits specified by + in comment. | ||||
| // Some take one or two operands. | ||||
| const ( | ||||
| 	frameNop              = 0<<6 + 0x00 | ||||
| 	frameAdvanceLoc       = 1<<6 + 0x00 // + delta | ||||
| 	frameOffset           = 2<<6 + 0x00 // + register op: ULEB128 offset | ||||
| 	frameRestore          = 3<<6 + 0x00 // + register | ||||
| 	frameSetLoc           = 0<<6 + 0x01 // op: address | ||||
| 	frameAdvanceLoc1      = 0<<6 + 0x02 // op: 1-byte delta | ||||
| 	frameAdvanceLoc2      = 0<<6 + 0x03 // op: 2-byte delta | ||||
| 	frameAdvanceLoc4      = 0<<6 + 0x04 // op: 4-byte delta | ||||
| 	frameOffsetExtended   = 0<<6 + 0x05 // ops: ULEB128 register ULEB128 offset | ||||
| 	frameRestoreExtended  = 0<<6 + 0x06 // op: ULEB128 register | ||||
| 	frameUndefined        = 0<<6 + 0x07 // op: ULEB128 register | ||||
| 	frameSameValue        = 0<<6 + 0x08 // op: ULEB128 register | ||||
| 	frameRegister         = 0<<6 + 0x09 // op: ULEB128 register ULEB128 register | ||||
| 	frameRememberState    = 0<<6 + 0x0a | ||||
| 	frameRestoreState     = 0<<6 + 0x0b | ||||
| 	frameDefCFA           = 0<<6 + 0x0c // op: ULEB128 register ULEB128 offset | ||||
| 	frameDefCFARegister   = 0<<6 + 0x0d // op: ULEB128 register | ||||
| 	frameDefCFAOffset     = 0<<6 + 0x0e // op: ULEB128 offset | ||||
| 	frameDefCFAExpression = 0<<6 + 0x0f // op: BLOCK | ||||
| 	frameExpression       = 0<<6 + 0x10 // op: ULEB128 register BLOCK | ||||
| 	frameOffsetExtendedSf = 0<<6 + 0x11 // op: ULEB128 register SLEB128 offset | ||||
| 	frameDefCFASf         = 0<<6 + 0x12 // op: ULEB128 register SLEB128 offset | ||||
| 	frameDefCFAOffsetSf   = 0<<6 + 0x13 // op: SLEB128 offset | ||||
| 	frameValOffset        = 0<<6 + 0x14 // op: ULEB128 ULEB128 | ||||
| 	frameValOffsetSf      = 0<<6 + 0x15 // op: ULEB128 SLEB128 | ||||
| 	frameValExpression    = 0<<6 + 0x16 // op: ULEB128 BLOCK | ||||
| 	frameLoUser           = 0<<6 + 0x1c | ||||
| 	frameHiUser           = 0<<6 + 0x3f | ||||
| ) | ||||
|  | ||||
| // frameMachine represents the PC/SP engine. | ||||
| // Section 6.4, page 129. | ||||
| type frameMachine struct { | ||||
| 	// Initial values from CIE. | ||||
| 	version               uint8  // Version number, "independent of DWARF version" | ||||
| 	augmentation          string // Augmentation; treated as unexpected for now. TODO. | ||||
| 	addressSize           uint8  // In DWARF v4 and above. Size of a target address. | ||||
| 	segmentSize           uint8  // In DWARF v4 and above. Size of a segment selector. | ||||
| 	codeAlignmentFactor   uint64 // Unit of code size in advance instructions. | ||||
| 	dataAlignmentFactor   int64  // Unit of data size in certain offset instructions. | ||||
| 	returnAddressRegister int    // Pseudo-register (actually data column) representing return address. | ||||
| 	returnRegisterOffset  int64  // Offset to saved PC from CFA in bytes. | ||||
| 	// CFA definition. | ||||
| 	cfaRegister int   // Which register represents the SP. | ||||
| 	cfaOffset   int64 // CFA offset value. | ||||
| 	// Running machine. | ||||
| 	location uint64 | ||||
| } | ||||
|  | ||||
| // evalCompilationUnit scans the frame data for one compilation unit to retrieve | ||||
| // the offset information for the specified pc. | ||||
| func (m *frameMachine) evalCompilationUnit(b *buf, pc uint64) (int64, error) { | ||||
| 	err := m.parseCIE(b) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	for { | ||||
| 		offset, found, err := m.scanFDE(b, pc) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 		if found { | ||||
| 			return offset, nil | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // parseCIE assumes the incoming buffer starts with a CIE block and parses it | ||||
| // to initialize a frameMachine. | ||||
| func (m *frameMachine) parseCIE(allBuf *buf) error { | ||||
| 	length := int(allBuf.uint32()) | ||||
| 	if len(allBuf.data) < length { | ||||
| 		return fmt.Errorf("CIE parse error: too short") | ||||
| 	} | ||||
| 	// Create buffer for just this section. | ||||
| 	b := allBuf.slice(length) | ||||
| 	cie := b.uint32() | ||||
| 	if cie != 0xFFFFFFFF { | ||||
| 		return fmt.Errorf("CIE parse error: not CIE: %x", cie) | ||||
| 	} | ||||
| 	m.version = b.uint8() | ||||
| 	if m.version != 3 && m.version != 4 { | ||||
| 		return fmt.Errorf("CIE parse error: unsupported version %d", m.version) | ||||
| 	} | ||||
| 	m.augmentation = b.string() | ||||
| 	if len(m.augmentation) > 0 { | ||||
| 		return fmt.Errorf("CIE: can't handled augmentation string %q", m.augmentation) | ||||
| 	} | ||||
| 	if m.version >= 4 { | ||||
| 		m.addressSize = b.uint8() | ||||
| 		m.segmentSize = b.uint8() | ||||
| 	} else { | ||||
| 		// Unused. Gc generates version 3, so these values will not be | ||||
| 		// set, but they are also not used so it's OK. | ||||
| 	} | ||||
| 	m.codeAlignmentFactor = b.uint() | ||||
| 	m.dataAlignmentFactor = b.int() | ||||
| 	m.returnAddressRegister = int(b.uint()) | ||||
|  | ||||
| 	// Initial instructions. At least for Go, establishes SP register number | ||||
| 	// and initial value of CFA offset at start of function. | ||||
| 	_, err := m.run(&b, ^uint64(0)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// There's padding, but we can ignore it. | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // scanFDE assumes the incoming buffer starts with a FDE block and parses it | ||||
| // to run a frameMachine and, if the PC is represented in its range, return | ||||
| // the CFA offset for that PC. The boolean returned reports whether the | ||||
| // PC is in range for this FDE. | ||||
| func (m *frameMachine) scanFDE(allBuf *buf, pc uint64) (int64, bool, error) { | ||||
| 	length := int(allBuf.uint32()) | ||||
| 	if len(allBuf.data) < length { | ||||
| 		return 0, false, fmt.Errorf("FDE parse error: too short") | ||||
| 	} | ||||
| 	if length <= 0 { | ||||
| 		if length == 0 { | ||||
| 			// EOF. | ||||
| 			return 0, false, fmt.Errorf("PC %#x not found in PC/SP table", pc) | ||||
| 		} | ||||
| 		return 0, false, fmt.Errorf("bad FDE length %d", length) | ||||
| 	} | ||||
| 	// Create buffer for just this section. | ||||
| 	b := allBuf.slice(length) | ||||
| 	cieOffset := b.uint32() // TODO assumes 32 bits. | ||||
| 	// Expect 0: first CIE in this segment. TODO. | ||||
| 	if cieOffset != 0 { | ||||
| 		return 0, false, fmt.Errorf("FDE parse error: bad CIE offset: %.2x", cieOffset) | ||||
| 	} | ||||
| 	// Initial location. | ||||
| 	m.location = b.addr() | ||||
| 	addressRange := b.addr() | ||||
| 	// If the PC is not in this function, there's no point in executing the instructions. | ||||
| 	if pc < m.location || m.location+addressRange <= pc { | ||||
| 		return 0, false, nil | ||||
| 	} | ||||
| 	// The PC appears in this FDE. Scan to find the location. | ||||
| 	offset, err := m.run(&b, pc) | ||||
| 	if err != nil { | ||||
| 		return 0, false, err | ||||
| 	} | ||||
|  | ||||
| 	// There's padding, but we can ignore it. | ||||
| 	return offset, true, nil | ||||
| } | ||||
|  | ||||
| // run executes the instructions in the buffer, which has been sliced to contain | ||||
| // only the data for this block. When we run out of data, we return. | ||||
| // Since we are only called when we know the PC is in this block, reaching | ||||
| // EOF is not an error, it just means the final CFA definition matches the | ||||
| // tail of the block that holds the PC. | ||||
| // The return value is the CFA at the end of the block or the PC, whichever | ||||
| // comes first. | ||||
| func (m *frameMachine) run(b *buf, pc uint64) (int64, error) { | ||||
| 	// We run the machine at location == PC because if the PC is at the first | ||||
| 	// instruction of a block, the definition of its offset arrives as an | ||||
| 	// offset-defining operand after the PC is set to that location. | ||||
| 	for m.location <= pc && len(b.data) > 0 { | ||||
| 		op := b.uint8() | ||||
| 		// Ops with embedded operands | ||||
| 		switch op & 0xC0 { | ||||
| 		case frameAdvanceLoc: // (6.4.2.1) | ||||
| 			// delta in low bits | ||||
| 			m.location += uint64(op & 0x3F) | ||||
| 			continue | ||||
| 		case frameOffset: // (6.4.2.3) | ||||
| 			// Register in low bits; ULEB128 offset. | ||||
| 			// For Go binaries we only see this in the CIE for the return address register. | ||||
| 			if int(op&0x3F) != m.returnAddressRegister { | ||||
| 				return 0, fmt.Errorf("invalid frameOffset register R%d should be R%d", op&0x3f, m.returnAddressRegister) | ||||
| 			} | ||||
| 			m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor | ||||
| 			continue | ||||
| 		case frameRestore: // (6.4.2.3) | ||||
| 			// register in low bits | ||||
| 			return 0, fmt.Errorf("unimplemented frameRestore(R%d)\n", op&0x3F) | ||||
| 		} | ||||
|  | ||||
| 		// The remaining ops do not have embedded operands. | ||||
|  | ||||
| 		switch op { | ||||
| 		// Row creation instructions (6.4.2.1) | ||||
| 		case frameNop: | ||||
| 		case frameSetLoc: // op: address | ||||
| 			return 0, fmt.Errorf("unimplemented setloc") // what size is operand? | ||||
| 		case frameAdvanceLoc1: // op: 1-byte delta | ||||
| 			m.location += uint64(b.uint8()) | ||||
| 		case frameAdvanceLoc2: // op: 2-byte delta | ||||
| 			m.location += uint64(b.uint16()) | ||||
| 		case frameAdvanceLoc4: // op: 4-byte delta | ||||
| 			m.location += uint64(b.uint32()) | ||||
|  | ||||
| 		// CFA definition instructions (6.4.2.2) | ||||
| 		case frameDefCFA: // op: ULEB128 register ULEB128 offset | ||||
| 			m.cfaRegister = int(b.int()) | ||||
| 			m.cfaOffset = int64(b.uint()) | ||||
| 		case frameDefCFASf: // op: ULEB128 register SLEB128 offset | ||||
| 			return 0, fmt.Errorf("unimplemented frameDefCFASf") | ||||
| 		case frameDefCFARegister: // op: ULEB128 register | ||||
| 			return 0, fmt.Errorf("unimplemented frameDefCFARegister") | ||||
| 		case frameDefCFAOffset: // op: ULEB128 offset | ||||
| 			return 0, fmt.Errorf("unimplemented frameDefCFAOffset") | ||||
| 		case frameDefCFAOffsetSf: // op: SLEB128 offset | ||||
| 			offset := b.int() | ||||
| 			m.cfaOffset = offset * m.dataAlignmentFactor | ||||
| 			// TODO: Verify we are using a factored offset. | ||||
| 		case frameDefCFAExpression: // op: BLOCK | ||||
| 			return 0, fmt.Errorf("unimplemented frameDefCFAExpression") | ||||
|  | ||||
| 		// Register Rule instructions (6.4.2.3) | ||||
| 		case frameOffsetExtended: // ops: ULEB128 register ULEB128 offset | ||||
| 			// The same as frameOffset, but with the register specified in an operand. | ||||
| 			reg := b.uint() | ||||
| 			// For Go binaries we only see this in the CIE for the return address register. | ||||
| 			if reg != uint64(m.returnAddressRegister) { | ||||
| 				return 0, fmt.Errorf("invalid frameOffsetExtended: register R%d should be R%d", reg, m.returnAddressRegister) | ||||
| 			} | ||||
| 			m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor | ||||
| 		case frameRestoreExtended: // op: ULEB128 register | ||||
| 			return 0, fmt.Errorf("unimplemented frameRestoreExtended") | ||||
| 		case frameUndefined: // op: ULEB128 register; unimplemented | ||||
| 			return 0, fmt.Errorf("unimplemented frameUndefined") | ||||
| 		case frameSameValue: // op: ULEB128 register | ||||
| 			return 0, fmt.Errorf("unimplemented frameSameValue") | ||||
| 		case frameRegister: // op: ULEB128 register ULEB128 register | ||||
| 			return 0, fmt.Errorf("unimplemented frameRegister") | ||||
| 		case frameRememberState: | ||||
| 			return 0, fmt.Errorf("unimplemented frameRememberState") | ||||
| 		case frameRestoreState: | ||||
| 			return 0, fmt.Errorf("unimplemented frameRestoreState") | ||||
| 		case frameExpression: // op: ULEB128 register BLOCK | ||||
| 			return 0, fmt.Errorf("unimplemented frameExpression") | ||||
| 		case frameOffsetExtendedSf: // op: ULEB128 register SLEB128 offset | ||||
| 			return 0, fmt.Errorf("unimplemented frameOffsetExtended_sf") | ||||
| 		case frameValOffset: // op: ULEB128 ULEB128 | ||||
| 			return 0, fmt.Errorf("unimplemented frameValOffset") | ||||
| 		case frameValOffsetSf: // op: ULEB128 SLEB128 | ||||
| 			return 0, fmt.Errorf("unimplemented frameValOffsetSf") | ||||
| 		case frameValExpression: // op: ULEB128 BLOCK | ||||
| 			return 0, fmt.Errorf("unimplemented frameValExpression") | ||||
|  | ||||
| 		default: | ||||
| 			if frameLoUser <= op && op <= frameHiUser { | ||||
| 				return 0, fmt.Errorf("unknown user-defined frame op %#x", op) | ||||
| 			} | ||||
| 			return 0, fmt.Errorf("unknown frame op %#x", op) | ||||
| 		} | ||||
| 	} | ||||
| 	return m.cfaOffset, nil | ||||
| } | ||||
							
								
								
									
										448
									
								
								vendor/golang.org/x/debug/dwarf/line.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										448
									
								
								vendor/golang.org/x/debug/dwarf/line.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,448 @@ | ||||
| // Copyright 2014 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| // This file implements the mapping from PC to lines. | ||||
| // TODO: Find a way to test this properly. | ||||
|  | ||||
| // http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.2 page 108 | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // PCToLine returns the file and line number corresponding to the PC value. | ||||
| // It returns an error if a correspondence cannot be found. | ||||
| func (d *Data) PCToLine(pc uint64) (file string, line uint64, err error) { | ||||
| 	c := d.pcToLineEntries | ||||
| 	if len(c) == 0 { | ||||
| 		return "", 0, fmt.Errorf("PCToLine: no line table") | ||||
| 	} | ||||
| 	i := sort.Search(len(c), func(i int) bool { return c[i].pc > pc }) - 1 | ||||
| 	// c[i] is now the entry in pcToLineEntries with the largest pc that is not | ||||
| 	// larger than the query pc. | ||||
| 	// The search has failed if: | ||||
| 	// - All pcs in c were larger than the query pc (i == -1). | ||||
| 	// - c[i] marked the end of a sequence of instructions (c[i].file == 0). | ||||
| 	// - c[i] is the last element of c, and isn't the end of a sequence of | ||||
| 	//   instructions, and the search pc is much larger than c[i].pc.  In this | ||||
| 	//   case, we don't know the range of the last instruction, but the search | ||||
| 	//   pc is probably past it. | ||||
| 	if i == -1 || c[i].file == 0 || (i+1 == len(c) && pc-c[i].pc > 1024) { | ||||
| 		return "", 0, fmt.Errorf("no source line defined for PC %#x", pc) | ||||
| 	} | ||||
| 	if c[i].file >= uint64(len(d.sourceFiles)) { | ||||
| 		return "", 0, fmt.Errorf("invalid file number in DWARF data") | ||||
| 	} | ||||
| 	return d.sourceFiles[c[i].file], c[i].line, nil | ||||
| } | ||||
|  | ||||
| // LineToBreakpointPCs returns the PCs that should be used as breakpoints | ||||
| // corresponding to the given file and line number. | ||||
| // It returns an empty slice if no PCs were found. | ||||
| func (d *Data) LineToBreakpointPCs(file string, line uint64) ([]uint64, error) { | ||||
| 	compDir := d.compilationDirectory() | ||||
|  | ||||
| 	// Find the closest match in the executable for the specified file. | ||||
| 	// We choose the file with the largest number of path components matching | ||||
| 	// at the end of the name. If there is a tie, we prefer files that are | ||||
| 	// under the compilation directory.  If there is still a tie, we choose | ||||
| 	// the file with the shortest name. | ||||
| 	// TODO: handle duplicate file names in the DWARF? | ||||
| 	var bestFile struct { | ||||
| 		fileNum    uint64 // Index of the file in the DWARF data. | ||||
| 		components int    // Number of matching path components. | ||||
| 		length     int    // Length of the filename. | ||||
| 		underComp  bool   // File is under the compilation directory. | ||||
| 	} | ||||
| 	for filenum, filename := range d.sourceFiles { | ||||
| 		c := matchingPathComponentSuffixSize(filename, file) | ||||
| 		underComp := strings.HasPrefix(filename, compDir) | ||||
| 		better := false | ||||
| 		if c != bestFile.components { | ||||
| 			better = c > bestFile.components | ||||
| 		} else if underComp != bestFile.underComp { | ||||
| 			better = underComp | ||||
| 		} else { | ||||
| 			better = len(filename) < bestFile.length | ||||
| 		} | ||||
| 		if better { | ||||
| 			bestFile.fileNum = uint64(filenum) | ||||
| 			bestFile.components = c | ||||
| 			bestFile.length = len(filename) | ||||
| 			bestFile.underComp = underComp | ||||
| 		} | ||||
| 	} | ||||
| 	if bestFile.components == 0 { | ||||
| 		return nil, fmt.Errorf("couldn't find file %q", file) | ||||
| 	} | ||||
|  | ||||
| 	c := d.lineToPCEntries[bestFile.fileNum] | ||||
| 	// c contains all (pc, line) pairs for the appropriate file. | ||||
| 	start := sort.Search(len(c), func(i int) bool { return c[i].line >= line }) | ||||
| 	end := sort.Search(len(c), func(i int) bool { return c[i].line > line }) | ||||
| 	// c[i].line == line for all i in the range [start, end). | ||||
| 	pcs := make([]uint64, 0, end-start) | ||||
| 	for i := start; i < end; i++ { | ||||
| 		pcs = append(pcs, c[i].pc) | ||||
| 	} | ||||
| 	return pcs, nil | ||||
| } | ||||
|  | ||||
| // compilationDirectory finds the first compilation unit entry in d and returns | ||||
| // the compilation directory contained in it. | ||||
| // If it fails, it returns the empty string. | ||||
| func (d *Data) compilationDirectory() string { | ||||
| 	r := d.Reader() | ||||
| 	for { | ||||
| 		entry, err := r.Next() | ||||
| 		if entry == nil || err != nil { | ||||
| 			return "" | ||||
| 		} | ||||
| 		if entry.Tag == TagCompileUnit { | ||||
| 			name, _ := entry.Val(AttrCompDir).(string) | ||||
| 			return name | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // matchingPathComponentSuffixSize returns the largest n such that the last n | ||||
| // components of the paths p1 and p2 are equal. | ||||
| // e.g. matchingPathComponentSuffixSize("a/b/x/y.go", "b/a/x/y.go") returns 2. | ||||
| func matchingPathComponentSuffixSize(p1, p2 string) int { | ||||
| 	// TODO: deal with other path separators. | ||||
| 	c1 := strings.Split(p1, "/") | ||||
| 	c2 := strings.Split(p2, "/") | ||||
| 	min := len(c1) | ||||
| 	if len(c2) < min { | ||||
| 		min = len(c2) | ||||
| 	} | ||||
| 	var n int | ||||
| 	for n = 0; n < min; n++ { | ||||
| 		if c1[len(c1)-1-n] != c2[len(c2)-1-n] { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| // Standard opcodes. Figure 37, page 178. | ||||
| // If an opcode >= lineMachine.prologue.opcodeBase, it is a special | ||||
| // opcode rather than the opcode defined in this table. | ||||
| const ( | ||||
| 	lineStdCopy             = 0x01 | ||||
| 	lineStdAdvancePC        = 0x02 | ||||
| 	lineStdAdvanceLine      = 0x03 | ||||
| 	lineStdSetFile          = 0x04 | ||||
| 	lineStdSetColumn        = 0x05 | ||||
| 	lineStdNegateStmt       = 0x06 | ||||
| 	lineStdSetBasicBlock    = 0x07 | ||||
| 	lineStdConstAddPC       = 0x08 | ||||
| 	lineStdFixedAdvancePC   = 0x09 | ||||
| 	lineStdSetPrologueEnd   = 0x0a | ||||
| 	lineStdSetEpilogueBegin = 0x0b | ||||
| 	lineStdSetISA           = 0x0c | ||||
| ) | ||||
|  | ||||
| // Extended opcodes. Figure 38, page 179. | ||||
| const ( | ||||
| 	lineStartExtendedOpcode = 0x00 // Not defined as a named constant in the spec. | ||||
| 	lineExtEndSequence      = 0x01 | ||||
| 	lineExtSetAddress       = 0x02 | ||||
| 	lineExtDefineFile       = 0x03 | ||||
| 	lineExtSetDiscriminator = 0x04 // New in version 4. | ||||
| 	lineExtLoUser           = 0x80 | ||||
| 	lineExtHiUser           = 0xff | ||||
| ) | ||||
|  | ||||
| // lineHeader holds the information stored in the header of the line table for a | ||||
| // single compilation unit. | ||||
| // Section 6.2.4, page 112. | ||||
| type lineHeader struct { | ||||
| 	unitLength           int | ||||
| 	version              int | ||||
| 	headerLength         int | ||||
| 	minInstructionLength int | ||||
| 	maxOpsPerInstruction int | ||||
| 	defaultIsStmt        bool | ||||
| 	lineBase             int | ||||
| 	lineRange            int | ||||
| 	opcodeBase           byte | ||||
| 	stdOpcodeLengths     []byte | ||||
| 	include              []string   // entry 0 is empty; means current directory | ||||
| 	file                 []lineFile // entry 0 is empty. | ||||
| } | ||||
|  | ||||
| // lineFile represents a file name stored in the PC/line table, usually in the header. | ||||
| type lineFile struct { | ||||
| 	name   string | ||||
| 	index  int // index into include directories | ||||
| 	time   int // implementation-defined time of last modification | ||||
| 	length int // length in bytes, 0 if not available. | ||||
| } | ||||
|  | ||||
| // lineMachine holds the registers evaluated during executing of the PC/line mapping engine. | ||||
| // Section 6.2.2, page 109. | ||||
| type lineMachine struct { | ||||
| 	// The program-counter value corresponding to a machine instruction generated by the compiler. | ||||
| 	address uint64 | ||||
|  | ||||
| 	// An unsigned integer representing the index of an operation within a VLIW | ||||
| 	// instruction. The index of the first operation is 0. For non-VLIW | ||||
| 	// architectures, this register will always be 0. | ||||
| 	// The address and op_index registers, taken together, form an operation | ||||
| 	// pointer that can reference any individual operation with the instruction | ||||
| 	// stream. | ||||
| 	opIndex uint64 | ||||
|  | ||||
| 	// An unsigned integer indicating the identity of the source file corresponding to a machine instruction. | ||||
| 	file uint64 | ||||
|  | ||||
| 	// An unsigned integer indicating a source line number. Lines are numbered | ||||
| 	// beginning at 1. The compiler may emit the value 0 in cases where an | ||||
| 	// instruction cannot be attributed to any source line. | ||||
| 	line uint64 | ||||
|  | ||||
| 	// An unsigned integer indicating a column number within a source line. | ||||
| 	// Columns are numbered beginning at 1. The value 0 is reserved to indicate | ||||
| 	// that a statement begins at the “left edge” of the line. | ||||
| 	column uint64 | ||||
|  | ||||
| 	// A boolean indicating that the current instruction is a recommended | ||||
| 	// breakpoint location. A recommended breakpoint location is intended to | ||||
| 	// “represent” a line, a statement and/or a semantically distinct subpart of a | ||||
| 	// statement. | ||||
| 	isStmt bool | ||||
|  | ||||
| 	// A boolean indicating that the current instruction is the beginning of a basic | ||||
| 	// block. | ||||
| 	basicBlock bool | ||||
|  | ||||
| 	// A boolean indicating that the current address is that of the first byte after | ||||
| 	// the end of a sequence of target machine instructions. end_sequence | ||||
| 	// terminates a sequence of lines; therefore other information in the same | ||||
| 	// row is not meaningful. | ||||
| 	endSequence bool | ||||
|  | ||||
| 	// A boolean indicating that the current address is one (of possibly many) | ||||
| 	// where execution should be suspended for an entry breakpoint of a | ||||
| 	// function. | ||||
| 	prologueEnd bool | ||||
|  | ||||
| 	// A boolean indicating that the current address is one (of possibly many) | ||||
| 	// where execution should be suspended for an exit breakpoint of a function. | ||||
| 	epilogueBegin bool | ||||
|  | ||||
| 	// An unsigned integer whose value encodes the applicable instruction set | ||||
| 	// architecture for the current instruction. | ||||
| 	// The encoding of instruction sets should be shared by all users of a given | ||||
| 	// architecture. It is recommended that this encoding be defined by the ABI | ||||
| 	// authoring committee for each architecture. | ||||
| 	isa uint64 | ||||
|  | ||||
| 	// An unsigned integer identifying the block to which the current instruction | ||||
| 	// belongs. Discriminator values are assigned arbitrarily by the DWARF | ||||
| 	// producer and serve to distinguish among multiple blocks that may all be | ||||
| 	// associated with the same source file, line, and column. Where only one | ||||
| 	// block exists for a given source position, the discriminator value should be | ||||
| 	// zero. | ||||
| 	discriminator uint64 | ||||
|  | ||||
| 	// The header for the current compilation unit. | ||||
| 	// Not an actual register, but stored here for cleanliness. | ||||
| 	header lineHeader | ||||
| } | ||||
|  | ||||
| // parseHeader parses the header describing the compilation unit in the line | ||||
| // table starting at the specified offset. | ||||
| func (m *lineMachine) parseHeader(b *buf) error { | ||||
| 	m.header = lineHeader{} | ||||
| 	m.header.unitLength = int(b.uint32()) // Note: We are assuming 32-bit DWARF format. | ||||
| 	if m.header.unitLength > len(b.data) { | ||||
| 		return fmt.Errorf("DWARF: bad PC/line header length") | ||||
| 	} | ||||
| 	m.header.version = int(b.uint16()) | ||||
| 	m.header.headerLength = int(b.uint32()) | ||||
| 	m.header.minInstructionLength = int(b.uint8()) | ||||
| 	if m.header.version >= 4 { | ||||
| 		m.header.maxOpsPerInstruction = int(b.uint8()) | ||||
| 	} else { | ||||
| 		m.header.maxOpsPerInstruction = 1 | ||||
| 	} | ||||
| 	m.header.defaultIsStmt = b.uint8() != 0 | ||||
| 	m.header.lineBase = int(int8(b.uint8())) | ||||
| 	m.header.lineRange = int(b.uint8()) | ||||
| 	m.header.opcodeBase = b.uint8() | ||||
| 	m.header.stdOpcodeLengths = make([]byte, m.header.opcodeBase-1) | ||||
| 	copy(m.header.stdOpcodeLengths, b.bytes(int(m.header.opcodeBase-1))) | ||||
| 	m.header.include = make([]string, 1) // First entry is empty; file index entries are 1-indexed. | ||||
| 	// Includes | ||||
| 	for { | ||||
| 		name := b.string() | ||||
| 		if name == "" { | ||||
| 			break | ||||
| 		} | ||||
| 		m.header.include = append(m.header.include, name) | ||||
| 	} | ||||
| 	// Files | ||||
| 	m.header.file = make([]lineFile, 1, 10) // entries are 1-indexed in line number program. | ||||
| 	for { | ||||
| 		name := b.string() | ||||
| 		if name == "" { | ||||
| 			break | ||||
| 		} | ||||
| 		index := b.uint() | ||||
| 		time := b.uint() | ||||
| 		length := b.uint() | ||||
| 		f := lineFile{ | ||||
| 			name:   name, | ||||
| 			index:  int(index), | ||||
| 			time:   int(time), | ||||
| 			length: int(length), | ||||
| 		} | ||||
| 		m.header.file = append(m.header.file, f) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Special opcodes, page 117. | ||||
| // There are seven steps to processing special opcodes.  We break them up here | ||||
| // because the caller needs to output a row between steps 2 and 4, and because | ||||
| // we need to perform just step 2 for the opcode DW_LNS_const_add_pc. | ||||
|  | ||||
| func (m *lineMachine) specialOpcodeStep1(opcode byte) { | ||||
| 	adjustedOpcode := int(opcode - m.header.opcodeBase) | ||||
| 	lineAdvance := m.header.lineBase + (adjustedOpcode % m.header.lineRange) | ||||
| 	m.line += uint64(lineAdvance) | ||||
| } | ||||
|  | ||||
| func (m *lineMachine) specialOpcodeStep2(opcode byte) { | ||||
| 	adjustedOpcode := int(opcode - m.header.opcodeBase) | ||||
| 	advance := adjustedOpcode / m.header.lineRange | ||||
| 	delta := (int(m.opIndex) + advance) / m.header.maxOpsPerInstruction | ||||
| 	m.address += uint64(m.header.minInstructionLength * delta) | ||||
| 	m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction) | ||||
| } | ||||
|  | ||||
| func (m *lineMachine) specialOpcodeSteps4To7() { | ||||
| 	m.basicBlock = false | ||||
| 	m.prologueEnd = false | ||||
| 	m.epilogueBegin = false | ||||
| 	m.discriminator = 0 | ||||
| } | ||||
|  | ||||
| // evalCompilationUnit reads the next compilation unit and calls f at each output row. | ||||
| // Line machine execution continues while f returns true. | ||||
| func (m *lineMachine) evalCompilationUnit(b *buf, f func(m *lineMachine) (cont bool)) error { | ||||
| 	m.reset() | ||||
| 	for len(b.data) > 0 { | ||||
| 		op := b.uint8() | ||||
| 		if op >= m.header.opcodeBase { | ||||
| 			m.specialOpcodeStep1(op) | ||||
| 			m.specialOpcodeStep2(op) | ||||
| 			// Step 3 is to output a row, so we call f here. | ||||
| 			if !f(m) { | ||||
| 				return nil | ||||
| 			} | ||||
| 			m.specialOpcodeSteps4To7() | ||||
| 			continue | ||||
| 		} | ||||
| 		switch op { | ||||
| 		case lineStartExtendedOpcode: | ||||
| 			if len(b.data) == 0 { | ||||
| 				return fmt.Errorf("DWARF: short extended opcode (1)") | ||||
| 			} | ||||
| 			size := b.uint() | ||||
| 			if uint64(len(b.data)) < size { | ||||
| 				return fmt.Errorf("DWARF: short extended opcode (2)") | ||||
| 			} | ||||
| 			op = b.uint8() | ||||
| 			switch op { | ||||
| 			case lineExtEndSequence: | ||||
| 				m.endSequence = true | ||||
| 				if !f(m) { | ||||
| 					return nil | ||||
| 				} | ||||
| 				if len(b.data) == 0 { | ||||
| 					return nil | ||||
| 				} | ||||
| 				m.reset() | ||||
| 			case lineExtSetAddress: | ||||
| 				m.address = b.addr() | ||||
| 				m.opIndex = 0 | ||||
| 			case lineExtDefineFile: | ||||
| 				return fmt.Errorf("DWARF: unimplemented define_file op") | ||||
| 			case lineExtSetDiscriminator: | ||||
| 				discriminator := b.uint() | ||||
| 				m.discriminator = discriminator | ||||
| 			default: | ||||
| 				return fmt.Errorf("DWARF: unknown extended opcode %#x", op) | ||||
| 			} | ||||
| 		case lineStdCopy: | ||||
| 			if !f(m) { | ||||
| 				return nil | ||||
| 			} | ||||
| 			m.discriminator = 0 | ||||
| 			m.basicBlock = false | ||||
| 			m.prologueEnd = false | ||||
| 			m.epilogueBegin = false | ||||
| 		case lineStdAdvancePC: | ||||
| 			advance := b.uint() | ||||
| 			delta := (int(m.opIndex) + int(advance)) / m.header.maxOpsPerInstruction | ||||
| 			m.address += uint64(m.header.minInstructionLength * delta) | ||||
| 			m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction) | ||||
| 			m.basicBlock = false | ||||
| 			m.prologueEnd = false | ||||
| 			m.epilogueBegin = false | ||||
| 			m.discriminator = 0 | ||||
| 		case lineStdAdvanceLine: | ||||
| 			advance := b.int() | ||||
| 			m.line = uint64(int64(m.line) + advance) | ||||
| 		case lineStdSetFile: | ||||
| 			index := b.uint() | ||||
| 			m.file = index | ||||
| 		case lineStdSetColumn: | ||||
| 			column := b.uint() | ||||
| 			m.column = column | ||||
| 		case lineStdNegateStmt: | ||||
| 			m.isStmt = !m.isStmt | ||||
| 		case lineStdSetBasicBlock: | ||||
| 			m.basicBlock = true | ||||
| 		case lineStdFixedAdvancePC: | ||||
| 			m.address += uint64(b.uint16()) | ||||
| 			m.opIndex = 0 | ||||
| 		case lineStdSetPrologueEnd: | ||||
| 			m.prologueEnd = true | ||||
| 		case lineStdSetEpilogueBegin: | ||||
| 			m.epilogueBegin = true | ||||
| 		case lineStdSetISA: | ||||
| 			m.isa = b.uint() | ||||
| 		case lineStdConstAddPC: | ||||
| 			// Update the the address and op_index registers. | ||||
| 			m.specialOpcodeStep2(255) | ||||
| 		default: | ||||
| 			panic("not reached") | ||||
| 		} | ||||
| 	} | ||||
| 	return fmt.Errorf("DWARF: unexpected end of line number information") | ||||
| } | ||||
|  | ||||
| // reset sets the machine's registers to the initial state. Page 111. | ||||
| func (m *lineMachine) reset() { | ||||
| 	m.address = 0 | ||||
| 	m.opIndex = 0 | ||||
| 	m.file = 1 | ||||
| 	m.line = 1 | ||||
| 	m.column = 0 | ||||
| 	m.isStmt = m.header.defaultIsStmt | ||||
| 	m.basicBlock = false | ||||
| 	m.endSequence = false | ||||
| 	m.prologueEnd = false | ||||
| 	m.epilogueBegin = false | ||||
| 	m.isa = 0 | ||||
| 	m.discriminator = 0 | ||||
| } | ||||
							
								
								
									
										94
									
								
								vendor/golang.org/x/debug/dwarf/open.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								vendor/golang.org/x/debug/dwarf/open.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Package dwarf provides access to DWARF debugging information loaded from | ||||
| // executable files, as defined in the DWARF 2.0 Standard at | ||||
| // http://dwarfstd.org/doc/dwarf-2.0.0.pdf | ||||
| package dwarf | ||||
|  | ||||
| import "encoding/binary" | ||||
|  | ||||
| // Data represents the DWARF debugging information | ||||
| // loaded from an executable file (for example, an ELF or Mach-O executable). | ||||
| type Data struct { | ||||
| 	// raw data | ||||
| 	abbrev   []byte | ||||
| 	aranges  []byte | ||||
| 	frame    []byte | ||||
| 	info     []byte | ||||
| 	line     []byte | ||||
| 	pubnames []byte | ||||
| 	ranges   []byte | ||||
| 	str      []byte | ||||
|  | ||||
| 	// parsed data | ||||
| 	abbrevCache     map[uint32]abbrevTable | ||||
| 	order           binary.ByteOrder | ||||
| 	typeCache       map[Offset]Type | ||||
| 	typeSigs        map[uint64]*typeUnit | ||||
| 	unit            []unit | ||||
| 	sourceFiles     []string // source files listed in .debug_line. | ||||
| 	nameCache                // map from name to top-level entries in .debug_info. | ||||
| 	pcToFuncEntries          // cache of .debug_info data for function bounds. | ||||
| 	pcToLineEntries          // cache of .debug_line data, used for efficient PC-to-line mapping. | ||||
| 	lineToPCEntries          // cache of .debug_line data, used for efficient line-to-[]PC mapping. | ||||
| } | ||||
|  | ||||
| // New returns a new Data object initialized from the given parameters. | ||||
| // Rather than calling this function directly, clients should typically use | ||||
| // the DWARF method of the File type of the appropriate package debug/elf, | ||||
| // debug/macho, or debug/pe. | ||||
| // | ||||
| // The []byte arguments are the data from the corresponding debug section | ||||
| // in the object file; for example, for an ELF object, abbrev is the contents of | ||||
| // the ".debug_abbrev" section. | ||||
| func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) { | ||||
| 	d := &Data{ | ||||
| 		abbrev:      abbrev, | ||||
| 		aranges:     aranges, | ||||
| 		frame:       frame, | ||||
| 		info:        info, | ||||
| 		line:        line, | ||||
| 		pubnames:    pubnames, | ||||
| 		ranges:      ranges, | ||||
| 		str:         str, | ||||
| 		abbrevCache: make(map[uint32]abbrevTable), | ||||
| 		typeCache:   make(map[Offset]Type), | ||||
| 		typeSigs:    make(map[uint64]*typeUnit), | ||||
| 	} | ||||
|  | ||||
| 	// Sniff .debug_info to figure out byte order. | ||||
| 	// bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3). | ||||
| 	if len(d.info) < 6 { | ||||
| 		return nil, DecodeError{"info", Offset(len(d.info)), "too short"} | ||||
| 	} | ||||
| 	x, y := d.info[4], d.info[5] | ||||
| 	switch { | ||||
| 	case x == 0 && y == 0: | ||||
| 		return nil, DecodeError{"info", 4, "unsupported version 0"} | ||||
| 	case x == 0: | ||||
| 		d.order = binary.BigEndian | ||||
| 	case y == 0: | ||||
| 		d.order = binary.LittleEndian | ||||
| 	default: | ||||
| 		return nil, DecodeError{"info", 4, "cannot determine byte order"} | ||||
| 	} | ||||
|  | ||||
| 	u, err := d.parseUnits() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	d.unit = u | ||||
| 	d.buildInfoCaches() | ||||
| 	d.buildLineCaches() | ||||
| 	return d, nil | ||||
| } | ||||
|  | ||||
| // AddTypes will add one .debug_types section to the DWARF data.  A | ||||
| // typical object with DWARF version 4 debug info will have multiple | ||||
| // .debug_types sections.  The name is used for error reporting only, | ||||
| // and serves to distinguish one .debug_types section from another. | ||||
| func (d *Data) AddTypes(name string, types []byte) error { | ||||
| 	return d.parseTypes(name, types) | ||||
| } | ||||
							
								
								
									
										119
									
								
								vendor/golang.org/x/debug/dwarf/symbol.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								vendor/golang.org/x/debug/dwarf/symbol.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| // Copyright 2014 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| // This file provides simple methods to access the symbol table by name and address. | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| ) | ||||
|  | ||||
| // lookupEntry returns the first Entry for the name. | ||||
| // If tag is non-zero, only entries with that tag are considered. | ||||
| func (d *Data) lookupEntry(name string, tag Tag) (*Entry, error) { | ||||
| 	x, ok := d.nameCache[name] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("DWARF entry for %q not found", name) | ||||
| 	} | ||||
| 	for ; x != nil; x = x.link { | ||||
| 		if tag == 0 || x.entry.Tag == tag { | ||||
| 			return x.entry, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("no DWARF entry for %q with tag %s", name, tag) | ||||
| } | ||||
|  | ||||
| // LookupMatchingSymbols returns the names of all top-level entries matching | ||||
| // the given regular expression. | ||||
| func (d *Data) LookupMatchingSymbols(nameRE *regexp.Regexp) (result []string, err error) { | ||||
| 	for name := range d.nameCache { | ||||
| 		if nameRE.MatchString(name) { | ||||
| 			result = append(result, name) | ||||
| 		} | ||||
| 	} | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| // LookupEntry returns the Entry for the named symbol. | ||||
| func (d *Data) LookupEntry(name string) (*Entry, error) { | ||||
| 	return d.lookupEntry(name, 0) | ||||
| } | ||||
|  | ||||
| // LookupFunction returns the entry for a function. | ||||
| func (d *Data) LookupFunction(name string) (*Entry, error) { | ||||
| 	return d.lookupEntry(name, TagSubprogram) | ||||
| } | ||||
|  | ||||
| // LookupVariable returns the entry for a (global) variable. | ||||
| func (d *Data) LookupVariable(name string) (*Entry, error) { | ||||
| 	return d.lookupEntry(name, TagVariable) | ||||
| } | ||||
|  | ||||
| // EntryLocation returns the address of the object referred to by the given Entry. | ||||
| func (d *Data) EntryLocation(e *Entry) (uint64, error) { | ||||
| 	loc, _ := e.Val(AttrLocation).([]byte) | ||||
| 	if len(loc) == 0 { | ||||
| 		return 0, fmt.Errorf("DWARF entry has no Location attribute") | ||||
| 	} | ||||
| 	// TODO: implement the DWARF Location bytecode. What we have here only | ||||
| 	// recognizes a program with a single literal opAddr bytecode. | ||||
| 	if asize := d.unit[0].asize; loc[0] == opAddr && len(loc) == 1+asize { | ||||
| 		switch asize { | ||||
| 		case 1: | ||||
| 			return uint64(loc[1]), nil | ||||
| 		case 2: | ||||
| 			return uint64(d.order.Uint16(loc[1:])), nil | ||||
| 		case 4: | ||||
| 			return uint64(d.order.Uint32(loc[1:])), nil | ||||
| 		case 8: | ||||
| 			return d.order.Uint64(loc[1:]), nil | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, fmt.Errorf("DWARF entry has an unimplemented Location op") | ||||
| } | ||||
|  | ||||
| // EntryType returns the Type for an Entry. | ||||
| func (d *Data) EntryType(e *Entry) (Type, error) { | ||||
| 	off, err := d.EntryTypeOffset(e) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return d.Type(off) | ||||
| } | ||||
|  | ||||
| // EntryTypeOffset returns the offset in the given Entry's type attribute. | ||||
| func (d *Data) EntryTypeOffset(e *Entry) (Offset, error) { | ||||
| 	v := e.Val(AttrType) | ||||
| 	if v == nil { | ||||
| 		return 0, fmt.Errorf("DWARF entry has no Type attribute") | ||||
| 	} | ||||
| 	off, ok := v.(Offset) | ||||
| 	if !ok { | ||||
| 		return 0, fmt.Errorf("DWARF entry has an invalid Type attribute") | ||||
| 	} | ||||
| 	return off, nil | ||||
| } | ||||
|  | ||||
| // PCToFunction returns the entry and address for the function containing the | ||||
| // specified PC. | ||||
| func (d *Data) PCToFunction(pc uint64) (entry *Entry, lowpc uint64, err error) { | ||||
| 	p := d.pcToFuncEntries | ||||
| 	if len(p) == 0 { | ||||
| 		return nil, 0, fmt.Errorf("no function addresses loaded") | ||||
| 	} | ||||
| 	i := sort.Search(len(p), func(i int) bool { return p[i].pc > pc }) - 1 | ||||
| 	// The search failed if: | ||||
| 	// - pc was before the start of any function. | ||||
| 	// - The largest function bound not larger than pc was the end of a function, | ||||
| 	//   not the start of one. | ||||
| 	// - The largest function bound not larger than pc was the start of a function | ||||
| 	//   that we don't know the end of, and the PC is much larger than the start. | ||||
| 	if i == -1 || p[i].entry == nil || (i+1 == len(p) && pc-p[i].pc >= 1<<20) { | ||||
| 		return nil, 0, fmt.Errorf("no function at %x", pc) | ||||
| 	} | ||||
| 	return p[i].entry, p[i].pc, nil | ||||
| } | ||||
							
								
								
									
										862
									
								
								vendor/golang.org/x/debug/dwarf/type.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										862
									
								
								vendor/golang.org/x/debug/dwarf/type.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,862 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // DWARF type information structures. | ||||
| // The format is heavily biased toward C, but for simplicity | ||||
| // the String methods use a pseudo-Go syntax. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // A Type conventionally represents a pointer to any of the | ||||
| // specific Type structures (CharType, StructType, etc.). | ||||
| type Type interface { | ||||
| 	Common() *CommonType | ||||
| 	String() string | ||||
| 	Size() int64 | ||||
| } | ||||
|  | ||||
| // A CommonType holds fields common to multiple types. | ||||
| // If a field is not known or not applicable for a given type, | ||||
| // the zero value is used. | ||||
| type CommonType struct { | ||||
| 	ByteSize    int64        // size of value of this type, in bytes | ||||
| 	Name        string       // name that can be used to refer to type | ||||
| 	ReflectKind reflect.Kind // the reflect kind of the type. | ||||
| 	Offset      Offset       // the offset at which this type was read | ||||
| } | ||||
|  | ||||
| func (c *CommonType) Common() *CommonType { return c } | ||||
|  | ||||
| func (c *CommonType) Size() int64 { return c.ByteSize } | ||||
|  | ||||
| // Basic types | ||||
|  | ||||
| // A BasicType holds fields common to all basic types. | ||||
| type BasicType struct { | ||||
| 	CommonType | ||||
| 	BitSize   int64 | ||||
| 	BitOffset int64 | ||||
| } | ||||
|  | ||||
| func (b *BasicType) Basic() *BasicType { return b } | ||||
|  | ||||
| func (t *BasicType) String() string { | ||||
| 	if t.Name != "" { | ||||
| 		return t.Name | ||||
| 	} | ||||
| 	return "?" | ||||
| } | ||||
|  | ||||
| // A CharType represents a signed character type. | ||||
| type CharType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // A UcharType represents an unsigned character type. | ||||
| type UcharType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // An IntType represents a signed integer type. | ||||
| type IntType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // A UintType represents an unsigned integer type. | ||||
| type UintType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // A FloatType represents a floating point type. | ||||
| type FloatType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // A ComplexType represents a complex floating point type. | ||||
| type ComplexType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // A BoolType represents a boolean type. | ||||
| type BoolType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // An AddrType represents a machine address type. | ||||
| type AddrType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type. | ||||
| type UnspecifiedType struct { | ||||
| 	BasicType | ||||
| } | ||||
|  | ||||
| // qualifiers | ||||
|  | ||||
| // A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier. | ||||
| type QualType struct { | ||||
| 	CommonType | ||||
| 	Qual string | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (t *QualType) String() string { return t.Qual + " " + t.Type.String() } | ||||
|  | ||||
| func (t *QualType) Size() int64 { return t.Type.Size() } | ||||
|  | ||||
| // An ArrayType represents a fixed size array type. | ||||
| type ArrayType struct { | ||||
| 	CommonType | ||||
| 	Type          Type | ||||
| 	StrideBitSize int64 // if > 0, number of bits to hold each element | ||||
| 	Count         int64 // if == -1, an incomplete array, like char x[]. | ||||
| } | ||||
|  | ||||
| func (t *ArrayType) String() string { | ||||
| 	return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String() | ||||
| } | ||||
|  | ||||
| func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() } | ||||
|  | ||||
| // A VoidType represents the C void type. | ||||
| type VoidType struct { | ||||
| 	CommonType | ||||
| } | ||||
|  | ||||
| func (t *VoidType) String() string { return "void" } | ||||
|  | ||||
| // A PtrType represents a pointer type. | ||||
| type PtrType struct { | ||||
| 	CommonType | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (t *PtrType) String() string { return "*" + t.Type.String() } | ||||
|  | ||||
| // A StructType represents a struct, union, or C++ class type. | ||||
| type StructType struct { | ||||
| 	CommonType | ||||
| 	StructName string | ||||
| 	Kind       string // "struct", "union", or "class". | ||||
| 	Field      []*StructField | ||||
| 	Incomplete bool // if true, struct, union, class is declared but not defined | ||||
| } | ||||
|  | ||||
| // A StructField represents a field in a struct, union, or C++ class type. | ||||
| type StructField struct { | ||||
| 	Name       string | ||||
| 	Type       Type | ||||
| 	ByteOffset int64 | ||||
| 	ByteSize   int64 | ||||
| 	BitOffset  int64 // within the ByteSize bytes at ByteOffset | ||||
| 	BitSize    int64 // zero if not a bit field | ||||
| } | ||||
|  | ||||
| func (t *StructType) String() string { | ||||
| 	if t.StructName != "" { | ||||
| 		return t.Kind + " " + t.StructName | ||||
| 	} | ||||
| 	return t.Defn() | ||||
| } | ||||
|  | ||||
| func (t *StructType) Defn() string { | ||||
| 	s := t.Kind | ||||
| 	if t.StructName != "" { | ||||
| 		s += " " + t.StructName | ||||
| 	} | ||||
| 	if t.Incomplete { | ||||
| 		s += " /*incomplete*/" | ||||
| 		return s | ||||
| 	} | ||||
| 	s += " {" | ||||
| 	for i, f := range t.Field { | ||||
| 		if i > 0 { | ||||
| 			s += "; " | ||||
| 		} | ||||
| 		s += f.Name + " " + f.Type.String() | ||||
| 		s += "@" + strconv.FormatInt(f.ByteOffset, 10) | ||||
| 		if f.BitSize > 0 { | ||||
| 			s += " : " + strconv.FormatInt(f.BitSize, 10) | ||||
| 			s += "@" + strconv.FormatInt(f.BitOffset, 10) | ||||
| 		} | ||||
| 	} | ||||
| 	s += "}" | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // A SliceType represents a Go slice type. It looks like a StructType, describing | ||||
| // the runtime-internal structure, with extra fields. | ||||
| type SliceType struct { | ||||
| 	StructType | ||||
| 	ElemType Type | ||||
| } | ||||
|  | ||||
| func (t *SliceType) String() string { | ||||
| 	if t.Name != "" { | ||||
| 		return t.Name | ||||
| 	} | ||||
| 	return "[]" + t.ElemType.String() | ||||
| } | ||||
|  | ||||
| // A StringType represents a Go string type. It looks like a StructType, describing | ||||
| // the runtime-internal structure, but we wrap it for neatness. | ||||
| type StringType struct { | ||||
| 	StructType | ||||
| } | ||||
|  | ||||
| func (t *StringType) String() string { | ||||
| 	if t.Name != "" { | ||||
| 		return t.Name | ||||
| 	} | ||||
| 	return "string" | ||||
| } | ||||
|  | ||||
| // An InterfaceType represents a Go interface. | ||||
| type InterfaceType struct { | ||||
| 	TypedefType | ||||
| } | ||||
|  | ||||
| func (t *InterfaceType) String() string { | ||||
| 	if t.Name != "" { | ||||
| 		return t.Name | ||||
| 	} | ||||
| 	return "Interface" | ||||
| } | ||||
|  | ||||
| // An EnumType represents an enumerated type. | ||||
| // The only indication of its native integer type is its ByteSize | ||||
| // (inside CommonType). | ||||
| type EnumType struct { | ||||
| 	CommonType | ||||
| 	EnumName string | ||||
| 	Val      []*EnumValue | ||||
| } | ||||
|  | ||||
| // An EnumValue represents a single enumeration value. | ||||
| type EnumValue struct { | ||||
| 	Name string | ||||
| 	Val  int64 | ||||
| } | ||||
|  | ||||
| func (t *EnumType) String() string { | ||||
| 	s := "enum" | ||||
| 	if t.EnumName != "" { | ||||
| 		s += " " + t.EnumName | ||||
| 	} | ||||
| 	s += " {" | ||||
| 	for i, v := range t.Val { | ||||
| 		if i > 0 { | ||||
| 			s += "; " | ||||
| 		} | ||||
| 		s += v.Name + "=" + strconv.FormatInt(v.Val, 10) | ||||
| 	} | ||||
| 	s += "}" | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // A FuncType represents a function type. | ||||
| type FuncType struct { | ||||
| 	CommonType | ||||
| 	ReturnType Type | ||||
| 	ParamType  []Type | ||||
| } | ||||
|  | ||||
| func (t *FuncType) String() string { | ||||
| 	s := "func(" | ||||
| 	for i, t := range t.ParamType { | ||||
| 		if i > 0 { | ||||
| 			s += ", " | ||||
| 		} | ||||
| 		s += t.String() | ||||
| 	} | ||||
| 	s += ")" | ||||
| 	if t.ReturnType != nil { | ||||
| 		s += " " + t.ReturnType.String() | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // A DotDotDotType represents the variadic ... function parameter. | ||||
| type DotDotDotType struct { | ||||
| 	CommonType | ||||
| } | ||||
|  | ||||
| func (t *DotDotDotType) String() string { return "..." } | ||||
|  | ||||
| // A TypedefType represents a named type. | ||||
| type TypedefType struct { | ||||
| 	CommonType | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (t *TypedefType) String() string { return t.Name } | ||||
|  | ||||
| func (t *TypedefType) Size() int64 { return t.Type.Size() } | ||||
|  | ||||
| // A MapType represents a Go map type. It looks like a TypedefType, describing | ||||
| // the runtime-internal structure, with extra fields. | ||||
| type MapType struct { | ||||
| 	TypedefType | ||||
| 	KeyType  Type | ||||
| 	ElemType Type | ||||
| } | ||||
|  | ||||
| func (t *MapType) String() string { | ||||
| 	if t.Name != "" { | ||||
| 		return t.Name | ||||
| 	} | ||||
| 	return "map[" + t.KeyType.String() + "]" + t.ElemType.String() | ||||
| } | ||||
|  | ||||
| // A ChanType represents a Go channel type. | ||||
| type ChanType struct { | ||||
| 	TypedefType | ||||
| 	ElemType Type | ||||
| } | ||||
|  | ||||
| func (t *ChanType) String() string { | ||||
| 	if t.Name != "" { | ||||
| 		return t.Name | ||||
| 	} | ||||
| 	return "chan " + t.ElemType.String() | ||||
| } | ||||
|  | ||||
| // typeReader is used to read from either the info section or the | ||||
| // types section. | ||||
| type typeReader interface { | ||||
| 	Seek(Offset) | ||||
| 	Next() (*Entry, error) | ||||
| 	clone() typeReader | ||||
| 	offset() Offset | ||||
| 	// AddressSize returns the size in bytes of addresses in the current | ||||
| 	// compilation unit. | ||||
| 	AddressSize() int | ||||
| } | ||||
|  | ||||
| // Type reads the type at off in the DWARF ``info'' section. | ||||
| func (d *Data) Type(off Offset) (Type, error) { | ||||
| 	return d.readType("info", d.Reader(), off, d.typeCache) | ||||
| } | ||||
|  | ||||
| func getKind(e *Entry) reflect.Kind { | ||||
| 	integer, _ := e.Val(AttrGoKind).(int64) | ||||
| 	return reflect.Kind(integer) | ||||
| } | ||||
|  | ||||
| // readType reads a type from r at off of name using and updating a | ||||
| // type cache. | ||||
| func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) { | ||||
| 	if t, ok := typeCache[off]; ok { | ||||
| 		return t, nil | ||||
| 	} | ||||
| 	r.Seek(off) | ||||
| 	e, err := r.Next() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	addressSize := r.AddressSize() | ||||
| 	if e == nil || e.Offset != off { | ||||
| 		return nil, DecodeError{name, off, "no type at offset"} | ||||
| 	} | ||||
|  | ||||
| 	// Parse type from Entry. | ||||
| 	// Must always set typeCache[off] before calling | ||||
| 	// d.Type recursively, to handle circular types correctly. | ||||
| 	var typ Type | ||||
|  | ||||
| 	nextDepth := 0 | ||||
|  | ||||
| 	// Get next child; set err if error happens. | ||||
| 	next := func() *Entry { | ||||
| 		if !e.Children { | ||||
| 			return nil | ||||
| 		} | ||||
| 		// Only return direct children. | ||||
| 		// Skip over composite entries that happen to be nested | ||||
| 		// inside this one. Most DWARF generators wouldn't generate | ||||
| 		// such a thing, but clang does. | ||||
| 		// See golang.org/issue/6472. | ||||
| 		for { | ||||
| 			kid, err1 := r.Next() | ||||
| 			if err1 != nil { | ||||
| 				err = err1 | ||||
| 				return nil | ||||
| 			} | ||||
| 			if kid == nil { | ||||
| 				err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"} | ||||
| 				return nil | ||||
| 			} | ||||
| 			if kid.Tag == 0 { | ||||
| 				if nextDepth > 0 { | ||||
| 					nextDepth-- | ||||
| 					continue | ||||
| 				} | ||||
| 				return nil | ||||
| 			} | ||||
| 			if kid.Children { | ||||
| 				nextDepth++ | ||||
| 			} | ||||
| 			if nextDepth > 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 			return kid | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Get Type referred to by Entry's attr. | ||||
| 	// Set err if error happens.  Not having a type is an error. | ||||
| 	typeOf := func(e *Entry, attr Attr) Type { | ||||
| 		tval := e.Val(attr) | ||||
| 		var t Type | ||||
| 		switch toff := tval.(type) { | ||||
| 		case Offset: | ||||
| 			if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil { | ||||
| 				return nil | ||||
| 			} | ||||
| 		case uint64: | ||||
| 			if t, err = d.sigToType(toff); err != nil { | ||||
| 				return nil | ||||
| 			} | ||||
| 		default: | ||||
| 			// It appears that no Type means "void". | ||||
| 			return new(VoidType) | ||||
| 		} | ||||
| 		return t | ||||
| 	} | ||||
|  | ||||
| 	switch e.Tag { | ||||
| 	case TagArrayType: | ||||
| 		// Multi-dimensional array.  (DWARF v2 §5.4) | ||||
| 		// Attributes: | ||||
| 		//	AttrType:subtype [required] | ||||
| 		//	AttrStrideSize: distance in bits between each element of the array | ||||
| 		//	AttrStride: distance in bytes between each element of the array | ||||
| 		//	AttrByteSize: size of entire array | ||||
| 		// Children: | ||||
| 		//	TagSubrangeType or TagEnumerationType giving one dimension. | ||||
| 		//	dimensions are in left to right order. | ||||
| 		t := new(ArrayType) | ||||
| 		t.Name, _ = e.Val(AttrName).(string) | ||||
| 		t.ReflectKind = getKind(e) | ||||
| 		typ = t | ||||
| 		typeCache[off] = t | ||||
| 		if t.Type = typeOf(e, AttrType); err != nil { | ||||
| 			goto Error | ||||
| 		} | ||||
| 		if bytes, ok := e.Val(AttrStride).(int64); ok { | ||||
| 			t.StrideBitSize = 8 * bytes | ||||
| 		} else if bits, ok := e.Val(AttrStrideSize).(int64); ok { | ||||
| 			t.StrideBitSize = bits | ||||
| 		} else { | ||||
| 			// If there's no stride specified, assume it's the size of the | ||||
| 			// array's element type. | ||||
| 			t.StrideBitSize = 8 * t.Type.Size() | ||||
| 		} | ||||
|  | ||||
| 		// Accumulate dimensions, | ||||
| 		ndim := 0 | ||||
| 		for kid := next(); kid != nil; kid = next() { | ||||
| 			// TODO(rsc): Can also be TagEnumerationType | ||||
| 			// but haven't seen that in the wild yet. | ||||
| 			switch kid.Tag { | ||||
| 			case TagSubrangeType: | ||||
| 				count, ok := kid.Val(AttrCount).(int64) | ||||
| 				if !ok { | ||||
| 					// Old binaries may have an upper bound instead. | ||||
| 					count, ok = kid.Val(AttrUpperBound).(int64) | ||||
| 					if ok { | ||||
| 						count++ // Length is one more than upper bound. | ||||
| 					} else { | ||||
| 						count = -1 // As in x[]. | ||||
| 					} | ||||
| 				} | ||||
| 				if ndim == 0 { | ||||
| 					t.Count = count | ||||
| 				} else { | ||||
| 					// Multidimensional array. | ||||
| 					// Create new array type underneath this one. | ||||
| 					t.Type = &ArrayType{Type: t.Type, Count: count} | ||||
| 				} | ||||
| 				ndim++ | ||||
| 			case TagEnumerationType: | ||||
| 				err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"} | ||||
| 				goto Error | ||||
| 			} | ||||
| 		} | ||||
| 		if ndim == 0 { | ||||
| 			// LLVM generates this for x[]. | ||||
| 			t.Count = -1 | ||||
| 		} | ||||
|  | ||||
| 	case TagBaseType: | ||||
| 		// Basic type.  (DWARF v2 §5.1) | ||||
| 		// Attributes: | ||||
| 		//	AttrName: name of base type in programming language of the compilation unit [required] | ||||
| 		//	AttrEncoding: encoding value for type (encFloat etc) [required] | ||||
| 		//	AttrByteSize: size of type in bytes [required] | ||||
| 		//	AttrBitOffset: for sub-byte types, size in bits | ||||
| 		//	AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes | ||||
| 		name, _ := e.Val(AttrName).(string) | ||||
| 		enc, ok := e.Val(AttrEncoding).(int64) | ||||
| 		if !ok { | ||||
| 			err = DecodeError{name, e.Offset, "missing encoding attribute for " + name} | ||||
| 			goto Error | ||||
| 		} | ||||
| 		switch enc { | ||||
| 		default: | ||||
| 			err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"} | ||||
| 			goto Error | ||||
|  | ||||
| 		case encAddress: | ||||
| 			typ = new(AddrType) | ||||
| 		case encBoolean: | ||||
| 			typ = new(BoolType) | ||||
| 		case encComplexFloat: | ||||
| 			typ = new(ComplexType) | ||||
| 			if name == "complex" { | ||||
| 				// clang writes out 'complex' instead of 'complex float' or 'complex double'. | ||||
| 				// clang also writes out a byte size that we can use to distinguish. | ||||
| 				// See issue 8694. | ||||
| 				switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize { | ||||
| 				case 8: | ||||
| 					name = "complex float" | ||||
| 				case 16: | ||||
| 					name = "complex double" | ||||
| 				} | ||||
| 			} | ||||
| 		case encFloat: | ||||
| 			typ = new(FloatType) | ||||
| 		case encSigned: | ||||
| 			typ = new(IntType) | ||||
| 		case encUnsigned: | ||||
| 			typ = new(UintType) | ||||
| 		case encSignedChar: | ||||
| 			typ = new(CharType) | ||||
| 		case encUnsignedChar: | ||||
| 			typ = new(UcharType) | ||||
| 		} | ||||
| 		typeCache[off] = typ | ||||
| 		t := typ.(interface { | ||||
| 			Basic() *BasicType | ||||
| 		}).Basic() | ||||
| 		t.Name = name | ||||
| 		t.BitSize, _ = e.Val(AttrBitSize).(int64) | ||||
| 		t.BitOffset, _ = e.Val(AttrBitOffset).(int64) | ||||
| 		t.ReflectKind = getKind(e) | ||||
|  | ||||
| 	case TagClassType, TagStructType, TagUnionType: | ||||
| 		// Structure, union, or class type.  (DWARF v2 §5.5) | ||||
| 		// Also Slices and Strings (Go-specific). | ||||
| 		// Attributes: | ||||
| 		//	AttrName: name of struct, union, or class | ||||
| 		//	AttrByteSize: byte size [required] | ||||
| 		//	AttrDeclaration: if true, struct/union/class is incomplete | ||||
| 		// 	AttrGoElem: present for slices only. | ||||
| 		// Children: | ||||
| 		//	TagMember to describe one member. | ||||
| 		//		AttrName: name of member [required] | ||||
| 		//		AttrType: type of member [required] | ||||
| 		//		AttrByteSize: size in bytes | ||||
| 		//		AttrBitOffset: bit offset within bytes for bit fields | ||||
| 		//		AttrBitSize: bit size for bit fields | ||||
| 		//		AttrDataMemberLoc: location within struct [required for struct, class] | ||||
| 		// There is much more to handle C++, all ignored for now. | ||||
| 		t := new(StructType) | ||||
| 		t.ReflectKind = getKind(e) | ||||
| 		switch t.ReflectKind { | ||||
| 		case reflect.Slice: | ||||
| 			slice := new(SliceType) | ||||
| 			slice.ElemType = typeOf(e, AttrGoElem) | ||||
| 			t = &slice.StructType | ||||
| 			typ = slice | ||||
| 		case reflect.String: | ||||
| 			str := new(StringType) | ||||
| 			t = &str.StructType | ||||
| 			typ = str | ||||
| 		default: | ||||
| 			typ = t | ||||
| 		} | ||||
| 		typeCache[off] = typ | ||||
| 		switch e.Tag { | ||||
| 		case TagClassType: | ||||
| 			t.Kind = "class" | ||||
| 		case TagStructType: | ||||
| 			t.Kind = "struct" | ||||
| 		case TagUnionType: | ||||
| 			t.Kind = "union" | ||||
| 		} | ||||
| 		t.Name, _ = e.Val(AttrName).(string) | ||||
| 		t.StructName, _ = e.Val(AttrName).(string) | ||||
| 		t.Incomplete = e.Val(AttrDeclaration) != nil | ||||
| 		t.Field = make([]*StructField, 0, 8) | ||||
| 		var lastFieldType Type | ||||
| 		var lastFieldBitOffset int64 | ||||
| 		for kid := next(); kid != nil; kid = next() { | ||||
| 			if kid.Tag == TagMember { | ||||
| 				f := new(StructField) | ||||
| 				if f.Type = typeOf(kid, AttrType); err != nil { | ||||
| 					goto Error | ||||
| 				} | ||||
| 				switch loc := kid.Val(AttrDataMemberLoc).(type) { | ||||
| 				case []byte: | ||||
| 					// TODO: Should have original compilation | ||||
| 					// unit here, not unknownFormat. | ||||
| 					if len(loc) == 0 { | ||||
| 						// Empty exprloc. f.ByteOffset=0. | ||||
| 						break | ||||
| 					} | ||||
| 					b := makeBuf(d, unknownFormat{}, "location", 0, loc) | ||||
| 					op := b.uint8() | ||||
| 					switch op { | ||||
| 					case opPlusUconst: | ||||
| 						// Handle opcode sequence [DW_OP_plus_uconst <uleb128>] | ||||
| 						f.ByteOffset = int64(b.uint()) | ||||
| 						b.assertEmpty() | ||||
| 					case opConsts: | ||||
| 						// Handle opcode sequence [DW_OP_consts <sleb128> DW_OP_plus] | ||||
| 						f.ByteOffset = b.int() | ||||
| 						op = b.uint8() | ||||
| 						if op != opPlus { | ||||
| 							err = DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op)} | ||||
| 							goto Error | ||||
| 						} | ||||
| 						b.assertEmpty() | ||||
| 					default: | ||||
| 						err = DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op)} | ||||
| 						goto Error | ||||
| 					} | ||||
| 					if b.err != nil { | ||||
| 						err = b.err | ||||
| 						goto Error | ||||
| 					} | ||||
| 				case int64: | ||||
| 					f.ByteOffset = loc | ||||
| 				} | ||||
|  | ||||
| 				haveBitOffset := false | ||||
| 				f.Name, _ = kid.Val(AttrName).(string) | ||||
| 				f.ByteSize, _ = kid.Val(AttrByteSize).(int64) | ||||
| 				f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64) | ||||
| 				f.BitSize, _ = kid.Val(AttrBitSize).(int64) | ||||
| 				t.Field = append(t.Field, f) | ||||
|  | ||||
| 				bito := f.BitOffset | ||||
| 				if !haveBitOffset { | ||||
| 					bito = f.ByteOffset * 8 | ||||
| 				} | ||||
| 				if bito == lastFieldBitOffset && t.Kind != "union" { | ||||
| 					// Last field was zero width.  Fix array length. | ||||
| 					// (DWARF writes out 0-length arrays as if they were 1-length arrays.) | ||||
| 					zeroArray(lastFieldType) | ||||
| 				} | ||||
| 				lastFieldType = f.Type | ||||
| 				lastFieldBitOffset = bito | ||||
| 			} | ||||
| 		} | ||||
| 		if t.Kind != "union" { | ||||
| 			b, ok := e.Val(AttrByteSize).(int64) | ||||
| 			if ok && b*8 == lastFieldBitOffset { | ||||
| 				// Final field must be zero width.  Fix array length. | ||||
| 				zeroArray(lastFieldType) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	case TagConstType, TagVolatileType, TagRestrictType: | ||||
| 		// Type modifier (DWARF v2 §5.2) | ||||
| 		// Attributes: | ||||
| 		//	AttrType: subtype | ||||
| 		t := new(QualType) | ||||
| 		t.Name, _ = e.Val(AttrName).(string) | ||||
| 		t.ReflectKind = getKind(e) | ||||
| 		typ = t | ||||
| 		typeCache[off] = t | ||||
| 		if t.Type = typeOf(e, AttrType); err != nil { | ||||
| 			goto Error | ||||
| 		} | ||||
| 		switch e.Tag { | ||||
| 		case TagConstType: | ||||
| 			t.Qual = "const" | ||||
| 		case TagRestrictType: | ||||
| 			t.Qual = "restrict" | ||||
| 		case TagVolatileType: | ||||
| 			t.Qual = "volatile" | ||||
| 		} | ||||
|  | ||||
| 	case TagEnumerationType: | ||||
| 		// Enumeration type (DWARF v2 §5.6) | ||||
| 		// Attributes: | ||||
| 		//	AttrName: enum name if any | ||||
| 		//	AttrByteSize: bytes required to represent largest value | ||||
| 		// Children: | ||||
| 		//	TagEnumerator: | ||||
| 		//		AttrName: name of constant | ||||
| 		//		AttrConstValue: value of constant | ||||
| 		t := new(EnumType) | ||||
| 		t.ReflectKind = getKind(e) | ||||
| 		typ = t | ||||
| 		typeCache[off] = t | ||||
| 		t.Name, _ = e.Val(AttrName).(string) | ||||
| 		t.EnumName, _ = e.Val(AttrName).(string) | ||||
| 		t.Val = make([]*EnumValue, 0, 8) | ||||
| 		for kid := next(); kid != nil; kid = next() { | ||||
| 			if kid.Tag == TagEnumerator { | ||||
| 				f := new(EnumValue) | ||||
| 				f.Name, _ = kid.Val(AttrName).(string) | ||||
| 				f.Val, _ = kid.Val(AttrConstValue).(int64) | ||||
| 				n := len(t.Val) | ||||
| 				if n >= cap(t.Val) { | ||||
| 					val := make([]*EnumValue, n, n*2) | ||||
| 					copy(val, t.Val) | ||||
| 					t.Val = val | ||||
| 				} | ||||
| 				t.Val = t.Val[0 : n+1] | ||||
| 				t.Val[n] = f | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	case TagPointerType: | ||||
| 		// Type modifier (DWARF v2 §5.2) | ||||
| 		// Attributes: | ||||
| 		//	AttrType: subtype [not required!  void* has no AttrType] | ||||
| 		//	AttrAddrClass: address class [ignored] | ||||
| 		t := new(PtrType) | ||||
| 		t.Name, _ = e.Val(AttrName).(string) | ||||
| 		t.ReflectKind = getKind(e) | ||||
| 		typ = t | ||||
| 		typeCache[off] = t | ||||
| 		if e.Val(AttrType) == nil { | ||||
| 			t.Type = &VoidType{} | ||||
| 			break | ||||
| 		} | ||||
| 		t.Type = typeOf(e, AttrType) | ||||
|  | ||||
| 	case TagSubroutineType: | ||||
| 		// Subroutine type.  (DWARF v2 §5.7) | ||||
| 		// Attributes: | ||||
| 		//	AttrType: type of return value if any | ||||
| 		//	AttrName: possible name of type [ignored] | ||||
| 		//	AttrPrototyped: whether used ANSI C prototype [ignored] | ||||
| 		// Children: | ||||
| 		//	TagFormalParameter: typed parameter | ||||
| 		//		AttrType: type of parameter | ||||
| 		//	TagUnspecifiedParameter: final ... | ||||
| 		t := new(FuncType) | ||||
| 		t.Name, _ = e.Val(AttrName).(string) | ||||
| 		t.ReflectKind = getKind(e) | ||||
| 		typ = t | ||||
| 		typeCache[off] = t | ||||
| 		if t.ReturnType = typeOf(e, AttrType); err != nil { | ||||
| 			goto Error | ||||
| 		} | ||||
| 		t.ParamType = make([]Type, 0, 8) | ||||
| 		for kid := next(); kid != nil; kid = next() { | ||||
| 			var tkid Type | ||||
| 			switch kid.Tag { | ||||
| 			default: | ||||
| 				continue | ||||
| 			case TagFormalParameter: | ||||
| 				if tkid = typeOf(kid, AttrType); err != nil { | ||||
| 					goto Error | ||||
| 				} | ||||
| 			case TagUnspecifiedParameters: | ||||
| 				tkid = &DotDotDotType{} | ||||
| 			} | ||||
| 			t.ParamType = append(t.ParamType, tkid) | ||||
| 		} | ||||
|  | ||||
| 	case TagTypedef: | ||||
| 		// Typedef (DWARF v2 §5.3) | ||||
| 		// Also maps and channels (Go-specific). | ||||
| 		// Attributes: | ||||
| 		//	AttrName: name [required] | ||||
| 		//	AttrType: type definition [required] | ||||
| 		//	AttrGoKey: present for maps. | ||||
| 		//	AttrGoElem: present for maps and channels. | ||||
| 		t := new(TypedefType) | ||||
| 		t.ReflectKind = getKind(e) | ||||
| 		switch t.ReflectKind { | ||||
| 		case reflect.Map: | ||||
| 			m := new(MapType) | ||||
| 			m.KeyType = typeOf(e, AttrGoKey) | ||||
| 			m.ElemType = typeOf(e, AttrGoElem) | ||||
| 			t = &m.TypedefType | ||||
| 			typ = m | ||||
| 		case reflect.Chan: | ||||
| 			c := new(ChanType) | ||||
| 			c.ElemType = typeOf(e, AttrGoElem) | ||||
| 			t = &c.TypedefType | ||||
| 			typ = c | ||||
| 		case reflect.Interface: | ||||
| 			it := new(InterfaceType) | ||||
| 			t = &it.TypedefType | ||||
| 			typ = it | ||||
| 		default: | ||||
| 			typ = t | ||||
| 		} | ||||
| 		typeCache[off] = typ | ||||
| 		t.Name, _ = e.Val(AttrName).(string) | ||||
| 		t.Type = typeOf(e, AttrType) | ||||
|  | ||||
| 	case TagUnspecifiedType: | ||||
| 		// Unspecified type (DWARF v3 §5.2) | ||||
| 		// Attributes: | ||||
| 		//      AttrName: name | ||||
| 		t := new(UnspecifiedType) | ||||
| 		typ = t | ||||
| 		typeCache[off] = t | ||||
| 		t.Name, _ = e.Val(AttrName).(string) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		goto Error | ||||
| 	} | ||||
|  | ||||
| 	typ.Common().Offset = off | ||||
|  | ||||
| 	{ | ||||
| 		b, ok := e.Val(AttrByteSize).(int64) | ||||
| 		if !ok { | ||||
| 			b = -1 | ||||
| 			switch t := typ.(type) { | ||||
| 			case *TypedefType: | ||||
| 				b = t.Type.Size() | ||||
| 			case *MapType: | ||||
| 				b = t.Type.Size() | ||||
| 			case *ChanType: | ||||
| 				b = t.Type.Size() | ||||
| 			case *InterfaceType: | ||||
| 				b = t.Type.Size() | ||||
| 			case *PtrType: | ||||
| 				b = int64(addressSize) | ||||
| 			} | ||||
| 		} | ||||
| 		typ.Common().ByteSize = b | ||||
| 	} | ||||
| 	return typ, nil | ||||
|  | ||||
| Error: | ||||
| 	// If the parse fails, take the type out of the cache | ||||
| 	// so that the next call with this offset doesn't hit | ||||
| 	// the cache and return success. | ||||
| 	delete(typeCache, off) | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| func zeroArray(t Type) { | ||||
| 	for { | ||||
| 		at, ok := t.(*ArrayType) | ||||
| 		if !ok { | ||||
| 			break | ||||
| 		} | ||||
| 		at.Count = 0 | ||||
| 		t = at.Type | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										171
									
								
								vendor/golang.org/x/debug/dwarf/typeunit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								vendor/golang.org/x/debug/dwarf/typeunit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| // Copyright 2012 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // Parse the type units stored in a DWARF4 .debug_types section.  Each | ||||
| // type unit defines a single primary type and an 8-byte signature. | ||||
| // Other sections may then use formRefSig8 to refer to the type. | ||||
|  | ||||
| // The typeUnit format is a single type with a signature.  It holds | ||||
| // the same data as a compilation unit. | ||||
| type typeUnit struct { | ||||
| 	unit | ||||
| 	toff  Offset // Offset to signature type within data. | ||||
| 	name  string // Name of .debug_type section. | ||||
| 	cache Type   // Cache the type, nil to start. | ||||
| } | ||||
|  | ||||
| // Parse a .debug_types section. | ||||
| func (d *Data) parseTypes(name string, types []byte) error { | ||||
| 	b := makeBuf(d, unknownFormat{}, name, 0, types) | ||||
| 	for len(b.data) > 0 { | ||||
| 		base := b.off | ||||
| 		dwarf64 := false | ||||
| 		n := b.uint32() | ||||
| 		if n == 0xffffffff { | ||||
| 			n64 := b.uint64() | ||||
| 			if n64 != uint64(uint32(n64)) { | ||||
| 				b.error("type unit length overflow") | ||||
| 				return b.err | ||||
| 			} | ||||
| 			n = uint32(n64) | ||||
| 			dwarf64 = true | ||||
| 		} | ||||
| 		hdroff := b.off | ||||
| 		vers := b.uint16() | ||||
| 		if vers != 4 { | ||||
| 			b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) | ||||
| 			return b.err | ||||
| 		} | ||||
| 		var ao uint32 | ||||
| 		if !dwarf64 { | ||||
| 			ao = b.uint32() | ||||
| 		} else { | ||||
| 			ao64 := b.uint64() | ||||
| 			if ao64 != uint64(uint32(ao64)) { | ||||
| 				b.error("type unit abbrev offset overflow") | ||||
| 				return b.err | ||||
| 			} | ||||
| 			ao = uint32(ao64) | ||||
| 		} | ||||
| 		atable, err := d.parseAbbrev(ao) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		asize := b.uint8() | ||||
| 		sig := b.uint64() | ||||
|  | ||||
| 		var toff uint32 | ||||
| 		if !dwarf64 { | ||||
| 			toff = b.uint32() | ||||
| 		} else { | ||||
| 			to64 := b.uint64() | ||||
| 			if to64 != uint64(uint32(to64)) { | ||||
| 				b.error("type unit type offset overflow") | ||||
| 				return b.err | ||||
| 			} | ||||
| 			toff = uint32(to64) | ||||
| 		} | ||||
|  | ||||
| 		boff := b.off | ||||
| 		d.typeSigs[sig] = &typeUnit{ | ||||
| 			unit: unit{ | ||||
| 				base:   base, | ||||
| 				off:    boff, | ||||
| 				data:   b.bytes(int(Offset(n) - (b.off - hdroff))), | ||||
| 				atable: atable, | ||||
| 				asize:  int(asize), | ||||
| 				vers:   int(vers), | ||||
| 				is64:   dwarf64, | ||||
| 			}, | ||||
| 			toff: Offset(toff), | ||||
| 			name: name, | ||||
| 		} | ||||
| 		if b.err != nil { | ||||
| 			return b.err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Return the type for a type signature. | ||||
| func (d *Data) sigToType(sig uint64) (Type, error) { | ||||
| 	tu := d.typeSigs[sig] | ||||
| 	if tu == nil { | ||||
| 		return nil, fmt.Errorf("no type unit with signature %v", sig) | ||||
| 	} | ||||
| 	if tu.cache != nil { | ||||
| 		return tu.cache, nil | ||||
| 	} | ||||
|  | ||||
| 	b := makeBuf(d, tu, tu.name, tu.off, tu.data) | ||||
| 	r := &typeUnitReader{d: d, tu: tu, b: b} | ||||
| 	t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tu.cache = t | ||||
| 	return t, nil | ||||
| } | ||||
|  | ||||
| // typeUnitReader is a typeReader for a tagTypeUnit. | ||||
| type typeUnitReader struct { | ||||
| 	d   *Data | ||||
| 	tu  *typeUnit | ||||
| 	b   buf | ||||
| 	err error | ||||
| } | ||||
|  | ||||
| // Seek to a new position in the type unit. | ||||
| func (tur *typeUnitReader) Seek(off Offset) { | ||||
| 	tur.err = nil | ||||
| 	doff := off - tur.tu.off | ||||
| 	if doff < 0 || doff >= Offset(len(tur.tu.data)) { | ||||
| 		tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data)) | ||||
| 		return | ||||
| 	} | ||||
| 	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:]) | ||||
| } | ||||
|  | ||||
| // AddressSize returns the size in bytes of addresses in the current type unit. | ||||
| func (tur *typeUnitReader) AddressSize() int { | ||||
| 	return tur.tu.unit.asize | ||||
| } | ||||
|  | ||||
| // Next reads the next Entry from the type unit. | ||||
| func (tur *typeUnitReader) Next() (*Entry, error) { | ||||
| 	if tur.err != nil { | ||||
| 		return nil, tur.err | ||||
| 	} | ||||
| 	if len(tur.tu.data) == 0 { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 	e := tur.b.entry(tur.tu.atable, tur.tu.base) | ||||
| 	if tur.b.err != nil { | ||||
| 		tur.err = tur.b.err | ||||
| 		return nil, tur.err | ||||
| 	} | ||||
| 	return e, nil | ||||
| } | ||||
|  | ||||
| // clone returns a new reader for the type unit. | ||||
| func (tur *typeUnitReader) clone() typeReader { | ||||
| 	return &typeUnitReader{ | ||||
| 		d:  tur.d, | ||||
| 		tu: tur.tu, | ||||
| 		b:  makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // offset returns the current offset. | ||||
| func (tur *typeUnitReader) offset() Offset { | ||||
| 	return tur.b.off | ||||
| } | ||||
							
								
								
									
										90
									
								
								vendor/golang.org/x/debug/dwarf/unit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								vendor/golang.org/x/debug/dwarf/unit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package dwarf | ||||
|  | ||||
| import "strconv" | ||||
|  | ||||
| // DWARF debug info is split into a sequence of compilation units. | ||||
| // Each unit has its own abbreviation table and address size. | ||||
|  | ||||
| type unit struct { | ||||
| 	base   Offset // byte offset of header within the aggregate info | ||||
| 	off    Offset // byte offset of data within the aggregate info | ||||
| 	data   []byte | ||||
| 	atable abbrevTable | ||||
| 	asize  int | ||||
| 	vers   int | ||||
| 	is64   bool // True for 64-bit DWARF format | ||||
| } | ||||
|  | ||||
| // Implement the dataFormat interface. | ||||
|  | ||||
| func (u *unit) version() int { | ||||
| 	return u.vers | ||||
| } | ||||
|  | ||||
| func (u *unit) dwarf64() (bool, bool) { | ||||
| 	return u.is64, true | ||||
| } | ||||
|  | ||||
| func (u *unit) addrsize() int { | ||||
| 	return u.asize | ||||
| } | ||||
|  | ||||
| func (d *Data) parseUnits() ([]unit, error) { | ||||
| 	// Count units. | ||||
| 	nunit := 0 | ||||
| 	b := makeBuf(d, unknownFormat{}, "info", 0, d.info) | ||||
| 	for len(b.data) > 0 { | ||||
| 		len := b.uint32() | ||||
| 		if len == 0xffffffff { | ||||
| 			len64 := b.uint64() | ||||
| 			if len64 != uint64(uint32(len64)) { | ||||
| 				b.error("unit length overflow") | ||||
| 				break | ||||
| 			} | ||||
| 			len = uint32(len64) | ||||
| 		} | ||||
| 		b.skip(int(len)) | ||||
| 		nunit++ | ||||
| 	} | ||||
| 	if b.err != nil { | ||||
| 		return nil, b.err | ||||
| 	} | ||||
|  | ||||
| 	// Again, this time writing them down. | ||||
| 	b = makeBuf(d, unknownFormat{}, "info", 0, d.info) | ||||
| 	units := make([]unit, nunit) | ||||
| 	for i := range units { | ||||
| 		u := &units[i] | ||||
| 		u.base = b.off | ||||
| 		n := b.uint32() | ||||
| 		if n == 0xffffffff { | ||||
| 			u.is64 = true | ||||
| 			n = uint32(b.uint64()) | ||||
| 		} | ||||
| 		vers := b.uint16() | ||||
| 		if vers != 2 && vers != 3 && vers != 4 { | ||||
| 			b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) | ||||
| 			break | ||||
| 		} | ||||
| 		u.vers = int(vers) | ||||
| 		atable, err := d.parseAbbrev(b.uint32()) | ||||
| 		if err != nil { | ||||
| 			if b.err == nil { | ||||
| 				b.err = err | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
| 		u.atable = atable | ||||
| 		u.asize = int(b.uint8()) | ||||
| 		u.off = b.off | ||||
| 		u.data = b.bytes(int(n - (2 + 4 + 1))) | ||||
| 	} | ||||
| 	if b.err != nil { | ||||
| 		return nil, b.err | ||||
| 	} | ||||
| 	return units, nil | ||||
| } | ||||
							
								
								
									
										1521
									
								
								vendor/golang.org/x/debug/elf/elf.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1521
									
								
								vendor/golang.org/x/debug/elf/elf.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										829
									
								
								vendor/golang.org/x/debug/elf/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										829
									
								
								vendor/golang.org/x/debug/elf/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,829 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Package elf implements access to ELF object files. | ||||
| package elf | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
|  | ||||
| 	"golang.org/x/debug/dwarf" | ||||
| ) | ||||
|  | ||||
| // TODO: error reporting detail | ||||
|  | ||||
| /* | ||||
|  * Internal ELF representation | ||||
|  */ | ||||
|  | ||||
| // A FileHeader represents an ELF file header. | ||||
| type FileHeader struct { | ||||
| 	Class      Class | ||||
| 	Data       Data | ||||
| 	Version    Version | ||||
| 	OSABI      OSABI | ||||
| 	ABIVersion uint8 | ||||
| 	ByteOrder  binary.ByteOrder | ||||
| 	Type       Type | ||||
| 	Machine    Machine | ||||
| 	Entry      uint64 | ||||
| } | ||||
|  | ||||
| // A File represents an open ELF file. | ||||
| type File struct { | ||||
| 	FileHeader | ||||
| 	Sections  []*Section | ||||
| 	Progs     []*Prog | ||||
| 	closer    io.Closer | ||||
| 	gnuNeed   []verneed | ||||
| 	gnuVersym []byte | ||||
| } | ||||
|  | ||||
| // A SectionHeader represents a single ELF section header. | ||||
| type SectionHeader struct { | ||||
| 	Name      string | ||||
| 	Type      SectionType | ||||
| 	Flags     SectionFlag | ||||
| 	Addr      uint64 | ||||
| 	Offset    uint64 | ||||
| 	Size      uint64 | ||||
| 	Link      uint32 | ||||
| 	Info      uint32 | ||||
| 	Addralign uint64 | ||||
| 	Entsize   uint64 | ||||
| } | ||||
|  | ||||
| // A Section represents a single section in an ELF file. | ||||
| type Section struct { | ||||
| 	SectionHeader | ||||
|  | ||||
| 	// Embed ReaderAt for ReadAt method. | ||||
| 	// Do not embed SectionReader directly | ||||
| 	// to avoid having Read and Seek. | ||||
| 	// If a client wants Read and Seek it must use | ||||
| 	// Open() to avoid fighting over the seek offset | ||||
| 	// with other clients. | ||||
| 	io.ReaderAt | ||||
| 	sr *io.SectionReader | ||||
| } | ||||
|  | ||||
| // Data reads and returns the contents of the ELF section. | ||||
| func (s *Section) Data() ([]byte, error) { | ||||
| 	dat := make([]byte, s.sr.Size()) | ||||
| 	n, err := s.sr.ReadAt(dat, 0) | ||||
| 	if n == len(dat) { | ||||
| 		err = nil | ||||
| 	} | ||||
| 	return dat[0:n], err | ||||
| } | ||||
|  | ||||
| // stringTable reads and returns the string table given by the | ||||
| // specified link value. | ||||
| func (f *File) stringTable(link uint32) ([]byte, error) { | ||||
| 	if link <= 0 || link >= uint32(len(f.Sections)) { | ||||
| 		return nil, errors.New("section has invalid string table link") | ||||
| 	} | ||||
| 	return f.Sections[link].Data() | ||||
| } | ||||
|  | ||||
| // Open returns a new ReadSeeker reading the ELF section. | ||||
| func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } | ||||
|  | ||||
| // A ProgHeader represents a single ELF program header. | ||||
| type ProgHeader struct { | ||||
| 	Type   ProgType | ||||
| 	Flags  ProgFlag | ||||
| 	Off    uint64 | ||||
| 	Vaddr  uint64 | ||||
| 	Paddr  uint64 | ||||
| 	Filesz uint64 | ||||
| 	Memsz  uint64 | ||||
| 	Align  uint64 | ||||
| } | ||||
|  | ||||
| // A Prog represents a single ELF program header in an ELF binary. | ||||
| type Prog struct { | ||||
| 	ProgHeader | ||||
|  | ||||
| 	// Embed ReaderAt for ReadAt method. | ||||
| 	// Do not embed SectionReader directly | ||||
| 	// to avoid having Read and Seek. | ||||
| 	// If a client wants Read and Seek it must use | ||||
| 	// Open() to avoid fighting over the seek offset | ||||
| 	// with other clients. | ||||
| 	io.ReaderAt | ||||
| 	sr *io.SectionReader | ||||
| } | ||||
|  | ||||
| // Open returns a new ReadSeeker reading the ELF program body. | ||||
| func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } | ||||
|  | ||||
| // A Symbol represents an entry in an ELF symbol table section. | ||||
| type Symbol struct { | ||||
| 	Name        string | ||||
| 	Info, Other byte | ||||
| 	Section     SectionIndex | ||||
| 	Value, Size uint64 | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * ELF reader | ||||
|  */ | ||||
|  | ||||
| type FormatError struct { | ||||
| 	off int64 | ||||
| 	msg string | ||||
| 	val interface{} | ||||
| } | ||||
|  | ||||
| func (e *FormatError) Error() string { | ||||
| 	msg := e.msg | ||||
| 	if e.val != nil { | ||||
| 		msg += fmt.Sprintf(" '%v' ", e.val) | ||||
| 	} | ||||
| 	msg += fmt.Sprintf("in record at byte %#x", e.off) | ||||
| 	return msg | ||||
| } | ||||
|  | ||||
| // Open opens the named file using os.Open and prepares it for use as an ELF binary. | ||||
| func Open(name string) (*File, error) { | ||||
| 	f, err := os.Open(name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ff, err := NewFile(f) | ||||
| 	if err != nil { | ||||
| 		f.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ff.closer = f | ||||
| 	return ff, nil | ||||
| } | ||||
|  | ||||
| // Close closes the File. | ||||
| // If the File was created using NewFile directly instead of Open, | ||||
| // Close has no effect. | ||||
| func (f *File) Close() error { | ||||
| 	var err error | ||||
| 	if f.closer != nil { | ||||
| 		err = f.closer.Close() | ||||
| 		f.closer = nil | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // SectionByType returns the first section in f with the | ||||
| // given type, or nil if there is no such section. | ||||
| func (f *File) SectionByType(typ SectionType) *Section { | ||||
| 	for _, s := range f.Sections { | ||||
| 		if s.Type == typ { | ||||
| 			return s | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // NewFile creates a new File for accessing an ELF binary in an underlying reader. | ||||
| // The ELF binary is expected to start at position 0 in the ReaderAt. | ||||
| func NewFile(r io.ReaderAt) (*File, error) { | ||||
| 	sr := io.NewSectionReader(r, 0, 1<<63-1) | ||||
| 	// Read and decode ELF identifier | ||||
| 	var ident [16]uint8 | ||||
| 	if _, err := r.ReadAt(ident[0:], 0); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { | ||||
| 		return nil, &FormatError{0, "bad magic number", ident[0:4]} | ||||
| 	} | ||||
|  | ||||
| 	f := new(File) | ||||
| 	f.Class = Class(ident[EI_CLASS]) | ||||
| 	switch f.Class { | ||||
| 	case ELFCLASS32: | ||||
| 	case ELFCLASS64: | ||||
| 		// ok | ||||
| 	default: | ||||
| 		return nil, &FormatError{0, "unknown ELF class", f.Class} | ||||
| 	} | ||||
|  | ||||
| 	f.Data = Data(ident[EI_DATA]) | ||||
| 	switch f.Data { | ||||
| 	case ELFDATA2LSB: | ||||
| 		f.ByteOrder = binary.LittleEndian | ||||
| 	case ELFDATA2MSB: | ||||
| 		f.ByteOrder = binary.BigEndian | ||||
| 	default: | ||||
| 		return nil, &FormatError{0, "unknown ELF data encoding", f.Data} | ||||
| 	} | ||||
|  | ||||
| 	f.Version = Version(ident[EI_VERSION]) | ||||
| 	if f.Version != EV_CURRENT { | ||||
| 		return nil, &FormatError{0, "unknown ELF version", f.Version} | ||||
| 	} | ||||
|  | ||||
| 	f.OSABI = OSABI(ident[EI_OSABI]) | ||||
| 	f.ABIVersion = ident[EI_ABIVERSION] | ||||
|  | ||||
| 	// Read ELF file header | ||||
| 	var phoff int64 | ||||
| 	var phentsize, phnum int | ||||
| 	var shoff int64 | ||||
| 	var shentsize, shnum, shstrndx int | ||||
| 	shstrndx = -1 | ||||
| 	switch f.Class { | ||||
| 	case ELFCLASS32: | ||||
| 		hdr := new(Header32) | ||||
| 		sr.Seek(0, os.SEEK_SET) | ||||
| 		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		f.Type = Type(hdr.Type) | ||||
| 		f.Machine = Machine(hdr.Machine) | ||||
| 		f.Entry = uint64(hdr.Entry) | ||||
| 		if v := Version(hdr.Version); v != f.Version { | ||||
| 			return nil, &FormatError{0, "mismatched ELF version", v} | ||||
| 		} | ||||
| 		phoff = int64(hdr.Phoff) | ||||
| 		phentsize = int(hdr.Phentsize) | ||||
| 		phnum = int(hdr.Phnum) | ||||
| 		shoff = int64(hdr.Shoff) | ||||
| 		shentsize = int(hdr.Shentsize) | ||||
| 		shnum = int(hdr.Shnum) | ||||
| 		shstrndx = int(hdr.Shstrndx) | ||||
| 	case ELFCLASS64: | ||||
| 		hdr := new(Header64) | ||||
| 		sr.Seek(0, os.SEEK_SET) | ||||
| 		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		f.Type = Type(hdr.Type) | ||||
| 		f.Machine = Machine(hdr.Machine) | ||||
| 		f.Entry = uint64(hdr.Entry) | ||||
| 		if v := Version(hdr.Version); v != f.Version { | ||||
| 			return nil, &FormatError{0, "mismatched ELF version", v} | ||||
| 		} | ||||
| 		phoff = int64(hdr.Phoff) | ||||
| 		phentsize = int(hdr.Phentsize) | ||||
| 		phnum = int(hdr.Phnum) | ||||
| 		shoff = int64(hdr.Shoff) | ||||
| 		shentsize = int(hdr.Shentsize) | ||||
| 		shnum = int(hdr.Shnum) | ||||
| 		shstrndx = int(hdr.Shstrndx) | ||||
| 	} | ||||
|  | ||||
| 	if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) { | ||||
| 		return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} | ||||
| 	} | ||||
|  | ||||
| 	// Read program headers | ||||
| 	f.Progs = make([]*Prog, phnum) | ||||
| 	for i := 0; i < phnum; i++ { | ||||
| 		off := phoff + int64(i)*int64(phentsize) | ||||
| 		sr.Seek(off, os.SEEK_SET) | ||||
| 		p := new(Prog) | ||||
| 		switch f.Class { | ||||
| 		case ELFCLASS32: | ||||
| 			ph := new(Prog32) | ||||
| 			if err := binary.Read(sr, f.ByteOrder, ph); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			p.ProgHeader = ProgHeader{ | ||||
| 				Type:   ProgType(ph.Type), | ||||
| 				Flags:  ProgFlag(ph.Flags), | ||||
| 				Off:    uint64(ph.Off), | ||||
| 				Vaddr:  uint64(ph.Vaddr), | ||||
| 				Paddr:  uint64(ph.Paddr), | ||||
| 				Filesz: uint64(ph.Filesz), | ||||
| 				Memsz:  uint64(ph.Memsz), | ||||
| 				Align:  uint64(ph.Align), | ||||
| 			} | ||||
| 		case ELFCLASS64: | ||||
| 			ph := new(Prog64) | ||||
| 			if err := binary.Read(sr, f.ByteOrder, ph); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			p.ProgHeader = ProgHeader{ | ||||
| 				Type:   ProgType(ph.Type), | ||||
| 				Flags:  ProgFlag(ph.Flags), | ||||
| 				Off:    uint64(ph.Off), | ||||
| 				Vaddr:  uint64(ph.Vaddr), | ||||
| 				Paddr:  uint64(ph.Paddr), | ||||
| 				Filesz: uint64(ph.Filesz), | ||||
| 				Memsz:  uint64(ph.Memsz), | ||||
| 				Align:  uint64(ph.Align), | ||||
| 			} | ||||
| 		} | ||||
| 		p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) | ||||
| 		p.ReaderAt = p.sr | ||||
| 		f.Progs[i] = p | ||||
| 	} | ||||
|  | ||||
| 	// Read section headers | ||||
| 	f.Sections = make([]*Section, shnum) | ||||
| 	names := make([]uint32, shnum) | ||||
| 	for i := 0; i < shnum; i++ { | ||||
| 		off := shoff + int64(i)*int64(shentsize) | ||||
| 		sr.Seek(off, os.SEEK_SET) | ||||
| 		s := new(Section) | ||||
| 		switch f.Class { | ||||
| 		case ELFCLASS32: | ||||
| 			sh := new(Section32) | ||||
| 			if err := binary.Read(sr, f.ByteOrder, sh); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			names[i] = sh.Name | ||||
| 			s.SectionHeader = SectionHeader{ | ||||
| 				Type:      SectionType(sh.Type), | ||||
| 				Flags:     SectionFlag(sh.Flags), | ||||
| 				Addr:      uint64(sh.Addr), | ||||
| 				Offset:    uint64(sh.Off), | ||||
| 				Size:      uint64(sh.Size), | ||||
| 				Link:      uint32(sh.Link), | ||||
| 				Info:      uint32(sh.Info), | ||||
| 				Addralign: uint64(sh.Addralign), | ||||
| 				Entsize:   uint64(sh.Entsize), | ||||
| 			} | ||||
| 		case ELFCLASS64: | ||||
| 			sh := new(Section64) | ||||
| 			if err := binary.Read(sr, f.ByteOrder, sh); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			names[i] = sh.Name | ||||
| 			s.SectionHeader = SectionHeader{ | ||||
| 				Type:      SectionType(sh.Type), | ||||
| 				Flags:     SectionFlag(sh.Flags), | ||||
| 				Offset:    uint64(sh.Off), | ||||
| 				Size:      uint64(sh.Size), | ||||
| 				Addr:      uint64(sh.Addr), | ||||
| 				Link:      uint32(sh.Link), | ||||
| 				Info:      uint32(sh.Info), | ||||
| 				Addralign: uint64(sh.Addralign), | ||||
| 				Entsize:   uint64(sh.Entsize), | ||||
| 			} | ||||
| 		} | ||||
| 		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size)) | ||||
| 		s.ReaderAt = s.sr | ||||
| 		f.Sections[i] = s | ||||
| 	} | ||||
|  | ||||
| 	if len(f.Sections) == 0 { | ||||
| 		return f, nil | ||||
| 	} | ||||
|  | ||||
| 	// Load section header string table. | ||||
| 	shstrtab, err := f.Sections[shstrndx].Data() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for i, s := range f.Sections { | ||||
| 		var ok bool | ||||
| 		s.Name, ok = getString(shstrtab, int(names[i])) | ||||
| 		if !ok { | ||||
| 			return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return f, nil | ||||
| } | ||||
|  | ||||
| // getSymbols returns a slice of Symbols from parsing the symbol table | ||||
| // with the given type, along with the associated string table. | ||||
| func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { | ||||
| 	switch f.Class { | ||||
| 	case ELFCLASS64: | ||||
| 		return f.getSymbols64(typ) | ||||
|  | ||||
| 	case ELFCLASS32: | ||||
| 		return f.getSymbols32(typ) | ||||
| 	} | ||||
|  | ||||
| 	return nil, nil, errors.New("not implemented") | ||||
| } | ||||
|  | ||||
| func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { | ||||
| 	symtabSection := f.SectionByType(typ) | ||||
| 	if symtabSection == nil { | ||||
| 		return nil, nil, errors.New("no symbol section") | ||||
| 	} | ||||
|  | ||||
| 	data, err := symtabSection.Data() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, errors.New("cannot load symbol section") | ||||
| 	} | ||||
| 	symtab := bytes.NewReader(data) | ||||
| 	if symtab.Len()%Sym32Size != 0 { | ||||
| 		return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") | ||||
| 	} | ||||
|  | ||||
| 	strdata, err := f.stringTable(symtabSection.Link) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, errors.New("cannot load string table section") | ||||
| 	} | ||||
|  | ||||
| 	// The first entry is all zeros. | ||||
| 	var skip [Sym32Size]byte | ||||
| 	symtab.Read(skip[:]) | ||||
|  | ||||
| 	symbols := make([]Symbol, symtab.Len()/Sym32Size) | ||||
|  | ||||
| 	i := 0 | ||||
| 	var sym Sym32 | ||||
| 	for symtab.Len() > 0 { | ||||
| 		binary.Read(symtab, f.ByteOrder, &sym) | ||||
| 		str, _ := getString(strdata, int(sym.Name)) | ||||
| 		symbols[i].Name = str | ||||
| 		symbols[i].Info = sym.Info | ||||
| 		symbols[i].Other = sym.Other | ||||
| 		symbols[i].Section = SectionIndex(sym.Shndx) | ||||
| 		symbols[i].Value = uint64(sym.Value) | ||||
| 		symbols[i].Size = uint64(sym.Size) | ||||
| 		i++ | ||||
| 	} | ||||
|  | ||||
| 	return symbols, strdata, nil | ||||
| } | ||||
|  | ||||
| func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { | ||||
| 	symtabSection := f.SectionByType(typ) | ||||
| 	if symtabSection == nil { | ||||
| 		return nil, nil, errors.New("no symbol section") | ||||
| 	} | ||||
|  | ||||
| 	data, err := symtabSection.Data() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, errors.New("cannot load symbol section") | ||||
| 	} | ||||
| 	symtab := bytes.NewReader(data) | ||||
| 	if symtab.Len()%Sym64Size != 0 { | ||||
| 		return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") | ||||
| 	} | ||||
|  | ||||
| 	strdata, err := f.stringTable(symtabSection.Link) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, errors.New("cannot load string table section") | ||||
| 	} | ||||
|  | ||||
| 	// The first entry is all zeros. | ||||
| 	var skip [Sym64Size]byte | ||||
| 	symtab.Read(skip[:]) | ||||
|  | ||||
| 	symbols := make([]Symbol, symtab.Len()/Sym64Size) | ||||
|  | ||||
| 	i := 0 | ||||
| 	var sym Sym64 | ||||
| 	for symtab.Len() > 0 { | ||||
| 		binary.Read(symtab, f.ByteOrder, &sym) | ||||
| 		str, _ := getString(strdata, int(sym.Name)) | ||||
| 		symbols[i].Name = str | ||||
| 		symbols[i].Info = sym.Info | ||||
| 		symbols[i].Other = sym.Other | ||||
| 		symbols[i].Section = SectionIndex(sym.Shndx) | ||||
| 		symbols[i].Value = sym.Value | ||||
| 		symbols[i].Size = sym.Size | ||||
| 		i++ | ||||
| 	} | ||||
|  | ||||
| 	return symbols, strdata, nil | ||||
| } | ||||
|  | ||||
| // getString extracts a string from an ELF string table. | ||||
| func getString(section []byte, start int) (string, bool) { | ||||
| 	if start < 0 || start >= len(section) { | ||||
| 		return "", false | ||||
| 	} | ||||
|  | ||||
| 	for end := start; end < len(section); end++ { | ||||
| 		if section[end] == 0 { | ||||
| 			return string(section[start:end]), true | ||||
| 		} | ||||
| 	} | ||||
| 	return "", false | ||||
| } | ||||
|  | ||||
| // Section returns a section with the given name, or nil if no such | ||||
| // section exists. | ||||
| func (f *File) Section(name string) *Section { | ||||
| 	for _, s := range f.Sections { | ||||
| 		if s.Name == name { | ||||
| 			return s | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // applyRelocations applies relocations to dst. rels is a relocations section | ||||
| // in RELA format. | ||||
| func (f *File) applyRelocations(dst []byte, rels []byte) error { | ||||
| 	if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 { | ||||
| 		return f.applyRelocationsAMD64(dst, rels) | ||||
| 	} | ||||
|  | ||||
| 	return errors.New("not implemented") | ||||
| } | ||||
|  | ||||
| func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { | ||||
| 	if len(rels)%Sym64Size != 0 { | ||||
| 		return errors.New("length of relocation section is not a multiple of Sym64Size") | ||||
| 	} | ||||
|  | ||||
| 	symbols, _, err := f.getSymbols(SHT_SYMTAB) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	b := bytes.NewReader(rels) | ||||
| 	var rela Rela64 | ||||
|  | ||||
| 	for b.Len() > 0 { | ||||
| 		binary.Read(b, f.ByteOrder, &rela) | ||||
| 		symNo := rela.Info >> 32 | ||||
| 		t := R_X86_64(rela.Info & 0xffff) | ||||
|  | ||||
| 		if symNo == 0 || symNo > uint64(len(symbols)) { | ||||
| 			continue | ||||
| 		} | ||||
| 		sym := &symbols[symNo-1] | ||||
| 		if SymType(sym.Info&0xf) != STT_SECTION { | ||||
| 			// We don't handle non-section relocations for now. | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		switch t { | ||||
| 		case R_X86_64_64: | ||||
| 			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) | ||||
| 		case R_X86_64_32: | ||||
| 			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (f *File) DWARF() (*dwarf.Data, error) { | ||||
| 	// There are many other DWARF sections, but these | ||||
| 	// are the required ones, and the debug/dwarf package | ||||
| 	// does not use the others, so don't bother loading them. | ||||
| 	// r: added line. | ||||
| 	var names = [...]string{"abbrev", "frame", "info", "line", "str"} | ||||
| 	var dat [len(names)][]byte | ||||
| 	for i, name := range names { | ||||
| 		name = ".debug_" + name | ||||
| 		s := f.Section(name) | ||||
| 		if s == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		b, err := s.Data() | ||||
| 		if err != nil && uint64(len(b)) < s.Size { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		dat[i] = b | ||||
| 	} | ||||
|  | ||||
| 	// If there's a relocation table for .debug_info, we have to process it | ||||
| 	// now otherwise the data in .debug_info is invalid for x86-64 objects. | ||||
| 	rela := f.Section(".rela.debug_info") | ||||
| 	if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 { | ||||
| 		data, err := rela.Data() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		err = f.applyRelocations(dat[2], data) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	abbrev, frame, info, line, str := dat[0], dat[1], dat[2], dat[3], dat[4] | ||||
| 	d, err := dwarf.New(abbrev, nil, frame, info, line, nil, nil, str) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Look for DWARF4 .debug_types sections. | ||||
| 	for i, s := range f.Sections { | ||||
| 		if s.Name == ".debug_types" { | ||||
| 			b, err := s.Data() | ||||
| 			if err != nil && uint64(len(b)) < s.Size { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			for _, r := range f.Sections { | ||||
| 				if r.Type != SHT_RELA && r.Type != SHT_REL { | ||||
| 					continue | ||||
| 				} | ||||
| 				if int(r.Info) != i { | ||||
| 					continue | ||||
| 				} | ||||
| 				rd, err := r.Data() | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				err = f.applyRelocations(b, rd) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			err = d.AddTypes(fmt.Sprintf("types-%d", i), b) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return d, nil | ||||
| } | ||||
|  | ||||
| // Symbols returns the symbol table for f. | ||||
| // | ||||
| // For compatibility with Go 1.0, Symbols omits the null symbol at index 0. | ||||
| // After retrieving the symbols as symtab, an externally supplied index x | ||||
| // corresponds to symtab[x-1], not symtab[x]. | ||||
| func (f *File) Symbols() ([]Symbol, error) { | ||||
| 	sym, _, err := f.getSymbols(SHT_SYMTAB) | ||||
| 	return sym, err | ||||
| } | ||||
|  | ||||
| type ImportedSymbol struct { | ||||
| 	Name    string | ||||
| 	Version string | ||||
| 	Library string | ||||
| } | ||||
|  | ||||
| // ImportedSymbols returns the names of all symbols | ||||
| // referred to by the binary f that are expected to be | ||||
| // satisfied by other libraries at dynamic load time. | ||||
| // It does not return weak symbols. | ||||
| func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { | ||||
| 	sym, str, err := f.getSymbols(SHT_DYNSYM) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	f.gnuVersionInit(str) | ||||
| 	var all []ImportedSymbol | ||||
| 	for i, s := range sym { | ||||
| 		if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { | ||||
| 			all = append(all, ImportedSymbol{Name: s.Name}) | ||||
| 			f.gnuVersion(i, &all[len(all)-1]) | ||||
| 		} | ||||
| 	} | ||||
| 	return all, nil | ||||
| } | ||||
|  | ||||
| type verneed struct { | ||||
| 	File string | ||||
| 	Name string | ||||
| } | ||||
|  | ||||
| // gnuVersionInit parses the GNU version tables | ||||
| // for use by calls to gnuVersion. | ||||
| func (f *File) gnuVersionInit(str []byte) { | ||||
| 	// Accumulate verneed information. | ||||
| 	vn := f.SectionByType(SHT_GNU_VERNEED) | ||||
| 	if vn == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	d, _ := vn.Data() | ||||
|  | ||||
| 	var need []verneed | ||||
| 	i := 0 | ||||
| 	for { | ||||
| 		if i+16 > len(d) { | ||||
| 			break | ||||
| 		} | ||||
| 		vers := f.ByteOrder.Uint16(d[i : i+2]) | ||||
| 		if vers != 1 { | ||||
| 			break | ||||
| 		} | ||||
| 		cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) | ||||
| 		fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) | ||||
| 		aux := f.ByteOrder.Uint32(d[i+8 : i+12]) | ||||
| 		next := f.ByteOrder.Uint32(d[i+12 : i+16]) | ||||
| 		file, _ := getString(str, int(fileoff)) | ||||
|  | ||||
| 		var name string | ||||
| 		j := i + int(aux) | ||||
| 		for c := 0; c < int(cnt); c++ { | ||||
| 			if j+16 > len(d) { | ||||
| 				break | ||||
| 			} | ||||
| 			// hash := f.ByteOrder.Uint32(d[j:j+4]) | ||||
| 			// flags := f.ByteOrder.Uint16(d[j+4:j+6]) | ||||
| 			other := f.ByteOrder.Uint16(d[j+6 : j+8]) | ||||
| 			nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) | ||||
| 			next := f.ByteOrder.Uint32(d[j+12 : j+16]) | ||||
| 			name, _ = getString(str, int(nameoff)) | ||||
| 			ndx := int(other) | ||||
| 			if ndx >= len(need) { | ||||
| 				a := make([]verneed, 2*(ndx+1)) | ||||
| 				copy(a, need) | ||||
| 				need = a | ||||
| 			} | ||||
|  | ||||
| 			need[ndx] = verneed{file, name} | ||||
| 			if next == 0 { | ||||
| 				break | ||||
| 			} | ||||
| 			j += int(next) | ||||
| 		} | ||||
|  | ||||
| 		if next == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 		i += int(next) | ||||
| 	} | ||||
|  | ||||
| 	// Versym parallels symbol table, indexing into verneed. | ||||
| 	vs := f.SectionByType(SHT_GNU_VERSYM) | ||||
| 	if vs == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	d, _ = vs.Data() | ||||
|  | ||||
| 	f.gnuNeed = need | ||||
| 	f.gnuVersym = d | ||||
| } | ||||
|  | ||||
| // gnuVersion adds Library and Version information to sym, | ||||
| // which came from offset i of the symbol table. | ||||
| func (f *File) gnuVersion(i int, sym *ImportedSymbol) { | ||||
| 	// Each entry is two bytes. | ||||
| 	i = (i + 1) * 2 | ||||
| 	if i >= len(f.gnuVersym) { | ||||
| 		return | ||||
| 	} | ||||
| 	j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) | ||||
| 	if j < 2 || j >= len(f.gnuNeed) { | ||||
| 		return | ||||
| 	} | ||||
| 	n := &f.gnuNeed[j] | ||||
| 	sym.Library = n.File | ||||
| 	sym.Version = n.Name | ||||
| } | ||||
|  | ||||
| // ImportedLibraries returns the names of all libraries | ||||
| // referred to by the binary f that are expected to be | ||||
| // linked with the binary at dynamic link time. | ||||
| func (f *File) ImportedLibraries() ([]string, error) { | ||||
| 	return f.DynString(DT_NEEDED) | ||||
| } | ||||
|  | ||||
| // DynString returns the strings listed for the given tag in the file's dynamic | ||||
| // section. | ||||
| // | ||||
| // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or | ||||
| // DT_RUNPATH. | ||||
| func (f *File) DynString(tag DynTag) ([]string, error) { | ||||
| 	switch tag { | ||||
| 	case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("non-string-valued tag %v", tag) | ||||
| 	} | ||||
| 	ds := f.SectionByType(SHT_DYNAMIC) | ||||
| 	if ds == nil { | ||||
| 		// not dynamic, so no libraries | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 	d, err := ds.Data() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	str, err := f.stringTable(ds.Link) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var all []string | ||||
| 	for len(d) > 0 { | ||||
| 		var t DynTag | ||||
| 		var v uint64 | ||||
| 		switch f.Class { | ||||
| 		case ELFCLASS32: | ||||
| 			t = DynTag(f.ByteOrder.Uint32(d[0:4])) | ||||
| 			v = uint64(f.ByteOrder.Uint32(d[4:8])) | ||||
| 			d = d[8:] | ||||
| 		case ELFCLASS64: | ||||
| 			t = DynTag(f.ByteOrder.Uint64(d[0:8])) | ||||
| 			v = f.ByteOrder.Uint64(d[8:16]) | ||||
| 			d = d[16:] | ||||
| 		} | ||||
| 		if t == tag { | ||||
| 			s, ok := getString(str, int(v)) | ||||
| 			if ok { | ||||
| 				all = append(all, s) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return all, nil | ||||
| } | ||||
							
								
								
									
										146
									
								
								vendor/golang.org/x/debug/macho/fat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								vendor/golang.org/x/debug/macho/fat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| // Copyright 2014 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package macho | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| // A FatFile is a Mach-O universal binary that contains at least one architecture. | ||||
| type FatFile struct { | ||||
| 	Magic  uint32 | ||||
| 	Arches []FatArch | ||||
| 	closer io.Closer | ||||
| } | ||||
|  | ||||
| // A FatArchHeader represents a fat header for a specific image architecture. | ||||
| type FatArchHeader struct { | ||||
| 	Cpu    Cpu | ||||
| 	SubCpu uint32 | ||||
| 	Offset uint32 | ||||
| 	Size   uint32 | ||||
| 	Align  uint32 | ||||
| } | ||||
|  | ||||
| const fatArchHeaderSize = 5 * 4 | ||||
|  | ||||
| // A FatArch is a Mach-O File inside a FatFile. | ||||
| type FatArch struct { | ||||
| 	FatArchHeader | ||||
| 	*File | ||||
| } | ||||
|  | ||||
| // ErrNotFat is returned from NewFatFile or OpenFat when the file is not a | ||||
| // universal binary but may be a thin binary, based on its magic number. | ||||
| var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil} | ||||
|  | ||||
| // NewFatFile creates a new FatFile for accessing all the Mach-O images in a | ||||
| // universal binary. The Mach-O binary is expected to start at position 0 in | ||||
| // the ReaderAt. | ||||
| func NewFatFile(r io.ReaderAt) (*FatFile, error) { | ||||
| 	var ff FatFile | ||||
| 	sr := io.NewSectionReader(r, 0, 1<<63-1) | ||||
|  | ||||
| 	// Read the fat_header struct, which is always in big endian. | ||||
| 	// Start with the magic number. | ||||
| 	err := binary.Read(sr, binary.BigEndian, &ff.Magic) | ||||
| 	if err != nil { | ||||
| 		return nil, &FormatError{0, "error reading magic number", nil} | ||||
| 	} else if ff.Magic != MagicFat { | ||||
| 		// See if this is a Mach-O file via its magic number. The magic | ||||
| 		// must be converted to little endian first though. | ||||
| 		var buf [4]byte | ||||
| 		binary.BigEndian.PutUint32(buf[:], ff.Magic) | ||||
| 		leMagic := binary.LittleEndian.Uint32(buf[:]) | ||||
| 		if leMagic == Magic32 || leMagic == Magic64 { | ||||
| 			return nil, ErrNotFat | ||||
| 		} else { | ||||
| 			return nil, &FormatError{0, "invalid magic number", nil} | ||||
| 		} | ||||
| 	} | ||||
| 	offset := int64(4) | ||||
|  | ||||
| 	// Read the number of FatArchHeaders that come after the fat_header. | ||||
| 	var narch uint32 | ||||
| 	err = binary.Read(sr, binary.BigEndian, &narch) | ||||
| 	if err != nil { | ||||
| 		return nil, &FormatError{offset, "invalid fat_header", nil} | ||||
| 	} | ||||
| 	offset += 4 | ||||
|  | ||||
| 	if narch < 1 { | ||||
| 		return nil, &FormatError{offset, "file contains no images", nil} | ||||
| 	} | ||||
|  | ||||
| 	// Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure | ||||
| 	// there are not duplicate architectures. | ||||
| 	seenArches := make(map[uint64]bool, narch) | ||||
| 	// Make sure that all images are for the same MH_ type. | ||||
| 	var machoType Type | ||||
|  | ||||
| 	// Following the fat_header comes narch fat_arch structs that index | ||||
| 	// Mach-O images further in the file. | ||||
| 	ff.Arches = make([]FatArch, narch) | ||||
| 	for i := uint32(0); i < narch; i++ { | ||||
| 		fa := &ff.Arches[i] | ||||
| 		err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader) | ||||
| 		if err != nil { | ||||
| 			return nil, &FormatError{offset, "invalid fat_arch header", nil} | ||||
| 		} | ||||
| 		offset += fatArchHeaderSize | ||||
|  | ||||
| 		fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size)) | ||||
| 		fa.File, err = NewFile(fr) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		// Make sure the architecture for this image is not duplicate. | ||||
| 		seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu) | ||||
| 		if o, k := seenArches[seenArch]; o || k { | ||||
| 			return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil} | ||||
| 		} | ||||
| 		seenArches[seenArch] = true | ||||
|  | ||||
| 		// Make sure the Mach-O type matches that of the first image. | ||||
| 		if i == 0 { | ||||
| 			machoType = fa.Type | ||||
| 		} else { | ||||
| 			if fa.Type != machoType { | ||||
| 				return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &ff, nil | ||||
| } | ||||
|  | ||||
| // OpenFat opens the named file using os.Open and prepares it for use as a Mach-O | ||||
| // universal binary. | ||||
| func OpenFat(name string) (ff *FatFile, err error) { | ||||
| 	f, err := os.Open(name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ff, err = NewFatFile(f) | ||||
| 	if err != nil { | ||||
| 		f.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ff.closer = f | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (ff *FatFile) Close() error { | ||||
| 	var err error | ||||
| 	if ff.closer != nil { | ||||
| 		err = ff.closer.Close() | ||||
| 		ff.closer = nil | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										525
									
								
								vendor/golang.org/x/debug/macho/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										525
									
								
								vendor/golang.org/x/debug/macho/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,525 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Package macho implements access to Mach-O object files. | ||||
| package macho | ||||
|  | ||||
| // High level access to low level data structures. | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
|  | ||||
| 	"golang.org/x/debug/dwarf" | ||||
| ) | ||||
|  | ||||
| // A File represents an open Mach-O file. | ||||
| type File struct { | ||||
| 	FileHeader | ||||
| 	ByteOrder binary.ByteOrder | ||||
| 	Loads     []Load | ||||
| 	Sections  []*Section | ||||
|  | ||||
| 	Symtab   *Symtab | ||||
| 	Dysymtab *Dysymtab | ||||
|  | ||||
| 	closer io.Closer | ||||
| } | ||||
|  | ||||
| // A Load represents any Mach-O load command. | ||||
| type Load interface { | ||||
| 	Raw() []byte | ||||
| } | ||||
|  | ||||
| // A LoadBytes is the uninterpreted bytes of a Mach-O load command. | ||||
| type LoadBytes []byte | ||||
|  | ||||
| func (b LoadBytes) Raw() []byte { return b } | ||||
|  | ||||
| // A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command. | ||||
| type SegmentHeader struct { | ||||
| 	Cmd     LoadCmd | ||||
| 	Len     uint32 | ||||
| 	Name    string | ||||
| 	Addr    uint64 | ||||
| 	Memsz   uint64 | ||||
| 	Offset  uint64 | ||||
| 	Filesz  uint64 | ||||
| 	Maxprot uint32 | ||||
| 	Prot    uint32 | ||||
| 	Nsect   uint32 | ||||
| 	Flag    uint32 | ||||
| } | ||||
|  | ||||
| // A Segment represents a Mach-O 32-bit or 64-bit load segment command. | ||||
| type Segment struct { | ||||
| 	LoadBytes | ||||
| 	SegmentHeader | ||||
|  | ||||
| 	// Embed ReaderAt for ReadAt method. | ||||
| 	// Do not embed SectionReader directly | ||||
| 	// to avoid having Read and Seek. | ||||
| 	// If a client wants Read and Seek it must use | ||||
| 	// Open() to avoid fighting over the seek offset | ||||
| 	// with other clients. | ||||
| 	io.ReaderAt | ||||
| 	sr *io.SectionReader | ||||
| } | ||||
|  | ||||
| // Data reads and returns the contents of the segment. | ||||
| func (s *Segment) Data() ([]byte, error) { | ||||
| 	dat := make([]byte, s.sr.Size()) | ||||
| 	n, err := s.sr.ReadAt(dat, 0) | ||||
| 	if n == len(dat) { | ||||
| 		err = nil | ||||
| 	} | ||||
| 	return dat[0:n], err | ||||
| } | ||||
|  | ||||
| // Open returns a new ReadSeeker reading the segment. | ||||
| func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } | ||||
|  | ||||
| type SectionHeader struct { | ||||
| 	Name   string | ||||
| 	Seg    string | ||||
| 	Addr   uint64 | ||||
| 	Size   uint64 | ||||
| 	Offset uint32 | ||||
| 	Align  uint32 | ||||
| 	Reloff uint32 | ||||
| 	Nreloc uint32 | ||||
| 	Flags  uint32 | ||||
| } | ||||
|  | ||||
| type Section struct { | ||||
| 	SectionHeader | ||||
|  | ||||
| 	// Embed ReaderAt for ReadAt method. | ||||
| 	// Do not embed SectionReader directly | ||||
| 	// to avoid having Read and Seek. | ||||
| 	// If a client wants Read and Seek it must use | ||||
| 	// Open() to avoid fighting over the seek offset | ||||
| 	// with other clients. | ||||
| 	io.ReaderAt | ||||
| 	sr *io.SectionReader | ||||
| } | ||||
|  | ||||
| // Data reads and returns the contents of the Mach-O section. | ||||
| func (s *Section) Data() ([]byte, error) { | ||||
| 	dat := make([]byte, s.sr.Size()) | ||||
| 	n, err := s.sr.ReadAt(dat, 0) | ||||
| 	if n == len(dat) { | ||||
| 		err = nil | ||||
| 	} | ||||
| 	return dat[0:n], err | ||||
| } | ||||
|  | ||||
| // Open returns a new ReadSeeker reading the Mach-O section. | ||||
| func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } | ||||
|  | ||||
| // A Dylib represents a Mach-O load dynamic library command. | ||||
| type Dylib struct { | ||||
| 	LoadBytes | ||||
| 	Name           string | ||||
| 	Time           uint32 | ||||
| 	CurrentVersion uint32 | ||||
| 	CompatVersion  uint32 | ||||
| } | ||||
|  | ||||
| // A Symtab represents a Mach-O symbol table command. | ||||
| type Symtab struct { | ||||
| 	LoadBytes | ||||
| 	SymtabCmd | ||||
| 	Syms []Symbol | ||||
| } | ||||
|  | ||||
| // A Dysymtab represents a Mach-O dynamic symbol table command. | ||||
| type Dysymtab struct { | ||||
| 	LoadBytes | ||||
| 	DysymtabCmd | ||||
| 	IndirectSyms []uint32 // indices into Symtab.Syms | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Mach-O reader | ||||
|  */ | ||||
|  | ||||
| // FormatError is returned by some operations if the data does | ||||
| // not have the correct format for an object file. | ||||
| type FormatError struct { | ||||
| 	off int64 | ||||
| 	msg string | ||||
| 	val interface{} | ||||
| } | ||||
|  | ||||
| func (e *FormatError) Error() string { | ||||
| 	msg := e.msg | ||||
| 	if e.val != nil { | ||||
| 		msg += fmt.Sprintf(" '%v'", e.val) | ||||
| 	} | ||||
| 	msg += fmt.Sprintf(" in record at byte %#x", e.off) | ||||
| 	return msg | ||||
| } | ||||
|  | ||||
| // Open opens the named file using os.Open and prepares it for use as a Mach-O binary. | ||||
| func Open(name string) (*File, error) { | ||||
| 	f, err := os.Open(name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ff, err := NewFile(f) | ||||
| 	if err != nil { | ||||
| 		f.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ff.closer = f | ||||
| 	return ff, nil | ||||
| } | ||||
|  | ||||
| // Close closes the File. | ||||
| // If the File was created using NewFile directly instead of Open, | ||||
| // Close has no effect. | ||||
| func (f *File) Close() error { | ||||
| 	var err error | ||||
| 	if f.closer != nil { | ||||
| 		err = f.closer.Close() | ||||
| 		f.closer = nil | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // NewFile creates a new File for accessing a Mach-O binary in an underlying reader. | ||||
| // The Mach-O binary is expected to start at position 0 in the ReaderAt. | ||||
| func NewFile(r io.ReaderAt) (*File, error) { | ||||
| 	f := new(File) | ||||
| 	sr := io.NewSectionReader(r, 0, 1<<63-1) | ||||
|  | ||||
| 	// Read and decode Mach magic to determine byte order, size. | ||||
| 	// Magic32 and Magic64 differ only in the bottom bit. | ||||
| 	var ident [4]byte | ||||
| 	if _, err := r.ReadAt(ident[0:], 0); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	be := binary.BigEndian.Uint32(ident[0:]) | ||||
| 	le := binary.LittleEndian.Uint32(ident[0:]) | ||||
| 	switch Magic32 &^ 1 { | ||||
| 	case be &^ 1: | ||||
| 		f.ByteOrder = binary.BigEndian | ||||
| 		f.Magic = be | ||||
| 	case le &^ 1: | ||||
| 		f.ByteOrder = binary.LittleEndian | ||||
| 		f.Magic = le | ||||
| 	default: | ||||
| 		return nil, &FormatError{0, "invalid magic number", nil} | ||||
| 	} | ||||
|  | ||||
| 	// Read entire file header. | ||||
| 	if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Then load commands. | ||||
| 	offset := int64(fileHeaderSize32) | ||||
| 	if f.Magic == Magic64 { | ||||
| 		offset = fileHeaderSize64 | ||||
| 	} | ||||
| 	dat := make([]byte, f.Cmdsz) | ||||
| 	if _, err := r.ReadAt(dat, offset); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	f.Loads = make([]Load, f.Ncmd) | ||||
| 	bo := f.ByteOrder | ||||
| 	for i := range f.Loads { | ||||
| 		// Each load command begins with uint32 command and length. | ||||
| 		if len(dat) < 8 { | ||||
| 			return nil, &FormatError{offset, "command block too small", nil} | ||||
| 		} | ||||
| 		cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8]) | ||||
| 		if siz < 8 || siz > uint32(len(dat)) { | ||||
| 			return nil, &FormatError{offset, "invalid command block size", nil} | ||||
| 		} | ||||
| 		var cmddat []byte | ||||
| 		cmddat, dat = dat[0:siz], dat[siz:] | ||||
| 		offset += int64(siz) | ||||
| 		var s *Segment | ||||
| 		switch cmd { | ||||
| 		default: | ||||
| 			f.Loads[i] = LoadBytes(cmddat) | ||||
|  | ||||
| 		case LoadCmdDylib: | ||||
| 			var hdr DylibCmd | ||||
| 			b := bytes.NewReader(cmddat) | ||||
| 			if err := binary.Read(b, bo, &hdr); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			l := new(Dylib) | ||||
| 			if hdr.Name >= uint32(len(cmddat)) { | ||||
| 				return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name} | ||||
| 			} | ||||
| 			l.Name = cstring(cmddat[hdr.Name:]) | ||||
| 			l.Time = hdr.Time | ||||
| 			l.CurrentVersion = hdr.CurrentVersion | ||||
| 			l.CompatVersion = hdr.CompatVersion | ||||
| 			l.LoadBytes = LoadBytes(cmddat) | ||||
| 			f.Loads[i] = l | ||||
|  | ||||
| 		case LoadCmdSymtab: | ||||
| 			var hdr SymtabCmd | ||||
| 			b := bytes.NewReader(cmddat) | ||||
| 			if err := binary.Read(b, bo, &hdr); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			strtab := make([]byte, hdr.Strsize) | ||||
| 			if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			var symsz int | ||||
| 			if f.Magic == Magic64 { | ||||
| 				symsz = 16 | ||||
| 			} else { | ||||
| 				symsz = 12 | ||||
| 			} | ||||
| 			symdat := make([]byte, int(hdr.Nsyms)*symsz) | ||||
| 			if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			f.Loads[i] = st | ||||
| 			f.Symtab = st | ||||
|  | ||||
| 		case LoadCmdDysymtab: | ||||
| 			var hdr DysymtabCmd | ||||
| 			b := bytes.NewReader(cmddat) | ||||
| 			if err := binary.Read(b, bo, &hdr); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			dat := make([]byte, hdr.Nindirectsyms*4) | ||||
| 			if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			x := make([]uint32, hdr.Nindirectsyms) | ||||
| 			if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			st := new(Dysymtab) | ||||
| 			st.LoadBytes = LoadBytes(cmddat) | ||||
| 			st.DysymtabCmd = hdr | ||||
| 			st.IndirectSyms = x | ||||
| 			f.Loads[i] = st | ||||
| 			f.Dysymtab = st | ||||
|  | ||||
| 		case LoadCmdSegment: | ||||
| 			var seg32 Segment32 | ||||
| 			b := bytes.NewReader(cmddat) | ||||
| 			if err := binary.Read(b, bo, &seg32); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			s = new(Segment) | ||||
| 			s.LoadBytes = cmddat | ||||
| 			s.Cmd = cmd | ||||
| 			s.Len = siz | ||||
| 			s.Name = cstring(seg32.Name[0:]) | ||||
| 			s.Addr = uint64(seg32.Addr) | ||||
| 			s.Memsz = uint64(seg32.Memsz) | ||||
| 			s.Offset = uint64(seg32.Offset) | ||||
| 			s.Filesz = uint64(seg32.Filesz) | ||||
| 			s.Maxprot = seg32.Maxprot | ||||
| 			s.Prot = seg32.Prot | ||||
| 			s.Nsect = seg32.Nsect | ||||
| 			s.Flag = seg32.Flag | ||||
| 			f.Loads[i] = s | ||||
| 			for i := 0; i < int(s.Nsect); i++ { | ||||
| 				var sh32 Section32 | ||||
| 				if err := binary.Read(b, bo, &sh32); err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				sh := new(Section) | ||||
| 				sh.Name = cstring(sh32.Name[0:]) | ||||
| 				sh.Seg = cstring(sh32.Seg[0:]) | ||||
| 				sh.Addr = uint64(sh32.Addr) | ||||
| 				sh.Size = uint64(sh32.Size) | ||||
| 				sh.Offset = sh32.Offset | ||||
| 				sh.Align = sh32.Align | ||||
| 				sh.Reloff = sh32.Reloff | ||||
| 				sh.Nreloc = sh32.Nreloc | ||||
| 				sh.Flags = sh32.Flags | ||||
| 				f.pushSection(sh, r) | ||||
| 			} | ||||
|  | ||||
| 		case LoadCmdSegment64: | ||||
| 			var seg64 Segment64 | ||||
| 			b := bytes.NewReader(cmddat) | ||||
| 			if err := binary.Read(b, bo, &seg64); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			s = new(Segment) | ||||
| 			s.LoadBytes = cmddat | ||||
| 			s.Cmd = cmd | ||||
| 			s.Len = siz | ||||
| 			s.Name = cstring(seg64.Name[0:]) | ||||
| 			s.Addr = seg64.Addr | ||||
| 			s.Memsz = seg64.Memsz | ||||
| 			s.Offset = seg64.Offset | ||||
| 			s.Filesz = seg64.Filesz | ||||
| 			s.Maxprot = seg64.Maxprot | ||||
| 			s.Prot = seg64.Prot | ||||
| 			s.Nsect = seg64.Nsect | ||||
| 			s.Flag = seg64.Flag | ||||
| 			f.Loads[i] = s | ||||
| 			for i := 0; i < int(s.Nsect); i++ { | ||||
| 				var sh64 Section64 | ||||
| 				if err := binary.Read(b, bo, &sh64); err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				sh := new(Section) | ||||
| 				sh.Name = cstring(sh64.Name[0:]) | ||||
| 				sh.Seg = cstring(sh64.Seg[0:]) | ||||
| 				sh.Addr = sh64.Addr | ||||
| 				sh.Size = sh64.Size | ||||
| 				sh.Offset = sh64.Offset | ||||
| 				sh.Align = sh64.Align | ||||
| 				sh.Reloff = sh64.Reloff | ||||
| 				sh.Nreloc = sh64.Nreloc | ||||
| 				sh.Flags = sh64.Flags | ||||
| 				f.pushSection(sh, r) | ||||
| 			} | ||||
| 		} | ||||
| 		if s != nil { | ||||
| 			s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz)) | ||||
| 			s.ReaderAt = s.sr | ||||
| 		} | ||||
| 	} | ||||
| 	return f, nil | ||||
| } | ||||
|  | ||||
| func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) { | ||||
| 	bo := f.ByteOrder | ||||
| 	symtab := make([]Symbol, hdr.Nsyms) | ||||
| 	b := bytes.NewReader(symdat) | ||||
| 	for i := range symtab { | ||||
| 		var n Nlist64 | ||||
| 		if f.Magic == Magic64 { | ||||
| 			if err := binary.Read(b, bo, &n); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} else { | ||||
| 			var n32 Nlist32 | ||||
| 			if err := binary.Read(b, bo, &n32); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			n.Name = n32.Name | ||||
| 			n.Type = n32.Type | ||||
| 			n.Sect = n32.Sect | ||||
| 			n.Desc = n32.Desc | ||||
| 			n.Value = uint64(n32.Value) | ||||
| 		} | ||||
| 		sym := &symtab[i] | ||||
| 		if n.Name >= uint32(len(strtab)) { | ||||
| 			return nil, &FormatError{offset, "invalid name in symbol table", n.Name} | ||||
| 		} | ||||
| 		sym.Name = cstring(strtab[n.Name:]) | ||||
| 		sym.Type = n.Type | ||||
| 		sym.Sect = n.Sect | ||||
| 		sym.Desc = n.Desc | ||||
| 		sym.Value = n.Value | ||||
| 	} | ||||
| 	st := new(Symtab) | ||||
| 	st.LoadBytes = LoadBytes(cmddat) | ||||
| 	st.Syms = symtab | ||||
| 	return st, nil | ||||
| } | ||||
|  | ||||
| func (f *File) pushSection(sh *Section, r io.ReaderAt) { | ||||
| 	f.Sections = append(f.Sections, sh) | ||||
| 	sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size)) | ||||
| 	sh.ReaderAt = sh.sr | ||||
| } | ||||
|  | ||||
| func cstring(b []byte) string { | ||||
| 	var i int | ||||
| 	for i = 0; i < len(b) && b[i] != 0; i++ { | ||||
| 	} | ||||
| 	return string(b[0:i]) | ||||
| } | ||||
|  | ||||
| // Segment returns the first Segment with the given name, or nil if no such segment exists. | ||||
| func (f *File) Segment(name string) *Segment { | ||||
| 	for _, l := range f.Loads { | ||||
| 		if s, ok := l.(*Segment); ok && s.Name == name { | ||||
| 			return s | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Section returns the first section with the given name, or nil if no such | ||||
| // section exists. | ||||
| func (f *File) Section(name string) *Section { | ||||
| 	for _, s := range f.Sections { | ||||
| 		if s.Name == name { | ||||
| 			return s | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // DWARF returns the DWARF debug information for the Mach-O file. | ||||
| func (f *File) DWARF() (*dwarf.Data, error) { | ||||
| 	// There are many other DWARF sections, but these | ||||
| 	// are the required ones, and the debug/dwarf package | ||||
| 	// does not use the others, so don't bother loading them. | ||||
| 	var names = [...]string{"abbrev", "frame", "info", "line", "str"} | ||||
| 	var dat [len(names)][]byte | ||||
| 	for i, name := range names { | ||||
| 		name = "__debug_" + name | ||||
| 		s := f.Section(name) | ||||
| 		if s == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		b, err := s.Data() | ||||
| 		if err != nil && uint64(len(b)) < s.Size { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		dat[i] = b | ||||
| 	} | ||||
|  | ||||
| 	abbrev, frame, info, line, str := dat[0], dat[1], dat[2], dat[3], dat[4] | ||||
| 	return dwarf.New(abbrev, nil, frame, info, line, nil, nil, str) | ||||
| } | ||||
|  | ||||
| // ImportedSymbols returns the names of all symbols | ||||
| // referred to by the binary f that are expected to be | ||||
| // satisfied by other libraries at dynamic load time. | ||||
| func (f *File) ImportedSymbols() ([]string, error) { | ||||
| 	if f.Dysymtab == nil || f.Symtab == nil { | ||||
| 		return nil, &FormatError{0, "missing symbol table", nil} | ||||
| 	} | ||||
|  | ||||
| 	st := f.Symtab | ||||
| 	dt := f.Dysymtab | ||||
| 	var all []string | ||||
| 	for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] { | ||||
| 		all = append(all, s.Name) | ||||
| 	} | ||||
| 	return all, nil | ||||
| } | ||||
|  | ||||
| // ImportedLibraries returns the paths of all libraries | ||||
| // referred to by the binary f that are expected to be | ||||
| // linked with the binary at dynamic link time. | ||||
| func (f *File) ImportedLibraries() ([]string, error) { | ||||
| 	var all []string | ||||
| 	for _, l := range f.Loads { | ||||
| 		if lib, ok := l.(*Dylib); ok { | ||||
| 			all = append(all, lib.Name) | ||||
| 		} | ||||
| 	} | ||||
| 	return all, nil | ||||
| } | ||||
							
								
								
									
										316
									
								
								vendor/golang.org/x/debug/macho/macho.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								vendor/golang.org/x/debug/macho/macho.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,316 @@ | ||||
| // Copyright 2009 The Go Authors.  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Mach-O header data structures | ||||
| // http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html | ||||
|  | ||||
| package macho | ||||
|  | ||||
| import "strconv" | ||||
|  | ||||
| // A FileHeader represents a Mach-O file header. | ||||
| type FileHeader struct { | ||||
| 	Magic  uint32 | ||||
| 	Cpu    Cpu | ||||
| 	SubCpu uint32 | ||||
| 	Type   Type | ||||
| 	Ncmd   uint32 | ||||
| 	Cmdsz  uint32 | ||||
| 	Flags  uint32 | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	fileHeaderSize32 = 7 * 4 | ||||
| 	fileHeaderSize64 = 8 * 4 | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	Magic32  uint32 = 0xfeedface | ||||
| 	Magic64  uint32 = 0xfeedfacf | ||||
| 	MagicFat uint32 = 0xcafebabe | ||||
| ) | ||||
|  | ||||
| // A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library. | ||||
| type Type uint32 | ||||
|  | ||||
| const ( | ||||
| 	TypeObj    Type = 1 | ||||
| 	TypeExec   Type = 2 | ||||
| 	TypeDylib  Type = 6 | ||||
| 	TypeBundle Type = 8 | ||||
| ) | ||||
|  | ||||
| // A Cpu is a Mach-O cpu type. | ||||
| type Cpu uint32 | ||||
|  | ||||
| const cpuArch64 = 0x01000000 | ||||
|  | ||||
| const ( | ||||
| 	Cpu386   Cpu = 7 | ||||
| 	CpuAmd64 Cpu = Cpu386 | cpuArch64 | ||||
| 	CpuArm   Cpu = 12 | ||||
| 	CpuPpc   Cpu = 18 | ||||
| 	CpuPpc64 Cpu = CpuPpc | cpuArch64 | ||||
| ) | ||||
|  | ||||
| var cpuStrings = []intName{ | ||||
| 	{uint32(Cpu386), "Cpu386"}, | ||||
| 	{uint32(CpuAmd64), "CpuAmd64"}, | ||||
| 	{uint32(CpuArm), "CpuArm"}, | ||||
| 	{uint32(CpuPpc), "CpuPpc"}, | ||||
| 	{uint32(CpuPpc64), "CpuPpc64"}, | ||||
| } | ||||
|  | ||||
| func (i Cpu) String() string   { return stringName(uint32(i), cpuStrings, false) } | ||||
| func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) } | ||||
|  | ||||
| // A LoadCmd is a Mach-O load command. | ||||
| type LoadCmd uint32 | ||||
|  | ||||
| const ( | ||||
| 	LoadCmdSegment    LoadCmd = 1 | ||||
| 	LoadCmdSymtab     LoadCmd = 2 | ||||
| 	LoadCmdThread     LoadCmd = 4 | ||||
| 	LoadCmdUnixThread LoadCmd = 5 // thread+stack | ||||
| 	LoadCmdDysymtab   LoadCmd = 11 | ||||
| 	LoadCmdDylib      LoadCmd = 12 | ||||
| 	LoadCmdDylinker   LoadCmd = 15 | ||||
| 	LoadCmdSegment64  LoadCmd = 25 | ||||
| ) | ||||
|  | ||||
| var cmdStrings = []intName{ | ||||
| 	{uint32(LoadCmdSegment), "LoadCmdSegment"}, | ||||
| 	{uint32(LoadCmdThread), "LoadCmdThread"}, | ||||
| 	{uint32(LoadCmdUnixThread), "LoadCmdUnixThread"}, | ||||
| 	{uint32(LoadCmdDylib), "LoadCmdDylib"}, | ||||
| 	{uint32(LoadCmdSegment64), "LoadCmdSegment64"}, | ||||
| } | ||||
|  | ||||
| func (i LoadCmd) String() string   { return stringName(uint32(i), cmdStrings, false) } | ||||
| func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) } | ||||
|  | ||||
| // A Segment64 is a 64-bit Mach-O segment load command. | ||||
| type Segment64 struct { | ||||
| 	Cmd     LoadCmd | ||||
| 	Len     uint32 | ||||
| 	Name    [16]byte | ||||
| 	Addr    uint64 | ||||
| 	Memsz   uint64 | ||||
| 	Offset  uint64 | ||||
| 	Filesz  uint64 | ||||
| 	Maxprot uint32 | ||||
| 	Prot    uint32 | ||||
| 	Nsect   uint32 | ||||
| 	Flag    uint32 | ||||
| } | ||||
|  | ||||
| // A Segment32 is a 32-bit Mach-O segment load command. | ||||
| type Segment32 struct { | ||||
| 	Cmd     LoadCmd | ||||
| 	Len     uint32 | ||||
| 	Name    [16]byte | ||||
| 	Addr    uint32 | ||||
| 	Memsz   uint32 | ||||
| 	Offset  uint32 | ||||
| 	Filesz  uint32 | ||||
| 	Maxprot uint32 | ||||
| 	Prot    uint32 | ||||
| 	Nsect   uint32 | ||||
| 	Flag    uint32 | ||||
| } | ||||
|  | ||||
| // A DylibCmd is a Mach-O load dynamic library command. | ||||
| type DylibCmd struct { | ||||
| 	Cmd            LoadCmd | ||||
| 	Len            uint32 | ||||
| 	Name           uint32 | ||||
| 	Time           uint32 | ||||
| 	CurrentVersion uint32 | ||||
| 	CompatVersion  uint32 | ||||
| } | ||||
|  | ||||
| // A Section32 is a 32-bit Mach-O section header. | ||||
| type Section32 struct { | ||||
| 	Name     [16]byte | ||||
| 	Seg      [16]byte | ||||
| 	Addr     uint32 | ||||
| 	Size     uint32 | ||||
| 	Offset   uint32 | ||||
| 	Align    uint32 | ||||
| 	Reloff   uint32 | ||||
| 	Nreloc   uint32 | ||||
| 	Flags    uint32 | ||||
| 	Reserve1 uint32 | ||||
| 	Reserve2 uint32 | ||||
| } | ||||
|  | ||||
| // A Section32 is a 64-bit Mach-O section header. | ||||
| type Section64 struct { | ||||
| 	Name     [16]byte | ||||
| 	Seg      [16]byte | ||||
| 	Addr     uint64 | ||||
| 	Size     uint64 | ||||
| 	Offset   uint32 | ||||
| 	Align    uint32 | ||||
| 	Reloff   uint32 | ||||
| 	Nreloc   uint32 | ||||
| 	Flags    uint32 | ||||
| 	Reserve1 uint32 | ||||
| 	Reserve2 uint32 | ||||
| 	Reserve3 uint32 | ||||
| } | ||||
|  | ||||
| // A SymtabCmd is a Mach-O symbol table command. | ||||
| type SymtabCmd struct { | ||||
| 	Cmd     LoadCmd | ||||
| 	Len     uint32 | ||||
| 	Symoff  uint32 | ||||
| 	Nsyms   uint32 | ||||
| 	Stroff  uint32 | ||||
| 	Strsize uint32 | ||||
| } | ||||
|  | ||||
| // A DysymtabCmd is a Mach-O dynamic symbol table command. | ||||
| type DysymtabCmd struct { | ||||
| 	Cmd            LoadCmd | ||||
| 	Len            uint32 | ||||
| 	Ilocalsym      uint32 | ||||
| 	Nlocalsym      uint32 | ||||
| 	Iextdefsym     uint32 | ||||
| 	Nextdefsym     uint32 | ||||
| 	Iundefsym      uint32 | ||||
| 	Nundefsym      uint32 | ||||
| 	Tocoffset      uint32 | ||||
| 	Ntoc           uint32 | ||||
| 	Modtaboff      uint32 | ||||
| 	Nmodtab        uint32 | ||||
| 	Extrefsymoff   uint32 | ||||
| 	Nextrefsyms    uint32 | ||||
| 	Indirectsymoff uint32 | ||||
| 	Nindirectsyms  uint32 | ||||
| 	Extreloff      uint32 | ||||
| 	Nextrel        uint32 | ||||
| 	Locreloff      uint32 | ||||
| 	Nlocrel        uint32 | ||||
| } | ||||
|  | ||||
| // An Nlist32 is a Mach-O 32-bit symbol table entry. | ||||
| type Nlist32 struct { | ||||
| 	Name  uint32 | ||||
| 	Type  uint8 | ||||
| 	Sect  uint8 | ||||
| 	Desc  uint16 | ||||
| 	Value uint32 | ||||
| } | ||||
|  | ||||
| // An Nlist64 is a Mach-O 64-bit symbol table entry. | ||||
| type Nlist64 struct { | ||||
| 	Name  uint32 | ||||
| 	Type  uint8 | ||||
| 	Sect  uint8 | ||||
| 	Desc  uint16 | ||||
| 	Value uint64 | ||||
| } | ||||
|  | ||||
| // A Symbol is a Mach-O 32-bit or 64-bit symbol table entry. | ||||
| type Symbol struct { | ||||
| 	Name  string | ||||
| 	Type  uint8 | ||||
| 	Sect  uint8 | ||||
| 	Desc  uint16 | ||||
| 	Value uint64 | ||||
| } | ||||
|  | ||||
| // A Thread is a Mach-O thread state command. | ||||
| type Thread struct { | ||||
| 	Cmd  LoadCmd | ||||
| 	Len  uint32 | ||||
| 	Type uint32 | ||||
| 	Data []uint32 | ||||
| } | ||||
|  | ||||
| // Regs386 is the Mach-O 386 register structure. | ||||
| type Regs386 struct { | ||||
| 	AX    uint32 | ||||
| 	BX    uint32 | ||||
| 	CX    uint32 | ||||
| 	DX    uint32 | ||||
| 	DI    uint32 | ||||
| 	SI    uint32 | ||||
| 	BP    uint32 | ||||
| 	SP    uint32 | ||||
| 	SS    uint32 | ||||
| 	FLAGS uint32 | ||||
| 	IP    uint32 | ||||
| 	CS    uint32 | ||||
| 	DS    uint32 | ||||
| 	ES    uint32 | ||||
| 	FS    uint32 | ||||
| 	GS    uint32 | ||||
| } | ||||
|  | ||||
| // RegsAMD64 is the Mach-O AMD64 register structure. | ||||
| type RegsAMD64 struct { | ||||
| 	AX    uint64 | ||||
| 	BX    uint64 | ||||
| 	CX    uint64 | ||||
| 	DX    uint64 | ||||
| 	DI    uint64 | ||||
| 	SI    uint64 | ||||
| 	BP    uint64 | ||||
| 	SP    uint64 | ||||
| 	R8    uint64 | ||||
| 	R9    uint64 | ||||
| 	R10   uint64 | ||||
| 	R11   uint64 | ||||
| 	R12   uint64 | ||||
| 	R13   uint64 | ||||
| 	R14   uint64 | ||||
| 	R15   uint64 | ||||
| 	IP    uint64 | ||||
| 	FLAGS uint64 | ||||
| 	CS    uint64 | ||||
| 	FS    uint64 | ||||
| 	GS    uint64 | ||||
| } | ||||
|  | ||||
| type intName struct { | ||||
| 	i uint32 | ||||
| 	s string | ||||
| } | ||||
|  | ||||
| func stringName(i uint32, names []intName, goSyntax bool) string { | ||||
| 	for _, n := range names { | ||||
| 		if n.i == i { | ||||
| 			if goSyntax { | ||||
| 				return "macho." + n.s | ||||
| 			} | ||||
| 			return n.s | ||||
| 		} | ||||
| 	} | ||||
| 	return strconv.FormatUint(uint64(i), 10) | ||||
| } | ||||
|  | ||||
| func flagName(i uint32, names []intName, goSyntax bool) string { | ||||
| 	s := "" | ||||
| 	for _, n := range names { | ||||
| 		if n.i&i == n.i { | ||||
| 			if len(s) > 0 { | ||||
| 				s += "+" | ||||
| 			} | ||||
| 			if goSyntax { | ||||
| 				s += "macho." | ||||
| 			} | ||||
| 			s += n.s | ||||
| 			i -= n.i | ||||
| 		} | ||||
| 	} | ||||
| 	if len(s) == 0 { | ||||
| 		return "0x" + strconv.FormatUint(uint64(i), 16) | ||||
| 	} | ||||
| 	if i != 0 { | ||||
| 		s += "+0x" + strconv.FormatUint(uint64(i), 16) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Faissal Elamraoui
					Faissal Elamraoui