all: delete obsolete/unsupported packages
Per discussion in proposal #25503, delete a number of packages which
were at best unmaintained and at worst completely broken. We don't think
anyone is using these.
IF THIS CHANGE BREAKS YOU:
Please file a bug on the main Go issue tracker and we'll try to work
something out. Go 1.11 will definitely cause problems for any users of
these packages without some work.
Change-Id: I19365e87d84c9a295bf6cf705a001992839a7dc7
Reviewed-on: https://go-review.googlesource.com/121017
Run-TryBot: Heschi Kreinick <heschi@google.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/arch/arch.go b/arch/arch.go
deleted file mode 100644
index acd2ee9..0000000
--- a/arch/arch.go
+++ /dev/null
@@ -1,176 +0,0 @@
-// 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 arch contains architecture-specific definitions.
-package arch // import "golang.org/x/debug/arch"
-
-import (
- "encoding/binary"
- "math"
-)
-
-const MaxBreakpointSize = 4 // TODO
-
-// Architecture defines the architecture-specific details for a given machine.
-type Architecture struct {
- // BreakpointSize is the size of a breakpoint instruction, in bytes.
- BreakpointSize int
- // IntSize is the size of the int type, in bytes.
- IntSize int
- // PointerSize is the size of a pointer, in bytes.
- PointerSize int
- // ByteOrder is the byte order for ints and pointers.
- ByteOrder binary.ByteOrder
- // FloatByteOrder is the byte order for floats.
- FloatByteOrder binary.ByteOrder
- BreakpointInstr [MaxBreakpointSize]byte
-}
-
-func (a *Architecture) Int(buf []byte) int64 {
- return int64(a.Uint(buf))
-}
-
-func (a *Architecture) Uint(buf []byte) uint64 {
- if len(buf) != a.IntSize {
- panic("bad IntSize")
- }
- switch a.IntSize {
- case 4:
- return uint64(a.ByteOrder.Uint32(buf[:4]))
- case 8:
- return a.ByteOrder.Uint64(buf[:8])
- }
- panic("no IntSize")
-}
-
-func (a *Architecture) Int16(buf []byte) int16 {
- return int16(a.Uint16(buf))
-}
-
-func (a *Architecture) Int32(buf []byte) int32 {
- return int32(a.Uint32(buf))
-}
-
-func (a *Architecture) Int64(buf []byte) int64 {
- return int64(a.Uint64(buf))
-}
-
-func (a *Architecture) Uint16(buf []byte) uint16 {
- return a.ByteOrder.Uint16(buf)
-}
-
-func (a *Architecture) Uint32(buf []byte) uint32 {
- return a.ByteOrder.Uint32(buf)
-}
-
-func (a *Architecture) Uint64(buf []byte) uint64 {
- return a.ByteOrder.Uint64(buf)
-}
-
-func (a *Architecture) IntN(buf []byte) int64 {
- if len(buf) == 0 {
- return 0
- }
- x := int64(0)
- if a.ByteOrder == binary.LittleEndian {
- i := len(buf) - 1
- x = int64(int8(buf[i])) // sign-extended
- for i--; i >= 0; i-- {
- x <<= 8
- x |= int64(buf[i]) // not sign-extended
- }
- } else {
- x = int64(int8(buf[0])) // sign-extended
- for i := 1; i < len(buf); i++ {
- x <<= 8
- x |= int64(buf[i]) // not sign-extended
- }
- }
- return x
-}
-
-func (a *Architecture) UintN(buf []byte) uint64 {
- u := uint64(0)
- if a.ByteOrder == binary.LittleEndian {
- shift := uint(0)
- for _, c := range buf {
- u |= uint64(c) << shift
- shift += 8
- }
- } else {
- for _, c := range buf {
- u <<= 8
- u |= uint64(c)
- }
- }
- return u
-}
-
-func (a *Architecture) Uintptr(buf []byte) uint64 {
- if len(buf) != a.PointerSize {
- panic("bad PointerSize")
- }
- switch a.PointerSize {
- case 4:
- return uint64(a.ByteOrder.Uint32(buf[:4]))
- case 8:
- return a.ByteOrder.Uint64(buf[:8])
- }
- panic("no PointerSize")
-}
-
-func (a *Architecture) Float32(buf []byte) float32 {
- if len(buf) != 4 {
- panic("bad float32 size")
- }
- return math.Float32frombits(a.FloatByteOrder.Uint32(buf))
-}
-
-func (a *Architecture) Float64(buf []byte) float64 {
- if len(buf) != 8 {
- panic("bad float64 size")
- }
- return math.Float64frombits(a.FloatByteOrder.Uint64(buf))
-}
-
-func (a *Architecture) Complex64(buf []byte) complex64 {
- if len(buf) != 8 {
- panic("bad complex64 size")
- }
- return complex(a.Float32(buf[0:4]), a.Float32(buf[4:8]))
-}
-
-func (a *Architecture) Complex128(buf []byte) complex128 {
- if len(buf) != 16 {
- panic("bad complex128 size")
- }
- return complex(a.Float64(buf[0:8]), a.Float64(buf[8:16]))
-}
-
-var AMD64 = Architecture{
- BreakpointSize: 1,
- IntSize: 8,
- PointerSize: 8,
- ByteOrder: binary.LittleEndian,
- FloatByteOrder: binary.LittleEndian,
- BreakpointInstr: [MaxBreakpointSize]byte{0xCC}, // INT 3
-}
-
-var X86 = Architecture{
- BreakpointSize: 1,
- IntSize: 4,
- PointerSize: 4,
- ByteOrder: binary.LittleEndian,
- FloatByteOrder: binary.LittleEndian,
- BreakpointInstr: [MaxBreakpointSize]byte{0xCC}, // INT 3
-}
-
-var ARM = Architecture{
- BreakpointSize: 4, // TODO
- IntSize: 4,
- PointerSize: 4,
- ByteOrder: binary.LittleEndian,
- FloatByteOrder: binary.LittleEndian, // TODO
- BreakpointInstr: [MaxBreakpointSize]byte{0x00, 0x00, 0x00, 0x00}, // TODO
-}
diff --git a/cmd/debugproxy/main.go b/cmd/debugproxy/main.go
deleted file mode 100644
index 942790b..0000000
--- a/cmd/debugproxy/main.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-
-// debugproxy connects to the target binary, and serves an RPC interface using
-// the types in server/protocol to access and control it.
-package main
-
-import (
- "flag"
- "fmt"
- "log"
- "net/rpc"
- "os"
-
- "golang.org/x/debug/server"
-)
-
-var (
- textFlag = flag.String("text", "", "file name of binary being debugged")
-)
-
-func main() {
- log.SetFlags(0)
- log.SetPrefix("debugproxy: ")
- flag.Parse()
- if *textFlag == "" {
- flag.Usage()
- os.Exit(2)
- }
- s, err := server.New(*textFlag)
- if err != nil {
- fmt.Printf("server.New: %v\n", err)
- os.Exit(2)
- }
- err = rpc.Register(s)
- if err != nil {
- fmt.Printf("rpc.Register: %v\n", err)
- os.Exit(2)
- }
- fmt.Println("OK")
- log.Print("starting server")
- rpc.ServeConn(&rwc{
- os.Stdin,
- os.Stdout,
- })
- log.Print("server finished")
-}
-
-// rwc creates a single io.ReadWriteCloser from a read side and a write side.
-// It allows us to do RPC using standard in and standard out.
-type rwc struct {
- r *os.File
- w *os.File
-}
-
-func (rwc *rwc) Read(p []byte) (int, error) {
- return rwc.r.Read(p)
-}
-
-func (rwc *rwc) Write(p []byte) (int, error) {
- return rwc.w.Write(p)
-}
-
-func (rwc *rwc) Close() error {
- rerr := rwc.r.Close()
- werr := rwc.w.Close()
- if rerr != nil {
- return rerr
- }
- return werr
-}
diff --git a/doc/ptrace-nptl.txt b/doc/ptrace-nptl.txt
deleted file mode 100644
index 81f6a10..0000000
--- a/doc/ptrace-nptl.txt
+++ /dev/null
@@ -1,128 +0,0 @@
-ptrace and NTPL, the missing manpage
-
-== Signals ==
-
-A signal sent to a ptrace'd process or thread causes only the thread
-that receives it to stop and report to the attached process.
-
-Use tgkill to target a signal (for example, SIGSTOP) at a particular
-thread. If you use kill, the signal could be delivered to another
-thread in the same process.
-
-Note that SIGSTOP differs from its usual behavior when a process is
-being traced. Usually, a SIGSTOP sent to any thread in a thread group
-will stop all threads in the thread group. When a thread is traced,
-however, a SIGSTOP affects only the receiving thread (and any other
-threads in the thread group that are not traced).
-
-SIGKILL behaves like it does for non-traced processes. It affects all
-threads in the process and terminates them without the WSTOPSIG event
-generated by other signals. However, if PTRACE_O_TRACEEXIT is set,
-the attached process will still receive PTRACE_EVENT_EXIT events
-before receiving WIFSIGNALED events.
-
-See "Following thread death" for a caveat regarding signal delivery to
-zombie threads.
-
-== Waiting on threads ==
-
-Cloned threads in ptrace'd processes are treated similarly to cloned
-threads in your own process. Thus, you must use the __WALL option in
-order to receive notifications from threads created by the child
-process. Similarly, the __WCLONE option will wait only on
-notifications from threads created by the child process and *not* on
-notifications from the initial child thread.
-
-Even when waiting on a specific thread's PID using waitpid or similar,
-__WALL or __WCLONE is necessary or waitpid will return ECHILD.
-
-== Attaching to existing threads ==
-
-libthread_db (which gdb uses), attaches to existing threads by pulling
-the pthread data structures out of the traced process. The much
-easier way is to traverse the /proc/PID/task directory, though it's
-unclear how the semantics of these two approaches differ.
-
-Unfortunately, if the main thread has exited (but the overall process
-has not), it sticks around as a zombie process. This zombie will
-appear in the /proc/PID/task directory, but trying to attach to it
-will yield EPERM. In this case, the third field of the
-/proc/PID/task/PID/stat file will be "Z". Attempting to open the stat
-file is also a convenient way to detect races between listing the task
-directory and the thread exiting. Coincidentally, gdb will simply
-fail to attach to a process whose main thread is a zombie.
-
-Because new threads may be created while the debugger is in the
-process of attaching to existing threads, the debugger must repeatedly
-re-list the task directory until it has attached to (and thus stopped)
-every thread listed.
-
-In order to follow new threads created by existing threads,
-PTRACE_O_TRACECLONE must be set on each thread attached to.
-
-== Following new threads ==
-
-With the child process stopped, use PTRACE_SETOPTIONS to set the
-PTRACE_O_TRACECLONE option. This option is per-thread, and thus must
-be set on each existing thread individually. When an existing thread
-with PTRACE_O_TRACECLONE set spawns a new thread, the existing thread
-will stop with (SIGTRAP | PTRACE_EVENT_CLONE << 8) and the PID of the
-new thread can be retrieved with PTRACE_GETEVENTMSG on the creating
-thread. At this time, the new thread will exist, but will initially
-be stopped with a SIGSTOP. The new thread will automatically be
-traced and will inherit the PTRACE_O_TRACECLONE option from its
-parent. The attached process should wait on the new thread to receive
-the SIGSTOP notification.
-
-When using waitpid(-1, ...), don't rely on the parent thread reporting
-a SIGTRAP before receiving the SIGSTOP from the new child thread.
-
-Without PTRACE_O_TRACECLONE, newly cloned threads will not be
-ptrace'd. As a result, signals received by new threads will be
-handled in the usual way, which may affect the parent and in turn
-appear to the attached process, but attributed to the parent (possibly
-in unexpected ways).
-
-== Following thread death ==
-
-If any thread with the PTRACE_O_TRACEEXIT option set exits (either by
-returning or pthread_exit'ing), the tracing process will receive an
-immediate PTRACE_EVENT_EXIT. At this point, the thread will still
-exist. The exit status, encoded as for wait, can be queried using
-PTRACE_GETEVENTMSG on the exiting thread's PID. The thread should be
-continued so it can actually exit, after which its wait behavior is
-the same as for a thread without the PTRACE_O_TRACEEXIT option.
-
-If a non-main thread exits (either by returning or pthread_exit'ing),
-its corresponding process will also exit, producing a WIFEXITED event
-(after the process is continued from a possible PTRACE_EVENT_EXIT
-event). It is *not* necessary for another thread to ptrace_join for
-this to happen.
-
-If the main thread exits by returning, then all threads will exit,
-first generating a PTRACE_EVENT_EXIT event for each thread if
-appropriate, then producing a WIFEXITED event for each thread.
-
-If the main thread exits using pthread_exit, then it enters a
-non-waitable zombie state. It will still produce an immediate
-PTRACE_O_TRACEEXIT event, but the WIFEXITED event will be delayed
-until the entire process exits. This state exists so that shells
-don't think the process is done until all of the threads have exited.
-Unfortunately, signals cannot be delivered to non-waitable zombies.
-Most notably, SIGSTOP cannot be delivered; as a result, when you
-broadcast SIGSTOP to all of the threads, you must not wait for
-non-waitable zombies to stop. Furthermore, any ptrace command on a
-non-waitable zombie, including PTRACE_DETACH, will return ESRCH.
-
-== Multi-threaded debuggers ==
-
-If the debugger itself is multi-threaded, ptrace calls must come from
-the same thread that originally attached to the remote thread. The
-kernel simply compares the PID of the caller of ptrace against the
-tracer PID of the process passed to ptrace. Because each debugger
-thread has a different PID, calling ptrace from a different thread
-might as well be calling it from a different process and the kernel
-will return ESRCH.
-
-wait, on the other hand, does not have this restriction. Any debugger
-thread can wait on any thread in the attached process.
diff --git a/dwarf/buf.go b/dwarf/buf.go
deleted file mode 100644
index 73fcc9a..0000000
--- a/dwarf/buf.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Buffered reading and decoding of DWARF data streams.
-
-package dwarf
-
-import (
- "encoding/binary"
- "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
-}
diff --git a/dwarf/cache.go b/dwarf/cache.go
deleted file mode 100644
index cf795e7..0000000
--- a/dwarf/cache.go
+++ /dev/null
@@ -1,249 +0,0 @@
-// 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
-}
diff --git a/dwarf/const.go b/dwarf/const.go
deleted file mode 100644
index b2debfb..0000000
--- a/dwarf/const.go
+++ /dev/null
@@ -1,470 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Constants
-
-package dwarf
-
-import "strconv"
-
-// An Attr identifies the attribute type in a DWARF Entry's Field.
-type Attr uint32
-
-const (
- AttrSibling Attr = 0x01
- AttrLocation Attr = 0x02
- AttrName Attr = 0x03
- AttrOrdering Attr = 0x09
- AttrByteSize Attr = 0x0B
- AttrBitOffset Attr = 0x0C
- AttrBitSize Attr = 0x0D
- AttrStmtList Attr = 0x10
- AttrLowpc Attr = 0x11
- AttrHighpc Attr = 0x12
- AttrLanguage Attr = 0x13
- AttrDiscr Attr = 0x15
- AttrDiscrValue Attr = 0x16
- AttrVisibility Attr = 0x17
- AttrImport Attr = 0x18
- AttrStringLength Attr = 0x19
- AttrCommonRef Attr = 0x1A
- AttrCompDir Attr = 0x1B
- AttrConstValue Attr = 0x1C
- AttrContainingType Attr = 0x1D
- AttrDefaultValue Attr = 0x1E
- AttrInline Attr = 0x20
- AttrIsOptional Attr = 0x21
- AttrLowerBound Attr = 0x22
- AttrProducer Attr = 0x25
- AttrPrototyped Attr = 0x27
- AttrReturnAddr Attr = 0x2A
- AttrStartScope Attr = 0x2C
- AttrStrideSize Attr = 0x2E
- AttrUpperBound Attr = 0x2F
- AttrAbstractOrigin Attr = 0x31
- AttrAccessibility Attr = 0x32
- AttrAddrClass Attr = 0x33
- AttrArtificial Attr = 0x34
- AttrBaseTypes Attr = 0x35
- AttrCalling Attr = 0x36
- AttrCount Attr = 0x37
- AttrDataMemberLoc Attr = 0x38
- AttrDeclColumn Attr = 0x39
- AttrDeclFile Attr = 0x3A
- AttrDeclLine Attr = 0x3B
- AttrDeclaration Attr = 0x3C
- AttrDiscrList Attr = 0x3D
- AttrEncoding Attr = 0x3E
- AttrExternal Attr = 0x3F
- AttrFrameBase Attr = 0x40
- AttrFriend Attr = 0x41
- AttrIdentifierCase Attr = 0x42
- AttrMacroInfo Attr = 0x43
- AttrNamelistItem Attr = 0x44
- AttrPriority Attr = 0x45
- AttrSegment Attr = 0x46
- AttrSpecification Attr = 0x47
- AttrStaticLink Attr = 0x48
- AttrType Attr = 0x49
- AttrUseLocation Attr = 0x4A
- AttrVarParam Attr = 0x4B
- AttrVirtuality Attr = 0x4C
- AttrVtableElemLoc Attr = 0x4D
- AttrAllocated Attr = 0x4E
- AttrAssociated Attr = 0x4F
- AttrDataLocation Attr = 0x50
- AttrStride Attr = 0x51
- AttrEntrypc Attr = 0x52
- AttrUseUTF8 Attr = 0x53
- AttrExtension Attr = 0x54
- AttrRanges Attr = 0x55
- AttrTrampoline Attr = 0x56
- AttrCallColumn Attr = 0x57
- AttrCallFile Attr = 0x58
- AttrCallLine Attr = 0x59
- AttrDescription Attr = 0x5A
-
- // Go-specific attributes.
- AttrGoKind Attr = 0x2900
- AttrGoKey Attr = 0x2901
- AttrGoElem Attr = 0x2902
- AttrGoEmbeddedField Attr = 0x2903
-)
-
-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"
- case AttrGoEmbeddedField:
- return "GoEmbeddedField"
- }
- 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
-)
diff --git a/dwarf/entry.go b/dwarf/entry.go
deleted file mode 100644
index 4076ec1..0000000
--- a/dwarf/entry.go
+++ /dev/null
@@ -1,407 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// DWARF debug information entry parser.
-// An entry is a sequence of data items of a given format.
-// The first word in the entry is an index into what DWARF
-// calls the ``abbreviation table.'' An abbreviation is really
-// just a type descriptor: it's an array of attribute tag/value format pairs.
-
-package dwarf
-
-import (
- "errors"
- "strconv"
-)
-
-// a single entry's description: a sequence of attributes
-type abbrev struct {
- tag Tag
- children bool
- field []afield
-}
-
-type afield struct {
- attr Attr
- fmt format
-}
-
-// a map from entry format ids to their descriptions
-type abbrevTable map[uint32]abbrev
-
-// ParseAbbrev returns the abbreviation table that starts at byte off
-// in the .debug_abbrev section.
-func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
- if m, ok := d.abbrevCache[off]; ok {
- return m, nil
- }
-
- data := d.abbrev
- if off > uint32(len(data)) {
- data = nil
- } else {
- data = data[off:]
- }
- b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
-
- // Error handling is simplified by the buf getters
- // returning an endless stream of 0s after an error.
- m := make(abbrevTable)
- for {
- // Table ends with id == 0.
- id := uint32(b.uint())
- if id == 0 {
- break
- }
-
- // Walk over attributes, counting.
- n := 0
- b1 := b // Read from copy of b.
- b1.uint()
- b1.uint8()
- for {
- tag := b1.uint()
- fmt := b1.uint()
- if tag == 0 && fmt == 0 {
- break
- }
- n++
- }
- if b1.err != nil {
- return nil, b1.err
- }
-
- // Walk over attributes again, this time writing them down.
- var a abbrev
- a.tag = Tag(b.uint())
- a.children = b.uint8() != 0
- a.field = make([]afield, n)
- for i := range a.field {
- a.field[i].attr = Attr(b.uint())
- a.field[i].fmt = format(b.uint())
- }
- b.uint()
- b.uint()
-
- m[id] = a
- }
- if b.err != nil {
- return nil, b.err
- }
- d.abbrevCache[off] = m
- return m, nil
-}
-
-// An entry is a sequence of attribute/value pairs.
-type Entry struct {
- Offset Offset // offset of Entry in DWARF info
- Tag Tag // tag (kind of Entry)
- Children bool // whether Entry is followed by children
- Field []Field
-}
-
-// A Field is a single attribute/value pair in an Entry.
-type Field struct {
- Attr Attr
- Val interface{}
-}
-
-// Val returns the value associated with attribute Attr in Entry,
-// or nil if there is no such attribute.
-//
-// A common idiom is to merge the check for nil return with
-// the check that the value has the expected dynamic type, as in:
-// v, ok := e.Val(AttrSibling).(int64);
-//
-func (e *Entry) Val(a Attr) interface{} {
- for _, f := range e.Field {
- if f.Attr == a {
- return f.Val
- }
- }
- return nil
-}
-
-// An Offset represents the location of an Entry within the DWARF info.
-// (See Reader.Seek.)
-type Offset uint32
-
-// Entry reads a single entry from buf, decoding
-// according to the given abbreviation table.
-func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
- off := b.off
- id := uint32(b.uint())
- if id == 0 {
- return &Entry{}
- }
- a, ok := atab[id]
- if !ok {
- b.error("unknown abbreviation table index")
- return nil
- }
- e := &Entry{
- Offset: off,
- Tag: a.tag,
- Children: a.children,
- Field: make([]Field, len(a.field)),
- }
- for i := range e.Field {
- e.Field[i].Attr = a.field[i].attr
- fmt := a.field[i].fmt
- if fmt == formIndirect {
- fmt = format(b.uint())
- }
- var val interface{}
- switch fmt {
- default:
- b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16))
-
- // address
- case formAddr:
- val = b.addr()
-
- // block
- case formDwarfBlock1:
- val = b.bytes(int(b.uint8()))
- case formDwarfBlock2:
- val = b.bytes(int(b.uint16()))
- case formDwarfBlock4:
- val = b.bytes(int(b.uint32()))
- case formDwarfBlock:
- val = b.bytes(int(b.uint()))
-
- // constant
- case formData1:
- val = int64(b.uint8())
- case formData2:
- val = int64(b.uint16())
- case formData4:
- val = int64(b.uint32())
- case formData8:
- val = int64(b.uint64())
- case formSdata:
- val = int64(b.int())
- case formUdata:
- val = int64(b.uint())
-
- // flag
- case formFlag:
- val = b.uint8() == 1
- // New in DWARF 4.
- case formFlagPresent:
- // The attribute is implicitly indicated as present, and no value is
- // encoded in the debugging information entry itself.
- val = true
-
- // reference to other entry
- case formRefAddr:
- vers := b.format.version()
- if vers == 0 {
- b.error("unknown version for DW_FORM_ref_addr")
- } else if vers == 2 {
- val = Offset(b.addr())
- } else {
- is64, known := b.format.dwarf64()
- if !known {
- b.error("unknown size for DW_FORM_ref_addr")
- } else if is64 {
- val = Offset(b.uint64())
- } else {
- val = Offset(b.uint32())
- }
- }
- case formRef1:
- val = Offset(b.uint8()) + ubase
- case formRef2:
- val = Offset(b.uint16()) + ubase
- case formRef4:
- val = Offset(b.uint32()) + ubase
- case formRef8:
- val = Offset(b.uint64()) + ubase
- case formRefUdata:
- val = Offset(b.uint()) + ubase
-
- // string
- case formString:
- val = b.string()
- case formStrp:
- off := b.uint32() // offset into .debug_str
- if b.err != nil {
- return nil
- }
- b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
- b1.skip(int(off))
- val = b1.string()
- if b1.err != nil {
- b.err = b1.err
- return nil
- }
-
- // lineptr, loclistptr, macptr, rangelistptr
- // New in DWARF 4, but clang can generate them with -gdwarf-2.
- // Section reference, replacing use of formData4 and formData8.
- case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
- is64, known := b.format.dwarf64()
- if !known {
- b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
- } else if is64 {
- val = int64(b.uint64())
- } else {
- val = int64(b.uint32())
- }
-
- // exprloc
- // New in DWARF 4.
- case formExprloc:
- val = b.bytes(int(b.uint()))
-
- // reference
- // New in DWARF 4.
- case formRefSig8:
- // 64-bit type signature.
- val = b.uint64()
- }
- e.Field[i].Val = val
- }
- if b.err != nil {
- return nil
- }
- return e
-}
-
-// A Reader allows reading Entry structures from a DWARF ``info'' section.
-// The Entry structures are arranged in a tree. The Reader's Next function
-// return successive entries from a pre-order traversal of the tree.
-// If an entry has children, its Children field will be true, and the children
-// follow, terminated by an Entry with Tag 0.
-type Reader struct {
- b buf
- d *Data
- err error
- unit int
- lastChildren bool // .Children of last entry returned by Next
- lastSibling Offset // .Val(AttrSibling) of last entry returned by Next
-}
-
-// Reader returns a new Reader for Data.
-// The reader is positioned at byte offset 0 in the DWARF ``info'' section.
-func (d *Data) Reader() *Reader {
- r := &Reader{d: d}
- r.Seek(0)
- return r
-}
-
-// 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
-}
diff --git a/dwarf/frame.go b/dwarf/frame.go
deleted file mode 100644
index c112c02..0000000
--- a/dwarf/frame.go
+++ /dev/null
@@ -1,299 +0,0 @@
-// 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
-}
diff --git a/dwarf/frame_test.go b/dwarf/frame_test.go
deleted file mode 100644
index 2bf41f5..0000000
--- a/dwarf/frame_test.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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_test
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
- "testing"
-
- "golang.org/x/debug/dwarf"
-)
-
-var (
- pcspTempDir string
- pcsptestBinary string
-)
-
-func doPCToSPTest(self bool) bool {
- // For now, only works on amd64 platforms.
- if runtime.GOARCH != "amd64" {
- return false
- }
- // Self test reads test binary; only works on Linux or Mac.
- if self {
- if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
- return false
- }
- }
- // Command below expects "sh", so Unix.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return false
- }
- if pcsptestBinary != "" {
- return true
- }
- var err error
- pcspTempDir, err = ioutil.TempDir("", "pcsptest")
- if err != nil {
- panic(err)
- }
- if strings.Contains(pcspTempDir, " ") {
- panic("unexpected space in tempdir")
- }
- // This command builds pcsptest from testdata/pcsptest.go.
- pcsptestBinary = filepath.Join(pcspTempDir, "pcsptest")
- command := fmt.Sprintf("go tool compile -o %s.6 testdata/pcsptest.go && go tool link -H %s -o %s %s.6",
- pcsptestBinary, runtime.GOOS, pcsptestBinary, pcsptestBinary)
- cmd := exec.Command("sh", "-c", command)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Run(); err != nil {
- panic(err)
- }
- return true
-}
-
-func endPCToSPTest() {
- if pcspTempDir != "" {
- os.RemoveAll(pcspTempDir)
- pcspTempDir = ""
- pcsptestBinary = ""
- }
-}
-
-func TestPCToSPOffset(t *testing.T) {
- if !doPCToSPTest(false) {
- return
- }
- defer endPCToSPTest()
-
- data, err := getData(pcsptestBinary)
- if err != nil {
- t.Fatal(err)
- }
- entry, err := data.LookupFunction("main.test")
- if err != nil {
- t.Fatal("lookup startPC:", err)
- }
- startPC, ok := entry.Val(dwarf.AttrLowpc).(uint64)
- if !ok {
- t.Fatal(`DWARF data for function "main.test" has no low PC`)
- }
- endPC, ok := entry.Val(dwarf.AttrHighpc).(uint64)
- if !ok {
- t.Fatal(`DWARF data for function "main.test" has no high PC`)
- }
-
- const addrSize = 8 // TODO: Assumes amd64.
- const argSize = 8 // Defined by int64 arguments in test binary.
-
- // On 64-bit machines, the first offset must be one address size,
- // for the return PC.
- offset, err := data.PCToSPOffset(startPC)
- if err != nil {
- t.Fatal("startPC:", err)
- }
- if offset != addrSize {
- t.Fatalf("expected %d at start of function; got %d", addrSize, offset)
- }
- // On 64-bit machines, expect some 8s and some 32s. (See the
- // comments in testdata/pcsptest.go.
- // TODO: The test could be stronger, but not much unless we
- // disassemble the binary.
- count := make(map[int64]int)
- for pc := startPC; pc < endPC; pc++ {
- offset, err := data.PCToSPOffset(pc)
- if err != nil {
- t.Fatal("scanning function:", err)
- }
- count[offset]++
- }
- if len(count) != 2 {
- t.Errorf("expected 2 offset values, got %d; counts are: %v", len(count), count)
- }
- if count[addrSize] == 0 {
- t.Errorf("expected some values at offset %d; got %v", addrSize, count)
- }
- if count[addrSize+3*argSize] == 0 {
- t.Errorf("expected some values at offset %d; got %v", addrSize+3*argSize, count)
- }
-}
diff --git a/dwarf/line.go b/dwarf/line.go
deleted file mode 100644
index 2f47739..0000000
--- a/dwarf/line.go
+++ /dev/null
@@ -1,448 +0,0 @@
-// 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
-}
diff --git a/dwarf/open.go b/dwarf/open.go
deleted file mode 100644
index a13c6ed..0000000
--- a/dwarf/open.go
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package dwarf provides access to DWARF debugging information loaded from
-// executable files, as defined in the DWARF 2.0 Standard at
-// http://dwarfstd.org/doc/dwarf-2.0.0.pdf
-package dwarf // import "golang.org/x/debug/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)
-}
diff --git a/dwarf/pclntab_test.go b/dwarf/pclntab_test.go
deleted file mode 100644
index 31ceb78..0000000
--- a/dwarf/pclntab_test.go
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package dwarf_test
-
-// Stripped-down, simplified version of ../../gosym/pclntab_test.go
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
- "testing"
-
- . "golang.org/x/debug/dwarf"
- "golang.org/x/debug/elf"
- "golang.org/x/debug/macho"
-)
-
-var (
- pclineTempDir string
- pclinetestBinary string
-)
-
-func dotest(self bool) bool {
- // For now, only works on amd64 platforms.
- if runtime.GOARCH != "amd64" {
- return false
- }
- // Self test reads test binary; only works on Linux or Mac.
- if self {
- if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
- return false
- }
- }
- // Command below expects "sh", so Unix.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return false
- }
- if pclinetestBinary != "" {
- return true
- }
- var err error
- pclineTempDir, err = ioutil.TempDir("", "pclinetest")
- if err != nil {
- panic(err)
- }
- if strings.Contains(pclineTempDir, " ") {
- panic("unexpected space in tempdir")
- }
- // This command builds pclinetest from ../../gosym/pclinetest.asm;
- // the resulting binary looks like it was built from pclinetest.s,
- // but we have renamed it to keep it away from the go tool.
- pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
- command := fmt.Sprintf("go tool asm -o %s.6 ../gosym/pclinetest.asm && go tool link -H %s -E main -o %s %s.6",
- pclinetestBinary, runtime.GOOS, pclinetestBinary, pclinetestBinary)
- cmd := exec.Command("sh", "-c", command)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Run(); err != nil {
- panic(err)
- }
- return true
-}
-
-func endtest() {
- if pclineTempDir != "" {
- os.RemoveAll(pclineTempDir)
- pclineTempDir = ""
- pclinetestBinary = ""
- }
-}
-
-func getData(file string) (*Data, error) {
- switch runtime.GOOS {
- case "linux":
- f, err := elf.Open(file)
- if err != nil {
- return nil, err
- }
- dwarf, err := f.DWARF()
- if err != nil {
- return nil, err
- }
- f.Close()
- return dwarf, nil
- case "darwin":
- f, err := macho.Open(file)
- if err != nil {
- return nil, err
- }
- dwarf, err := f.DWARF()
- if err != nil {
- return nil, err
- }
- f.Close()
- return dwarf, nil
- }
- panic("unimplemented DWARF for GOOS=" + runtime.GOOS)
-}
-
-func TestPCToLine(t *testing.T) {
- if !dotest(false) {
- return
- }
- defer endtest()
-
- data, err := getData(pclinetestBinary)
- if err != nil {
- t.Fatal(err)
- }
-
- // Test PCToLine.
- entry, err := data.LookupFunction("linefrompc")
- if err != nil {
- t.Fatal(err)
- }
- pc, ok := entry.Val(AttrLowpc).(uint64)
- if !ok {
- t.Fatal(`DWARF data for function "linefrompc" has no PC`)
- }
- for _, tt := range []struct {
- offset, want uint64
- }{
- {0, 2},
- {1, 3},
- {2, 4},
- {3, 4},
- {4, 5},
- {6, 5},
- {7, 6},
- {11, 6},
- {12, 7},
- {19, 7},
- {20, 8},
- {32, 8},
- {33, 9},
- {53, 9},
- {54, 10},
- } {
- file, line, err := data.PCToLine(pc + tt.offset)
- if err != nil {
- t.Fatal(err)
- }
- if !strings.HasSuffix(file, "/pclinetest.asm") {
- t.Errorf("got %s; want %s", file, ".../pclinetest.asm")
- }
- if line != tt.want {
- t.Errorf("line for offset %d: got %d; want %d", tt.offset, line, tt.want)
- }
- }
-}
diff --git a/dwarf/symbol.go b/dwarf/symbol.go
deleted file mode 100644
index 52d6829..0000000
--- a/dwarf/symbol.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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
-}
diff --git a/dwarf/testdata/pcsptest.go b/dwarf/testdata/pcsptest.go
deleted file mode 100644
index f0f2822..0000000
--- a/dwarf/testdata/pcsptest.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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 main
-
-import "fmt"
-
-func main() {
- test(1, 2, 3)
-}
-
-// This is the function we examine. After the preamble its stack should be
-// pulled down 1*addrSize for the return PC plus 3*8 for the three
-// arguments. That will be (1+3)*8=32 on 64-bit machines.
-func test(a, b, c int64) int64 {
- // Put in enough code that it's not inlined.
- for a = 0; a < 100; a++ {
- b += c
- }
- afterTest(a, b, c)
- return b
-}
-
-// This function follows test in the binary. We use it to force arguments
-// onto the stack and as a delimiter in the text we scan in the test.
-func afterTest(a, b, c int64) {
- fmt.Println(a, b, c)
-}
diff --git a/dwarf/testdata/typedef.c b/dwarf/testdata/typedef.c
deleted file mode 100644
index f05f015..0000000
--- a/dwarf/testdata/typedef.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Linux ELF:
-gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o
-
-OS X Mach-O:
-gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho
-*/
-#include <complex.h>
-
-typedef volatile int* t_ptr_volatile_int;
-typedef const char *t_ptr_const_char;
-typedef long t_long;
-typedef unsigned short t_ushort;
-typedef int t_func_int_of_float_double(float, double);
-typedef int (*t_ptr_func_int_of_float_double)(float, double);
-typedef int (*t_ptr_func_int_of_float_complex)(float complex);
-typedef int (*t_ptr_func_int_of_double_complex)(double complex);
-typedef int (*t_ptr_func_int_of_long_double_complex)(long double complex);
-typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char);
-typedef void t_func_void_of_char(char);
-typedef void t_func_void_of_void(void);
-typedef void t_func_void_of_ptr_char_dots(char*, ...);
-typedef struct my_struct {
- volatile int vi;
- char x : 1;
- int y : 4;
- int z[0];
- long long array[40];
- int zz[0];
-} t_my_struct;
-typedef struct my_struct1 {
- int zz [1];
-} t_my_struct1;
-typedef union my_union {
- volatile int vi;
- char x : 1;
- int y : 4;
- long long array[40];
-} t_my_union;
-typedef enum my_enum {
- e1 = 1,
- e2 = 2,
- e3 = -5,
- e4 = 1000000000000000LL,
-} t_my_enum;
-
-typedef struct list t_my_list;
-struct list {
- short val;
- t_my_list *next;
-};
-
-typedef struct tree {
- struct tree *left, *right;
- unsigned long long val;
-} t_my_tree;
-
-t_ptr_volatile_int *a2;
-t_ptr_const_char **a3a;
-t_long *a4;
-t_ushort *a5;
-t_func_int_of_float_double *a6;
-t_ptr_func_int_of_float_double *a7;
-t_func_ptr_int_of_char_schar_uchar *a8;
-t_func_void_of_char *a9;
-t_func_void_of_void *a10;
-t_func_void_of_ptr_char_dots *a11;
-t_my_struct *a12;
-t_my_struct1 *a12a;
-t_my_union *a12b;
-t_my_enum *a13;
-t_my_list *a14;
-t_my_tree *a15;
-t_ptr_func_int_of_float_complex *a16;
-t_ptr_func_int_of_double_complex *a17;
-t_ptr_func_int_of_long_double_complex *a18;
-
-int main()
-{
- return 0;
-}
diff --git a/dwarf/testdata/typedef.elf b/dwarf/testdata/typedef.elf
deleted file mode 100755
index b2062d2..0000000
--- a/dwarf/testdata/typedef.elf
+++ /dev/null
Binary files differ
diff --git a/dwarf/testdata/typedef.elf4 b/dwarf/testdata/typedef.elf4
deleted file mode 100644
index 3d5a5a1..0000000
--- a/dwarf/testdata/typedef.elf4
+++ /dev/null
Binary files differ
diff --git a/dwarf/testdata/typedef.macho b/dwarf/testdata/typedef.macho
deleted file mode 100644
index f75afcc..0000000
--- a/dwarf/testdata/typedef.macho
+++ /dev/null
Binary files differ
diff --git a/dwarf/type.go b/dwarf/type.go
deleted file mode 100644
index 04bbdad..0000000
--- a/dwarf/type.go
+++ /dev/null
@@ -1,867 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// DWARF type information structures.
-// The format is heavily biased toward C, but for simplicity
-// the String methods use a pseudo-Go syntax.
-
-package dwarf
-
-import (
- "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
- Embedded bool
-}
-
-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)
- f.Embedded, _ = kid.Val(AttrGoEmbeddedField).(bool)
- 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)
-
- default:
- err = DecodeError{name, off, "unsupported type tag"}
- }
-
- 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
- }
-}
diff --git a/dwarf/type_test.go b/dwarf/type_test.go
deleted file mode 100644
index aeb954c..0000000
--- a/dwarf/type_test.go
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package dwarf_test
-
-import (
- "testing"
-
- . "golang.org/x/debug/dwarf"
- "golang.org/x/debug/elf"
- "golang.org/x/debug/macho"
-)
-
-var typedefTests = map[string]string{
- "t_ptr_volatile_int": "*volatile int",
- "t_ptr_const_char": "*const char",
- "t_long": "long int",
- "t_ushort": "short unsigned int",
- "t_func_int_of_float_double": "func(float, double) int",
- "t_ptr_func_int_of_float_double": "*func(float, double) int",
- "t_ptr_func_int_of_float_complex": "*func(complex float) int",
- "t_ptr_func_int_of_double_complex": "*func(complex double) int",
- "t_ptr_func_int_of_long_double_complex": "*func(complex long double) int",
- "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int",
- "t_func_void_of_char": "func(char) void",
- "t_func_void_of_void": "func() void",
- "t_func_void_of_ptr_char_dots": "func(*char, ...) void",
- "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; z [0]int@8; array [40]long long int@8; zz [0]int@328}",
- "t_my_struct1": "struct my_struct1 {zz [1]int@0}",
- "t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
- "t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
- "t_my_list": "struct list {val short int@0; next *t_my_list@8}",
- "t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
-}
-
-// As Apple converts gcc to a clang-based front end
-// they keep breaking the DWARF output. This map lists the
-// conversion from real answer to Apple answer.
-var machoBug = map[string]string{
- "func(*char, ...) void": "func(*char) void",
- "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}": "enum my_enum {e1=1; e2=2; e3=-5; e4=-1530494976}",
-}
-
-func elfData(t *testing.T, name string) *Data {
- f, err := elf.Open(name)
- if err != nil {
- t.Fatal(err)
- }
-
- d, err := f.DWARF()
- if err != nil {
- t.Fatal(err)
- }
- return d
-}
-
-func machoData(t *testing.T, name string) *Data {
- f, err := macho.Open(name)
- if err != nil {
- t.Fatal(err)
- }
-
- d, err := f.DWARF()
- if err != nil {
- t.Fatal(err)
- }
- return d
-}
-
-func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf") }
-
-func TestTypedefsMachO(t *testing.T) {
- testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
-}
-
-func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") }
-
-func testTypedefs(t *testing.T, d *Data, kind string) {
- r := d.Reader()
- seen := make(map[string]bool)
- for {
- e, err := r.Next()
- if err != nil {
- t.Fatal("r.Next:", err)
- }
- if e == nil {
- break
- }
- if e.Tag == TagTypedef {
- typ, err := d.Type(e.Offset)
- if err != nil {
- t.Fatal("d.Type:", err)
- }
- t1 := typ.(*TypedefType)
- var typstr string
- if ts, ok := t1.Type.(*StructType); ok {
- typstr = ts.Defn()
- } else {
- typstr = t1.Type.String()
- }
-
- if want, ok := typedefTests[t1.Name]; ok {
- if seen[t1.Name] {
- t.Errorf("multiple definitions for %s", t1.Name)
- }
- seen[t1.Name] = true
- if typstr != want && (kind != "macho" || typstr != machoBug[want]) {
- t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
- }
- }
- }
- if e.Tag != TagCompileUnit {
- r.SkipChildren()
- }
- }
-
- for k := range typedefTests {
- if !seen[k] {
- t.Errorf("missing %s", k)
- }
- }
-}
-
-func TestTypeForNonTypeEntry(t *testing.T) {
- d := elfData(t, "testdata/typedef.elf")
-
- // The returned entry will be a Subprogram.
- ent, err := d.LookupFunction("main")
- if err != nil {
- t.Fatal("d.LookupFunction:", err)
- }
-
- _, err = d.Type(ent.Offset)
- if err == nil {
- t.Fatal("nil error for unreadable entry")
- }
-}
diff --git a/dwarf/typeunit.go b/dwarf/typeunit.go
deleted file mode 100644
index d93b9f5..0000000
--- a/dwarf/typeunit.go
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package dwarf
-
-import (
- "fmt"
- "strconv"
-)
-
-// Parse the type units stored in a DWARF4 .debug_types section. Each
-// type unit defines a single primary type and an 8-byte signature.
-// Other sections may then use formRefSig8 to refer to the type.
-
-// The typeUnit format is a single type with a signature. It holds
-// the same data as a compilation unit.
-type typeUnit struct {
- unit
- toff Offset // Offset to signature type within data.
- name string // Name of .debug_type section.
- cache Type // Cache the type, nil to start.
-}
-
-// Parse a .debug_types section.
-func (d *Data) parseTypes(name string, types []byte) error {
- b := makeBuf(d, unknownFormat{}, name, 0, types)
- for len(b.data) > 0 {
- base := b.off
- dwarf64 := false
- n := b.uint32()
- if n == 0xffffffff {
- n64 := b.uint64()
- if n64 != uint64(uint32(n64)) {
- b.error("type unit length overflow")
- return b.err
- }
- n = uint32(n64)
- dwarf64 = true
- }
- hdroff := b.off
- vers := b.uint16()
- if vers != 4 {
- b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
- return b.err
- }
- var ao uint32
- if !dwarf64 {
- ao = b.uint32()
- } else {
- ao64 := b.uint64()
- if ao64 != uint64(uint32(ao64)) {
- b.error("type unit abbrev offset overflow")
- return b.err
- }
- ao = uint32(ao64)
- }
- atable, err := d.parseAbbrev(ao)
- if err != nil {
- return err
- }
- asize := b.uint8()
- sig := b.uint64()
-
- var toff uint32
- if !dwarf64 {
- toff = b.uint32()
- } else {
- to64 := b.uint64()
- if to64 != uint64(uint32(to64)) {
- b.error("type unit type offset overflow")
- return b.err
- }
- toff = uint32(to64)
- }
-
- boff := b.off
- d.typeSigs[sig] = &typeUnit{
- unit: unit{
- base: base,
- off: boff,
- data: b.bytes(int(Offset(n) - (b.off - hdroff))),
- atable: atable,
- asize: int(asize),
- vers: int(vers),
- is64: dwarf64,
- },
- toff: Offset(toff),
- name: name,
- }
- if b.err != nil {
- return b.err
- }
- }
- return nil
-}
-
-// Return the type for a type signature.
-func (d *Data) sigToType(sig uint64) (Type, error) {
- tu := d.typeSigs[sig]
- if tu == nil {
- return nil, fmt.Errorf("no type unit with signature %v", sig)
- }
- if tu.cache != nil {
- return tu.cache, nil
- }
-
- b := makeBuf(d, tu, tu.name, tu.off, tu.data)
- r := &typeUnitReader{d: d, tu: tu, b: b}
- t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
- if err != nil {
- return nil, err
- }
-
- tu.cache = t
- return t, nil
-}
-
-// typeUnitReader is a typeReader for a tagTypeUnit.
-type typeUnitReader struct {
- d *Data
- tu *typeUnit
- b buf
- err error
-}
-
-// Seek to a new position in the type unit.
-func (tur *typeUnitReader) Seek(off Offset) {
- tur.err = nil
- doff := off - tur.tu.off
- if doff < 0 || doff >= Offset(len(tur.tu.data)) {
- tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
- return
- }
- tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
-}
-
-// 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
-}
diff --git a/dwarf/unit.go b/dwarf/unit.go
deleted file mode 100644
index 0fbc8e0..0000000
--- a/dwarf/unit.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package dwarf
-
-import "strconv"
-
-// DWARF debug info is split into a sequence of compilation units.
-// Each unit has its own abbreviation table and address size.
-
-type unit struct {
- base Offset // byte offset of header within the aggregate info
- off Offset // byte offset of data within the aggregate info
- data []byte
- atable abbrevTable
- asize int
- vers int
- is64 bool // True for 64-bit DWARF format
-}
-
-// Implement the dataFormat interface.
-
-func (u *unit) version() int {
- return u.vers
-}
-
-func (u *unit) dwarf64() (bool, bool) {
- return u.is64, true
-}
-
-func (u *unit) addrsize() int {
- return u.asize
-}
-
-func (d *Data) parseUnits() ([]unit, error) {
- // Count units.
- nunit := 0
- b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
- for len(b.data) > 0 {
- len := b.uint32()
- if len == 0xffffffff {
- len64 := b.uint64()
- if len64 != uint64(uint32(len64)) {
- b.error("unit length overflow")
- break
- }
- len = uint32(len64)
- }
- b.skip(int(len))
- nunit++
- }
- if b.err != nil {
- return nil, b.err
- }
-
- // Again, this time writing them down.
- b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
- units := make([]unit, nunit)
- for i := range units {
- u := &units[i]
- u.base = b.off
- n := b.uint32()
- if n == 0xffffffff {
- u.is64 = true
- n = uint32(b.uint64())
- }
- vers := b.uint16()
- if vers != 2 && vers != 3 && vers != 4 {
- b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
- break
- }
- u.vers = int(vers)
- atable, err := d.parseAbbrev(b.uint32())
- if err != nil {
- if b.err == nil {
- b.err = err
- }
- break
- }
- u.atable = atable
- u.asize = int(b.uint8())
- u.off = b.off
- u.data = b.bytes(int(n - (2 + 4 + 1)))
- }
- if b.err != nil {
- return nil, b.err
- }
- return units, nil
-}
diff --git a/elf/elf.go b/elf/elf.go
deleted file mode 100644
index 4e924dc..0000000
--- a/elf/elf.go
+++ /dev/null
@@ -1,1521 +0,0 @@
-/*
- * ELF constants and data structures
- *
- * Derived from:
- * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
- * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
- * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
- * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
- * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
- * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
- *
- * Copyright (c) 1996-1998 John D. Polstra. All rights reserved.
- * Copyright (c) 2001 David E. O'Brien
- * Portions Copyright 2009 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:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- */
-
-package elf // import "golang.org/x/debug/elf"
-
-import "strconv"
-
-/*
- * Constants
- */
-
-// Indexes into the Header.Ident array.
-const (
- EI_CLASS = 4 /* Class of machine. */
- EI_DATA = 5 /* Data format. */
- EI_VERSION = 6 /* ELF format version. */
- EI_OSABI = 7 /* Operating system / ABI identification */
- EI_ABIVERSION = 8 /* ABI version */
- EI_PAD = 9 /* Start of padding (per SVR4 ABI). */
- EI_NIDENT = 16 /* Size of e_ident array. */
-)
-
-// Initial magic number for ELF files.
-const ELFMAG = "\177ELF"
-
-// Version is found in Header.Ident[EI_VERSION] and Header.Version.
-type Version byte
-
-const (
- EV_NONE Version = 0
- EV_CURRENT Version = 1
-)
-
-var versionStrings = []intName{
- {0, "EV_NONE"},
- {1, "EV_CURRENT"},
-}
-
-func (i Version) String() string { return stringName(uint32(i), versionStrings, false) }
-func (i Version) GoString() string { return stringName(uint32(i), versionStrings, true) }
-
-// Class is found in Header.Ident[EI_CLASS] and Header.Class.
-type Class byte
-
-const (
- ELFCLASSNONE Class = 0 /* Unknown class. */
- ELFCLASS32 Class = 1 /* 32-bit architecture. */
- ELFCLASS64 Class = 2 /* 64-bit architecture. */
-)
-
-var classStrings = []intName{
- {0, "ELFCLASSNONE"},
- {1, "ELFCLASS32"},
- {2, "ELFCLASS64"},
-}
-
-func (i Class) String() string { return stringName(uint32(i), classStrings, false) }
-func (i Class) GoString() string { return stringName(uint32(i), classStrings, true) }
-
-// Data is found in Header.Ident[EI_DATA] and Header.Data.
-type Data byte
-
-const (
- ELFDATANONE Data = 0 /* Unknown data format. */
- ELFDATA2LSB Data = 1 /* 2's complement little-endian. */
- ELFDATA2MSB Data = 2 /* 2's complement big-endian. */
-)
-
-var dataStrings = []intName{
- {0, "ELFDATANONE"},
- {1, "ELFDATA2LSB"},
- {2, "ELFDATA2MSB"},
-}
-
-func (i Data) String() string { return stringName(uint32(i), dataStrings, false) }
-func (i Data) GoString() string { return stringName(uint32(i), dataStrings, true) }
-
-// OSABI is found in Header.Ident[EI_OSABI] and Header.OSABI.
-type OSABI byte
-
-const (
- ELFOSABI_NONE OSABI = 0 /* UNIX System V ABI */
- ELFOSABI_HPUX OSABI = 1 /* HP-UX operating system */
- ELFOSABI_NETBSD OSABI = 2 /* NetBSD */
- ELFOSABI_LINUX OSABI = 3 /* GNU/Linux */
- ELFOSABI_HURD OSABI = 4 /* GNU/Hurd */
- ELFOSABI_86OPEN OSABI = 5 /* 86Open common IA32 ABI */
- ELFOSABI_SOLARIS OSABI = 6 /* Solaris */
- ELFOSABI_AIX OSABI = 7 /* AIX */
- ELFOSABI_IRIX OSABI = 8 /* IRIX */
- ELFOSABI_FREEBSD OSABI = 9 /* FreeBSD */
- ELFOSABI_TRU64 OSABI = 10 /* TRU64 UNIX */
- ELFOSABI_MODESTO OSABI = 11 /* Novell Modesto */
- ELFOSABI_OPENBSD OSABI = 12 /* OpenBSD */
- ELFOSABI_OPENVMS OSABI = 13 /* Open VMS */
- ELFOSABI_NSK OSABI = 14 /* HP Non-Stop Kernel */
- ELFOSABI_ARM OSABI = 97 /* ARM */
- ELFOSABI_STANDALONE OSABI = 255 /* Standalone (embedded) application */
-)
-
-var osabiStrings = []intName{
- {0, "ELFOSABI_NONE"},
- {1, "ELFOSABI_HPUX"},
- {2, "ELFOSABI_NETBSD"},
- {3, "ELFOSABI_LINUX"},
- {4, "ELFOSABI_HURD"},
- {5, "ELFOSABI_86OPEN"},
- {6, "ELFOSABI_SOLARIS"},
- {7, "ELFOSABI_AIX"},
- {8, "ELFOSABI_IRIX"},
- {9, "ELFOSABI_FREEBSD"},
- {10, "ELFOSABI_TRU64"},
- {11, "ELFOSABI_MODESTO"},
- {12, "ELFOSABI_OPENBSD"},
- {13, "ELFOSABI_OPENVMS"},
- {14, "ELFOSABI_NSK"},
- {97, "ELFOSABI_ARM"},
- {255, "ELFOSABI_STANDALONE"},
-}
-
-func (i OSABI) String() string { return stringName(uint32(i), osabiStrings, false) }
-func (i OSABI) GoString() string { return stringName(uint32(i), osabiStrings, true) }
-
-// Type is found in Header.Type.
-type Type uint16
-
-const (
- ET_NONE Type = 0 /* Unknown type. */
- ET_REL Type = 1 /* Relocatable. */
- ET_EXEC Type = 2 /* Executable. */
- ET_DYN Type = 3 /* Shared object. */
- ET_CORE Type = 4 /* Core file. */
- ET_LOOS Type = 0xfe00 /* First operating system specific. */
- ET_HIOS Type = 0xfeff /* Last operating system-specific. */
- ET_LOPROC Type = 0xff00 /* First processor-specific. */
- ET_HIPROC Type = 0xffff /* Last processor-specific. */
-)
-
-var typeStrings = []intName{
- {0, "ET_NONE"},
- {1, "ET_REL"},
- {2, "ET_EXEC"},
- {3, "ET_DYN"},
- {4, "ET_CORE"},
- {0xfe00, "ET_LOOS"},
- {0xfeff, "ET_HIOS"},
- {0xff00, "ET_LOPROC"},
- {0xffff, "ET_HIPROC"},
-}
-
-func (i Type) String() string { return stringName(uint32(i), typeStrings, false) }
-func (i Type) GoString() string { return stringName(uint32(i), typeStrings, true) }
-
-// Machine is found in Header.Machine.
-type Machine uint16
-
-const (
- EM_NONE Machine = 0 /* Unknown machine. */
- EM_M32 Machine = 1 /* AT&T WE32100. */
- EM_SPARC Machine = 2 /* Sun SPARC. */
- EM_386 Machine = 3 /* Intel i386. */
- EM_68K Machine = 4 /* Motorola 68000. */
- EM_88K Machine = 5 /* Motorola 88000. */
- EM_860 Machine = 7 /* Intel i860. */
- EM_MIPS Machine = 8 /* MIPS R3000 Big-Endian only. */
- EM_S370 Machine = 9 /* IBM System/370. */
- EM_MIPS_RS3_LE Machine = 10 /* MIPS R3000 Little-Endian. */
- EM_PARISC Machine = 15 /* HP PA-RISC. */
- EM_VPP500 Machine = 17 /* Fujitsu VPP500. */
- EM_SPARC32PLUS Machine = 18 /* SPARC v8plus. */
- EM_960 Machine = 19 /* Intel 80960. */
- EM_PPC Machine = 20 /* PowerPC 32-bit. */
- EM_PPC64 Machine = 21 /* PowerPC 64-bit. */
- EM_S390 Machine = 22 /* IBM System/390. */
- EM_V800 Machine = 36 /* NEC V800. */
- EM_FR20 Machine = 37 /* Fujitsu FR20. */
- EM_RH32 Machine = 38 /* TRW RH-32. */
- EM_RCE Machine = 39 /* Motorola RCE. */
- EM_ARM Machine = 40 /* ARM. */
- EM_SH Machine = 42 /* Hitachi SH. */
- EM_SPARCV9 Machine = 43 /* SPARC v9 64-bit. */
- EM_TRICORE Machine = 44 /* Siemens TriCore embedded processor. */
- EM_ARC Machine = 45 /* Argonaut RISC Core. */
- EM_H8_300 Machine = 46 /* Hitachi H8/300. */
- EM_H8_300H Machine = 47 /* Hitachi H8/300H. */
- EM_H8S Machine = 48 /* Hitachi H8S. */
- EM_H8_500 Machine = 49 /* Hitachi H8/500. */
- EM_IA_64 Machine = 50 /* Intel IA-64 Processor. */
- EM_MIPS_X Machine = 51 /* Stanford MIPS-X. */
- EM_COLDFIRE Machine = 52 /* Motorola ColdFire. */
- EM_68HC12 Machine = 53 /* Motorola M68HC12. */
- EM_MMA Machine = 54 /* Fujitsu MMA. */
- EM_PCP Machine = 55 /* Siemens PCP. */
- EM_NCPU Machine = 56 /* Sony nCPU. */
- EM_NDR1 Machine = 57 /* Denso NDR1 microprocessor. */
- EM_STARCORE Machine = 58 /* Motorola Star*Core processor. */
- EM_ME16 Machine = 59 /* Toyota ME16 processor. */
- EM_ST100 Machine = 60 /* STMicroelectronics ST100 processor. */
- EM_TINYJ Machine = 61 /* Advanced Logic Corp. TinyJ processor. */
- EM_X86_64 Machine = 62 /* Advanced Micro Devices x86-64 */
-
- /* Non-standard or deprecated. */
- EM_486 Machine = 6 /* Intel i486. */
- EM_MIPS_RS4_BE Machine = 10 /* MIPS R4000 Big-Endian */
- EM_ALPHA_STD Machine = 41 /* Digital Alpha (standard value). */
- EM_ALPHA Machine = 0x9026 /* Alpha (written in the absence of an ABI) */
-)
-
-var machineStrings = []intName{
- {0, "EM_NONE"},
- {1, "EM_M32"},
- {2, "EM_SPARC"},
- {3, "EM_386"},
- {4, "EM_68K"},
- {5, "EM_88K"},
- {7, "EM_860"},
- {8, "EM_MIPS"},
- {9, "EM_S370"},
- {10, "EM_MIPS_RS3_LE"},
- {15, "EM_PARISC"},
- {17, "EM_VPP500"},
- {18, "EM_SPARC32PLUS"},
- {19, "EM_960"},
- {20, "EM_PPC"},
- {21, "EM_PPC64"},
- {22, "EM_S390"},
- {36, "EM_V800"},
- {37, "EM_FR20"},
- {38, "EM_RH32"},
- {39, "EM_RCE"},
- {40, "EM_ARM"},
- {42, "EM_SH"},
- {43, "EM_SPARCV9"},
- {44, "EM_TRICORE"},
- {45, "EM_ARC"},
- {46, "EM_H8_300"},
- {47, "EM_H8_300H"},
- {48, "EM_H8S"},
- {49, "EM_H8_500"},
- {50, "EM_IA_64"},
- {51, "EM_MIPS_X"},
- {52, "EM_COLDFIRE"},
- {53, "EM_68HC12"},
- {54, "EM_MMA"},
- {55, "EM_PCP"},
- {56, "EM_NCPU"},
- {57, "EM_NDR1"},
- {58, "EM_STARCORE"},
- {59, "EM_ME16"},
- {60, "EM_ST100"},
- {61, "EM_TINYJ"},
- {62, "EM_X86_64"},
-
- /* Non-standard or deprecated. */
- {6, "EM_486"},
- {10, "EM_MIPS_RS4_BE"},
- {41, "EM_ALPHA_STD"},
- {0x9026, "EM_ALPHA"},
-}
-
-func (i Machine) String() string { return stringName(uint32(i), machineStrings, false) }
-func (i Machine) GoString() string { return stringName(uint32(i), machineStrings, true) }
-
-// Special section indices.
-type SectionIndex int
-
-const (
- SHN_UNDEF SectionIndex = 0 /* Undefined, missing, irrelevant. */
- SHN_LORESERVE SectionIndex = 0xff00 /* First of reserved range. */
- SHN_LOPROC SectionIndex = 0xff00 /* First processor-specific. */
- SHN_HIPROC SectionIndex = 0xff1f /* Last processor-specific. */
- SHN_LOOS SectionIndex = 0xff20 /* First operating system-specific. */
- SHN_HIOS SectionIndex = 0xff3f /* Last operating system-specific. */
- SHN_ABS SectionIndex = 0xfff1 /* Absolute values. */
- SHN_COMMON SectionIndex = 0xfff2 /* Common data. */
- SHN_XINDEX SectionIndex = 0xffff /* Escape -- index stored elsewhere. */
- SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */
-)
-
-var shnStrings = []intName{
- {0, "SHN_UNDEF"},
- {0xff00, "SHN_LOPROC"},
- {0xff20, "SHN_LOOS"},
- {0xfff1, "SHN_ABS"},
- {0xfff2, "SHN_COMMON"},
- {0xffff, "SHN_XINDEX"},
-}
-
-func (i SectionIndex) String() string { return stringName(uint32(i), shnStrings, false) }
-func (i SectionIndex) GoString() string { return stringName(uint32(i), shnStrings, true) }
-
-// Section type.
-type SectionType uint32
-
-const (
- SHT_NULL SectionType = 0 /* inactive */
- SHT_PROGBITS SectionType = 1 /* program defined information */
- SHT_SYMTAB SectionType = 2 /* symbol table section */
- SHT_STRTAB SectionType = 3 /* string table section */
- SHT_RELA SectionType = 4 /* relocation section with addends */
- SHT_HASH SectionType = 5 /* symbol hash table section */
- SHT_DYNAMIC SectionType = 6 /* dynamic section */
- SHT_NOTE SectionType = 7 /* note section */
- SHT_NOBITS SectionType = 8 /* no space section */
- SHT_REL SectionType = 9 /* relocation section - no addends */
- SHT_SHLIB SectionType = 10 /* reserved - purpose unknown */
- SHT_DYNSYM SectionType = 11 /* dynamic symbol table section */
- SHT_INIT_ARRAY SectionType = 14 /* Initialization function pointers. */
- SHT_FINI_ARRAY SectionType = 15 /* Termination function pointers. */
- SHT_PREINIT_ARRAY SectionType = 16 /* Pre-initialization function ptrs. */
- SHT_GROUP SectionType = 17 /* Section group. */
- SHT_SYMTAB_SHNDX SectionType = 18 /* Section indexes (see SHN_XINDEX). */
- SHT_LOOS SectionType = 0x60000000 /* First of OS specific semantics */
- SHT_GNU_ATTRIBUTES SectionType = 0x6ffffff5 /* GNU object attributes */
- SHT_GNU_HASH SectionType = 0x6ffffff6 /* GNU hash table */
- SHT_GNU_LIBLIST SectionType = 0x6ffffff7 /* GNU prelink library list */
- SHT_GNU_VERDEF SectionType = 0x6ffffffd /* GNU version definition section */
- SHT_GNU_VERNEED SectionType = 0x6ffffffe /* GNU version needs section */
- SHT_GNU_VERSYM SectionType = 0x6fffffff /* GNU version symbol table */
- SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */
- SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */
- SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */
- SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */
- SHT_HIUSER SectionType = 0xffffffff /* specific indexes */
-)
-
-var shtStrings = []intName{
- {0, "SHT_NULL"},
- {1, "SHT_PROGBITS"},
- {2, "SHT_SYMTAB"},
- {3, "SHT_STRTAB"},
- {4, "SHT_RELA"},
- {5, "SHT_HASH"},
- {6, "SHT_DYNAMIC"},
- {7, "SHT_NOTE"},
- {8, "SHT_NOBITS"},
- {9, "SHT_REL"},
- {10, "SHT_SHLIB"},
- {11, "SHT_DYNSYM"},
- {14, "SHT_INIT_ARRAY"},
- {15, "SHT_FINI_ARRAY"},
- {16, "SHT_PREINIT_ARRAY"},
- {17, "SHT_GROUP"},
- {18, "SHT_SYMTAB_SHNDX"},
- {0x60000000, "SHT_LOOS"},
- {0x6ffffff5, "SHT_GNU_ATTRIBUTES"},
- {0x6ffffff6, "SHT_GNU_HASH"},
- {0x6ffffff7, "SHT_GNU_LIBLIST"},
- {0x6ffffffd, "SHT_GNU_VERDEF"},
- {0x6ffffffe, "SHT_GNU_VERNEED"},
- {0x6fffffff, "SHT_GNU_VERSYM"},
- {0x70000000, "SHT_LOPROC"},
- {0x7fffffff, "SHT_HIPROC"},
- {0x80000000, "SHT_LOUSER"},
- {0xffffffff, "SHT_HIUSER"},
-}
-
-func (i SectionType) String() string { return stringName(uint32(i), shtStrings, false) }
-func (i SectionType) GoString() string { return stringName(uint32(i), shtStrings, true) }
-
-// Section flags.
-type SectionFlag uint32
-
-const (
- SHF_WRITE SectionFlag = 0x1 /* Section contains writable data. */
- SHF_ALLOC SectionFlag = 0x2 /* Section occupies memory. */
- SHF_EXECINSTR SectionFlag = 0x4 /* Section contains instructions. */
- SHF_MERGE SectionFlag = 0x10 /* Section may be merged. */
- SHF_STRINGS SectionFlag = 0x20 /* Section contains strings. */
- SHF_INFO_LINK SectionFlag = 0x40 /* sh_info holds section index. */
- SHF_LINK_ORDER SectionFlag = 0x80 /* Special ordering requirements. */
- SHF_OS_NONCONFORMING SectionFlag = 0x100 /* OS-specific processing required. */
- SHF_GROUP SectionFlag = 0x200 /* Member of section group. */
- SHF_TLS SectionFlag = 0x400 /* Section contains TLS data. */
- SHF_MASKOS SectionFlag = 0x0ff00000 /* OS-specific semantics. */
- SHF_MASKPROC SectionFlag = 0xf0000000 /* Processor-specific semantics. */
-)
-
-var shfStrings = []intName{
- {0x1, "SHF_WRITE"},
- {0x2, "SHF_ALLOC"},
- {0x4, "SHF_EXECINSTR"},
- {0x10, "SHF_MERGE"},
- {0x20, "SHF_STRINGS"},
- {0x40, "SHF_INFO_LINK"},
- {0x80, "SHF_LINK_ORDER"},
- {0x100, "SHF_OS_NONCONFORMING"},
- {0x200, "SHF_GROUP"},
- {0x400, "SHF_TLS"},
-}
-
-func (i SectionFlag) String() string { return flagName(uint32(i), shfStrings, false) }
-func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) }
-
-// Prog.Type
-type ProgType int
-
-const (
- PT_NULL ProgType = 0 /* Unused entry. */
- PT_LOAD ProgType = 1 /* Loadable segment. */
- PT_DYNAMIC ProgType = 2 /* Dynamic linking information segment. */
- PT_INTERP ProgType = 3 /* Pathname of interpreter. */
- PT_NOTE ProgType = 4 /* Auxiliary information. */
- PT_SHLIB ProgType = 5 /* Reserved (not used). */
- PT_PHDR ProgType = 6 /* Location of program header itself. */
- PT_TLS ProgType = 7 /* Thread local storage segment */
- PT_LOOS ProgType = 0x60000000 /* First OS-specific. */
- PT_HIOS ProgType = 0x6fffffff /* Last OS-specific. */
- PT_LOPROC ProgType = 0x70000000 /* First processor-specific type. */
- PT_HIPROC ProgType = 0x7fffffff /* Last processor-specific type. */
-)
-
-var ptStrings = []intName{
- {0, "PT_NULL"},
- {1, "PT_LOAD"},
- {2, "PT_DYNAMIC"},
- {3, "PT_INTERP"},
- {4, "PT_NOTE"},
- {5, "PT_SHLIB"},
- {6, "PT_PHDR"},
- {7, "PT_TLS"},
- {0x60000000, "PT_LOOS"},
- {0x6fffffff, "PT_HIOS"},
- {0x70000000, "PT_LOPROC"},
- {0x7fffffff, "PT_HIPROC"},
-}
-
-func (i ProgType) String() string { return stringName(uint32(i), ptStrings, false) }
-func (i ProgType) GoString() string { return stringName(uint32(i), ptStrings, true) }
-
-// Prog.Flag
-type ProgFlag uint32
-
-const (
- PF_X ProgFlag = 0x1 /* Executable. */
- PF_W ProgFlag = 0x2 /* Writable. */
- PF_R ProgFlag = 0x4 /* Readable. */
- PF_MASKOS ProgFlag = 0x0ff00000 /* Operating system-specific. */
- PF_MASKPROC ProgFlag = 0xf0000000 /* Processor-specific. */
-)
-
-var pfStrings = []intName{
- {0x1, "PF_X"},
- {0x2, "PF_W"},
- {0x4, "PF_R"},
-}
-
-func (i ProgFlag) String() string { return flagName(uint32(i), pfStrings, false) }
-func (i ProgFlag) GoString() string { return flagName(uint32(i), pfStrings, true) }
-
-// Dyn.Tag
-type DynTag int
-
-const (
- DT_NULL DynTag = 0 /* Terminating entry. */
- DT_NEEDED DynTag = 1 /* String table offset of a needed shared library. */
- DT_PLTRELSZ DynTag = 2 /* Total size in bytes of PLT relocations. */
- DT_PLTGOT DynTag = 3 /* Processor-dependent address. */
- DT_HASH DynTag = 4 /* Address of symbol hash table. */
- DT_STRTAB DynTag = 5 /* Address of string table. */
- DT_SYMTAB DynTag = 6 /* Address of symbol table. */
- DT_RELA DynTag = 7 /* Address of ElfNN_Rela relocations. */
- DT_RELASZ DynTag = 8 /* Total size of ElfNN_Rela relocations. */
- DT_RELAENT DynTag = 9 /* Size of each ElfNN_Rela relocation entry. */
- DT_STRSZ DynTag = 10 /* Size of string table. */
- DT_SYMENT DynTag = 11 /* Size of each symbol table entry. */
- DT_INIT DynTag = 12 /* Address of initialization function. */
- DT_FINI DynTag = 13 /* Address of finalization function. */
- DT_SONAME DynTag = 14 /* String table offset of shared object name. */
- DT_RPATH DynTag = 15 /* String table offset of library path. [sup] */
- DT_SYMBOLIC DynTag = 16 /* Indicates "symbolic" linking. [sup] */
- DT_REL DynTag = 17 /* Address of ElfNN_Rel relocations. */
- DT_RELSZ DynTag = 18 /* Total size of ElfNN_Rel relocations. */
- DT_RELENT DynTag = 19 /* Size of each ElfNN_Rel relocation. */
- DT_PLTREL DynTag = 20 /* Type of relocation used for PLT. */
- DT_DEBUG DynTag = 21 /* Reserved (not used). */
- DT_TEXTREL DynTag = 22 /* Indicates there may be relocations in non-writable segments. [sup] */
- DT_JMPREL DynTag = 23 /* Address of PLT relocations. */
- DT_BIND_NOW DynTag = 24 /* [sup] */
- DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */
- DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */
- DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */
- DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */
- DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */
- DT_FLAGS DynTag = 30 /* Object specific flag values. */
- DT_ENCODING DynTag = 32 /* Values greater than or equal to DT_ENCODING
- and less than DT_LOOS follow the rules for
- the interpretation of the d_un union
- as follows: even == 'd_ptr', even == 'd_val'
- or none */
- DT_PREINIT_ARRAY DynTag = 32 /* Address of the array of pointers to pre-initialization functions. */
- DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */
- DT_LOOS DynTag = 0x6000000d /* First OS-specific */
- DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */
- DT_VERSYM DynTag = 0x6ffffff0
- DT_VERNEED DynTag = 0x6ffffffe
- DT_VERNEEDNUM DynTag = 0x6fffffff
- DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */
- DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */
-)
-
-var dtStrings = []intName{
- {0, "DT_NULL"},
- {1, "DT_NEEDED"},
- {2, "DT_PLTRELSZ"},
- {3, "DT_PLTGOT"},
- {4, "DT_HASH"},
- {5, "DT_STRTAB"},
- {6, "DT_SYMTAB"},
- {7, "DT_RELA"},
- {8, "DT_RELASZ"},
- {9, "DT_RELAENT"},
- {10, "DT_STRSZ"},
- {11, "DT_SYMENT"},
- {12, "DT_INIT"},
- {13, "DT_FINI"},
- {14, "DT_SONAME"},
- {15, "DT_RPATH"},
- {16, "DT_SYMBOLIC"},
- {17, "DT_REL"},
- {18, "DT_RELSZ"},
- {19, "DT_RELENT"},
- {20, "DT_PLTREL"},
- {21, "DT_DEBUG"},
- {22, "DT_TEXTREL"},
- {23, "DT_JMPREL"},
- {24, "DT_BIND_NOW"},
- {25, "DT_INIT_ARRAY"},
- {26, "DT_FINI_ARRAY"},
- {27, "DT_INIT_ARRAYSZ"},
- {28, "DT_FINI_ARRAYSZ"},
- {29, "DT_RUNPATH"},
- {30, "DT_FLAGS"},
- {32, "DT_ENCODING"},
- {32, "DT_PREINIT_ARRAY"},
- {33, "DT_PREINIT_ARRAYSZ"},
- {0x6000000d, "DT_LOOS"},
- {0x6ffff000, "DT_HIOS"},
- {0x6ffffff0, "DT_VERSYM"},
- {0x6ffffffe, "DT_VERNEED"},
- {0x6fffffff, "DT_VERNEEDNUM"},
- {0x70000000, "DT_LOPROC"},
- {0x7fffffff, "DT_HIPROC"},
-}
-
-func (i DynTag) String() string { return stringName(uint32(i), dtStrings, false) }
-func (i DynTag) GoString() string { return stringName(uint32(i), dtStrings, true) }
-
-// DT_FLAGS values.
-type DynFlag int
-
-const (
- DF_ORIGIN DynFlag = 0x0001 /* Indicates that the object being loaded may
- make reference to the
- $ORIGIN substitution string */
- DF_SYMBOLIC DynFlag = 0x0002 /* Indicates "symbolic" linking. */
- DF_TEXTREL DynFlag = 0x0004 /* Indicates there may be relocations in non-writable segments. */
- DF_BIND_NOW DynFlag = 0x0008 /* Indicates that the dynamic linker should
- process all relocations for the object
- containing this entry before transferring
- control to the program. */
- DF_STATIC_TLS DynFlag = 0x0010 /* Indicates that the shared object or
- executable contains code using a static
- thread-local storage scheme. */
-)
-
-var dflagStrings = []intName{
- {0x0001, "DF_ORIGIN"},
- {0x0002, "DF_SYMBOLIC"},
- {0x0004, "DF_TEXTREL"},
- {0x0008, "DF_BIND_NOW"},
- {0x0010, "DF_STATIC_TLS"},
-}
-
-func (i DynFlag) String() string { return flagName(uint32(i), dflagStrings, false) }
-func (i DynFlag) GoString() string { return flagName(uint32(i), dflagStrings, true) }
-
-// NType values; used in core files.
-type NType int
-
-const (
- NT_PRSTATUS NType = 1 /* Process status. */
- NT_FPREGSET NType = 2 /* Floating point registers. */
- NT_PRPSINFO NType = 3 /* Process state info. */
-)
-
-var ntypeStrings = []intName{
- {1, "NT_PRSTATUS"},
- {2, "NT_FPREGSET"},
- {3, "NT_PRPSINFO"},
-}
-
-func (i NType) String() string { return stringName(uint32(i), ntypeStrings, false) }
-func (i NType) GoString() string { return stringName(uint32(i), ntypeStrings, true) }
-
-/* Symbol Binding - ELFNN_ST_BIND - st_info */
-type SymBind int
-
-const (
- STB_LOCAL SymBind = 0 /* Local symbol */
- STB_GLOBAL SymBind = 1 /* Global symbol */
- STB_WEAK SymBind = 2 /* like global - lower precedence */
- STB_LOOS SymBind = 10 /* Reserved range for operating system */
- STB_HIOS SymBind = 12 /* specific semantics. */
- STB_LOPROC SymBind = 13 /* reserved range for processor */
- STB_HIPROC SymBind = 15 /* specific semantics. */
-)
-
-var stbStrings = []intName{
- {0, "STB_LOCAL"},
- {1, "STB_GLOBAL"},
- {2, "STB_WEAK"},
- {10, "STB_LOOS"},
- {12, "STB_HIOS"},
- {13, "STB_LOPROC"},
- {15, "STB_HIPROC"},
-}
-
-func (i SymBind) String() string { return stringName(uint32(i), stbStrings, false) }
-func (i SymBind) GoString() string { return stringName(uint32(i), stbStrings, true) }
-
-/* Symbol type - ELFNN_ST_TYPE - st_info */
-type SymType int
-
-const (
- STT_NOTYPE SymType = 0 /* Unspecified type. */
- STT_OBJECT SymType = 1 /* Data object. */
- STT_FUNC SymType = 2 /* Function. */
- STT_SECTION SymType = 3 /* Section. */
- STT_FILE SymType = 4 /* Source file. */
- STT_COMMON SymType = 5 /* Uninitialized common block. */
- STT_TLS SymType = 6 /* TLS object. */
- STT_LOOS SymType = 10 /* Reserved range for operating system */
- STT_HIOS SymType = 12 /* specific semantics. */
- STT_LOPROC SymType = 13 /* reserved range for processor */
- STT_HIPROC SymType = 15 /* specific semantics. */
-)
-
-var sttStrings = []intName{
- {0, "STT_NOTYPE"},
- {1, "STT_OBJECT"},
- {2, "STT_FUNC"},
- {3, "STT_SECTION"},
- {4, "STT_FILE"},
- {5, "STT_COMMON"},
- {6, "STT_TLS"},
- {10, "STT_LOOS"},
- {12, "STT_HIOS"},
- {13, "STT_LOPROC"},
- {15, "STT_HIPROC"},
-}
-
-func (i SymType) String() string { return stringName(uint32(i), sttStrings, false) }
-func (i SymType) GoString() string { return stringName(uint32(i), sttStrings, true) }
-
-/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
-type SymVis int
-
-const (
- STV_DEFAULT SymVis = 0x0 /* Default visibility (see binding). */
- STV_INTERNAL SymVis = 0x1 /* Special meaning in relocatable objects. */
- STV_HIDDEN SymVis = 0x2 /* Not visible. */
- STV_PROTECTED SymVis = 0x3 /* Visible but not preemptible. */
-)
-
-var stvStrings = []intName{
- {0x0, "STV_DEFAULT"},
- {0x1, "STV_INTERNAL"},
- {0x2, "STV_HIDDEN"},
- {0x3, "STV_PROTECTED"},
-}
-
-func (i SymVis) String() string { return stringName(uint32(i), stvStrings, false) }
-func (i SymVis) GoString() string { return stringName(uint32(i), stvStrings, true) }
-
-/*
- * Relocation types.
- */
-
-// Relocation types for x86-64.
-type R_X86_64 int
-
-const (
- R_X86_64_NONE R_X86_64 = 0 /* No relocation. */
- R_X86_64_64 R_X86_64 = 1 /* Add 64 bit symbol value. */
- R_X86_64_PC32 R_X86_64 = 2 /* PC-relative 32 bit signed sym value. */
- R_X86_64_GOT32 R_X86_64 = 3 /* PC-relative 32 bit GOT offset. */
- R_X86_64_PLT32 R_X86_64 = 4 /* PC-relative 32 bit PLT offset. */
- R_X86_64_COPY R_X86_64 = 5 /* Copy data from shared object. */
- R_X86_64_GLOB_DAT R_X86_64 = 6 /* Set GOT entry to data address. */
- R_X86_64_JMP_SLOT R_X86_64 = 7 /* Set GOT entry to code address. */
- R_X86_64_RELATIVE R_X86_64 = 8 /* Add load address of shared object. */
- R_X86_64_GOTPCREL R_X86_64 = 9 /* Add 32 bit signed pcrel offset to GOT. */
- R_X86_64_32 R_X86_64 = 10 /* Add 32 bit zero extended symbol value */
- R_X86_64_32S R_X86_64 = 11 /* Add 32 bit sign extended symbol value */
- R_X86_64_16 R_X86_64 = 12 /* Add 16 bit zero extended symbol value */
- R_X86_64_PC16 R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */
- R_X86_64_8 R_X86_64 = 14 /* Add 8 bit zero extended symbol value */
- R_X86_64_PC8 R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */
- R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */
- R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */
- R_X86_64_TPOFF64 R_X86_64 = 18 /* Offset in static TLS block */
- R_X86_64_TLSGD R_X86_64 = 19 /* PC relative offset to GD GOT entry */
- R_X86_64_TLSLD R_X86_64 = 20 /* PC relative offset to LD GOT entry */
- R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */
- R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */
- R_X86_64_TPOFF32 R_X86_64 = 23 /* Offset in static TLS block */
-)
-
-var rx86_64Strings = []intName{
- {0, "R_X86_64_NONE"},
- {1, "R_X86_64_64"},
- {2, "R_X86_64_PC32"},
- {3, "R_X86_64_GOT32"},
- {4, "R_X86_64_PLT32"},
- {5, "R_X86_64_COPY"},
- {6, "R_X86_64_GLOB_DAT"},
- {7, "R_X86_64_JMP_SLOT"},
- {8, "R_X86_64_RELATIVE"},
- {9, "R_X86_64_GOTPCREL"},
- {10, "R_X86_64_32"},
- {11, "R_X86_64_32S"},
- {12, "R_X86_64_16"},
- {13, "R_X86_64_PC16"},
- {14, "R_X86_64_8"},
- {15, "R_X86_64_PC8"},
- {16, "R_X86_64_DTPMOD64"},
- {17, "R_X86_64_DTPOFF64"},
- {18, "R_X86_64_TPOFF64"},
- {19, "R_X86_64_TLSGD"},
- {20, "R_X86_64_TLSLD"},
- {21, "R_X86_64_DTPOFF32"},
- {22, "R_X86_64_GOTTPOFF"},
- {23, "R_X86_64_TPOFF32"},
-}
-
-func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) }
-func (i R_X86_64) GoString() string { return stringName(uint32(i), rx86_64Strings, true) }
-
-// Relocation types for Alpha.
-type R_ALPHA int
-
-const (
- R_ALPHA_NONE R_ALPHA = 0 /* No reloc */
- R_ALPHA_REFLONG R_ALPHA = 1 /* Direct 32 bit */
- R_ALPHA_REFQUAD R_ALPHA = 2 /* Direct 64 bit */
- R_ALPHA_GPREL32 R_ALPHA = 3 /* GP relative 32 bit */
- R_ALPHA_LITERAL R_ALPHA = 4 /* GP relative 16 bit w/optimization */
- R_ALPHA_LITUSE R_ALPHA = 5 /* Optimization hint for LITERAL */
- R_ALPHA_GPDISP R_ALPHA = 6 /* Add displacement to GP */
- R_ALPHA_BRADDR R_ALPHA = 7 /* PC+4 relative 23 bit shifted */
- R_ALPHA_HINT R_ALPHA = 8 /* PC+4 relative 16 bit shifted */
- R_ALPHA_SREL16 R_ALPHA = 9 /* PC relative 16 bit */
- R_ALPHA_SREL32 R_ALPHA = 10 /* PC relative 32 bit */
- R_ALPHA_SREL64 R_ALPHA = 11 /* PC relative 64 bit */
- R_ALPHA_OP_PUSH R_ALPHA = 12 /* OP stack push */
- R_ALPHA_OP_STORE R_ALPHA = 13 /* OP stack pop and store */
- R_ALPHA_OP_PSUB R_ALPHA = 14 /* OP stack subtract */
- R_ALPHA_OP_PRSHIFT R_ALPHA = 15 /* OP stack right shift */
- R_ALPHA_GPVALUE R_ALPHA = 16
- R_ALPHA_GPRELHIGH R_ALPHA = 17
- R_ALPHA_GPRELLOW R_ALPHA = 18
- R_ALPHA_IMMED_GP_16 R_ALPHA = 19
- R_ALPHA_IMMED_GP_HI32 R_ALPHA = 20
- R_ALPHA_IMMED_SCN_HI32 R_ALPHA = 21
- R_ALPHA_IMMED_BR_HI32 R_ALPHA = 22
- R_ALPHA_IMMED_LO32 R_ALPHA = 23
- R_ALPHA_COPY R_ALPHA = 24 /* Copy symbol at runtime */
- R_ALPHA_GLOB_DAT R_ALPHA = 25 /* Create GOT entry */
- R_ALPHA_JMP_SLOT R_ALPHA = 26 /* Create PLT entry */
- R_ALPHA_RELATIVE R_ALPHA = 27 /* Adjust by program base */
-)
-
-var ralphaStrings = []intName{
- {0, "R_ALPHA_NONE"},
- {1, "R_ALPHA_REFLONG"},
- {2, "R_ALPHA_REFQUAD"},
- {3, "R_ALPHA_GPREL32"},
- {4, "R_ALPHA_LITERAL"},
- {5, "R_ALPHA_LITUSE"},
- {6, "R_ALPHA_GPDISP"},
- {7, "R_ALPHA_BRADDR"},
- {8, "R_ALPHA_HINT"},
- {9, "R_ALPHA_SREL16"},
- {10, "R_ALPHA_SREL32"},
- {11, "R_ALPHA_SREL64"},
- {12, "R_ALPHA_OP_PUSH"},
- {13, "R_ALPHA_OP_STORE"},
- {14, "R_ALPHA_OP_PSUB"},
- {15, "R_ALPHA_OP_PRSHIFT"},
- {16, "R_ALPHA_GPVALUE"},
- {17, "R_ALPHA_GPRELHIGH"},
- {18, "R_ALPHA_GPRELLOW"},
- {19, "R_ALPHA_IMMED_GP_16"},
- {20, "R_ALPHA_IMMED_GP_HI32"},
- {21, "R_ALPHA_IMMED_SCN_HI32"},
- {22, "R_ALPHA_IMMED_BR_HI32"},
- {23, "R_ALPHA_IMMED_LO32"},
- {24, "R_ALPHA_COPY"},
- {25, "R_ALPHA_GLOB_DAT"},
- {26, "R_ALPHA_JMP_SLOT"},
- {27, "R_ALPHA_RELATIVE"},
-}
-
-func (i R_ALPHA) String() string { return stringName(uint32(i), ralphaStrings, false) }
-func (i R_ALPHA) GoString() string { return stringName(uint32(i), ralphaStrings, true) }
-
-// Relocation types for ARM.
-type R_ARM int
-
-const (
- R_ARM_NONE R_ARM = 0 /* No relocation. */
- R_ARM_PC24 R_ARM = 1
- R_ARM_ABS32 R_ARM = 2
- R_ARM_REL32 R_ARM = 3
- R_ARM_PC13 R_ARM = 4
- R_ARM_ABS16 R_ARM = 5
- R_ARM_ABS12 R_ARM = 6
- R_ARM_THM_ABS5 R_ARM = 7
- R_ARM_ABS8 R_ARM = 8
- R_ARM_SBREL32 R_ARM = 9
- R_ARM_THM_PC22 R_ARM = 10
- R_ARM_THM_PC8 R_ARM = 11
- R_ARM_AMP_VCALL9 R_ARM = 12
- R_ARM_SWI24 R_ARM = 13
- R_ARM_THM_SWI8 R_ARM = 14
- R_ARM_XPC25 R_ARM = 15
- R_ARM_THM_XPC22 R_ARM = 16
- R_ARM_COPY R_ARM = 20 /* Copy data from shared object. */
- R_ARM_GLOB_DAT R_ARM = 21 /* Set GOT entry to data address. */
- R_ARM_JUMP_SLOT R_ARM = 22 /* Set GOT entry to code address. */
- R_ARM_RELATIVE R_ARM = 23 /* Add load address of shared object. */
- R_ARM_GOTOFF R_ARM = 24 /* Add GOT-relative symbol address. */
- R_ARM_GOTPC R_ARM = 25 /* Add PC-relative GOT table address. */
- R_ARM_GOT32 R_ARM = 26 /* Add PC-relative GOT offset. */
- R_ARM_PLT32 R_ARM = 27 /* Add PC-relative PLT offset. */
- R_ARM_GNU_VTENTRY R_ARM = 100
- R_ARM_GNU_VTINHERIT R_ARM = 101
- R_ARM_RSBREL32 R_ARM = 250
- R_ARM_THM_RPC22 R_ARM = 251
- R_ARM_RREL32 R_ARM = 252
- R_ARM_RABS32 R_ARM = 253
- R_ARM_RPC24 R_ARM = 254
- R_ARM_RBASE R_ARM = 255
-)
-
-var rarmStrings = []intName{
- {0, "R_ARM_NONE"},
- {1, "R_ARM_PC24"},
- {2, "R_ARM_ABS32"},
- {3, "R_ARM_REL32"},
- {4, "R_ARM_PC13"},
- {5, "R_ARM_ABS16"},
- {6, "R_ARM_ABS12"},
- {7, "R_ARM_THM_ABS5"},
- {8, "R_ARM_ABS8"},
- {9, "R_ARM_SBREL32"},
- {10, "R_ARM_THM_PC22"},
- {11, "R_ARM_THM_PC8"},
- {12, "R_ARM_AMP_VCALL9"},
- {13, "R_ARM_SWI24"},
- {14, "R_ARM_THM_SWI8"},
- {15, "R_ARM_XPC25"},
- {16, "R_ARM_THM_XPC22"},
- {20, "R_ARM_COPY"},
- {21, "R_ARM_GLOB_DAT"},
- {22, "R_ARM_JUMP_SLOT"},
- {23, "R_ARM_RELATIVE"},
- {24, "R_ARM_GOTOFF"},
- {25, "R_ARM_GOTPC"},
- {26, "R_ARM_GOT32"},
- {27, "R_ARM_PLT32"},
- {100, "R_ARM_GNU_VTENTRY"},
- {101, "R_ARM_GNU_VTINHERIT"},
- {250, "R_ARM_RSBREL32"},
- {251, "R_ARM_THM_RPC22"},
- {252, "R_ARM_RREL32"},
- {253, "R_ARM_RABS32"},
- {254, "R_ARM_RPC24"},
- {255, "R_ARM_RBASE"},
-}
-
-func (i R_ARM) String() string { return stringName(uint32(i), rarmStrings, false) }
-func (i R_ARM) GoString() string { return stringName(uint32(i), rarmStrings, true) }
-
-// Relocation types for 386.
-type R_386 int
-
-const (
- R_386_NONE R_386 = 0 /* No relocation. */
- R_386_32 R_386 = 1 /* Add symbol value. */
- R_386_PC32 R_386 = 2 /* Add PC-relative symbol value. */
- R_386_GOT32 R_386 = 3 /* Add PC-relative GOT offset. */
- R_386_PLT32 R_386 = 4 /* Add PC-relative PLT offset. */
- R_386_COPY R_386 = 5 /* Copy data from shared object. */
- R_386_GLOB_DAT R_386 = 6 /* Set GOT entry to data address. */
- R_386_JMP_SLOT R_386 = 7 /* Set GOT entry to code address. */
- R_386_RELATIVE R_386 = 8 /* Add load address of shared object. */
- R_386_GOTOFF R_386 = 9 /* Add GOT-relative symbol address. */
- R_386_GOTPC R_386 = 10 /* Add PC-relative GOT table address. */
- R_386_TLS_TPOFF R_386 = 14 /* Negative offset in static TLS block */
- R_386_TLS_IE R_386 = 15 /* Absolute address of GOT for -ve static TLS */
- R_386_TLS_GOTIE R_386 = 16 /* GOT entry for negative static TLS block */
- R_386_TLS_LE R_386 = 17 /* Negative offset relative to static TLS */
- R_386_TLS_GD R_386 = 18 /* 32 bit offset to GOT (index,off) pair */
- R_386_TLS_LDM R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */
- R_386_TLS_GD_32 R_386 = 24 /* 32 bit offset to GOT (index,off) pair */
- R_386_TLS_GD_PUSH R_386 = 25 /* pushl instruction for Sun ABI GD sequence */
- R_386_TLS_GD_CALL R_386 = 26 /* call instruction for Sun ABI GD sequence */
- R_386_TLS_GD_POP R_386 = 27 /* popl instruction for Sun ABI GD sequence */
- R_386_TLS_LDM_32 R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */
- R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */
- R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */
- R_386_TLS_LDM_POP R_386 = 31 /* popl instruction for Sun ABI LD sequence */
- R_386_TLS_LDO_32 R_386 = 32 /* 32 bit offset from start of TLS block */
- R_386_TLS_IE_32 R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */
- R_386_TLS_LE_32 R_386 = 34 /* 32 bit offset within static TLS block */
- R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */
- R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */
- R_386_TLS_TPOFF32 R_386 = 37 /* GOT entry of -ve static TLS offset */
-)
-
-var r386Strings = []intName{
- {0, "R_386_NONE"},
- {1, "R_386_32"},
- {2, "R_386_PC32"},
- {3, "R_386_GOT32"},
- {4, "R_386_PLT32"},
- {5, "R_386_COPY"},
- {6, "R_386_GLOB_DAT"},
- {7, "R_386_JMP_SLOT"},
- {8, "R_386_RELATIVE"},
- {9, "R_386_GOTOFF"},
- {10, "R_386_GOTPC"},
- {14, "R_386_TLS_TPOFF"},
- {15, "R_386_TLS_IE"},
- {16, "R_386_TLS_GOTIE"},
- {17, "R_386_TLS_LE"},
- {18, "R_386_TLS_GD"},
- {19, "R_386_TLS_LDM"},
- {24, "R_386_TLS_GD_32"},
- {25, "R_386_TLS_GD_PUSH"},
- {26, "R_386_TLS_GD_CALL"},
- {27, "R_386_TLS_GD_POP"},
- {28, "R_386_TLS_LDM_32"},
- {29, "R_386_TLS_LDM_PUSH"},
- {30, "R_386_TLS_LDM_CALL"},
- {31, "R_386_TLS_LDM_POP"},
- {32, "R_386_TLS_LDO_32"},
- {33, "R_386_TLS_IE_32"},
- {34, "R_386_TLS_LE_32"},
- {35, "R_386_TLS_DTPMOD32"},
- {36, "R_386_TLS_DTPOFF32"},
- {37, "R_386_TLS_TPOFF32"},
-}
-
-func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) }
-func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) }
-
-// Relocation types for PowerPC.
-type R_PPC int
-
-const (
- R_PPC_NONE R_PPC = 0 /* No relocation. */
- R_PPC_ADDR32 R_PPC = 1
- R_PPC_ADDR24 R_PPC = 2
- R_PPC_ADDR16 R_PPC = 3
- R_PPC_ADDR16_LO R_PPC = 4
- R_PPC_ADDR16_HI R_PPC = 5
- R_PPC_ADDR16_HA R_PPC = 6
- R_PPC_ADDR14 R_PPC = 7
- R_PPC_ADDR14_BRTAKEN R_PPC = 8
- R_PPC_ADDR14_BRNTAKEN R_PPC = 9
- R_PPC_REL24 R_PPC = 10
- R_PPC_REL14 R_PPC = 11
- R_PPC_REL14_BRTAKEN R_PPC = 12
- R_PPC_REL14_BRNTAKEN R_PPC = 13
- R_PPC_GOT16 R_PPC = 14
- R_PPC_GOT16_LO R_PPC = 15
- R_PPC_GOT16_HI R_PPC = 16
- R_PPC_GOT16_HA R_PPC = 17
- R_PPC_PLTREL24 R_PPC = 18
- R_PPC_COPY R_PPC = 19
- R_PPC_GLOB_DAT R_PPC = 20
- R_PPC_JMP_SLOT R_PPC = 21
- R_PPC_RELATIVE R_PPC = 22
- R_PPC_LOCAL24PC R_PPC = 23
- R_PPC_UADDR32 R_PPC = 24
- R_PPC_UADDR16 R_PPC = 25
- R_PPC_REL32 R_PPC = 26
- R_PPC_PLT32 R_PPC = 27
- R_PPC_PLTREL32 R_PPC = 28
- R_PPC_PLT16_LO R_PPC = 29
- R_PPC_PLT16_HI R_PPC = 30
- R_PPC_PLT16_HA R_PPC = 31
- R_PPC_SDAREL16 R_PPC = 32
- R_PPC_SECTOFF R_PPC = 33
- R_PPC_SECTOFF_LO R_PPC = 34
- R_PPC_SECTOFF_HI R_PPC = 35
- R_PPC_SECTOFF_HA R_PPC = 36
- R_PPC_TLS R_PPC = 67
- R_PPC_DTPMOD32 R_PPC = 68
- R_PPC_TPREL16 R_PPC = 69
- R_PPC_TPREL16_LO R_PPC = 70
- R_PPC_TPREL16_HI R_PPC = 71
- R_PPC_TPREL16_HA R_PPC = 72
- R_PPC_TPREL32 R_PPC = 73
- R_PPC_DTPREL16 R_PPC = 74
- R_PPC_DTPREL16_LO R_PPC = 75
- R_PPC_DTPREL16_HI R_PPC = 76
- R_PPC_DTPREL16_HA R_PPC = 77
- R_PPC_DTPREL32 R_PPC = 78
- R_PPC_GOT_TLSGD16 R_PPC = 79
- R_PPC_GOT_TLSGD16_LO R_PPC = 80
- R_PPC_GOT_TLSGD16_HI R_PPC = 81
- R_PPC_GOT_TLSGD16_HA R_PPC = 82
- R_PPC_GOT_TLSLD16 R_PPC = 83
- R_PPC_GOT_TLSLD16_LO R_PPC = 84
- R_PPC_GOT_TLSLD16_HI R_PPC = 85
- R_PPC_GOT_TLSLD16_HA R_PPC = 86
- R_PPC_GOT_TPREL16 R_PPC = 87
- R_PPC_GOT_TPREL16_LO R_PPC = 88
- R_PPC_GOT_TPREL16_HI R_PPC = 89
- R_PPC_GOT_TPREL16_HA R_PPC = 90
- R_PPC_EMB_NADDR32 R_PPC = 101
- R_PPC_EMB_NADDR16 R_PPC = 102
- R_PPC_EMB_NADDR16_LO R_PPC = 103
- R_PPC_EMB_NADDR16_HI R_PPC = 104
- R_PPC_EMB_NADDR16_HA R_PPC = 105
- R_PPC_EMB_SDAI16 R_PPC = 106
- R_PPC_EMB_SDA2I16 R_PPC = 107
- R_PPC_EMB_SDA2REL R_PPC = 108
- R_PPC_EMB_SDA21 R_PPC = 109
- R_PPC_EMB_MRKREF R_PPC = 110
- R_PPC_EMB_RELSEC16 R_PPC = 111
- R_PPC_EMB_RELST_LO R_PPC = 112
- R_PPC_EMB_RELST_HI R_PPC = 113
- R_PPC_EMB_RELST_HA R_PPC = 114
- R_PPC_EMB_BIT_FLD R_PPC = 115
- R_PPC_EMB_RELSDA R_PPC = 116
-)
-
-var rppcStrings = []intName{
- {0, "R_PPC_NONE"},
- {1, "R_PPC_ADDR32"},
- {2, "R_PPC_ADDR24"},
- {3, "R_PPC_ADDR16"},
- {4, "R_PPC_ADDR16_LO"},
- {5, "R_PPC_ADDR16_HI"},
- {6, "R_PPC_ADDR16_HA"},
- {7, "R_PPC_ADDR14"},
- {8, "R_PPC_ADDR14_BRTAKEN"},
- {9, "R_PPC_ADDR14_BRNTAKEN"},
- {10, "R_PPC_REL24"},
- {11, "R_PPC_REL14"},
- {12, "R_PPC_REL14_BRTAKEN"},
- {13, "R_PPC_REL14_BRNTAKEN"},
- {14, "R_PPC_GOT16"},
- {15, "R_PPC_GOT16_LO"},
- {16, "R_PPC_GOT16_HI"},
- {17, "R_PPC_GOT16_HA"},
- {18, "R_PPC_PLTREL24"},
- {19, "R_PPC_COPY"},
- {20, "R_PPC_GLOB_DAT"},
- {21, "R_PPC_JMP_SLOT"},
- {22, "R_PPC_RELATIVE"},
- {23, "R_PPC_LOCAL24PC"},
- {24, "R_PPC_UADDR32"},
- {25, "R_PPC_UADDR16"},
- {26, "R_PPC_REL32"},
- {27, "R_PPC_PLT32"},
- {28, "R_PPC_PLTREL32"},
- {29, "R_PPC_PLT16_LO"},
- {30, "R_PPC_PLT16_HI"},
- {31, "R_PPC_PLT16_HA"},
- {32, "R_PPC_SDAREL16"},
- {33, "R_PPC_SECTOFF"},
- {34, "R_PPC_SECTOFF_LO"},
- {35, "R_PPC_SECTOFF_HI"},
- {36, "R_PPC_SECTOFF_HA"},
-
- {67, "R_PPC_TLS"},
- {68, "R_PPC_DTPMOD32"},
- {69, "R_PPC_TPREL16"},
- {70, "R_PPC_TPREL16_LO"},
- {71, "R_PPC_TPREL16_HI"},
- {72, "R_PPC_TPREL16_HA"},
- {73, "R_PPC_TPREL32"},
- {74, "R_PPC_DTPREL16"},
- {75, "R_PPC_DTPREL16_LO"},
- {76, "R_PPC_DTPREL16_HI"},
- {77, "R_PPC_DTPREL16_HA"},
- {78, "R_PPC_DTPREL32"},
- {79, "R_PPC_GOT_TLSGD16"},
- {80, "R_PPC_GOT_TLSGD16_LO"},
- {81, "R_PPC_GOT_TLSGD16_HI"},
- {82, "R_PPC_GOT_TLSGD16_HA"},
- {83, "R_PPC_GOT_TLSLD16"},
- {84, "R_PPC_GOT_TLSLD16_LO"},
- {85, "R_PPC_GOT_TLSLD16_HI"},
- {86, "R_PPC_GOT_TLSLD16_HA"},
- {87, "R_PPC_GOT_TPREL16"},
- {88, "R_PPC_GOT_TPREL16_LO"},
- {89, "R_PPC_GOT_TPREL16_HI"},
- {90, "R_PPC_GOT_TPREL16_HA"},
-
- {101, "R_PPC_EMB_NADDR32"},
- {102, "R_PPC_EMB_NADDR16"},
- {103, "R_PPC_EMB_NADDR16_LO"},
- {104, "R_PPC_EMB_NADDR16_HI"},
- {105, "R_PPC_EMB_NADDR16_HA"},
- {106, "R_PPC_EMB_SDAI16"},
- {107, "R_PPC_EMB_SDA2I16"},
- {108, "R_PPC_EMB_SDA2REL"},
- {109, "R_PPC_EMB_SDA21"},
- {110, "R_PPC_EMB_MRKREF"},
- {111, "R_PPC_EMB_RELSEC16"},
- {112, "R_PPC_EMB_RELST_LO"},
- {113, "R_PPC_EMB_RELST_HI"},
- {114, "R_PPC_EMB_RELST_HA"},
- {115, "R_PPC_EMB_BIT_FLD"},
- {116, "R_PPC_EMB_RELSDA"},
-}
-
-func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) }
-func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) }
-
-// Relocation types for SPARC.
-type R_SPARC int
-
-const (
- R_SPARC_NONE R_SPARC = 0
- R_SPARC_8 R_SPARC = 1
- R_SPARC_16 R_SPARC = 2
- R_SPARC_32 R_SPARC = 3
- R_SPARC_DISP8 R_SPARC = 4
- R_SPARC_DISP16 R_SPARC = 5
- R_SPARC_DISP32 R_SPARC = 6
- R_SPARC_WDISP30 R_SPARC = 7
- R_SPARC_WDISP22 R_SPARC = 8
- R_SPARC_HI22 R_SPARC = 9
- R_SPARC_22 R_SPARC = 10
- R_SPARC_13 R_SPARC = 11
- R_SPARC_LO10 R_SPARC = 12
- R_SPARC_GOT10 R_SPARC = 13
- R_SPARC_GOT13 R_SPARC = 14
- R_SPARC_GOT22 R_SPARC = 15
- R_SPARC_PC10 R_SPARC = 16
- R_SPARC_PC22 R_SPARC = 17
- R_SPARC_WPLT30 R_SPARC = 18
- R_SPARC_COPY R_SPARC = 19
- R_SPARC_GLOB_DAT R_SPARC = 20
- R_SPARC_JMP_SLOT R_SPARC = 21
- R_SPARC_RELATIVE R_SPARC = 22
- R_SPARC_UA32 R_SPARC = 23
- R_SPARC_PLT32 R_SPARC = 24
- R_SPARC_HIPLT22 R_SPARC = 25
- R_SPARC_LOPLT10 R_SPARC = 26
- R_SPARC_PCPLT32 R_SPARC = 27
- R_SPARC_PCPLT22 R_SPARC = 28
- R_SPARC_PCPLT10 R_SPARC = 29
- R_SPARC_10 R_SPARC = 30
- R_SPARC_11 R_SPARC = 31
- R_SPARC_64 R_SPARC = 32
- R_SPARC_OLO10 R_SPARC = 33
- R_SPARC_HH22 R_SPARC = 34
- R_SPARC_HM10 R_SPARC = 35
- R_SPARC_LM22 R_SPARC = 36
- R_SPARC_PC_HH22 R_SPARC = 37
- R_SPARC_PC_HM10 R_SPARC = 38
- R_SPARC_PC_LM22 R_SPARC = 39
- R_SPARC_WDISP16 R_SPARC = 40
- R_SPARC_WDISP19 R_SPARC = 41
- R_SPARC_GLOB_JMP R_SPARC = 42
- R_SPARC_7 R_SPARC = 43
- R_SPARC_5 R_SPARC = 44
- R_SPARC_6 R_SPARC = 45
- R_SPARC_DISP64 R_SPARC = 46
- R_SPARC_PLT64 R_SPARC = 47
- R_SPARC_HIX22 R_SPARC = 48
- R_SPARC_LOX10 R_SPARC = 49
- R_SPARC_H44 R_SPARC = 50
- R_SPARC_M44 R_SPARC = 51
- R_SPARC_L44 R_SPARC = 52
- R_SPARC_REGISTER R_SPARC = 53
- R_SPARC_UA64 R_SPARC = 54
- R_SPARC_UA16 R_SPARC = 55
-)
-
-var rsparcStrings = []intName{
- {0, "R_SPARC_NONE"},
- {1, "R_SPARC_8"},
- {2, "R_SPARC_16"},
- {3, "R_SPARC_32"},
- {4, "R_SPARC_DISP8"},
- {5, "R_SPARC_DISP16"},
- {6, "R_SPARC_DISP32"},
- {7, "R_SPARC_WDISP30"},
- {8, "R_SPARC_WDISP22"},
- {9, "R_SPARC_HI22"},
- {10, "R_SPARC_22"},
- {11, "R_SPARC_13"},
- {12, "R_SPARC_LO10"},
- {13, "R_SPARC_GOT10"},
- {14, "R_SPARC_GOT13"},
- {15, "R_SPARC_GOT22"},
- {16, "R_SPARC_PC10"},
- {17, "R_SPARC_PC22"},
- {18, "R_SPARC_WPLT30"},
- {19, "R_SPARC_COPY"},
- {20, "R_SPARC_GLOB_DAT"},
- {21, "R_SPARC_JMP_SLOT"},
- {22, "R_SPARC_RELATIVE"},
- {23, "R_SPARC_UA32"},
- {24, "R_SPARC_PLT32"},
- {25, "R_SPARC_HIPLT22"},
- {26, "R_SPARC_LOPLT10"},
- {27, "R_SPARC_PCPLT32"},
- {28, "R_SPARC_PCPLT22"},
- {29, "R_SPARC_PCPLT10"},
- {30, "R_SPARC_10"},
- {31, "R_SPARC_11"},
- {32, "R_SPARC_64"},
- {33, "R_SPARC_OLO10"},
- {34, "R_SPARC_HH22"},
- {35, "R_SPARC_HM10"},
- {36, "R_SPARC_LM22"},
- {37, "R_SPARC_PC_HH22"},
- {38, "R_SPARC_PC_HM10"},
- {39, "R_SPARC_PC_LM22"},
- {40, "R_SPARC_WDISP16"},
- {41, "R_SPARC_WDISP19"},
- {42, "R_SPARC_GLOB_JMP"},
- {43, "R_SPARC_7"},
- {44, "R_SPARC_5"},
- {45, "R_SPARC_6"},
- {46, "R_SPARC_DISP64"},
- {47, "R_SPARC_PLT64"},
- {48, "R_SPARC_HIX22"},
- {49, "R_SPARC_LOX10"},
- {50, "R_SPARC_H44"},
- {51, "R_SPARC_M44"},
- {52, "R_SPARC_L44"},
- {53, "R_SPARC_REGISTER"},
- {54, "R_SPARC_UA64"},
- {55, "R_SPARC_UA16"},
-}
-
-func (i R_SPARC) String() string { return stringName(uint32(i), rsparcStrings, false) }
-func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings, true) }
-
-// Magic number for the elf trampoline, chosen wisely to be an immediate value.
-const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
-
-// ELF32 File header.
-type Header32 struct {
- Ident [EI_NIDENT]byte /* File identification. */
- Type uint16 /* File type. */
- Machine uint16 /* Machine architecture. */
- Version uint32 /* ELF format version. */
- Entry uint32 /* Entry point. */
- Phoff uint32 /* Program header file offset. */
- Shoff uint32 /* Section header file offset. */
- Flags uint32 /* Architecture-specific flags. */
- Ehsize uint16 /* Size of ELF header in bytes. */
- Phentsize uint16 /* Size of program header entry. */
- Phnum uint16 /* Number of program header entries. */
- Shentsize uint16 /* Size of section header entry. */
- Shnum uint16 /* Number of section header entries. */
- Shstrndx uint16 /* Section name strings section. */
-}
-
-// ELF32 Section header.
-type Section32 struct {
- Name uint32 /* Section name (index into the section header string table). */
- Type uint32 /* Section type. */
- Flags uint32 /* Section flags. */
- Addr uint32 /* Address in memory image. */
- Off uint32 /* Offset in file. */
- Size uint32 /* Size in bytes. */
- Link uint32 /* Index of a related section. */
- Info uint32 /* Depends on section type. */
- Addralign uint32 /* Alignment in bytes. */
- Entsize uint32 /* Size of each entry in section. */
-}
-
-// ELF32 Program header.
-type Prog32 struct {
- Type uint32 /* Entry type. */
- Off uint32 /* File offset of contents. */
- Vaddr uint32 /* Virtual address in memory image. */
- Paddr uint32 /* Physical address (not used). */
- Filesz uint32 /* Size of contents in file. */
- Memsz uint32 /* Size of contents in memory. */
- Flags uint32 /* Access permission flags. */
- Align uint32 /* Alignment in memory and file. */
-}
-
-// ELF32 Dynamic structure. The ".dynamic" section contains an array of them.
-type Dyn32 struct {
- Tag int32 /* Entry type. */
- Val uint32 /* Integer/Address value. */
-}
-
-/*
- * Relocation entries.
- */
-
-// ELF32 Relocations that don't need an addend field.
-type Rel32 struct {
- Off uint32 /* Location to be relocated. */
- Info uint32 /* Relocation type and symbol index. */
-}
-
-// ELF32 Relocations that need an addend field.
-type Rela32 struct {
- Off uint32 /* Location to be relocated. */
- Info uint32 /* Relocation type and symbol index. */
- Addend int32 /* Addend. */
-}
-
-func R_SYM32(info uint32) uint32 { return uint32(info >> 8) }
-func R_TYPE32(info uint32) uint32 { return uint32(info & 0xff) }
-func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ }
-
-// ELF32 Symbol.
-type Sym32 struct {
- Name uint32
- Value uint32
- Size uint32
- Info uint8
- Other uint8
- Shndx uint16
-}
-
-const Sym32Size = 16
-
-func ST_BIND(info uint8) SymBind { return SymBind(info >> 4) }
-func ST_TYPE(info uint8) SymType { return SymType(info & 0xF) }
-func ST_INFO(bind SymBind, typ SymType) uint8 {
- return uint8(bind)<<4 | uint8(typ)&0xf
-}
-func ST_VISIBILITY(other uint8) SymVis { return SymVis(other & 3) }
-
-/*
- * ELF64
- */
-
-// ELF64 file header.
-type Header64 struct {
- Ident [EI_NIDENT]byte /* File identification. */
- Type uint16 /* File type. */
- Machine uint16 /* Machine architecture. */
- Version uint32 /* ELF format version. */
- Entry uint64 /* Entry point. */
- Phoff uint64 /* Program header file offset. */
- Shoff uint64 /* Section header file offset. */
- Flags uint32 /* Architecture-specific flags. */
- Ehsize uint16 /* Size of ELF header in bytes. */
- Phentsize uint16 /* Size of program header entry. */
- Phnum uint16 /* Number of program header entries. */
- Shentsize uint16 /* Size of section header entry. */
- Shnum uint16 /* Number of section header entries. */
- Shstrndx uint16 /* Section name strings section. */
-}
-
-// ELF64 Section header.
-type Section64 struct {
- Name uint32 /* Section name (index into the section header string table). */
- Type uint32 /* Section type. */
- Flags uint64 /* Section flags. */
- Addr uint64 /* Address in memory image. */
- Off uint64 /* Offset in file. */
- Size uint64 /* Size in bytes. */
- Link uint32 /* Index of a related section. */
- Info uint32 /* Depends on section type. */
- Addralign uint64 /* Alignment in bytes. */
- Entsize uint64 /* Size of each entry in section. */
-}
-
-// ELF64 Program header.
-type Prog64 struct {
- Type uint32 /* Entry type. */
- Flags uint32 /* Access permission flags. */
- Off uint64 /* File offset of contents. */
- Vaddr uint64 /* Virtual address in memory image. */
- Paddr uint64 /* Physical address (not used). */
- Filesz uint64 /* Size of contents in file. */
- Memsz uint64 /* Size of contents in memory. */
- Align uint64 /* Alignment in memory and file. */
-}
-
-// ELF64 Dynamic structure. The ".dynamic" section contains an array of them.
-type Dyn64 struct {
- Tag int64 /* Entry type. */
- Val uint64 /* Integer/address value */
-}
-
-/*
- * Relocation entries.
- */
-
-/* ELF64 relocations that don't need an addend field. */
-type Rel64 struct {
- Off uint64 /* Location to be relocated. */
- Info uint64 /* Relocation type and symbol index. */
-}
-
-/* ELF64 relocations that need an addend field. */
-type Rela64 struct {
- Off uint64 /* Location to be relocated. */
- Info uint64 /* Relocation type and symbol index. */
- Addend int64 /* Addend. */
-}
-
-func R_SYM64(info uint64) uint32 { return uint32(info >> 32) }
-func R_TYPE64(info uint64) uint32 { return uint32(info) }
-func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) }
-
-// ELF64 symbol table entries.
-type Sym64 struct {
- Name uint32 /* String table index of name. */
- Info uint8 /* Type and binding information. */
- Other uint8 /* Reserved (not used). */
- Shndx uint16 /* Section index of symbol. */
- Value uint64 /* Symbol value. */
- Size uint64 /* Size of associated object. */
-}
-
-const Sym64Size = 24
-
-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 "elf." + n.s
- }
- return n.s
- }
- }
-
- // second pass - look for smaller to add with.
- // assume sorted already
- for j := len(names) - 1; j >= 0; j-- {
- n := names[j]
- if n.i < i {
- s := n.s
- if goSyntax {
- s = "elf." + s
- }
- return s + "+" + strconv.FormatUint(uint64(i-n.i), 10)
- }
- }
-
- 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 += "elf."
- }
- 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
-}
diff --git a/elf/elf_test.go b/elf/elf_test.go
deleted file mode 100644
index e3c51bb..0000000
--- a/elf/elf_test.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package elf
-
-import (
- "fmt"
- "testing"
-)
-
-type nameTest struct {
- val interface{}
- str string
-}
-
-var nameTests = []nameTest{
- {ELFOSABI_LINUX, "ELFOSABI_LINUX"},
- {ET_EXEC, "ET_EXEC"},
- {EM_860, "EM_860"},
- {SHN_LOPROC, "SHN_LOPROC"},
- {SHT_PROGBITS, "SHT_PROGBITS"},
- {SHF_MERGE + SHF_TLS, "SHF_MERGE+SHF_TLS"},
- {PT_LOAD, "PT_LOAD"},
- {PF_W + PF_R + 0x50, "PF_W+PF_R+0x50"},
- {DT_SYMBOLIC, "DT_SYMBOLIC"},
- {DF_BIND_NOW, "DF_BIND_NOW"},
- {NT_FPREGSET, "NT_FPREGSET"},
- {STB_GLOBAL, "STB_GLOBAL"},
- {STT_COMMON, "STT_COMMON"},
- {STV_HIDDEN, "STV_HIDDEN"},
- {R_X86_64_PC32, "R_X86_64_PC32"},
- {R_ALPHA_OP_PUSH, "R_ALPHA_OP_PUSH"},
- {R_ARM_THM_ABS5, "R_ARM_THM_ABS5"},
- {R_386_GOT32, "R_386_GOT32"},
- {R_PPC_GOT16_HI, "R_PPC_GOT16_HI"},
- {R_SPARC_GOT22, "R_SPARC_GOT22"},
- {ET_LOOS + 5, "ET_LOOS+5"},
- {ProgFlag(0x50), "0x50"},
-}
-
-func TestNames(t *testing.T) {
- for i, tt := range nameTests {
- s := fmt.Sprint(tt.val)
- if s != tt.str {
- t.Errorf("#%d: Sprint(%d) = %q, want %q", i, tt.val, s, tt.str)
- }
- }
-}
diff --git a/elf/file.go b/elf/file.go
deleted file mode 100644
index 6946550..0000000
--- a/elf/file.go
+++ /dev/null
@@ -1,829 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package elf implements access to ELF object files.
-package elf
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
- "os"
-
- "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
-}
diff --git a/elf/file_test.go b/elf/file_test.go
deleted file mode 100644
index 596dc4e..0000000
--- a/elf/file_test.go
+++ /dev/null
@@ -1,334 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package elf
-
-import (
- "bytes"
- "compress/gzip"
- "encoding/binary"
- "io"
- "net"
- "os"
- "path"
- "reflect"
- "runtime"
- "testing"
-
- "golang.org/x/debug/dwarf"
-)
-
-type fileTest struct {
- file string
- hdr FileHeader
- sections []SectionHeader
- progs []ProgHeader
- needed []string
-}
-
-var fileTests = []fileTest{
- {
- "testdata/gcc-386-freebsd-exec",
- FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
- []SectionHeader{
- {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
- {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
- {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
- {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
- {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
- {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
- {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
- {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
- {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
- {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
- {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
- {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
- {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
- {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
- {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
- {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
- {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
- {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
- {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
- {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
- {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
- {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
- {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
- {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
- {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
- {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
- {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
- {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
- {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
- {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
- },
- []ProgHeader{
- {PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
- {PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
- {PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
- {PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
- {PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
- },
- []string{"libc.so.6"},
- },
- {
- "testdata/gcc-amd64-linux-exec",
- FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
- []SectionHeader{
- {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
- {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
- {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
- {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
- {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
- {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
- {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
- {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
- {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
- {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
- {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
- {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
- {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
- {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
- {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
- {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
- {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
- {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
- {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
- {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
- {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
- {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
- {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
- {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
- {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
- {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
- {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
- {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
- {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
- {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
- {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
- {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
- {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
- {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
- {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
- {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
- {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
- },
- []ProgHeader{
- {PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
- {PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
- {PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
- {PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
- {PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
- {PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
- {PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
- {PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
- },
- []string{"libc.so.6"},
- },
- {
- "testdata/hello-world-core.gz",
- FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_CORE, EM_X86_64, 0x0},
- []SectionHeader{},
- []ProgHeader{
- {Type: PT_NOTE, Flags: 0x0, Off: 0x3f8, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x8ac, Memsz: 0x0, Align: 0x0},
- {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x1000, Vaddr: 0x400000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_R, Off: 0x1000, Vaddr: 0x401000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x2000, Vaddr: 0x402000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3000, Vaddr: 0x7f54078b8000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1b5000, Align: 0x1000},
- {Type: PT_LOAD, Flags: 0x0, Off: 0x3000, Vaddr: 0x7f5407a6d000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1ff000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_R, Off: 0x3000, Vaddr: 0x7f5407c6c000, Paddr: 0x0, Filesz: 0x4000, Memsz: 0x4000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x7000, Vaddr: 0x7f5407c70000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x9000, Vaddr: 0x7f5407c72000, Paddr: 0x0, Filesz: 0x5000, Memsz: 0x5000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0xe000, Vaddr: 0x7f5407c77000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x22000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0xe000, Vaddr: 0x7f5407e81000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x11000, Vaddr: 0x7f5407e96000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_R, Off: 0x14000, Vaddr: 0x7f5407e99000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x15000, Vaddr: 0x7f5407e9a000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x17000, Vaddr: 0x7fff79972000, Paddr: 0x0, Filesz: 0x23000, Memsz: 0x23000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3a000, Vaddr: 0x7fff799f8000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
- {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3b000, Vaddr: 0xffffffffff600000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
- },
- nil,
- },
-}
-
-func TestOpen(t *testing.T) {
- for i := range fileTests {
- tt := &fileTests[i]
-
- var f *File
- var err error
- if path.Ext(tt.file) == ".gz" {
- var r io.ReaderAt
- if r, err = decompress(tt.file); err == nil {
- f, err = NewFile(r)
- }
- } else {
- f, err = Open(tt.file)
- }
- if err != nil {
- t.Errorf("cannot open file %s: %v", tt.file, err)
- continue
- }
- defer f.Close()
- if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
- t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
- continue
- }
- for i, s := range f.Sections {
- if i >= len(tt.sections) {
- break
- }
- sh := &tt.sections[i]
- if !reflect.DeepEqual(&s.SectionHeader, sh) {
- t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
- }
- }
- for i, p := range f.Progs {
- if i >= len(tt.progs) {
- break
- }
- ph := &tt.progs[i]
- if !reflect.DeepEqual(&p.ProgHeader, ph) {
- t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph)
- }
- }
- tn := len(tt.sections)
- fn := len(f.Sections)
- if tn != fn {
- t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
- }
- tn = len(tt.progs)
- fn = len(f.Progs)
- if tn != fn {
- t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
- }
- tl := tt.needed
- fl, err := f.ImportedLibraries()
- if err != nil {
- t.Error(err)
- }
- if !reflect.DeepEqual(tl, fl) {
- t.Errorf("open %s: DT_NEEDED = %v, want %v", tt.file, tl, fl)
- }
- }
-}
-
-// elf.NewFile requires io.ReaderAt, which compress/gzip cannot
-// provide. Decompress the file to a bytes.Reader.
-func decompress(gz string) (io.ReaderAt, error) {
- in, err := os.Open(gz)
- if err != nil {
- return nil, err
- }
- defer in.Close()
- r, err := gzip.NewReader(in)
- if err != nil {
- return nil, err
- }
- var out bytes.Buffer
- _, err = io.Copy(&out, r)
- return bytes.NewReader(out.Bytes()), err
-}
-
-type relocationTestEntry struct {
- entryNumber int
- entry *dwarf.Entry
-}
-
-type relocationTest struct {
- file string
- entries []relocationTestEntry
-}
-
-var relocationTests = []relocationTest{
- {
- "testdata/go-relocation-test-gcc441-x86-64.obj",
- []relocationTestEntry{
- {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
- },
- },
- {
- "testdata/go-relocation-test-gcc441-x86.obj",
- []relocationTestEntry{
- {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
- },
- },
- {
- "testdata/go-relocation-test-gcc424-x86-64.obj",
- []relocationTestEntry{
- {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
- },
- },
- {
- "testdata/gcc-amd64-openbsd-debug-with-rela.obj",
- []relocationTestEntry{
- {203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}},
- {204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(237)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}}}},
- },
- },
-}
-
-func TestDWARFRelocations(t *testing.T) {
- for i, test := range relocationTests {
- f, err := Open(test.file)
- if err != nil {
- t.Error(err)
- continue
- }
- dwarf, err := f.DWARF()
- if err != nil {
- t.Error(err)
- continue
- }
- for _, testEntry := range test.entries {
- reader := dwarf.Reader()
- for j := 0; j < testEntry.entryNumber; j++ {
- entry, err := reader.Next()
- if entry == nil || err != nil {
- t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
- continue
- }
- }
- entry, err := reader.Next()
- if err != nil {
- t.Error(err)
- continue
- }
- if !reflect.DeepEqual(testEntry.entry, entry) {
- t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry)
- continue
- }
- }
- }
-}
-
-func TestNoSectionOverlaps(t *testing.T) {
- // Ensure 6l outputs sections without overlaps.
- if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
- return // not ELF
- }
- _ = net.ResolveIPAddr // force dynamic linkage
- f, err := Open(os.Args[0])
- if err != nil {
- t.Error(err)
- return
- }
- for i, si := range f.Sections {
- sih := si.SectionHeader
- if sih.Type == SHT_NOBITS {
- continue
- }
- for j, sj := range f.Sections {
- sjh := sj.SectionHeader
- if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
- continue
- }
- if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
- t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
- sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
- }
- }
- }
-}
diff --git a/elf/testdata/gcc-386-freebsd-exec b/elf/testdata/gcc-386-freebsd-exec
deleted file mode 100755
index 7af9c58..0000000
--- a/elf/testdata/gcc-386-freebsd-exec
+++ /dev/null
Binary files differ
diff --git a/elf/testdata/gcc-amd64-linux-exec b/elf/testdata/gcc-amd64-linux-exec
deleted file mode 100755
index c6cb1de..0000000
--- a/elf/testdata/gcc-amd64-linux-exec
+++ /dev/null
Binary files differ
diff --git a/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj b/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj
deleted file mode 100644
index f62b1ea..0000000
--- a/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj
+++ /dev/null
Binary files differ
diff --git a/elf/testdata/go-relocation-test-gcc424-x86-64.obj b/elf/testdata/go-relocation-test-gcc424-x86-64.obj
deleted file mode 100644
index a7c6d6e..0000000
--- a/elf/testdata/go-relocation-test-gcc424-x86-64.obj
+++ /dev/null
Binary files differ
diff --git a/elf/testdata/go-relocation-test-gcc441-x86-64.obj b/elf/testdata/go-relocation-test-gcc441-x86-64.obj
deleted file mode 100644
index 2d37ab6..0000000
--- a/elf/testdata/go-relocation-test-gcc441-x86-64.obj
+++ /dev/null
Binary files differ
diff --git a/elf/testdata/go-relocation-test-gcc441-x86.obj b/elf/testdata/go-relocation-test-gcc441-x86.obj
deleted file mode 100644
index 0d59fe3..0000000
--- a/elf/testdata/go-relocation-test-gcc441-x86.obj
+++ /dev/null
Binary files differ
diff --git a/elf/testdata/hello-world-core.gz b/elf/testdata/hello-world-core.gz
deleted file mode 100644
index 806af6e..0000000
--- a/elf/testdata/hello-world-core.gz
+++ /dev/null
Binary files differ
diff --git a/elf/testdata/hello.c b/elf/testdata/hello.c
deleted file mode 100644
index 34d9ee7..0000000
--- a/elf/testdata/hello.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <stdio.h>
-
-void
-main(int argc, char *argv[])
-{
- printf("hello, world\n");
-}
diff --git a/gosym/pclinetest.asm b/gosym/pclinetest.asm
deleted file mode 100644
index b9ee9c0..0000000
--- a/gosym/pclinetest.asm
+++ /dev/null
@@ -1,58 +0,0 @@
-TEXT linefrompc(SB),4,$0 // Each byte stores its line delta
-BYTE $2;
-BYTE $1;
-BYTE $1; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1;
-BYTE $1;
-BYTE $1; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-#include "pclinetest.h"
-BYTE $2;
-#include "pclinetest.h"
-BYTE $2;
-BYTE $255;
-
-TEXT pcfromline(SB),4,$0 // Each record stores its line delta, then n, then n more bytes
-BYTE $32; BYTE $0;
-BYTE $1; BYTE $1; BYTE $0;
-BYTE $1; BYTE $0;
-
-BYTE $2; BYTE $4; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
-
-
-#include "pclinetest.h"
-BYTE $4; BYTE $0;
-
-
-BYTE $3; BYTE $3; BYTE $0; BYTE $0; BYTE $0;
-#include "pclinetest.h"
-
-
-BYTE $4; BYTE $3; BYTE $0; BYTE $0; BYTE $0;
-BYTE $255;
-
-// Keep the linker happy
-TEXT main·main(SB),4,$0
- RET
-
-TEXT main·init(SB),4,$0
- // Prevent GC of our test symbols
- CALL linefrompc(SB)
- CALL pcfromline(SB)
- RET
diff --git a/gosym/pclinetest.h b/gosym/pclinetest.h
deleted file mode 100644
index 156c0b8..0000000
--- a/gosym/pclinetest.h
+++ /dev/null
@@ -1,9 +0,0 @@
-// +build ignore
-
-// Empty include file to generate z symbols
-
-
-
-
-
-// EOF
diff --git a/gosym/pclntab.go b/gosym/pclntab.go
deleted file mode 100644
index a9c2fc7..0000000
--- a/gosym/pclntab.go
+++ /dev/null
@@ -1,462 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * Line tables
- */
-
-package gosym
-
-import (
- "encoding/binary"
- "sync"
-)
-
-// A LineTable is a data structure mapping program counters to line numbers.
-//
-// In Go 1.1 and earlier, each function (represented by a Func) had its own LineTable,
-// and the line number corresponded to a numbering of all source lines in the
-// program, across all files. That absolute line number would then have to be
-// converted separately to a file name and line number within the file.
-//
-// In Go 1.2, the format of the data changed so that there is a single LineTable
-// for the entire program, shared by all Funcs, and there are no absolute line
-// numbers, just line numbers within specific files.
-//
-// For the most part, LineTable's methods should be treated as an internal
-// detail of the package; callers should use the methods on Table instead.
-type LineTable struct {
- Data []byte
- PC uint64
- Line int
-
- // Go 1.2 state
- mu sync.Mutex
- go12 int // is this in Go 1.2 format? -1 no, 0 unknown, 1 yes
- binary binary.ByteOrder
- quantum uint32
- ptrsize uint32
- functab []byte
- nfunctab uint32
- filetab []byte
- nfiletab uint32
- fileMap map[string]uint32
-}
-
-// NOTE(rsc): This is wrong for GOARCH=arm, which uses a quantum of 4,
-// but we have no idea whether we're using arm or not. This only
-// matters in the old (pre-Go 1.2) symbol table format, so it's not worth
-// fixing.
-const oldQuantum = 1
-
-func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
- // The PC/line table can be thought of as a sequence of
- // <pc update>* <line update>
- // batches. Each update batch results in a (pc, line) pair,
- // where line applies to every PC from pc up to but not
- // including the pc of the next pair.
- //
- // Here we process each update individually, which simplifies
- // the code, but makes the corner cases more confusing.
- b, pc, line = t.Data, t.PC, t.Line
- for pc <= targetPC && line != targetLine && len(b) > 0 {
- code := b[0]
- b = b[1:]
- switch {
- case code == 0:
- if len(b) < 4 {
- b = b[0:0]
- break
- }
- val := binary.BigEndian.Uint32(b)
- b = b[4:]
- line += int(val)
- case code <= 64:
- line += int(code)
- case code <= 128:
- line -= int(code - 64)
- default:
- pc += oldQuantum * uint64(code-128)
- continue
- }
- pc += oldQuantum
- }
- return b, pc, line
-}
-
-func (t *LineTable) slice(pc uint64) *LineTable {
- data, pc, line := t.parse(pc, -1)
- return &LineTable{Data: data, PC: pc, Line: line}
-}
-
-// PCToLine returns the line number for the given program counter.
-// Callers should use Table's PCToLine method instead.
-func (t *LineTable) PCToLine(pc uint64) int {
- if t.isGo12() {
- return t.go12PCToLine(pc)
- }
- _, _, line := t.parse(pc, -1)
- return line
-}
-
-// LineToPC returns the program counter for the given line number,
-// considering only program counters before maxpc.
-// Callers should use Table's LineToPC method instead.
-func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 {
- if t.isGo12() {
- return 0
- }
- _, pc, line1 := t.parse(maxpc, line)
- if line1 != line {
- return 0
- }
- // Subtract quantum from PC to account for post-line increment
- return pc - oldQuantum
-}
-
-// NewLineTable returns a new PC/line table
-// corresponding to the encoded data.
-// Text must be the start address of the
-// corresponding text segment.
-func NewLineTable(data []byte, text uint64) *LineTable {
- return &LineTable{Data: data, PC: text, Line: 0}
-}
-
-// Go 1.2 symbol table format.
-// See golang.org/s/go12symtab.
-//
-// A general note about the methods here: rather than try to avoid
-// index out of bounds errors, we trust Go to detect them, and then
-// we recover from the panics and treat them as indicative of a malformed
-// or incomplete table.
-//
-// The methods called by symtab.go, which begin with "go12" prefixes,
-// are expected to have that recovery logic.
-
-// isGo12 reports whether this is a Go 1.2 (or later) symbol table.
-func (t *LineTable) isGo12() bool {
- t.go12Init()
- return t.go12 == 1
-}
-
-const go12magic = 0xfffffffb
-
-// uintptr returns the pointer-sized value encoded at b.
-// The pointer size is dictated by the table being read.
-func (t *LineTable) uintptr(b []byte) uint64 {
- if t.ptrsize == 4 {
- return uint64(t.binary.Uint32(b))
- }
- return t.binary.Uint64(b)
-}
-
-// go12init initializes the Go 1.2 metadata if t is a Go 1.2 symbol table.
-func (t *LineTable) go12Init() {
- t.mu.Lock()
- defer t.mu.Unlock()
- if t.go12 != 0 {
- return
- }
-
- defer func() {
- // If we panic parsing, assume it's not a Go 1.2 symbol table.
- recover()
- }()
-
- // Check header: 4-byte magic, two zeros, pc quantum, pointer size.
- t.go12 = -1 // not Go 1.2 until proven otherwise
- if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 ||
- (t.Data[6] != 1 && t.Data[6] != 4) || // pc quantum
- (t.Data[7] != 4 && t.Data[7] != 8) { // pointer size
- return
- }
-
- switch uint32(go12magic) {
- case binary.LittleEndian.Uint32(t.Data):
- t.binary = binary.LittleEndian
- case binary.BigEndian.Uint32(t.Data):
- t.binary = binary.BigEndian
- default:
- return
- }
-
- t.quantum = uint32(t.Data[6])
- t.ptrsize = uint32(t.Data[7])
-
- t.nfunctab = uint32(t.uintptr(t.Data[8:]))
- t.functab = t.Data[8+t.ptrsize:]
- functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
- fileoff := t.binary.Uint32(t.functab[functabsize:])
- t.functab = t.functab[:functabsize]
- t.filetab = t.Data[fileoff:]
- t.nfiletab = t.binary.Uint32(t.filetab)
- t.filetab = t.filetab[:t.nfiletab*4]
-
- t.go12 = 1 // so far so good
-}
-
-// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table.
-func (t *LineTable) go12Funcs() []Func {
- // Assume it is malformed and return nil on error.
- defer func() {
- recover()
- }()
-
- n := len(t.functab) / int(t.ptrsize) / 2
- funcs := make([]Func, n)
- for i := range funcs {
- f := &funcs[i]
- f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
- f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
- info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
- f.LineTable = t
- f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
- f.Sym = &Sym{
- Value: f.Entry,
- Type: 'T',
- Name: t.string(t.binary.Uint32(info[t.ptrsize:])),
- GoType: 0,
- Func: f,
- }
- }
- return funcs
-}
-
-// findFunc returns the func corresponding to the given program counter.
-func (t *LineTable) findFunc(pc uint64) []byte {
- if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
- return nil
- }
-
- // The function table is a list of 2*nfunctab+1 uintptrs,
- // alternating program counters and offsets to func structures.
- f := t.functab
- nf := t.nfunctab
- for nf > 0 {
- m := nf / 2
- fm := f[2*t.ptrsize*m:]
- if t.uintptr(fm) <= pc && pc < t.uintptr(fm[2*t.ptrsize:]) {
- return t.Data[t.uintptr(fm[t.ptrsize:]):]
- } else if pc < t.uintptr(fm) {
- nf = m
- } else {
- f = f[(m+1)*2*t.ptrsize:]
- nf -= m + 1
- }
- }
- return nil
-}
-
-// readvarint reads, removes, and returns a varint from *pp.
-func (t *LineTable) readvarint(pp *[]byte) uint32 {
- var v, shift uint32
- p := *pp
- for shift = 0; ; shift += 7 {
- b := p[0]
- p = p[1:]
- v |= (uint32(b) & 0x7F) << shift
- if b&0x80 == 0 {
- break
- }
- }
- *pp = p
- return v
-}
-
-// string returns a Go string found at off.
-func (t *LineTable) string(off uint32) string {
- for i := off; ; i++ {
- if t.Data[i] == 0 {
- return string(t.Data[off:i])
- }
- }
-}
-
-// step advances to the next pc, value pair in the encoded table.
-func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
- uvdelta := t.readvarint(p)
- if uvdelta == 0 && !first {
- return false
- }
- if uvdelta&1 != 0 {
- uvdelta = ^(uvdelta >> 1)
- } else {
- uvdelta >>= 1
- }
- vdelta := int32(uvdelta)
- pcdelta := t.readvarint(p) * t.quantum
- *pc += uint64(pcdelta)
- *val += vdelta
- return true
-}
-
-// pcvalue reports the value associated with the target pc.
-// off is the offset to the beginning of the pc-value table,
-// and entry is the start PC for the corresponding function.
-func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
- if off == 0 {
- return -1
- }
- p := t.Data[off:]
-
- val := int32(-1)
- pc := entry
- for t.step(&p, &pc, &val, pc == entry) {
- if targetpc < pc {
- return val
- }
- }
- return -1
-}
-
-// findFileLine scans one function in the binary looking for a
-// program counter in the given file on the given line.
-// It does so by running the pc-value tables mapping program counter
-// to file number. Since most functions come from a single file, these
-// are usually short and quick to scan. If a file match is found, then the
-// code goes to the expense of looking for a simultaneous line number match.
-func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32) uint64 {
- if filetab == 0 || linetab == 0 {
- return 0
- }
-
- fp := t.Data[filetab:]
- fl := t.Data[linetab:]
- fileVal := int32(-1)
- filePC := entry
- lineVal := int32(-1)
- linePC := entry
- fileStartPC := filePC
- for t.step(&fp, &filePC, &fileVal, filePC == entry) {
- if fileVal == filenum && fileStartPC < filePC {
- // fileVal is in effect starting at fileStartPC up to
- // but not including filePC, and it's the file we want.
- // Run the PC table looking for a matching line number
- // or until we reach filePC.
- lineStartPC := linePC
- for linePC < filePC && t.step(&fl, &linePC, &lineVal, linePC == entry) {
- // lineVal is in effect until linePC, and lineStartPC < filePC.
- if lineVal == line {
- if fileStartPC <= lineStartPC {
- return lineStartPC
- }
- if fileStartPC < linePC {
- return fileStartPC
- }
- }
- lineStartPC = linePC
- }
- }
- fileStartPC = filePC
- }
- return 0
-}
-
-// go12PCToLine maps program counter to line number for the Go 1.2 pcln table.
-func (t *LineTable) go12PCToLine(pc uint64) (line int) {
- return t.go12PCToVal(pc, t.ptrsize+5*4)
-}
-
-// go12PCToSPAdj maps program counter to Stack Pointer adjustment for the Go 1.2 pcln table.
-func (t *LineTable) go12PCToSPAdj(pc uint64) (spadj int) {
- return t.go12PCToVal(pc, t.ptrsize+3*4)
-}
-
-func (t *LineTable) go12PCToVal(pc uint64, fOffset uint32) (val int) {
- defer func() {
- if recover() != nil {
- val = -1
- }
- }()
-
- f := t.findFunc(pc)
- if f == nil {
- return -1
- }
- entry := t.uintptr(f)
- linetab := t.binary.Uint32(f[fOffset:])
- return int(t.pcvalue(linetab, entry, pc))
-}
-
-// go12PCToFile maps program counter to file name for the Go 1.2 pcln table.
-func (t *LineTable) go12PCToFile(pc uint64) (file string) {
- defer func() {
- if recover() != nil {
- file = ""
- }
- }()
-
- f := t.findFunc(pc)
- if f == nil {
- return ""
- }
- entry := t.uintptr(f)
- filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
- fno := t.pcvalue(filetab, entry, pc)
- if fno <= 0 {
- return ""
- }
- return t.string(t.binary.Uint32(t.filetab[4*fno:]))
-}
-
-// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2 pcln table.
-func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
- defer func() {
- if recover() != nil {
- pc = 0
- }
- }()
-
- t.initFileMap()
- filenum := t.fileMap[file]
- if filenum == 0 {
- return 0
- }
-
- // Scan all functions.
- // If this turns out to be a bottleneck, we could build a map[int32][]int32
- // mapping file number to a list of functions with code from that file.
- for i := uint32(0); i < t.nfunctab; i++ {
- f := t.Data[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
- entry := t.uintptr(f)
- filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
- linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
- pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line))
- if pc != 0 {
- return pc
- }
- }
- return 0
-}
-
-// initFileMap initializes the map from file name to file number.
-func (t *LineTable) initFileMap() {
- t.mu.Lock()
- defer t.mu.Unlock()
-
- if t.fileMap != nil {
- return
- }
- m := make(map[string]uint32)
-
- for i := uint32(1); i < t.nfiletab; i++ {
- s := t.string(t.binary.Uint32(t.filetab[4*i:]))
- m[s] = i
- }
- t.fileMap = m
-}
-
-// go12MapFiles adds to m a key for every file in the Go 1.2 LineTable.
-// Every key maps to obj. That's not a very interesting map, but it provides
-// a way for callers to obtain the list of files in the program.
-func (t *LineTable) go12MapFiles(m map[string]*Obj, obj *Obj) {
- defer func() {
- recover()
- }()
-
- t.initFileMap()
- for file := range t.fileMap {
- m[file] = obj
- }
-}
diff --git a/gosym/pclntab_test.go b/gosym/pclntab_test.go
deleted file mode 100644
index 35502e8..0000000
--- a/gosym/pclntab_test.go
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gosym
-
-import (
- "debug/elf"
- "fmt"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
- "testing"
-)
-
-var (
- pclineTempDir string
- pclinetestBinary string
-)
-
-func dotest(self bool) bool {
- // For now, only works on amd64 platforms.
- if runtime.GOARCH != "amd64" {
- return false
- }
- // Self test reads test binary; only works on Linux.
- if self && runtime.GOOS != "linux" {
- return false
- }
- // Command below expects "sh", so Unix.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return false
- }
- if pclinetestBinary != "" {
- return true
- }
- var err error
- pclineTempDir, err = ioutil.TempDir("", "pclinetest")
- if err != nil {
- panic(err)
- }
- if strings.Contains(pclineTempDir, " ") {
- panic("unexpected space in tempdir")
- }
- // This command builds pclinetest from pclinetest.asm;
- // the resulting binary looks like it was built from pclinetest.s,
- // but we have renamed it to keep it away from the go tool.
- pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
- command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6",
- pclinetestBinary, pclinetestBinary, pclinetestBinary)
- cmd := exec.Command("sh", "-c", command)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Run(); err != nil {
- panic(err)
- }
- return true
-}
-
-func endtest() {
- if pclineTempDir != "" {
- os.RemoveAll(pclineTempDir)
- pclineTempDir = ""
- pclinetestBinary = ""
- }
-}
-
-func getTable(t *testing.T) *Table {
- f, tab := crack(os.Args[0], t)
- f.Close()
- return tab
-}
-
-func crack(file string, t *testing.T) (*elf.File, *Table) {
- // Open self
- f, err := elf.Open(file)
- if err != nil {
- t.Fatal(err)
- }
- return parse(file, f, t)
-}
-
-func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
- symdat, err := f.Section(".gosymtab").Data()
- if err != nil {
- f.Close()
- t.Fatalf("reading %s gosymtab: %v", file, err)
- }
- pclndat, err := f.Section(".gopclntab").Data()
- if err != nil {
- f.Close()
- t.Fatalf("reading %s gopclntab: %v", file, err)
- }
-
- pcln := NewLineTable(pclndat, f.Section(".text").Addr)
- tab, err := NewTable(symdat, pcln)
- if err != nil {
- f.Close()
- t.Fatalf("parsing %s gosymtab: %v", file, err)
- }
-
- return f, tab
-}
-
-var goarch = os.Getenv("O")
-
-func TestLineFromAline(t *testing.T) {
- if !dotest(true) {
- return
- }
- defer endtest()
-
- tab := getTable(t)
- if tab.go12line != nil {
- // aline's don't exist in the Go 1.2 table.
- t.Skip("not relevant to Go 1.2 symbol table")
- }
-
- // Find the sym package
- pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
- if pkg == nil {
- t.Fatalf("nil pkg")
- }
-
- // Walk every absolute line and ensure that we hit every
- // source line monotonically
- lastline := make(map[string]int)
- final := -1
- for i := 0; i < 10000; i++ {
- path, line := pkg.lineFromAline(i)
- // Check for end of object
- if path == "" {
- if final == -1 {
- final = i - 1
- }
- continue
- } else if final != -1 {
- t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
- }
- // It's okay to see files multiple times (e.g., sys.a)
- if line == 1 {
- lastline[path] = 1
- continue
- }
- // Check that the is the next line in path
- ll, ok := lastline[path]
- if !ok {
- t.Errorf("file %s starts on line %d", path, line)
- } else if line != ll+1 {
- t.Fatalf("expected next line of file %s to be %d, got %d", path, ll+1, line)
- }
- lastline[path] = line
- }
- if final == -1 {
- t.Errorf("never reached end of object")
- }
-}
-
-func TestLineAline(t *testing.T) {
- if !dotest(true) {
- return
- }
- defer endtest()
-
- tab := getTable(t)
- if tab.go12line != nil {
- // aline's don't exist in the Go 1.2 table.
- t.Skip("not relevant to Go 1.2 symbol table")
- }
-
- for _, o := range tab.Files {
- // A source file can appear multiple times in a
- // object. alineFromLine will always return alines in
- // the first file, so track which lines we've seen.
- found := make(map[string]int)
- for i := 0; i < 1000; i++ {
- path, line := o.lineFromAline(i)
- if path == "" {
- break
- }
-
- // cgo files are full of 'Z' symbols, which we don't handle
- if len(path) > 4 && path[len(path)-4:] == ".cgo" {
- continue
- }
-
- if minline, ok := found[path]; path != "" && ok {
- if minline >= line {
- // We've already covered this file
- continue
- }
- }
- found[path] = line
-
- a, err := o.alineFromLine(path, line)
- if err != nil {
- t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
- } else if a != i {
- t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
- }
- }
- }
-}
-
-func TestPCLine(t *testing.T) {
- if !dotest(false) {
- return
- }
- defer endtest()
-
- f, tab := crack(pclinetestBinary, t)
- text := f.Section(".text")
- textdat, err := text.Data()
- if err != nil {
- t.Fatalf("reading .text: %v", err)
- }
-
- // Test PCToLine
- sym := tab.LookupFunc("linefrompc")
- wantLine := 0
- for pc := sym.Entry; pc < sym.End; pc++ {
- off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
- if textdat[off] == 255 {
- break
- }
- wantLine += int(textdat[off])
- t.Logf("off is %d %#x (max %d)", off, textdat[off], sym.End-pc)
- file, line, fn := tab.PCToLine(pc)
- if fn == nil {
- t.Errorf("failed to get line of PC %#x", pc)
- } else if !strings.HasSuffix(file, "pclinetest.asm") || line != wantLine || fn != sym {
- t.Errorf("PCToLine(%#x) = %s:%d (%s), want %s:%d (%s)", pc, file, line, fn.Name, "pclinetest.asm", wantLine, sym.Name)
- }
- }
-
- // Test LineToPC
- sym = tab.LookupFunc("pcfromline")
- lookupline := -1
- wantLine = 0
- off := uint64(0) // TODO(rsc): should not need off; bug in 8g
- for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
- file, line, fn := tab.PCToLine(pc)
- off = pc - text.Addr
- if textdat[off] == 255 {
- break
- }
- wantLine += int(textdat[off])
- if line != wantLine {
- t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
- off = pc + 1 - text.Addr
- continue
- }
- if lookupline == -1 {
- lookupline = line
- }
- for ; lookupline <= line; lookupline++ {
- pc2, fn2, err := tab.LineToPC(file, lookupline)
- if lookupline != line {
- // Should be nothing on this line
- if err == nil {
- t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
- }
- } else if err != nil {
- t.Errorf("failed to get PC of line %d: %s", lookupline, err)
- } else if pc != pc2 {
- t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
- }
- }
- off = pc + 1 - text.Addr
- }
-}
diff --git a/gosym/symtab.go b/gosym/symtab.go
deleted file mode 100644
index 9121c37..0000000
--- a/gosym/symtab.go
+++ /dev/null
@@ -1,721 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package gosym implements access to the Go symbol
-// and line number tables embedded in Go binaries generated
-// by the gc compilers.
-package gosym // import "golang.org/x/debug/gosym"
-
-// The table format is a variant of the format used in Plan 9's a.out
-// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out.
-// The best reference for the differences between the Plan 9 format
-// and the Go format is the runtime source, specifically ../../runtime/symtab.c.
-
-import (
- "bytes"
- "encoding/binary"
- "fmt"
- "strconv"
- "strings"
-)
-
-/*
- * Symbols
- */
-
-// A Sym represents a single symbol table entry.
-type Sym struct {
- Value uint64
- Type byte
- Name string
- GoType uint64
- // If this symbol if a function symbol, the corresponding Func
- Func *Func
-}
-
-// Static reports whether this symbol is static (not visible outside its file).
-func (s *Sym) Static() bool { return s.Type >= 'a' }
-
-// PackageName returns the package part of the symbol name,
-// or the empty string if there is none.
-func (s *Sym) PackageName() string {
- if i := strings.Index(s.Name, "."); i != -1 {
- return s.Name[0:i]
- }
- return ""
-}
-
-// ReceiverName returns the receiver type name of this symbol,
-// or the empty string if there is none.
-func (s *Sym) ReceiverName() string {
- l := strings.Index(s.Name, ".")
- r := strings.LastIndex(s.Name, ".")
- if l == -1 || r == -1 || l == r {
- return ""
- }
- return s.Name[l+1 : r]
-}
-
-// BaseName returns the symbol name without the package or receiver name.
-func (s *Sym) BaseName() string {
- if i := strings.LastIndex(s.Name, "."); i != -1 {
- return s.Name[i+1:]
- }
- return s.Name
-}
-
-// A Func collects information about a single function.
-type Func struct {
- Entry uint64
- *Sym
- End uint64
- Params []*Sym
- Locals []*Sym
- FrameSize int
- LineTable *LineTable
- Obj *Obj
-}
-
-// An Obj represents a collection of functions in a symbol table.
-//
-// The exact method of division of a binary into separate Objs is an internal detail
-// of the symbol table format.
-//
-// In early versions of Go each source file became a different Obj.
-//
-// In Go 1 and Go 1.1, each package produced one Obj for all Go sources
-// and one Obj per C source file.
-//
-// In Go 1.2, there is a single Obj for the entire program.
-type Obj struct {
- // Funcs is a list of functions in the Obj.
- Funcs []Func
-
- // In Go 1.1 and earlier, Paths is a list of symbols corresponding
- // to the source file names that produced the Obj.
- // In Go 1.2, Paths is nil.
- // Use the keys of Table.Files to obtain a list of source files.
- Paths []Sym // meta
-}
-
-/*
- * Symbol tables
- */
-
-// Table represents a Go symbol table. It stores all of the
-// symbols decoded from the program and provides methods to translate
-// between symbols, names, and addresses.
-type Table struct {
- Syms []Sym
- Funcs []Func
- Files map[string]*Obj // nil for Go 1.2 and later binaries
- Objs []Obj // nil for Go 1.2 and later binaries
-
- go12line *LineTable // Go 1.2 line number table
-}
-
-type sym struct {
- value uint64
- gotype uint64
- typ byte
- name []byte
-}
-
-var (
- littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}
- bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00}
- oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
-)
-
-func walksymtab(data []byte, fn func(sym) error) error {
- if len(data) == 0 { // missing symtab is okay
- return nil
- }
- var order binary.ByteOrder = binary.BigEndian
- newTable := false
- switch {
- case bytes.HasPrefix(data, oldLittleEndianSymtab):
- // Same as Go 1.0, but little endian.
- // Format was used during interim development between Go 1.0 and Go 1.1.
- // Should not be widespread, but easy to support.
- data = data[6:]
- order = binary.LittleEndian
- case bytes.HasPrefix(data, bigEndianSymtab):
- newTable = true
- case bytes.HasPrefix(data, littleEndianSymtab):
- newTable = true
- order = binary.LittleEndian
- }
- var ptrsz int
- if newTable {
- if len(data) < 8 {
- return &DecodingError{len(data), "unexpected EOF", nil}
- }
- ptrsz = int(data[7])
- if ptrsz != 4 && ptrsz != 8 {
- return &DecodingError{7, "invalid pointer size", ptrsz}
- }
- data = data[8:]
- }
- var s sym
- p := data
- for len(p) >= 4 {
- var typ byte
- if newTable {
- // Symbol type, value, Go type.
- typ = p[0] & 0x3F
- wideValue := p[0]&0x40 != 0
- goType := p[0]&0x80 != 0
- if typ < 26 {
- typ += 'A'
- } else {
- typ += 'a' - 26
- }
- s.typ = typ
- p = p[1:]
- if wideValue {
- if len(p) < ptrsz {
- return &DecodingError{len(data), "unexpected EOF", nil}
- }
- // fixed-width value
- if ptrsz == 8 {
- s.value = order.Uint64(p[0:8])
- p = p[8:]
- } else {
- s.value = uint64(order.Uint32(p[0:4]))
- p = p[4:]
- }
- } else {
- // varint value
- s.value = 0
- shift := uint(0)
- for len(p) > 0 && p[0]&0x80 != 0 {
- s.value |= uint64(p[0]&0x7F) << shift
- shift += 7
- p = p[1:]
- }
- if len(p) == 0 {
- return &DecodingError{len(data), "unexpected EOF", nil}
- }
- s.value |= uint64(p[0]) << shift
- p = p[1:]
- }
- if goType {
- if len(p) < ptrsz {
- return &DecodingError{len(data), "unexpected EOF", nil}
- }
- // fixed-width go type
- if ptrsz == 8 {
- s.gotype = order.Uint64(p[0:8])
- p = p[8:]
- } else {
- s.gotype = uint64(order.Uint32(p[0:4]))
- p = p[4:]
- }
- }
- } else {
- // Value, symbol type.
- s.value = uint64(order.Uint32(p[0:4]))
- if len(p) < 5 {
- return &DecodingError{len(data), "unexpected EOF", nil}
- }
- typ = p[4]
- if typ&0x80 == 0 {
- return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
- }
- typ &^= 0x80
- s.typ = typ
- p = p[5:]
- }
-
- // Name.
- var i int
- var nnul int
- for i = 0; i < len(p); i++ {
- if p[i] == 0 {
- nnul = 1
- break
- }
- }
- switch typ {
- case 'z', 'Z':
- p = p[i+nnul:]
- for i = 0; i+2 <= len(p); i += 2 {
- if p[i] == 0 && p[i+1] == 0 {
- nnul = 2
- break
- }
- }
- }
- if len(p) < i+nnul {
- return &DecodingError{len(data), "unexpected EOF", nil}
- }
- s.name = p[0:i]
- i += nnul
- p = p[i:]
-
- if !newTable {
- if len(p) < 4 {
- return &DecodingError{len(data), "unexpected EOF", nil}
- }
- // Go type.
- s.gotype = uint64(order.Uint32(p[:4]))
- p = p[4:]
- }
- fn(s)
- }
- return nil
-}
-
-// NewTable decodes the Go symbol table in data,
-// returning an in-memory representation.
-func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
- var n int
- err := walksymtab(symtab, func(s sym) error {
- n++
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- var t Table
- if pcln.isGo12() {
- t.go12line = pcln
- }
- fname := make(map[uint16]string)
- t.Syms = make([]Sym, 0, n)
- nf := 0
- nz := 0
- lasttyp := uint8(0)
- err = walksymtab(symtab, func(s sym) error {
- n := len(t.Syms)
- t.Syms = t.Syms[0 : n+1]
- ts := &t.Syms[n]
- ts.Type = s.typ
- ts.Value = uint64(s.value)
- ts.GoType = uint64(s.gotype)
- switch s.typ {
- default:
- // rewrite name to use . instead of · (c2 b7)
- w := 0
- b := s.name
- for i := 0; i < len(b); i++ {
- if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 {
- i++
- b[i] = '.'
- }
- b[w] = b[i]
- w++
- }
- ts.Name = string(s.name[0:w])
- case 'z', 'Z':
- if lasttyp != 'z' && lasttyp != 'Z' {
- nz++
- }
- for i := 0; i < len(s.name); i += 2 {
- eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
- elt, ok := fname[eltIdx]
- if !ok {
- return &DecodingError{-1, "bad filename code", eltIdx}
- }
- if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
- ts.Name += "/"
- }
- ts.Name += elt
- }
- }
- switch s.typ {
- case 'T', 't', 'L', 'l':
- nf++
- case 'f':
- fname[uint16(s.value)] = ts.Name
- }
- lasttyp = s.typ
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- t.Funcs = make([]Func, 0, nf)
- t.Files = make(map[string]*Obj)
-
- var obj *Obj
- if t.go12line != nil {
- // Put all functions into one Obj.
- t.Objs = make([]Obj, 1)
- obj = &t.Objs[0]
- t.go12line.go12MapFiles(t.Files, obj)
- } else {
- t.Objs = make([]Obj, 0, nz)
- }
-
- // Count text symbols and attach frame sizes, parameters, and
- // locals to them. Also, find object file boundaries.
- lastf := 0
- for i := 0; i < len(t.Syms); i++ {
- sym := &t.Syms[i]
- switch sym.Type {
- case 'Z', 'z': // path symbol
- if t.go12line != nil {
- // Go 1.2 binaries have the file information elsewhere. Ignore.
- break
- }
- // Finish the current object
- if obj != nil {
- obj.Funcs = t.Funcs[lastf:]
- }
- lastf = len(t.Funcs)
-
- // Start new object
- n := len(t.Objs)
- t.Objs = t.Objs[0 : n+1]
- obj = &t.Objs[n]
-
- // Count & copy path symbols
- var end int
- for end = i + 1; end < len(t.Syms); end++ {
- if c := t.Syms[end].Type; c != 'Z' && c != 'z' {
- break
- }
- }
- obj.Paths = t.Syms[i:end]
- i = end - 1 // loop will i++
-
- // Record file names
- depth := 0
- for j := range obj.Paths {
- s := &obj.Paths[j]
- if s.Name == "" {
- depth--
- } else {
- if depth == 0 {
- t.Files[s.Name] = obj
- }
- depth++
- }
- }
-
- case 'T', 't', 'L', 'l': // text symbol
- if n := len(t.Funcs); n > 0 {
- t.Funcs[n-1].End = sym.Value
- }
- if sym.Name == "etext" {
- continue
- }
-
- // Count parameter and local (auto) syms
- var np, na int
- var end int
- countloop:
- for end = i + 1; end < len(t.Syms); end++ {
- switch t.Syms[end].Type {
- case 'T', 't', 'L', 'l', 'Z', 'z':
- break countloop
- case 'p':
- np++
- case 'a':
- na++
- }
- }
-
- // Fill in the function symbol
- n := len(t.Funcs)
- t.Funcs = t.Funcs[0 : n+1]
- fn := &t.Funcs[n]
- sym.Func = fn
- fn.Params = make([]*Sym, 0, np)
- fn.Locals = make([]*Sym, 0, na)
- fn.Sym = sym
- fn.Entry = sym.Value
- fn.Obj = obj
- if t.go12line != nil {
- // All functions share the same line table.
- // It knows how to narrow down to a specific
- // function quickly.
- fn.LineTable = t.go12line
- } else if pcln != nil {
- fn.LineTable = pcln.slice(fn.Entry)
- pcln = fn.LineTable
- }
- for j := i; j < end; j++ {
- s := &t.Syms[j]
- switch s.Type {
- case 'm':
- fn.FrameSize = int(s.Value)
- case 'p':
- n := len(fn.Params)
- fn.Params = fn.Params[0 : n+1]
- fn.Params[n] = s
- case 'a':
- n := len(fn.Locals)
- fn.Locals = fn.Locals[0 : n+1]
- fn.Locals[n] = s
- }
- }
- i = end - 1 // loop will i++
- }
- }
-
- if t.go12line != nil && nf == 0 {
- t.Funcs = t.go12line.go12Funcs()
- }
- if obj != nil {
- obj.Funcs = t.Funcs[lastf:]
- }
- return &t, nil
-}
-
-// PCToFunc returns the function containing the program counter pc,
-// or nil if there is no such function.
-func (t *Table) PCToFunc(pc uint64) *Func {
- funcs := t.Funcs
- for len(funcs) > 0 {
- m := len(funcs) / 2
- fn := &funcs[m]
- switch {
- case pc < fn.Entry:
- funcs = funcs[0:m]
- case fn.Entry <= pc && pc < fn.End:
- return fn
- default:
- funcs = funcs[m+1:]
- }
- }
- return nil
-}
-
-// PCToLine looks up line number information for a program counter.
-// If there is no information, it returns fn == nil.
-func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
- if fn = t.PCToFunc(pc); fn == nil {
- return
- }
- if t.go12line != nil {
- file = t.go12line.go12PCToFile(pc)
- line = t.go12line.go12PCToLine(pc)
- } else {
- file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc))
- }
- return
-}
-
-// PCToSPAdj returns the stack pointer adjustment for a program counter.
-func (t *Table) PCToSPAdj(pc uint64) (spadj int) {
- if fn := t.PCToFunc(pc); fn == nil {
- return 0
- }
- if t.go12line != nil {
- return t.go12line.go12PCToSPAdj(pc)
- }
- return 0
-}
-
-// LineToPC looks up the first program counter on the given line in
-// the named file. It returns UnknownPathError or UnknownLineError if
-// there is an error looking up this line.
-func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) {
- obj, ok := t.Files[file]
- if !ok {
- return 0, nil, UnknownFileError(file)
- }
-
- if t.go12line != nil {
- pc := t.go12line.go12LineToPC(file, line)
- if pc == 0 {
- return 0, nil, &UnknownLineError{file, line}
- }
- return pc, t.PCToFunc(pc), nil
- }
-
- abs, err := obj.alineFromLine(file, line)
- if err != nil {
- return
- }
- for i := range obj.Funcs {
- f := &obj.Funcs[i]
- pc := f.LineTable.LineToPC(abs, f.End)
- if pc != 0 {
- return pc, f, nil
- }
- }
- return 0, nil, &UnknownLineError{file, line}
-}
-
-// LookupSym returns the text, data, or bss symbol with the given name,
-// or nil if no such symbol is found.
-func (t *Table) LookupSym(name string) *Sym {
- // TODO(austin) Maybe make a map
- for i := range t.Syms {
- s := &t.Syms[i]
- switch s.Type {
- case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
- if s.Name == name {
- return s
- }
- }
- }
- return nil
-}
-
-// LookupFunc returns the text, data, or bss symbol with the given name,
-// or nil if no such symbol is found.
-func (t *Table) LookupFunc(name string) *Func {
- for i := range t.Funcs {
- f := &t.Funcs[i]
- if f.Sym.Name == name {
- return f
- }
- }
- return nil
-}
-
-// SymByAddr returns the text, data, or bss symbol starting at the given address.
-func (t *Table) SymByAddr(addr uint64) *Sym {
- for i := range t.Syms {
- s := &t.Syms[i]
- switch s.Type {
- case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
- if s.Value == addr {
- return s
- }
- }
- }
- return nil
-}
-
-/*
- * Object files
- */
-
-// This is legacy code for Go 1.1 and earlier, which used the
-// Plan 9 format for pc-line tables. This code was never quite
-// correct. It's probably very close, and it's usually correct, but
-// we never quite found all the corner cases.
-//
-// Go 1.2 and later use a simpler format, documented at golang.org/s/go12symtab.
-
-func (o *Obj) lineFromAline(aline int) (string, int) {
- type stackEnt struct {
- path string
- start int
- offset int
- prev *stackEnt
- }
-
- noPath := &stackEnt{"", 0, 0, nil}
- tos := noPath
-
-pathloop:
- for _, s := range o.Paths {
- val := int(s.Value)
- switch {
- case val > aline:
- break pathloop
-
- case val == 1:
- // Start a new stack
- tos = &stackEnt{s.Name, val, 0, noPath}
-
- case s.Name == "":
- // Pop
- if tos == noPath {
- return "<malformed symbol table>", 0
- }
- tos.prev.offset += val - tos.start
- tos = tos.prev
-
- default:
- // Push
- tos = &stackEnt{s.Name, val, 0, tos}
- }
- }
-
- if tos == noPath {
- return "", 0
- }
- return tos.path, aline - tos.start - tos.offset + 1
-}
-
-func (o *Obj) alineFromLine(path string, line int) (int, error) {
- if line < 1 {
- return 0, &UnknownLineError{path, line}
- }
-
- for i, s := range o.Paths {
- // Find this path
- if s.Name != path {
- continue
- }
-
- // Find this line at this stack level
- depth := 0
- var incstart int
- line += int(s.Value)
- pathloop:
- for _, s := range o.Paths[i:] {
- val := int(s.Value)
- switch {
- case depth == 1 && val >= line:
- return line - 1, nil
-
- case s.Name == "":
- depth--
- if depth == 0 {
- break pathloop
- } else if depth == 1 {
- line += val - incstart
- }
-
- default:
- if depth == 1 {
- incstart = val
- }
- depth++
- }
- }
- return 0, &UnknownLineError{path, line}
- }
- return 0, UnknownFileError(path)
-}
-
-/*
- * Errors
- */
-
-// UnknownFileError represents a failure to find the specific file in
-// the symbol table.
-type UnknownFileError string
-
-func (e UnknownFileError) Error() string { return "unknown file: " + string(e) }
-
-// UnknownLineError represents a failure to map a line to a program
-// counter, either because the line is beyond the bounds of the file
-// or because there is no code on the given line.
-type UnknownLineError struct {
- File string
- Line int
-}
-
-func (e *UnknownLineError) Error() string {
- return "no code at " + e.File + ":" + strconv.Itoa(e.Line)
-}
-
-// DecodingError represents an error during the decoding of
-// the symbol table.
-type DecodingError struct {
- off int
- msg string
- val interface{}
-}
-
-func (e *DecodingError) Error() string {
- msg := e.msg
- if e.val != nil {
- msg += fmt.Sprintf(" '%v'", e.val)
- }
- msg += fmt.Sprintf(" at byte %#x", e.off)
- return msg
-}
diff --git a/local/local.go b/local/local.go
deleted file mode 100644
index e054249..0000000
--- a/local/local.go
+++ /dev/null
@@ -1,193 +0,0 @@
-// 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 local provides access to a local program.
-package local // import "golang.org/x/debug/local"
-
-import (
- "golang.org/x/debug"
- "golang.org/x/debug/server"
- "golang.org/x/debug/server/protocol"
-)
-
-var _ debug.Program = (*Program)(nil)
-var _ debug.File = (*File)(nil)
-
-// Program implements the debug.Program interface.
-// Through that interface it provides access to a program being debugged.
-type Program struct {
- s *server.Server
-}
-
-// New creates a new program from the specified file.
-// The program can then be started by the Run method.
-func New(textFile string) (*Program, error) {
- s, err := server.New(textFile)
- return &Program{s: s}, err
-}
-
-func (p *Program) Open(name string, mode string) (debug.File, error) {
- req := protocol.OpenRequest{
- Name: name,
- Mode: mode,
- }
- var resp protocol.OpenResponse
- err := p.s.Open(&req, &resp)
- if err != nil {
- return nil, err
- }
- f := &File{
- prog: p,
- fd: resp.FD,
- }
- return f, nil
-}
-
-func (p *Program) Run(args ...string) (debug.Status, error) {
- req := protocol.RunRequest{args}
- var resp protocol.RunResponse
- err := p.s.Run(&req, &resp)
- if err != nil {
- return debug.Status{}, err
- }
- return resp.Status, nil
-}
-
-func (p *Program) Stop() (debug.Status, error) {
- panic("unimplemented")
-}
-
-func (p *Program) Resume() (debug.Status, error) {
- req := protocol.ResumeRequest{}
- var resp protocol.ResumeResponse
- err := p.s.Resume(&req, &resp)
- if err != nil {
- return debug.Status{}, err
- }
- return resp.Status, nil
-}
-
-func (p *Program) Kill() (debug.Status, error) {
- panic("unimplemented")
-}
-
-func (p *Program) Breakpoint(address uint64) ([]uint64, error) {
- req := protocol.BreakpointRequest{
- Address: address,
- }
- var resp protocol.BreakpointResponse
- err := p.s.Breakpoint(&req, &resp)
- return resp.PCs, err
-}
-
-func (p *Program) BreakpointAtFunction(name string) ([]uint64, error) {
- req := protocol.BreakpointAtFunctionRequest{
- Function: name,
- }
- var resp protocol.BreakpointResponse
- err := p.s.BreakpointAtFunction(&req, &resp)
- return resp.PCs, err
-}
-
-func (p *Program) BreakpointAtLine(file string, line uint64) ([]uint64, error) {
- req := protocol.BreakpointAtLineRequest{
- File: file,
- Line: line,
- }
- var resp protocol.BreakpointResponse
- err := p.s.BreakpointAtLine(&req, &resp)
- return resp.PCs, err
-}
-
-func (p *Program) DeleteBreakpoints(pcs []uint64) error {
- req := protocol.DeleteBreakpointsRequest{PCs: pcs}
- var resp protocol.DeleteBreakpointsResponse
- return p.s.DeleteBreakpoints(&req, &resp)
-}
-
-func (p *Program) Eval(expr string) ([]string, error) {
- req := protocol.EvalRequest{
- Expr: expr,
- }
- var resp protocol.EvalResponse
- err := p.s.Eval(&req, &resp)
- return resp.Result, err
-}
-
-func (p *Program) Evaluate(e string) (debug.Value, error) {
- req := protocol.EvaluateRequest{
- Expression: e,
- }
- var resp protocol.EvaluateResponse
- err := p.s.Evaluate(&req, &resp)
- return resp.Result, err
-}
-
-func (p *Program) Frames(count int) ([]debug.Frame, error) {
- req := protocol.FramesRequest{
- Count: count,
- }
- var resp protocol.FramesResponse
- err := p.s.Frames(&req, &resp)
- return resp.Frames, err
-}
-
-func (p *Program) Goroutines() ([]*debug.Goroutine, error) {
- req := protocol.GoroutinesRequest{}
- var resp protocol.GoroutinesResponse
- err := p.s.Goroutines(&req, &resp)
- return resp.Goroutines, err
-}
-
-func (p *Program) VarByName(name string) (debug.Var, error) {
- req := protocol.VarByNameRequest{Name: name}
- var resp protocol.VarByNameResponse
- err := p.s.VarByName(&req, &resp)
- return resp.Var, err
-}
-
-func (p *Program) Value(v debug.Var) (debug.Value, error) {
- req := protocol.ValueRequest{Var: v}
- var resp protocol.ValueResponse
- err := p.s.Value(&req, &resp)
- return resp.Value, err
-}
-
-func (p *Program) MapElement(m debug.Map, index uint64) (debug.Var, debug.Var, error) {
- req := protocol.MapElementRequest{Map: m, Index: index}
- var resp protocol.MapElementResponse
- err := p.s.MapElement(&req, &resp)
- return resp.Key, resp.Value, err
-}
-
-// File implements the debug.File interface, providing access
-// to file-like resources associated with the target program.
-type File struct {
- prog *Program // The Program associated with the file.
- fd int // File descriptor.
-}
-
-func (f *File) ReadAt(p []byte, offset int64) (int, error) {
- req := protocol.ReadAtRequest{
- FD: f.fd,
- Len: len(p),
- Offset: offset,
- }
- var resp protocol.ReadAtResponse
- err := f.prog.s.ReadAt(&req, &resp)
- return copy(p, resp.Data), err
-}
-
-func (f *File) WriteAt(p []byte, offset int64) (int, error) {
- panic("unimplemented")
-}
-
-func (f *File) Close() error {
- req := protocol.CloseRequest{
- FD: f.fd,
- }
- var resp protocol.CloseResponse
- err := f.prog.s.Close(&req, &resp)
- return err
-}
diff --git a/macho/fat.go b/macho/fat.go
deleted file mode 100644
index 93b8315..0000000
--- a/macho/fat.go
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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
-}
diff --git a/macho/file.go b/macho/file.go
deleted file mode 100644
index 7f59901..0000000
--- a/macho/file.go
+++ /dev/null
@@ -1,525 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package 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
-}
diff --git a/macho/file_test.go b/macho/file_test.go
deleted file mode 100644
index 4797780..0000000
--- a/macho/file_test.go
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package macho
-
-import (
- "reflect"
- "testing"
-)
-
-type fileTest struct {
- file string
- hdr FileHeader
- segments []*SegmentHeader
- sections []*SectionHeader
-}
-
-var fileTests = []fileTest{
- {
- "testdata/gcc-386-darwin-exec",
- FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85},
- []*SegmentHeader{
- {LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
- {LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0},
- {LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0},
- {LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0},
- {LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0},
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- },
- []*SectionHeader{
- {"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400},
- {"__cstring", "__TEXT", 0x1ff0, 0xd, 0xff0, 0x0, 0x0, 0x0, 0x2},
- {"__data", "__DATA", 0x2000, 0x14, 0x1000, 0x2, 0x0, 0x0, 0x0},
- {"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0},
- {"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
- },
- },
- {
- "testdata/gcc-amd64-darwin-exec",
- FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85},
- []*SegmentHeader{
- {LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
- {LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0},
- {LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0},
- {LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0},
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- },
- []*SectionHeader{
- {"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400},
- {"__symbol_stub1", "__TEXT", 0x100000f81, 0xc, 0xf81, 0x0, 0x0, 0x0, 0x80000408},
- {"__stub_helper", "__TEXT", 0x100000f90, 0x18, 0xf90, 0x2, 0x0, 0x0, 0x0},
- {"__cstring", "__TEXT", 0x100000fa8, 0xd, 0xfa8, 0x0, 0x0, 0x0, 0x2},
- {"__eh_frame", "__TEXT", 0x100000fb8, 0x48, 0xfb8, 0x3, 0x0, 0x0, 0x6000000b},
- {"__data", "__DATA", 0x100001000, 0x1c, 0x1000, 0x3, 0x0, 0x0, 0x0},
- {"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0},
- {"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
- },
- },
- {
- "testdata/gcc-amd64-darwin-exec-debug",
- FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0},
- []*SegmentHeader{
- nil,
- {LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0},
- {LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0},
- {LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0},
- },
- []*SectionHeader{
- {"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400},
- {"__symbol_stub1", "__TEXT", 0x100000f81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000408},
- {"__stub_helper", "__TEXT", 0x100000f90, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0},
- {"__cstring", "__TEXT", 0x100000fa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
- {"__eh_frame", "__TEXT", 0x100000fb8, 0x0, 0x0, 0x3, 0x0, 0x0, 0x6000000b},
- {"__data", "__DATA", 0x100001000, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
- {"__dyld", "__DATA", 0x100001020, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
- {"__la_symbol_ptr", "__DATA", 0x100001058, 0x0, 0x0, 0x2, 0x0, 0x0, 0x7},
- {"__debug_abbrev", "__DWARF", 0x100002000, 0x36, 0x1000, 0x0, 0x0, 0x0, 0x0},
- {"__debug_aranges", "__DWARF", 0x100002036, 0x30, 0x1036, 0x0, 0x0, 0x0, 0x0},
- {"__debug_frame", "__DWARF", 0x100002066, 0x40, 0x1066, 0x0, 0x0, 0x0, 0x0},
- {"__debug_info", "__DWARF", 0x1000020a6, 0x54, 0x10a6, 0x0, 0x0, 0x0, 0x0},
- {"__debug_line", "__DWARF", 0x1000020fa, 0x47, 0x10fa, 0x0, 0x0, 0x0, 0x0},
- {"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0},
- {"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0},
- },
- },
-}
-
-func TestOpen(t *testing.T) {
- for i := range fileTests {
- tt := &fileTests[i]
-
- f, err := Open(tt.file)
- if err != nil {
- t.Error(err)
- continue
- }
- if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
- t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
- continue
- }
- for i, l := range f.Loads {
- if i >= len(tt.segments) {
- break
- }
- sh := tt.segments[i]
- s, ok := l.(*Segment)
- if sh == nil {
- if ok {
- t.Errorf("open %s, section %d: skipping %#v\n", tt.file, i, &s.SegmentHeader)
- }
- continue
- }
- if !ok {
- t.Errorf("open %s, section %d: not *Segment\n", tt.file, i)
- continue
- }
- have := &s.SegmentHeader
- want := sh
- if !reflect.DeepEqual(have, want) {
- t.Errorf("open %s, segment %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
- }
- }
- tn := len(tt.segments)
- fn := len(f.Loads)
- if tn != fn {
- t.Errorf("open %s: len(Loads) = %d, want %d", tt.file, fn, tn)
- }
-
- for i, sh := range f.Sections {
- if i >= len(tt.sections) {
- break
- }
- have := &sh.SectionHeader
- want := tt.sections[i]
- if !reflect.DeepEqual(have, want) {
- t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
- }
- }
- tn = len(tt.sections)
- fn = len(f.Sections)
- if tn != fn {
- t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
- }
-
- }
-}
-
-func TestOpenFailure(t *testing.T) {
- filename := "file.go" // not a Mach-O file
- _, err := Open(filename) // don't crash
- if err == nil {
- t.Errorf("open %s: succeeded unexpectedly", filename)
- }
-}
-
-func TestOpenFat(t *testing.T) {
- ff, err := OpenFat("testdata/fat-gcc-386-amd64-darwin-exec")
- if err != nil {
- t.Fatal(err)
- }
-
- if ff.Magic != MagicFat {
- t.Errorf("OpenFat: got magic number %#x, want %#x", ff.Magic, MagicFat)
- }
- if len(ff.Arches) != 2 {
- t.Errorf("OpenFat: got %d architectures, want 2", len(ff.Arches))
- }
-
- for i := range ff.Arches {
- arch := &ff.Arches[i]
- ftArch := &fileTests[i]
-
- if arch.Cpu != ftArch.hdr.Cpu || arch.SubCpu != ftArch.hdr.SubCpu {
- t.Errorf("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu)
- }
-
- if !reflect.DeepEqual(arch.FileHeader, ftArch.hdr) {
- t.Errorf("OpenFat header:\n\tgot %#v\n\twant %#v\n", arch.FileHeader, ftArch.hdr)
- }
- }
-}
-
-func TestOpenFatFailure(t *testing.T) {
- filename := "file.go" // not a Mach-O file
- if _, err := OpenFat(filename); err == nil {
- t.Errorf("OpenFat %s: succeeded unexpectedly", filename)
- }
-
- filename = "testdata/gcc-386-darwin-exec" // not a fat Mach-O
- ff, err := OpenFat(filename)
- if err != ErrNotFat {
- t.Errorf("OpenFat %s: got %v, want ErrNotFat", filename, err)
- }
- if ff != nil {
- t.Errorf("OpenFat %s: got %v, want nil", filename, ff)
- }
-}
diff --git a/macho/macho.go b/macho/macho.go
deleted file mode 100644
index b35e436..0000000
--- a/macho/macho.go
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Mach-O header data structures
-// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
-
-package macho // import "golang.org/x/debug/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
-}
diff --git a/macho/testdata/fat-gcc-386-amd64-darwin-exec b/macho/testdata/fat-gcc-386-amd64-darwin-exec
deleted file mode 100644
index 7efd193..0000000
--- a/macho/testdata/fat-gcc-386-amd64-darwin-exec
+++ /dev/null
Binary files differ
diff --git a/macho/testdata/gcc-386-darwin-exec b/macho/testdata/gcc-386-darwin-exec
deleted file mode 100755
index 03ba1ba..0000000
--- a/macho/testdata/gcc-386-darwin-exec
+++ /dev/null
Binary files differ
diff --git a/macho/testdata/gcc-amd64-darwin-exec b/macho/testdata/gcc-amd64-darwin-exec
deleted file mode 100755
index 5155a5a..0000000
--- a/macho/testdata/gcc-amd64-darwin-exec
+++ /dev/null
Binary files differ
diff --git a/macho/testdata/gcc-amd64-darwin-exec-debug b/macho/testdata/gcc-amd64-darwin-exec-debug
deleted file mode 100644
index a47d3ae..0000000
--- a/macho/testdata/gcc-amd64-darwin-exec-debug
+++ /dev/null
Binary files differ
diff --git a/macho/testdata/hello.c b/macho/testdata/hello.c
deleted file mode 100644
index a689d36..0000000
--- a/macho/testdata/hello.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <stdio.h>
-
-int
-main(void)
-{
- printf("hello, world\n");
- return 0;
-}
diff --git a/program.go b/program.go
deleted file mode 100644
index b988d83..0000000
--- a/program.go
+++ /dev/null
@@ -1,317 +0,0 @@
-// 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 debug provides the portable interface to a program being debugged.
-package debug // import "golang.org/x/debug"
-
-import (
- "fmt"
- "io"
- "strings"
-)
-
-// Program is the interface to a (possibly remote) program being debugged.
-// The process (if any) and text file associated with it may change during
-// the session, but many resources are associated with the Program rather
-// than process or text file so they persist across debuggging runs.
-type Program interface {
- // Open opens a virtual file associated with the process.
- // Names are things like "text", "mem", "fd/2".
- // Mode is one of "r", "w", "rw".
- // Return values are open File and error.
- // When the target binary is re-run, open files are
- // automatically updated to refer to the corresponding
- // file in the new process.
- Open(name string, mode string) (File, error)
-
- // Run abandons the current running process, if any,
- // and execs a new instance of the target binary file
- // (which may have changed underfoot).
- // Breakpoints and open files are re-established.
- // The call hangs until the program stops executing,
- // at which point it returns the program status.
- // args contains the command-line arguments for the process.
- Run(args ...string) (Status, error)
-
- // Stop stops execution of the current process but
- // does not kill it.
- Stop() (Status, error)
-
- // Resume resumes execution of a stopped process.
- // The call hangs until the program stops executing,
- // at which point it returns the program status.
- Resume() (Status, error)
-
- // TODO: Step(). Where does the granularity happen,
- // on the proxy end or the debugging control end?
-
- // Kill kills the current process.
- Kill() (Status, error)
-
- // Breakpoint sets a breakpoint at the specified address.
- Breakpoint(address uint64) (PCs []uint64, err error)
-
- // BreakpointAtFunction sets a breakpoint at the start of the specified function.
- BreakpointAtFunction(name string) (PCs []uint64, err error)
-
- // BreakpointAtLine sets a breakpoint at the specified source line.
- BreakpointAtLine(file string, line uint64) (PCs []uint64, err error)
-
- // DeleteBreakpoints removes the breakpoints at the specified addresses.
- // Addresses where no breakpoint is set are ignored.
- DeleteBreakpoints(pcs []uint64) error
-
- // Eval evaluates the expression (typically an address) and returns
- // its string representation(s). Multivalued expressions such as
- // matches for regular expressions return multiple values.
- // TODO: change this to multiple functions with more specific names.
- // Syntax:
- // re:regexp
- // Returns a list of symbol names that match the expression
- // addr:symbol
- // Returns a one-element list holding the hexadecimal
- // ("0x1234") value of the address of the symbol
- // val:symbol
- // Returns a one-element list holding the formatted
- // value of the symbol
- // 0x1234, 01234, 467
- // Returns a one-element list holding the name of the
- // symbol ("main.foo") at that address (hex, octal, decimal).
- Eval(expr string) ([]string, error)
-
- // Evaluate evaluates an expression. Accepts a subset of Go expression syntax:
- // basic literals, identifiers, parenthesized expressions, and most operators.
- // Only the len function call is available.
- //
- // The expression can refer to local variables and function parameters of the
- // function where the program is stopped.
- //
- // On success, the type of the value returned will be one of:
- // int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64,
- // complex64, complex128, bool, Pointer, Array, Slice, String, Map, Struct,
- // Channel, Func, or Interface.
- Evaluate(e string) (Value, error)
-
- // Frames returns up to count stack frames from where the program
- // is currently stopped.
- Frames(count int) ([]Frame, error)
-
- // VarByName returns a Var referring to a global variable with the given name.
- // TODO: local variables
- VarByName(name string) (Var, error)
-
- // Value gets the value of a variable by reading the program's memory.
- Value(v Var) (Value, error)
-
- // MapElement returns Vars for the key and value of a map element specified by
- // a 0-based index.
- MapElement(m Map, index uint64) (Var, Var, error)
-
- // Goroutines gets the current goroutines.
- Goroutines() ([]*Goroutine, error)
-}
-
-type Goroutine struct {
- ID int64
- Status GoroutineStatus
- StatusString string // A human-readable string explaining the status in more detail.
- Function string // Name of the goroutine function.
- Caller string // Name of the function that created this goroutine.
- StackFrames []Frame
-}
-
-type GoroutineStatus byte
-
-const (
- Running GoroutineStatus = iota
- Queued
- Blocked
-)
-
-func (g GoroutineStatus) String() string {
- switch g {
- case Running:
- return "running"
- case Queued:
- return "queued"
- case Blocked:
- return "blocked"
- }
- return "invalid status"
-}
-
-func (g *Goroutine) String() string {
- return fmt.Sprintf("goroutine %d [%s] %s -> %s", g.ID, g.StatusString, g.Caller, g.Function)
-}
-
-// A reference to a variable in a program.
-// TODO: handle variables stored in registers
-type Var struct {
- TypeID uint64 // A type identifier, opaque to the user.
- Address uint64 // The address of the variable.
-}
-
-// A value read from a remote program.
-type Value interface{}
-
-// Pointer is a Value representing a pointer.
-// Note that the TypeID field will be the type of the variable being pointed to,
-// not the type of this pointer.
-type Pointer struct {
- TypeID uint64 // A type identifier, opaque to the user.
- Address uint64 // The address of the variable.
-}
-
-// Array is a Value representing an array.
-type Array struct {
- ElementTypeID uint64
- Address uint64
- Length uint64 // Number of elements in the array
- StrideBits uint64 // Number of bits between array entries
-}
-
-// Len returns the number of elements in the array.
-func (a Array) Len() uint64 {
- return a.Length
-}
-
-// Element returns a Var referring to the given element of the array.
-func (a Array) Element(index uint64) Var {
- return Var{
- TypeID: a.ElementTypeID,
- Address: a.Address + index*(a.StrideBits/8),
- }
-}
-
-// Slice is a Value representing a slice.
-type Slice struct {
- Array
- Capacity uint64
-}
-
-// String is a Value representing a string.
-// TODO: a method to access more of a truncated string.
-type String struct {
- // Length contains the length of the remote string, in bytes.
- Length uint64
- // String contains the string itself; it may be truncated to fewer bytes than the value of the Length field.
- String string
-}
-
-// Map is a Value representing a map.
-type Map struct {
- TypeID uint64
- Address uint64
- Length uint64 // Number of elements in the map.
-}
-
-// Struct is a Value representing a struct.
-type Struct struct {
- Fields []StructField
-}
-
-// StructField represents a field in a struct object.
-type StructField struct {
- Name string
- Var Var
-}
-
-// Channel is a Value representing a channel.
-type Channel struct {
- ElementTypeID uint64
- Address uint64 // Location of the channel struct in memory.
- Buffer uint64 // Location of the buffer; zero for nil channels.
- Length uint64 // Number of elements stored in the channel buffer.
- Capacity uint64 // Capacity of the buffer; zero for unbuffered channels.
- Stride uint64 // Number of bytes between buffer entries.
- BufferStart uint64 // Index in the buffer of the element at the head of the queue.
-}
-
-// Element returns a Var referring to the given element of the channel's queue.
-// If the channel is unbuffered, nil, or if the index is too large, returns a Var with Address == 0.
-func (m Channel) Element(index uint64) Var {
- if index >= m.Length {
- return Var{
- TypeID: m.ElementTypeID,
- Address: 0,
- }
- }
- if index < m.Capacity-m.BufferStart {
- // The element is in the part of the queue that occurs later in the buffer
- // than the head of the queue.
- return Var{
- TypeID: m.ElementTypeID,
- Address: m.Buffer + (m.BufferStart+index)*m.Stride,
- }
- }
- // The element is in the part of the queue that has wrapped around to the
- // start of the buffer.
- return Var{
- TypeID: m.ElementTypeID,
- Address: m.Buffer + (m.BufferStart+index-m.Capacity)*m.Stride,
- }
-}
-
-// Func is a Value representing a func.
-type Func struct {
- Address uint64
-}
-
-// Interface is a Value representing an interface.
-type Interface struct{}
-
-// The File interface provides access to file-like resources in the program.
-// It implements only ReaderAt and WriterAt, not Reader and Writer, because
-// random access is a far more common pattern for things like symbol tables,
-// and because enormous address space of virtual memory makes routines
-// like io.Copy dangerous.
-type File interface {
- io.ReaderAt
- io.WriterAt
- io.Closer
-}
-
-type Status struct {
- PC, SP uint64
-}
-
-type Frame struct {
- // PC is the hardware program counter.
- PC uint64
- // SP is the hardware stack pointer.
- SP uint64
- // File and Line are the source code location of the PC.
- File string
- Line uint64
- // Function is the name of this frame's function.
- Function string
- // FunctionStart is the starting PC of the function.
- FunctionStart uint64
- // Params contains the function's parameters.
- Params []Param
- // Vars contains the function's local variables.
- Vars []LocalVar
-}
-
-func (f Frame) String() string {
- params := make([]string, len(f.Params))
- for i, p := range f.Params {
- params[i] = p.Name // TODO: more information
- }
- p := strings.Join(params, ", ")
- off := f.PC - f.FunctionStart
- return fmt.Sprintf("%s(%s)\n\t%s:%d +0x%x", f.Function, p, f.File, f.Line, off)
-}
-
-// Param is a parameter of a function.
-type Param struct {
- Name string
- Var Var
-}
-
-// LocalVar is a local variable of a function.
-type LocalVar struct {
- Name string
- Var Var
-}
diff --git a/remote/remote.go b/remote/remote.go
deleted file mode 100644
index 66080c0..0000000
--- a/remote/remote.go
+++ /dev/null
@@ -1,295 +0,0 @@
-// 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 remote provides remote access to a debugproxy server.
-package remote // import "golang.org/x/debug/remote"
-
-import (
- "fmt"
- "io"
- "net/rpc"
- "os"
- "os/exec"
-
- "golang.org/x/debug"
- "golang.org/x/debug/server/protocol"
-)
-
-var _ debug.Program = (*Program)(nil)
-var _ debug.File = (*File)(nil)
-
-// Program implements the debug.Program interface.
-// Through that interface it provides access to a program being
-// debugged on a possibly remote machine by communicating
-// with a debugproxy adjacent to the target program.
-type Program struct {
- client *rpc.Client
-}
-
-// DebugproxyCmd is the path to the debugproxy command. It is a variable in case
-// the default value, "debugproxy", is not in the $PATH.
-var DebugproxyCmd = "debugproxy"
-
-// New connects to the specified host using SSH, starts DebugproxyCmd
-// there, and creates a new program from the specified file.
-// The program can then be started by the Run method.
-func New(host string, textFile string) (*Program, error) {
- // TODO: add args.
- cmdStrs := []string{"/usr/bin/ssh", host, DebugproxyCmd, "-text", textFile}
- if host == "localhost" {
- cmdStrs = cmdStrs[2:]
- }
- cmd := exec.Command(cmdStrs[0], cmdStrs[1:]...)
- stdin, toStdin, err := os.Pipe()
- if err != nil {
- return nil, err
- }
- fromStdout, stdout, err := os.Pipe()
- if err != nil {
- return nil, err
- }
- cmd.Stdin = stdin
- cmd.Stdout = stdout
- cmd.Stderr = os.Stderr // Stderr from proxy appears on our stderr.
- err = cmd.Start()
- if err != nil {
- return nil, err
- }
- stdout.Close()
- if msg, err := readLine(fromStdout); err != nil {
- return nil, err
- } else if msg != "OK" {
- // Communication error.
- return nil, fmt.Errorf("unrecognized message %q", msg)
- }
- program := &Program{
- client: rpc.NewClient(&rwc{
- ssh: cmd,
- r: fromStdout,
- w: toStdin,
- }),
- }
- return program, nil
-}
-
-// readLine reads one line of text from the reader. It does no buffering.
-// The trailing newline is read but not returned.
-func readLine(r io.Reader) (string, error) {
- b := make([]byte, 0, 10)
- var c [1]byte
- for {
- _, err := io.ReadFull(r, c[:])
- if err != nil {
- return "", err
- }
- if c[0] == '\n' {
- break
- }
- b = append(b, c[0])
- }
- return string(b), nil
-}
-
-// rwc creates a single io.ReadWriteCloser from a read side and a write side.
-// It also holds the command object so we can wait for SSH to complete.
-// It allows us to do RPC over an SSH connection.
-type rwc struct {
- ssh *exec.Cmd
- r *os.File
- w *os.File
-}
-
-func (rwc *rwc) Read(p []byte) (int, error) {
- return rwc.r.Read(p)
-}
-
-func (rwc *rwc) Write(p []byte) (int, error) {
- return rwc.w.Write(p)
-}
-
-func (rwc *rwc) Close() error {
- rerr := rwc.r.Close()
- werr := rwc.w.Close()
- cerr := rwc.ssh.Wait()
- if cerr != nil {
- // Wait exit status is most important.
- return cerr
- }
- if rerr != nil {
- return rerr
- }
- return werr
-}
-
-func (p *Program) Open(name string, mode string) (debug.File, error) {
- req := protocol.OpenRequest{
- Name: name,
- Mode: mode,
- }
- var resp protocol.OpenResponse
- err := p.client.Call("Server.Open", &req, &resp)
- if err != nil {
- return nil, err
- }
- f := &File{
- prog: p,
- fd: resp.FD,
- }
- return f, nil
-}
-
-func (p *Program) Run(args ...string) (debug.Status, error) {
- req := protocol.RunRequest{args}
- var resp protocol.RunResponse
- err := p.client.Call("Server.Run", &req, &resp)
- if err != nil {
- return debug.Status{}, err
- }
- return resp.Status, nil
-}
-
-func (p *Program) Stop() (debug.Status, error) {
- panic("unimplemented")
-}
-
-func (p *Program) Resume() (debug.Status, error) {
- req := protocol.ResumeRequest{}
- var resp protocol.ResumeResponse
- err := p.client.Call("Server.Resume", &req, &resp)
- if err != nil {
- return debug.Status{}, err
- }
- return resp.Status, nil
-}
-
-func (p *Program) Kill() (debug.Status, error) {
- panic("unimplemented")
-}
-
-func (p *Program) Breakpoint(address uint64) ([]uint64, error) {
- req := protocol.BreakpointRequest{
- Address: address,
- }
- var resp protocol.BreakpointResponse
- err := p.client.Call("Server.Breakpoint", &req, &resp)
- return resp.PCs, err
-}
-
-func (p *Program) BreakpointAtFunction(name string) ([]uint64, error) {
- req := protocol.BreakpointAtFunctionRequest{
- Function: name,
- }
- var resp protocol.BreakpointResponse
- err := p.client.Call("Server.BreakpointAtFunction", &req, &resp)
- return resp.PCs, err
-}
-
-func (p *Program) BreakpointAtLine(file string, line uint64) ([]uint64, error) {
- req := protocol.BreakpointAtLineRequest{
- File: file,
- Line: line,
- }
- var resp protocol.BreakpointResponse
- err := p.client.Call("Server.BreakpointAtLine", &req, &resp)
- return resp.PCs, err
-}
-
-func (p *Program) DeleteBreakpoints(pcs []uint64) error {
- req := protocol.DeleteBreakpointsRequest{PCs: pcs}
- var resp protocol.DeleteBreakpointsResponse
- return p.client.Call("Server.DeleteBreakpoints", &req, &resp)
-}
-
-func (p *Program) Eval(expr string) ([]string, error) {
- req := protocol.EvalRequest{
- Expr: expr,
- }
- var resp protocol.EvalResponse
- err := p.client.Call("Server.Eval", &req, &resp)
- return resp.Result, err
-}
-
-func (p *Program) Evaluate(e string) (debug.Value, error) {
- req := protocol.EvaluateRequest{
- Expression: e,
- }
- var resp protocol.EvaluateResponse
- err := p.client.Call("Server.Evaluate", &req, &resp)
- return resp.Result, err
-}
-
-func (p *Program) Frames(count int) ([]debug.Frame, error) {
- req := protocol.FramesRequest{
- Count: count,
- }
- var resp protocol.FramesResponse
- err := p.client.Call("Server.Frames", &req, &resp)
- return resp.Frames, err
-}
-
-func (p *Program) Goroutines() ([]*debug.Goroutine, error) {
- req := protocol.GoroutinesRequest{}
- var resp protocol.GoroutinesResponse
- err := p.client.Call("Server.Goroutines", &req, &resp)
- return resp.Goroutines, err
-}
-
-func (p *Program) VarByName(name string) (debug.Var, error) {
- req := protocol.VarByNameRequest{Name: name}
- var resp protocol.VarByNameResponse
- err := p.client.Call("Server.VarByName", &req, &resp)
- return resp.Var, err
-}
-
-func (p *Program) Value(v debug.Var) (debug.Value, error) {
- req := protocol.ValueRequest{Var: v}
- var resp protocol.ValueResponse
- err := p.client.Call("Server.Value", &req, &resp)
- return resp.Value, err
-}
-
-func (p *Program) MapElement(m debug.Map, index uint64) (debug.Var, debug.Var, error) {
- req := protocol.MapElementRequest{Map: m, Index: index}
- var resp protocol.MapElementResponse
- err := p.client.Call("Server.MapElement", &req, &resp)
- return resp.Key, resp.Value, err
-}
-
-// File implements the debug.File interface, providing access
-// to file-like resources associated with the target program.
-type File struct {
- prog *Program // The Program associated with the file.
- fd int // File descriptor.
-}
-
-func (f *File) ReadAt(p []byte, offset int64) (int, error) {
- req := protocol.ReadAtRequest{
- FD: f.fd,
- Len: len(p),
- Offset: offset,
- }
- var resp protocol.ReadAtResponse
- err := f.prog.client.Call("Server.ReadAt", &req, &resp)
- return copy(p, resp.Data), err
-}
-
-func (f *File) WriteAt(p []byte, offset int64) (int, error) {
- req := protocol.WriteAtRequest{
- FD: f.fd,
- Data: p,
- Offset: offset,
- }
- var resp protocol.WriteAtResponse
- err := f.prog.client.Call("Server.WriteAt", &req, &resp)
- return resp.Len, err
-}
-
-func (f *File) Close() error {
- req := protocol.CloseRequest{
- FD: f.fd,
- }
- var resp protocol.CloseResponse
- err := f.prog.client.Call("Server.Close", &req, &resp)
- return err
-}
diff --git a/server/dwarf.go b/server/dwarf.go
deleted file mode 100644
index 3c4e2a2..0000000
--- a/server/dwarf.go
+++ /dev/null
@@ -1,100 +0,0 @@
-// 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 server
-
-import (
- "errors"
- "fmt"
-
- "golang.org/x/debug/dwarf"
-)
-
-func (s *Server) functionStartAddress(name string) (uint64, error) {
- entry, err := s.dwarfData.LookupFunction(name)
- if err != nil {
- return 0, err
- }
- addrAttr := entry.Val(dwarf.AttrLowpc)
- if addrAttr == nil {
- return 0, fmt.Errorf("symbol %q has no LowPC attribute", name)
- }
- addr, ok := addrAttr.(uint64)
- if !ok {
- return 0, fmt.Errorf("symbol %q has non-uint64 LowPC attribute", name)
- }
- return addr, nil
-}
-
-// evalLocation parses a DWARF location description encoded in v. It works for
-// cases where the variable is stored at an offset from the Canonical Frame
-// Address. The return value is this offset.
-// TODO: a more general location-description-parsing function.
-func evalLocation(v []uint8) (int64, error) {
- // Some DWARF constants.
- const (
- opConsts = 0x11
- opPlus = 0x22
- opCallFrameCFA = 0x9C
- )
- if len(v) == 0 {
- return 0, errors.New("empty location specifier")
- }
- if v[0] != opCallFrameCFA {
- return 0, errors.New("unsupported location specifier")
- }
- if len(v) == 1 {
- // The location description was just DW_OP_call_frame_cfa, so the location is exactly the CFA.
- return 0, nil
- }
- if v[1] != opConsts {
- return 0, errors.New("unsupported location specifier")
- }
- offset, v, err := sleb128(v[2:])
- if err != nil {
- return 0, err
- }
- if len(v) == 1 && v[0] == opPlus {
- // The location description was DW_OP_call_frame_cfa, DW_OP_consts <offset>, DW_OP_plus.
- // So return the offset.
- return offset, nil
- }
- return 0, errors.New("unsupported location specifier")
-}
-
-func uleb128(v []uint8) (u uint64) {
- var shift uint
- for _, x := range v {
- u |= (uint64(x) & 0x7F) << shift
- shift += 7
- if x&0x80 == 0 {
- break
- }
- }
- return u
-}
-
-// sleb128 parses a signed integer encoded with sleb128 at the start of v, and
-// returns the integer and the remainder of v.
-func sleb128(v []uint8) (s int64, rest []uint8, err error) {
- var shift uint
- var sign int64 = -1
- var i int
- var x uint8
- for i, x = range v {
- s |= (int64(x) & 0x7F) << shift
- shift += 7
- sign <<= 7
- if x&0x80 == 0 {
- if x&0x40 != 0 {
- s |= sign
- }
- break
- }
- }
- if i == len(v) {
- return 0, nil, errors.New("truncated sleb128")
- }
- return s, v[i+1:], nil
-}
diff --git a/server/eval.go b/server/eval.go
deleted file mode 100644
index d964a32..0000000
--- a/server/eval.go
+++ /dev/null
@@ -1,2103 +0,0 @@
-// Copyright 2015 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.
-//
-// Evaluates Go expressions, using the current values of variables in a program
-// being debugged.
-//
-// TODOs:
-// More overflow checking.
-// Stricter type checking.
-// More expression types.
-
-package server
-
-import (
- "errors"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "math"
- "math/big"
-
- "golang.org/x/debug"
- "golang.org/x/debug/dwarf"
-)
-
-const prec = 256 // precision for untyped float and complex constants.
-
-var (
- // Some big.Ints to use in overflow checks.
- bigIntMaxInt32 = big.NewInt(math.MaxInt32)
- bigIntMinInt32 = big.NewInt(math.MinInt32)
- bigIntMaxInt64 = big.NewInt(math.MaxInt64)
- bigIntMinInt64 = big.NewInt(math.MinInt64)
- bigIntMaxUint64 = new(big.Int).SetUint64(math.MaxUint64)
-)
-
-// result stores an intermediate value produced during evaluation of an expression.
-//
-// d contains the DWARF type of the value. For untyped values, d will be nil.
-//
-// v contains the value itself. For numeric and bool types, v will have the
-// corresponding predeclared Go type.
-// For untyped integer, rune, float, complex, string, and bool constants, v will
-// have type untInt, untRune, untFloat, untComplex, untString, or bool,
-// respectively.
-// For values of type int, uint and uintptr, v will be an int32, int64, uint32
-// or uint64 as appropriate.
-// For address operations, v will have type pointerToValue.
-// For the operands of address operations, v will have type addressableValue.
-// Other types are represented using the corresponding implementation of
-// debug.Value in program.go.
-//
-// If an evaluation results in an error, the zero value of result is used.
-type result struct {
- d dwarf.Type
- v interface{}
-}
-
-// untInt is an untyped integer constant
-type untInt struct {
- *big.Int
-}
-
-// untRune is an untyped rune constant
-type untRune struct {
- *big.Int
-}
-
-// untFloat is an untyped floating-point constant
-type untFloat struct {
- *big.Float
-}
-
-// untComplex is an untyped complex constant
-type untComplex struct {
- r *big.Float
- i *big.Float
-}
-
-// untString is an untyped string constant
-type untString string
-
-// pointerToValue is a pointer to a value in memory.
-// The evaluator constructs these as the result of address operations like "&x".
-// Unlike debug.Pointer, the DWARF type stored alongside values of this type
-// is the type of the variable, not the type of the pointer.
-type pointerToValue struct {
- a uint64
-}
-
-// addressableValue is the memory location of a value.
-// The evaluator constructs these while evaluating the operands of address
-// operations like "&x", instead of computing the value of x itself.
-type addressableValue struct {
- a uint64
-}
-
-// A sliceOf is a slice created by slicing an array.
-// Unlike debug.Slice, the DWARF type stored alongside a value of this type is
-// the type of the slice's elements, not the type of the slice.
-type sliceOf debug.Slice
-
-// ident is a value for representing a special identifier.
-type ident string
-
-// identLookup is a built-in function of the expression evaluator which gets the
-// value of a global symbol.
-var identLookup ident = "lookup"
-
-// evalExpression evaluates a Go expression.
-// If the program counter and stack pointer are nonzero, they are used to determine
-// what local variables are available and where in memory they are.
-func (s *Server) evalExpression(expression string, pc, sp uint64) (debug.Value, error) {
- e := evaluator{server: s, expression: expression, pc: pc, sp: sp}
- node, err := parser.ParseExpr(expression)
- if err != nil {
- return nil, err
- }
- val := e.evalNode(node, false)
- if e.evalError != nil {
- return nil, e.evalError
- }
-
- // Convert untyped constants to their default types.
- switch v := val.v.(type) {
- case untInt:
- return e.intFromInteger(v)
- case untRune:
- if v.Cmp(bigIntMaxInt32) == +1 {
- return nil, errors.New("constant overflows rune")
- }
- if v.Cmp(bigIntMinInt32) == -1 {
- return nil, errors.New("constant overflows rune")
- }
- return int32(v.Int64()), nil
- case untFloat:
- f, _ := v.Float64()
- if math.IsInf(f, 0) {
- return nil, errors.New("constant overflows float64")
- }
- if math.IsNaN(f) {
- return nil, errors.New("constant is NaN")
- }
- return f, nil
- case untComplex:
- r, _ := v.r.Float64()
- i, _ := v.i.Float64()
- if math.IsInf(r, 0) || math.IsInf(i, 0) {
- return nil, errors.New("constant overflows complex128")
- }
- if math.IsNaN(r) || math.IsNaN(i) {
- return nil, errors.New("constant is NaN")
- }
- return complex(r, i), nil
- case untString:
- return debug.String{Length: uint64(len(v)), String: string(v)}, nil
- case pointerToValue:
- return debug.Pointer{TypeID: uint64(val.d.Common().Offset), Address: v.a}, nil
- case sliceOf:
- return debug.Slice(v), nil
- case nil, addressableValue:
- // This case should not be reachable.
- return nil, errors.New("unknown error")
- }
- return val.v, nil
-}
-
-type evaluator struct {
- // expression is the expression being evaluated.
- expression string
- // server interacts with the program being debugged.
- server *Server
- // curNode is the current parse tree node. This is set so that error messages
- // can quote the part of the expression that caused an error.
- curNode ast.Node
- // evalError is the first error that occurred while evaluating the expression,
- // or nil if no error has occurred.
- evalError error
- // pc and sp are the current program counter and stack pointer, used for
- // finding local variables. If either are zero, the expression is evaluated
- // without using local variables.
- pc uint64
- sp uint64
-}
-
-// setNode sets curNode, and returns curNode's previous value.
-func (e *evaluator) setNode(node ast.Node) (old ast.Node) {
- old, e.curNode = e.curNode, node
- return old
-}
-
-// err saves an error that occurred during evaluation.
-// It returns a zero result, so that functions can exit and set an error with
-// return e.err(...)
-func (e *evaluator) err(s string) result {
- if e.evalError != nil {
- return result{}
- }
- // Append the substring of the expression that corresponds to the current AST node.
- start := int(e.curNode.Pos() - 1)
- end := int(e.curNode.End() - 1)
- if start < 0 {
- start = 0
- }
- if end > len(e.expression) {
- end = len(e.expression)
- }
- if start > end {
- start, end = 0, 0
- }
- e.evalError = errors.New(s + `: "` + e.expression[start:end] + `"`)
- return result{}
-}
-
-// evalNode computes the value of a node in the expression tree.
-// If getAddress is true, the node is the argument of an & operator, so evalNode
-// will return a result with a value of type addressableValue if possible.
-func (e *evaluator) evalNode(node ast.Node, getAddress bool) result {
- // Set the current node in the evaluator, so that error messages can refer to
- // it. Defer a function call that changes it back.
- defer e.setNode(e.setNode(node))
-
- switch n := node.(type) {
- case *ast.Ident:
- if e.pc != 0 && e.sp != 0 {
- a, t := e.server.findLocalVar(n.Name, e.pc, e.sp)
- if t != nil {
- return e.resultFrom(a, t, getAddress)
- }
- }
- a, t := e.server.findGlobalVar(n.Name)
- if t != nil {
- return e.resultFrom(a, t, getAddress)
- }
- switch n.Name {
- // Note: these could have been redefined as constants in the code, but we
- // don't have a way to detect that.
- case "true":
- return result{nil, true}
- case "false":
- return result{nil, false}
- case "lookup":
- return result{nil, identLookup}
- }
- return e.err("unknown identifier")
-
- case *ast.BasicLit:
- switch n.Kind {
- case token.INT:
- i := new(big.Int)
- if _, ok := i.SetString(n.Value, 0); !ok {
- return e.err("invalid integer constant")
- }
- return result{nil, untInt{i}}
- case token.FLOAT:
- r, _, err := big.ParseFloat(n.Value, 10, prec, big.ToNearestEven)
- if err != nil {
- return e.err(err.Error())
- }
- return result{nil, untFloat{r}}
- case token.IMAG:
- if len(n.Value) <= 1 || n.Value[len(n.Value)-1] != 'i' {
- return e.err("invalid imaginary constant")
- }
- r, _, err := big.ParseFloat(n.Value[:len(n.Value)-1], 10, prec, big.ToNearestEven)
- if err != nil {
- return e.err(err.Error())
- }
- return result{nil, untComplex{new(big.Float), r}}
- case token.CHAR:
- // TODO: unescaping
- return result{nil, untRune{new(big.Int).SetInt64(int64(n.Value[1]))}}
- case token.STRING:
- // TODO: unescaping
- if len(n.Value) <= 1 {
- return e.err("invalid string constant")
- }
- return result{nil, untString(n.Value[1 : len(n.Value)-1])}
- }
-
- case *ast.ParenExpr:
- return e.evalNode(n.X, getAddress)
-
- case *ast.StarExpr:
- x := e.evalNode(n.X, false)
- switch v := x.v.(type) {
- case debug.Pointer:
- // x.d may be a typedef pointing to a pointer type (or a typedef pointing
- // to a typedef pointing to a pointer type, etc.), so remove typedefs
- // until we get the underlying pointer type.
- t := followTypedefs(x.d)
- if pt, ok := t.(*dwarf.PtrType); ok {
- return e.resultFrom(v.Address, pt.Type, getAddress)
- } else {
- return e.err("invalid DWARF type for pointer")
- }
- case pointerToValue:
- return e.resultFrom(v.a, x.d, getAddress)
- case nil:
- return x
- }
- return e.err("invalid indirect")
-
- case *ast.SelectorExpr:
- x := e.evalNode(n.X, false)
- sel := n.Sel.Name
- switch v := x.v.(type) {
- case debug.Struct:
- for _, f := range v.Fields {
- if f.Name == sel {
- t, err := e.server.dwarfData.Type(dwarf.Offset(f.Var.TypeID))
- if err != nil {
- return e.err(err.Error())
- }
- return e.resultFrom(f.Var.Address, t, getAddress)
- }
- }
- return e.err("struct field not found")
- case debug.Pointer:
- pt, ok := followTypedefs(x.d).(*dwarf.PtrType) // x.d should be a pointer to struct.
- if !ok {
- return e.err("invalid DWARF information for pointer")
- }
- st, ok := followTypedefs(pt.Type).(*dwarf.StructType)
- if !ok {
- break
- }
- for _, f := range st.Field {
- if f.Name == sel {
- return e.resultFrom(v.Address+uint64(f.ByteOffset), f.Type, getAddress)
- }
- }
- return e.err("struct field not found")
- case pointerToValue:
- st, ok := followTypedefs(x.d).(*dwarf.StructType) // x.d should be a struct.
- if !ok {
- break
- }
- for _, f := range st.Field {
- if f.Name == sel {
- return e.resultFrom(v.a+uint64(f.ByteOffset), f.Type, getAddress)
- }
- }
- return e.err("struct field not found")
- }
- return e.err("invalid selector expression")
-
- case *ast.IndexExpr:
- x, index := e.evalNode(n.X, false), e.evalNode(n.Index, false)
- if x.v == nil || index.v == nil {
- return result{}
- }
- // The expression is x[index]
- if m, ok := x.v.(debug.Map); ok {
- if getAddress {
- return e.err("can't take address of map value")
- }
- mt, ok := followTypedefs(x.d).(*dwarf.MapType)
- if !ok {
- return e.err("invalid DWARF type for map")
- }
- var (
- found bool // true if the key was found
- value result // the map value for the key
- abort bool // true if an error occurred while searching
- // fn is a function that checks if one (key, value) pair corresponds
- // to the index in the expression.
- fn = func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool {
- key := e.resultFrom(keyAddr, keyType, false)
- if key.v == nil {
- abort = true
- return false // stop searching map
- }
- equal, ok := e.evalBinaryOp(token.EQL, index, key).v.(bool)
- if !ok {
- abort = true
- return false // stop searching map
- }
- if equal {
- found = true
- value = e.resultFrom(valAddr, valType, false)
- return false // stop searching map
- }
- return true // continue searching map
- }
- )
- if err := e.server.peekMapValues(mt, m.Address, fn); err != nil {
- return e.err(err.Error())
- }
- if abort {
- // Some operation on individual map keys failed.
- return result{}
- }
- if found {
- return value
- }
- // The key wasn't in the map; return the zero value.
- return e.zero(mt.ElemType)
- }
-
- // The index should be a non-negative integer for the remaining cases.
- u, err := uint64FromResult(index)
- if err != nil {
- return e.err("invalid index: " + err.Error())
- }
- switch v := x.v.(type) {
- case debug.Array:
- if u >= v.Length {
- return e.err("array index out of bounds")
- }
- elemType, err := e.server.dwarfData.Type(dwarf.Offset(v.ElementTypeID))
- if err != nil {
- return e.err(err.Error())
- }
- return e.resultFrom(v.Element(u).Address, elemType, getAddress)
- case debug.Slice:
- if u >= v.Length {
- return e.err("slice index out of bounds")
- }
- elemType, err := e.server.dwarfData.Type(dwarf.Offset(v.ElementTypeID))
- if err != nil {
- return e.err(err.Error())
- }
- return e.resultFrom(v.Element(u).Address, elemType, getAddress)
- case sliceOf:
- if u >= v.Length {
- return e.err("slice index out of bounds")
- }
- return e.resultFrom(v.Element(u).Address, x.d, getAddress)
- case debug.String:
- if getAddress {
- return e.err("can't take address of string element")
- }
- if u >= v.Length {
- return e.err("string index out of bounds")
- }
- if u >= uint64(len(v.String)) {
- return e.err("string element unavailable")
- }
- return e.uint8Result(v.String[u])
- case untString:
- if getAddress {
- return e.err("can't take address of string element")
- }
- if u >= uint64(len(v)) {
- return e.err("string index out of bounds")
- }
- return e.uint8Result(v[u])
- }
- return e.err("invalid index expression")
-
- case *ast.SliceExpr:
- if n.Slice3 && n.High == nil {
- return e.err("middle index required in full slice")
- }
- if n.Slice3 && n.Max == nil {
- return e.err("final index required in full slice")
- }
- var (
- low, high, max uint64
- err error
- )
- if n.Low != nil {
- low, err = uint64FromResult(e.evalNode(n.Low, false))
- if err != nil {
- return e.err("invalid slice lower bound: " + err.Error())
- }
- }
- if n.High != nil {
- high, err = uint64FromResult(e.evalNode(n.High, false))
- if err != nil {
- return e.err("invalid slice upper bound: " + err.Error())
- }
- }
- if n.Max != nil {
- max, err = uint64FromResult(e.evalNode(n.Max, false))
- if err != nil {
- return e.err("invalid slice capacity: " + err.Error())
- }
- }
- x := e.evalNode(n.X, false)
- switch v := x.v.(type) {
- case debug.Array, debug.Pointer, pointerToValue:
- // This case handles the slicing of arrays and pointers to arrays.
- var arr debug.Array
- switch v := x.v.(type) {
- case debug.Array:
- arr = v
- case debug.Pointer:
- pt, ok := followTypedefs(x.d).(*dwarf.PtrType)
- if !ok {
- return e.err("invalid DWARF type for pointer")
- }
- a := e.resultFrom(v.Address, pt.Type, false)
- arr, ok = a.v.(debug.Array)
- if !ok {
- // v is a pointer to something other than an array.
- return e.err("cannot slice pointer")
- }
- case pointerToValue:
- a := e.resultFrom(v.a, x.d, false)
- var ok bool
- arr, ok = a.v.(debug.Array)
- if !ok {
- // v is a pointer to something other than an array.
- return e.err("cannot slice pointer")
- }
- }
- elemType, err := e.server.dwarfData.Type(dwarf.Offset(arr.ElementTypeID))
- if err != nil {
- return e.err(err.Error())
- }
- if n.High == nil {
- high = arr.Length
- } else if high > arr.Length {
- return e.err("slice upper bound is too large")
- }
- if n.Max == nil {
- max = arr.Length
- } else if max > arr.Length {
- return e.err("slice capacity is too large")
- }
- if low > high || high > max {
- return e.err("invalid slice index")
- }
- return result{
- d: elemType,
- v: sliceOf{
- Array: debug.Array{
- ElementTypeID: arr.ElementTypeID,
- Address: arr.Element(low).Address,
- Length: high - low,
- StrideBits: uint64(elemType.Common().ByteSize) * 8,
- },
- Capacity: max - low,
- },
- }
- case debug.Slice:
- if n.High == nil {
- high = v.Length
- } else if high > v.Capacity {
- return e.err("slice upper bound is too large")
- }
- if n.Max == nil {
- max = v.Capacity
- } else if max > v.Capacity {
- return e.err("slice capacity is too large")
- }
- if low > high || high > max {
- return e.err("invalid slice index")
- }
- v.Address += low * (v.StrideBits / 8)
- v.Length = high - low
- v.Capacity = max - low
- return result{x.d, v}
- case sliceOf:
- if n.High == nil {
- high = v.Length
- } else if high > v.Capacity {
- return e.err("slice upper bound is too large")
- }
- if n.Max == nil {
- max = v.Capacity
- } else if max > v.Capacity {
- return e.err("slice capacity is too large")
- }
- if low > high || high > max {
- return e.err("invalid slice index")
- }
- v.Address += low * (v.StrideBits / 8)
- v.Length = high - low
- v.Capacity = max - low
- return result{x.d, v}
- case debug.String:
- if n.Max != nil {
- return e.err("full slice of string")
- }
- if n.High == nil {
- high = v.Length
- }
- if low > high || high > v.Length {
- return e.err("invalid slice index")
- }
- v.Length = high - low
- if low > uint64(len(v.String)) {
- // v.String was truncated before the point where this slice starts.
- v.String = ""
- } else {
- if high > uint64(len(v.String)) {
- // v.String was truncated before the point where this slice ends.
- high = uint64(len(v.String))
- }
- v.String = v.String[low:high]
- }
- return result{x.d, v}
- case untString:
- if n.Max != nil {
- return e.err("full slice of string")
- }
- if n.High == nil {
- high = uint64(len(v))
- }
- if low > high {
- return e.err("invalid slice expression")
- }
- if high > uint64(len(v)) {
- return e.err("slice upper bound is too large")
- }
- return e.stringResult(string(v[low:high]))
- default:
- return e.err("invalid slice expression")
- }
-
- case *ast.CallExpr:
- // Only supports lookup("x"), which gets the value of a global symbol x.
- fun := e.evalNode(n.Fun, false)
- var args []result
- for _, a := range n.Args {
- args = append(args, e.evalNode(a, false))
- }
- if fun.v == identLookup {
- if len(args) != 1 {
- return e.err("lookup should have one argument")
- }
- ident, ok := args[0].v.(untString)
- if !ok {
- return e.err("argument for lookup should be a string constant")
- }
- if a, t := e.server.findGlobalVar(string(ident)); t == nil {
- return e.err("symbol not found")
- } else {
- return e.resultFrom(a, t, getAddress)
- }
- }
- return e.err("function calls not implemented")
-
- case *ast.UnaryExpr:
- if n.Op == token.AND {
- x := e.evalNode(n.X, true)
- switch v := x.v.(type) {
- case addressableValue:
- return result{x.d, pointerToValue{v.a}}
- case nil:
- return x
- }
- return e.err("can't take address")
- }
-
- x := e.evalNode(n.X, false)
- if x.v == nil {
- return x
- }
- switch v := x.v.(type) {
-
- case int8:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case int16:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case int32:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case int64:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case uint8:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case uint16:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case uint32:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case uint64:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case float32:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case float64:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case complex64:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case complex128:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case untInt:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v.Int.Neg(v.Int)
- case token.XOR:
- v.Int.Not(v.Int)
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case untRune:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v.Int.Neg(v.Int)
- case token.XOR:
- v.Int.Not(v.Int)
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case untFloat:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v.Float.Neg(v.Float)
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case untComplex:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v.r.Neg(v.r)
- v.i.Neg(v.i)
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case bool:
- switch n.Op {
- case token.NOT:
- v = !v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
- }
-
- case *ast.BinaryExpr:
- x := e.evalNode(n.X, false)
- if x.v == nil {
- return x
- }
- y := e.evalNode(n.Y, false)
- if y.v == nil {
- return y
- }
- return e.evalBinaryOp(n.Op, x, y)
- }
- return e.err("invalid expression")
-}
-
-// evalBinaryOp evaluates a binary operator op applied to x and y.
-func (e *evaluator) evalBinaryOp(op token.Token, x, y result) result {
- if op == token.NEQ {
- tmp := e.evalBinaryOp(token.EQL, x, y)
- b, ok := tmp.v.(bool)
- if !ok {
- return tmp
- }
- return result{nil, !b}
- }
- if op == token.GTR {
- return e.evalBinaryOp(token.LSS, y, x)
- }
- if op == token.GEQ {
- return e.evalBinaryOp(token.LEQ, x, y)
- }
-
- x = convertUntyped(x, y)
- y = convertUntyped(y, x)
-
- switch a := x.v.(type) {
-
- case int8:
- b, ok := y.v.(int8)
- if !ok {
- return e.err("type mismatch")
- }
- var c int8
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case int16:
- b, ok := y.v.(int16)
- if !ok {
- return e.err("type mismatch")
- }
- var c int16
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case int32:
- b, ok := y.v.(int32)
- if !ok {
- return e.err("type mismatch")
- }
- var c int32
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case int64:
- b, ok := y.v.(int64)
- if !ok {
- return e.err("type mismatch")
- }
- var c int64
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case uint8:
- b, ok := y.v.(uint8)
- if !ok {
- return e.err("type mismatch")
- }
- var c uint8
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case uint16:
- b, ok := y.v.(uint16)
- if !ok {
- return e.err("type mismatch")
- }
- var c uint16
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case uint32:
- b, ok := y.v.(uint32)
- if !ok {
- return e.err("type mismatch")
- }
- var c uint32
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case uint64:
- b, ok := y.v.(uint64)
- if !ok {
- return e.err("type mismatch")
- }
- var c uint64
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case float32:
- b, ok := y.v.(float32)
- if !ok {
- return e.err("type mismatch")
- }
- var c float32
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.MUL:
- c = a * b
- case token.QUO:
- c = a / b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case float64:
- b, ok := y.v.(float64)
- if !ok {
- return e.err("type mismatch")
- }
- var c float64
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.MUL:
- c = a * b
- case token.QUO:
- c = a / b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case complex64:
- b, ok := y.v.(complex64)
- if !ok {
- return e.err("type mismatch")
- }
- var c complex64
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.MUL:
- c = a * b
- case token.QUO:
- c = a / b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case complex128:
- b, ok := y.v.(complex128)
- if !ok {
- return e.err("type mismatch")
- }
- var c complex128
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.MUL:
- c = a * b
- case token.QUO:
- c = a / b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case bool:
- b, ok := y.v.(bool)
- if !ok {
- return e.err("type mismatch")
- }
- var c bool
- switch op {
- case token.LOR:
- c = a || b
- case token.LAND:
- c = a && b
- case token.EQL:
- c = a == b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case debug.String:
- b, ok := y.v.(debug.String)
- if !ok {
- return e.err("type mismatch")
- }
- var c debug.String
- switch op {
- // TODO: these comparison operators only use the part of the string that
- // was read. Very large strings do not have their entire contents read by
- // server.value.
- case token.EQL:
- return result{nil, a.Length == b.Length && a.String == b.String}
- case token.LSS:
- return result{nil, a.String < b.String}
- case token.LEQ:
- return result{nil, a.String <= b.String}
- case token.ADD:
- c.Length = a.Length + b.Length
- if a.Length == uint64(len(a.String)) {
- c.String = a.String + b.String
- } else {
- // The first string was truncated at a.Length characters, so the sum
- // must be truncated there too.
- c.String = a.String
- }
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case untString:
- b, ok := y.v.(untString)
- if !ok {
- return e.err("type mismatch")
- }
- var c untString
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case untInt:
- i := a.Int
- b, ok := y.v.(untInt)
- if !ok {
- return e.err("type mismatch")
- }
- switch op {
- case token.EQL:
- return result{nil, i.Cmp(b.Int) == 0}
- case token.LSS:
- return result{nil, i.Cmp(b.Int) < 0}
- case token.LEQ:
- return result{nil, i.Cmp(b.Int) <= 0}
- }
- c := new(big.Int)
- switch op {
- case token.ADD:
- c.Add(i, b.Int)
- case token.SUB:
- c.Sub(i, b.Int)
- case token.OR:
- c.Or(i, b.Int)
- case token.XOR:
- c.Xor(i, b.Int)
- case token.MUL:
- c.Mul(i, b.Int)
- case token.QUO:
- if b.Sign() == 0 {
- return e.err("integer divide by zero")
- }
- c.Quo(i, b.Int)
- case token.REM:
- if b.Sign() == 0 {
- return e.err("integer divide by zero")
- }
- c.Mod(i, b.Int)
- case token.AND:
- c.And(i, b.Int)
- case token.AND_NOT:
- c.AndNot(i, b.Int)
- default:
- return e.err("invalid operation")
- }
- return result{nil, untInt{c}}
-
- case untRune:
- i := a.Int
- b, ok := y.v.(untRune)
- if !ok {
- return e.err("type mismatch")
- }
- switch op {
- case token.EQL:
- return result{nil, i.Cmp(b.Int) == 0}
- case token.LSS:
- return result{nil, i.Cmp(b.Int) < 0}
- case token.LEQ:
- return result{nil, i.Cmp(b.Int) <= 0}
- }
- c := new(big.Int)
- switch op {
- case token.ADD:
- c.Add(i, b.Int)
- case token.SUB:
- c.Sub(i, b.Int)
- case token.OR:
- c.Or(i, b.Int)
- case token.XOR:
- c.Xor(i, b.Int)
- case token.MUL:
- c.Mul(i, b.Int)
- case token.QUO:
- if b.Sign() == 0 {
- return e.err("integer divide by zero")
- }
- c.Quo(i, b.Int)
- case token.REM:
- if b.Sign() == 0 {
- return e.err("integer divide by zero")
- }
- c.Mod(i, b.Int)
- case token.AND:
- c.And(i, b.Int)
- case token.AND_NOT:
- c.AndNot(i, b.Int)
- default:
- return e.err("invalid operation")
- }
- return result{nil, untRune{c}}
-
- case untFloat:
- r := a.Float
- b, ok := y.v.(untFloat)
- if !ok {
- return e.err("type mismatch")
- }
- switch op {
- case token.EQL:
- return result{nil, r.Cmp(b.Float) == 0}
- case token.LSS:
- return result{nil, r.Cmp(b.Float) < 0}
- case token.LEQ:
- return result{nil, r.Cmp(b.Float) <= 0}
- }
- c := new(big.Float)
- switch op {
- case token.ADD:
- c.Add(r, b.Float)
- case token.SUB:
- c.Sub(r, b.Float)
- case token.MUL:
- c.Mul(r, b.Float)
- case token.QUO:
- if b.Sign() == 0 {
- return e.err("divide by zero")
- }
- c.Quo(r, b.Float)
- default:
- return e.err("invalid operation")
- }
- return result{nil, untFloat{c}}
-
- case untComplex:
- b, ok := y.v.(untComplex)
- if !ok {
- return e.err("type mismatch")
- }
- var (
- ar = a.r
- br = b.r
- ai = a.i
- bi = b.i
- )
- if op == token.EQL {
- return result{nil, ar.Cmp(br) == 0 && ai.Cmp(bi) == 0}
- }
- var (
- cr = new(big.Float)
- ci = new(big.Float)
- )
- switch op {
- case token.ADD:
- cr.Add(ar, br)
- ci.Add(ai, bi)
- case token.SUB:
- cr.Sub(ar, br)
- ci.Sub(ai, bi)
- case token.MUL:
- var t0, t1 big.Float
- t0.Mul(ar, br)
- t1.Mul(ai, bi)
- cr.Sub(&t0, &t1)
- t0.Mul(ar, bi)
- t1.Mul(ai, br)
- ci.Add(&t0, &t1)
- case token.QUO:
- // a/b = a*conj(b)/|b|^2
- var t0, t1 big.Float
- cr.Mul(ar, br)
- t0.Mul(ai, bi)
- cr.Add(cr, &t0) // cr = Re(a*conj(b))
- ci.Mul(ai, br)
- t0.Mul(ar, bi)
- ci.Sub(ci, &t0) // ci = Im(a*conj(b))
- t0.Mul(br, br)
- t1.Mul(bi, bi)
- t0.Add(&t0, &t1) // t0 = |b|^2
- if t0.Sign() == 0 {
- return e.err("divide by zero")
- }
- cr.Quo(cr, &t0) // cr = Re(a*conj(b))/|b|^2 = Re(a/b)
- ci.Quo(ci, &t0) // ci = Im(a*conj(b))/|b|^2 = Im(a/b)
- }
- return result{nil, untComplex{cr, ci}}
- }
-
- return e.err("invalid operation")
-}
-
-// findLocalVar finds a local variable (or function parameter) by name, and
-// returns its address and DWARF type. It returns a nil type on failure.
-// The PC and SP are used to determine the current function and stack frame.
-func (s *Server) findLocalVar(name string, pc, sp uint64) (uint64, dwarf.Type) {
- // Find the DWARF entry for the function at pc.
- funcEntry, _, err := s.dwarfData.PCToFunction(uint64(pc))
- if err != nil {
- return 0, nil
- }
-
- // Compute the stack frame pointer.
- fpOffset, err := s.dwarfData.PCToSPOffset(uint64(pc))
- if err != nil {
- return 0, nil
- }
- framePointer := sp + uint64(fpOffset)
-
- // Check each child of the function's DWARF entry to see if it is a parameter
- // or local variable with the right name. If so, return its address and type.
- r := s.dwarfData.Reader()
- r.Seek(funcEntry.Offset)
- for {
- varEntry, err := r.Next()
- if err != nil {
- break
- }
- if varEntry.Tag == 0 {
- // This tag marks the end of the function's DWARF entry's children.
- break
- }
-
- // Check this entry corresponds to a local variable or function parameter,
- // that it has the correct name, and that we can get its type and location.
- // If so, return them.
- if varEntry.Tag != dwarf.TagFormalParameter && varEntry.Tag != dwarf.TagVariable {
- continue
- }
- varName, ok := varEntry.Val(dwarf.AttrName).(string)
- if !ok {
- continue
- }
- if varName != name {
- continue
- }
- varTypeOffset, ok := varEntry.Val(dwarf.AttrType).(dwarf.Offset)
- if !ok {
- continue
- }
- varType, err := s.dwarfData.Type(varTypeOffset)
- if err != nil {
- continue
- }
- locationAttribute := varEntry.Val(dwarf.AttrLocation)
- if locationAttribute == nil {
- continue
- }
- locationDescription, ok := locationAttribute.([]uint8)
- if !ok {
- continue
- }
- frameOffset, err := evalLocation(locationDescription)
- if err != nil {
- continue
- }
- return framePointer + uint64(frameOffset), varType
- }
-
- return 0, nil
-}
-
-// findGlobalVar finds a global variable by name, and returns its address and
-// DWARF type. It returns a nil type on failure.
-func (s *Server) findGlobalVar(name string) (uint64, dwarf.Type) {
- entry, err := s.dwarfData.LookupVariable(name)
- if err != nil {
- return 0, nil
- }
- loc, err := s.dwarfData.EntryLocation(entry)
- if err != nil {
- return 0, nil
- }
- ofs, err := s.dwarfData.EntryTypeOffset(entry)
- if err != nil {
- return 0, nil
- }
- typ, err := s.dwarfData.Type(ofs)
- if err != nil {
- return 0, nil
- }
- return loc, typ
-}
-
-// intFromInteger converts an untyped integer constant to an int32 or int64,
-// depending on the int size of the debugged program.
-// It returns an error on overflow, or if it can't determine the int size.
-func (e *evaluator) intFromInteger(v untInt) (interface{}, error) {
- t, ok := e.getBaseType("int")
- if !ok {
- return nil, errors.New("couldn't get int size from DWARF info")
- }
- switch t.Common().ByteSize {
- case 4:
- if v.Cmp(bigIntMaxInt32) == +1 || v.Cmp(bigIntMinInt32) == -1 {
- return nil, errors.New("constant overflows int")
- }
- return int32(v.Int64()), nil
- case 8:
- if v.Cmp(bigIntMaxInt64) == +1 || v.Cmp(bigIntMinInt64) == -1 {
- return nil, errors.New("constant overflows int")
- }
- return v.Int64(), nil
- }
- return nil, errors.New("invalid int size in DWARF info")
-}
-
-// uint8Result constructs a result for a uint8 value.
-func (e *evaluator) uint8Result(v uint8) result {
- t, ok := e.getBaseType("uint8")
- if !ok {
- e.err("couldn't construct uint8")
- }
- return result{t, uint8(v)}
-}
-
-// stringResult constructs a result for a string value.
-func (e *evaluator) stringResult(s string) result {
- t, ok := e.getBaseType("string")
- if !ok {
- e.err("couldn't construct string")
- }
- return result{t, debug.String{Length: uint64(len(s)), String: s}}
-}
-
-// getBaseType returns the *dwarf.Type with a given name.
-// TODO: cache this.
-func (e *evaluator) getBaseType(name string) (dwarf.Type, bool) {
- entry, err := e.server.dwarfData.LookupEntry(name)
- if err != nil {
- return nil, false
- }
- t, err := e.server.dwarfData.Type(entry.Offset)
- if err != nil {
- return nil, false
- }
- return t, true
-}
-
-// resultFrom constructs a result corresponding to a value in the program with
-// the given address and DWARF type.
-// If getAddress is true, the result will be the operand of an address expression,
-// so resultFrom returns a result containing a value of type addressableValue.
-func (e *evaluator) resultFrom(a uint64, t dwarf.Type, getAddress bool) result {
- if a == 0 {
- return e.err("nil pointer dereference")
- }
- if getAddress {
- return result{t, addressableValue{a}}
- }
- v, err := e.server.value(t, a)
- if err != nil {
- return e.err(err.Error())
- }
- return result{t, v}
-}
-
-// zero returns the zero value of type t.
-// TODO: implement for array and struct.
-func (e *evaluator) zero(t dwarf.Type) result {
- var v interface{}
- switch typ := followTypedefs(t).(type) {
- case *dwarf.CharType, *dwarf.IntType, *dwarf.EnumType:
- switch typ.Common().ByteSize {
- case 1:
- v = int8(0)
- case 2:
- v = int16(0)
- case 4:
- v = int32(0)
- case 8:
- v = int64(0)
- default:
- return e.err("invalid integer size " + fmt.Sprint(typ.Common().ByteSize))
- }
- case *dwarf.UcharType, *dwarf.UintType:
- switch typ.Common().ByteSize {
- case 1:
- v = uint8(0)
- case 2:
- v = uint16(0)
- case 4:
- v = uint32(0)
- case 8:
- v = uint64(0)
- default:
- return e.err("invalid unsigned integer size " + fmt.Sprint(typ.Common().ByteSize))
- }
- case *dwarf.FloatType:
- switch typ.Common().ByteSize {
- case 4:
- v = float32(0)
- case 8:
- v = float64(0)
- default:
- return e.err("invalid float size " + fmt.Sprint(typ.Common().ByteSize))
- }
- case *dwarf.ComplexType:
- switch typ.Common().ByteSize {
- case 8:
- v = complex64(0)
- case 16:
- v = complex128(0)
- default:
- return e.err("invalid complex size " + fmt.Sprint(typ.Common().ByteSize))
- }
- case *dwarf.BoolType:
- v = false
- case *dwarf.PtrType:
- v = debug.Pointer{TypeID: uint64(t.Common().Offset)}
- case *dwarf.SliceType:
- v = debug.Slice{
- Array: debug.Array{
- ElementTypeID: uint64(typ.ElemType.Common().Offset),
- StrideBits: uint64(typ.ElemType.Common().ByteSize) * 8,
- },
- }
- case *dwarf.StringType:
- v = debug.String{}
- case *dwarf.InterfaceType:
- v = debug.Interface{}
- case *dwarf.FuncType:
- v = debug.Func{}
- case *dwarf.MapType:
- v = debug.Map{TypeID: uint64(t.Common().Offset)}
- case *dwarf.ChanType:
- v = debug.Channel{
- ElementTypeID: uint64(typ.ElemType.Common().Offset),
- Stride: uint64(typ.ElemType.Common().ByteSize),
- }
- default:
- return e.err("can't get zero value of this type")
- }
- return result{t, v}
-}
-
-// convertUntyped converts x to be the same type as y, if x is untyped and the
-// conversion is possible.
-//
-// An untyped bool can be converted to a boolean type.
-// An untyped string can be converted to a string type.
-// An untyped integer, rune, float or complex value can be converted to a
-// numeric type, or to an untyped value later in that list.
-//
-// x is returned unchanged if none of these cases apply.
-func convertUntyped(x, y result) result {
- switch a := x.v.(type) {
- case untInt:
- i := a.Int
- switch y.v.(type) {
- case int8:
- return result{y.d, int8(i.Int64())}
- case int16:
- return result{y.d, int16(i.Int64())}
- case int32:
- return result{y.d, int32(i.Int64())}
- case int64:
- return result{y.d, int64(i.Int64())}
- case uint8:
- return result{y.d, uint8(i.Uint64())}
- case uint16:
- return result{y.d, uint16(i.Uint64())}
- case uint32:
- return result{y.d, uint32(i.Uint64())}
- case uint64:
- return result{y.d, uint64(i.Uint64())}
- case float32:
- f, _ := new(big.Float).SetInt(i).Float32()
- return result{y.d, f}
- case float64:
- f, _ := new(big.Float).SetInt(i).Float64()
- return result{y.d, f}
- case complex64:
- f, _ := new(big.Float).SetInt(i).Float32()
- return result{y.d, complex(f, 0)}
- case complex128:
- f, _ := new(big.Float).SetInt(i).Float64()
- return result{y.d, complex(f, 0)}
- case untRune:
- return result{nil, untRune{i}}
- case untFloat:
- return result{nil, untFloat{new(big.Float).SetPrec(prec).SetInt(i)}}
- case untComplex:
- return result{nil, untComplex{new(big.Float).SetPrec(prec).SetInt(i), new(big.Float)}}
- }
- case untRune:
- i := a.Int
- switch y.v.(type) {
- case int8:
- return result{y.d, int8(i.Int64())}
- case int16:
- return result{y.d, int16(i.Int64())}
- case int32:
- return result{y.d, int32(i.Int64())}
- case int64:
- return result{y.d, int64(i.Int64())}
- case uint8:
- return result{y.d, uint8(i.Uint64())}
- case uint16:
- return result{y.d, uint16(i.Uint64())}
- case uint32:
- return result{y.d, uint32(i.Uint64())}
- case uint64:
- return result{y.d, uint64(i.Uint64())}
- case float32:
- f, _ := new(big.Float).SetInt(i).Float32()
- return result{y.d, f}
- case float64:
- f, _ := new(big.Float).SetInt(i).Float64()
- return result{y.d, f}
- case complex64:
- f, _ := new(big.Float).SetInt(i).Float32()
- return result{y.d, complex(f, 0)}
- case complex128:
- f, _ := new(big.Float).SetInt(i).Float64()
- return result{y.d, complex(f, 0)}
- case untRune:
- return result{nil, untRune{i}}
- case untFloat:
- return result{nil, untFloat{new(big.Float).SetPrec(prec).SetInt(i)}}
- case untComplex:
- return result{nil, untComplex{new(big.Float).SetPrec(prec).SetInt(i), new(big.Float)}}
- }
- case untFloat:
- if a.IsInt() {
- i, _ := a.Int(nil)
- switch y.v.(type) {
- case int8:
- return result{y.d, int8(i.Int64())}
- case int16:
- return result{y.d, int16(i.Int64())}
- case int32:
- return result{y.d, int32(i.Int64())}
- case int64:
- return result{y.d, int64(i.Int64())}
- case uint8:
- return result{y.d, uint8(i.Uint64())}
- case uint16:
- return result{y.d, uint16(i.Uint64())}
- case uint32:
- return result{y.d, uint32(i.Uint64())}
- case uint64:
- return result{y.d, uint64(i.Uint64())}
- }
- }
- switch y.v.(type) {
- case float32:
- f, _ := a.Float32()
- return result{y.d, float32(f)}
- case float64:
- f, _ := a.Float64()
- return result{y.d, float64(f)}
- case complex64:
- f, _ := a.Float32()
- return result{y.d, complex(f, 0)}
- case complex128:
- f, _ := a.Float64()
- return result{y.d, complex(f, 0)}
- case untComplex:
- return result{nil, untComplex{a.Float, new(big.Float)}}
- }
- case untComplex:
- if a.i.Sign() == 0 {
- // a is a real number.
- if a.r.IsInt() {
- // a is an integer.
- i, _ := a.r.Int(nil)
- switch y.v.(type) {
- case int8:
- return result{y.d, int8(i.Int64())}
- case int16:
- return result{y.d, int16(i.Int64())}
- case int32:
- return result{y.d, int32(i.Int64())}
- case int64:
- return result{y.d, int64(i.Int64())}
- case uint8:
- return result{y.d, uint8(i.Uint64())}
- case uint16:
- return result{y.d, uint16(i.Uint64())}
- case uint32:
- return result{y.d, uint32(i.Uint64())}
- case uint64:
- return result{y.d, uint64(i.Uint64())}
- }
- }
- switch y.v.(type) {
- case float32:
- f, _ := a.r.Float32()
- return result{y.d, float32(f)}
- case float64:
- f, _ := a.r.Float64()
- return result{y.d, float64(f)}
- }
- }
- switch y.v.(type) {
- case complex64:
- r, _ := a.r.Float32()
- i, _ := a.i.Float32()
- return result{y.d, complex(r, i)}
- case complex128:
- r, _ := a.r.Float64()
- i, _ := a.i.Float64()
- return result{y.d, complex(r, i)}
- }
- case bool:
- if x.d != nil {
- // x is a typed bool, not an untyped bool.
- break
- }
- switch y.v.(type) {
- case bool:
- return result{y.d, bool(a)}
- }
- case untString:
- switch y.v.(type) {
- case debug.String:
- return result{y.d, debug.String{Length: uint64(len(a)), String: string(a)}}
- }
- }
- return x
-}
-
-// uint64FromResult converts a result into a uint64 for slice or index expressions.
-// It returns an error if the conversion cannot be done.
-func uint64FromResult(x result) (uint64, error) {
- switch v := x.v.(type) {
- case int8:
- if v < 0 {
- return 0, errors.New("value is negative")
- }
- return uint64(v), nil
- case int16:
- if v < 0 {
- return 0, errors.New("value is negative")
- }
- return uint64(v), nil
- case int32:
- if v < 0 {
- return 0, errors.New("value is negative")
- }
- return uint64(v), nil
- case int64:
- if v < 0 {
- return 0, errors.New("value is negative")
- }
- return uint64(v), nil
- case uint8:
- return uint64(v), nil
- case uint16:
- return uint64(v), nil
- case uint32:
- return uint64(v), nil
- case uint64:
- return v, nil
- case untInt:
- if v.Int.Sign() == -1 {
- return 0, errors.New("value is negative")
- }
- if v.Int.Cmp(bigIntMaxUint64) == +1 {
- return 0, errors.New("value is too large")
- }
- return v.Int.Uint64(), nil
- case untRune:
- if v.Sign() == -1 {
- return 0, errors.New("value is negative")
- }
- if v.Cmp(bigIntMaxUint64) == +1 {
- return 0, errors.New("value is too large")
- }
- return v.Uint64(), nil
- case untFloat:
- if !v.IsInt() {
- return 0, errors.New("value is not an integer")
- }
- if v.Sign() == -1 {
- return 0, errors.New("value is negative")
- }
- i, _ := v.Int(nil)
- if i.Cmp(bigIntMaxUint64) == +1 {
- return 0, errors.New("value is too large")
- }
- return i.Uint64(), nil
- case untComplex:
- if v.i.Sign() != 0 {
- return 0, errors.New("value is complex")
- }
- if !v.r.IsInt() {
- return 0, errors.New("value is not an integer")
- }
- if v.r.Sign() == -1 {
- return 0, errors.New("value is negative")
- }
- i, _ := v.r.Int(nil)
- if i.Cmp(bigIntMaxUint64) == +1 {
- return 0, errors.New("value is too large")
- }
- return i.Uint64(), nil
- }
- return 0, fmt.Errorf("cannot convert to unsigned integer")
-}
-
-// followTypedefs returns the underlying type of t, removing any typedefs.
-// If t leads to a cycle of typedefs, followTypedefs returns nil.
-func followTypedefs(t dwarf.Type) dwarf.Type {
- // If t is a *dwarf.TypedefType, next returns t.Type, otherwise it returns t.
- // The bool returned is true when the argument was a typedef.
- next := func(t dwarf.Type) (dwarf.Type, bool) {
- tt, ok := t.(*dwarf.TypedefType)
- if !ok {
- return t, false
- }
- return tt.Type, true
- }
- // Advance two pointers, one at twice the speed, so we can detect if we get
- // stuck in a cycle.
- slow, fast := t, t
- for {
- var wasTypedef bool
- fast, wasTypedef = next(fast)
- if !wasTypedef {
- return fast
- }
- fast, wasTypedef = next(fast)
- if !wasTypedef {
- return fast
- }
- slow, _ = next(slow)
- if slow == fast {
- return nil
- }
- }
-}
diff --git a/server/eval.m4 b/server/eval.m4
deleted file mode 100644
index 7b7594a..0000000
--- a/server/eval.m4
+++ /dev/null
@@ -1,1711 +0,0 @@
-// Copyright 2015 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.
-//m4_changequote(`@',`@')
-// Evaluates Go expressions, using the current values of variables in a program
-// being debugged.
-//
-// TODOs:
-// More overflow checking.
-// Stricter type checking.
-// More expression types.
-
-package server
-
-import (
- "errors"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "math"
- "math/big"
-
- "golang.org/x/debug"
- "golang.org/x/debug/dwarf"
-)
-
-const prec = 256 // precision for untyped float and complex constants.
-
-var (
- // Some big.Ints to use in overflow checks.
- bigIntMaxInt32 = big.NewInt(math.MaxInt32)
- bigIntMinInt32 = big.NewInt(math.MinInt32)
- bigIntMaxInt64 = big.NewInt(math.MaxInt64)
- bigIntMinInt64 = big.NewInt(math.MinInt64)
- bigIntMaxUint64 = new(big.Int).SetUint64(math.MaxUint64)
-)
-
-// result stores an intermediate value produced during evaluation of an expression.
-//
-// d contains the DWARF type of the value. For untyped values, d will be nil.
-//
-// v contains the value itself. For numeric and bool types, v will have the
-// corresponding predeclared Go type.
-// For untyped integer, rune, float, complex, string, and bool constants, v will
-// have type untInt, untRune, untFloat, untComplex, untString, or bool,
-// respectively.
-// For values of type int, uint and uintptr, v will be an int32, int64, uint32
-// or uint64 as appropriate.
-// For address operations, v will have type pointerToValue.
-// For the operands of address operations, v will have type addressableValue.
-// Other types are represented using the corresponding implementation of
-// debug.Value in program.go.
-//
-// If an evaluation results in an error, the zero value of result is used.
-type result struct {
- d dwarf.Type
- v interface{}
-}
-
-// untInt is an untyped integer constant
-type untInt struct {
- *big.Int
-}
-
-// untRune is an untyped rune constant
-type untRune struct {
- *big.Int
-}
-
-// untFloat is an untyped floating-point constant
-type untFloat struct {
- *big.Float
-}
-
-// untComplex is an untyped complex constant
-type untComplex struct {
- r *big.Float
- i *big.Float
-}
-
-// untString is an untyped string constant
-type untString string
-
-// pointerToValue is a pointer to a value in memory.
-// The evaluator constructs these as the result of address operations like "&x".
-// Unlike debug.Pointer, the DWARF type stored alongside values of this type
-// is the type of the variable, not the type of the pointer.
-type pointerToValue struct {
- a uint64
-}
-
-// addressableValue is the memory location of a value.
-// The evaluator constructs these while evaluating the operands of address
-// operations like "&x", instead of computing the value of x itself.
-type addressableValue struct {
- a uint64
-}
-
-// A sliceOf is a slice created by slicing an array.
-// Unlike debug.Slice, the DWARF type stored alongside a value of this type is
-// the type of the slice's elements, not the type of the slice.
-type sliceOf debug.Slice
-
-// ident is a value for representing a special identifier.
-type ident string
-
-// identLookup is a built-in function of the expression evaluator which gets the
-// value of a global symbol.
-var identLookup ident = "lookup"
-
-// evalExpression evaluates a Go expression.
-// If the program counter and stack pointer are nonzero, they are used to determine
-// what local variables are available and where in memory they are.
-func (s *Server) evalExpression(expression string, pc, sp uint64) (debug.Value, error) {
- e := evaluator{server: s, expression: expression, pc: pc, sp: sp}
- node, err := parser.ParseExpr(expression)
- if err != nil {
- return nil, err
- }
- val := e.evalNode(node, false)
- if e.evalError != nil {
- return nil, e.evalError
- }
-
- // Convert untyped constants to their default types.
- switch v := val.v.(type) {
- case untInt:
- return e.intFromInteger(v)
- case untRune:
- if v.Cmp(bigIntMaxInt32) == +1 {
- return nil, errors.New("constant overflows rune")
- }
- if v.Cmp(bigIntMinInt32) == -1 {
- return nil, errors.New("constant overflows rune")
- }
- return int32(v.Int64()), nil
- case untFloat:
- f, _ := v.Float64()
- if math.IsInf(f, 0) {
- return nil, errors.New("constant overflows float64")
- }
- if math.IsNaN(f) {
- return nil, errors.New("constant is NaN")
- }
- return f, nil
- case untComplex:
- r, _ := v.r.Float64()
- i, _ := v.i.Float64()
- if math.IsInf(r, 0) || math.IsInf(i, 0) {
- return nil, errors.New("constant overflows complex128")
- }
- if math.IsNaN(r) || math.IsNaN(i) {
- return nil, errors.New("constant is NaN")
- }
- return complex(r, i), nil
- case untString:
- return debug.String{Length: uint64(len(v)), String: string(v)}, nil
- case pointerToValue:
- return debug.Pointer{TypeID: uint64(val.d.Common().Offset), Address: v.a}, nil
- case sliceOf:
- return debug.Slice(v), nil
- case nil, addressableValue:
- // This case should not be reachable.
- return nil, errors.New("unknown error")
- }
- return val.v, nil
-}
-
-type evaluator struct {
- // expression is the expression being evaluated.
- expression string
- // server interacts with the program being debugged.
- server *Server
- // curNode is the current parse tree node. This is set so that error messages
- // can quote the part of the expression that caused an error.
- curNode ast.Node
- // evalError is the first error that occurred while evaluating the expression,
- // or nil if no error has occurred.
- evalError error
- // pc and sp are the current program counter and stack pointer, used for
- // finding local variables. If either are zero, the expression is evaluated
- // without using local variables.
- pc uint64
- sp uint64
-}
-
-// setNode sets curNode, and returns curNode's previous value.
-func (e *evaluator) setNode(node ast.Node) (old ast.Node) {
- old, e.curNode = e.curNode, node
- return old
-}
-
-// err saves an error that occurred during evaluation.
-// It returns a zero result, so that functions can exit and set an error with
-// return e.err(...)
-func (e *evaluator) err(s string) result {
- if e.evalError != nil {
- return result{}
- }
- // Append the substring of the expression that corresponds to the current AST node.
- start := int(e.curNode.Pos() - 1)
- end := int(e.curNode.End() - 1)
- if start < 0 {
- start = 0
- }
- if end > len(e.expression) {
- end = len(e.expression)
- }
- if start > end {
- start, end = 0, 0
- }
- e.evalError = errors.New(s + `: "` + e.expression[start:end] + `"`)
- return result{}
-}
-
-// evalNode computes the value of a node in the expression tree.
-// If getAddress is true, the node is the argument of an & operator, so evalNode
-// will return a result with a value of type addressableValue if possible.
-func (e *evaluator) evalNode(node ast.Node, getAddress bool) result {
- // Set the current node in the evaluator, so that error messages can refer to
- // it. Defer a function call that changes it back.
- defer e.setNode(e.setNode(node))
-
- switch n := node.(type) {
- case *ast.Ident:
- if e.pc != 0 && e.sp != 0 {
- a, t := e.server.findLocalVar(n.Name, e.pc, e.sp)
- if t != nil {
- return e.resultFrom(a, t, getAddress)
- }
- }
- a, t := e.server.findGlobalVar(n.Name)
- if t != nil {
- return e.resultFrom(a, t, getAddress)
- }
- switch n.Name {
- // Note: these could have been redefined as constants in the code, but we
- // don't have a way to detect that.
- case "true":
- return result{nil, true}
- case "false":
- return result{nil, false}
- case "lookup":
- return result{nil, identLookup}
- }
- return e.err("unknown identifier")
-
- case *ast.BasicLit:
- switch n.Kind {
- case token.INT:
- i := new(big.Int)
- if _, ok := i.SetString(n.Value, 0); !ok {
- return e.err("invalid integer constant")
- }
- return result{nil, untInt{i}}
- case token.FLOAT:
- r, _, err := big.ParseFloat(n.Value, 10, prec, big.ToNearestEven)
- if err != nil {
- return e.err(err.Error())
- }
- return result{nil, untFloat{r}}
- case token.IMAG:
- if len(n.Value) <= 1 || n.Value[len(n.Value)-1] != 'i' {
- return e.err("invalid imaginary constant")
- }
- r, _, err := big.ParseFloat(n.Value[:len(n.Value)-1], 10, prec, big.ToNearestEven)
- if err != nil {
- return e.err(err.Error())
- }
- return result{nil, untComplex{new(big.Float), r}}
- case token.CHAR:
- // TODO: unescaping
- return result{nil, untRune{new(big.Int).SetInt64(int64(n.Value[1]))}}
- case token.STRING:
- // TODO: unescaping
- if len(n.Value) <= 1 {
- return e.err("invalid string constant")
- }
- return result{nil, untString(n.Value[1 : len(n.Value)-1])}
- }
-
- case *ast.ParenExpr:
- return e.evalNode(n.X, getAddress)
-
- case *ast.StarExpr:
- x := e.evalNode(n.X, false)
- switch v := x.v.(type) {
- case debug.Pointer:
- // x.d may be a typedef pointing to a pointer type (or a typedef pointing
- // to a typedef pointing to a pointer type, etc.), so remove typedefs
- // until we get the underlying pointer type.
- t := followTypedefs(x.d)
- if pt, ok := t.(*dwarf.PtrType); ok {
- return e.resultFrom(v.Address, pt.Type, getAddress)
- } else {
- return e.err("invalid DWARF type for pointer")
- }
- case pointerToValue:
- return e.resultFrom(v.a, x.d, getAddress)
- case nil:
- return x
- }
- return e.err("invalid indirect")
-
- case *ast.SelectorExpr:
- x := e.evalNode(n.X, false)
- sel := n.Sel.Name
- switch v := x.v.(type) {
- case debug.Struct:
- for _, f := range v.Fields {
- if f.Name == sel {
- t, err := e.server.dwarfData.Type(dwarf.Offset(f.Var.TypeID))
- if err != nil {
- return e.err(err.Error())
- }
- return e.resultFrom(f.Var.Address, t, getAddress)
- }
- }
- return e.err("struct field not found")
- case debug.Pointer:
- pt, ok := followTypedefs(x.d).(*dwarf.PtrType) // x.d should be a pointer to struct.
- if !ok {
- return e.err("invalid DWARF information for pointer")
- }
- st, ok := followTypedefs(pt.Type).(*dwarf.StructType)
- if !ok {
- break
- }
- for _, f := range st.Field {
- if f.Name == sel {
- return e.resultFrom(v.Address+uint64(f.ByteOffset), f.Type, getAddress)
- }
- }
- return e.err("struct field not found")
- case pointerToValue:
- st, ok := followTypedefs(x.d).(*dwarf.StructType) // x.d should be a struct.
- if !ok {
- break
- }
- for _, f := range st.Field {
- if f.Name == sel {
- return e.resultFrom(v.a+uint64(f.ByteOffset), f.Type, getAddress)
- }
- }
- return e.err("struct field not found")
- }
- return e.err("invalid selector expression")
-
- case *ast.IndexExpr:
- x, index := e.evalNode(n.X, false), e.evalNode(n.Index, false)
- if x.v == nil || index.v == nil {
- return result{}
- }
- // The expression is x[index]
- if m, ok := x.v.(debug.Map); ok {
- if getAddress {
- return e.err("can't take address of map value")
- }
- mt, ok := followTypedefs(x.d).(*dwarf.MapType)
- if !ok {
- return e.err("invalid DWARF type for map")
- }
- var (
- found bool // true if the key was found
- value result // the map value for the key
- abort bool // true if an error occurred while searching
- // fn is a function that checks if one (key, value) pair corresponds
- // to the index in the expression.
- fn = func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool {
- key := e.resultFrom(keyAddr, keyType, false)
- if key.v == nil {
- abort = true
- return false // stop searching map
- }
- equal, ok := e.evalBinaryOp(token.EQL, index, key).v.(bool)
- if !ok {
- abort = true
- return false // stop searching map
- }
- if equal {
- found = true
- value = e.resultFrom(valAddr, valType, false)
- return false // stop searching map
- }
- return true // continue searching map
- }
- )
- if err := e.server.peekMapValues(mt, m.Address, fn); err != nil {
- return e.err(err.Error())
- }
- if abort {
- // Some operation on individual map keys failed.
- return result{}
- }
- if found {
- return value
- }
- // The key wasn't in the map; return the zero value.
- return e.zero(mt.ElemType)
- }
-
- // The index should be a non-negative integer for the remaining cases.
- u, err := uint64FromResult(index)
- if err != nil {
- return e.err("invalid index: " + err.Error())
- }
- switch v := x.v.(type) {
- case debug.Array:
- if u >= v.Length {
- return e.err("array index out of bounds")
- }
- elemType, err := e.server.dwarfData.Type(dwarf.Offset(v.ElementTypeID))
- if err != nil {
- return e.err(err.Error())
- }
- return e.resultFrom(v.Element(u).Address, elemType, getAddress)
- case debug.Slice:
- if u >= v.Length {
- return e.err("slice index out of bounds")
- }
- elemType, err := e.server.dwarfData.Type(dwarf.Offset(v.ElementTypeID))
- if err != nil {
- return e.err(err.Error())
- }
- return e.resultFrom(v.Element(u).Address, elemType, getAddress)
- case sliceOf:
- if u >= v.Length {
- return e.err("slice index out of bounds")
- }
- return e.resultFrom(v.Element(u).Address, x.d, getAddress)
- case debug.String:
- if getAddress {
- return e.err("can't take address of string element")
- }
- if u >= v.Length {
- return e.err("string index out of bounds")
- }
- if u >= uint64(len(v.String)) {
- return e.err("string element unavailable")
- }
- return e.uint8Result(v.String[u])
- case untString:
- if getAddress {
- return e.err("can't take address of string element")
- }
- if u >= uint64(len(v)) {
- return e.err("string index out of bounds")
- }
- return e.uint8Result(v[u])
- }
- return e.err("invalid index expression")
-
- case *ast.SliceExpr:
- if n.Slice3 && n.High == nil {
- return e.err("middle index required in full slice")
- }
- if n.Slice3 && n.Max == nil {
- return e.err("final index required in full slice")
- }
- var (
- low, high, max uint64
- err error
- )
- if n.Low != nil {
- low, err = uint64FromResult(e.evalNode(n.Low, false))
- if err != nil {
- return e.err("invalid slice lower bound: " + err.Error())
- }
- }
- if n.High != nil {
- high, err = uint64FromResult(e.evalNode(n.High, false))
- if err != nil {
- return e.err("invalid slice upper bound: " + err.Error())
- }
- }
- if n.Max != nil {
- max, err = uint64FromResult(e.evalNode(n.Max, false))
- if err != nil {
- return e.err("invalid slice capacity: " + err.Error())
- }
- }
- x := e.evalNode(n.X, false)
- switch v := x.v.(type) {
- case debug.Array, debug.Pointer, pointerToValue:
- // This case handles the slicing of arrays and pointers to arrays.
- var arr debug.Array
- switch v := x.v.(type) {
- case debug.Array:
- arr = v
- case debug.Pointer:
- pt, ok := followTypedefs(x.d).(*dwarf.PtrType)
- if !ok {
- return e.err("invalid DWARF type for pointer")
- }
- a := e.resultFrom(v.Address, pt.Type, false)
- arr, ok = a.v.(debug.Array)
- if !ok {
- // v is a pointer to something other than an array.
- return e.err("cannot slice pointer")
- }
- case pointerToValue:
- a := e.resultFrom(v.a, x.d, false)
- var ok bool
- arr, ok = a.v.(debug.Array)
- if !ok {
- // v is a pointer to something other than an array.
- return e.err("cannot slice pointer")
- }
- }
- elemType, err := e.server.dwarfData.Type(dwarf.Offset(arr.ElementTypeID))
- if err != nil {
- return e.err(err.Error())
- }
- if n.High == nil {
- high = arr.Length
- } else if high > arr.Length {
- return e.err("slice upper bound is too large")
- }
- if n.Max == nil {
- max = arr.Length
- } else if max > arr.Length {
- return e.err("slice capacity is too large")
- }
- if low > high || high > max {
- return e.err("invalid slice index")
- }
- return result{
- d: elemType,
- v: sliceOf{
- Array: debug.Array{
- ElementTypeID: arr.ElementTypeID,
- Address: arr.Element(low).Address,
- Length: high - low,
- StrideBits: uint64(elemType.Common().ByteSize) * 8,
- },
- Capacity: max - low,
- },
- }
- case debug.Slice:
- if n.High == nil {
- high = v.Length
- } else if high > v.Capacity {
- return e.err("slice upper bound is too large")
- }
- if n.Max == nil {
- max = v.Capacity
- } else if max > v.Capacity {
- return e.err("slice capacity is too large")
- }
- if low > high || high > max {
- return e.err("invalid slice index")
- }
- v.Address += low * (v.StrideBits / 8)
- v.Length = high - low
- v.Capacity = max - low
- return result{x.d, v}
- case sliceOf:
- if n.High == nil {
- high = v.Length
- } else if high > v.Capacity {
- return e.err("slice upper bound is too large")
- }
- if n.Max == nil {
- max = v.Capacity
- } else if max > v.Capacity {
- return e.err("slice capacity is too large")
- }
- if low > high || high > max {
- return e.err("invalid slice index")
- }
- v.Address += low * (v.StrideBits / 8)
- v.Length = high - low
- v.Capacity = max - low
- return result{x.d, v}
- case debug.String:
- if n.Max != nil {
- return e.err("full slice of string")
- }
- if n.High == nil {
- high = v.Length
- }
- if low > high || high > v.Length {
- return e.err("invalid slice index")
- }
- v.Length = high - low
- if low > uint64(len(v.String)) {
- // v.String was truncated before the point where this slice starts.
- v.String = ""
- } else {
- if high > uint64(len(v.String)) {
- // v.String was truncated before the point where this slice ends.
- high = uint64(len(v.String))
- }
- v.String = v.String[low:high]
- }
- return result{x.d, v}
- case untString:
- if n.Max != nil {
- return e.err("full slice of string")
- }
- if n.High == nil {
- high = uint64(len(v))
- }
- if low > high {
- return e.err("invalid slice expression")
- }
- if high > uint64(len(v)) {
- return e.err("slice upper bound is too large")
- }
- return e.stringResult(string(v[low:high]))
- default:
- return e.err("invalid slice expression")
- }
-
- case *ast.CallExpr:
- // Only supports lookup("x"), which gets the value of a global symbol x.
- fun := e.evalNode(n.Fun, false)
- var args []result
- for _, a := range n.Args {
- args = append(args, e.evalNode(a, false))
- }
- if fun.v == identLookup {
- if len(args) != 1 {
- return e.err("lookup should have one argument")
- }
- ident, ok := args[0].v.(untString)
- if !ok {
- return e.err("argument for lookup should be a string constant")
- }
- if a, t := e.server.findGlobalVar(string(ident)); t == nil {
- return e.err("symbol not found")
- } else {
- return e.resultFrom(a, t, getAddress)
- }
- }
- return e.err("function calls not implemented")
-
- case *ast.UnaryExpr:
- if n.Op == token.AND {
- x := e.evalNode(n.X, true)
- switch v := x.v.(type) {
- case addressableValue:
- return result{x.d, pointerToValue{v.a}}
- case nil:
- return x
- }
- return e.err("can't take address")
- }
-
- x := e.evalNode(n.X, false)
- if x.v == nil {
- return x
- }
- switch v := x.v.(type) {
-m4_define(UNARY_INT_OPS, @case $1:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- case token.XOR:
- v = ^v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-@)
-m4_define(UNARY_FLOAT_OPS, @case $1:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v = -v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-@)
- UNARY_INT_OPS(int8)
- UNARY_INT_OPS(int16)
- UNARY_INT_OPS(int32)
- UNARY_INT_OPS(int64)
- UNARY_INT_OPS(uint8)
- UNARY_INT_OPS(uint16)
- UNARY_INT_OPS(uint32)
- UNARY_INT_OPS(uint64)
- UNARY_FLOAT_OPS(float32)
- UNARY_FLOAT_OPS(float64)
- UNARY_FLOAT_OPS(complex64)
- UNARY_FLOAT_OPS(complex128)
- case untInt:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v.Int.Neg(v.Int)
- case token.XOR:
- v.Int.Not(v.Int)
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case untRune:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v.Int.Neg(v.Int)
- case token.XOR:
- v.Int.Not(v.Int)
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case untFloat:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v.Float.Neg(v.Float)
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case untComplex:
- switch n.Op {
- case token.ADD:
- case token.SUB:
- v.r.Neg(v.r)
- v.i.Neg(v.i)
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
-
- case bool:
- switch n.Op {
- case token.NOT:
- v = !v
- default:
- return e.err("invalid operation")
- }
- return result{x.d, v}
- }
-
- case *ast.BinaryExpr:
- x := e.evalNode(n.X, false)
- if x.v == nil {
- return x
- }
- y := e.evalNode(n.Y, false)
- if y.v == nil {
- return y
- }
- return e.evalBinaryOp(n.Op, x, y)
- }
- return e.err("invalid expression")
-}
-
-// evalBinaryOp evaluates a binary operator op applied to x and y.
-func (e *evaluator) evalBinaryOp(op token.Token, x, y result) result {
- if op == token.NEQ {
- tmp := e.evalBinaryOp(token.EQL, x, y)
- b, ok := tmp.v.(bool)
- if !ok {
- return tmp
- }
- return result{nil, !b}
- }
- if op == token.GTR {
- return e.evalBinaryOp(token.LSS, y, x)
- }
- if op == token.GEQ {
- return e.evalBinaryOp(token.LEQ, x, y)
- }
-
- x = convertUntyped(x, y)
- y = convertUntyped(y, x)
-
- switch a := x.v.(type) {
-m4_define(INT_OPS, @case $1:
- b, ok := y.v.($1)
- if !ok {
- return e.err("type mismatch")
- }
- var c $1
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-@)
-m4_define(UINT_OPS, @case $1:
- b, ok := y.v.($1)
- if !ok {
- return e.err("type mismatch")
- }
- var c $1
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.OR:
- c = a | b
- case token.XOR:
- c = a ^ b
- case token.MUL:
- c = a * b
- case token.QUO:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a / b
- case token.REM:
- if b == 0 {
- return e.err("integer divide by zero")
- }
- c = a % b
- case token.AND:
- c = a & b
- case token.AND_NOT:
- c = a &^ b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-@)
-m4_define(FLOAT_OPS, @case $1:
- b, ok := y.v.($1)
- if !ok {
- return e.err("type mismatch")
- }
- var c $1
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.MUL:
- c = a * b
- case token.QUO:
- c = a / b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-@)
-m4_define(COMPLEX_OPS, @case $1:
- b, ok := y.v.($1)
- if !ok {
- return e.err("type mismatch")
- }
- var c $1
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.ADD:
- c = a + b
- case token.SUB:
- c = a - b
- case token.MUL:
- c = a * b
- case token.QUO:
- c = a / b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-@)
- INT_OPS(int8)
- INT_OPS(int16)
- INT_OPS(int32)
- INT_OPS(int64)
- UINT_OPS(uint8)
- UINT_OPS(uint16)
- UINT_OPS(uint32)
- UINT_OPS(uint64)
- FLOAT_OPS(float32)
- FLOAT_OPS(float64)
- COMPLEX_OPS(complex64)
- COMPLEX_OPS(complex128)
- case bool:
- b, ok := y.v.(bool)
- if !ok {
- return e.err("type mismatch")
- }
- var c bool
- switch op {
- case token.LOR:
- c = a || b
- case token.LAND:
- c = a && b
- case token.EQL:
- c = a == b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case debug.String:
- b, ok := y.v.(debug.String)
- if !ok {
- return e.err("type mismatch")
- }
- var c debug.String
- switch op {
- // TODO: these comparison operators only use the part of the string that
- // was read. Very large strings do not have their entire contents read by
- // server.value.
- case token.EQL:
- return result{nil, a.Length == b.Length && a.String == b.String}
- case token.LSS:
- return result{nil, a.String < b.String}
- case token.LEQ:
- return result{nil, a.String <= b.String}
- case token.ADD:
- c.Length = a.Length + b.Length
- if a.Length == uint64(len(a.String)) {
- c.String = a.String + b.String
- } else {
- // The first string was truncated at a.Length characters, so the sum
- // must be truncated there too.
- c.String = a.String
- }
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case untString:
- b, ok := y.v.(untString)
- if !ok {
- return e.err("type mismatch")
- }
- var c untString
- switch op {
- case token.EQL:
- return result{nil, a == b}
- case token.LSS:
- return result{nil, a < b}
- case token.LEQ:
- return result{nil, a <= b}
- case token.ADD:
- c = a + b
- default:
- return e.err("invalid operation")
- }
- return result{x.d, c}
-
- case untInt:
- i := a.Int
- b, ok := y.v.(untInt)
- if !ok {
- return e.err("type mismatch")
- }
- switch op {
- case token.EQL:
- return result{nil, i.Cmp(b.Int) == 0}
- case token.LSS:
- return result{nil, i.Cmp(b.Int) < 0}
- case token.LEQ:
- return result{nil, i.Cmp(b.Int) <= 0}
- }
- c := new(big.Int)
- switch op {
- case token.ADD:
- c.Add(i, b.Int)
- case token.SUB:
- c.Sub(i, b.Int)
- case token.OR:
- c.Or(i, b.Int)
- case token.XOR:
- c.Xor(i, b.Int)
- case token.MUL:
- c.Mul(i, b.Int)
- case token.QUO:
- if b.Sign() == 0 {
- return e.err("integer divide by zero")
- }
- c.Quo(i, b.Int)
- case token.REM:
- if b.Sign() == 0 {
- return e.err("integer divide by zero")
- }
- c.Mod(i, b.Int)
- case token.AND:
- c.And(i, b.Int)
- case token.AND_NOT:
- c.AndNot(i, b.Int)
- default:
- return e.err("invalid operation")
- }
- return result{nil, untInt{c}}
-
- case untRune:
- i := a.Int
- b, ok := y.v.(untRune)
- if !ok {
- return e.err("type mismatch")
- }
- switch op {
- case token.EQL:
- return result{nil, i.Cmp(b.Int) == 0}
- case token.LSS:
- return result{nil, i.Cmp(b.Int) < 0}
- case token.LEQ:
- return result{nil, i.Cmp(b.Int) <= 0}
- }
- c := new(big.Int)
- switch op {
- case token.ADD:
- c.Add(i, b.Int)
- case token.SUB:
- c.Sub(i, b.Int)
- case token.OR:
- c.Or(i, b.Int)
- case token.XOR:
- c.Xor(i, b.Int)
- case token.MUL:
- c.Mul(i, b.Int)
- case token.QUO:
- if b.Sign() == 0 {
- return e.err("integer divide by zero")
- }
- c.Quo(i, b.Int)
- case token.REM:
- if b.Sign() == 0 {
- return e.err("integer divide by zero")
- }
- c.Mod(i, b.Int)
- case token.AND:
- c.And(i, b.Int)
- case token.AND_NOT:
- c.AndNot(i, b.Int)
- default:
- return e.err("invalid operation")
- }
- return result{nil, untRune{c}}
-
- case untFloat:
- r := a.Float
- b, ok := y.v.(untFloat)
- if !ok {
- return e.err("type mismatch")
- }
- switch op {
- case token.EQL:
- return result{nil, r.Cmp(b.Float) == 0}
- case token.LSS:
- return result{nil, r.Cmp(b.Float) < 0}
- case token.LEQ:
- return result{nil, r.Cmp(b.Float) <= 0}
- }
- c := new(big.Float)
- switch op {
- case token.ADD:
- c.Add(r, b.Float)
- case token.SUB:
- c.Sub(r, b.Float)
- case token.MUL:
- c.Mul(r, b.Float)
- case token.QUO:
- if b.Sign() == 0 {
- return e.err("divide by zero")
- }
- c.Quo(r, b.Float)
- default:
- return e.err("invalid operation")
- }
- return result{nil, untFloat{c}}
-
- case untComplex:
- b, ok := y.v.(untComplex)
- if !ok {
- return e.err("type mismatch")
- }
- var (
- ar = a.r
- br = b.r
- ai = a.i
- bi = b.i
- )
- if op == token.EQL {
- return result{nil, ar.Cmp(br) == 0 && ai.Cmp(bi) == 0}
- }
- var (
- cr = new(big.Float)
- ci = new(big.Float)
- )
- switch op {
- case token.ADD:
- cr.Add(ar, br)
- ci.Add(ai, bi)
- case token.SUB:
- cr.Sub(ar, br)
- ci.Sub(ai, bi)
- case token.MUL:
- var t0, t1 big.Float
- t0.Mul(ar, br)
- t1.Mul(ai, bi)
- cr.Sub(&t0, &t1)
- t0.Mul(ar, bi)
- t1.Mul(ai, br)
- ci.Add(&t0, &t1)
- case token.QUO:
- // a/b = a*conj(b)/|b|^2
- var t0, t1 big.Float
- cr.Mul(ar, br)
- t0.Mul(ai, bi)
- cr.Add(cr, &t0) // cr = Re(a*conj(b))
- ci.Mul(ai, br)
- t0.Mul(ar, bi)
- ci.Sub(ci, &t0) // ci = Im(a*conj(b))
- t0.Mul(br, br)
- t1.Mul(bi, bi)
- t0.Add(&t0, &t1) // t0 = |b|^2
- if t0.Sign() == 0 {
- return e.err("divide by zero")
- }
- cr.Quo(cr, &t0) // cr = Re(a*conj(b))/|b|^2 = Re(a/b)
- ci.Quo(ci, &t0) // ci = Im(a*conj(b))/|b|^2 = Im(a/b)
- }
- return result{nil, untComplex{cr, ci}}
- }
-
- return e.err("invalid operation")
-}
-
-// findLocalVar finds a local variable (or function parameter) by name, and
-// returns its address and DWARF type. It returns a nil type on failure.
-// The PC and SP are used to determine the current function and stack frame.
-func (s *Server) findLocalVar(name string, pc, sp uint64) (uint64, dwarf.Type) {
- // Find the DWARF entry for the function at pc.
- funcEntry, _, err := s.dwarfData.PCToFunction(uint64(pc))
- if err != nil {
- return 0, nil
- }
-
- // Compute the stack frame pointer.
- fpOffset, err := s.dwarfData.PCToSPOffset(uint64(pc))
- if err != nil {
- return 0, nil
- }
- framePointer := sp + uint64(fpOffset)
-
- // Check each child of the function's DWARF entry to see if it is a parameter
- // or local variable with the right name. If so, return its address and type.
- r := s.dwarfData.Reader()
- r.Seek(funcEntry.Offset)
- for {
- varEntry, err := r.Next()
- if err != nil {
- break
- }
- if varEntry.Tag == 0 {
- // This tag marks the end of the function's DWARF entry's children.
- break
- }
-
- // Check this entry corresponds to a local variable or function parameter,
- // that it has the correct name, and that we can get its type and location.
- // If so, return them.
- if varEntry.Tag != dwarf.TagFormalParameter && varEntry.Tag != dwarf.TagVariable {
- continue
- }
- varName, ok := varEntry.Val(dwarf.AttrName).(string)
- if !ok {
- continue
- }
- if varName != name {
- continue
- }
- varTypeOffset, ok := varEntry.Val(dwarf.AttrType).(dwarf.Offset)
- if !ok {
- continue
- }
- varType, err := s.dwarfData.Type(varTypeOffset)
- if err != nil {
- continue
- }
- locationAttribute := varEntry.Val(dwarf.AttrLocation)
- if locationAttribute == nil {
- continue
- }
- locationDescription, ok := locationAttribute.([]uint8)
- if !ok {
- continue
- }
- frameOffset, err := evalLocation(locationDescription)
- if err != nil {
- continue
- }
- return framePointer + uint64(frameOffset), varType
- }
-
- return 0, nil
-}
-
-// findGlobalVar finds a global variable by name, and returns its address and
-// DWARF type. It returns a nil type on failure.
-func (s *Server) findGlobalVar(name string) (uint64, dwarf.Type) {
- entry, err := s.dwarfData.LookupVariable(name)
- if err != nil {
- return 0, nil
- }
- loc, err := s.dwarfData.EntryLocation(entry)
- if err != nil {
- return 0, nil
- }
- ofs, err := s.dwarfData.EntryTypeOffset(entry)
- if err != nil {
- return 0, nil
- }
- typ, err := s.dwarfData.Type(ofs)
- if err != nil {
- return 0, nil
- }
- return loc, typ
-}
-
-// intFromInteger converts an untyped integer constant to an int32 or int64,
-// depending on the int size of the debugged program.
-// It returns an error on overflow, or if it can't determine the int size.
-func (e *evaluator) intFromInteger(v untInt) (interface{}, error) {
- t, ok := e.getBaseType("int")
- if !ok {
- return nil, errors.New("couldn't get int size from DWARF info")
- }
- switch t.Common().ByteSize {
- case 4:
- if v.Cmp(bigIntMaxInt32) == +1 || v.Cmp(bigIntMinInt32) == -1 {
- return nil, errors.New("constant overflows int")
- }
- return int32(v.Int64()), nil
- case 8:
- if v.Cmp(bigIntMaxInt64) == +1 || v.Cmp(bigIntMinInt64) == -1 {
- return nil, errors.New("constant overflows int")
- }
- return v.Int64(), nil
- }
- return nil, errors.New("invalid int size in DWARF info")
-}
-
-// uint8Result constructs a result for a uint8 value.
-func (e *evaluator) uint8Result(v uint8) result {
- t, ok := e.getBaseType("uint8")
- if !ok {
- e.err("couldn't construct uint8")
- }
- return result{t, uint8(v)}
-}
-
-// stringResult constructs a result for a string value.
-func (e *evaluator) stringResult(s string) result {
- t, ok := e.getBaseType("string")
- if !ok {
- e.err("couldn't construct string")
- }
- return result{t, debug.String{Length: uint64(len(s)), String: s}}
-}
-
-// getBaseType returns the *dwarf.Type with a given name.
-// TODO: cache this.
-func (e *evaluator) getBaseType(name string) (dwarf.Type, bool) {
- entry, err := e.server.dwarfData.LookupEntry(name)
- if err != nil {
- return nil, false
- }
- t, err := e.server.dwarfData.Type(entry.Offset)
- if err != nil {
- return nil, false
- }
- return t, true
-}
-
-// resultFrom constructs a result corresponding to a value in the program with
-// the given address and DWARF type.
-// If getAddress is true, the result will be the operand of an address expression,
-// so resultFrom returns a result containing a value of type addressableValue.
-func (e *evaluator) resultFrom(a uint64, t dwarf.Type, getAddress bool) result {
- if a == 0 {
- return e.err("nil pointer dereference")
- }
- if getAddress {
- return result{t, addressableValue{a}}
- }
- v, err := e.server.value(t, a)
- if err != nil {
- return e.err(err.Error())
- }
- return result{t, v}
-}
-
-// zero returns the zero value of type t.
-// TODO: implement for array and struct.
-func (e *evaluator) zero(t dwarf.Type) result {
- var v interface{}
- switch typ := followTypedefs(t).(type) {
- case *dwarf.CharType, *dwarf.IntType, *dwarf.EnumType:
- switch typ.Common().ByteSize {
- case 1:
- v = int8(0)
- case 2:
- v = int16(0)
- case 4:
- v = int32(0)
- case 8:
- v = int64(0)
- default:
- return e.err("invalid integer size " + fmt.Sprint(typ.Common().ByteSize))
- }
- case *dwarf.UcharType, *dwarf.UintType:
- switch typ.Common().ByteSize {
- case 1:
- v = uint8(0)
- case 2:
- v = uint16(0)
- case 4:
- v = uint32(0)
- case 8:
- v = uint64(0)
- default:
- return e.err("invalid unsigned integer size " + fmt.Sprint(typ.Common().ByteSize))
- }
- case *dwarf.FloatType:
- switch typ.Common().ByteSize {
- case 4:
- v = float32(0)
- case 8:
- v = float64(0)
- default:
- return e.err("invalid float size " + fmt.Sprint(typ.Common().ByteSize))
- }
- case *dwarf.ComplexType:
- switch typ.Common().ByteSize {
- case 8:
- v = complex64(0)
- case 16:
- v = complex128(0)
- default:
- return e.err("invalid complex size " + fmt.Sprint(typ.Common().ByteSize))
- }
- case *dwarf.BoolType:
- v = false
- case *dwarf.PtrType:
- v = debug.Pointer{TypeID: uint64(t.Common().Offset)}
- case *dwarf.SliceType:
- v = debug.Slice{
- Array: debug.Array{
- ElementTypeID: uint64(typ.ElemType.Common().Offset),
- StrideBits: uint64(typ.ElemType.Common().ByteSize) * 8,
- },
- }
- case *dwarf.StringType:
- v = debug.String{}
- case *dwarf.InterfaceType:
- v = debug.Interface{}
- case *dwarf.FuncType:
- v = debug.Func{}
- case *dwarf.MapType:
- v = debug.Map{TypeID: uint64(t.Common().Offset)}
- case *dwarf.ChanType:
- v = debug.Channel{
- ElementTypeID: uint64(typ.ElemType.Common().Offset),
- Stride: uint64(typ.ElemType.Common().ByteSize),
- }
- default:
- return e.err("can't get zero value of this type")
- }
- return result{t, v}
-}
-
-// convertUntyped converts x to be the same type as y, if x is untyped and the
-// conversion is possible.
-//
-// An untyped bool can be converted to a boolean type.
-// An untyped string can be converted to a string type.
-// An untyped integer, rune, float or complex value can be converted to a
-// numeric type, or to an untyped value later in that list.
-//
-// x is returned unchanged if none of these cases apply.
-func convertUntyped(x, y result) result {
- switch a := x.v.(type) {
- case untInt:
- i := a.Int
- switch y.v.(type) {
- case int8:
- return result{y.d, int8(i.Int64())}
- case int16:
- return result{y.d, int16(i.Int64())}
- case int32:
- return result{y.d, int32(i.Int64())}
- case int64:
- return result{y.d, int64(i.Int64())}
- case uint8:
- return result{y.d, uint8(i.Uint64())}
- case uint16:
- return result{y.d, uint16(i.Uint64())}
- case uint32:
- return result{y.d, uint32(i.Uint64())}
- case uint64:
- return result{y.d, uint64(i.Uint64())}
- case float32:
- f, _ := new(big.Float).SetInt(i).Float32()
- return result{y.d, f}
- case float64:
- f, _ := new(big.Float).SetInt(i).Float64()
- return result{y.d, f}
- case complex64:
- f, _ := new(big.Float).SetInt(i).Float32()
- return result{y.d, complex(f, 0)}
- case complex128:
- f, _ := new(big.Float).SetInt(i).Float64()
- return result{y.d, complex(f, 0)}
- case untRune:
- return result{nil, untRune{i}}
- case untFloat:
- return result{nil, untFloat{new(big.Float).SetPrec(prec).SetInt(i)}}
- case untComplex:
- return result{nil, untComplex{new(big.Float).SetPrec(prec).SetInt(i), new(big.Float)}}
- }
- case untRune:
- i := a.Int
- switch y.v.(type) {
- case int8:
- return result{y.d, int8(i.Int64())}
- case int16:
- return result{y.d, int16(i.Int64())}
- case int32:
- return result{y.d, int32(i.Int64())}
- case int64:
- return result{y.d, int64(i.Int64())}
- case uint8:
- return result{y.d, uint8(i.Uint64())}
- case uint16:
- return result{y.d, uint16(i.Uint64())}
- case uint32:
- return result{y.d, uint32(i.Uint64())}
- case uint64:
- return result{y.d, uint64(i.Uint64())}
- case float32:
- f, _ := new(big.Float).SetInt(i).Float32()
- return result{y.d, f}
- case float64:
- f, _ := new(big.Float).SetInt(i).Float64()
- return result{y.d, f}
- case complex64:
- f, _ := new(big.Float).SetInt(i).Float32()
- return result{y.d, complex(f, 0)}
- case complex128:
- f, _ := new(big.Float).SetInt(i).Float64()
- return result{y.d, complex(f, 0)}
- case untRune:
- return result{nil, untRune{i}}
- case untFloat:
- return result{nil, untFloat{new(big.Float).SetPrec(prec).SetInt(i)}}
- case untComplex:
- return result{nil, untComplex{new(big.Float).SetPrec(prec).SetInt(i), new(big.Float)}}
- }
- case untFloat:
- if a.IsInt() {
- i, _ := a.Int(nil)
- switch y.v.(type) {
- case int8:
- return result{y.d, int8(i.Int64())}
- case int16:
- return result{y.d, int16(i.Int64())}
- case int32:
- return result{y.d, int32(i.Int64())}
- case int64:
- return result{y.d, int64(i.Int64())}
- case uint8:
- return result{y.d, uint8(i.Uint64())}
- case uint16:
- return result{y.d, uint16(i.Uint64())}
- case uint32:
- return result{y.d, uint32(i.Uint64())}
- case uint64:
- return result{y.d, uint64(i.Uint64())}
- }
- }
- switch y.v.(type) {
- case float32:
- f, _ := a.Float32()
- return result{y.d, float32(f)}
- case float64:
- f, _ := a.Float64()
- return result{y.d, float64(f)}
- case complex64:
- f, _ := a.Float32()
- return result{y.d, complex(f, 0)}
- case complex128:
- f, _ := a.Float64()
- return result{y.d, complex(f, 0)}
- case untComplex:
- return result{nil, untComplex{a.Float, new(big.Float)}}
- }
- case untComplex:
- if a.i.Sign() == 0 {
- // a is a real number.
- if a.r.IsInt() {
- // a is an integer.
- i, _ := a.r.Int(nil)
- switch y.v.(type) {
- case int8:
- return result{y.d, int8(i.Int64())}
- case int16:
- return result{y.d, int16(i.Int64())}
- case int32:
- return result{y.d, int32(i.Int64())}
- case int64:
- return result{y.d, int64(i.Int64())}
- case uint8:
- return result{y.d, uint8(i.Uint64())}
- case uint16:
- return result{y.d, uint16(i.Uint64())}
- case uint32:
- return result{y.d, uint32(i.Uint64())}
- case uint64:
- return result{y.d, uint64(i.Uint64())}
- }
- }
- switch y.v.(type) {
- case float32:
- f, _ := a.r.Float32()
- return result{y.d, float32(f)}
- case float64:
- f, _ := a.r.Float64()
- return result{y.d, float64(f)}
- }
- }
- switch y.v.(type) {
- case complex64:
- r, _ := a.r.Float32()
- i, _ := a.i.Float32()
- return result{y.d, complex(r, i)}
- case complex128:
- r, _ := a.r.Float64()
- i, _ := a.i.Float64()
- return result{y.d, complex(r, i)}
- }
- case bool:
- if x.d != nil {
- // x is a typed bool, not an untyped bool.
- break
- }
- switch y.v.(type) {
- case bool:
- return result{y.d, bool(a)}
- }
- case untString:
- switch y.v.(type) {
- case debug.String:
- return result{y.d, debug.String{Length: uint64(len(a)), String: string(a)}}
- }
- }
- return x
-}
-
-// uint64FromResult converts a result into a uint64 for slice or index expressions.
-// It returns an error if the conversion cannot be done.
-func uint64FromResult(x result) (uint64, error) {
- switch v := x.v.(type) {
- case int8:
- if v < 0 {
- return 0, errors.New("value is negative")
- }
- return uint64(v), nil
- case int16:
- if v < 0 {
- return 0, errors.New("value is negative")
- }
- return uint64(v), nil
- case int32:
- if v < 0 {
- return 0, errors.New("value is negative")
- }
- return uint64(v), nil
- case int64:
- if v < 0 {
- return 0, errors.New("value is negative")
- }
- return uint64(v), nil
- case uint8:
- return uint64(v), nil
- case uint16:
- return uint64(v), nil
- case uint32:
- return uint64(v), nil
- case uint64:
- return v, nil
- case untInt:
- if v.Int.Sign() == -1 {
- return 0, errors.New("value is negative")
- }
- if v.Int.Cmp(bigIntMaxUint64) == +1 {
- return 0, errors.New("value is too large")
- }
- return v.Int.Uint64(), nil
- case untRune:
- if v.Sign() == -1 {
- return 0, errors.New("value is negative")
- }
- if v.Cmp(bigIntMaxUint64) == +1 {
- return 0, errors.New("value is too large")
- }
- return v.Uint64(), nil
- case untFloat:
- if !v.IsInt() {
- return 0, errors.New("value is not an integer")
- }
- if v.Sign() == -1 {
- return 0, errors.New("value is negative")
- }
- i, _ := v.Int(nil)
- if i.Cmp(bigIntMaxUint64) == +1 {
- return 0, errors.New("value is too large")
- }
- return i.Uint64(), nil
- case untComplex:
- if v.i.Sign() != 0 {
- return 0, errors.New("value is complex")
- }
- if !v.r.IsInt() {
- return 0, errors.New("value is not an integer")
- }
- if v.r.Sign() == -1 {
- return 0, errors.New("value is negative")
- }
- i, _ := v.r.Int(nil)
- if i.Cmp(bigIntMaxUint64) == +1 {
- return 0, errors.New("value is too large")
- }
- return i.Uint64(), nil
- }
- return 0, fmt.Errorf("cannot convert to unsigned integer")
-}
-
-// followTypedefs returns the underlying type of t, removing any typedefs.
-// If t leads to a cycle of typedefs, followTypedefs returns nil.
-func followTypedefs(t dwarf.Type) dwarf.Type {
- // If t is a *dwarf.TypedefType, next returns t.Type, otherwise it returns t.
- // The bool returned is true when the argument was a typedef.
- next := func(t dwarf.Type) (dwarf.Type, bool) {
- tt, ok := t.(*dwarf.TypedefType)
- if !ok {
- return t, false
- }
- return tt.Type, true
- }
- // Advance two pointers, one at twice the speed, so we can detect if we get
- // stuck in a cycle.
- slow, fast := t, t
- for {
- var wasTypedef bool
- fast, wasTypedef = next(fast)
- if !wasTypedef {
- return fast
- }
- fast, wasTypedef = next(fast)
- if !wasTypedef {
- return fast
- }
- slow, _ = next(slow)
- if slow == fast {
- return nil
- }
- }
-}
diff --git a/server/peek.go b/server/peek.go
deleted file mode 100644
index a26677d..0000000
--- a/server/peek.go
+++ /dev/null
@@ -1,366 +0,0 @@
-// Copyright 2015 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.
-
-// Functions for reading values of various types from a program's memory.
-
-package server
-
-import (
- "errors"
- "fmt"
-
- "golang.org/x/debug"
- "golang.org/x/debug/dwarf"
-)
-
-// peekBytes reads len(buf) bytes at addr.
-func (s *Server) peekBytes(addr uint64, buf []byte) error {
- return s.ptracePeek(s.stoppedPid, uintptr(addr), buf)
-}
-
-// peekPtr reads a pointer at addr.
-func (s *Server) peekPtr(addr uint64) (uint64, error) {
- buf := make([]byte, s.arch.PointerSize)
- if err := s.peekBytes(addr, buf); err != nil {
- return 0, err
- }
- return s.arch.Uintptr(buf), nil
-}
-
-// peekUint8 reads a single byte at addr.
-func (s *Server) peekUint8(addr uint64) (byte, error) {
- buf := make([]byte, 1)
- if err := s.peekBytes(addr, buf); err != nil {
- return 0, err
- }
- return uint8(s.arch.UintN(buf)), nil
-}
-
-// peekInt reads an int of size n bytes at addr.
-func (s *Server) peekInt(addr uint64, n int64) (int64, error) {
- buf := make([]byte, n)
- if err := s.peekBytes(addr, buf); err != nil {
- return 0, err
- }
- return s.arch.IntN(buf), nil
-}
-
-// peekUint reads a uint of size n bytes at addr.
-func (s *Server) peekUint(addr uint64, n int64) (uint64, error) {
- buf := make([]byte, n)
- if err := s.peekBytes(addr, buf); err != nil {
- return 0, err
- }
- return s.arch.UintN(buf), nil
-}
-
-// peekSlice reads the header of a slice with the given type and address.
-func (s *Server) peekSlice(t *dwarf.SliceType, addr uint64) (debug.Slice, error) {
- ptr, err := s.peekPtrStructField(&t.StructType, addr, "array")
- if err != nil {
- return debug.Slice{}, fmt.Errorf("reading slice location: %s", err)
- }
- length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len")
- if err != nil {
- return debug.Slice{}, fmt.Errorf("reading slice length: %s", err)
- }
- capacity, err := s.peekUintOrIntStructField(&t.StructType, addr, "cap")
- if err != nil {
- return debug.Slice{}, fmt.Errorf("reading slice capacity: %s", err)
- }
- if capacity < length {
- return debug.Slice{}, fmt.Errorf("slice's capacity %d is less than its length %d", capacity, length)
- }
-
- return debug.Slice{
- debug.Array{
- ElementTypeID: uint64(t.ElemType.Common().Offset),
- Address: uint64(ptr),
- Length: length,
- StrideBits: uint64(t.ElemType.Common().ByteSize) * 8,
- },
- capacity,
- }, nil
-}
-
-// peekString reads a string of the given type at the given address.
-// At most byteLimit bytes will be read. If the string is longer, "..." is appended.
-func (s *Server) peekString(typ *dwarf.StringType, a uint64, byteLimit uint64) (string, error) {
- ptr, err := s.peekPtrStructField(&typ.StructType, a, "str")
- if err != nil {
- return "", err
- }
- length, err := s.peekUintOrIntStructField(&typ.StructType, a, "len")
- if err != nil {
- return "", err
- }
- if length > byteLimit {
- buf := make([]byte, byteLimit, byteLimit+3)
- if err := s.peekBytes(ptr, buf); err != nil {
- return "", err
- } else {
- buf = append(buf, '.', '.', '.')
- return string(buf), nil
- }
- } else {
- buf := make([]byte, length)
- if err := s.peekBytes(ptr, buf); err != nil {
- return "", err
- } else {
- return string(buf), nil
- }
- }
-}
-
-// peekCString reads a NUL-terminated string at the given address.
-// At most byteLimit bytes will be read. If the string is longer, "..." is appended.
-// peekCString never returns errors; if an error occurs, the string will be truncated in some way.
-func (s *Server) peekCString(a uint64, byteLimit uint64) string {
- buf := make([]byte, byteLimit, byteLimit+3)
- s.peekBytes(a, buf)
- for i, c := range buf {
- if c == 0 {
- return string(buf[0:i])
- }
- }
- buf = append(buf, '.', '.', '.')
- return string(buf)
-}
-
-// peekPtrStructField reads a pointer in the field fieldName of the struct
-// of type t at addr.
-func (s *Server) peekPtrStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) {
- f, err := getField(t, fieldName)
- if err != nil {
- return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
- }
- if _, ok := f.Type.(*dwarf.PtrType); !ok {
- return 0, fmt.Errorf("field %s is not a pointer", fieldName)
- }
- return s.peekPtr(addr + uint64(f.ByteOffset))
-}
-
-// peekUintOrIntStructField reads a signed or unsigned integer in the field fieldName
-// of the struct of type t at addr. If the value is negative, it returns an error.
-// This function is used when the value should be non-negative, but the DWARF
-// type of the field may be signed or unsigned.
-func (s *Server) peekUintOrIntStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) {
- f, err := getField(t, fieldName)
- if err != nil {
- return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
- }
- ut, ok := f.Type.(*dwarf.UintType)
- if ok {
- return s.peekUint(addr+uint64(f.ByteOffset), ut.ByteSize)
- }
- it, ok := f.Type.(*dwarf.IntType)
- if !ok {
- return 0, fmt.Errorf("field %s is not an integer", fieldName)
- }
- i, err := s.peekInt(addr+uint64(f.ByteOffset), it.ByteSize)
- if err != nil {
- return 0, err
- }
- if i < 0 {
- return 0, fmt.Errorf("field %s is negative", fieldName)
- }
- return uint64(i), nil
-}
-
-// peekUintStructField reads a uint in the field fieldName of the struct
-// of type t at addr. The size of the uint is determined by the field.
-func (s *Server) peekUintStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) {
- f, err := getField(t, fieldName)
- if err != nil {
- return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
- }
- ut, ok := f.Type.(*dwarf.UintType)
- if !ok {
- return 0, fmt.Errorf("field %s is not an unsigned integer", fieldName)
- }
- return s.peekUint(addr+uint64(f.ByteOffset), ut.ByteSize)
-}
-
-// peekIntStructField reads an int in the field fieldName of the struct
-// of type t at addr. The size of the int is determined by the field.
-func (s *Server) peekIntStructField(t *dwarf.StructType, addr uint64, fieldName string) (int64, error) {
- f, err := getField(t, fieldName)
- if err != nil {
- return 0, fmt.Errorf("reading field %s: %s", fieldName, err)
- }
- it, ok := f.Type.(*dwarf.IntType)
- if !ok {
- return 0, fmt.Errorf("field %s is not a signed integer", fieldName)
- }
- return s.peekInt(addr+uint64(f.ByteOffset), it.ByteSize)
-}
-
-// peekStringStructField reads a string field from the struct of the given type
-// at the given address.
-// At most byteLimit bytes will be read. If the string is longer, "..." is appended.
-func (s *Server) peekStringStructField(t *dwarf.StructType, addr uint64, fieldName string, byteLimit uint64) (string, error) {
- f, err := getField(t, fieldName)
- if err != nil {
- return "", fmt.Errorf("reading field %s: %s", fieldName, err)
- }
- st, ok := followTypedefs(f.Type).(*dwarf.StringType)
- if !ok {
- return "", fmt.Errorf("field %s is not a string", fieldName)
- }
- return s.peekString(st, addr+uint64(f.ByteOffset), byteLimit)
-}
-
-// peekMapLocationAndType returns the address and DWARF type of the underlying
-// struct of a map variable.
-func (s *Server) peekMapLocationAndType(t *dwarf.MapType, a uint64) (uint64, *dwarf.StructType, error) {
- // Maps are pointers to structs.
- pt, ok := t.Type.(*dwarf.PtrType)
- if !ok {
- return 0, nil, errors.New("bad map type: not a pointer")
- }
- st, ok := pt.Type.(*dwarf.StructType)
- if !ok {
- return 0, nil, errors.New("bad map type: not a pointer to a struct")
- }
- // a is the address of a pointer to a struct. Get the pointer's value.
- a, err := s.peekPtr(a)
- if err != nil {
- return 0, nil, fmt.Errorf("reading map pointer: %s", err)
- }
- return a, st, nil
-}
-
-// peekMapValues reads a map at the given address and calls fn with the addresses for each (key, value) pair.
-// If fn returns false, peekMapValues stops.
-func (s *Server) peekMapValues(t *dwarf.MapType, a uint64, fn func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool) error {
- a, st, err := s.peekMapLocationAndType(t, a)
- if err != nil {
- return err
- }
- if a == 0 {
- // The pointer was nil, so the map is empty.
- return nil
- }
- // Gather information about the struct type and the map bucket type.
- b, err := s.peekUintStructField(st, a, "B")
- if err != nil {
- return fmt.Errorf("reading map: %s", err)
- }
- buckets, err := s.peekPtrStructField(st, a, "buckets")
- if err != nil {
- return fmt.Errorf("reading map: %s", err)
- }
- oldbuckets, err := s.peekPtrStructField(st, a, "oldbuckets")
- if err != nil {
- return fmt.Errorf("reading map: %s", err)
- }
- bf, err := getField(st, "buckets")
- if err != nil {
- return fmt.Errorf("reading map: %s", err)
- }
- bucketPtrType, ok := bf.Type.(*dwarf.PtrType)
- if !ok {
- return errors.New("bad map bucket type: not a pointer")
- }
- bt, ok := bucketPtrType.Type.(*dwarf.StructType)
- if !ok {
- return errors.New("bad map bucket type: not a pointer to a struct")
- }
- bucketSize := uint64(bucketPtrType.Type.Size())
- tophashField, err := getField(bt, "tophash")
- if err != nil {
- return fmt.Errorf("reading map: %s", err)
- }
- bucketCnt := uint64(tophashField.Type.Size())
- tophashFieldOffset := uint64(tophashField.ByteOffset)
- keysField, err := getField(bt, "keys")
- if err != nil {
- return fmt.Errorf("reading map: %s", err)
- }
- keysType, ok := keysField.Type.(*dwarf.ArrayType)
- if !ok {
- return errors.New(`bad map bucket type: "keys" is not an array`)
- }
- keyType := keysType.Type
- keysStride := uint64(keysType.StrideBitSize / 8)
- keysFieldOffset := uint64(keysField.ByteOffset)
- valuesField, err := getField(bt, "values")
- if err != nil {
- return fmt.Errorf("reading map: %s", err)
- }
- valuesType, ok := valuesField.Type.(*dwarf.ArrayType)
- if !ok {
- return errors.New(`bad map bucket type: "values" is not an array`)
- }
- valueType := valuesType.Type
- valuesStride := uint64(valuesType.StrideBitSize / 8)
- valuesFieldOffset := uint64(valuesField.ByteOffset)
- overflowField, err := getField(bt, "overflow")
- if err != nil {
- return fmt.Errorf("reading map: %s", err)
- }
- overflowFieldOffset := uint64(overflowField.ByteOffset)
-
- // Iterate through the two arrays of buckets.
- bucketArrays := [2]struct {
- addr uint64
- size uint64
- }{
- {buckets, 1 << b},
- {oldbuckets, 1 << (b - 1)},
- }
- for _, bucketArray := range bucketArrays {
- if bucketArray.addr == 0 {
- continue
- }
- for i := uint64(0); i < bucketArray.size; i++ {
- bucketAddr := bucketArray.addr + i*bucketSize
- // Iterate through the linked list of buckets.
- // TODO: check for repeated bucket pointers.
- for bucketAddr != 0 {
- // Iterate through each entry in the bucket.
- for j := uint64(0); j < bucketCnt; j++ {
- tophash, err := s.peekUint8(bucketAddr + tophashFieldOffset + j)
- if err != nil {
- return errors.New("reading map: " + err.Error())
- }
- // From runtime/hashmap.go
- const minTopHash = 4
- if tophash < minTopHash {
- continue
- }
- keyAddr := bucketAddr + keysFieldOffset + j*keysStride
- valAddr := bucketAddr + valuesFieldOffset + j*valuesStride
- if !fn(keyAddr, valAddr, keyType, valueType) {
- return nil
- }
- }
- var err error
- bucketAddr, err = s.peekPtr(bucketAddr + overflowFieldOffset)
- if err != nil {
- return errors.New("reading map: " + err.Error())
- }
- }
- }
- }
-
- return nil
-}
-
-// peekMapLength returns the number of elements in a map at the given address.
-func (s *Server) peekMapLength(t *dwarf.MapType, a uint64) (uint64, error) {
- a, st, err := s.peekMapLocationAndType(t, a)
- if err != nil {
- return 0, err
- }
- if a == 0 {
- // The pointer was nil, so the map is empty.
- return 0, nil
- }
- length, err := s.peekUintOrIntStructField(st, a, "count")
- if err != nil {
- return 0, fmt.Errorf("reading map: %s", err)
- }
- return uint64(length), nil
-}
diff --git a/server/print.go b/server/print.go
deleted file mode 100644
index e370498..0000000
--- a/server/print.go
+++ /dev/null
@@ -1,536 +0,0 @@
-// 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 server
-
-import (
- "bytes"
- "fmt"
-
- "golang.org/x/debug/arch"
- "golang.org/x/debug/dwarf"
-)
-
-// typeAndAddress associates an address in the target with a DWARF type.
-type typeAndAddress struct {
- Type dwarf.Type
- Address uint64
-}
-
-// Routines to print a value using DWARF type descriptions.
-// TODO: Does this deserve its own package? It has no dependencies on Server.
-
-// A Printer pretty-prints values in the target address space.
-// It can be reused after each printing operation to avoid unnecessary
-// allocations. However, it is not safe for concurrent access.
-type Printer struct {
- err error // Sticky error value.
- server *Server
- dwarf *dwarf.Data
- arch *arch.Architecture
- printBuf bytes.Buffer // Accumulates the output.
- visited map[typeAndAddress]bool // Prevents looping on cyclic data.
-}
-
-// printf prints to printBuf.
-func (p *Printer) printf(format string, args ...interface{}) {
- fmt.Fprintf(&p.printBuf, format, args...)
-}
-
-// errorf prints the error to printBuf, then sets the sticky error for the
-// printer, if not already set.
-func (p *Printer) errorf(format string, args ...interface{}) {
- fmt.Fprintf(&p.printBuf, "<"+format+">", args...)
- if p.err != nil {
- return
- }
- p.err = fmt.Errorf(format, args...)
-}
-
-// NewPrinter returns a printer that can use the Server to access and print
-// values of the specified architecture described by the provided DWARF data.
-func NewPrinter(arch *arch.Architecture, dwarf *dwarf.Data, server *Server) *Printer {
- return &Printer{
- server: server,
- arch: arch,
- dwarf: dwarf,
- visited: make(map[typeAndAddress]bool),
- }
-}
-
-// reset resets the Printer. It must be called before starting a new
-// printing operation.
-func (p *Printer) reset() {
- p.err = nil
- p.printBuf.Reset()
- // Just wipe the map rather than reallocating. It's almost always tiny.
- for k := range p.visited {
- delete(p.visited, k)
- }
-}
-
-// Sprint returns the pretty-printed value of the item with the given name, such as "main.global".
-func (p *Printer) Sprint(name string) (string, error) {
- entry, err := p.dwarf.LookupEntry(name)
- if err != nil {
- return "", err
- }
- p.reset()
- switch entry.Tag {
- case dwarf.TagVariable: // TODO: What other entries have global location attributes?
- var a uint64
- iface := entry.Val(dwarf.AttrLocation)
- if iface != nil {
- a = p.decodeLocation(iface.([]byte))
- }
- p.printEntryValueAt(entry, a)
- default:
- p.errorf("unrecognized entry type %s", entry.Tag)
- }
- return p.printBuf.String(), p.err
-}
-
-// Figure 24 of DWARF v4.
-const (
- locationAddr = 0x03
-)
-
-// decodeLocation decodes the dwarf data describing an address.
-func (p *Printer) decodeLocation(data []byte) uint64 {
- switch data[0] {
- case locationAddr:
- return p.arch.Uintptr(data[1:])
- default:
- p.errorf("unimplemented location type %#x", data[0])
- }
- return 0
-}
-
-// SprintEntry returns the pretty-printed value of the item with the specified DWARF Entry and address.
-func (p *Printer) SprintEntry(entry *dwarf.Entry, a uint64) (string, error) {
- p.reset()
- p.printEntryValueAt(entry, a)
- return p.printBuf.String(), p.err
-}
-
-// printEntryValueAt pretty-prints the data at the specified address.
-// using the type information in the Entry.
-func (p *Printer) printEntryValueAt(entry *dwarf.Entry, a uint64) {
- if a == 0 {
- p.printf("<nil>")
- return
- }
- switch entry.Tag {
- case dwarf.TagVariable, dwarf.TagFormalParameter:
- // OK
- default:
- p.errorf("unrecognized entry type %s", entry.Tag)
- return
- }
- iface := entry.Val(dwarf.AttrType)
- if iface == nil {
- p.errorf("no type")
- return
- }
- typ, err := p.dwarf.Type(iface.(dwarf.Offset))
- if err != nil {
- p.errorf("type lookup: %v", err)
- return
- }
- p.printValueAt(typ, a)
-}
-
-// printValueAt pretty-prints the data at the specified address.
-// using the provided type information.
-func (p *Printer) printValueAt(typ dwarf.Type, a uint64) {
- if a != 0 {
- // Check if we are repeating the same type and address.
- ta := typeAndAddress{typ, a}
- if p.visited[ta] {
- p.printf("(%v %#x)", typ, a)
- return
- }
- p.visited[ta] = true
- }
- switch typ := typ.(type) {
- case *dwarf.BoolType:
- if typ.ByteSize != 1 {
- p.errorf("unrecognized bool size %d", typ.ByteSize)
- return
- }
- if b, err := p.server.peekUint8(a); err != nil {
- p.errorf("reading bool: %s", err)
- } else {
- p.printf("%t", b != 0)
- }
- case *dwarf.PtrType:
- if ptr, err := p.server.peekPtr(a); err != nil {
- p.errorf("reading pointer: %s", err)
- } else {
- p.printf("%#x", ptr)
- }
- case *dwarf.IntType:
- // Sad we can't tell a rune from an int32.
- if i, err := p.server.peekInt(a, typ.ByteSize); err != nil {
- p.errorf("reading integer: %s", err)
- } else {
- p.printf("%d", i)
- }
- case *dwarf.UintType:
- if u, err := p.server.peekUint(a, typ.ByteSize); err != nil {
- p.errorf("reading unsigned integer: %s", err)
- } else {
- p.printf("%d", u)
- }
- case *dwarf.FloatType:
- buf := make([]byte, typ.ByteSize)
- if err := p.server.peekBytes(a, buf); err != nil {
- p.errorf("reading float: %s", err)
- return
- }
- switch typ.ByteSize {
- case 4:
- p.printf("%g", p.arch.Float32(buf))
- case 8:
- p.printf("%g", p.arch.Float64(buf))
- default:
- p.errorf("unrecognized float size %d", typ.ByteSize)
- }
- case *dwarf.ComplexType:
- buf := make([]byte, typ.ByteSize)
- if err := p.server.peekBytes(a, buf); err != nil {
- p.errorf("reading complex: %s", err)
- return
- }
- switch typ.ByteSize {
- case 8:
- p.printf("%g", p.arch.Complex64(buf))
- case 16:
- p.printf("%g", p.arch.Complex128(buf))
- default:
- p.errorf("unrecognized complex size %d", typ.ByteSize)
- }
- case *dwarf.StructType:
- if typ.Kind != "struct" {
- // Could be "class" or "union".
- p.errorf("can't handle struct type %s", typ.Kind)
- return
- }
- p.printf("%s {", typ.String())
- for i, field := range typ.Field {
- if i != 0 {
- p.printf(", ")
- }
- p.printValueAt(field.Type, a+uint64(field.ByteOffset))
- }
- p.printf("}")
- case *dwarf.ArrayType:
- p.printArrayAt(typ, a)
- case *dwarf.InterfaceType:
- p.printInterfaceAt(typ, a)
- case *dwarf.MapType:
- p.printMapAt(typ, a)
- case *dwarf.ChanType:
- p.printChannelAt(typ, a)
- case *dwarf.SliceType:
- p.printSliceAt(typ, a)
- case *dwarf.StringType:
- p.printStringAt(typ, a)
- case *dwarf.TypedefType:
- p.printValueAt(typ.Type, a)
- case *dwarf.FuncType:
- p.printf("%v @%#x ", typ, a)
- case *dwarf.VoidType:
- p.printf("void")
- default:
- p.errorf("unimplemented type %v", typ)
- }
-}
-
-func (p *Printer) printArrayAt(typ *dwarf.ArrayType, a uint64) {
- elemType := typ.Type
- length := typ.Count
- stride, ok := p.arrayStride(typ)
- if !ok {
- p.errorf("can't determine element size")
- }
- p.printf("%s{", typ)
- n := length
- if n > 100 {
- n = 100 // TODO: Have a way to control this?
- }
- for i := int64(0); i < n; i++ {
- if i != 0 {
- p.printf(", ")
- }
- p.printValueAt(elemType, a)
- a += stride // TODO: Alignment and padding - not given by Type
- }
- if n < length {
- p.printf(", ...")
- }
- p.printf("}")
-}
-
-func (p *Printer) printInterfaceAt(t *dwarf.InterfaceType, a uint64) {
- // t embeds a TypedefType, which may point to another typedef.
- // The underlying type should be a struct.
- st, ok := followTypedefs(&t.TypedefType).(*dwarf.StructType)
- if !ok {
- p.errorf("bad interface type: not a struct")
- return
- }
- p.printf("(")
- tab, err := p.server.peekPtrStructField(st, a, "tab")
- if err != nil {
- p.errorf("reading interface type: %s", err)
- } else {
- f, err := getField(st, "tab")
- if err != nil {
- p.errorf("%s", err)
- } else {
- p.printTypeOfInterface(f.Type, tab)
- }
- }
- p.printf(", ")
- data, err := p.server.peekPtrStructField(st, a, "data")
- if err != nil {
- p.errorf("reading interface value: %s", err)
- } else if data == 0 {
- p.printf("<nil>")
- } else {
- p.printf("%#x", data)
- }
- p.printf(")")
-}
-
-// printTypeOfInterface prints the type of the given tab pointer.
-func (p *Printer) printTypeOfInterface(t dwarf.Type, a uint64) {
- if a == 0 {
- p.printf("<nil>")
- return
- }
- // t should be a pointer to a struct containing _type, which is a pointer to a
- // struct containing _string, which is the name of the type.
- // Depending on the compiler version, some of these types can be typedefs, and
- // _string may be a string or a *string.
- t1, ok := followTypedefs(t).(*dwarf.PtrType)
- if !ok {
- p.errorf("interface's tab is not a pointer")
- return
- }
- t2, ok := followTypedefs(t1.Type).(*dwarf.StructType)
- if !ok {
- p.errorf("interface's tab is not a pointer to struct")
- return
- }
- typeField, err := getField(t2, "_type")
- if err != nil {
- p.errorf("%s", err)
- return
- }
- t3, ok := followTypedefs(typeField.Type).(*dwarf.PtrType)
- if !ok {
- p.errorf("interface's _type is not a pointer")
- return
- }
- t4, ok := followTypedefs(t3.Type).(*dwarf.StructType)
- if !ok {
- p.errorf("interface's _type is not a pointer to struct")
- return
- }
- stringField, err := getField(t4, "_string")
- if err != nil {
- p.errorf("%s", err)
- return
- }
- if t5, ok := stringField.Type.(*dwarf.PtrType); ok {
- stringType, ok := t5.Type.(*dwarf.StringType)
- if !ok {
- p.errorf("interface _string is a pointer to %T, want string or *string", t5.Type)
- return
- }
- typeAddr, err := p.server.peekPtrStructField(t2, a, "_type")
- if err != nil {
- p.errorf("reading interface type: %s", err)
- return
- }
- stringAddr, err := p.server.peekPtrStructField(t4, typeAddr, "_string")
- if err != nil {
- p.errorf("reading interface type: %s", err)
- return
- }
- p.printStringAt(stringType, stringAddr)
- } else {
- stringType, ok := stringField.Type.(*dwarf.StringType)
- if !ok {
- p.errorf("interface _string is a %T, want string or *string", stringField.Type)
- return
- }
- typeAddr, err := p.server.peekPtrStructField(t2, a, "_type")
- if err != nil {
- p.errorf("reading interface type: %s", err)
- return
- }
- stringAddr := typeAddr + uint64(stringField.ByteOffset)
- p.printStringAt(stringType, stringAddr)
- }
-}
-
-// maxMapValuesToPrint values are printed for each map; any remaining values are
-// truncated to "...".
-const maxMapValuesToPrint = 8
-
-func (p *Printer) printMapAt(typ *dwarf.MapType, a uint64) {
- count := 0
- fn := func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) (stop bool) {
- count++
- if count > maxMapValuesToPrint {
- return false
- }
- if count > 1 {
- p.printf(" ")
- }
- p.printValueAt(keyType, keyAddr)
- p.printf(":")
- p.printValueAt(valType, valAddr)
- return true
- }
- p.printf("map[")
- if err := p.server.peekMapValues(typ, a, fn); err != nil {
- p.errorf("reading map values: %s", err)
- }
- if count > maxMapValuesToPrint {
- p.printf(" ...")
- }
- p.printf("]")
-}
-
-func (p *Printer) printChannelAt(ct *dwarf.ChanType, a uint64) {
- p.printf("(chan %s ", ct.ElemType)
- defer p.printf(")")
-
- a, err := p.server.peekPtr(a)
- if err != nil {
- p.errorf("reading channel: %s", err)
- return
- }
- if a == 0 {
- p.printf("<nil>")
- return
- }
- p.printf("%#x", a)
-
- // ct is a typedef for a pointer to a struct.
- pt, ok := ct.TypedefType.Type.(*dwarf.PtrType)
- if !ok {
- p.errorf("bad channel type: not a pointer")
- return
- }
- st, ok := pt.Type.(*dwarf.StructType)
- if !ok {
- p.errorf("bad channel type: not a pointer to a struct")
- return
- }
-
- // Print the channel buffer's length (qcount) and capacity (dataqsiz),
- // if not 0/0.
- qcount, err := p.server.peekUintOrIntStructField(st, a, "qcount")
- if err != nil {
- p.errorf("reading channel: %s", err)
- return
- }
- dataqsiz, err := p.server.peekUintOrIntStructField(st, a, "dataqsiz")
- if err != nil {
- p.errorf("reading channel: %s", err)
- return
- }
- if qcount != 0 || dataqsiz != 0 {
- p.printf(" [%d/%d]", qcount, dataqsiz)
- }
-}
-
-func (p *Printer) printSliceAt(typ *dwarf.SliceType, a uint64) {
- // Slices look like a struct with fields array *elemtype, len uint32/64, cap uint32/64.
- // BUG: Slice header appears to have fields with ByteSize == 0
- ptr, err := p.server.peekPtrStructField(&typ.StructType, a, "array")
- if err != nil {
- p.errorf("reading slice: %s", err)
- return
- }
- length, err := p.server.peekUintOrIntStructField(&typ.StructType, a, "len")
- if err != nil {
- p.errorf("reading slice: %s", err)
- return
- }
- // Capacity is not used yet.
- _, err = p.server.peekUintOrIntStructField(&typ.StructType, a, "cap")
- if err != nil {
- p.errorf("reading slice: %s", err)
- return
- }
- elemType := typ.ElemType
- size, ok := p.sizeof(typ.ElemType)
- if !ok {
- p.errorf("can't determine element size")
- }
- p.printf("%s{", typ)
- for i := uint64(0); i < length; i++ {
- if i != 0 {
- p.printf(", ")
- }
- p.printValueAt(elemType, ptr)
- ptr += size // TODO: Alignment and padding - not given by Type
- }
- p.printf("}")
-}
-
-func (p *Printer) printStringAt(typ *dwarf.StringType, a uint64) {
- const maxStringSize = 100
- if s, err := p.server.peekString(typ, a, maxStringSize); err != nil {
- p.errorf("reading string: %s", err)
- } else {
- p.printf("%q", s)
- }
-}
-
-// sizeof returns the byte size of the type.
-func (p *Printer) sizeof(typ dwarf.Type) (uint64, bool) {
- size := typ.Size() // Will be -1 if ByteSize is not set.
- if size >= 0 {
- return uint64(size), true
- }
- switch typ.(type) {
- case *dwarf.PtrType:
- // This is the only one we know of, but more may arise.
- return uint64(p.arch.PointerSize), true
- }
- return 0, false
-}
-
-// arrayStride returns the stride of a dwarf.ArrayType in bytes.
-func (p *Printer) arrayStride(t *dwarf.ArrayType) (uint64, bool) {
- stride := t.StrideBitSize
- if stride > 0 {
- return uint64(stride / 8), true
- }
- return p.sizeof(t.Type)
-}
-
-// getField finds the *dwarf.StructField in a dwarf.StructType with name fieldName.
-func getField(t *dwarf.StructType, fieldName string) (*dwarf.StructField, error) {
- var r *dwarf.StructField
- for _, f := range t.Field {
- if f.Name == fieldName {
- if r != nil {
- return nil, fmt.Errorf("struct definition repeats field %s", fieldName)
- }
- r = f
- }
- }
- if r == nil {
- return nil, fmt.Errorf("struct field %s missing", fieldName)
- }
- return r, nil
-}
diff --git a/server/protocol/protocol.go b/server/protocol/protocol.go
deleted file mode 100644
index c08b895..0000000
--- a/server/protocol/protocol.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// 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 protocol defines the types used to represent calls to the debug server.
-package protocol // import "golang.org/x/debug/server/protocol"
-
-import (
- "encoding/gob"
-
- "golang.org/x/debug"
-)
-
-func init() {
- // Register implementations of debug.Value with gob.
- gob.Register(debug.Pointer{})
- gob.Register(debug.Array{})
- gob.Register(debug.Struct{})
- gob.Register(debug.Slice{})
- gob.Register(debug.Map{})
- gob.Register(debug.String{})
- gob.Register(debug.Channel{})
- gob.Register(debug.Func{})
- gob.Register(debug.Interface{})
-}
-
-// For regularity, each method has a unique Request and a Response type even
-// when not strictly necessary.
-
-// File I/O, at the top because they're simple.
-
-type ReadAtRequest struct {
- FD int
- Len int
- Offset int64
-}
-
-type ReadAtResponse struct {
- Data []byte
-}
-
-type WriteAtRequest struct {
- FD int
- Data []byte
- Offset int64
-}
-
-type WriteAtResponse struct {
- Len int
-}
-
-type CloseRequest struct {
- FD int
-}
-
-type CloseResponse struct {
-}
-
-// Program methods.
-
-type OpenRequest struct {
- Name string
- Mode string
-}
-
-type OpenResponse struct {
- FD int
-}
-
-type RunRequest struct {
- Args []string
-}
-
-type RunResponse struct {
- Status debug.Status
-}
-
-type ResumeRequest struct {
-}
-
-type ResumeResponse struct {
- Status debug.Status
-}
-
-type BreakpointRequest struct {
- Address uint64
-}
-
-type BreakpointAtFunctionRequest struct {
- Function string
-}
-
-type BreakpointAtLineRequest struct {
- File string
- Line uint64
-}
-
-type BreakpointResponse struct {
- PCs []uint64
-}
-
-type DeleteBreakpointsRequest struct {
- PCs []uint64
-}
-
-type DeleteBreakpointsResponse struct {
-}
-
-type EvalRequest struct {
- Expr string
-}
-
-type EvalResponse struct {
- Result []string
-}
-
-type EvaluateRequest struct {
- Expression string
-}
-
-type EvaluateResponse struct {
- Result debug.Value
-}
-
-type FramesRequest struct {
- Count int
-}
-
-type FramesResponse struct {
- Frames []debug.Frame
-}
-
-type VarByNameRequest struct {
- Name string
-}
-
-type VarByNameResponse struct {
- Var debug.Var
-}
-
-type ValueRequest struct {
- Var debug.Var
-}
-
-type ValueResponse struct {
- Value debug.Value
-}
-
-type MapElementRequest struct {
- Map debug.Map
- Index uint64
-}
-
-type MapElementResponse struct {
- Key debug.Var
- Value debug.Var
-}
-
-type GoroutinesRequest struct {
-}
-
-type GoroutinesResponse struct {
- Goroutines []*debug.Goroutine
-}
diff --git a/server/ptrace.go b/server/ptrace.go
deleted file mode 100644
index 068e234..0000000
--- a/server/ptrace.go
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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 server
-
-import (
- "fmt"
- "os"
- "runtime"
- "syscall"
- "time"
-)
-
-// ptraceRun runs all the closures from fc on a dedicated OS thread. Errors
-// are returned on ec. Both channels must be unbuffered, to ensure that the
-// resultant error is sent back to the same goroutine that sent the closure.
-func ptraceRun(fc chan func() error, ec chan error) {
- if cap(fc) != 0 || cap(ec) != 0 {
- panic("ptraceRun was given buffered channels")
- }
- runtime.LockOSThread()
- for f := range fc {
- ec <- f()
- }
-}
-
-func (s *Server) startProcess(name string, argv []string, attr *os.ProcAttr) (proc *os.Process, err error) {
- s.fc <- func() error {
- var err1 error
- proc, err1 = os.StartProcess(name, argv, attr)
- return err1
- }
- err = <-s.ec
- return
-}
-
-func (s *Server) ptraceCont(pid int, signal int) (err error) {
- s.fc <- func() error {
- return syscall.PtraceCont(pid, signal)
- }
- return <-s.ec
-}
-
-func (s *Server) ptraceGetRegs(pid int, regsout *syscall.PtraceRegs) (err error) {
- s.fc <- func() error {
- return syscall.PtraceGetRegs(pid, regsout)
- }
- return <-s.ec
-}
-
-func (s *Server) ptracePeek(pid int, addr uintptr, out []byte) (err error) {
- s.fc <- func() error {
- n, err := syscall.PtracePeekText(pid, addr, out)
- if err != nil {
- return err
- }
- if n != len(out) {
- return fmt.Errorf("ptracePeek: peeked %d bytes, want %d", n, len(out))
- }
- return nil
- }
- return <-s.ec
-}
-
-func (s *Server) ptracePoke(pid int, addr uintptr, data []byte) (err error) {
- s.fc <- func() error {
- n, err := syscall.PtracePokeText(pid, addr, data)
- if err != nil {
- return err
- }
- if n != len(data) {
- return fmt.Errorf("ptracePoke: poked %d bytes, want %d", n, len(data))
- }
- return nil
- }
- return <-s.ec
-}
-
-func (s *Server) ptraceSetOptions(pid int, options int) (err error) {
- s.fc <- func() error {
- return syscall.PtraceSetOptions(pid, options)
- }
- return <-s.ec
-}
-
-func (s *Server) ptraceSetRegs(pid int, regs *syscall.PtraceRegs) (err error) {
- s.fc <- func() error {
- return syscall.PtraceSetRegs(pid, regs)
- }
- return <-s.ec
-}
-
-func (s *Server) ptraceSingleStep(pid int) (err error) {
- s.fc <- func() error {
- return syscall.PtraceSingleStep(pid)
- }
- return <-s.ec
-}
-
-type breakpointsChangedError struct {
- call call
-}
-
-func (*breakpointsChangedError) Error() string {
- return "breakpoints changed"
-}
-
-func (s *Server) wait(pid int, allowBreakpointsChange bool) (wpid int, status syscall.WaitStatus, err error) {
- // We poll syscall.Wait4 with WNOHANG, sleeping in between, as a poor man's
- // waitpid-with-timeout. This allows adding and removing breakpoints
- // concurrently with waiting to hit an existing breakpoint.
- f := func() error {
- var err1 error
- wpid, err1 = syscall.Wait4(pid, &status, syscall.WALL|syscall.WNOHANG, nil)
- return err1
- }
-
- const (
- minSleep = 1 * time.Microsecond
- maxSleep = 100 * time.Millisecond
- )
- for sleep := minSleep; ; {
- s.fc <- f
- err = <-s.ec
-
- // wpid == 0 means that wait found nothing (and returned due to WNOHANG).
- if wpid != 0 {
- return
- }
-
- if allowBreakpointsChange {
- select {
- case c := <-s.breakpointc:
- return 0, 0, &breakpointsChangedError{c}
- default:
- }
- }
-
- time.Sleep(sleep)
- if sleep < maxSleep {
- sleep *= 10
- }
- }
-}
diff --git a/server/server.go b/server/server.go
deleted file mode 100644
index e4caa40..0000000
--- a/server/server.go
+++ /dev/null
@@ -1,1145 +0,0 @@
-// 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 server provides RPC access to a local program being debugged.
-// It is the remote end of the client implementation of the Program interface.
-package server // import "golang.org/x/debug/server"
-
-//go:generate sh -c "m4 -P eval.m4 > eval.go"
-
-import (
- "bytes"
- "errors"
- "fmt"
- "os"
- "regexp"
- "strconv"
- "strings"
- "sync"
- "syscall"
-
- "golang.org/x/debug"
- "golang.org/x/debug/arch"
- "golang.org/x/debug/dwarf"
- "golang.org/x/debug/elf"
- "golang.org/x/debug/macho"
- "golang.org/x/debug/server/protocol"
-)
-
-type breakpoint struct {
- pc uint64
- origInstr [arch.MaxBreakpointSize]byte
-}
-
-type call struct {
- req, resp interface{}
- errc chan error
-}
-
-type Server struct {
- arch arch.Architecture
- executable string // Name of executable.
- dwarfData *dwarf.Data
-
- breakpointc chan call
- otherc chan call
-
- fc chan func() error
- ec chan error
-
- proc *os.Process
- procIsUp bool
- stoppedPid int
- stoppedRegs syscall.PtraceRegs
- topOfStackAddrs []uint64
- breakpoints map[uint64]breakpoint
- files []*file // Index == file descriptor.
- printer *Printer
-
- // goroutineStack reads the stack of a (non-running) goroutine.
- goroutineStack func(uint64) ([]debug.Frame, error)
- goroutineStackOnce sync.Once
-}
-
-// peek implements the Peeker interface required by the printer.
-func (s *Server) peek(offset uintptr, buf []byte) error {
- return s.ptracePeek(s.stoppedPid, offset, buf)
-}
-
-// New parses the executable and builds local data structures for answering requests.
-// It returns a Server ready to serve requests about the executable.
-func New(executable string) (*Server, error) {
- fd, err := os.Open(executable)
- if err != nil {
- return nil, err
- }
- defer fd.Close()
- architecture, dwarfData, err := loadExecutable(fd)
- if err != nil {
- return nil, err
- }
- srv := &Server{
- arch: *architecture,
- executable: executable,
- dwarfData: dwarfData,
- breakpointc: make(chan call),
- otherc: make(chan call),
- fc: make(chan func() error),
- ec: make(chan error),
- breakpoints: make(map[uint64]breakpoint),
- }
- srv.printer = NewPrinter(architecture, dwarfData, srv)
- go ptraceRun(srv.fc, srv.ec)
- go srv.loop()
- return srv, nil
-}
-
-func loadExecutable(f *os.File) (*arch.Architecture, *dwarf.Data, error) {
- // TODO: How do we detect NaCl?
- if obj, err := elf.NewFile(f); err == nil {
- dwarfData, err := obj.DWARF()
- if err != nil {
- return nil, nil, err
- }
-
- switch obj.Machine {
- case elf.EM_ARM:
- return &arch.ARM, dwarfData, nil
- case elf.EM_386:
- switch obj.Class {
- case elf.ELFCLASS32:
- return &arch.X86, dwarfData, nil
- case elf.ELFCLASS64:
- return &arch.AMD64, dwarfData, nil
- }
- case elf.EM_X86_64:
- return &arch.AMD64, dwarfData, nil
- }
- return nil, nil, fmt.Errorf("unrecognized ELF architecture")
- }
- if obj, err := macho.NewFile(f); err == nil {
- dwarfData, err := obj.DWARF()
- if err != nil {
- return nil, nil, err
- }
-
- /* TODO
- table, err := parseMachO(obj)
- if err != nil {
- return nil, nil, err
- }
- */
- switch obj.Cpu {
- case macho.Cpu386:
- return &arch.X86, dwarfData, nil
- case macho.CpuAmd64:
- return &arch.AMD64, dwarfData, nil
- }
- return nil, nil, fmt.Errorf("unrecognized Mach-O architecture")
- }
- return nil, nil, fmt.Errorf("unrecognized binary format")
-}
-
-func (s *Server) loop() {
- for {
- var c call
- select {
- case c = <-s.breakpointc:
- case c = <-s.otherc:
- }
- s.dispatch(c)
- }
-}
-
-func (s *Server) dispatch(c call) {
- switch req := c.req.(type) {
- case *protocol.BreakpointRequest:
- c.errc <- s.handleBreakpoint(req, c.resp.(*protocol.BreakpointResponse))
- case *protocol.BreakpointAtFunctionRequest:
- c.errc <- s.handleBreakpointAtFunction(req, c.resp.(*protocol.BreakpointResponse))
- case *protocol.BreakpointAtLineRequest:
- c.errc <- s.handleBreakpointAtLine(req, c.resp.(*protocol.BreakpointResponse))
- case *protocol.DeleteBreakpointsRequest:
- c.errc <- s.handleDeleteBreakpoints(req, c.resp.(*protocol.DeleteBreakpointsResponse))
- case *protocol.CloseRequest:
- c.errc <- s.handleClose(req, c.resp.(*protocol.CloseResponse))
- case *protocol.EvalRequest:
- c.errc <- s.handleEval(req, c.resp.(*protocol.EvalResponse))
- case *protocol.EvaluateRequest:
- c.errc <- s.handleEvaluate(req, c.resp.(*protocol.EvaluateResponse))
- case *protocol.FramesRequest:
- c.errc <- s.handleFrames(req, c.resp.(*protocol.FramesResponse))
- case *protocol.OpenRequest:
- c.errc <- s.handleOpen(req, c.resp.(*protocol.OpenResponse))
- case *protocol.ReadAtRequest:
- c.errc <- s.handleReadAt(req, c.resp.(*protocol.ReadAtResponse))
- case *protocol.ResumeRequest:
- c.errc <- s.handleResume(req, c.resp.(*protocol.ResumeResponse))
- case *protocol.RunRequest:
- c.errc <- s.handleRun(req, c.resp.(*protocol.RunResponse))
- case *protocol.VarByNameRequest:
- c.errc <- s.handleVarByName(req, c.resp.(*protocol.VarByNameResponse))
- case *protocol.ValueRequest:
- c.errc <- s.handleValue(req, c.resp.(*protocol.ValueResponse))
- case *protocol.MapElementRequest:
- c.errc <- s.handleMapElement(req, c.resp.(*protocol.MapElementResponse))
- case *protocol.GoroutinesRequest:
- c.errc <- s.handleGoroutines(req, c.resp.(*protocol.GoroutinesResponse))
- default:
- panic(fmt.Sprintf("unexpected call request type %T", c.req))
- }
-}
-
-func (s *Server) call(c chan call, req, resp interface{}) error {
- errc := make(chan error)
- c <- call{req, resp, errc}
- return <-errc
-}
-
-type file struct {
- mode string
- index int
- f debug.File
-}
-
-func (s *Server) Open(req *protocol.OpenRequest, resp *protocol.OpenResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleOpen(req *protocol.OpenRequest, resp *protocol.OpenResponse) error {
- // TODO: Better simulation. For now we just open the named OS file.
- var flag int
- switch req.Mode {
- case "r":
- flag = os.O_RDONLY
- case "w":
- flag = os.O_WRONLY
- case "rw":
- flag = os.O_RDWR
- default:
- return fmt.Errorf("Open: bad open mode %q", req.Mode)
- }
- osFile, err := os.OpenFile(req.Name, flag, 0)
- if err != nil {
- return err
- }
- // Find a file descriptor (index) slot.
- index := 0
- for ; index < len(s.files) && s.files[index] != nil; index++ {
- }
- f := &file{
- mode: req.Mode,
- index: index,
- f: osFile,
- }
- if index == len(s.files) {
- s.files = append(s.files, f)
- } else {
- s.files[index] = f
- }
- return nil
-}
-
-func (s *Server) ReadAt(req *protocol.ReadAtRequest, resp *protocol.ReadAtResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleReadAt(req *protocol.ReadAtRequest, resp *protocol.ReadAtResponse) error {
- fd := req.FD
- if fd < 0 || len(s.files) <= fd || s.files[fd] == nil {
- return fmt.Errorf("ReadAt: bad file descriptor %d", fd)
- }
- f := s.files[fd]
- buf := make([]byte, req.Len) // TODO: Don't allocate every time
- n, err := f.f.ReadAt(buf, req.Offset)
- resp.Data = buf[:n]
- return err
-}
-
-func (s *Server) Close(req *protocol.CloseRequest, resp *protocol.CloseResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleClose(req *protocol.CloseRequest, resp *protocol.CloseResponse) error {
- fd := req.FD
- if fd < 0 || fd >= len(s.files) || s.files[fd] == nil {
- return fmt.Errorf("Close: bad file descriptor %d", fd)
- }
- err := s.files[fd].f.Close()
- // Remove it regardless
- s.files[fd] = nil
- return err
-}
-
-func (s *Server) Run(req *protocol.RunRequest, resp *protocol.RunResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleRun(req *protocol.RunRequest, resp *protocol.RunResponse) error {
- if s.proc != nil {
- s.proc.Kill()
- s.proc = nil
- s.procIsUp = false
- s.stoppedPid = 0
- s.stoppedRegs = syscall.PtraceRegs{}
- s.topOfStackAddrs = nil
- }
- argv := append([]string{s.executable}, req.Args...)
- p, err := s.startProcess(s.executable, argv, &os.ProcAttr{
- Files: []*os.File{
- nil, // TODO: be able to feed the target's stdin.
- os.Stderr, // TODO: be able to capture the target's stdout.
- os.Stderr,
- },
- Sys: &syscall.SysProcAttr{
- Pdeathsig: syscall.SIGKILL,
- Ptrace: true,
- },
- })
- if err != nil {
- return err
- }
- s.proc = p
- s.stoppedPid = p.Pid
- return nil
-}
-
-func (s *Server) Resume(req *protocol.ResumeRequest, resp *protocol.ResumeResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleResume(req *protocol.ResumeRequest, resp *protocol.ResumeResponse) error {
- if s.proc == nil {
- return fmt.Errorf("Resume: Run did not successfully start a process")
- }
-
- if !s.procIsUp {
- s.procIsUp = true
- if _, err := s.waitForTrap(s.stoppedPid, false); err != nil {
- return err
- }
- if err := s.ptraceSetOptions(s.stoppedPid, syscall.PTRACE_O_TRACECLONE); err != nil {
- return fmt.Errorf("ptraceSetOptions: %v", err)
- }
- } else if _, ok := s.breakpoints[s.stoppedRegs.Rip]; ok {
- if err := s.ptraceSingleStep(s.stoppedPid); err != nil {
- return fmt.Errorf("ptraceSingleStep: %v", err)
- }
- if _, err := s.waitForTrap(s.stoppedPid, false); err != nil {
- return err
- }
- }
-
- for {
- if err := s.setBreakpoints(); err != nil {
- return err
- }
- if err := s.ptraceCont(s.stoppedPid, 0); err != nil {
- return fmt.Errorf("ptraceCont: %v", err)
- }
-
- wpid, err := s.waitForTrap(-1, true)
- if err == nil {
- s.stoppedPid = wpid
- break
- }
- bce, ok := err.(*breakpointsChangedError)
- if !ok {
- return err
- }
-
- if err := syscall.Kill(s.stoppedPid, syscall.SIGSTOP); err != nil {
- return fmt.Errorf("kill(SIGSTOP): %v", err)
- }
- _, status, err := s.wait(s.stoppedPid, false)
- if err != nil {
- return fmt.Errorf("wait (after SIGSTOP): %v", err)
- }
- if !status.Stopped() || status.StopSignal() != syscall.SIGSTOP {
- return fmt.Errorf("wait (after SIGSTOP): unexpected wait status 0x%x", status)
- }
-
- if err := s.liftBreakpoints(); err != nil {
- return err
- }
-
- loop:
- for c := bce.call; ; {
- s.dispatch(c)
- select {
- case c = <-s.breakpointc:
- default:
- break loop
- }
- }
- }
- if err := s.liftBreakpoints(); err != nil {
- return err
- }
-
- if err := s.ptraceGetRegs(s.stoppedPid, &s.stoppedRegs); err != nil {
- return fmt.Errorf("ptraceGetRegs: %v", err)
- }
-
- s.stoppedRegs.Rip -= uint64(s.arch.BreakpointSize)
-
- if err := s.ptraceSetRegs(s.stoppedPid, &s.stoppedRegs); err != nil {
- return fmt.Errorf("ptraceSetRegs: %v", err)
- }
-
- resp.Status.PC = s.stoppedRegs.Rip
- resp.Status.SP = s.stoppedRegs.Rsp
- return nil
-}
-
-func (s *Server) waitForTrap(pid int, allowBreakpointsChange bool) (wpid int, err error) {
- for {
- wpid, status, err := s.wait(pid, allowBreakpointsChange)
- if err != nil {
- if _, ok := err.(*breakpointsChangedError); !ok {
- err = fmt.Errorf("wait: %v", err)
- }
- return 0, err
- }
- if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != syscall.PTRACE_EVENT_CLONE {
- return wpid, nil
- }
- if status.StopSignal() == syscall.SIGPROF {
- err = s.ptraceCont(wpid, int(syscall.SIGPROF))
- } else {
- err = s.ptraceCont(wpid, 0) // TODO: non-zero when wait catches other signals?
- }
- if err != nil {
- return 0, fmt.Errorf("ptraceCont: %v", err)
- }
- }
-}
-
-func (s *Server) Breakpoint(req *protocol.BreakpointRequest, resp *protocol.BreakpointResponse) error {
- return s.call(s.breakpointc, req, resp)
-}
-
-func (s *Server) handleBreakpoint(req *protocol.BreakpointRequest, resp *protocol.BreakpointResponse) error {
- return s.addBreakpoints([]uint64{req.Address}, resp)
-}
-
-func (s *Server) BreakpointAtFunction(req *protocol.BreakpointAtFunctionRequest, resp *protocol.BreakpointResponse) error {
- return s.call(s.breakpointc, req, resp)
-}
-
-func (s *Server) handleBreakpointAtFunction(req *protocol.BreakpointAtFunctionRequest, resp *protocol.BreakpointResponse) error {
- pc, err := s.functionStartAddress(req.Function)
- if err != nil {
- return err
- }
- return s.addBreakpoints([]uint64{pc}, resp)
-}
-
-func (s *Server) BreakpointAtLine(req *protocol.BreakpointAtLineRequest, resp *protocol.BreakpointResponse) error {
- return s.call(s.breakpointc, req, resp)
-}
-
-func (s *Server) handleBreakpointAtLine(req *protocol.BreakpointAtLineRequest, resp *protocol.BreakpointResponse) error {
- if s.dwarfData == nil {
- return fmt.Errorf("no DWARF data")
- }
- if pcs, err := s.dwarfData.LineToBreakpointPCs(req.File, req.Line); err != nil {
- return err
- } else {
- return s.addBreakpoints(pcs, resp)
- }
-}
-
-// addBreakpoints adds breakpoints at the addresses in pcs, then stores pcs in the response.
-func (s *Server) addBreakpoints(pcs []uint64, resp *protocol.BreakpointResponse) error {
- // Get the original code at each address with ptracePeek.
- bps := make([]breakpoint, 0, len(pcs))
- for _, pc := range pcs {
- if _, alreadySet := s.breakpoints[pc]; alreadySet {
- continue
- }
- var bp breakpoint
- if err := s.ptracePeek(s.stoppedPid, uintptr(pc), bp.origInstr[:s.arch.BreakpointSize]); err != nil {
- return fmt.Errorf("ptracePeek: %v", err)
- }
- bp.pc = pc
- bps = append(bps, bp)
- }
- // If all the peeks succeeded, update the list of breakpoints.
- for _, bp := range bps {
- s.breakpoints[bp.pc] = bp
- }
- resp.PCs = pcs
- return nil
-}
-
-func (s *Server) DeleteBreakpoints(req *protocol.DeleteBreakpointsRequest, resp *protocol.DeleteBreakpointsResponse) error {
- return s.call(s.breakpointc, req, resp)
-}
-
-func (s *Server) handleDeleteBreakpoints(req *protocol.DeleteBreakpointsRequest, resp *protocol.DeleteBreakpointsResponse) error {
- for _, pc := range req.PCs {
- delete(s.breakpoints, pc)
- }
- return nil
-}
-
-func (s *Server) setBreakpoints() error {
- for pc := range s.breakpoints {
- err := s.ptracePoke(s.stoppedPid, uintptr(pc), s.arch.BreakpointInstr[:s.arch.BreakpointSize])
- if err != nil {
- return fmt.Errorf("setBreakpoints: %v", err)
- }
- }
- return nil
-}
-
-func (s *Server) liftBreakpoints() error {
- for pc, breakpoint := range s.breakpoints {
- err := s.ptracePoke(s.stoppedPid, uintptr(pc), breakpoint.origInstr[:s.arch.BreakpointSize])
- if err != nil {
- return fmt.Errorf("liftBreakpoints: %v", err)
- }
- }
- return nil
-}
-
-func (s *Server) Eval(req *protocol.EvalRequest, resp *protocol.EvalResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleEval(req *protocol.EvalRequest, resp *protocol.EvalResponse) (err error) {
- resp.Result, err = s.eval(req.Expr)
- return err
-}
-
-// eval evaluates an expression.
-// TODO: very weak.
-func (s *Server) eval(expr string) ([]string, error) {
- switch {
- case strings.HasPrefix(expr, "re:"):
- // Regular expression. Return list of symbols.
- re, err := regexp.Compile(expr[3:])
- if err != nil {
- return nil, err
- }
- return s.dwarfData.LookupMatchingSymbols(re)
-
- case strings.HasPrefix(expr, "addr:"):
- // Symbol lookup. Return address.
- addr, err := s.functionStartAddress(expr[5:])
- if err != nil {
- return nil, err
- }
- return []string{fmt.Sprintf("%#x", addr)}, nil
-
- case strings.HasPrefix(expr, "val:"):
- // Symbol lookup. Return formatted value.
- value, err := s.printer.Sprint(expr[4:])
- if err != nil {
- return nil, err
- }
- return []string{value}, nil
-
- case strings.HasPrefix(expr, "src:"):
- // Numerical address. Return file.go:123.
- addr, err := strconv.ParseUint(expr[4:], 0, 0)
- if err != nil {
- return nil, err
- }
- file, line, err := s.lookupSource(addr)
- if err != nil {
- return nil, err
- }
- return []string{fmt.Sprintf("%s:%d", file, line)}, nil
-
- case len(expr) > 0 && '0' <= expr[0] && expr[0] <= '9':
- // Numerical address. Return symbol.
- addr, err := strconv.ParseUint(expr, 0, 0)
- if err != nil {
- return nil, err
- }
- entry, _, err := s.dwarfData.PCToFunction(addr)
- if err != nil {
- return nil, err
- }
- name, ok := entry.Val(dwarf.AttrName).(string)
- if !ok {
- return nil, fmt.Errorf("function at 0x%x has no name", addr)
- }
- return []string{name}, nil
- }
-
- return nil, fmt.Errorf("bad expression syntax: %q", expr)
-}
-
-func (s *Server) Evaluate(req *protocol.EvaluateRequest, resp *protocol.EvaluateResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleEvaluate(req *protocol.EvaluateRequest, resp *protocol.EvaluateResponse) (err error) {
- resp.Result, err = s.evalExpression(req.Expression, s.stoppedRegs.Rip, s.stoppedRegs.Rsp)
- return err
-}
-
-func (s *Server) lookupSource(pc uint64) (file string, line uint64, err error) {
- if s.dwarfData == nil {
- return
- }
- // TODO: The gosym equivalent also returns the relevant Func. Do that when
- // DWARF has the same facility.
- return s.dwarfData.PCToLine(pc)
-}
-
-func (s *Server) Frames(req *protocol.FramesRequest, resp *protocol.FramesResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleFrames(req *protocol.FramesRequest, resp *protocol.FramesResponse) error {
- // TODO: verify that we're stopped.
- if s.topOfStackAddrs == nil {
- if err := s.evaluateTopOfStackAddrs(); err != nil {
- return err
- }
- }
-
- regs := syscall.PtraceRegs{}
- err := s.ptraceGetRegs(s.stoppedPid, ®s)
- if err != nil {
- return err
- }
- resp.Frames, err = s.walkStack(regs.Rip, regs.Rsp, req.Count)
- return err
-}
-
-// walkStack returns up to the requested number of stack frames.
-func (s *Server) walkStack(pc, sp uint64, count int) ([]debug.Frame, error) {
- var frames []debug.Frame
-
- var buf [8]byte
- b := new(bytes.Buffer)
- r := s.dwarfData.Reader()
-
- // TODO: handle walking over a split stack.
- for i := 0; i < count; i++ {
- b.Reset()
- file, line, err := s.dwarfData.PCToLine(pc)
- if err != nil {
- return frames, err
- }
- fpOffset, err := s.dwarfData.PCToSPOffset(pc)
- if err != nil {
- return frames, err
- }
- fp := sp + uint64(fpOffset)
- entry, funcEntry, err := s.dwarfData.PCToFunction(pc)
- if err != nil {
- return frames, err
- }
- frame := debug.Frame{
- PC: pc,
- SP: sp,
- File: file,
- Line: line,
- FunctionStart: funcEntry,
- }
- frame.Function, _ = entry.Val(dwarf.AttrName).(string)
- r.Seek(entry.Offset)
- for {
- entry, err := r.Next()
- if err != nil {
- return frames, err
- }
- if entry.Tag == 0 {
- break
- }
- // TODO: report variables we couldn't parse?
- if entry.Tag == dwarf.TagFormalParameter {
- if v, err := s.parseParameterOrLocal(entry, fp); err == nil {
- frame.Params = append(frame.Params, debug.Param(v))
- }
- }
- if entry.Tag == dwarf.TagVariable {
- if v, err := s.parseParameterOrLocal(entry, fp); err == nil {
- frame.Vars = append(frame.Vars, v)
- }
- }
- }
- frames = append(frames, frame)
-
- // Walk to the caller's PC and SP.
- if s.topOfStack(funcEntry) {
- break
- }
- err = s.ptracePeek(s.stoppedPid, uintptr(fp-uint64(s.arch.PointerSize)), buf[:s.arch.PointerSize])
- if err != nil {
- return frames, fmt.Errorf("ptracePeek: %v", err)
- }
- pc, sp = s.arch.Uintptr(buf[:s.arch.PointerSize]), fp
- }
- return frames, nil
-}
-
-// parseParameterOrLocal parses the entry for a function parameter or local
-// variable, which are both specified the same way. fp contains the frame
-// pointer, which is used to calculate the variable location.
-func (s *Server) parseParameterOrLocal(entry *dwarf.Entry, fp uint64) (debug.LocalVar, error) {
- var v debug.LocalVar
- v.Name, _ = entry.Val(dwarf.AttrName).(string)
- if off, err := s.dwarfData.EntryTypeOffset(entry); err != nil {
- return v, err
- } else {
- v.Var.TypeID = uint64(off)
- }
- if i := entry.Val(dwarf.AttrLocation); i == nil {
- return v, fmt.Errorf("missing location description")
- } else if locationDescription, ok := i.([]uint8); !ok {
- return v, fmt.Errorf("unsupported location description")
- } else if offset, err := evalLocation(locationDescription); err != nil {
- return v, err
- } else {
- v.Var.Address = fp + uint64(offset)
- }
- return v, nil
-}
-
-func (s *Server) evaluateTopOfStackAddrs() error {
- var (
- lookup func(name string) (uint64, error)
- indirect bool
- names []string
- )
- if _, err := s.dwarfData.LookupVariable("runtime.rt0_goPC"); err != nil {
- // Look for a Go 1.3 binary (or earlier version).
- lookup, indirect, names = s.functionStartAddress, false, []string{
- "runtime.goexit",
- "runtime.mstart",
- "runtime.mcall",
- "runtime.morestack",
- "runtime.lessstack",
- "_rt0_go",
- }
- } else {
- // Look for a Go 1.4 binary (or later version).
- lookup = func(name string) (uint64, error) {
- entry, err := s.dwarfData.LookupVariable(name)
- if err != nil {
- return 0, err
- }
- return s.dwarfData.EntryLocation(entry)
- }
- indirect, names = true, []string{
- "runtime.goexitPC",
- "runtime.mstartPC",
- "runtime.mcallPC",
- "runtime.morestackPC",
- "runtime.rt0_goPC",
- }
- }
- // TODO: also look for runtime.externalthreadhandlerp, on Windows.
-
- addrs := make([]uint64, 0, len(names))
- for _, name := range names {
- addr, err := lookup(name)
- if err != nil {
- return err
- }
- addrs = append(addrs, addr)
- }
-
- if indirect {
- buf := make([]byte, s.arch.PointerSize)
- for i, addr := range addrs {
- if err := s.ptracePeek(s.stoppedPid, uintptr(addr), buf); err != nil {
- return fmt.Errorf("ptracePeek: %v", err)
- }
- addrs[i] = s.arch.Uintptr(buf)
- }
- }
-
- s.topOfStackAddrs = addrs
- return nil
-}
-
-// topOfStack is the out-of-process equivalent of runtime·topofstack.
-func (s *Server) topOfStack(funcEntry uint64) bool {
- for _, addr := range s.topOfStackAddrs {
- if addr == funcEntry {
- return true
- }
- }
- return false
-}
-
-func (s *Server) VarByName(req *protocol.VarByNameRequest, resp *protocol.VarByNameResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleVarByName(req *protocol.VarByNameRequest, resp *protocol.VarByNameResponse) error {
- entry, err := s.dwarfData.LookupVariable(req.Name)
- if err != nil {
- return fmt.Errorf("variable %s: %s", req.Name, err)
- }
-
- loc, err := s.dwarfData.EntryLocation(entry)
- if err != nil {
- return fmt.Errorf("variable %s: %s", req.Name, err)
- }
-
- off, err := s.dwarfData.EntryTypeOffset(entry)
- if err != nil {
- return fmt.Errorf("variable %s: %s", req.Name, err)
- }
-
- resp.Var.TypeID = uint64(off)
- resp.Var.Address = loc
- return nil
-}
-
-func (s *Server) Value(req *protocol.ValueRequest, resp *protocol.ValueResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleValue(req *protocol.ValueRequest, resp *protocol.ValueResponse) error {
- t, err := s.dwarfData.Type(dwarf.Offset(req.Var.TypeID))
- if err != nil {
- return err
- }
- resp.Value, err = s.value(t, req.Var.Address)
- return err
-}
-
-func (s *Server) MapElement(req *protocol.MapElementRequest, resp *protocol.MapElementResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-func (s *Server) handleMapElement(req *protocol.MapElementRequest, resp *protocol.MapElementResponse) error {
- t, err := s.dwarfData.Type(dwarf.Offset(req.Map.TypeID))
- if err != nil {
- return err
- }
- m, ok := t.(*dwarf.MapType)
- if !ok {
- return fmt.Errorf("variable is not a map")
- }
- var count uint64
- // fn will be called for each element of the map.
- // When we reach the requested element, we fill in *resp and stop.
- // TODO: cache locations of elements.
- fn := func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool {
- count++
- if count == req.Index+1 {
- resp.Key = debug.Var{TypeID: uint64(keyType.Common().Offset), Address: keyAddr}
- resp.Value = debug.Var{TypeID: uint64(valType.Common().Offset), Address: valAddr}
- return false
- }
- return true
- }
- if err := s.peekMapValues(m, req.Map.Address, fn); err != nil {
- return err
- }
- if count <= req.Index {
- // There weren't enough elements.
- return fmt.Errorf("map has no element %d", req.Index)
- }
- return nil
-}
-
-func (s *Server) Goroutines(req *protocol.GoroutinesRequest, resp *protocol.GoroutinesResponse) error {
- return s.call(s.otherc, req, resp)
-}
-
-const invalidStatus debug.GoroutineStatus = 99
-
-var (
- gStatus = [...]debug.GoroutineStatus{
- 0: debug.Queued, // _Gidle
- 1: debug.Queued, // _Grunnable
- 2: debug.Running, // _Grunning
- 3: debug.Blocked, // _Gsyscall
- 4: debug.Blocked, // _Gwaiting
- 5: invalidStatus, // _Gmoribund_unused
- 6: invalidStatus, // _Gdead
- 7: invalidStatus, // _Genqueue
- 8: debug.Running, // _Gcopystack
- }
- gScanStatus = [...]debug.GoroutineStatus{
- 0: invalidStatus, // _Gscan + _Gidle
- 1: debug.Queued, // _Gscanrunnable
- 2: debug.Running, // _Gscanrunning
- 3: debug.Blocked, // _Gscansyscall
- 4: debug.Blocked, // _Gscanwaiting
- 5: invalidStatus, // _Gscan + _Gmoribund_unused
- 6: invalidStatus, // _Gscan + _Gdead
- 7: debug.Queued, // _Gscanenqueue
- }
- gStatusString = [...]string{
- 0: "idle",
- 1: "runnable",
- 2: "running",
- 3: "syscall",
- 4: "waiting",
- 8: "copystack",
- }
- gScanStatusString = [...]string{
- 1: "scanrunnable",
- 2: "scanrunning",
- 3: "scansyscall",
- 4: "scanwaiting",
- 7: "scanenqueue",
- }
-)
-
-func (s *Server) handleGoroutines(req *protocol.GoroutinesRequest, resp *protocol.GoroutinesResponse) error {
- // Get DWARF type information for runtime.g.
- ge, err := s.dwarfData.LookupEntry("runtime.g")
- if err != nil {
- return err
- }
- t, err := s.dwarfData.Type(ge.Offset)
- if err != nil {
- return err
- }
- gType, ok := followTypedefs(t).(*dwarf.StructType)
- if !ok {
- return errors.New("runtime.g is not a struct")
- }
-
- var (
- allgPtr, allgLen uint64
- allgPtrOk bool
- )
- for {
- // Try to read the slice runtime.allgs.
- allgsEntry, err := s.dwarfData.LookupVariable("runtime.allgs")
- if err != nil {
- break
- }
- allgsAddr, err := s.dwarfData.EntryLocation(allgsEntry)
- if err != nil {
- break
- }
- off, err := s.dwarfData.EntryTypeOffset(allgsEntry)
- if err != nil {
- break
- }
- t, err := s.dwarfData.Type(off)
- if err != nil {
- break
- }
- allgsType, ok := followTypedefs(t).(*dwarf.SliceType)
- if !ok {
- break
- }
- allgs, err := s.peekSlice(allgsType, allgsAddr)
- if err != nil {
- break
- }
-
- allgPtr, allgLen, allgPtrOk = allgs.Address, allgs.Length, true
- break
- }
- if !allgPtrOk {
- // Read runtime.allg.
- allgEntry, err := s.dwarfData.LookupVariable("runtime.allg")
- if err != nil {
- return err
- }
- allgAddr, err := s.dwarfData.EntryLocation(allgEntry)
- if err != nil {
- return err
- }
- allgPtr, err = s.peekPtr(allgAddr)
- if err != nil {
- return fmt.Errorf("reading allg: %v", err)
- }
-
- // Read runtime.allglen.
- allglenEntry, err := s.dwarfData.LookupVariable("runtime.allglen")
- if err != nil {
- return err
- }
- off, err := s.dwarfData.EntryTypeOffset(allglenEntry)
- if err != nil {
- return err
- }
- allglenType, err := s.dwarfData.Type(off)
- if err != nil {
- return err
- }
- allglenAddr, err := s.dwarfData.EntryLocation(allglenEntry)
- if err != nil {
- return err
- }
- switch followTypedefs(allglenType).(type) {
- case *dwarf.UintType, *dwarf.IntType:
- allgLen, err = s.peekUint(allglenAddr, allglenType.Common().ByteSize)
- if err != nil {
- return fmt.Errorf("reading allglen: %v", err)
- }
- default:
- // Some runtimes don't specify the type for allglen. Assume it's uint32.
- allgLen, err = s.peekUint(allglenAddr, 4)
- if err != nil {
- return fmt.Errorf("reading allglen: %v", err)
- }
- if allgLen != 0 {
- break
- }
- // Zero? Let's try uint64.
- allgLen, err = s.peekUint(allglenAddr, 8)
- if err != nil {
- return fmt.Errorf("reading allglen: %v", err)
- }
- }
- }
-
- // Initialize s.goroutineStack.
- s.goroutineStackOnce.Do(func() { s.goroutineStackInit(gType) })
-
- for i := uint64(0); i < allgLen; i++ {
- // allg is an array of pointers to g structs. Read allg[i].
- g, err := s.peekPtr(allgPtr + i*uint64(s.arch.PointerSize))
- if err != nil {
- return err
- }
- gr := debug.Goroutine{}
-
- // Read status from the field named "atomicstatus" or "status".
- status, err := s.peekUintStructField(gType, g, "atomicstatus")
- if err != nil {
- status, err = s.peekUintOrIntStructField(gType, g, "status")
- }
- if err != nil {
- return err
- }
- if status == 6 {
- // _Gdead.
- continue
- }
- gr.Status = invalidStatus
- if status < uint64(len(gStatus)) {
- gr.Status = gStatus[status]
- gr.StatusString = gStatusString[status]
- } else if status^0x1000 < uint64(len(gScanStatus)) {
- gr.Status = gScanStatus[status^0x1000]
- gr.StatusString = gScanStatusString[status^0x1000]
- }
- if gr.Status == invalidStatus {
- return fmt.Errorf("unexpected goroutine status 0x%x", status)
- }
- if status == 4 || status == 0x1004 {
- // _Gwaiting or _Gscanwaiting.
- // Try reading waitreason to get a better value for StatusString.
- // Depending on the runtime, waitreason may be a Go string or a C string.
- if waitreason, err := s.peekStringStructField(gType, g, "waitreason", 80); err == nil {
- if waitreason != "" {
- gr.StatusString = waitreason
- }
- } else if ptr, err := s.peekPtrStructField(gType, g, "waitreason"); err == nil {
- waitreason := s.peekCString(ptr, 80)
- if waitreason != "" {
- gr.StatusString = waitreason
- }
- }
- }
-
- gr.ID, err = s.peekIntStructField(gType, g, "goid")
- if err != nil {
- return err
- }
-
- // Best-effort attempt to get the names of the goroutine function and the
- // function that created the goroutine. They aren't always available.
- functionName := func(pc uint64) string {
- entry, _, err := s.dwarfData.PCToFunction(pc)
- if err != nil {
- return ""
- }
- name, _ := entry.Val(dwarf.AttrName).(string)
- return name
- }
- if startpc, err := s.peekUintStructField(gType, g, "startpc"); err == nil {
- gr.Function = functionName(startpc)
- }
- if gopc, err := s.peekUintStructField(gType, g, "gopc"); err == nil {
- gr.Caller = functionName(gopc)
- }
- if gr.Status != debug.Running {
- // TODO: running goroutines too.
- gr.StackFrames, _ = s.goroutineStack(g)
- }
-
- resp.Goroutines = append(resp.Goroutines, &gr)
- }
-
- return nil
-}
-
-// TODO: let users specify how many frames they want. 10 will be enough to
-// determine the reason a goroutine is blocked.
-const goroutineStackFrameCount = 10
-
-// goroutineStackInit initializes s.goroutineStack.
-func (s *Server) goroutineStackInit(gType *dwarf.StructType) {
- // If we fail to read the DWARF data needed for s.goroutineStack, calling it
- // will always return the error that occurred during initialization.
- var err error // err is captured by the func below.
- s.goroutineStack = func(gAddr uint64) ([]debug.Frame, error) {
- return nil, err
- }
-
- // Get g field "sched", which contains fields pc and sp.
- schedField, err := getField(gType, "sched")
- if err != nil {
- return
- }
- schedOffset := uint64(schedField.ByteOffset)
- schedType, ok := followTypedefs(schedField.Type).(*dwarf.StructType)
- if !ok {
- err = errors.New(`g field "sched" has the wrong type`)
- return
- }
-
- // Get the size of the pc and sp fields and their offsets inside the g struct,
- // so we can quickly peek those values for each goroutine later.
- var (
- schedPCOffset, schedSPOffset uint64
- schedPCByteSize, schedSPByteSize int64
- )
- for _, x := range []struct {
- field string
- offset *uint64
- bytesize *int64
- }{
- {"pc", &schedPCOffset, &schedPCByteSize},
- {"sp", &schedSPOffset, &schedSPByteSize},
- } {
- var f *dwarf.StructField
- f, err = getField(schedType, x.field)
- if err != nil {
- return
- }
- *x.offset = schedOffset + uint64(f.ByteOffset)
- switch t := followTypedefs(f.Type).(type) {
- case *dwarf.UintType, *dwarf.IntType:
- *x.bytesize = t.Common().ByteSize
- default:
- err = fmt.Errorf("gobuf field %q has the wrong type", x.field)
- return
- }
- }
-
- s.goroutineStack = func(gAddr uint64) ([]debug.Frame, error) {
- schedPC, err := s.peekUint(gAddr+schedPCOffset, schedPCByteSize)
- if err != nil {
- return nil, err
- }
- schedSP, err := s.peekUint(gAddr+schedSPOffset, schedSPByteSize)
- if err != nil {
- return nil, err
- }
- return s.walkStack(schedPC, schedSP, goroutineStackFrameCount)
- }
-}
diff --git a/server/value.go b/server/value.go
deleted file mode 100644
index e5bb0d2..0000000
--- a/server/value.go
+++ /dev/null
@@ -1,248 +0,0 @@
-// Copyright 2015 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 server
-
-import (
- "fmt"
-
- "golang.org/x/debug"
- "golang.org/x/debug/dwarf"
-)
-
-// value peeks the program's memory at the given address, parsing it as a value of type t.
-func (s *Server) value(t dwarf.Type, addr uint64) (debug.Value, error) {
- // readBasic reads the memory for a basic type of size n bytes.
- readBasic := func(n int64) ([]byte, error) {
- switch n {
- case 1, 2, 4, 8, 16:
- default:
- return nil, fmt.Errorf("invalid size: %d", n)
- }
- buf := make([]byte, n)
- if err := s.peek(uintptr(addr), buf); err != nil {
- return nil, err
- }
- return buf, nil
- }
-
- switch t := t.(type) {
- case *dwarf.CharType, *dwarf.IntType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading integer: %s", err)
- }
- x := s.arch.IntN(buf)
- switch bs {
- case 1:
- return int8(x), nil
- case 2:
- return int16(x), nil
- case 4:
- return int32(x), nil
- case 8:
- return int64(x), nil
- default:
- return nil, fmt.Errorf("invalid integer size: %d", bs)
- }
- case *dwarf.UcharType, *dwarf.UintType, *dwarf.AddrType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading unsigned integer: %s", err)
- }
- x := s.arch.UintN(buf)
- switch bs {
- case 1:
- return uint8(x), nil
- case 2:
- return uint16(x), nil
- case 4:
- return uint32(x), nil
- case 8:
- return uint64(x), nil
- default:
- return nil, fmt.Errorf("invalid unsigned integer size: %d", bs)
- }
- case *dwarf.BoolType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading boolean: %s", err)
- }
- for _, b := range buf {
- if b != 0 {
- return true, nil
- }
- }
- return false, nil
- case *dwarf.FloatType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading float: %s", err)
- }
- switch bs {
- case 4:
- return s.arch.Float32(buf), nil
- case 8:
- return s.arch.Float64(buf), nil
- default:
- return nil, fmt.Errorf("invalid float size: %d", bs)
- }
- case *dwarf.ComplexType:
- bs := t.Common().ByteSize
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading complex: %s", err)
- }
- switch bs {
- case 8:
- return s.arch.Complex64(buf), nil
- case 16:
- return s.arch.Complex128(buf), nil
- default:
- return nil, fmt.Errorf("invalid complex size: %d", bs)
- }
- case *dwarf.PtrType:
- bs := t.Common().ByteSize
- if bs != int64(s.arch.PointerSize) {
- return nil, fmt.Errorf("invalid pointer size: %d", bs)
- }
- buf, err := readBasic(bs)
- if err != nil {
- return nil, fmt.Errorf("reading pointer: %s", err)
- }
- return debug.Pointer{
- TypeID: uint64(t.Type.Common().Offset),
- Address: uint64(s.arch.Uintptr(buf)),
- }, nil
- case *dwarf.SliceType:
- if s, err := s.peekSlice(t, addr); err != nil {
- return nil, err
- } else {
- return s, nil
- }
- case *dwarf.ArrayType:
- length := t.Count
- stride := t.StrideBitSize
- if stride%8 != 0 {
- return nil, fmt.Errorf("array is not byte-aligned")
- }
- return debug.Array{
- ElementTypeID: uint64(t.Type.Common().Offset),
- Address: uint64(addr),
- Length: uint64(length),
- StrideBits: uint64(stride),
- }, nil
- case *dwarf.StructType:
- fields := make([]debug.StructField, len(t.Field))
- for i, field := range t.Field {
- fields[i] = debug.StructField{
- Name: field.Name,
- Var: debug.Var{
- TypeID: uint64(field.Type.Common().Offset),
- Address: uint64(addr) + uint64(field.ByteOffset),
- },
- }
- }
- return debug.Struct{fields}, nil
- case *dwarf.TypedefType:
- return s.value(t.Type, addr)
- case *dwarf.MapType:
- length, err := s.peekMapLength(t, addr)
- if err != nil {
- return nil, err
- }
- return debug.Map{
- TypeID: uint64(t.Common().Offset),
- Address: addr,
- Length: length,
- }, nil
- case *dwarf.StringType:
- ptr, err := s.peekPtrStructField(&t.StructType, addr, "str")
- if err != nil {
- return nil, fmt.Errorf("reading string location: %s", err)
- }
- length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len")
- if err != nil {
- return nil, fmt.Errorf("reading string length: %s", err)
- }
-
- const maxStringSize = 256
-
- n := length
- if n > maxStringSize {
- n = maxStringSize
- }
- tmp := make([]byte, n)
- if err := s.peekBytes(ptr, tmp); err != nil {
- return nil, fmt.Errorf("reading string contents: %s", err)
- }
- return debug.String{Length: length, String: string(tmp)}, nil
- case *dwarf.ChanType:
- pt, ok := t.TypedefType.Type.(*dwarf.PtrType)
- if !ok {
- return nil, fmt.Errorf("reading channel: type is not a pointer")
- }
- st, ok := pt.Type.(*dwarf.StructType)
- if !ok {
- return nil, fmt.Errorf("reading channel: type is not a pointer to struct")
- }
-
- a, err := s.peekPtr(addr)
- if err != nil {
- return nil, fmt.Errorf("reading channel pointer: %s", err)
- }
- if a == 0 {
- // This channel is nil.
- return debug.Channel{
- ElementTypeID: uint64(t.ElemType.Common().Offset),
- Address: 0,
- Buffer: 0,
- Length: 0,
- Capacity: 0,
- Stride: uint64(t.ElemType.Common().ByteSize),
- BufferStart: 0,
- }, nil
- }
-
- buf, err := s.peekPtrStructField(st, a, "buf")
- if err != nil {
- return nil, fmt.Errorf("reading channel buffer location: %s", err)
- }
- qcount, err := s.peekUintOrIntStructField(st, a, "qcount")
- if err != nil {
- return nil, fmt.Errorf("reading channel length: %s", err)
- }
- capacity, err := s.peekUintOrIntStructField(st, a, "dataqsiz")
- if err != nil {
- return nil, fmt.Errorf("reading channel capacity: %s", err)
- }
- recvx, err := s.peekUintOrIntStructField(st, a, "recvx")
- if err != nil {
- return nil, fmt.Errorf("reading channel buffer index: %s", err)
- }
- return debug.Channel{
- ElementTypeID: uint64(t.ElemType.Common().Offset),
- Address: a,
- Buffer: buf,
- Length: qcount,
- Capacity: capacity,
- Stride: uint64(t.ElemType.Common().ByteSize),
- BufferStart: recvx,
- }, nil
- case *dwarf.FuncType:
- a, err := s.peekPtr(addr)
- if err != nil {
- return nil, fmt.Errorf("reading func: %s", err)
- }
- return debug.Func{Address: a}, nil
- case *dwarf.InterfaceType:
- return debug.Interface{}, nil
- // TODO: more types
- }
- return nil, fmt.Errorf("Unsupported type %T", t)
-}
diff --git a/tests/peek/peek_test.go b/tests/peek/peek_test.go
deleted file mode 100644
index 12c748f..0000000
--- a/tests/peek/peek_test.go
+++ /dev/null
@@ -1,1060 +0,0 @@
-// 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 peek_test
-
-import (
- "flag"
- "fmt"
- "log"
- "os"
- "os/exec"
- "reflect"
- "regexp"
- "sync"
- "testing"
-
- "golang.org/x/debug"
- "golang.org/x/debug/local"
- "golang.org/x/debug/remote"
-)
-
-var expectedVarValues = map[string]interface{}{
- `main.Z_bool_false`: false,
- `main.Z_bool_true`: true,
- `main.Z_complex128`: complex128(1.987654321 - 2.987654321i),
- `main.Z_complex64`: complex64(1.54321 + 2.54321i),
- `main.Z_float32`: float32(1.54321),
- `main.Z_float64`: float64(1.987654321),
- `main.Z_int16`: int16(-32321),
- `main.Z_int32`: int32(-1987654321),
- `main.Z_int64`: int64(-9012345678987654321),
- `main.Z_int8`: int8(-121),
- `main.Z_uint16`: uint16(54321),
- `main.Z_uint32`: uint32(3217654321),
- `main.Z_uint64`: uint64(12345678900987654321),
- `main.Z_uint8`: uint8(231),
-}
-
-// TODO: the string forms of some types we're testing aren't stable
-var expectedVars = map[string]string{
- `main.Z_array`: `[5]int8{-121, 121, 3, 2, 1}`,
- `main.Z_array_empty`: `[0]int8{}`,
- `main.Z_bool_false`: `false`,
- `main.Z_bool_true`: `true`,
- `main.Z_channel`: `(chan int16 0xX)`,
- `main.Z_channel_2`: `(chan int16 0xX)`,
- `main.Z_channel_buffered`: `(chan int16 0xX [6/10])`,
- `main.Z_channel_nil`: `(chan int16 <nil>)`,
- `main.Z_array_of_empties`: `[2]{}{{} {}, ({} 0xX)}`,
- `main.Z_complex128`: `(1.987654321-2.987654321i)`,
- `main.Z_complex64`: `(1.54321+2.54321i)`,
- `main.Z_float32`: `1.54321`,
- `main.Z_float64`: `1.987654321`,
- `main.Z_func_int8_r_int8`: `func(int8, *int8) void @0xX `,
- `main.Z_func_int8_r_pint8`: `func(int8, **int8) void @0xX `,
- `main.Z_func_bar`: `func(*main.FooStruct) void @0xX `,
- `main.Z_func_nil`: `func(int8, *int8) void @0xX `,
- `main.Z_int`: `-21`,
- `main.Z_int16`: `-32321`,
- `main.Z_int32`: `-1987654321`,
- `main.Z_int64`: `-9012345678987654321`,
- `main.Z_int8`: `-121`,
- `main.Z_int_typedef`: `88`,
- `main.Z_interface`: `("*main.FooStruct", 0xX)`,
- `main.Z_interface_nil`: `(<nil>, <nil>)`,
- `main.Z_interface_typed_nil`: `("*main.FooStruct", <nil>)`,
- `main.Z_map`: `map[-21:3.54321]`,
- `main.Z_map_2`: `map[1024:1]`,
- `main.Z_map_3`: `map[1024:1 512:-1]`,
- `main.Z_map_empty`: `map[]`,
- `main.Z_map_nil`: `map[]`,
- `main.Z_pointer`: `0xX`,
- `main.Z_pointer_nil`: `0x0`,
- `main.Z_slice`: `[]uint8{115, 108, 105, 99, 101}`,
- `main.Z_slice_2`: `[]int8{-121, 121}`,
- `main.Z_slice_nil`: `[]uint8{}`,
- `main.Z_string`: `"I'm a string"`,
- `main.Z_struct`: `main.FooStruct {21, "hi"}`,
- `main.Z_uint`: `21`,
- `main.Z_uint16`: `54321`,
- `main.Z_uint32`: `3217654321`,
- `main.Z_uint64`: `12345678900987654321`,
- `main.Z_uint8`: `231`,
- `main.Z_uintptr`: `21`,
- `main.Z_unsafe_pointer`: `0xX`,
- `main.Z_unsafe_pointer_nil`: `0x0`,
-}
-
-// expectedEvaluate contains expected results of the debug.Evaluate function.
-// A nil value indicates that an error is expected.
-var expectedEvaluate = map[string]debug.Value{
- `x`: int16(42),
- `local_array`: debug.Array{42, 42, 5, 8},
- `local_channel`: debug.Channel{42, 42, 42, 0, 0, 2, 0},
- `local_channel_buffered`: debug.Channel{42, 42, 42, 6, 10, 2, 8},
- `local_map`: debug.Map{42, 42, 1},
- `local_map_2`: debug.Map{42, 42, 1},
- `local_map_3`: debug.Map{42, 42, 2},
- `local_map_empty`: debug.Map{42, 42, 0},
- `x + 5`: int16(47),
- `x - 5`: int16(37),
- `x / 5`: int16(8),
- `x % 5`: int16(2),
- `x & 2`: int16(2),
- `x | 1`: int16(43),
- `x ^ 3`: int16(41),
- `5 + x`: int16(47),
- `5 - x`: int16(-37),
- `100 / x`: int16(2),
- `100 % x`: int16(16),
- `2 & x`: int16(2),
- `1 | x`: int16(43),
- `3 ^ x`: int16(41),
- `12`: 12,
- `+42`: 42,
- `23i`: 23i,
- `34.0`: 34.0,
- `34.5`: 34.5,
- `1e5`: 100000.0,
- `0x42`: 66,
- `'c'`: 'c',
- `"de"`: debug.String{2, `de`},
- "`ef`": debug.String{2, `ef`},
- `"de" + "fg"`: debug.String{4, `defg`},
- `/* comment */ -5`: -5,
- `false`: false,
- `true`: true,
- `!false`: true,
- `!true`: false,
- `5 + 5`: 10,
- `true || false`: true,
- `false || false`: false,
- `true && false`: false,
- `true && true`: true,
- `!(5 > 8)`: true,
- `10 + 'a'`: 'k',
- `10 + 10.5`: 20.5,
- `10 + 10.5i`: 10 + 10.5i,
- `'a' + 10.5`: 107.5,
- `'a' + 10.5i`: 97 + 10.5i,
- `10.5 + 20.5i`: 10.5 + 20.5i,
- `10 * 20`: 200,
- `10.0 - 20.5`: -10.5,
- `(6 + 8i) * 4`: 24 + 32i,
- `(6 + 8i) * (1 + 1i)`: -2 + 14i,
- `(6 + 8i) * (6 - 8i)`: complex128(100),
- `(6 + 8i) / (3 + 4i)`: complex128(2),
- `local_array[2]`: int8(3),
- `&local_array[1]`: debug.Pointer{42, 42},
- `local_map[-21]`: float32(3.54321),
- `local_map[+21]`: float32(0),
- `local_map_3[1024]`: int8(1),
- `local_map_3[512]`: int8(-1),
- `local_map_empty[21]`: float32(0),
- `"hello"[2]`: uint8('l'),
- `local_array[1:3][1]`: int8(3),
- `local_array[0:4][2:3][0]`: int8(3),
- `local_array[:]`: debug.Slice{debug.Array{42, 42, 5, 8}, 5},
- `local_array[:2]`: debug.Slice{debug.Array{42, 42, 2, 8}, 5},
- `local_array[2:]`: debug.Slice{debug.Array{42, 42, 3, 8}, 3},
- `local_array[1:3]`: debug.Slice{debug.Array{42, 42, 2, 8}, 4},
- `local_array[:3:4]`: debug.Slice{debug.Array{42, 42, 3, 8}, 4},
- `local_array[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3},
- `local_array[1:][1:][1:]`: debug.Slice{debug.Array{42, 42, 2, 8}, 2},
- `(&local_array)[:]`: debug.Slice{debug.Array{42, 42, 5, 8}, 5},
- `(&local_array)[:2]`: debug.Slice{debug.Array{42, 42, 2, 8}, 5},
- `(&local_array)[2:]`: debug.Slice{debug.Array{42, 42, 3, 8}, 3},
- `(&local_array)[1:3]`: debug.Slice{debug.Array{42, 42, 2, 8}, 4},
- `(&local_array)[:3:4]`: debug.Slice{debug.Array{42, 42, 3, 8}, 4},
- `(&local_array)[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3},
- `lookup("main.Z_array")`: debug.Array{42, 42, 5, 8},
- `lookup("main.Z_array_empty")`: debug.Array{42, 42, 0, 8},
- `lookup("main.Z_bool_false")`: false,
- `lookup("main.Z_bool_true")`: true,
- `lookup("main.Z_channel")`: debug.Channel{42, 42, 42, 0, 0, 2, 0},
- `lookup("main.Z_channel_buffered")`: debug.Channel{42, 42, 42, 6, 10, 2, 8},
- `lookup("main.Z_channel_nil")`: debug.Channel{42, 0, 0, 0, 0, 2, 0},
- `lookup("main.Z_array_of_empties")`: debug.Array{42, 42, 2, 0},
- `lookup("main.Z_complex128")`: complex128(1.987654321 - 2.987654321i),
- `lookup("main.Z_complex64")`: complex64(1.54321 + 2.54321i),
- `lookup("main.Z_float32")`: float32(1.54321),
- `lookup("main.Z_float64")`: float64(1.987654321),
- `lookup("main.Z_func_int8_r_int8")`: debug.Func{42},
- `lookup("main.Z_func_int8_r_pint8")`: debug.Func{42},
- `lookup("main.Z_func_bar")`: debug.Func{42},
- `lookup("main.Z_func_nil")`: debug.Func{0},
- `lookup("main.Z_int")`: -21,
- `lookup("main.Z_int16")`: int16(-32321),
- `lookup("main.Z_int32")`: int32(-1987654321),
- `lookup("main.Z_int64")`: int64(-9012345678987654321),
- `lookup("main.Z_int8")`: int8(-121),
- `lookup("main.Z_int_typedef")`: int16(88),
- `lookup("main.Z_interface")`: debug.Interface{},
- `lookup("main.Z_interface_nil")`: debug.Interface{},
- `lookup("main.Z_interface_typed_nil")`: debug.Interface{},
- `lookup("main.Z_map")`: debug.Map{42, 42, 1},
- `lookup("main.Z_map_2")`: debug.Map{42, 42, 1},
- `lookup("main.Z_map_3")`: debug.Map{42, 42, 2},
- `lookup("main.Z_map_empty")`: debug.Map{42, 42, 0},
- `lookup("main.Z_map_nil")`: debug.Map{42, 42, 0},
- `lookup("main.Z_pointer")`: debug.Pointer{42, 42},
- `lookup("main.Z_pointer_nil")`: debug.Pointer{42, 0},
- `lookup("main.Z_slice")`: debug.Slice{debug.Array{42, 42, 5, 8}, 5},
- `lookup("main.Z_slice_2")`: debug.Slice{debug.Array{42, 42, 2, 8}, 5},
- `lookup("main.Z_slice_nil")`: debug.Slice{debug.Array{42, 0, 0, 8}, 0},
- `lookup("main.Z_string")`: debug.String{12, `I'm a string`},
- `lookup("main.Z_struct")`: debug.Struct{[]debug.StructField{{"a", debug.Var{}}, {"b", debug.Var{}}}},
- `lookup("main.Z_uint")`: uint(21),
- `lookup("main.Z_uint16")`: uint16(54321),
- `lookup("main.Z_uint32")`: uint32(3217654321),
- `lookup("main.Z_uint64")`: uint64(12345678900987654321),
- `lookup("main.Z_uint8")`: uint8(231),
- `lookup("main.Z_uintptr")`: uint(21),
- `lookup("main.Z_unsafe_pointer")`: debug.Pointer{0, 42},
- `lookup("main.Z_unsafe_pointer_nil")`: debug.Pointer{0, 0},
- `lookup("main.Z_int") + lookup("main.Z_int")`: -42,
- `lookup("main.Z_int16") < 0`: true,
- `lookup("main.Z_uint32") + lookup("main.Z_uint32")`: uint32(2140341346),
- `lookup("main.Z_bool_true") || lookup("main.Z_bool_false")`: true,
- `lookup("main.Z_bool_true") && lookup("main.Z_bool_false")`: false,
- `lookup("main.Z_bool_false") || lookup("main.Z_bool_false")`: false,
- `!lookup("main.Z_bool_true")`: false,
- `!lookup("main.Z_bool_false")`: true,
- `lookup("main.Z_array")[2]`: int8(3),
- `lookup("main.Z_array")[1:3][1]`: int8(3),
- `lookup("main.Z_array")[0:4][2:3][0]`: int8(3),
- `lookup("main.Z_array_of_empties")[0]`: debug.Struct{},
- `lookup("main.Z_complex128") * 10.0`: complex128(19.87654321 - 29.87654321i),
- `lookup("main.Z_complex64") * 0.1`: complex64(0.154321 + 0.254321i),
- `lookup("main.Z_float32") * 10.0`: float32(15.4321),
- `lookup("main.Z_float64") * 0.1`: float64(0.1987654321),
- `lookup("main.Z_int") + 1`: int(-20),
- `lookup("main.Z_int16") - 10`: int16(-32331),
- `lookup("main.Z_int32") / 10`: int32(-198765432),
- `lookup("main.Z_int64") / 10`: int64(-901234567898765432),
- `lookup("main.Z_int8") + 10`: int8(-111),
- `lookup("main.Z_map")[-21]`: float32(3.54321),
- `lookup("main.Z_map")[+21]`: float32(0),
- `lookup("main.Z_map_empty")[21]`: float32(0),
- `lookup("main.Z_slice")[1]`: uint8(108),
- `lookup("main.Z_slice_2")[1]`: int8(121),
- `lookup("main.Z_slice")[1:5][0:3][1]`: uint8('i'),
- `lookup("main.Z_array")[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3},
- `(&lookup("main.Z_array"))[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3},
- `lookup("main.Z_string") + "!"`: debug.String{13, `I'm a string!`},
- `lookup("main.Z_struct").a`: 21,
- `(&lookup("main.Z_struct")).a`: 21,
- `lookup("main.Z_uint")/10`: uint(2),
- `lookup("main.Z_uint16")/10`: uint16(5432),
- `lookup("main.Z_uint32")/10`: uint32(321765432),
- `lookup("main.Z_uint64")/10`: uint64(1234567890098765432),
- `lookup("main.Z_uint8")/10`: uint8(23),
- `lookup("main.Z_pointer").a`: 21,
- `(*lookup("main.Z_pointer")).a`: 21,
- `(&*lookup("main.Z_pointer")).a`: 21,
- `lookup("main.Z_pointer").b`: debug.String{2, `hi`},
- `(*lookup("main.Z_pointer")).b`: debug.String{2, `hi`},
- `(&*lookup("main.Z_pointer")).b`: debug.String{2, `hi`},
- `lookup("main.Z_map_nil")[32]`: float32(0),
- `&lookup("main.Z_int16")`: debug.Pointer{42, 42},
- `&lookup("main.Z_array")[1]`: debug.Pointer{42, 42},
- `&lookup("main.Z_slice")[1]`: debug.Pointer{42, 42},
- `*&lookup("main.Z_int16")`: int16(-32321),
- `*&*&*&*&lookup("main.Z_int16")`: int16(-32321),
- `lookup("time.Local")`: debug.Pointer{42, 42},
- `5 + false`: nil,
- ``: nil,
- `x + ""`: nil,
- `x / 0`: nil,
- `0 / 0`: nil,
- `'a' / ('a'-'a')`: nil,
- `0.0 / 0.0`: nil,
- `3i / 0.0`: nil,
- `x % 0`: nil,
- `0 % 0`: nil,
- `'a' % ('a'-'a')`: nil,
- `local_array[-2] + 1`: nil,
- `local_array[22] + 1`: nil,
- `local_slice[-2] + 1`: nil,
- `local_slice[22] + 1`: nil,
- `local_string[-2]`: nil,
- `local_string[22]`: nil,
- `"hello"[-2]`: nil,
- `"hello"[22]`: nil,
- `local_pointer_nil.a`: nil,
- `(local_struct).c`: nil,
- `(&local_struct).c`: nil,
- `(*local_pointer).c`: nil,
- `lookup("not a real symbol")`: nil,
- `lookup("x")`: nil,
- `lookup(x)`: nil,
- `lookup(42)`: nil,
-}
-
-func isHex(r uint8) bool {
- switch {
- case '0' <= r && r <= '9':
- return true
- case 'a' <= r && r <= 'f':
- return true
- case 'A' <= r && r <= 'F':
- return true
- default:
- return false
- }
-}
-
-// structRE is used by matches to remove 'struct ' from type names, which is not
-// output by every version of the compiler.
-var structRE = regexp.MustCompile("struct *")
-
-// Check s matches the pattern in p.
-// An 'X' in p greedily matches one or more hex characters in s.
-func matches(p, s string) bool {
- // Remove 'struct' and following spaces from s.
- s = structRE.ReplaceAllString(s, "")
- j := 0
- for i := 0; i < len(p); i++ {
- if j == len(s) {
- return false
- }
- c := p[i]
- if c == 'X' {
- if !isHex(s[j]) {
- return false
- }
- for j < len(s) && isHex(s[j]) {
- j++
- }
- continue
- }
- if c != s[j] {
- return false
- }
- j++
- }
- return j == len(s)
-}
-
-const (
- proxySrc = "golang.org/x/debug/cmd/debugproxy"
- traceeSrc = "golang.org/x/debug/tests/peek/testdata"
-)
-
-var (
- // Locations of the proxy and tracee executables.
- proxyBinary = "./debugproxy.out"
- traceeBinary = "./tracee.out"
- // Onces that ensure initProxy and initTracee are called at most once.
- proxyOnce sync.Once
- traceeOnce sync.Once
- // Flags for setting the location of the proxy and tracee, so they don't need to be built.
- proxyFlag = flag.String("proxy", "", "Location of debugproxy. If empty, proxy will be built.")
- traceeFlag = flag.String("target", "", "Location of target. If empty, target will be built.")
- // Executables this test has built, which will be removed on completion of the tests.
- filesToRemove []string
-)
-
-func TestMain(m *testing.M) {
- flag.Parse()
- x := m.Run()
- for _, f := range filesToRemove {
- os.Remove(f)
- }
- os.Exit(x)
-}
-
-func run(name string, args ...string) error {
- cmd := exec.Command(name, args...)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- return cmd.Run()
-}
-
-func initProxy() {
- if *proxyFlag != "" {
- proxyBinary = *proxyFlag
- remote.DebugproxyCmd = proxyBinary
- return
- }
- if err := run("go", "build", "-o", proxyBinary, proxySrc); err != nil {
- log.Fatalf("couldn't build proxy: %v", err)
- }
- filesToRemove = append(filesToRemove, proxyBinary)
- remote.DebugproxyCmd = proxyBinary
-}
-
-func initTracee() {
- if *traceeFlag != "" {
- traceeBinary = *traceeFlag
- return
- }
- if err := run("go", "build", "-o", traceeBinary, traceeSrc); err != nil {
- log.Fatalf("couldn't build target: %v", err)
- }
- filesToRemove = append(filesToRemove, traceeBinary)
-}
-
-func TestLocalProgram(t *testing.T) {
- traceeOnce.Do(initTracee)
- prog, err := local.New(traceeBinary)
- if err != nil {
- t.Fatal("local.New:", err)
- }
- testProgram(t, prog)
-}
-
-func TestRemoteProgram(t *testing.T) {
- traceeOnce.Do(initTracee)
- proxyOnce.Do(initProxy)
- prog, err := remote.New("localhost", traceeBinary)
- if err != nil {
- t.Fatal("remote.New:", err)
- }
- testProgram(t, prog)
-}
-
-func testProgram(t *testing.T, prog debug.Program) {
- _, err := prog.Run("some", "arguments")
- if err != nil {
- log.Fatalf("Run: %v", err)
- }
-
- pcs, err := prog.BreakpointAtFunction("main.foo")
- if err != nil {
- log.Fatalf("BreakpointAtFunction: %v", err)
- }
- fmt.Printf("breakpoints set at %x\n", pcs)
-
- _, err = prog.Resume()
- if err != nil {
- log.Fatalf("Resume: %v", err)
- }
-
- gs, err := prog.Goroutines()
- if err != nil {
- t.Fatalf("Goroutines(): got error %s", err)
- }
- for _, g := range gs {
- fmt.Println(g)
- for _, f := range g.StackFrames {
- fmt.Println(f)
- }
- }
-
- frames, err := prog.Frames(100)
- if err != nil {
- log.Fatalf("prog.Frames error: %v", err)
- }
- fmt.Printf("%#v\n", frames)
- if len(frames) == 0 {
- t.Fatalf("no stack frames returned")
- }
- if frames[0].Function != "main.foo" {
- t.Errorf("function name: got %s expected main.foo", frames[0].Function)
- }
- if len(frames[0].Params) != 2 {
- t.Errorf("got %d parameters, expected 2", len(frames[0].Params))
- } else {
- x := frames[0].Params[0]
- y := frames[0].Params[1]
- if x.Name != "x" {
- x, y = y, x
- }
- if x.Name != "x" {
- t.Errorf("parameter name: got %s expected x", x.Name)
- }
- if y.Name != "y" {
- t.Errorf("parameter name: got %s expected y", y.Name)
- }
- if val, err := prog.Value(x.Var); err != nil {
- t.Errorf("value of x: %s", err)
- } else if val != int16(42) {
- t.Errorf("value of x: got %T(%v) expected int16(42)", val, val)
- }
- if val, err := prog.Value(y.Var); err != nil {
- t.Errorf("value of y: %s", err)
- } else if val != float32(1.5) {
- t.Errorf("value of y: got %T(%v) expected float32(1.5)", val, val)
- }
- }
-
- varnames, err := prog.Eval(`re:main\.Z_.*`)
- if err != nil {
- log.Fatalf("prog.Eval error: %v", err)
- }
-
- // Evaluate each of the variables found above, and check they match
- // expectedVars.
- seen := make(map[string]bool)
- for _, v := range varnames {
- val, err := prog.Eval("val:" + v)
- if err != nil {
- log.Fatalf("prog.Eval error for %s: %v", v, err)
- } else {
- fmt.Printf("%s = %v\n", v, val)
- if seen[v] {
- log.Fatalf("repeated variable %s\n", v)
- }
- seen[v] = true
- if len(val) != 1 {
- log.Fatalf("should be one value for %s\n", v)
- }
- expected, ok := expectedVars[v]
- if !ok {
- log.Fatalf("unexpected variable %s\n", v)
- } else {
- if !matches(expected, val[0]) {
- log.Fatalf("expected %s = %s\n", v, expected)
- }
- }
- }
- }
- for v, e := range expectedVars {
- if !seen[v] {
- log.Fatalf("didn't get %s = %s\n", v, e)
- }
- }
-
- // Remove the breakpoint at main.foo.
- err = prog.DeleteBreakpoints(pcs)
- if err != nil {
- log.Fatalf("DeleteBreakpoints: %v", err)
- }
-
- // Set a breakpoint at line 125, resume, and check we stopped there.
- pcsLine125, err := prog.BreakpointAtLine("testdata/main.go", 125)
- if err != nil {
- t.Fatal("BreakpointAtLine:", err)
- }
- status, err := prog.Resume()
- if err != nil {
- log.Fatalf("Resume: %v", err)
- }
- stoppedAt := func(pcs []uint64) bool {
- for _, pc := range pcs {
- if status.PC == pc {
- return true
- }
- }
- return false
- }
- if !stoppedAt(pcsLine125) {
- t.Errorf("stopped at %X; expected one of %X.", status.PC, pcsLine125)
- }
-
- for k, v := range expectedEvaluate {
- val, err := prog.Evaluate(k)
- if v == nil {
- if err == nil {
- t.Errorf("got Evaluate(%s) = %v, expected error", k, val)
- }
- continue
- }
- if err != nil {
- t.Errorf("Evaluate(%s): got error %s, expected %v", k, err, v)
- continue
- }
- typ := reflect.TypeOf(v)
- if typ != reflect.TypeOf(val) && typ != reflect.TypeOf(int(0)) && typ != reflect.TypeOf(uint(0)) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- continue
- }
-
- // For types with fields like Address, TypeID, etc., we can't know the exact
- // value, so we only test whether those fields are zero or not.
- switch v := v.(type) {
- default:
- if v != val {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- }
- case debug.Array:
- val := val.(debug.Array)
- if v.ElementTypeID == 0 && val.ElementTypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val)
- }
- if v.ElementTypeID != 0 && val.ElementTypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case debug.Slice:
- val := val.(debug.Slice)
- if v.ElementTypeID == 0 && val.ElementTypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val)
- }
- if v.ElementTypeID != 0 && val.ElementTypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case debug.Map:
- val := val.(debug.Map)
- if v.TypeID == 0 && val.TypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero TypeID", k, val)
- }
- if v.TypeID != 0 && val.TypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero TypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case debug.Pointer:
- val := val.(debug.Pointer)
- if v.TypeID == 0 && val.TypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero TypeID", k, val)
- }
- if v.TypeID != 0 && val.TypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero TypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case debug.Channel:
- val := val.(debug.Channel)
- if v.ElementTypeID == 0 && val.ElementTypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val)
- }
- if v.ElementTypeID != 0 && val.ElementTypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- if v.Buffer == 0 && val.Buffer != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Buffer", k, val)
- }
- if v.Buffer != 0 && val.Buffer == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Buffer", k, val)
- }
- case debug.Struct:
- val := val.(debug.Struct)
- if len(v.Fields) != len(val.Fields) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- break
- }
- for i := range v.Fields {
- a := v.Fields[i].Name
- b := val.Fields[i].Name
- if a != b {
- t.Errorf("Evaluate(%s): field name mismatch: %s vs %s", k, a, b)
- break
- }
- }
- case debug.Func:
- val := val.(debug.Func)
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case int:
- // ints in a remote program can be returned as int32 or int64
- switch val := val.(type) {
- case int32:
- if val != int32(v) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v)
- }
- case int64:
- if val != int64(v) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v)
- }
- default:
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- }
- case uint:
- // uints in a remote program can be returned as uint32 or uint64
- switch val := val.(type) {
- case uint32:
- if val != uint32(v) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v)
- }
- case uint64:
- if val != uint64(v) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v)
- }
- default:
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- }
- }
- }
-
- // Evaluate a struct.
- v := `lookup("main.Z_struct")`
- val, err := prog.Evaluate(v)
- if err != nil {
- t.Fatalf("Evaluate: %s", err)
- }
- s, ok := val.(debug.Struct)
- if !ok {
- t.Fatalf("got Evaluate(%q) = %T(%v), expected debug.Struct", v, val, val)
- }
- // Check the values of its fields.
- if len(s.Fields) != 2 {
- t.Fatalf("got Evaluate(%q) = %+v, expected 2 fields", v, s)
- }
- if v0, err := prog.Value(s.Fields[0].Var); err != nil {
- t.Errorf("Value: %s", err)
- } else if v0 != int32(21) && v0 != int64(21) {
- t.Errorf("Value: got %T(%v), expected 21", v0, v0)
- }
- if v1, err := prog.Value(s.Fields[1].Var); err != nil {
- t.Errorf("Value: %s", err)
- } else if v1 != (debug.String{2, "hi"}) {
- t.Errorf("Value: got %T(%v), expected `hi`", v1, v1)
- }
-
- // Remove the breakpoint at line 125, set a breakpoint at main.f1 and main.f2,
- // then delete the breakpoint at main.f1. Resume, then check we stopped at
- // main.f2.
- err = prog.DeleteBreakpoints(pcsLine125)
- if err != nil {
- log.Fatalf("DeleteBreakpoints: %v", err)
- }
- pcs1, err := prog.BreakpointAtFunction("main.f1")
- if err != nil {
- log.Fatalf("BreakpointAtFunction: %v", err)
- }
- pcs2, err := prog.BreakpointAtFunction("main.f2")
- if err != nil {
- log.Fatalf("BreakpointAtFunction: %v", err)
- }
- err = prog.DeleteBreakpoints(pcs1)
- if err != nil {
- log.Fatalf("DeleteBreakpoints: %v", err)
- }
- status, err = prog.Resume()
- if err != nil {
- log.Fatalf("Resume: %v", err)
- }
- if !stoppedAt(pcs2) {
- t.Errorf("stopped at %X; expected one of %X.", status.PC, pcs2)
- }
-
- // Check we get the expected results calling VarByName then Value
- // for the variables in expectedVarValues.
- for name, exp := range expectedVarValues {
- if v, err := prog.VarByName(name); err != nil {
- t.Errorf("VarByName(%s): %s", name, err)
- } else if val, err := prog.Value(v); err != nil {
- t.Errorf("value of %s: %s", name, err)
- } else if val != exp {
- t.Errorf("value of %s: got %T(%v) want %T(%v)", name, val, val, exp, exp)
- }
- }
-
- // Check some error cases for VarByName and Value.
- if _, err = prog.VarByName("not a real name"); err == nil {
- t.Error("VarByName for invalid name: expected error")
- }
- if _, err = prog.Value(debug.Var{}); err == nil {
- t.Error("value of invalid var: expected error")
- }
- if v, err := prog.VarByName("main.Z_int16"); err != nil {
- t.Error("VarByName(main.Z_int16) error:", err)
- } else {
- v.Address = 0
- // v now has a valid type but a bad address.
- _, err = prog.Value(v)
- if err == nil {
- t.Error("value of invalid location: expected error")
- }
- }
-
- // checkValue tests that we can get a Var for a variable with the given name,
- // that we can then get the value of that Var, and that calling fn for that
- // value succeeds.
- checkValue := func(name string, fn func(val debug.Value) error) {
- if v, err := prog.VarByName(name); err != nil {
- t.Errorf("VarByName(%s): %s", name, err)
- } else if val, err := prog.Value(v); err != nil {
- t.Errorf("value of %s: %s", name, err)
- } else if err := fn(val); err != nil {
- t.Errorf("value of %s: %s", name, err)
- }
- }
-
- checkValue("main.Z_uintptr", func(val debug.Value) error {
- if val != uint32(21) && val != uint64(21) {
- // Z_uintptr should be an unsigned integer with size equal to the debugged
- // program's address size.
- return fmt.Errorf("got %T(%v) want 21", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_int", func(val debug.Value) error {
- if val != int32(-21) && val != int64(-21) {
- return fmt.Errorf("got %T(%v) want -21", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_uint", func(val debug.Value) error {
- if val != uint32(21) && val != uint64(21) {
- return fmt.Errorf("got %T(%v) want 21", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_pointer", func(val debug.Value) error {
- if _, ok := val.(debug.Pointer); !ok {
- return fmt.Errorf("got %T(%v) expected Pointer", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_pointer_nil", func(val debug.Value) error {
- if p, ok := val.(debug.Pointer); !ok {
- return fmt.Errorf("got %T(%v) expected Pointer", val, val)
- } else if p.Address != 0 {
- return fmt.Errorf("got %T(%v) expected nil pointer", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_array", func(val debug.Value) error {
- a, ok := val.(debug.Array)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Array", val, val)
- }
- if a.Len() != 5 {
- return fmt.Errorf("got array length %d expected 5", a.Len())
- }
- expected := [5]int8{-121, 121, 3, 2, 1}
- for i := uint64(0); i < 5; i++ {
- if v, err := prog.Value(a.Element(i)); err != nil {
- return fmt.Errorf("reading element %d: %s", i, err)
- } else if v != expected[i] {
- return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i])
- }
- }
- return nil
- })
-
- checkValue("main.Z_slice", func(val debug.Value) error {
- s, ok := val.(debug.Slice)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Slice", val, val)
- }
- if s.Len() != 5 {
- return fmt.Errorf("got slice length %d expected 5", s.Len())
- }
- expected := []uint8{115, 108, 105, 99, 101}
- for i := uint64(0); i < 5; i++ {
- if v, err := prog.Value(s.Element(i)); err != nil {
- return fmt.Errorf("reading element %d: %s", i, err)
- } else if v != expected[i] {
- return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i])
- }
- }
- return nil
- })
-
- checkValue("main.Z_map_empty", func(val debug.Value) error {
- m, ok := val.(debug.Map)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Map", val, val)
- }
- if m.Length != 0 {
- return fmt.Errorf("got map length %d expected 0", m.Length)
- }
- return nil
- })
-
- checkValue("main.Z_map_nil", func(val debug.Value) error {
- m, ok := val.(debug.Map)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Map", val, val)
- }
- if m.Length != 0 {
- return fmt.Errorf("got map length %d expected 0", m.Length)
- }
- return nil
- })
-
- checkValue("main.Z_map_3", func(val debug.Value) error {
- m, ok := val.(debug.Map)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Map", val, val)
- }
- if m.Length != 2 {
- return fmt.Errorf("got map length %d expected 2", m.Length)
- }
- keyVar0, valVar0, err := prog.MapElement(m, 0)
- if err != nil {
- return err
- }
- keyVar1, valVar1, err := prog.MapElement(m, 1)
- if err != nil {
- return err
- }
- key0, err := prog.Value(keyVar0)
- if err != nil {
- return err
- }
- key1, err := prog.Value(keyVar1)
- if err != nil {
- return err
- }
- val0, err := prog.Value(valVar0)
- if err != nil {
- return err
- }
- val1, err := prog.Value(valVar1)
- if err != nil {
- return err
- }
- // The map should contain 1024,1 and 512,-1 in some order.
- ok1 := key0 == int16(1024) && val0 == int8(1) && key1 == int16(512) && val1 == int8(-1)
- ok2 := key1 == int16(1024) && val1 == int8(1) && key0 == int16(512) && val0 == int8(-1)
- if !ok1 && !ok2 {
- return fmt.Errorf("got values (%d,%d) and (%d,%d), expected (1024,1) and (512,-1) in some order", key0, val0, key1, val1)
- }
- _, _, err = prog.MapElement(m, 2)
- if err == nil {
- return fmt.Errorf("MapElement: reading at a bad index succeeded, expected error")
- }
- return nil
- })
-
- checkValue("main.Z_string", func(val debug.Value) error {
- s, ok := val.(debug.String)
- if !ok {
- return fmt.Errorf("got %T(%v) expected String", val, val)
- }
- if s.Length != 12 {
- return fmt.Errorf("got string length %d expected 12", s.Length)
- }
- expected := "I'm a string"
- if s.String != expected {
- return fmt.Errorf("got %s expected %s", s.String, expected)
- }
- return nil
- })
-
- checkValue("main.Z_channel", func(val debug.Value) error {
- c, ok := val.(debug.Channel)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Channel", val, val)
- }
- if c.Buffer == 0 {
- return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer)
- }
- if c.Length != 0 {
- return fmt.Errorf("got length %d expected 0", c.Length)
- }
- if c.Capacity != 0 {
- return fmt.Errorf("got capacity %d expected 0", c.Capacity)
- }
- return nil
- })
-
- checkValue("main.Z_channel_2", func(val debug.Value) error {
- c, ok := val.(debug.Channel)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Channel", val, val)
- }
- if c.Buffer == 0 {
- return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer)
- }
- if c.Length != 0 {
- return fmt.Errorf("got length %d expected 0", c.Length)
- }
- if c.Capacity != 0 {
- return fmt.Errorf("got capacity %d expected 0", c.Capacity)
- }
- return nil
- })
-
- checkValue("main.Z_channel_nil", func(val debug.Value) error {
- c, ok := val.(debug.Channel)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Channel", val, val)
- }
- if c.Buffer != 0 {
- return fmt.Errorf("got buffer address %d expected 0", c.Buffer)
- }
- if c.Length != 0 {
- return fmt.Errorf("got length %d expected 0", c.Length)
- }
- if c.Capacity != 0 {
- return fmt.Errorf("got capacity %d expected 0", c.Capacity)
- }
- return nil
- })
-
- checkValue("main.Z_channel_buffered", func(val debug.Value) error {
- c, ok := val.(debug.Channel)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Channel", val, val)
- }
- if c.Buffer == 0 {
- return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer)
- }
- if c.Length != 6 {
- return fmt.Errorf("got length %d expected 6", c.Length)
- }
- if c.Capacity != 10 {
- return fmt.Errorf("got capacity %d expected 10", c.Capacity)
- }
- if c.Stride != 2 {
- return fmt.Errorf("got stride %d expected 2", c.Stride)
- }
- expected := []int16{8, 9, 10, 11, 12, 13}
- for i := uint64(0); i < 6; i++ {
- if v, err := prog.Value(c.Element(i)); err != nil {
- return fmt.Errorf("reading element %d: %s", i, err)
- } else if v != expected[i] {
- return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i])
- }
- }
- v := c.Element(6)
- if v.Address != 0 {
- return fmt.Errorf("invalid element returned Var with address %d, expected 0", v.Address)
- }
- return nil
- })
-
- checkValue("main.Z_func_bar", func(val debug.Value) error {
- f, ok := val.(debug.Func)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Func", val, val)
- }
- if f.Address == 0 {
- return fmt.Errorf("got func address %d expected nonzero", f.Address)
- }
- return nil
- })
-
- checkValue("main.Z_func_nil", func(val debug.Value) error {
- f, ok := val.(debug.Func)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Func", val, val)
- }
- if f.Address != 0 {
- return fmt.Errorf("got func address %d expected zero", f.Address)
- }
- return nil
- })
-}
diff --git a/tests/peek/testdata/main.go b/tests/peek/testdata/main.go
deleted file mode 100644
index 61a568e..0000000
--- a/tests/peek/testdata/main.go
+++ /dev/null
@@ -1,193 +0,0 @@
-// 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 main
-
-import (
- "fmt"
- "log"
- "os"
- "time"
- "unsafe"
-)
-
-type FooInterface interface {
- Bar()
-}
-
-type FooStruct struct {
- a int
- b string
-}
-
-func (f *FooStruct) Bar() {}
-
-type myInt int16
-
-var (
- Z_bool_false bool = false
- Z_bool_true bool = true
- Z_int int = -21
- Z_int8 int8 = -121
- Z_int16 int16 = -32321
- Z_int32 int32 = -1987654321
- Z_int64 int64 = -9012345678987654321
- Z_int_typedef myInt = 88
- Z_uint uint = 21
- Z_uint8 uint8 = 231
- Z_uint16 uint16 = 54321
- Z_uint32 uint32 = 3217654321
- Z_uint64 uint64 = 12345678900987654321
- Z_uintptr uintptr = 21
- Z_float32 float32 = 1.54321
- Z_float64 float64 = 1.987654321
- Z_complex64 complex64 = 1.54321 + 2.54321i
- Z_complex128 complex128 = 1.987654321 - 2.987654321i
- Z_array [5]int8 = [5]int8{-121, 121, 3, 2, 1}
- Z_array_empty [0]int8 = [0]int8{}
- Z_array_of_empties [2]struct{} = [2]struct{}{struct{}{}, struct{}{}}
- Z_channel chan int16 = make(chan int16)
- Z_channel_2 chan int16 = make(chan int16)
- Z_channel_buffered chan int16 = make(chan int16, 10)
- Z_channel_nil chan int16
- Z_func_bar = (*FooStruct).Bar
- Z_func_int8_r_int8 = func(x int8) int8 { return x + 1 }
- Z_func_int8_r_pint8 = func(x int8) *int8 { y := x + 1; return &y }
- Z_func_nil func(x int8) int8 = nil
- Z_interface FooInterface = &Z_struct
- Z_interface_typed_nil FooInterface = Z_pointer_nil
- Z_interface_nil FooInterface
- Z_map map[int8]float32 = map[int8]float32{-21: 3.54321}
- Z_map_2 map[int16]int8 = map[int16]int8{1024: 1}
- Z_map_3 map[int16]int8 = map[int16]int8{1024: 1, 512: -1}
- Z_map_empty map[int8]float32 = map[int8]float32{}
- Z_map_nil map[int8]float32
- Z_pointer *FooStruct = &Z_struct
- Z_pointer_nil *FooStruct
- Z_slice []byte = []byte{'s', 'l', 'i', 'c', 'e'}
- Z_slice_2 []int8 = Z_array[0:2]
- Z_slice_nil []byte
- Z_string string = "I'm a string"
- Z_struct FooStruct = FooStruct{a: 21, b: "hi"}
- Z_unsafe_pointer unsafe.Pointer = unsafe.Pointer(&Z_uint)
- Z_unsafe_pointer_nil unsafe.Pointer
-)
-
-func foo(x int16, y float32) {
- var (
- local_array [5]int8 = [5]int8{-121, 121, 3, 2, 1}
- local_bool_false bool = false
- local_bool_true bool = true
- local_channel chan int16 = Z_channel
- local_channel_buffered chan int16 = Z_channel_buffered
- local_channel_nil chan int16
- local_complex128 complex128 = 1.987654321 - 2.987654321i
- local_complex64 complex64 = 1.54321 + 2.54321i
- local_float32 float32 = 1.54321
- local_float64 float64 = 1.987654321
- local_func_bar = (*FooStruct).Bar
- local_func_int8_r_int8 = func(x int8) int8 { return x + 1 }
- local_func_int8_r_pint8 = func(x int8) *int8 { y := x + 1; return &y }
- local_func_nil func(x int8) int8 = nil
- local_int int = -21
- local_int16 int16 = -32321
- local_int32 int32 = -1987654321
- local_int64 int64 = -9012345678987654321
- local_int8 int8 = -121
- local_int_typedef myInt = 88
- local_interface FooInterface = &Z_struct
- local_interface_nil FooInterface
- local_interface_typed_nil FooInterface = Z_pointer_nil
- local_map map[int8]float32 = map[int8]float32{-21: 3.54321}
- local_map_2 map[int16]int8 = map[int16]int8{1024: 1}
- local_map_3 map[int16]int8 = map[int16]int8{1024: 1, 512: -1}
- local_map_empty map[int8]float32 = map[int8]float32{}
- local_map_nil map[int8]float32
- local_pointer *FooStruct = &Z_struct
- local_pointer_nil *FooStruct
- local_slice []byte = []byte{'s', 'l', 'i', 'c', 'e'}
- local_slice_2 []int8 = Z_array[0:2]
- local_slice_nil []byte
- local_string string = "I'm a string"
- local_struct FooStruct = FooStruct{a: 21, b: "hi"}
- local_uint uint = 21
- local_uint16 uint16 = 54321
- local_uint32 uint32 = 3217654321
- local_uint64 uint64 = 12345678900987654321
- local_uint8 uint8 = 231
- local_uintptr uintptr = 21
- local_unsafe_pointer unsafe.Pointer = unsafe.Pointer(&Z_uint)
- local_unsafe_pointer_nil unsafe.Pointer
- )
- fmt.Println(Z_bool_false, Z_bool_true)
- fmt.Println(Z_int, Z_int8, Z_int16, Z_int32, Z_int64, Z_int_typedef)
- fmt.Println(Z_uint, Z_uint8, Z_uint16, Z_uint32, Z_uint64, Z_uintptr)
- fmt.Println(Z_float32, Z_float64, Z_complex64, Z_complex128)
- fmt.Println(Z_array, Z_array_empty, Z_array_of_empties)
- fmt.Println(Z_channel, Z_channel_buffered, Z_channel_nil)
- fmt.Println(Z_func_bar, Z_func_int8_r_int8, Z_func_int8_r_pint8, Z_func_nil)
- fmt.Println(Z_interface, Z_interface_nil, Z_interface_typed_nil)
- fmt.Println(Z_map, Z_map_2, Z_map_3, Z_map_empty, Z_map_nil)
- fmt.Println(Z_pointer, Z_pointer_nil)
- fmt.Println(Z_slice, Z_slice_2, Z_slice_nil)
- fmt.Println(Z_string, Z_struct)
- fmt.Println(Z_unsafe_pointer, Z_unsafe_pointer_nil)
- fmt.Println(local_bool_false, local_bool_true)
- fmt.Println(local_int, local_int8, local_int16, local_int32, local_int64, local_int_typedef)
- fmt.Println(local_uint, local_uint8, local_uint16, local_uint32, local_uint64, local_uintptr)
- fmt.Println(local_float32, local_float64, local_complex64, local_complex128, local_array)
- fmt.Println(local_channel, local_channel_buffered, local_channel_nil)
- fmt.Println(local_func_bar, local_func_int8_r_int8, local_func_int8_r_pint8, local_func_nil)
- fmt.Println(local_interface, local_interface_nil, local_interface_typed_nil)
- fmt.Println(local_map, local_map_2, local_map_3, local_map_empty, local_map_nil)
- fmt.Println(local_pointer, local_pointer_nil)
- fmt.Println(local_slice, local_slice_2, local_slice_nil)
- fmt.Println(local_string, local_struct)
- fmt.Println(local_unsafe_pointer, local_unsafe_pointer_nil)
- f1()
- f2()
-}
-
-func f1() {
- fmt.Println()
-}
-
-func f2() {
- fmt.Println()
-}
-
-func bar() {
- foo(42, 1.5)
- fmt.Print()
-}
-
-func populateChannels() {
- go func() {
- Z_channel_2 <- 8
- }()
- go func() {
- for i := int16(0); i < 14; i++ {
- Z_channel_buffered <- i
- }
- }()
- go func() {
- for i := 0; i < 8; i++ {
- <-Z_channel_buffered
- }
- }()
- time.Sleep(time.Second / 20)
-}
-
-func main() {
- args := os.Args[1:]
- expected := []string{"some", "arguments"}
- if len(args) != 2 || args[0] != expected[0] || args[1] != expected[1] {
- log.Fatalf("got command-line args %v, expected %v", args, expected)
- }
- populateChannels()
- for ; ; time.Sleep(2 * time.Second) {
- bar()
- }
- select {}
-}