mirror of
https://github.com/beego/bee.git
synced 2025-07-05 13:10:18 +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
|
||||
}
|
8
vendor/golang.org/x/sys/windows/asm.s
generated
vendored
Normal file
8
vendor/golang.org/x/sys/windows/asm.s
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// 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.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·use(SB),NOSPLIT,$0
|
||||
RET
|
13
vendor/golang.org/x/sys/windows/asm_windows_386.s
generated
vendored
Normal file
13
vendor/golang.org/x/sys/windows/asm_windows_386.s
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// 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.
|
||||
|
||||
//
|
||||
// System calls for 386, Windows are implemented in runtime/syscall_windows.goc
|
||||
//
|
||||
|
||||
TEXT ·getprocaddress(SB), 7, $0-8
|
||||
JMP syscall·getprocaddress(SB)
|
||||
|
||||
TEXT ·loadlibrary(SB), 7, $0-4
|
||||
JMP syscall·loadlibrary(SB)
|
13
vendor/golang.org/x/sys/windows/asm_windows_amd64.s
generated
vendored
Normal file
13
vendor/golang.org/x/sys/windows/asm_windows_amd64.s
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// 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.
|
||||
|
||||
//
|
||||
// System calls for amd64, Windows are implemented in runtime/syscall_windows.goc
|
||||
//
|
||||
|
||||
TEXT ·getprocaddress(SB), 7, $0-32
|
||||
JMP syscall·getprocaddress(SB)
|
||||
|
||||
TEXT ·loadlibrary(SB), 7, $0-8
|
||||
JMP syscall·loadlibrary(SB)
|
275
vendor/golang.org/x/sys/windows/dll_windows.go
generated
vendored
Normal file
275
vendor/golang.org/x/sys/windows/dll_windows.go
generated
vendored
Normal file
@ -0,0 +1,275 @@
|
||||
// Copyright 2011 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 windows
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// DLLError describes reasons for DLL load failures.
|
||||
type DLLError struct {
|
||||
Err error
|
||||
ObjName string
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (e *DLLError) Error() string { return e.Msg }
|
||||
|
||||
// Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file.
|
||||
func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
|
||||
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
|
||||
|
||||
// A DLL implements access to a single DLL.
|
||||
type DLL struct {
|
||||
Name string
|
||||
Handle Handle
|
||||
}
|
||||
|
||||
// LoadDLL loads DLL file into memory.
|
||||
func LoadDLL(name string) (dll *DLL, err error) {
|
||||
namep, err := UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, e := loadlibrary(namep)
|
||||
if e != 0 {
|
||||
return nil, &DLLError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to load " + name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
d := &DLL{
|
||||
Name: name,
|
||||
Handle: Handle(h),
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// MustLoadDLL is like LoadDLL but panics if load operation failes.
|
||||
func MustLoadDLL(name string) *DLL {
|
||||
d, e := LoadDLL(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// FindProc searches DLL d for procedure named name and returns *Proc
|
||||
// if found. It returns an error if search fails.
|
||||
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
|
||||
namep, err := BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a, e := getprocaddress(uintptr(d.Handle), namep)
|
||||
if e != 0 {
|
||||
return nil, &DLLError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
p := &Proc{
|
||||
Dll: d,
|
||||
Name: name,
|
||||
addr: a,
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// MustFindProc is like FindProc but panics if search fails.
|
||||
func (d *DLL) MustFindProc(name string) *Proc {
|
||||
p, e := d.FindProc(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Release unloads DLL d from memory.
|
||||
func (d *DLL) Release() (err error) {
|
||||
return FreeLibrary(d.Handle)
|
||||
}
|
||||
|
||||
// A Proc implements access to a procedure inside a DLL.
|
||||
type Proc struct {
|
||||
Dll *DLL
|
||||
Name string
|
||||
addr uintptr
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *Proc) Addr() uintptr {
|
||||
return p.addr
|
||||
}
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
||||
// are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||
// Callers must inspect the primary return value to decide whether an error occurred
|
||||
// (according to the semantics of the specific function being called) before consulting
|
||||
// the error. The error will be guaranteed to contain windows.Errno.
|
||||
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
switch len(a) {
|
||||
case 0:
|
||||
return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
|
||||
case 1:
|
||||
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
|
||||
case 2:
|
||||
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
|
||||
case 3:
|
||||
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
|
||||
case 4:
|
||||
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
|
||||
case 5:
|
||||
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
|
||||
case 6:
|
||||
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
|
||||
case 7:
|
||||
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
|
||||
case 8:
|
||||
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
|
||||
case 9:
|
||||
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
|
||||
case 10:
|
||||
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
|
||||
case 11:
|
||||
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
|
||||
case 12:
|
||||
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
|
||||
case 13:
|
||||
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
|
||||
case 14:
|
||||
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
|
||||
case 15:
|
||||
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
|
||||
default:
|
||||
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// A LazyDLL implements access to a single DLL.
|
||||
// It will delay the load of the DLL until the first
|
||||
// call to its Handle method or to one of its
|
||||
// LazyProc's Addr method.
|
||||
type LazyDLL struct {
|
||||
mu sync.Mutex
|
||||
dll *DLL // non nil once DLL is loaded
|
||||
Name string
|
||||
}
|
||||
|
||||
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
||||
// Load will not try to load DLL, if it is already loaded into memory.
|
||||
func (d *LazyDLL) Load() error {
|
||||
// Non-racy version of:
|
||||
// if d.dll == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.dll == nil {
|
||||
dll, e := LoadDLL(d.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// d.dll = dll
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustLoad is like Load but panics if search fails.
|
||||
func (d *LazyDLL) mustLoad() {
|
||||
e := d.Load()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle returns d's module handle.
|
||||
func (d *LazyDLL) Handle() uintptr {
|
||||
d.mustLoad()
|
||||
return uintptr(d.dll.Handle)
|
||||
}
|
||||
|
||||
// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
|
||||
func (d *LazyDLL) NewProc(name string) *LazyProc {
|
||||
return &LazyProc{l: d, Name: name}
|
||||
}
|
||||
|
||||
// NewLazyDLL creates new LazyDLL associated with DLL file.
|
||||
func NewLazyDLL(name string) *LazyDLL {
|
||||
return &LazyDLL{Name: name}
|
||||
}
|
||||
|
||||
// A LazyProc implements access to a procedure inside a LazyDLL.
|
||||
// It delays the lookup until the Addr method is called.
|
||||
type LazyProc struct {
|
||||
mu sync.Mutex
|
||||
Name string
|
||||
l *LazyDLL
|
||||
proc *Proc
|
||||
}
|
||||
|
||||
// Find searches DLL for procedure named p.Name. It returns
|
||||
// an error if search fails. Find will not search procedure,
|
||||
// if it is already found and loaded into memory.
|
||||
func (p *LazyProc) Find() error {
|
||||
// Non-racy version of:
|
||||
// if p.proc == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
if p.proc == nil {
|
||||
e := p.l.Load()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
proc, e := p.l.dll.FindProc(p.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// p.proc = proc
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustFind is like Find but panics if search fails.
|
||||
func (p *LazyProc) mustFind() {
|
||||
e := p.Find()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *LazyProc) Addr() uintptr {
|
||||
p.mustFind()
|
||||
return p.proc.Addr()
|
||||
}
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
||||
// are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||
// Callers must inspect the primary return value to decide whether an error occurred
|
||||
// (according to the semantics of the specific function being called) before consulting
|
||||
// the error. The error will be guaranteed to contain windows.Errno.
|
||||
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
p.mustFind()
|
||||
return p.proc.Call(a...)
|
||||
}
|
14
vendor/golang.org/x/sys/windows/env_unset.go
generated
vendored
Normal file
14
vendor/golang.org/x/sys/windows/env_unset.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
// +build go1.4
|
||||
|
||||
package windows
|
||||
|
||||
import "syscall"
|
||||
|
||||
func Unsetenv(key string) error {
|
||||
// This was added in Go 1.4.
|
||||
return syscall.Unsetenv(key)
|
||||
}
|
25
vendor/golang.org/x/sys/windows/env_windows.go
generated
vendored
Normal file
25
vendor/golang.org/x/sys/windows/env_windows.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
// Windows environment variables.
|
||||
|
||||
package windows
|
||||
|
||||
import "syscall"
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
return syscall.Getenv(key)
|
||||
}
|
||||
|
||||
func Setenv(key, value string) error {
|
||||
return syscall.Setenv(key, value)
|
||||
}
|
||||
|
||||
func Clearenv() {
|
||||
syscall.Clearenv()
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
return syscall.Environ()
|
||||
}
|
20
vendor/golang.org/x/sys/windows/eventlog.go
generated
vendored
Normal file
20
vendor/golang.org/x/sys/windows/eventlog.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
const (
|
||||
EVENTLOG_SUCCESS = 0
|
||||
EVENTLOG_ERROR_TYPE = 1
|
||||
EVENTLOG_WARNING_TYPE = 2
|
||||
EVENTLOG_INFORMATION_TYPE = 4
|
||||
EVENTLOG_AUDIT_SUCCESS = 8
|
||||
EVENTLOG_AUDIT_FAILURE = 16
|
||||
)
|
||||
|
||||
//sys RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) [failretval==0] = advapi32.RegisterEventSourceW
|
||||
//sys DeregisterEventSource(handle Handle) (err error) = advapi32.DeregisterEventSource
|
||||
//sys ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) = advapi32.ReportEventW
|
97
vendor/golang.org/x/sys/windows/exec_windows.go
generated
vendored
Normal file
97
vendor/golang.org/x/sys/windows/exec_windows.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// 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.
|
||||
|
||||
// Fork, exec, wait, etc.
|
||||
|
||||
package windows
|
||||
|
||||
// EscapeArg rewrites command line argument s as prescribed
|
||||
// in http://msdn.microsoft.com/en-us/library/ms880421.
|
||||
// This function returns "" (2 double quotes) if s is empty.
|
||||
// Alternatively, these transformations are done:
|
||||
// - every back slash (\) is doubled, but only if immediately
|
||||
// followed by double quote (");
|
||||
// - every double quote (") is escaped by back slash (\);
|
||||
// - finally, s is wrapped with double quotes (arg -> "arg"),
|
||||
// but only if there is space or tab inside s.
|
||||
func EscapeArg(s string) string {
|
||||
if len(s) == 0 {
|
||||
return "\"\""
|
||||
}
|
||||
n := len(s)
|
||||
hasSpace := false
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '"', '\\':
|
||||
n++
|
||||
case ' ', '\t':
|
||||
hasSpace = true
|
||||
}
|
||||
}
|
||||
if hasSpace {
|
||||
n += 2
|
||||
}
|
||||
if n == len(s) {
|
||||
return s
|
||||
}
|
||||
|
||||
qs := make([]byte, n)
|
||||
j := 0
|
||||
if hasSpace {
|
||||
qs[j] = '"'
|
||||
j++
|
||||
}
|
||||
slashes := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
default:
|
||||
slashes = 0
|
||||
qs[j] = s[i]
|
||||
case '\\':
|
||||
slashes++
|
||||
qs[j] = s[i]
|
||||
case '"':
|
||||
for ; slashes > 0; slashes-- {
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
}
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
qs[j] = s[i]
|
||||
}
|
||||
j++
|
||||
}
|
||||
if hasSpace {
|
||||
for ; slashes > 0; slashes-- {
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
}
|
||||
qs[j] = '"'
|
||||
j++
|
||||
}
|
||||
return string(qs[:j])
|
||||
}
|
||||
|
||||
func CloseOnExec(fd Handle) {
|
||||
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
||||
}
|
||||
|
||||
// FullPath retrieves the full path of the specified file.
|
||||
func FullPath(name string) (path string, err error) {
|
||||
p, err := UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
n := uint32(100)
|
||||
for {
|
||||
buf := make([]uint16, n)
|
||||
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n <= uint32(len(buf)) {
|
||||
return UTF16ToString(buf[:n]), nil
|
||||
}
|
||||
}
|
||||
}
|
30
vendor/golang.org/x/sys/windows/race.go
generated
vendored
Normal file
30
vendor/golang.org/x/sys/windows/race.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
|
||||
// +build windows,race
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = true
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
runtime.RaceAcquire(addr)
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
runtime.RaceReleaseMerge(addr)
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceReadRange(addr, len)
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceWriteRange(addr, len)
|
||||
}
|
25
vendor/golang.org/x/sys/windows/race0.go
generated
vendored
Normal file
25
vendor/golang.org/x/sys/windows/race0.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// 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.
|
||||
|
||||
// +build windows,!race
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = false
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
}
|
435
vendor/golang.org/x/sys/windows/security_windows.go
generated
vendored
Normal file
435
vendor/golang.org/x/sys/windows/security_windows.go
generated
vendored
Normal file
@ -0,0 +1,435 @@
|
||||
// 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 windows
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
STANDARD_RIGHTS_REQUIRED = 0xf0000
|
||||
STANDARD_RIGHTS_READ = 0x20000
|
||||
STANDARD_RIGHTS_WRITE = 0x20000
|
||||
STANDARD_RIGHTS_EXECUTE = 0x20000
|
||||
STANDARD_RIGHTS_ALL = 0x1F0000
|
||||
)
|
||||
|
||||
const (
|
||||
NameUnknown = 0
|
||||
NameFullyQualifiedDN = 1
|
||||
NameSamCompatible = 2
|
||||
NameDisplay = 3
|
||||
NameUniqueId = 6
|
||||
NameCanonical = 7
|
||||
NameUserPrincipal = 8
|
||||
NameCanonicalEx = 9
|
||||
NameServicePrincipal = 10
|
||||
NameDnsDomain = 12
|
||||
)
|
||||
|
||||
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
|
||||
// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
|
||||
//sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
|
||||
//sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
|
||||
|
||||
// TranslateAccountName converts a directory service
|
||||
// object name from one format to another.
|
||||
func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
|
||||
u, e := UTF16PtrFromString(username)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
n := uint32(50)
|
||||
for {
|
||||
b := make([]uint16, n)
|
||||
e = TranslateName(u, from, to, &b[0], &n)
|
||||
if e == nil {
|
||||
return UTF16ToString(b[:n]), nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return "", e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
NetSetupUnknownStatus = iota
|
||||
NetSetupUnjoined
|
||||
NetSetupWorkgroupName
|
||||
NetSetupDomainName
|
||||
)
|
||||
|
||||
type UserInfo10 struct {
|
||||
Name *uint16
|
||||
Comment *uint16
|
||||
UsrComment *uint16
|
||||
FullName *uint16
|
||||
}
|
||||
|
||||
//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
|
||||
//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
|
||||
//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
SidTypeUser = 1 + iota
|
||||
SidTypeGroup
|
||||
SidTypeDomain
|
||||
SidTypeAlias
|
||||
SidTypeWellKnownGroup
|
||||
SidTypeDeletedAccount
|
||||
SidTypeInvalid
|
||||
SidTypeUnknown
|
||||
SidTypeComputer
|
||||
SidTypeLabel
|
||||
)
|
||||
|
||||
type SidIdentifierAuthority struct {
|
||||
Value [6]byte
|
||||
}
|
||||
|
||||
var (
|
||||
SECURITY_NULL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 0}}
|
||||
SECURITY_WORLD_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 1}}
|
||||
SECURITY_LOCAL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 2}}
|
||||
SECURITY_CREATOR_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 3}}
|
||||
SECURITY_NON_UNIQUE_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 4}}
|
||||
SECURITY_NT_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 5}}
|
||||
SECURITY_MANDATORY_LABEL_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 16}}
|
||||
)
|
||||
|
||||
const (
|
||||
SECURITY_NULL_RID = 0
|
||||
SECURITY_WORLD_RID = 0
|
||||
SECURITY_LOCAL_RID = 0
|
||||
SECURITY_CREATOR_OWNER_RID = 0
|
||||
SECURITY_CREATOR_GROUP_RID = 1
|
||||
SECURITY_DIALUP_RID = 1
|
||||
SECURITY_NETWORK_RID = 2
|
||||
SECURITY_BATCH_RID = 3
|
||||
SECURITY_INTERACTIVE_RID = 4
|
||||
SECURITY_LOGON_IDS_RID = 5
|
||||
SECURITY_SERVICE_RID = 6
|
||||
SECURITY_LOCAL_SYSTEM_RID = 18
|
||||
SECURITY_BUILTIN_DOMAIN_RID = 32
|
||||
SECURITY_PRINCIPAL_SELF_RID = 10
|
||||
SECURITY_CREATOR_OWNER_SERVER_RID = 0x2
|
||||
SECURITY_CREATOR_GROUP_SERVER_RID = 0x3
|
||||
SECURITY_LOGON_IDS_RID_COUNT = 0x3
|
||||
SECURITY_ANONYMOUS_LOGON_RID = 0x7
|
||||
SECURITY_PROXY_RID = 0x8
|
||||
SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9
|
||||
SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID
|
||||
SECURITY_AUTHENTICATED_USER_RID = 0xb
|
||||
SECURITY_RESTRICTED_CODE_RID = 0xc
|
||||
SECURITY_NT_NON_UNIQUE_RID = 0x15
|
||||
)
|
||||
|
||||
//sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
|
||||
//sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
|
||||
//sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
||||
//sys ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
|
||||
//sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
|
||||
//sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
|
||||
//sys AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid
|
||||
//sys FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid
|
||||
//sys EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid
|
||||
|
||||
// The security identifier (SID) structure is a variable-length
|
||||
// structure used to uniquely identify users or groups.
|
||||
type SID struct{}
|
||||
|
||||
// StringToSid converts a string-format security identifier
|
||||
// sid into a valid, functional sid.
|
||||
func StringToSid(s string) (*SID, error) {
|
||||
var sid *SID
|
||||
p, e := UTF16PtrFromString(s)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
e = ConvertStringSidToSid(p, &sid)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
defer LocalFree((Handle)(unsafe.Pointer(sid)))
|
||||
return sid.Copy()
|
||||
}
|
||||
|
||||
// LookupSID retrieves a security identifier sid for the account
|
||||
// and the name of the domain on which the account was found.
|
||||
// System specify target computer to search.
|
||||
func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
|
||||
if len(account) == 0 {
|
||||
return nil, "", 0, syscall.EINVAL
|
||||
}
|
||||
acc, e := UTF16PtrFromString(account)
|
||||
if e != nil {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
var sys *uint16
|
||||
if len(system) > 0 {
|
||||
sys, e = UTF16PtrFromString(system)
|
||||
if e != nil {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
}
|
||||
n := uint32(50)
|
||||
dn := uint32(50)
|
||||
for {
|
||||
b := make([]byte, n)
|
||||
db := make([]uint16, dn)
|
||||
sid = (*SID)(unsafe.Pointer(&b[0]))
|
||||
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
|
||||
if e == nil {
|
||||
return sid, UTF16ToString(db), accType, nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String converts sid to a string format
|
||||
// suitable for display, storage, or transmission.
|
||||
func (sid *SID) String() (string, error) {
|
||||
var s *uint16
|
||||
e := ConvertSidToStringSid(sid, &s)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
defer LocalFree((Handle)(unsafe.Pointer(s)))
|
||||
return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
|
||||
}
|
||||
|
||||
// Len returns the length, in bytes, of a valid security identifier sid.
|
||||
func (sid *SID) Len() int {
|
||||
return int(GetLengthSid(sid))
|
||||
}
|
||||
|
||||
// Copy creates a duplicate of security identifier sid.
|
||||
func (sid *SID) Copy() (*SID, error) {
|
||||
b := make([]byte, sid.Len())
|
||||
sid2 := (*SID)(unsafe.Pointer(&b[0]))
|
||||
e := CopySid(uint32(len(b)), sid2, sid)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return sid2, nil
|
||||
}
|
||||
|
||||
// LookupAccount retrieves the name of the account for this sid
|
||||
// and the name of the first domain on which this sid is found.
|
||||
// System specify target computer to search for.
|
||||
func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
|
||||
var sys *uint16
|
||||
if len(system) > 0 {
|
||||
sys, err = UTF16PtrFromString(system)
|
||||
if err != nil {
|
||||
return "", "", 0, err
|
||||
}
|
||||
}
|
||||
n := uint32(50)
|
||||
dn := uint32(50)
|
||||
for {
|
||||
b := make([]uint16, n)
|
||||
db := make([]uint16, dn)
|
||||
e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
|
||||
if e == nil {
|
||||
return UTF16ToString(b), UTF16ToString(db), accType, nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", "", 0, e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return "", "", 0, e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
TOKEN_ASSIGN_PRIMARY = 1 << iota
|
||||
TOKEN_DUPLICATE
|
||||
TOKEN_IMPERSONATE
|
||||
TOKEN_QUERY
|
||||
TOKEN_QUERY_SOURCE
|
||||
TOKEN_ADJUST_PRIVILEGES
|
||||
TOKEN_ADJUST_GROUPS
|
||||
TOKEN_ADJUST_DEFAULT
|
||||
|
||||
TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
|
||||
TOKEN_ASSIGN_PRIMARY |
|
||||
TOKEN_DUPLICATE |
|
||||
TOKEN_IMPERSONATE |
|
||||
TOKEN_QUERY |
|
||||
TOKEN_QUERY_SOURCE |
|
||||
TOKEN_ADJUST_PRIVILEGES |
|
||||
TOKEN_ADJUST_GROUPS |
|
||||
TOKEN_ADJUST_DEFAULT
|
||||
TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY
|
||||
TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
|
||||
TOKEN_ADJUST_PRIVILEGES |
|
||||
TOKEN_ADJUST_GROUPS |
|
||||
TOKEN_ADJUST_DEFAULT
|
||||
TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
|
||||
)
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
TokenUser = 1 + iota
|
||||
TokenGroups
|
||||
TokenPrivileges
|
||||
TokenOwner
|
||||
TokenPrimaryGroup
|
||||
TokenDefaultDacl
|
||||
TokenSource
|
||||
TokenType
|
||||
TokenImpersonationLevel
|
||||
TokenStatistics
|
||||
TokenRestrictedSids
|
||||
TokenSessionId
|
||||
TokenGroupsAndPrivileges
|
||||
TokenSessionReference
|
||||
TokenSandBoxInert
|
||||
TokenAuditPolicy
|
||||
TokenOrigin
|
||||
TokenElevationType
|
||||
TokenLinkedToken
|
||||
TokenElevation
|
||||
TokenHasRestrictions
|
||||
TokenAccessInformation
|
||||
TokenVirtualizationAllowed
|
||||
TokenVirtualizationEnabled
|
||||
TokenIntegrityLevel
|
||||
TokenUIAccess
|
||||
TokenMandatoryPolicy
|
||||
TokenLogonSid
|
||||
MaxTokenInfoClass
|
||||
)
|
||||
|
||||
type SIDAndAttributes struct {
|
||||
Sid *SID
|
||||
Attributes uint32
|
||||
}
|
||||
|
||||
type Tokenuser struct {
|
||||
User SIDAndAttributes
|
||||
}
|
||||
|
||||
type Tokenprimarygroup struct {
|
||||
PrimaryGroup *SID
|
||||
}
|
||||
|
||||
type Tokengroups struct {
|
||||
GroupCount uint32
|
||||
Groups [1]SIDAndAttributes
|
||||
}
|
||||
|
||||
//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
|
||||
//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
|
||||
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
|
||||
|
||||
// An access token contains the security information for a logon session.
|
||||
// The system creates an access token when a user logs on, and every
|
||||
// process executed on behalf of the user has a copy of the token.
|
||||
// The token identifies the user, the user's groups, and the user's
|
||||
// privileges. The system uses the token to control access to securable
|
||||
// objects and to control the ability of the user to perform various
|
||||
// system-related operations on the local computer.
|
||||
type Token Handle
|
||||
|
||||
// OpenCurrentProcessToken opens the access token
|
||||
// associated with current process.
|
||||
func OpenCurrentProcessToken() (Token, error) {
|
||||
p, e := GetCurrentProcess()
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
var t Token
|
||||
e = OpenProcessToken(p, TOKEN_QUERY, &t)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Close releases access to access token.
|
||||
func (t Token) Close() error {
|
||||
return CloseHandle(Handle(t))
|
||||
}
|
||||
|
||||
// getInfo retrieves a specified type of information about an access token.
|
||||
func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
|
||||
n := uint32(initSize)
|
||||
for {
|
||||
b := make([]byte, n)
|
||||
e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
|
||||
if e == nil {
|
||||
return unsafe.Pointer(&b[0]), nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return nil, e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetTokenUser retrieves access token t user account information.
|
||||
func (t Token) GetTokenUser() (*Tokenuser, error) {
|
||||
i, e := t.getInfo(TokenUser, 50)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return (*Tokenuser)(i), nil
|
||||
}
|
||||
|
||||
// GetTokenGroups retrieves group accounts associated with access token t.
|
||||
func (t Token) GetTokenGroups() (*Tokengroups, error) {
|
||||
i, e := t.getInfo(TokenGroups, 50)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return (*Tokengroups)(i), nil
|
||||
}
|
||||
|
||||
// GetTokenPrimaryGroup retrieves access token t primary group information.
|
||||
// A pointer to a SID structure representing a group that will become
|
||||
// the primary group of any objects created by a process using this access token.
|
||||
func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
|
||||
i, e := t.getInfo(TokenPrimaryGroup, 50)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return (*Tokenprimarygroup)(i), nil
|
||||
}
|
||||
|
||||
// GetUserProfileDirectory retrieves path to the
|
||||
// root directory of the access token t user's profile.
|
||||
func (t Token) GetUserProfileDirectory() (string, error) {
|
||||
n := uint32(100)
|
||||
for {
|
||||
b := make([]uint16, n)
|
||||
e := GetUserProfileDirectory(t, &b[0], &n)
|
||||
if e == nil {
|
||||
return UTF16ToString(b), nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return "", e
|
||||
}
|
||||
}
|
||||
}
|
143
vendor/golang.org/x/sys/windows/service.go
generated
vendored
Normal file
143
vendor/golang.org/x/sys/windows/service.go
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
// 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.
|
||||
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
const (
|
||||
SC_MANAGER_CONNECT = 1
|
||||
SC_MANAGER_CREATE_SERVICE = 2
|
||||
SC_MANAGER_ENUMERATE_SERVICE = 4
|
||||
SC_MANAGER_LOCK = 8
|
||||
SC_MANAGER_QUERY_LOCK_STATUS = 16
|
||||
SC_MANAGER_MODIFY_BOOT_CONFIG = 32
|
||||
SC_MANAGER_ALL_ACCESS = 0xf003f
|
||||
)
|
||||
|
||||
//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW
|
||||
|
||||
const (
|
||||
SERVICE_KERNEL_DRIVER = 1
|
||||
SERVICE_FILE_SYSTEM_DRIVER = 2
|
||||
SERVICE_ADAPTER = 4
|
||||
SERVICE_RECOGNIZER_DRIVER = 8
|
||||
SERVICE_WIN32_OWN_PROCESS = 16
|
||||
SERVICE_WIN32_SHARE_PROCESS = 32
|
||||
SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
|
||||
SERVICE_INTERACTIVE_PROCESS = 256
|
||||
SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
|
||||
SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
|
||||
|
||||
SERVICE_BOOT_START = 0
|
||||
SERVICE_SYSTEM_START = 1
|
||||
SERVICE_AUTO_START = 2
|
||||
SERVICE_DEMAND_START = 3
|
||||
SERVICE_DISABLED = 4
|
||||
|
||||
SERVICE_ERROR_IGNORE = 0
|
||||
SERVICE_ERROR_NORMAL = 1
|
||||
SERVICE_ERROR_SEVERE = 2
|
||||
SERVICE_ERROR_CRITICAL = 3
|
||||
|
||||
SC_STATUS_PROCESS_INFO = 0
|
||||
|
||||
SERVICE_STOPPED = 1
|
||||
SERVICE_START_PENDING = 2
|
||||
SERVICE_STOP_PENDING = 3
|
||||
SERVICE_RUNNING = 4
|
||||
SERVICE_CONTINUE_PENDING = 5
|
||||
SERVICE_PAUSE_PENDING = 6
|
||||
SERVICE_PAUSED = 7
|
||||
SERVICE_NO_CHANGE = 0xffffffff
|
||||
|
||||
SERVICE_ACCEPT_STOP = 1
|
||||
SERVICE_ACCEPT_PAUSE_CONTINUE = 2
|
||||
SERVICE_ACCEPT_SHUTDOWN = 4
|
||||
SERVICE_ACCEPT_PARAMCHANGE = 8
|
||||
SERVICE_ACCEPT_NETBINDCHANGE = 16
|
||||
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32
|
||||
SERVICE_ACCEPT_POWEREVENT = 64
|
||||
SERVICE_ACCEPT_SESSIONCHANGE = 128
|
||||
|
||||
SERVICE_CONTROL_STOP = 1
|
||||
SERVICE_CONTROL_PAUSE = 2
|
||||
SERVICE_CONTROL_CONTINUE = 3
|
||||
SERVICE_CONTROL_INTERROGATE = 4
|
||||
SERVICE_CONTROL_SHUTDOWN = 5
|
||||
SERVICE_CONTROL_PARAMCHANGE = 6
|
||||
SERVICE_CONTROL_NETBINDADD = 7
|
||||
SERVICE_CONTROL_NETBINDREMOVE = 8
|
||||
SERVICE_CONTROL_NETBINDENABLE = 9
|
||||
SERVICE_CONTROL_NETBINDDISABLE = 10
|
||||
SERVICE_CONTROL_DEVICEEVENT = 11
|
||||
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12
|
||||
SERVICE_CONTROL_POWEREVENT = 13
|
||||
SERVICE_CONTROL_SESSIONCHANGE = 14
|
||||
|
||||
SERVICE_ACTIVE = 1
|
||||
SERVICE_INACTIVE = 2
|
||||
SERVICE_STATE_ALL = 3
|
||||
|
||||
SERVICE_QUERY_CONFIG = 1
|
||||
SERVICE_CHANGE_CONFIG = 2
|
||||
SERVICE_QUERY_STATUS = 4
|
||||
SERVICE_ENUMERATE_DEPENDENTS = 8
|
||||
SERVICE_START = 16
|
||||
SERVICE_STOP = 32
|
||||
SERVICE_PAUSE_CONTINUE = 64
|
||||
SERVICE_INTERROGATE = 128
|
||||
SERVICE_USER_DEFINED_CONTROL = 256
|
||||
SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL
|
||||
SERVICE_RUNS_IN_SYSTEM_PROCESS = 1
|
||||
SERVICE_CONFIG_DESCRIPTION = 1
|
||||
SERVICE_CONFIG_FAILURE_ACTIONS = 2
|
||||
|
||||
NO_ERROR = 0
|
||||
)
|
||||
|
||||
type SERVICE_STATUS struct {
|
||||
ServiceType uint32
|
||||
CurrentState uint32
|
||||
ControlsAccepted uint32
|
||||
Win32ExitCode uint32
|
||||
ServiceSpecificExitCode uint32
|
||||
CheckPoint uint32
|
||||
WaitHint uint32
|
||||
}
|
||||
|
||||
type SERVICE_TABLE_ENTRY struct {
|
||||
ServiceName *uint16
|
||||
ServiceProc uintptr
|
||||
}
|
||||
|
||||
type QUERY_SERVICE_CONFIG struct {
|
||||
ServiceType uint32
|
||||
StartType uint32
|
||||
ErrorControl uint32
|
||||
BinaryPathName *uint16
|
||||
LoadOrderGroup *uint16
|
||||
TagId uint32
|
||||
Dependencies *uint16
|
||||
ServiceStartName *uint16
|
||||
DisplayName *uint16
|
||||
}
|
||||
|
||||
type SERVICE_DESCRIPTION struct {
|
||||
Description *uint16
|
||||
}
|
||||
|
||||
//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
|
||||
//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
|
||||
//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW
|
||||
//sys DeleteService(service Handle) (err error) = advapi32.DeleteService
|
||||
//sys StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) = advapi32.StartServiceW
|
||||
//sys QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus
|
||||
//sys ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) = advapi32.ControlService
|
||||
//sys StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) = advapi32.StartServiceCtrlDispatcherW
|
||||
//sys SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) = advapi32.SetServiceStatus
|
||||
//sys ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) = advapi32.ChangeServiceConfigW
|
||||
//sys QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfigW
|
||||
//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W
|
||||
//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W
|
22
vendor/golang.org/x/sys/windows/str.go
generated
vendored
Normal file
22
vendor/golang.org/x/sys/windows/str.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// 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.
|
||||
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||
if val < 0 {
|
||||
return "-" + itoa(-val)
|
||||
}
|
||||
var buf [32]byte // big enough for int64
|
||||
i := len(buf) - 1
|
||||
for val >= 10 {
|
||||
buf[i] = byte(val%10 + '0')
|
||||
i--
|
||||
val /= 10
|
||||
}
|
||||
buf[i] = byte(val + '0')
|
||||
return string(buf[i:])
|
||||
}
|
77
vendor/golang.org/x/sys/windows/syscall.go
generated
vendored
Normal file
77
vendor/golang.org/x/sys/windows/syscall.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// 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.
|
||||
|
||||
// +build windows
|
||||
|
||||
// Package windows contains an interface to the low-level operating system
|
||||
// primitives. OS details vary depending on the underlying system, and
|
||||
// by default, godoc will display the OS-specific documentation for the current
|
||||
// system. If you want godoc to display syscall documentation for another
|
||||
// system, set $GOOS and $GOARCH to the desired system. For example, if
|
||||
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
|
||||
// to freebsd and $GOARCH to arm.
|
||||
// The primary use of this package is inside other packages that provide a more
|
||||
// portable interface to the system, such as "os", "time" and "net". Use
|
||||
// those packages rather than this one if you can.
|
||||
// For details of the functions and data types in this package consult
|
||||
// the manuals for the appropriate operating system.
|
||||
// These calls return err == nil to indicate success; otherwise
|
||||
// err represents an operating system error describing the failure and
|
||||
// holds a value of type syscall.Errno.
|
||||
package windows
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||
// containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, syscall.EINVAL).
|
||||
func ByteSliceFromString(s string) ([]byte, error) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == 0 {
|
||||
return nil, syscall.EINVAL
|
||||
}
|
||||
}
|
||||
a := make([]byte, len(s)+1)
|
||||
copy(a, s)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// BytePtrFromString returns a pointer to a NUL-terminated array of
|
||||
// bytes containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, syscall.EINVAL).
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
a, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &a[0], nil
|
||||
}
|
||||
|
||||
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||
// See mksyscall.pl.
|
||||
var _zero uintptr
|
||||
|
||||
func (ts *Timespec) Unix() (sec int64, nsec int64) {
|
||||
return int64(ts.Sec), int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Unix() (sec int64, nsec int64) {
|
||||
return int64(tv.Sec), int64(tv.Usec) * 1000
|
||||
}
|
||||
|
||||
func (ts *Timespec) Nano() int64 {
|
||||
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Nano() int64 {
|
||||
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
|
||||
}
|
||||
|
||||
// use is a no-op, but the compiler cannot see that it is.
|
||||
// Calling use(p) ensures that p is kept live until that point.
|
||||
//go:noescape
|
||||
func use(p unsafe.Pointer)
|
990
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
Normal file
990
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,990 @@
|
||||
// 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.
|
||||
|
||||
// Windows system calls.
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
errorspkg "errors"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
|
||||
|
||||
type Handle uintptr
|
||||
|
||||
const InvalidHandle = ^Handle(0)
|
||||
|
||||
// StringToUTF16 is deprecated. Use UTF16FromString instead.
|
||||
// If s contains a NUL byte this function panics instead of
|
||||
// returning an error.
|
||||
func StringToUTF16(s string) []uint16 {
|
||||
a, err := UTF16FromString(s)
|
||||
if err != nil {
|
||||
panic("windows: string with NUL passed to StringToUTF16")
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// UTF16FromString returns the UTF-16 encoding of the UTF-8 string
|
||||
// s, with a terminating NUL added. If s contains a NUL byte at any
|
||||
// location, it returns (nil, syscall.EINVAL).
|
||||
func UTF16FromString(s string) ([]uint16, error) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == 0 {
|
||||
return nil, syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return utf16.Encode([]rune(s + "\x00")), nil
|
||||
}
|
||||
|
||||
// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
|
||||
// with a terminating NUL removed.
|
||||
func UTF16ToString(s []uint16) string {
|
||||
for i, v := range s {
|
||||
if v == 0 {
|
||||
s = s[0:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
return string(utf16.Decode(s))
|
||||
}
|
||||
|
||||
// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
|
||||
// If s contains a NUL byte this function panics instead of
|
||||
// returning an error.
|
||||
func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
|
||||
|
||||
// UTF16PtrFromString returns pointer to the UTF-16 encoding of
|
||||
// the UTF-8 string s, with a terminating NUL added. If s
|
||||
// contains a NUL byte at any location, it returns (nil, syscall.EINVAL).
|
||||
func UTF16PtrFromString(s string) (*uint16, error) {
|
||||
a, err := UTF16FromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &a[0], nil
|
||||
}
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
// Converts a Go function to a function pointer conforming
|
||||
// to the stdcall or cdecl calling convention. This is useful when
|
||||
// interoperating with Windows code requiring callbacks.
|
||||
// Implemented in runtime/syscall_windows.goc
|
||||
func NewCallback(fn interface{}) uintptr
|
||||
func NewCallbackCDecl(fn interface{}) uintptr
|
||||
|
||||
// windows api calls
|
||||
|
||||
//sys GetLastError() (lasterr error)
|
||||
//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW
|
||||
//sys FreeLibrary(handle Handle) (err error)
|
||||
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
|
||||
//sys GetVersion() (ver uint32, err error)
|
||||
//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
|
||||
//sys ExitProcess(exitcode uint32)
|
||||
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
|
||||
//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
|
||||
//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
|
||||
//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff]
|
||||
//sys CloseHandle(handle Handle) (err error)
|
||||
//sys GetStdHandle(stdhandle int) (handle Handle, err error) [failretval==InvalidHandle]
|
||||
//sys findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW
|
||||
//sys findNextFile1(handle Handle, data *win32finddata1) (err error) = FindNextFileW
|
||||
//sys FindClose(handle Handle) (err error)
|
||||
//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error)
|
||||
//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW
|
||||
//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW
|
||||
//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW
|
||||
//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW
|
||||
//sys DeleteFile(path *uint16) (err error) = DeleteFileW
|
||||
//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW
|
||||
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
|
||||
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
|
||||
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
|
||||
//sys SetEndOfFile(handle Handle) (err error)
|
||||
//sys GetSystemTimeAsFileTime(time *Filetime)
|
||||
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
|
||||
//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error)
|
||||
//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error)
|
||||
//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error)
|
||||
//sys CancelIo(s Handle) (err error)
|
||||
//sys CancelIoEx(s Handle, o *Overlapped) (err error)
|
||||
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW
|
||||
//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error)
|
||||
//sys TerminateProcess(handle Handle, exitcode uint32) (err error)
|
||||
//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error)
|
||||
//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW
|
||||
//sys GetCurrentProcess() (pseudoHandle Handle, err error)
|
||||
//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
|
||||
//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
|
||||
//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
|
||||
//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW
|
||||
//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error)
|
||||
//sys GetFileType(filehandle Handle) (n uint32, err error)
|
||||
//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW
|
||||
//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext
|
||||
//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom
|
||||
//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW
|
||||
//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW
|
||||
//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW
|
||||
//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW
|
||||
//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
|
||||
//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
|
||||
//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW
|
||||
//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW
|
||||
//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
|
||||
//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW
|
||||
//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0]
|
||||
//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
|
||||
//sys FlushFileBuffers(handle Handle) (err error)
|
||||
//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW
|
||||
//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW
|
||||
//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW
|
||||
//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW
|
||||
//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error)
|
||||
//sys UnmapViewOfFile(addr uintptr) (err error)
|
||||
//sys FlushViewOfFile(addr uintptr, length uintptr) (err error)
|
||||
//sys VirtualLock(addr uintptr, length uintptr) (err error)
|
||||
//sys VirtualUnlock(addr uintptr, length uintptr) (err error)
|
||||
//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
|
||||
//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
|
||||
//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW
|
||||
//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore
|
||||
//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore
|
||||
//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore
|
||||
//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore
|
||||
//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain
|
||||
//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain
|
||||
//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext
|
||||
//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext
|
||||
//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy
|
||||
//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW
|
||||
//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey
|
||||
//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
|
||||
//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
|
||||
//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
|
||||
//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
|
||||
//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
|
||||
//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
|
||||
//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
|
||||
//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
|
||||
//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW
|
||||
//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW
|
||||
//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error)
|
||||
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
|
||||
//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW
|
||||
//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW
|
||||
//sys GetCurrentThreadId() (id uint32)
|
||||
//sys CreateEvent(eventAttrs *syscall.SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) = kernel32.CreateEventW
|
||||
//sys SetEvent(event Handle) (err error) = kernel32.SetEvent
|
||||
|
||||
// syscall interface implementation for other packages
|
||||
|
||||
func Exit(code int) { ExitProcess(uint32(code)) }
|
||||
|
||||
func makeInheritSa() *SecurityAttributes {
|
||||
var sa SecurityAttributes
|
||||
sa.Length = uint32(unsafe.Sizeof(sa))
|
||||
sa.InheritHandle = 1
|
||||
return &sa
|
||||
}
|
||||
|
||||
func Open(path string, mode int, perm uint32) (fd Handle, err error) {
|
||||
if len(path) == 0 {
|
||||
return InvalidHandle, ERROR_FILE_NOT_FOUND
|
||||
}
|
||||
pathp, err := UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return InvalidHandle, err
|
||||
}
|
||||
var access uint32
|
||||
switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
|
||||
case O_RDONLY:
|
||||
access = GENERIC_READ
|
||||
case O_WRONLY:
|
||||
access = GENERIC_WRITE
|
||||
case O_RDWR:
|
||||
access = GENERIC_READ | GENERIC_WRITE
|
||||
}
|
||||
if mode&O_CREAT != 0 {
|
||||
access |= GENERIC_WRITE
|
||||
}
|
||||
if mode&O_APPEND != 0 {
|
||||
access &^= GENERIC_WRITE
|
||||
access |= FILE_APPEND_DATA
|
||||
}
|
||||
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
|
||||
var sa *SecurityAttributes
|
||||
if mode&O_CLOEXEC == 0 {
|
||||
sa = makeInheritSa()
|
||||
}
|
||||
var createmode uint32
|
||||
switch {
|
||||
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
|
||||
createmode = CREATE_NEW
|
||||
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
|
||||
createmode = CREATE_ALWAYS
|
||||
case mode&O_CREAT == O_CREAT:
|
||||
createmode = OPEN_ALWAYS
|
||||
case mode&O_TRUNC == O_TRUNC:
|
||||
createmode = TRUNCATE_EXISTING
|
||||
default:
|
||||
createmode = OPEN_EXISTING
|
||||
}
|
||||
h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
|
||||
return h, e
|
||||
}
|
||||
|
||||
func Read(fd Handle, p []byte) (n int, err error) {
|
||||
var done uint32
|
||||
e := ReadFile(fd, p, &done, nil)
|
||||
if e != nil {
|
||||
if e == ERROR_BROKEN_PIPE {
|
||||
// NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
|
||||
return 0, nil
|
||||
}
|
||||
return 0, e
|
||||
}
|
||||
if raceenabled {
|
||||
if done > 0 {
|
||||
raceWriteRange(unsafe.Pointer(&p[0]), int(done))
|
||||
}
|
||||
raceAcquire(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
return int(done), nil
|
||||
}
|
||||
|
||||
func Write(fd Handle, p []byte) (n int, err error) {
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
var done uint32
|
||||
e := WriteFile(fd, p, &done, nil)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
if raceenabled && done > 0 {
|
||||
raceReadRange(unsafe.Pointer(&p[0]), int(done))
|
||||
}
|
||||
return int(done), nil
|
||||
}
|
||||
|
||||
var ioSync int64
|
||||
|
||||
func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) {
|
||||
var w uint32
|
||||
switch whence {
|
||||
case 0:
|
||||
w = FILE_BEGIN
|
||||
case 1:
|
||||
w = FILE_CURRENT
|
||||
case 2:
|
||||
w = FILE_END
|
||||
}
|
||||
hi := int32(offset >> 32)
|
||||
lo := int32(offset)
|
||||
// use GetFileType to check pipe, pipe can't do seek
|
||||
ft, _ := GetFileType(fd)
|
||||
if ft == FILE_TYPE_PIPE {
|
||||
return 0, syscall.EPIPE
|
||||
}
|
||||
rlo, e := SetFilePointer(fd, lo, &hi, w)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
return int64(hi)<<32 + int64(rlo), nil
|
||||
}
|
||||
|
||||
func Close(fd Handle) (err error) {
|
||||
return CloseHandle(fd)
|
||||
}
|
||||
|
||||
var (
|
||||
Stdin = getStdHandle(STD_INPUT_HANDLE)
|
||||
Stdout = getStdHandle(STD_OUTPUT_HANDLE)
|
||||
Stderr = getStdHandle(STD_ERROR_HANDLE)
|
||||
)
|
||||
|
||||
func getStdHandle(h int) (fd Handle) {
|
||||
r, _ := GetStdHandle(h)
|
||||
CloseOnExec(r)
|
||||
return r
|
||||
}
|
||||
|
||||
const ImplementsGetwd = true
|
||||
|
||||
func Getwd() (wd string, err error) {
|
||||
b := make([]uint16, 300)
|
||||
n, e := GetCurrentDirectory(uint32(len(b)), &b[0])
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
return string(utf16.Decode(b[0:n])), nil
|
||||
}
|
||||
|
||||
func Chdir(path string) (err error) {
|
||||
pathp, err := UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return SetCurrentDirectory(pathp)
|
||||
}
|
||||
|
||||
func Mkdir(path string, mode uint32) (err error) {
|
||||
pathp, err := UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return CreateDirectory(pathp, nil)
|
||||
}
|
||||
|
||||
func Rmdir(path string) (err error) {
|
||||
pathp, err := UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return RemoveDirectory(pathp)
|
||||
}
|
||||
|
||||
func Unlink(path string) (err error) {
|
||||
pathp, err := UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return DeleteFile(pathp)
|
||||
}
|
||||
|
||||
func Rename(oldpath, newpath string) (err error) {
|
||||
from, err := UTF16PtrFromString(oldpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
to, err := UTF16PtrFromString(newpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
|
||||
}
|
||||
|
||||
func ComputerName() (name string, err error) {
|
||||
var n uint32 = MAX_COMPUTERNAME_LENGTH + 1
|
||||
b := make([]uint16, n)
|
||||
e := GetComputerName(&b[0], &n)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
return string(utf16.Decode(b[0:n])), nil
|
||||
}
|
||||
|
||||
func Ftruncate(fd Handle, length int64) (err error) {
|
||||
curoffset, e := Seek(fd, 0, 1)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer Seek(fd, curoffset, 0)
|
||||
_, e = Seek(fd, length, 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
e = SetEndOfFile(fd)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Gettimeofday(tv *Timeval) (err error) {
|
||||
var ft Filetime
|
||||
GetSystemTimeAsFileTime(&ft)
|
||||
*tv = NsecToTimeval(ft.Nanoseconds())
|
||||
return nil
|
||||
}
|
||||
|
||||
func Pipe(p []Handle) (err error) {
|
||||
if len(p) != 2 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
var r, w Handle
|
||||
e := CreatePipe(&r, &w, makeInheritSa(), 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
p[0] = r
|
||||
p[1] = w
|
||||
return nil
|
||||
}
|
||||
|
||||
func Utimes(path string, tv []Timeval) (err error) {
|
||||
if len(tv) != 2 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
pathp, e := UTF16PtrFromString(path)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
h, e := CreateFile(pathp,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer Close(h)
|
||||
a := NsecToFiletime(tv[0].Nanoseconds())
|
||||
w := NsecToFiletime(tv[1].Nanoseconds())
|
||||
return SetFileTime(h, nil, &a, &w)
|
||||
}
|
||||
|
||||
func UtimesNano(path string, ts []Timespec) (err error) {
|
||||
if len(ts) != 2 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
pathp, e := UTF16PtrFromString(path)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
h, e := CreateFile(pathp,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer Close(h)
|
||||
a := NsecToFiletime(TimespecToNsec(ts[0]))
|
||||
w := NsecToFiletime(TimespecToNsec(ts[1]))
|
||||
return SetFileTime(h, nil, &a, &w)
|
||||
}
|
||||
|
||||
func Fsync(fd Handle) (err error) {
|
||||
return FlushFileBuffers(fd)
|
||||
}
|
||||
|
||||
func Chmod(path string, mode uint32) (err error) {
|
||||
if mode == 0 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
p, e := UTF16PtrFromString(path)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
attrs, e := GetFileAttributes(p)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
if mode&S_IWRITE != 0 {
|
||||
attrs &^= FILE_ATTRIBUTE_READONLY
|
||||
} else {
|
||||
attrs |= FILE_ATTRIBUTE_READONLY
|
||||
}
|
||||
return SetFileAttributes(p, attrs)
|
||||
}
|
||||
|
||||
func LoadCancelIoEx() error {
|
||||
return procCancelIoEx.Find()
|
||||
}
|
||||
|
||||
func LoadSetFileCompletionNotificationModes() error {
|
||||
return procSetFileCompletionNotificationModes.Find()
|
||||
}
|
||||
|
||||
// net api calls
|
||||
|
||||
const socket_error = uintptr(^uint32(0))
|
||||
|
||||
//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup
|
||||
//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup
|
||||
//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl
|
||||
//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
|
||||
//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
|
||||
//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
|
||||
//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
|
||||
//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
|
||||
//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname
|
||||
//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername
|
||||
//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen
|
||||
//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown
|
||||
//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket
|
||||
//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx
|
||||
//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs
|
||||
//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv
|
||||
//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend
|
||||
//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom
|
||||
//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo
|
||||
//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname
|
||||
//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname
|
||||
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
|
||||
//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname
|
||||
//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W
|
||||
//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
|
||||
//sys DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) = dnsapi.DnsNameCompare_W
|
||||
//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW
|
||||
//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW
|
||||
//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
|
||||
//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
|
||||
//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes
|
||||
//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW
|
||||
//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
|
||||
//sys GetACP() (acp uint32) = kernel32.GetACP
|
||||
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
|
||||
|
||||
// For testing: clients can set this flag to force
|
||||
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||
var SocketDisableIPv6 bool
|
||||
|
||||
type RawSockaddrInet4 struct {
|
||||
Family uint16
|
||||
Port uint16
|
||||
Addr [4]byte /* in_addr */
|
||||
Zero [8]uint8
|
||||
}
|
||||
|
||||
type RawSockaddrInet6 struct {
|
||||
Family uint16
|
||||
Port uint16
|
||||
Flowinfo uint32
|
||||
Addr [16]byte /* in6_addr */
|
||||
Scope_id uint32
|
||||
}
|
||||
|
||||
type RawSockaddr struct {
|
||||
Family uint16
|
||||
Data [14]int8
|
||||
}
|
||||
|
||||
type RawSockaddrAny struct {
|
||||
Addr RawSockaddr
|
||||
Pad [96]int8
|
||||
}
|
||||
|
||||
type Sockaddr interface {
|
||||
sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs
|
||||
}
|
||||
|
||||
type SockaddrInet4 struct {
|
||||
Port int
|
||||
Addr [4]byte
|
||||
raw RawSockaddrInet4
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) {
|
||||
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||||
return nil, 0, syscall.EINVAL
|
||||
}
|
||||
sa.raw.Family = AF_INET
|
||||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
||||
p[0] = byte(sa.Port >> 8)
|
||||
p[1] = byte(sa.Port)
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.raw.Addr[i] = sa.Addr[i]
|
||||
}
|
||||
return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
|
||||
}
|
||||
|
||||
type SockaddrInet6 struct {
|
||||
Port int
|
||||
ZoneId uint32
|
||||
Addr [16]byte
|
||||
raw RawSockaddrInet6
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
|
||||
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||||
return nil, 0, syscall.EINVAL
|
||||
}
|
||||
sa.raw.Family = AF_INET6
|
||||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
||||
p[0] = byte(sa.Port >> 8)
|
||||
p[1] = byte(sa.Port)
|
||||
sa.raw.Scope_id = sa.ZoneId
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.raw.Addr[i] = sa.Addr[i]
|
||||
}
|
||||
return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
|
||||
}
|
||||
|
||||
type SockaddrUnix struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
|
||||
// TODO(brainman): implement SockaddrUnix.sockaddr()
|
||||
return nil, 0, syscall.EWINDOWS
|
||||
}
|
||||
|
||||
func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
|
||||
switch rsa.Addr.Family {
|
||||
case AF_UNIX:
|
||||
return nil, syscall.EWINDOWS
|
||||
|
||||
case AF_INET:
|
||||
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet4)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
|
||||
case AF_INET6:
|
||||
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet6)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
sa.ZoneId = pp.Scope_id
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
}
|
||||
return nil, syscall.EAFNOSUPPORT
|
||||
}
|
||||
|
||||
func Socket(domain, typ, proto int) (fd Handle, err error) {
|
||||
if domain == AF_INET6 && SocketDisableIPv6 {
|
||||
return InvalidHandle, syscall.EAFNOSUPPORT
|
||||
}
|
||||
return socket(int32(domain), int32(typ), int32(proto))
|
||||
}
|
||||
|
||||
func SetsockoptInt(fd Handle, level, opt int, value int) (err error) {
|
||||
v := int32(value)
|
||||
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v)))
|
||||
}
|
||||
|
||||
func Bind(fd Handle, sa Sockaddr) (err error) {
|
||||
ptr, n, err := sa.sockaddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bind(fd, ptr, n)
|
||||
}
|
||||
|
||||
func Connect(fd Handle, sa Sockaddr) (err error) {
|
||||
ptr, n, err := sa.sockaddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return connect(fd, ptr, n)
|
||||
}
|
||||
|
||||
func Getsockname(fd Handle) (sa Sockaddr, err error) {
|
||||
var rsa RawSockaddrAny
|
||||
l := int32(unsafe.Sizeof(rsa))
|
||||
if err = getsockname(fd, &rsa, &l); err != nil {
|
||||
return
|
||||
}
|
||||
return rsa.Sockaddr()
|
||||
}
|
||||
|
||||
func Getpeername(fd Handle) (sa Sockaddr, err error) {
|
||||
var rsa RawSockaddrAny
|
||||
l := int32(unsafe.Sizeof(rsa))
|
||||
if err = getpeername(fd, &rsa, &l); err != nil {
|
||||
return
|
||||
}
|
||||
return rsa.Sockaddr()
|
||||
}
|
||||
|
||||
func Listen(s Handle, n int) (err error) {
|
||||
return listen(s, int32(n))
|
||||
}
|
||||
|
||||
func Shutdown(fd Handle, how int) (err error) {
|
||||
return shutdown(fd, int32(how))
|
||||
}
|
||||
|
||||
func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) {
|
||||
rsa, l, err := to.sockaddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine)
|
||||
}
|
||||
|
||||
func LoadGetAddrInfo() error {
|
||||
return procGetAddrInfoW.Find()
|
||||
}
|
||||
|
||||
var connectExFunc struct {
|
||||
once sync.Once
|
||||
addr uintptr
|
||||
err error
|
||||
}
|
||||
|
||||
func LoadConnectEx() error {
|
||||
connectExFunc.once.Do(func() {
|
||||
var s Handle
|
||||
s, connectExFunc.err = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
|
||||
if connectExFunc.err != nil {
|
||||
return
|
||||
}
|
||||
defer CloseHandle(s)
|
||||
var n uint32
|
||||
connectExFunc.err = WSAIoctl(s,
|
||||
SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||
(*byte)(unsafe.Pointer(&WSAID_CONNECTEX)),
|
||||
uint32(unsafe.Sizeof(WSAID_CONNECTEX)),
|
||||
(*byte)(unsafe.Pointer(&connectExFunc.addr)),
|
||||
uint32(unsafe.Sizeof(connectExFunc.addr)),
|
||||
&n, nil, 0)
|
||||
})
|
||||
return connectExFunc.err
|
||||
}
|
||||
|
||||
func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ConnectEx(fd Handle, sa Sockaddr, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) error {
|
||||
err := LoadConnectEx()
|
||||
if err != nil {
|
||||
return errorspkg.New("failed to find ConnectEx: " + err.Error())
|
||||
}
|
||||
ptr, n, err := sa.sockaddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
|
||||
}
|
||||
|
||||
// Invented structures to support what package os expects.
|
||||
type Rusage struct {
|
||||
CreationTime Filetime
|
||||
ExitTime Filetime
|
||||
KernelTime Filetime
|
||||
UserTime Filetime
|
||||
}
|
||||
|
||||
type WaitStatus struct {
|
||||
ExitCode uint32
|
||||
}
|
||||
|
||||
func (w WaitStatus) Exited() bool { return true }
|
||||
|
||||
func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) }
|
||||
|
||||
func (w WaitStatus) Signal() Signal { return -1 }
|
||||
|
||||
func (w WaitStatus) CoreDump() bool { return false }
|
||||
|
||||
func (w WaitStatus) Stopped() bool { return false }
|
||||
|
||||
func (w WaitStatus) Continued() bool { return false }
|
||||
|
||||
func (w WaitStatus) StopSignal() Signal { return -1 }
|
||||
|
||||
func (w WaitStatus) Signaled() bool { return false }
|
||||
|
||||
func (w WaitStatus) TrapCause() int { return -1 }
|
||||
|
||||
// Timespec is an invented structure on Windows, but here for
|
||||
// consistency with the corresponding package for other operating systems.
|
||||
type Timespec struct {
|
||||
Sec int64
|
||||
Nsec int64
|
||||
}
|
||||
|
||||
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
||||
|
||||
func NsecToTimespec(nsec int64) (ts Timespec) {
|
||||
ts.Sec = nsec / 1e9
|
||||
ts.Nsec = nsec % 1e9
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(brainman): fix all needed for net
|
||||
|
||||
func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, syscall.EWINDOWS }
|
||||
func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) {
|
||||
return 0, nil, syscall.EWINDOWS
|
||||
}
|
||||
func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return syscall.EWINDOWS }
|
||||
func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return syscall.EWINDOWS }
|
||||
|
||||
// The Linger struct is wrong but we only noticed after Go 1.
|
||||
// sysLinger is the real system call structure.
|
||||
|
||||
// BUG(brainman): The definition of Linger is not appropriate for direct use
|
||||
// with Setsockopt and Getsockopt.
|
||||
// Use SetsockoptLinger instead.
|
||||
|
||||
type Linger struct {
|
||||
Onoff int32
|
||||
Linger int32
|
||||
}
|
||||
|
||||
type sysLinger struct {
|
||||
Onoff uint16
|
||||
Linger uint16
|
||||
}
|
||||
|
||||
type IPMreq struct {
|
||||
Multiaddr [4]byte /* in_addr */
|
||||
Interface [4]byte /* in_addr */
|
||||
}
|
||||
|
||||
type IPv6Mreq struct {
|
||||
Multiaddr [16]byte /* in6_addr */
|
||||
Interface uint32
|
||||
}
|
||||
|
||||
func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, syscall.EWINDOWS }
|
||||
|
||||
func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) {
|
||||
sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)}
|
||||
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&sys)), int32(unsafe.Sizeof(sys)))
|
||||
}
|
||||
|
||||
func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) {
|
||||
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
|
||||
}
|
||||
func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) {
|
||||
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq)))
|
||||
}
|
||||
func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) {
|
||||
return syscall.EWINDOWS
|
||||
}
|
||||
|
||||
func Getpid() (pid int) { return int(getCurrentProcessId()) }
|
||||
|
||||
func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) {
|
||||
// NOTE(rsc): The Win32finddata struct is wrong for the system call:
|
||||
// the two paths are each one uint16 short. Use the correct struct,
|
||||
// a win32finddata1, and then copy the results out.
|
||||
// There is no loss of expressivity here, because the final
|
||||
// uint16, if it is used, is supposed to be a NUL, and Go doesn't need that.
|
||||
// For Go 1.1, we might avoid the allocation of win32finddata1 here
|
||||
// by adding a final Bug [2]uint16 field to the struct and then
|
||||
// adjusting the fields in the result directly.
|
||||
var data1 win32finddata1
|
||||
handle, err = findFirstFile1(name, &data1)
|
||||
if err == nil {
|
||||
copyFindData(data, &data1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func FindNextFile(handle Handle, data *Win32finddata) (err error) {
|
||||
var data1 win32finddata1
|
||||
err = findNextFile1(handle, &data1)
|
||||
if err == nil {
|
||||
copyFindData(data, &data1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getProcessEntry(pid int) (*ProcessEntry32, error) {
|
||||
snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer CloseHandle(snapshot)
|
||||
var procEntry ProcessEntry32
|
||||
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
|
||||
if err = Process32First(snapshot, &procEntry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
if procEntry.ProcessID == uint32(pid) {
|
||||
return &procEntry, nil
|
||||
}
|
||||
err = Process32Next(snapshot, &procEntry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Getppid() (ppid int) {
|
||||
pe, err := getProcessEntry(Getpid())
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return int(pe.ParentProcessID)
|
||||
}
|
||||
|
||||
// TODO(brainman): fix all needed for os
|
||||
func Fchdir(fd Handle) (err error) { return syscall.EWINDOWS }
|
||||
func Link(oldpath, newpath string) (err error) { return syscall.EWINDOWS }
|
||||
func Symlink(path, link string) (err error) { return syscall.EWINDOWS }
|
||||
|
||||
func Fchmod(fd Handle, mode uint32) (err error) { return syscall.EWINDOWS }
|
||||
func Chown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS }
|
||||
func Lchown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS }
|
||||
func Fchown(fd Handle, uid int, gid int) (err error) { return syscall.EWINDOWS }
|
||||
|
||||
func Getuid() (uid int) { return -1 }
|
||||
func Geteuid() (euid int) { return -1 }
|
||||
func Getgid() (gid int) { return -1 }
|
||||
func Getegid() (egid int) { return -1 }
|
||||
func Getgroups() (gids []int, err error) { return nil, syscall.EWINDOWS }
|
||||
|
||||
type Signal int
|
||||
|
||||
func (s Signal) Signal() {}
|
||||
|
||||
func (s Signal) String() string {
|
||||
if 0 <= s && int(s) < len(signals) {
|
||||
str := signals[s]
|
||||
if str != "" {
|
||||
return str
|
||||
}
|
||||
}
|
||||
return "signal " + itoa(int(s))
|
||||
}
|
||||
|
||||
func LoadCreateSymbolicLink() error {
|
||||
return procCreateSymbolicLinkW.Find()
|
||||
}
|
||||
|
||||
// Readlink returns the destination of the named symbolic link.
|
||||
func Readlink(path string, buf []byte) (n int, err error) {
|
||||
fd, err := CreateFile(StringToUTF16Ptr(path), GENERIC_READ, 0, nil, OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
defer CloseHandle(fd)
|
||||
|
||||
rdbbuf := make([]byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
||||
var bytesReturned uint32
|
||||
err = DeviceIoControl(fd, FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
|
||||
var s string
|
||||
switch rdb.ReparseTag {
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
|
||||
p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
|
||||
s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
|
||||
case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
|
||||
p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
|
||||
s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
|
||||
default:
|
||||
// the path is not a symlink or junction but another type of reparse
|
||||
// point
|
||||
return -1, syscall.ENOENT
|
||||
}
|
||||
n = copy(buf, []byte(s))
|
||||
|
||||
return n, nil
|
||||
}
|
2220
vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
Normal file
2220
vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1242
vendor/golang.org/x/sys/windows/ztypes_windows.go
generated
vendored
Normal file
1242
vendor/golang.org/x/sys/windows/ztypes_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22
vendor/golang.org/x/sys/windows/ztypes_windows_386.go
generated
vendored
Normal file
22
vendor/golang.org/x/sys/windows/ztypes_windows_386.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2011 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 windows
|
||||
|
||||
type WSAData struct {
|
||||
Version uint16
|
||||
HighVersion uint16
|
||||
Description [WSADESCRIPTION_LEN + 1]byte
|
||||
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||
MaxSockets uint16
|
||||
MaxUdpDg uint16
|
||||
VendorInfo *byte
|
||||
}
|
||||
|
||||
type Servent struct {
|
||||
Name *byte
|
||||
Aliases **byte
|
||||
Port uint16
|
||||
Proto *byte
|
||||
}
|
22
vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go
generated
vendored
Normal file
22
vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2011 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 windows
|
||||
|
||||
type WSAData struct {
|
||||
Version uint16
|
||||
HighVersion uint16
|
||||
MaxSockets uint16
|
||||
MaxUdpDg uint16
|
||||
VendorInfo *byte
|
||||
Description [WSADESCRIPTION_LEN + 1]byte
|
||||
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||
}
|
||||
|
||||
type Servent struct {
|
||||
Name *byte
|
||||
Aliases **byte
|
||||
Proto *byte
|
||||
Port uint16
|
||||
}
|
Reference in New Issue
Block a user