x/debug: reorganize directory structure. Fundamental types like Program, Var, Value, Frame are now in x/debug. Deletes some unreferenced prototype code. Change-Id: I618c6ee8327ef7f76f31a7cc98673cd3f38f2461 Reviewed-on: https://go-review.googlesource.com/19876 Reviewed-by: Rob Pike <r@golang.org> Reviewed-by: Dave Day <djd@golang.org>
diff --git a/ogle/arch/arch.go b/arch/arch.go similarity index 98% rename from ogle/arch/arch.go rename to arch/arch.go index 4c76dc0..acd2ee9 100644 --- a/ogle/arch/arch.go +++ b/arch/arch.go
@@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package arch contains architecture-specific definitions. -package arch // import "golang.org/x/debug/ogle/arch" +package arch // import "golang.org/x/debug/arch" import ( "encoding/binary"
diff --git a/ogle/cmd/ogleproxy/main.go b/cmd/debugproxy/main.go similarity index 72% rename from ogle/cmd/ogleproxy/main.go rename to cmd/debugproxy/main.go index 5459118..942790b 100644 --- a/ogle/cmd/ogleproxy/main.go +++ b/cmd/debugproxy/main.go
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The ogleproxy connects to the target binary and serves an RPC -// interface to access and control it. +// 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 ( @@ -13,7 +13,7 @@ "net/rpc" "os" - "golang.org/x/debug/ogle/program/server" + "golang.org/x/debug/server" ) var ( @@ -22,31 +22,29 @@ func main() { log.SetFlags(0) - log.SetPrefix("ogleproxy: ") + log.SetPrefix("debugproxy: ") flag.Parse() if *textFlag == "" { - fmt.Printf("OGLE BAD\n") flag.Usage() os.Exit(2) } s, err := server.New(*textFlag) if err != nil { - fmt.Printf("OGLE BAD\n%s\n", err) + fmt.Printf("server.New: %v\n", err) os.Exit(2) } err = rpc.Register(s) if err != nil { - fmt.Printf("OGLE BAD\n%s\n", err) + fmt.Printf("rpc.Register: %v\n", err) os.Exit(2) } - fmt.Println("OGLE OK") - log.Print("start server") - // TODO: Usually done in a go. + fmt.Println("OK") + log.Print("starting server") rpc.ServeConn(&rwc{ os.Stdin, os.Stdout, }) - log.Print("finish server") + log.Print("server finished") } // rwc creates a single io.ReadWriteCloser from a read side and a write side.
diff --git a/ogle/doc/ptrace-nptl.txt b/doc/ptrace-nptl.txt similarity index 100% rename from ogle/doc/ptrace-nptl.txt rename to doc/ptrace-nptl.txt
diff --git a/local/local.go b/local/local.go new file mode 100644 index 0000000..e054249 --- /dev/null +++ b/local/local.go
@@ -0,0 +1,193 @@ +// 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/ogle/demo/ptrace-linux-amd64/main.go b/ogle/demo/ptrace-linux-amd64/main.go deleted file mode 100644 index c90c534..0000000 --- a/ogle/demo/ptrace-linux-amd64/main.go +++ /dev/null
@@ -1,270 +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. - -// This program is a standalone demo that demonstrates a Go tracer program -// (this program) forking, executing and inserting breakpoints into a (multi- -// threaded) Go tracee program. It logs all syscall.Wait4 results, and reading -// those logs, as well as ../../doc/ptrace-nptl.txt, should help understand how -// the (more complicated) golang.org/x/debug/ogle/program/server package works. -// -// Only tested on linux/amd64. -package main - -// TODO: other threads are not stopped when one tracee thread hits a breakpoint. -// Thus, other threads could racily miss a breakpoint when they concurrently -// execute code where the trap should be, in between lifting and re-setting the -// trap. -// -// One option is to simply accept this behavior as is. Another option, "all- -// stop", is to stop all other threads when one traps. A third option, "non- -// stop", is to not lift the trap and not stop other threads, but to simulate -// the original instruction when single-stepping: the "Non-stop Multi-Threaded -// Debugging in GDB" paper calls this "displaced stepping". "Non-stop" is less -// intrusive than "all-stop" (e.g. network I/O can still happen while at a -// breakpoint), but it involves complicated, architecture-specific code. - -import ( - "fmt" - "log" - "os" - "runtime" - "syscall" - "time" - - "golang.org/x/debug/dwarf" - "golang.org/x/debug/elf" - "golang.org/x/debug/macho" -) - -const ( - exeFilename = "tracee/tracee" - - // TODO: don't be amd64-specific. - breakpointInstr = 0xcc - breakpointInstrLen = 1 -) - -type breakpoint struct { - pc uint64 - origInstr byte // TODO: don't be amd64-specific. -} - -func main() { - go run() - time.Sleep(2 * time.Second) -} - -func run() { - // If the debugger itself is multi-threaded, ptrace calls must come from - // the same thread that originally attached to the remote thread. - runtime.LockOSThread() - - f, err := os.Open(exeFilename) - if err != nil { - log.Printf(`%q not found. Did you run "go build ." in that directory?`, exeFilename) - log.Fatalf("Open: %v", err) - } - defer f.Close() - dwarfData, err := loadDwarfData(f) - if err != nil { - log.Fatalf("loadDwarfData: %v", err) - } - - proc, err := os.StartProcess(exeFilename, []string{exeFilename}, &os.ProcAttr{ - Files: []*os.File{ - os.Stdin, - os.Stdout, - os.Stderr, - }, - Sys: &syscall.SysProcAttr{ - Ptrace: true, - Pdeathsig: syscall.SIGKILL, - }, - }) - if err != nil { - log.Fatalf("StartProcess: %v", err) - } - - fmt.Printf("\tproc.Pid=%d\n", proc.Pid) - - _, status, err := wait(proc.Pid) - if err != nil { - log.Fatalf("wait: %v", err) - } - if status != 0x00057f { // 0x05=SIGTRAP, 0x7f=stopped. - log.Fatalf("status: got %#x, want %#x", status, 0x57f) - } - err = syscall.PtraceSetOptions(proc.Pid, syscall.PTRACE_O_TRACECLONE|syscall.PTRACE_O_TRACEEXIT) - if err != nil { - log.Fatalf("PtraceSetOptions: %v", err) - } - - addr, err := lookupSym(dwarfData, "fmt.Printf") - if err != nil { - log.Fatalf("lookupSym: %v", err) - } - fmt.Printf("\tfmt.Printf=%#x\n", addr) - - var buf [1]byte - if err := peek(proc.Pid, addr, buf[:1]); err != nil { - log.Fatalf("peek: %v", err) - } - breakpoints := map[uint64]breakpoint{ - addr: {pc: addr, origInstr: buf[0]}, - } - buf[0] = breakpointInstr - if err := poke(proc.Pid, addr, buf[:1]); err != nil { - log.Fatalf("poke: %v", err) - } - - err = syscall.PtraceCont(proc.Pid, 0) - if err != nil { - log.Fatalf("PtraceCont: %v", err) - } - - for { - pid, status, err := wait(-1) - if err != nil { - log.Fatalf("wait: %v", err) - } - - switch status { - case 0x00057f: // 0x05=SIGTRAP, 0x7f=stopped. - regs := syscall.PtraceRegs{} - if err := syscall.PtraceGetRegs(pid, ®s); err != nil { - log.Fatalf("PtraceGetRegs: %v", err) - } - regs.Rip -= breakpointInstrLen - if err := syscall.PtraceSetRegs(pid, ®s); err != nil { - log.Fatalf("PtraceSetRegs: %v", err) - } - bp, ok := breakpoints[regs.Rip] - if !ok { - log.Fatalf("no breakpoint for address %#x\n", regs.Rip) - } - buf[0] = bp.origInstr - if err := poke(pid, addr, buf[:1]); err != nil { - log.Fatalf("poke: %v", err) - } - fmt.Printf("\thit breakpoint at %#x, pid=%5d\n", regs.Rip, pid) - if err := syscall.PtraceSingleStep(pid); err != nil { - log.Fatalf("PtraceSingleStep: %v", err) - } - _, status, err := wait(pid) - if err != nil { - log.Fatalf("wait: %v", err) - } - if status != 0x00057f { - log.Fatalf("PtraceSingleStep: unexpected status %#x\n", status) - } - buf[0] = breakpointInstr - if err := poke(pid, addr, buf[:1]); err != nil { - log.Fatalf("poke: %v", err) - } - - case 0x00137f: // 0x13=SIGSTOP, 0x7f=stopped. - // No-op. - - case 0x03057f: // 0x05=SIGTRAP, 0x7f=stopped, 0x03=PTRACE_EVENT_CLONE. - msg, err := syscall.PtraceGetEventMsg(pid) - if err != nil { - log.Fatalf("PtraceGetEventMsg: %v", err) - } - fmt.Printf("\tclone: new pid=%d\n", msg) - - default: - log.Fatalf("unexpected status %#x\n", status) - } - - err = syscall.PtraceCont(pid, 0) - if err != nil { - log.Fatalf("PtraceCont: %v", err) - } - } -} - -func wait(pid int) (wpid int, status syscall.WaitStatus, err error) { - wpid, err = syscall.Wait4(pid, &status, syscall.WALL, nil) - if err != nil { - return 0, 0, err - } - fmt.Printf("\t\twait: wpid=%5d, status=0x%06x\n", wpid, status) - return wpid, status, nil -} - -func peek(pid int, addr uint64, data []byte) error { - n, err := syscall.PtracePeekText(pid, uintptr(addr), data) - if err != nil { - return err - } - if n != len(data) { - return fmt.Errorf("peek: got %d bytes, want %d", len(data)) - } - return nil -} - -func poke(pid int, addr uint64, data []byte) error { - n, err := syscall.PtracePokeText(pid, uintptr(addr), data) - if err != nil { - return err - } - if n != len(data) { - return fmt.Errorf("poke: got %d bytes, want %d", len(data)) - } - return nil -} - -func lookupSym(dwarfData *dwarf.Data, name string) (uint64, error) { - r := dwarfData.Reader() - for { - entry, err := r.Next() - if err != nil { - return 0, err - } - if entry == nil { - // TODO: why don't we get an error here. - break - } - if entry.Tag != dwarf.TagSubprogram { - continue - } - nameAttr := lookupAttr(entry, dwarf.AttrName) - if nameAttr == nil { - // TODO: this shouldn't be possible. - continue - } - if nameAttr.(string) != name { - continue - } - addrAttr := lookupAttr(entry, 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 - } - return 0, fmt.Errorf("symbol %q not found", name) -} - -func lookupAttr(e *dwarf.Entry, a dwarf.Attr) interface{} { - for _, f := range e.Field { - if f.Attr == a { - return f.Val - } - } - return nil -} - -func loadDwarfData(f *os.File) (*dwarf.Data, error) { - if obj, err := elf.NewFile(f); err == nil { - return obj.DWARF() - } - if obj, err := macho.NewFile(f); err == nil { - return obj.DWARF() - } - return nil, fmt.Errorf("unrecognized binary format") -}
diff --git a/ogle/demo/ptrace-linux-amd64/tracee/main.go b/ogle/demo/ptrace-linux-amd64/tracee/main.go deleted file mode 100644 index 042e4f7..0000000 --- a/ogle/demo/ptrace-linux-amd64/tracee/main.go +++ /dev/null
@@ -1,42 +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. - -// This program prints to stdout from multiple goroutines multiplexed onto -// multiple threads. It is used as the tracee program by the debugger (tracer) -// program in the parent directory. -package main - -import ( - "fmt" - "runtime" - "syscall" - "time" -) - -// ansiColor is whether to display ANSI color codes in the program's output. -// This distinguishes this program's output (the tracee's) from the debugger -// program's output (the tracer's). -const ansiColor = false - -var prefix, suffix string - -func run(base int, sleep time.Duration, lockOSThread bool) { - if lockOSThread { - runtime.LockOSThread() - } - for i := 0; ; i++ { - fmt.Printf("%sx=%5d tid=%d%s\n", prefix, base+i, syscall.Gettid(), suffix) - time.Sleep(sleep) - } -} - -func main() { - if ansiColor { - prefix, suffix = "\x1b[36m", "\x1b[0m" - } - go run(0, 300*time.Millisecond, false) - go run(100, 500*time.Millisecond, false) - go run(10000, 700*time.Millisecond, true) - time.Sleep(5 * time.Second) -}
diff --git a/ogle/probe/addr_test.go b/ogle/probe/addr_test.go deleted file mode 100644 index 48ff2ac..0000000 --- a/ogle/probe/addr_test.go +++ /dev/null
@@ -1,85 +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 probe - -import ( - "reflect" - "testing" -) - -// Defined in assembler. -func base() uintptr -func etext() uintptr -func edata() uintptr -func end() uintptr - -var dataItem = 3 -var bssItem [100]int - -// addr turns an arbitrary address into a uintptr. -func addr(p interface{}) uintptr { - v := reflect.ValueOf(p) - switch v.Kind() { - case reflect.Ptr: - return v.Elem().UnsafeAddr() - default: - // TODO: how do we find the address of a text symbol? - panic("unknown type " + v.Type().String()) - } -} - -func TestGoodReadAddresses(t *testing.T) { - addrs := []uintptr{ - base(), - addr(&t), // On the stack. - addr(&dataItem), // In data. - addr(&bssItem), // In bss. - } - for _, a := range addrs { - if !validRead(a, 1) { - t.Errorf("%#x is invalid; should be valid", a) - } - } -} - -func TestBadReadAddresses(t *testing.T) { - addrs := []uintptr{ - 0, - base()/2 - 1, // Pull well down below; the Mac only unmaps up to 0x1000. - ^uintptr(0), - } - for _, a := range addrs { - if validRead(a, 1) { - t.Errorf("%#x is valid; should be invalid", a) - } - } -} - -func TestGoodWriteAddresses(t *testing.T) { - addrs := []uintptr{ - addr(&t), // On the stack. - addr(&dataItem), // In data. - addr(&bssItem), // In bss. - } - for _, a := range addrs { - if !validWrite(a, 1) { - t.Errorf("%#x is invalid; should be valid", a) - } - } -} - -func TestBadWriteAddresses(t *testing.T) { - addrs := []uintptr{ - 0, - base(), // In the text segment. - base() - 1, - ^uintptr(0), - } - for _, a := range addrs { - if validWrite(a, 1) { - t.Errorf("%#x is valid; should be invalid", a) - } - } -}
diff --git a/ogle/probe/net.go b/ogle/probe/net.go deleted file mode 100644 index 87ebe98..0000000 --- a/ogle/probe/net.go +++ /dev/null
@@ -1,286 +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. - -// TODO: Document the protocol once it settles. - -package probe - -import ( - "errors" - "io" // Used only for the definitions of the various interfaces and errors. - "net" - - "golang.org/x/debug/ogle/socket" -) - -var ( - tracing = false - listening = make(chan struct{}) -) - -// init starts a listener and leaves it in the background waiting for connections. -func init() { - go demon() -} - -// demon answers consecutive connection requests and starts a server to manage each one. -// The server runs in the same goroutine as the demon, so a new connection cannot be -// established until the previous one is completed. -func demon() { - listener, err := socket.Listen() - close(listening) - if err != nil { - trace("listen:", err) - return - } - trace("listening") - for { - conn, err := listener.Accept() - if err != nil { - trace("accept", err) - continue - } - trace("accepted a connection") - serve(conn) - conn.Close() - } -} - -// stringer is the same as fmt.Stringer. We redefine it here to avoid pulling in fmt. -type stringer interface { - String() string -} - -func printHex(b byte) { - const hex = "0123456789ABCDEF" - b1, b0 := b>>4&0xF, b&0xF - print(hex[b1:b1+1], hex[b0:b0+1]) -} - -// trace is a simple version of println that is enabled by the tracing boolean. -func trace(args ...interface{}) { - if !tracing { - return - } - print("ogle demon: ") - for i, arg := range args { - if i > 0 { - print(" ") - } - // A little help. Built-in print isn't very capable. - switch arg := arg.(type) { - case stringer: - print(arg.String()) - case error: - print(arg.Error()) - case []byte: - print("[") - for i := range arg { - if i > 0 { - print(" ") - } - printHex(arg[i]) - } - print("]") - case int: - print(arg) - case string: - print(arg) - case uintptr: - print("0x") - for i := ptrSize - 1; i >= 0; i-- { - printHex(byte(arg >> uint(8*i))) - } - default: - print(arg) - } - } - print("\n") -} - -func serve(conn net.Conn) { - const ( - bufSize = 1 << 16 - ) - var buf [bufSize]byte - network := &pipe{ - rw: conn, - } - for { - // One message per loop. - n, err := network.Read(buf[:1]) - if n != 1 || err != nil { - return - } - switch buf[0] { - case 'r': - // Read: ['r', address, size] => [0, size, size bytes] - u, err := network.readUintptr() - if err != nil { - return - } - n, err := network.readInt() - if err != nil { - return - } - if !validRead(u, n) { - trace("read", err) - network.error("invalid read address") - continue - } - network.sendReadResponse(u, n) - default: - // TODO: shut down connection? - trace("unknown message type:", buf[0]) - } - } -} - -// pipe is a buffered network connection (actually just a reader/writer) that -// implements Read and ReadByte as well as readFull. -// It also has support routines to make it easier to read and write -// network messages. -type pipe struct { - rw io.ReadWriter - pos int - end int - oneByte [1]byte - buf [4096]byte -} - -// readFull fills the argument slice with data from the wire. If it cannot fill the -// slice, it returns an error. -// TODO: unused for now; write will need it. -func (p *pipe) readFull(buf []byte) error { - for len(buf) > 0 { - n, err := p.rw.Read(buf) - if n == len(buf) { - return nil - } - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return err - } - if n == 0 { - return io.EOF - } - buf = buf[n:] - } - return nil -} - -// Read satisfies io.Reader. -func (p *pipe) Read(buf []byte) (int, error) { - n := len(buf) - if p.end == p.pos { - p.pos = 0 - // Read from network - var err error - p.end, err = p.rw.Read(p.buf[:]) - if err != nil { - trace("read:", err) - return p.end, err - } - if p.end == 0 { - trace("read: eof") - return p.end, io.EOF - } - } - if n > p.end-p.pos { - n = p.end - p.pos - } - copy(buf, p.buf[p.pos:p.pos+n]) - p.pos += n - return n, nil -} - -// ReadByte satisfies io.ByteReader. -func (p *pipe) ReadByte() (byte, error) { - _, err := p.Read(p.oneByte[:]) - return p.oneByte[0], err -} - -// readUintptr reads a varint-encoded uinptr value from the connection. -func (p *pipe) readUintptr() (uintptr, error) { - u, err := readUvarint(p) - if err != nil { - trace("read uintptr:", err) - return 0, err - } - if u > uint64(^uintptr(0)) { - trace("read uintptr: overflow") - return 0, err - } - return uintptr(u), nil -} - -var intOverflow = errors.New("ogle probe: varint overflows int") - -// readInt reads an varint-encoded int value from the connection. -// The transported value is always a uint64; this routine -// verifies that it fits in an int. -func (p *pipe) readInt() (int, error) { - u, err := readUvarint(p) - if err != nil { - trace("read int:", err) - return 0, err - } - // Does it fit in an int? - if u > maxInt { - trace("int overflow") - return 0, intOverflow - } - return int(u), nil -} - -// error writes an error message to the connection. -// The format is [size, size bytes]. -func (p *pipe) error(msg string) { - // A zero-length message is problematic. It should never arise, but be safe. - if len(msg) == 0 { - msg = "undefined error" - } - // Truncate if necessary. Extremely unlikely. - if len(msg) > len(p.buf)-maxVarintLen64 { - msg = msg[:len(p.buf)-maxVarintLen64] - } - n := putUvarint(p.buf[:], uint64(len(msg))) - n += copy(p.buf[n:], msg) - _, err := p.rw.Write(p.buf[:n]) - if err != nil { - trace("write:", err) - // TODO: shut down connection? - } -} - -// sendReadResponse sends a read response to the connection. -// The format is [0, size, size bytes]. -func (p *pipe) sendReadResponse(addr uintptr, size int) { - trace("sendRead:", addr, size) - m := 0 - m += putUvarint(p.buf[m:], 0) // No error. - m += putUvarint(p.buf[m:], uint64(size)) // Number of bytes to follow. - for m > 0 || size > 0 { - n := len(p.buf) - m - if n > size { - n = size - } - if !read(addr, p.buf[m:m+n]) { - trace("copy error") - // TODO: shut down connection? - // TODO: for now, continue delivering data. We said we would. - } - _, err := p.rw.Write(p.buf[:m+n]) - if err != nil { - trace("write:", err) - // TODO: shut down connection? - } - addr += uintptr(n) - size -= n - // Next time we can use the whole buffer. - m = 0 - } -}
diff --git a/ogle/probe/net_test.go b/ogle/probe/net_test.go deleted file mode 100644 index c9d599d..0000000 --- a/ogle/probe/net_test.go +++ /dev/null
@@ -1,233 +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 probe - -import ( - "bufio" - "io" - "net" - "os" - "testing" - "unsafe" - - "golang.org/x/debug/ogle/socket" -) - -// traceThisFunction turns on tracing and returns a function to turn it off. -// It is intended for use as "defer traceThisFunction()()". -func traceThisFunction() func() { - // TODO: This should be done atomically to guarantee the probe can see the update. - tracing = true - return func() { - tracing = false - } -} - -type Conn struct { - conn net.Conn - input *bufio.Reader - output *bufio.Writer -} - -func (c *Conn) close() { - c.output.Flush() - c.conn.Close() -} - -// newConn makes a connection. -func newConn(t *testing.T) *Conn { - // defer traceThisFunction()() - <-listening - conn, err := socket.Dial(os.Getuid(), os.Getpid()) - if err != nil { - t.Fatal(err) - } - return &Conn{ - conn: conn, - input: bufio.NewReader(conn), - output: bufio.NewWriter(conn), - } -} - -// bytesToUint64 returns the uint64 stored in the 8 bytes of buf. -func bytesToUint64(buf []byte) uint64 { - // We're using same machine here, so byte order is the same. - // We can just fetch it, but on some architectures it - // must be aligned so copy first. - var tmp [8]byte - copy(tmp[:], buf) - return *(*uint64)(unsafe.Pointer(&tmp[0])) -} - -// Test that we get an error back for a request to read an illegal address. -func TestReadBadAddress(t *testing.T) { - //defer traceThisFunction()() - - conn := newConn(t) - defer conn.close() - - // Read the elements in pseudo-random order. - var tmp [100]byte - // Request a read of a bad address. - conn.output.WriteByte('r') - // Address. - n := putUvarint(tmp[:], 0) - conn.output.Write(tmp[:n]) - // Length. Any length will do. - n = putUvarint(tmp[:], 8) - conn.output.Write(tmp[:n]) - // Send it. - err := conn.output.Flush() - if err != nil { - t.Fatal(err) - } - // Read result. - // We expect an initial non-zero value, the number of bytes of the error message. - u, err := readUvarint(conn.input) - if err != nil { - t.Fatal(err) - } - if u == 0 { - t.Fatalf("expected error return; got none") - } - // We expect a particular error. - const expect = "invalid read address" - if u != uint64(len(expect)) { - t.Fatalf("got %d bytes; expected %d", u, len(expect)) - } - _, err = io.ReadFull(conn.input, tmp[:u]) - if err != nil { - t.Fatal(err) - } - msg := string(tmp[:u]) - if msg != expect { - t.Fatalf("got %q; expected %q", msg, expect) - } -} - -// Test that we can read some data from the address space on the other side of the connection. -func TestReadUint64(t *testing.T) { - //defer traceThisFunction()() - - conn := newConn(t) - defer conn.close() - - // Some data to send over the wire. - data := make([]uint64, 10) - for i := range data { - data[i] = 0x1234567887654321 + 12345*uint64(i) - } - // TODO: To be righteous we should put a memory barrier here. - - // Read the elements in pseudo-random order. - var tmp [100]byte - which := 0 - for i := 0; i < 100; i++ { - which = (which + 7) % len(data) - // Request a read of data[which]. - conn.output.WriteByte('r') - // Address. - n := putUvarint(tmp[:], uint64(addr(&data[which]))) - conn.output.Write(tmp[:n]) - // Length - n = putUvarint(tmp[:], 8) - conn.output.Write(tmp[:n]) - // Send it. - err := conn.output.Flush() - if err != nil { - t.Fatal(err) - } - // Read result. - // We expect 10 bytes: the initial zero, followed by 8 (the count), followed by 8 bytes of data. - u, err := readUvarint(conn.input) - if err != nil { - t.Fatal(err) - } - if u != 0 { - t.Fatalf("expected leading zero byte; got %#x\n", u) - } - // N bytes of data. - u, err = readUvarint(conn.input) - if err != nil { - t.Fatal(err) - } - if u != 8 { - t.Fatalf("got %d bytes of data; expected 8", u) - } - _, err = io.ReadFull(conn.input, tmp[:u]) - if err != nil { - t.Fatal(err) - } - u = bytesToUint64(tmp[:u]) - if u != data[which] { - t.Fatalf("got %#x; expected %#x", u, data[which]) - } - } -} - -// Test that we can read an array bigger than the pipe's buffer size. -func TestBigRead(t *testing.T) { - // defer traceThisFunction()() - - conn := newConn(t) - defer conn.close() - - // A big slice. - data := make([]byte, 3*len(pipe{}.buf)) - noise := 17 - for i := range data { - data[i] = byte(noise) - noise += 23 - } - // TODO: To be righteous we should put a memory barrier here. - - // Read the elements in one big call. - tmp := make([]byte, len(data)) - conn.output.WriteByte('r') - // Address. - n := putUvarint(tmp[:], uint64(addr(&data[0]))) - conn.output.Write(tmp[:n]) - // Length. - n = putUvarint(tmp[:], uint64(len(data))) - conn.output.Write(tmp[:n]) - // Send it. - err := conn.output.Flush() - if err != nil { - t.Fatal(err) - } - // Read result. - // We expect the full data back. - u, err := readUvarint(conn.input) - if err != nil { - t.Fatal(err) - } - if u != 0 { - t.Fatalf("expected leading zero byte; got %#x\n", u) - } - // N bytes of data. - u, err = readUvarint(conn.input) - if err != nil { - t.Fatal(err) - } - if u != uint64(len(data)) { - t.Fatalf("got %d bytes of data; expected 8", u) - } - _, err = io.ReadFull(conn.input, tmp) - if err != nil { - t.Fatal(err) - } - for i, c := range data { - if tmp[i] != c { - t.Fatalf("at offset %d expected %#x; got %#x", i, c, tmp[i]) - } - } -} - -// TestCollectGarbage doesn't actually test anything, but it does collect any -// garbage sockets that are no longer used. It is a courtesy for computers that -// run this test suite often. -func TestCollectGarbage(t *testing.T) { - socket.CollectGarbage() -}
diff --git a/ogle/probe/probe.go b/ogle/probe/probe.go deleted file mode 100644 index 9db1f81..0000000 --- a/ogle/probe/probe.go +++ /dev/null
@@ -1,79 +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 probe is imported by programs to provide (possibly remote) -// access to a separate debugger program. -package probe // import "golang.org/x/debug/ogle/probe" - -import ( - "runtime/debug" - "unsafe" -) - -// catchFault is used by the read and write routines to turn a panic into an error return. -func catchFault(ok *bool) { - if e := recover(); e != nil { - *ok = false - } -} - -// validRead reports whether a read of the specified size can be done at address p. -// TODO: It does this by actually doing the read and seeing if it succeeds. Do better. -func validRead(p uintptr, size int) (ok bool) { - // Check for negative size and for (p + size) overflow. - if size < 0 || uint64(^uintptr(0)-p) < uint64(size) { - return false - } - defer catchFault(&ok) - defer debug.SetPanicOnFault(debug.SetPanicOnFault(true)) - ep := p + uintptr(size) - var b byte - for p < ep { - b = *(*byte)(unsafe.Pointer(p)) - _ = b - p++ - } - return true -} - -// validWrite reports whether a write of the specified size can be done at address p. -// TODO: It does this by actually doing a write and seeing if it succeeds. Do better. -func validWrite(p uintptr, size int) (ok bool) { - // Check for negative size and for (p + size) overflow. - if size < 0 || uint64(^uintptr(0)-p) < uint64(size) { - return false - } - defer catchFault(&ok) - defer debug.SetPanicOnFault(debug.SetPanicOnFault(true)) - ep := p + uintptr(size) - for p < ep { - *(*byte)(unsafe.Pointer(p)) = *(*byte)(unsafe.Pointer(p)) - p++ - } - return true -} - -// read copies into the argument buffer the contents of memory starting at address p. -// Its boolean return tells whether it succeeded. If it fails, no bytes were copied. -func read(p uintptr, buf []byte) (ok bool) { - defer catchFault(&ok) - defer debug.SetPanicOnFault(debug.SetPanicOnFault(true)) - for i := range buf { - buf[i] = *(*byte)(unsafe.Pointer(p)) - p++ - } - return true -} - -// write copies the argument buffer to memory starting at address p. -// Its boolean return tells whether it succeeded. If it fails, no bytes were copied. -func write(p uintptr, buf []byte) (ok bool) { - defer catchFault(&ok) - defer debug.SetPanicOnFault(debug.SetPanicOnFault(true)) - for i := range buf { - *(*byte)(unsafe.Pointer(p)) = buf[i] - p++ - } - return true -}
diff --git a/ogle/probe/probe_darwin_amd64.s b/ogle/probe/probe_darwin_amd64.s deleted file mode 100644 index 90ec8cc..0000000 --- a/ogle/probe/probe_darwin_amd64.s +++ /dev/null
@@ -1,38 +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. - -// TODO #include "../../cmd/ld/textflag.h" - -#define NOSPLIT 4 - -// Functions that return details about our address space. -// They use the C-defined symbols like edata and also know -// a little about the heap and memory layout. - -// From the linker. Well-known but might change. -// TODO: Is there a better way to know this? -#define INITTEXT 0x2000 - -// base of the address space. -TEXT ·base(SB), NOSPLIT, $0 - MOVQ $INITTEXT, ret+0(FP) - RET - -// end of the text segment. -TEXT ·etext(SB), NOSPLIT, $0 - LEAQ etext+0(SB), BX - MOVQ BX, ret+0(FP) - RET - -// end of the data segment. -TEXT ·edata(SB), NOSPLIT, $0 - LEAQ edata+0(SB), BX - MOVQ BX, ret+0(FP) - RET - -// end of the pre-defined address space. -TEXT ·end(SB), NOSPLIT, $0 - LEAQ end+0(SB), BX - MOVQ BX, ret+0(FP) - RET
diff --git a/ogle/probe/probe_linux_amd64.s b/ogle/probe/probe_linux_amd64.s deleted file mode 100644 index 37999a2..0000000 --- a/ogle/probe/probe_linux_amd64.s +++ /dev/null
@@ -1,39 +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. - -// TODO #include "../../cmd/ld/textflag.h" - -#define NOSPLIT 4 - -// Functions that return details about our address space. -// They use the C-defined symbols like edata and also know -// a little about the heap and memory layout. - -// From the linker. Well-known but might change. -// TODO: Is there a better way to know this? -#define ELFRESERVE 3072 -#define INITTEXT ((1<<22)+ELFRESERVE) - -// base of the address space. -TEXT ·base(SB), NOSPLIT, $0 - MOVQ $INITTEXT, ret+0(FP) - RET - -// end of the text segment. -TEXT ·etext(SB), NOSPLIT, $0 - LEAQ etext+0(SB), BX - MOVQ BX, ret+0(FP) - RET - -// end of the data segment. -TEXT ·edata(SB), NOSPLIT, $0 - LEAQ edata+0(SB), BX - MOVQ BX, ret+0(FP) - RET - -// end of the pre-defined address space. -TEXT ·end(SB), NOSPLIT, $0 - LEAQ end+0(SB), BX - MOVQ BX, ret+0(FP) - RET
diff --git a/ogle/probe/size_amd64.go b/ogle/probe/size_amd64.go deleted file mode 100644 index 08783a5..0000000 --- a/ogle/probe/size_amd64.go +++ /dev/null
@@ -1,12 +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 probe - -// Sizes of values for the AMD64 architecture. - -const ( - ptrSize = 8 - maxInt = 1<<63 - 1 -)
diff --git a/ogle/probe/varint.go b/ogle/probe/varint.go deleted file mode 100644 index 2d4f1b3..0000000 --- a/ogle/probe/varint.go +++ /dev/null
@@ -1,82 +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 probe - -// This file contains an implementation of "varint" encoding and decoding. -// Code is adapted from encoding/binary/varint.go, copied here to avoid dependencies, -// simplified somewhat, and made local to the package. -// It handles unsigned integers only. - -import ( - "errors" - "io" -) - -// maxVarintLenN is the maximum length of a varint-encoded N-bit integer. -const ( - maxVarintLen16 = 3 - maxVarintLen32 = 5 - maxVarintLen64 = 10 -) - -// putUvarint encodes a uint64 into buf and returns the number of bytes written. -// If the buffer is too small, putUvarint will panic. -func putUvarint(buf []byte, x uint64) int { - i := 0 - for x >= 0x80 { - buf[i] = byte(x) | 0x80 - x >>= 7 - i++ - } - buf[i] = byte(x) - return i + 1 -} - -// getUvarint decodes a uint64 from buf and returns that value and the -// number of bytes read (> 0). If an error occurred, the value is 0 -// and the number of bytes n is <= 0 meaning: -// -// n == 0: buf too small -// n < 0: value larger than 64 bits (overflow) -// and -n is the number of bytes read -// -// TODO: Unused. Delete if it doesn't get used. -func getUvarint(buf []byte) (uint64, int) { - var x uint64 - var s uint - for i, b := range buf { - if b < 0x80 { - if i > 9 || i == 9 && b > 1 { - return 0, -(i + 1) // overflow - } - return x | uint64(b)<<s, i + 1 - } - x |= uint64(b&0x7f) << s - s += 7 - } - return 0, 0 -} - -var overflow = errors.New("ogle probe: varint overflows a 64-bit integer") - -// readUvarint reads an encoded unsigned integer from r and returns it as a uint64. -func readUvarint(r io.ByteReader) (uint64, error) { - var x uint64 - var s uint - for i := 0; ; i++ { - b, err := r.ReadByte() - if err != nil { - return x, err - } - if b < 0x80 { - if i > 9 || i == 9 && b > 1 { - return x, overflow - } - return x | uint64(b)<<s, nil - } - x |= uint64(b&0x7f) << s - s += 7 - } -}
diff --git a/ogle/program/local/local.go b/ogle/program/local/local.go deleted file mode 100644 index ed9bdc8..0000000 --- a/ogle/program/local/local.go +++ /dev/null
@@ -1,186 +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/ogle/program/local" - -import ( - "golang.org/x/debug/ogle/program" - "golang.org/x/debug/ogle/program/proxyrpc" - "golang.org/x/debug/ogle/program/server" -) - -var _ program.Program = (*Local)(nil) -var _ program.File = (*File)(nil) - -// Local implements the interface program.Program. -// Through that interface it provides access to a program being debugged. -type Local 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) (*Local, error) { - s, err := server.New(textFile) - return &Local{s: s}, err -} - -func (l *Local) Open(name string, mode string) (program.File, error) { - req := proxyrpc.OpenRequest{ - Name: name, - Mode: mode, - } - var resp proxyrpc.OpenResponse - err := l.s.Open(&req, &resp) - if err != nil { - return nil, err - } - f := &File{ - prog: l, - fd: resp.FD, - } - return f, nil -} - -func (l *Local) Run(args ...string) (program.Status, error) { - req := proxyrpc.RunRequest{args} - var resp proxyrpc.RunResponse - err := l.s.Run(&req, &resp) - if err != nil { - return program.Status{}, err - } - return resp.Status, nil -} - -func (l *Local) Stop() (program.Status, error) { - panic("unimplemented") -} - -func (l *Local) Resume() (program.Status, error) { - req := proxyrpc.ResumeRequest{} - var resp proxyrpc.ResumeResponse - err := l.s.Resume(&req, &resp) - if err != nil { - return program.Status{}, err - } - return resp.Status, nil -} - -func (l *Local) Kill() (program.Status, error) { - panic("unimplemented") -} - -func (l *Local) Breakpoint(address uint64) ([]uint64, error) { - req := proxyrpc.BreakpointRequest{address} - var resp proxyrpc.BreakpointResponse - err := l.s.Breakpoint(&req, &resp) - return resp.PCs, err -} - -func (l *Local) BreakpointAtFunction(name string) ([]uint64, error) { - req := proxyrpc.BreakpointAtFunctionRequest{name} - var resp proxyrpc.BreakpointResponse - err := l.s.BreakpointAtFunction(&req, &resp) - return resp.PCs, err -} - -func (l *Local) BreakpointAtLine(file string, line uint64) ([]uint64, error) { - req := proxyrpc.BreakpointAtLineRequest{file, line} - var resp proxyrpc.BreakpointResponse - err := l.s.BreakpointAtLine(&req, &resp) - return resp.PCs, err -} - -func (l *Local) DeleteBreakpoints(pcs []uint64) error { - req := proxyrpc.DeleteBreakpointsRequest{PCs: pcs} - var resp proxyrpc.DeleteBreakpointsResponse - return l.s.DeleteBreakpoints(&req, &resp) -} - -func (l *Local) Eval(expr string) ([]string, error) { - req := proxyrpc.EvalRequest{ - Expr: expr, - } - var resp proxyrpc.EvalResponse - err := l.s.Eval(&req, &resp) - return resp.Result, err -} - -func (l *Local) Evaluate(e string) (program.Value, error) { - req := proxyrpc.EvaluateRequest{ - Expression: e, - } - var resp proxyrpc.EvaluateResponse - err := l.s.Evaluate(&req, &resp) - return resp.Result, err -} - -func (l *Local) Frames(count int) ([]program.Frame, error) { - req := proxyrpc.FramesRequest{ - Count: count, - } - var resp proxyrpc.FramesResponse - err := l.s.Frames(&req, &resp) - return resp.Frames, err -} - -func (l *Local) Goroutines() ([]*program.Goroutine, error) { - req := proxyrpc.GoroutinesRequest{} - var resp proxyrpc.GoroutinesResponse - err := l.s.Goroutines(&req, &resp) - return resp.Goroutines, err -} - -func (l *Local) VarByName(name string) (program.Var, error) { - req := proxyrpc.VarByNameRequest{Name: name} - var resp proxyrpc.VarByNameResponse - err := l.s.VarByName(&req, &resp) - return resp.Var, err -} - -func (l *Local) Value(v program.Var) (program.Value, error) { - req := proxyrpc.ValueRequest{Var: v} - var resp proxyrpc.ValueResponse - err := l.s.Value(&req, &resp) - return resp.Value, err -} - -func (l *Local) MapElement(m program.Map, index uint64) (program.Var, program.Var, error) { - req := proxyrpc.MapElementRequest{Map: m, Index: index} - var resp proxyrpc.MapElementResponse - err := l.s.MapElement(&req, &resp) - return resp.Key, resp.Value, err -} - -// File implements the program.File interface, providing access -// to file-like resources associated with the target program. -type File struct { - prog *Local // The Program associated with the file. - fd int // File descriptor. -} - -func (f *File) ReadAt(p []byte, offset int64) (int, error) { - req := proxyrpc.ReadAtRequest{ - FD: f.fd, - Len: len(p), - Offset: offset, - } - var resp proxyrpc.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 := proxyrpc.CloseRequest{ - FD: f.fd, - } - var resp proxyrpc.CloseResponse - err := f.prog.s.Close(&req, &resp) - return err -}
diff --git a/ogle/socket/socket.go b/ogle/socket/socket.go deleted file mode 100644 index 4745dc2..0000000 --- a/ogle/socket/socket.go +++ /dev/null
@@ -1,107 +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 socket provides a way for multiple processes from the same user to -// communicate over a Unix domain socket. -package socket // import "golang.org/x/debug/ogle/socket" - -// TODO: euid instead of uid? -// TODO: Windows support. - -import ( - "net" - "os" - "syscall" -) - -// atoi is like strconv.Atoi but we aim to minimize this package's dependencies. -func atoi(s string) (i int, ok bool) { - for _, c := range s { - if c < '0' || '9' < c { - return 0, false - } - i = 10*i + int(c-'0') - } - return i, true -} - -// itoa is like strconv.Itoa but we aim to minimize this package's dependencies. -func itoa(i int) string { - var buf [30]byte - n := len(buf) - neg := false - if i < 0 { - i = -i - neg = true - } - ui := uint(i) - for ui > 0 || n == len(buf) { - n-- - buf[n] = byte('0' + ui%10) - ui /= 10 - } - if neg { - n-- - buf[n] = '-' - } - return string(buf[n:]) -} - -func names(uid, pid int) (dirName, socketName string) { - dirName = "/tmp/ogle-socket-uid" + itoa(uid) - socketName = dirName + "/pid" + itoa(pid) - return -} - -// Listen creates a PID-specific socket under a UID-specific sub-directory of -// /tmp. That sub-directory is created with 0700 permission bits (before -// umasking), so that only processes with the same UID can dial that socket. -func Listen() (net.Listener, error) { - dirName, socketName := names(os.Getuid(), os.Getpid()) - if err := os.MkdirAll(dirName, 0700); err != nil { - return nil, err - } - if err := os.Remove(socketName); err != nil && !os.IsNotExist(err) { - return nil, err - } - return net.Listen("unix", socketName) -} - -// Dial dials the Unix domain socket created by the process with the given UID -// and PID. -func Dial(uid, pid int) (net.Conn, error) { - _, socketName := names(uid, pid) - return net.Dial("unix", socketName) -} - -// CollectGarbage deletes any no-longer-used sockets in the UID-specific sub- -// directory of /tmp. -func CollectGarbage() { - dirName, _ := names(os.Getuid(), os.Getpid()) - dir, err := os.Open(dirName) - if err != nil { - return - } - defer dir.Close() - fileNames, err := dir.Readdirnames(-1) - if err != nil { - return - } - for _, fileName := range fileNames { - if len(fileName) < 3 || fileName[:3] != "pid" { - continue - } - pid, ok := atoi(fileName[3:]) - if !ok { - continue - } - // See if there is a process with the given PID. The os.FindProcess function - // looks relevant, but on Unix that always succeeds even if there is no such - // process. Instead, we send signal 0 and look for ESRCH. - if syscall.Kill(pid, 0) != syscall.ESRCH { - continue - } - os.Remove(dirName + "/" + fileName) - } -}
diff --git a/ogle/socket/socket_test.go b/ogle/socket/socket_test.go deleted file mode 100644 index b07a732..0000000 --- a/ogle/socket/socket_test.go +++ /dev/null
@@ -1,79 +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 socket - -import ( - "fmt" - "io/ioutil" - "os" - "testing" - "time" -) - -func TestSocket(t *testing.T) { - const msg = "Zoich!" - - l, err := Listen() - if err != nil { - t.Fatalf("listen: %v", err) - } - defer l.Close() - - wc := make(chan string, 1) - go func(c chan string) { - w, err := Dial(os.Getuid(), os.Getpid()) - if err != nil { - c <- fmt.Sprintf("dial: %v", err) - return - } - defer w.Close() - _, err = w.Write([]byte(msg)) - if err != nil { - c <- fmt.Sprintf("write: %v", err) - return - } - c <- "" - }(wc) - - rc := make(chan string, 1) - go func(c chan string) { - r, err := l.Accept() - if err != nil { - c <- fmt.Sprintf("accept: %v", err) - return - } - defer r.Close() - s, err := ioutil.ReadAll(r) - if err != nil { - c <- fmt.Sprintf("readAll: %v", err) - return - } - c <- string(s) - }(rc) - - for wc != nil || rc != nil { - select { - case <-time.After(100 * time.Millisecond): - t.Fatal("timed out") - case errStr := <-wc: - if errStr != "" { - t.Fatal(errStr) - } - wc = nil - case got := <-rc: - if got != msg { - t.Fatalf("got %q, want %q", got, msg) - } - rc = nil - } - } -} - -// TestCollectGarbage doesn't actually test anything, but it does collect any -// garbage sockets that are no longer used. It is a courtesy for computers that -// run this test suite often. -func TestCollectGarbage(t *testing.T) { - CollectGarbage() -}
diff --git a/ogle/program/program.go b/program.go similarity index 98% rename from ogle/program/program.go rename to program.go index 72c0389..b988d83 100644 --- a/ogle/program/program.go +++ b/program.go
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package program provides the portable interface to a program being debugged. -package program // import "golang.org/x/debug/ogle/program" +// Package debug provides the portable interface to a program being debugged. +package debug // import "golang.org/x/debug" import ( "fmt"
diff --git a/ogle/program/client/client.go b/remote/remote.go similarity index 60% rename from ogle/program/client/client.go rename to remote/remote.go index 51bf1a5..66080c0 100644 --- a/ogle/program/client/client.go +++ b/remote/remote.go
@@ -2,34 +2,41 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package client provides remote access to an ogle proxy. -package client // import "golang.org/x/debug/ogle/program/client" +// Package remote provides remote access to a debugproxy server. +package remote // import "golang.org/x/debug/remote" import ( - "errors" "fmt" "io" "net/rpc" "os" "os/exec" - "golang.org/x/debug/ogle/program" - "golang.org/x/debug/ogle/program/proxyrpc" + "golang.org/x/debug" + "golang.org/x/debug/server/protocol" ) -var _ program.Program = (*Program)(nil) -var _ program.File = (*File)(nil) +var _ debug.Program = (*Program)(nil) +var _ debug.File = (*File)(nil) -// OgleproxyCmd is the path to the ogleproxy command. It is a variable in case -// the default value, "ogleproxy", is not in the $PATH. -var OgleproxyCmd = "ogleproxy" +// 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 +} -// New connects to the specified host using SSH, starts an ogle proxy +// 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, OgleproxyCmd, "-text", textFile} + cmdStrs := []string{"/usr/bin/ssh", host, DebugproxyCmd, "-text", textFile} if host == "localhost" { cmdStrs = cmdStrs[2:] } @@ -50,21 +57,9 @@ return nil, err } stdout.Close() - // Read back one line. It must start "OGLE" and we hope says "OK". - msg, err := readLine(fromStdout) - if err != nil { + if msg, err := readLine(fromStdout); err != nil { return nil, err - } - switch msg { - case "OGLE BAD": - // Error is on next line. - msg, err = readLine(fromStdout) - if err == nil { - err = errors.New(msg) - } - return nil, err - case "OGLE OK": - default: + } else if msg != "OK" { // Communication error. return nil, fmt.Errorf("unrecognized message %q", msg) } @@ -127,20 +122,12 @@ return werr } -// Program implements the similarly named ogle interface. -// Through that interface it provides access to a program being -// debugged on a possibly remote machine by communicating -// with an ogle proxy adjacent to the target program. -type Program struct { - client *rpc.Client -} - -func (p *Program) Open(name string, mode string) (program.File, error) { - req := proxyrpc.OpenRequest{ +func (p *Program) Open(name string, mode string) (debug.File, error) { + req := protocol.OpenRequest{ Name: name, Mode: mode, } - var resp proxyrpc.OpenResponse + var resp protocol.OpenResponse err := p.client.Call("Server.Open", &req, &resp) if err != nil { return nil, err @@ -152,124 +139,124 @@ return f, nil } -func (p *Program) Run(args ...string) (program.Status, error) { - req := proxyrpc.RunRequest{args} - var resp proxyrpc.RunResponse +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 program.Status{}, err + return debug.Status{}, err } return resp.Status, nil } -func (p *Program) Stop() (program.Status, error) { +func (p *Program) Stop() (debug.Status, error) { panic("unimplemented") } -func (p *Program) Resume() (program.Status, error) { - req := proxyrpc.ResumeRequest{} - var resp proxyrpc.ResumeResponse +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 program.Status{}, err + return debug.Status{}, err } return resp.Status, nil } -func (p *Program) Kill() (program.Status, error) { +func (p *Program) Kill() (debug.Status, error) { panic("unimplemented") } func (p *Program) Breakpoint(address uint64) ([]uint64, error) { - req := proxyrpc.BreakpointRequest{ + req := protocol.BreakpointRequest{ Address: address, } - var resp proxyrpc.BreakpointResponse + 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 := proxyrpc.BreakpointAtFunctionRequest{ + req := protocol.BreakpointAtFunctionRequest{ Function: name, } - var resp proxyrpc.BreakpointResponse + 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 := proxyrpc.BreakpointAtLineRequest{ + req := protocol.BreakpointAtLineRequest{ File: file, Line: line, } - var resp proxyrpc.BreakpointResponse + var resp protocol.BreakpointResponse err := p.client.Call("Server.BreakpointAtLine", &req, &resp) return resp.PCs, err } func (p *Program) DeleteBreakpoints(pcs []uint64) error { - req := proxyrpc.DeleteBreakpointsRequest{PCs: pcs} - var resp proxyrpc.DeleteBreakpointsResponse + 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 := proxyrpc.EvalRequest{ + req := protocol.EvalRequest{ Expr: expr, } - var resp proxyrpc.EvalResponse + var resp protocol.EvalResponse err := p.client.Call("Server.Eval", &req, &resp) return resp.Result, err } -func (p *Program) Evaluate(e string) (program.Value, error) { - req := proxyrpc.EvaluateRequest{ +func (p *Program) Evaluate(e string) (debug.Value, error) { + req := protocol.EvaluateRequest{ Expression: e, } - var resp proxyrpc.EvaluateResponse + var resp protocol.EvaluateResponse err := p.client.Call("Server.Evaluate", &req, &resp) return resp.Result, err } -func (p *Program) Frames(count int) ([]program.Frame, error) { - req := proxyrpc.FramesRequest{ +func (p *Program) Frames(count int) ([]debug.Frame, error) { + req := protocol.FramesRequest{ Count: count, } - var resp proxyrpc.FramesResponse + var resp protocol.FramesResponse err := p.client.Call("Server.Frames", &req, &resp) return resp.Frames, err } -func (p *Program) Goroutines() ([]*program.Goroutine, error) { - req := proxyrpc.GoroutinesRequest{} - var resp proxyrpc.GoroutinesResponse +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) (program.Var, error) { - req := proxyrpc.VarByNameRequest{Name: name} - var resp proxyrpc.VarByNameResponse +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 program.Var) (program.Value, error) { - req := proxyrpc.ValueRequest{Var: v} - var resp proxyrpc.ValueResponse +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 program.Map, index uint64) (program.Var, program.Var, error) { - req := proxyrpc.MapElementRequest{Map: m, Index: index} - var resp proxyrpc.MapElementResponse +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 program.File interface, providing access +// 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. @@ -277,32 +264,32 @@ } func (f *File) ReadAt(p []byte, offset int64) (int, error) { - req := proxyrpc.ReadAtRequest{ + req := protocol.ReadAtRequest{ FD: f.fd, Len: len(p), Offset: offset, } - var resp proxyrpc.ReadAtResponse + 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 := proxyrpc.WriteAtRequest{ + req := protocol.WriteAtRequest{ FD: f.fd, Data: p, Offset: offset, } - var resp proxyrpc.WriteAtResponse + var resp protocol.WriteAtResponse err := f.prog.client.Call("Server.WriteAt", &req, &resp) return resp.Len, err } func (f *File) Close() error { - req := proxyrpc.CloseRequest{ + req := protocol.CloseRequest{ FD: f.fd, } - var resp proxyrpc.CloseResponse + var resp protocol.CloseResponse err := f.prog.client.Call("Server.Close", &req, &resp) return err }
diff --git a/ogle/program/server/dwarf.go b/server/dwarf.go similarity index 100% rename from ogle/program/server/dwarf.go rename to server/dwarf.go
diff --git a/ogle/program/server/eval.go b/server/eval.go similarity index 96% rename from ogle/program/server/eval.go rename to server/eval.go index 51e8a28..b7a1b68 100644 --- a/ogle/program/server/eval.go +++ b/server/eval.go
@@ -21,8 +21,8 @@ "math" "math/big" + "golang.org/x/debug" "golang.org/x/debug/dwarf" - "golang.org/x/debug/ogle/program" ) const prec = 256 // precision for untyped float and complex constants. @@ -50,7 +50,7 @@ // 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 -// program.Value in program.go. +// debug.Value in program.go. // // If an evaluation results in an error, the zero value of result is used. type result struct { @@ -84,7 +84,7 @@ // pointerToValue is a pointer to a value in memory. // The evaluator constructs these as the result of address operations like "&x". -// Unlike program.Pointer, the DWARF type stored alongside values of this type +// 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 @@ -98,9 +98,9 @@ } // A sliceOf is a slice created by slicing an array. -// Unlike program.Slice, the DWARF type stored alongside a value of this type is +// 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 program.Slice +type sliceOf debug.Slice // ident is a value for representing a special identifier. type ident string @@ -112,7 +112,7 @@ // 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) (program.Value, error) { +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 { @@ -155,11 +155,11 @@ } return complex(r, i), nil case untString: - return program.String{Length: uint64(len(v)), String: string(v)}, nil + return debug.String{Length: uint64(len(v)), String: string(v)}, nil case pointerToValue: - return program.Pointer{TypeID: uint64(val.d.Common().Offset), Address: v.a}, nil + return debug.Pointer{TypeID: uint64(val.d.Common().Offset), Address: v.a}, nil case sliceOf: - return program.Slice(v), nil + return debug.Slice(v), nil case nil, addressableValue: // This case should not be reachable. return nil, errors.New("unknown error") @@ -286,7 +286,7 @@ case *ast.StarExpr: x := e.evalNode(n.X, false) switch v := x.v.(type) { - case program.Pointer: + 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. @@ -307,7 +307,7 @@ x := e.evalNode(n.X, false) sel := n.Sel.Name switch v := x.v.(type) { - case program.Struct: + case debug.Struct: for _, f := range v.Fields { if f.Name == sel { t, err := e.server.dwarfData.Type(dwarf.Offset(f.Var.TypeID)) @@ -318,7 +318,7 @@ } } return e.err("struct field not found") - case program.Pointer: + 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") @@ -353,7 +353,7 @@ return result{} } // The expression is x[index] - if m, ok := x.v.(program.Map); ok { + if m, ok := x.v.(debug.Map); ok { if getAddress { return e.err("can't take address of map value") } @@ -406,7 +406,7 @@ return e.err("invalid index: " + err.Error()) } switch v := x.v.(type) { - case program.Array: + case debug.Array: if u >= v.Length { return e.err("array index out of bounds") } @@ -415,7 +415,7 @@ return e.err(err.Error()) } return e.resultFrom(v.Element(u).Address, elemType, getAddress) - case program.Slice: + case debug.Slice: if u >= v.Length { return e.err("slice index out of bounds") } @@ -429,7 +429,7 @@ return e.err("slice index out of bounds") } return e.resultFrom(v.Element(u).Address, x.d, getAddress) - case program.String: + case debug.String: if getAddress { return e.err("can't take address of string element") } @@ -482,19 +482,19 @@ } x := e.evalNode(n.X, false) switch v := x.v.(type) { - case program.Array, program.Pointer, pointerToValue: + case debug.Array, debug.Pointer, pointerToValue: // This case handles the slicing of arrays and pointers to arrays. - var arr program.Array + var arr debug.Array switch v := x.v.(type) { - case program.Array: + case debug.Array: arr = v - case program.Pointer: + 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.(program.Array) + arr, ok = a.v.(debug.Array) if !ok { // v is a pointer to something other than an array. return e.err("cannot slice pointer") @@ -502,7 +502,7 @@ case pointerToValue: a := e.resultFrom(v.a, x.d, false) var ok bool - arr, ok = a.v.(program.Array) + arr, ok = a.v.(debug.Array) if !ok { // v is a pointer to something other than an array. return e.err("cannot slice pointer") @@ -528,7 +528,7 @@ return result{ d: elemType, v: sliceOf{ - Array: program.Array{ + Array: debug.Array{ ElementTypeID: arr.ElementTypeID, Address: arr.Element(low).Address, Length: high - low, @@ -537,7 +537,7 @@ Capacity: max - low, }, } - case program.Slice: + case debug.Slice: if n.High == nil { high = v.Length } else if high > v.Capacity { @@ -573,7 +573,7 @@ v.Length = high - low v.Capacity = max - low return result{x.d, v} - case program.String: + case debug.String: if n.Max != nil { return e.err("full slice of string") } @@ -1331,12 +1331,12 @@ } return result{x.d, c} - case program.String: - b, ok := y.v.(program.String) + case debug.String: + b, ok := y.v.(debug.String) if !ok { return e.err("type mismatch") } - var c program.String + 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 @@ -1690,7 +1690,7 @@ if !ok { e.err("couldn't construct string") } - return result{t, program.String{Length: uint64(len(s)), String: s}} + return result{t, debug.String{Length: uint64(len(s)), String: s}} } // getBaseType returns the *dwarf.Type with a given name. @@ -1777,24 +1777,24 @@ case *dwarf.BoolType: v = false case *dwarf.PtrType: - v = program.Pointer{TypeID: uint64(t.Common().Offset)} + v = debug.Pointer{TypeID: uint64(t.Common().Offset)} case *dwarf.SliceType: - v = program.Slice{ - Array: program.Array{ + v = debug.Slice{ + Array: debug.Array{ ElementTypeID: uint64(typ.ElemType.Common().Offset), StrideBits: uint64(typ.ElemType.Common().ByteSize) * 8, }, } case *dwarf.StringType: - v = program.String{} + v = debug.String{} case *dwarf.InterfaceType: - v = program.Interface{} + v = debug.Interface{} case *dwarf.FuncType: - v = program.Func{} + v = debug.Func{} case *dwarf.MapType: - v = program.Map{TypeID: uint64(t.Common().Offset)} + v = debug.Map{TypeID: uint64(t.Common().Offset)} case *dwarf.ChanType: - v = program.Channel{ + v = debug.Channel{ ElementTypeID: uint64(typ.ElemType.Common().Offset), Stride: uint64(typ.ElemType.Common().ByteSize), } @@ -1984,8 +1984,8 @@ } case untString: switch y.v.(type) { - case program.String: - return result{y.d, program.String{Length: uint64(len(a)), String: string(a)}} + case debug.String: + return result{y.d, debug.String{Length: uint64(len(a)), String: string(a)}} } } return x
diff --git a/ogle/program/server/eval.m4 b/server/eval.m4 similarity index 96% rename from ogle/program/server/eval.m4 rename to server/eval.m4 index ec48880..0e0def3 100644 --- a/ogle/program/server/eval.m4 +++ b/server/eval.m4
@@ -21,8 +21,8 @@ "math" "math/big" + "golang.org/x/debug" "golang.org/x/debug/dwarf" - "golang.org/x/debug/ogle/program" ) const prec = 256 // precision for untyped float and complex constants. @@ -50,7 +50,7 @@ // 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 -// program.Value in program.go. +// debug.Value in program.go. // // If an evaluation results in an error, the zero value of result is used. type result struct { @@ -84,7 +84,7 @@ // pointerToValue is a pointer to a value in memory. // The evaluator constructs these as the result of address operations like "&x". -// Unlike program.Pointer, the DWARF type stored alongside values of this type +// 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 @@ -98,9 +98,9 @@ } // A sliceOf is a slice created by slicing an array. -// Unlike program.Slice, the DWARF type stored alongside a value of this type is +// 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 program.Slice +type sliceOf debug.Slice // ident is a value for representing a special identifier. type ident string @@ -112,7 +112,7 @@ // 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) (program.Value, error) { +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 { @@ -155,11 +155,11 @@ } return complex(r, i), nil case untString: - return program.String{Length: uint64(len(v)), String: string(v)}, nil + return debug.String{Length: uint64(len(v)), String: string(v)}, nil case pointerToValue: - return program.Pointer{TypeID: uint64(val.d.Common().Offset), Address: v.a}, nil + return debug.Pointer{TypeID: uint64(val.d.Common().Offset), Address: v.a}, nil case sliceOf: - return program.Slice(v), nil + return debug.Slice(v), nil case nil, addressableValue: // This case should not be reachable. return nil, errors.New("unknown error") @@ -286,7 +286,7 @@ case *ast.StarExpr: x := e.evalNode(n.X, false) switch v := x.v.(type) { - case program.Pointer: + 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. @@ -307,7 +307,7 @@ x := e.evalNode(n.X, false) sel := n.Sel.Name switch v := x.v.(type) { - case program.Struct: + case debug.Struct: for _, f := range v.Fields { if f.Name == sel { t, err := e.server.dwarfData.Type(dwarf.Offset(f.Var.TypeID)) @@ -318,7 +318,7 @@ } } return e.err("struct field not found") - case program.Pointer: + 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") @@ -353,7 +353,7 @@ return result{} } // The expression is x[index] - if m, ok := x.v.(program.Map); ok { + if m, ok := x.v.(debug.Map); ok { if getAddress { return e.err("can't take address of map value") } @@ -406,7 +406,7 @@ return e.err("invalid index: " + err.Error()) } switch v := x.v.(type) { - case program.Array: + case debug.Array: if u >= v.Length { return e.err("array index out of bounds") } @@ -415,7 +415,7 @@ return e.err(err.Error()) } return e.resultFrom(v.Element(u).Address, elemType, getAddress) - case program.Slice: + case debug.Slice: if u >= v.Length { return e.err("slice index out of bounds") } @@ -429,7 +429,7 @@ return e.err("slice index out of bounds") } return e.resultFrom(v.Element(u).Address, x.d, getAddress) - case program.String: + case debug.String: if getAddress { return e.err("can't take address of string element") } @@ -482,19 +482,19 @@ } x := e.evalNode(n.X, false) switch v := x.v.(type) { - case program.Array, program.Pointer, pointerToValue: + case debug.Array, debug.Pointer, pointerToValue: // This case handles the slicing of arrays and pointers to arrays. - var arr program.Array + var arr debug.Array switch v := x.v.(type) { - case program.Array: + case debug.Array: arr = v - case program.Pointer: + 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.(program.Array) + arr, ok = a.v.(debug.Array) if !ok { // v is a pointer to something other than an array. return e.err("cannot slice pointer") @@ -502,7 +502,7 @@ case pointerToValue: a := e.resultFrom(v.a, x.d, false) var ok bool - arr, ok = a.v.(program.Array) + arr, ok = a.v.(debug.Array) if !ok { // v is a pointer to something other than an array. return e.err("cannot slice pointer") @@ -528,7 +528,7 @@ return result{ d: elemType, v: sliceOf{ - Array: program.Array{ + Array: debug.Array{ ElementTypeID: arr.ElementTypeID, Address: arr.Element(low).Address, Length: high - low, @@ -537,7 +537,7 @@ Capacity: max - low, }, } - case program.Slice: + case debug.Slice: if n.High == nil { high = v.Length } else if high > v.Capacity { @@ -573,7 +573,7 @@ v.Length = high - low v.Capacity = max - low return result{x.d, v} - case program.String: + case debug.String: if n.Max != nil { return e.err("full slice of string") } @@ -939,12 +939,12 @@ } return result{x.d, c} - case program.String: - b, ok := y.v.(program.String) + case debug.String: + b, ok := y.v.(debug.String) if !ok { return e.err("type mismatch") } - var c program.String + 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 @@ -1298,7 +1298,7 @@ if !ok { e.err("couldn't construct string") } - return result{t, program.String{Length: uint64(len(s)), String: s}} + return result{t, debug.String{Length: uint64(len(s)), String: s}} } // getBaseType returns the *dwarf.Type with a given name. @@ -1385,24 +1385,24 @@ case *dwarf.BoolType: v = false case *dwarf.PtrType: - v = program.Pointer{TypeID: uint64(t.Common().Offset)} + v = debug.Pointer{TypeID: uint64(t.Common().Offset)} case *dwarf.SliceType: - v = program.Slice{ - Array: program.Array{ + v = debug.Slice{ + Array: debug.Array{ ElementTypeID: uint64(typ.ElemType.Common().Offset), StrideBits: uint64(typ.ElemType.Common().ByteSize) * 8, }, } case *dwarf.StringType: - v = program.String{} + v = debug.String{} case *dwarf.InterfaceType: - v = program.Interface{} + v = debug.Interface{} case *dwarf.FuncType: - v = program.Func{} + v = debug.Func{} case *dwarf.MapType: - v = program.Map{TypeID: uint64(t.Common().Offset)} + v = debug.Map{TypeID: uint64(t.Common().Offset)} case *dwarf.ChanType: - v = program.Channel{ + v = debug.Channel{ ElementTypeID: uint64(typ.ElemType.Common().Offset), Stride: uint64(typ.ElemType.Common().ByteSize), } @@ -1592,8 +1592,8 @@ } case untString: switch y.v.(type) { - case program.String: - return result{y.d, program.String{Length: uint64(len(a)), String: string(a)}} + case debug.String: + return result{y.d, debug.String{Length: uint64(len(a)), String: string(a)}} } } return x
diff --git a/ogle/program/server/peek.go b/server/peek.go similarity index 100% rename from ogle/program/server/peek.go rename to server/peek.go
diff --git a/ogle/program/server/print.go b/server/print.go similarity index 99% rename from ogle/program/server/print.go rename to server/print.go index 0ec0e5c..927988a 100644 --- a/ogle/program/server/print.go +++ b/server/print.go
@@ -8,8 +8,8 @@ "bytes" "fmt" + "golang.org/x/debug/arch" "golang.org/x/debug/dwarf" - "golang.org/x/debug/ogle/arch" ) // typeAndAddress associates an address in the target with a DWARF type.
diff --git a/ogle/program/proxyrpc/proxyrpc.go b/server/protocol/protocol.go similarity index 69% rename from ogle/program/proxyrpc/proxyrpc.go rename to server/protocol/protocol.go index b6636f8..c08b895 100644 --- a/ogle/program/proxyrpc/proxyrpc.go +++ b/server/protocol/protocol.go
@@ -2,27 +2,26 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package proxyrpc defines the types used to represent the RPC calls -// used to the ogleproxy. -package proxyrpc // import "golang.org/x/debug/ogle/program/proxyrpc" +// 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/ogle/program" + "golang.org/x/debug" ) func init() { - // Register implementations of program.Value with gob. - gob.Register(program.Pointer{}) - gob.Register(program.Array{}) - gob.Register(program.Struct{}) - gob.Register(program.Slice{}) - gob.Register(program.Map{}) - gob.Register(program.String{}) - gob.Register(program.Channel{}) - gob.Register(program.Func{}) - gob.Register(program.Interface{}) + // 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 @@ -73,14 +72,14 @@ } type RunResponse struct { - Status program.Status + Status debug.Status } type ResumeRequest struct { } type ResumeResponse struct { - Status program.Status + Status debug.Status } type BreakpointRequest struct { @@ -120,7 +119,7 @@ } type EvaluateResponse struct { - Result program.Value + Result debug.Value } type FramesRequest struct { @@ -128,7 +127,7 @@ } type FramesResponse struct { - Frames []program.Frame + Frames []debug.Frame } type VarByNameRequest struct { @@ -136,30 +135,30 @@ } type VarByNameResponse struct { - Var program.Var + Var debug.Var } type ValueRequest struct { - Var program.Var + Var debug.Var } type ValueResponse struct { - Value program.Value + Value debug.Value } type MapElementRequest struct { - Map program.Map + Map debug.Map Index uint64 } type MapElementResponse struct { - Key program.Var - Value program.Var + Key debug.Var + Value debug.Var } type GoroutinesRequest struct { } type GoroutinesResponse struct { - Goroutines []*program.Goroutine + Goroutines []*debug.Goroutine }
diff --git a/ogle/program/server/ptrace.go b/server/ptrace.go similarity index 100% rename from ogle/program/server/ptrace.go rename to server/ptrace.go
diff --git a/ogle/program/server/server.go b/server/server.go similarity index 78% rename from ogle/program/server/server.go rename to server/server.go index 2d86704..584ed5b 100644 --- a/ogle/program/server/server.go +++ b/server/server.go
@@ -4,7 +4,7 @@ // 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/ogle/program/server" +package server // import "golang.org/x/debug/server" //go:generate sh -c "m4 -P eval.m4 > eval.go" @@ -19,12 +19,12 @@ "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/ogle/arch" - "golang.org/x/debug/ogle/program" - "golang.org/x/debug/ogle/program/proxyrpc" + "golang.org/x/debug/server/protocol" ) type breakpoint struct { @@ -58,7 +58,7 @@ printer *Printer // goroutineStack reads the stack of a (non-running) goroutine. - goroutineStack func(uint64) ([]program.Frame, error) + goroutineStack func(uint64) ([]debug.Frame, error) goroutineStackOnce sync.Once } @@ -154,38 +154,38 @@ func (s *Server) dispatch(c call) { switch req := c.req.(type) { - case *proxyrpc.BreakpointRequest: - c.errc <- s.handleBreakpoint(req, c.resp.(*proxyrpc.BreakpointResponse)) - case *proxyrpc.BreakpointAtFunctionRequest: - c.errc <- s.handleBreakpointAtFunction(req, c.resp.(*proxyrpc.BreakpointResponse)) - case *proxyrpc.BreakpointAtLineRequest: - c.errc <- s.handleBreakpointAtLine(req, c.resp.(*proxyrpc.BreakpointResponse)) - case *proxyrpc.DeleteBreakpointsRequest: - c.errc <- s.handleDeleteBreakpoints(req, c.resp.(*proxyrpc.DeleteBreakpointsResponse)) - case *proxyrpc.CloseRequest: - c.errc <- s.handleClose(req, c.resp.(*proxyrpc.CloseResponse)) - case *proxyrpc.EvalRequest: - c.errc <- s.handleEval(req, c.resp.(*proxyrpc.EvalResponse)) - case *proxyrpc.EvaluateRequest: - c.errc <- s.handleEvaluate(req, c.resp.(*proxyrpc.EvaluateResponse)) - case *proxyrpc.FramesRequest: - c.errc <- s.handleFrames(req, c.resp.(*proxyrpc.FramesResponse)) - case *proxyrpc.OpenRequest: - c.errc <- s.handleOpen(req, c.resp.(*proxyrpc.OpenResponse)) - case *proxyrpc.ReadAtRequest: - c.errc <- s.handleReadAt(req, c.resp.(*proxyrpc.ReadAtResponse)) - case *proxyrpc.ResumeRequest: - c.errc <- s.handleResume(req, c.resp.(*proxyrpc.ResumeResponse)) - case *proxyrpc.RunRequest: - c.errc <- s.handleRun(req, c.resp.(*proxyrpc.RunResponse)) - case *proxyrpc.VarByNameRequest: - c.errc <- s.handleVarByName(req, c.resp.(*proxyrpc.VarByNameResponse)) - case *proxyrpc.ValueRequest: - c.errc <- s.handleValue(req, c.resp.(*proxyrpc.ValueResponse)) - case *proxyrpc.MapElementRequest: - c.errc <- s.handleMapElement(req, c.resp.(*proxyrpc.MapElementResponse)) - case *proxyrpc.GoroutinesRequest: - c.errc <- s.handleGoroutines(req, c.resp.(*proxyrpc.GoroutinesResponse)) + 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)) } @@ -200,14 +200,14 @@ type file struct { mode string index int - f program.File + f debug.File } -func (s *Server) Open(req *proxyrpc.OpenRequest, resp *proxyrpc.OpenResponse) error { +func (s *Server) Open(req *protocol.OpenRequest, resp *protocol.OpenResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleOpen(req *proxyrpc.OpenRequest, resp *proxyrpc.OpenResponse) error { +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 { @@ -241,11 +241,11 @@ return nil } -func (s *Server) ReadAt(req *proxyrpc.ReadAtRequest, resp *proxyrpc.ReadAtResponse) error { +func (s *Server) ReadAt(req *protocol.ReadAtRequest, resp *protocol.ReadAtResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleReadAt(req *proxyrpc.ReadAtRequest, resp *proxyrpc.ReadAtResponse) error { +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) @@ -257,11 +257,11 @@ return err } -func (s *Server) Close(req *proxyrpc.CloseRequest, resp *proxyrpc.CloseResponse) error { +func (s *Server) Close(req *protocol.CloseRequest, resp *protocol.CloseResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleClose(req *proxyrpc.CloseRequest, resp *proxyrpc.CloseResponse) error { +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) @@ -272,11 +272,11 @@ return err } -func (s *Server) Run(req *proxyrpc.RunRequest, resp *proxyrpc.RunResponse) error { +func (s *Server) Run(req *protocol.RunRequest, resp *protocol.RunResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleRun(req *proxyrpc.RunRequest, resp *proxyrpc.RunResponse) error { +func (s *Server) handleRun(req *protocol.RunRequest, resp *protocol.RunResponse) error { if s.proc != nil { s.proc.Kill() s.proc = nil @@ -305,11 +305,11 @@ return nil } -func (s *Server) Resume(req *proxyrpc.ResumeRequest, resp *proxyrpc.ResumeResponse) error { +func (s *Server) Resume(req *protocol.ResumeRequest, resp *protocol.ResumeResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleResume(req *proxyrpc.ResumeRequest, resp *proxyrpc.ResumeResponse) error { +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") } @@ -412,19 +412,19 @@ } } -func (s *Server) Breakpoint(req *proxyrpc.BreakpointRequest, resp *proxyrpc.BreakpointResponse) error { +func (s *Server) Breakpoint(req *protocol.BreakpointRequest, resp *protocol.BreakpointResponse) error { return s.call(s.breakpointc, req, resp) } -func (s *Server) handleBreakpoint(req *proxyrpc.BreakpointRequest, resp *proxyrpc.BreakpointResponse) error { +func (s *Server) handleBreakpoint(req *protocol.BreakpointRequest, resp *protocol.BreakpointResponse) error { return s.addBreakpoints([]uint64{req.Address}, resp) } -func (s *Server) BreakpointAtFunction(req *proxyrpc.BreakpointAtFunctionRequest, resp *proxyrpc.BreakpointResponse) error { +func (s *Server) BreakpointAtFunction(req *protocol.BreakpointAtFunctionRequest, resp *protocol.BreakpointResponse) error { return s.call(s.breakpointc, req, resp) } -func (s *Server) handleBreakpointAtFunction(req *proxyrpc.BreakpointAtFunctionRequest, resp *proxyrpc.BreakpointResponse) error { +func (s *Server) handleBreakpointAtFunction(req *protocol.BreakpointAtFunctionRequest, resp *protocol.BreakpointResponse) error { pc, err := s.lookupFunction(req.Function) if err != nil { return err @@ -432,11 +432,11 @@ return s.addBreakpoints([]uint64{pc}, resp) } -func (s *Server) BreakpointAtLine(req *proxyrpc.BreakpointAtLineRequest, resp *proxyrpc.BreakpointResponse) error { +func (s *Server) BreakpointAtLine(req *protocol.BreakpointAtLineRequest, resp *protocol.BreakpointResponse) error { return s.call(s.breakpointc, req, resp) } -func (s *Server) handleBreakpointAtLine(req *proxyrpc.BreakpointAtLineRequest, resp *proxyrpc.BreakpointResponse) error { +func (s *Server) handleBreakpointAtLine(req *protocol.BreakpointAtLineRequest, resp *protocol.BreakpointResponse) error { if s.dwarfData == nil { return fmt.Errorf("no DWARF data") } @@ -448,7 +448,7 @@ } // addBreakpoints adds breakpoints at the addresses in pcs, then stores pcs in the response. -func (s *Server) addBreakpoints(pcs []uint64, resp *proxyrpc.BreakpointResponse) error { +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 { @@ -470,11 +470,11 @@ return nil } -func (s *Server) DeleteBreakpoints(req *proxyrpc.DeleteBreakpointsRequest, resp *proxyrpc.DeleteBreakpointsResponse) error { +func (s *Server) DeleteBreakpoints(req *protocol.DeleteBreakpointsRequest, resp *protocol.DeleteBreakpointsResponse) error { return s.call(s.breakpointc, req, resp) } -func (s *Server) handleDeleteBreakpoints(req *proxyrpc.DeleteBreakpointsRequest, resp *proxyrpc.DeleteBreakpointsResponse) error { +func (s *Server) handleDeleteBreakpoints(req *protocol.DeleteBreakpointsRequest, resp *protocol.DeleteBreakpointsResponse) error { for _, pc := range req.PCs { delete(s.breakpoints, pc) } @@ -501,11 +501,11 @@ return nil } -func (s *Server) Eval(req *proxyrpc.EvalRequest, resp *proxyrpc.EvalResponse) error { +func (s *Server) Eval(req *protocol.EvalRequest, resp *protocol.EvalResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleEval(req *proxyrpc.EvalRequest, resp *proxyrpc.EvalResponse) (err error) { +func (s *Server) handleEval(req *protocol.EvalRequest, resp *protocol.EvalResponse) (err error) { resp.Result, err = s.eval(req.Expr) return err } @@ -566,11 +566,11 @@ return nil, fmt.Errorf("bad expression syntax: %q", expr) } -func (s *Server) Evaluate(req *proxyrpc.EvaluateRequest, resp *proxyrpc.EvaluateResponse) error { +func (s *Server) Evaluate(req *protocol.EvaluateRequest, resp *protocol.EvaluateResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleEvaluate(req *proxyrpc.EvaluateRequest, resp *proxyrpc.EvaluateResponse) (err error) { +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 } @@ -602,11 +602,11 @@ return addr, nil } -func (s *Server) Frames(req *proxyrpc.FramesRequest, resp *proxyrpc.FramesResponse) error { +func (s *Server) Frames(req *protocol.FramesRequest, resp *protocol.FramesResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleFrames(req *proxyrpc.FramesRequest, resp *proxyrpc.FramesResponse) error { +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 { @@ -624,8 +624,8 @@ } // walkStack returns up to the requested number of stack frames. -func (s *Server) walkStack(pc, sp uint64, count int) ([]program.Frame, error) { - var frames []program.Frame +func (s *Server) walkStack(pc, sp uint64, count int) ([]debug.Frame, error) { + var frames []debug.Frame var buf [8]byte b := new(bytes.Buffer) @@ -647,7 +647,7 @@ if err != nil { return frames, err } - frame := program.Frame{ + frame := debug.Frame{ PC: pc, SP: sp, File: file, @@ -667,7 +667,7 @@ // 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, program.Param(v)) + frame.Params = append(frame.Params, debug.Param(v)) } } if entry.Tag == dwarf.TagVariable { @@ -694,8 +694,8 @@ // 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) (program.LocalVar, error) { - var v program.LocalVar +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 @@ -775,11 +775,11 @@ return false } -func (s *Server) VarByName(req *proxyrpc.VarByNameRequest, resp *proxyrpc.VarByNameResponse) error { +func (s *Server) VarByName(req *protocol.VarByNameRequest, resp *protocol.VarByNameResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleVarByName(req *proxyrpc.VarByNameRequest, resp *proxyrpc.VarByNameResponse) error { +func (s *Server) handleVarByName(req *protocol.VarByNameRequest, resp *protocol.VarByNameResponse) error { entry, err := s.dwarfData.LookupEntry(req.Name) if err != nil { return fmt.Errorf("variable %s: %s", req.Name, err) @@ -800,11 +800,11 @@ return nil } -func (s *Server) Value(req *proxyrpc.ValueRequest, resp *proxyrpc.ValueResponse) error { +func (s *Server) Value(req *protocol.ValueRequest, resp *protocol.ValueResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleValue(req *proxyrpc.ValueRequest, resp *proxyrpc.ValueResponse) error { +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 @@ -813,11 +813,11 @@ return err } -func (s *Server) MapElement(req *proxyrpc.MapElementRequest, resp *proxyrpc.MapElementResponse) error { +func (s *Server) MapElement(req *protocol.MapElementRequest, resp *protocol.MapElementResponse) error { return s.call(s.otherc, req, resp) } -func (s *Server) handleMapElement(req *proxyrpc.MapElementRequest, resp *proxyrpc.MapElementResponse) error { +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 @@ -833,8 +833,8 @@ fn := func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool { count++ if count == req.Index+1 { - resp.Key = program.Var{TypeID: uint64(keyType.Common().Offset), Address: keyAddr} - resp.Value = program.Var{TypeID: uint64(valType.Common().Offset), Address: valAddr} + 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 @@ -849,33 +849,33 @@ return nil } -func (s *Server) Goroutines(req *proxyrpc.GoroutinesRequest, resp *proxyrpc.GoroutinesResponse) error { +func (s *Server) Goroutines(req *protocol.GoroutinesRequest, resp *protocol.GoroutinesResponse) error { return s.call(s.otherc, req, resp) } -const invalidStatus program.GoroutineStatus = 99 +const invalidStatus debug.GoroutineStatus = 99 var ( - gStatus = [...]program.GoroutineStatus{ - 0: program.Queued, // _Gidle - 1: program.Queued, // _Grunnable - 2: program.Running, // _Grunning - 3: program.Blocked, // _Gsyscall - 4: program.Blocked, // _Gwaiting - 5: invalidStatus, // _Gmoribund_unused - 6: invalidStatus, // _Gdead - 7: invalidStatus, // _Genqueue - 8: program.Running, // _Gcopystack + 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 = [...]program.GoroutineStatus{ - 0: invalidStatus, // _Gscan + _Gidle - 1: program.Queued, // _Gscanrunnable - 2: program.Running, // _Gscanrunning - 3: program.Blocked, // _Gscansyscall - 4: program.Blocked, // _Gscanwaiting - 5: invalidStatus, // _Gscan + _Gmoribund_unused - 6: invalidStatus, // _Gscan + _Gdead - 7: program.Queued, // _Gscanenqueue + 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", @@ -894,7 +894,7 @@ } ) -func (s *Server) handleGoroutines(req *proxyrpc.GoroutinesRequest, resp *proxyrpc.GoroutinesResponse) error { +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 { @@ -972,7 +972,7 @@ if err != nil { return err } - gr := program.Goroutine{} + gr := debug.Goroutine{} // Read status from the field named "atomicstatus" or "status". status, err := s.peekUintStructField(gType, g, "atomicstatus") @@ -1034,7 +1034,7 @@ if gopc, err := s.peekUintStructField(gType, g, "gopc"); err == nil { gr.Caller = functionName(gopc) } - if gr.Status != program.Running { + if gr.Status != debug.Running { // TODO: running goroutines too. gr.StackFrames, _ = s.goroutineStack(g) } @@ -1054,7 +1054,7 @@ // 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) ([]program.Frame, error) { + s.goroutineStack = func(gAddr uint64) ([]debug.Frame, error) { return nil, err } @@ -1099,7 +1099,7 @@ } } - s.goroutineStack = func(gAddr uint64) ([]program.Frame, error) { + s.goroutineStack = func(gAddr uint64) ([]debug.Frame, error) { schedPC, err := s.peekUint(gAddr+schedPCOffset, schedPCByteSize) if err != nil { return nil, err
diff --git a/ogle/program/server/value.go b/server/value.go similarity index 91% rename from ogle/program/server/value.go rename to server/value.go index 2b5c1c6..0fef7fe 100644 --- a/ogle/program/server/value.go +++ b/server/value.go
@@ -6,12 +6,13 @@ import ( "fmt" + + "golang.org/x/debug" "golang.org/x/debug/dwarf" - "golang.org/x/debug/ogle/program" ) // 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) (program.Value, error) { +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 { @@ -114,7 +115,7 @@ if err != nil { return nil, fmt.Errorf("reading pointer: %s", err) } - return program.Pointer{ + return debug.Pointer{ TypeID: uint64(t.Type.Common().Offset), Address: uint64(s.arch.Uintptr(buf)), }, nil @@ -135,8 +136,8 @@ return nil, fmt.Errorf("slice's capacity %d is less than its length %d", capacity, length) } - return program.Slice{ - program.Array{ + return debug.Slice{ + debug.Array{ ElementTypeID: uint64(t.ElemType.Common().Offset), Address: uint64(ptr), Length: length, @@ -150,24 +151,24 @@ if stride%8 != 0 { return nil, fmt.Errorf("array is not byte-aligned") } - return program.Array{ + return debug.Array{ ElementTypeID: uint64(t.Type.Common().Offset), Address: uint64(addr), Length: uint64(length), StrideBits: uint64(stride), }, nil case *dwarf.StructType: - fields := make([]program.StructField, len(t.Field)) + fields := make([]debug.StructField, len(t.Field)) for i, field := range t.Field { - fields[i] = program.StructField{ + fields[i] = debug.StructField{ Name: field.Name, - Var: program.Var{ + Var: debug.Var{ TypeID: uint64(field.Type.Common().Offset), Address: uint64(addr) + uint64(field.ByteOffset), }, } } - return program.Struct{fields}, nil + return debug.Struct{fields}, nil case *dwarf.TypedefType: return s.value(t.Type, addr) case *dwarf.MapType: @@ -175,7 +176,7 @@ if err != nil { return nil, err } - return program.Map{ + return debug.Map{ TypeID: uint64(t.Common().Offset), Address: addr, Length: length, @@ -200,7 +201,7 @@ if err := s.peekBytes(ptr, tmp); err != nil { return nil, fmt.Errorf("reading string contents: %s", err) } - return program.String{Length: length, String: string(tmp)}, nil + return debug.String{Length: length, String: string(tmp)}, nil case *dwarf.ChanType: pt, ok := t.TypedefType.Type.(*dwarf.PtrType) if !ok { @@ -217,7 +218,7 @@ } if a == 0 { // This channel is nil. - return program.Channel{ + return debug.Channel{ ElementTypeID: uint64(t.ElemType.Common().Offset), Address: 0, Buffer: 0, @@ -244,7 +245,7 @@ if err != nil { return nil, fmt.Errorf("reading channel buffer index: %s", err) } - return program.Channel{ + return debug.Channel{ ElementTypeID: uint64(t.ElemType.Common().Offset), Address: a, Buffer: buf, @@ -258,9 +259,9 @@ if err != nil { return nil, fmt.Errorf("reading func: %s", err) } - return program.Func{Address: a}, nil + return debug.Func{Address: a}, nil case *dwarf.InterfaceType: - return program.Interface{}, nil + return debug.Interface{}, nil // TODO: more types } return nil, fmt.Errorf("Unsupported type %T", t)
diff --git a/ogle/demo/ogler/ogler_test.go b/tests/peek/peek_test.go similarity index 73% rename from ogle/demo/ogler/ogler_test.go rename to tests/peek/peek_test.go index 729fa75..8d00a93 100644 --- a/ogle/demo/ogler/ogler_test.go +++ b/tests/peek/peek_test.go
@@ -2,10 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Demo program that starts another program and calls Ogle library functions -// to debug it. - -package ogler +package peek_test import ( "fmt" @@ -15,9 +12,9 @@ "reflect" "testing" - "golang.org/x/debug/ogle/program" - "golang.org/x/debug/ogle/program/client" - "golang.org/x/debug/ogle/program/local" + "golang.org/x/debug" + "golang.org/x/debug/local" + "golang.org/x/debug/remote" ) var expectedVarValues = map[string]interface{}{ @@ -87,53 +84,53 @@ `main.Z_unsafe_pointer_nil`: `0x0`, } -// expectedEvaluate contains expected results of the program.Evaluate function. +// expectedEvaluate contains expected results of the debug.Evaluate function. // A nil value indicates that an error is expected. -var expectedEvaluate = map[string]program.Value{ +var expectedEvaluate = map[string]debug.Value{ `x`: int16(42), - `local_array`: program.Array{42, 42, 5, 8}, + `local_array`: debug.Array{42, 42, 5, 8}, `local_bool_false`: false, `local_bool_true`: true, - `local_channel`: program.Channel{42, 42, 42, 0, 0, 2, 0}, - `local_channel_buffered`: program.Channel{42, 42, 42, 6, 10, 2, 8}, - `local_channel_nil`: program.Channel{42, 0, 0, 0, 0, 2, 0}, + `local_channel`: debug.Channel{42, 42, 42, 0, 0, 2, 0}, + `local_channel_buffered`: debug.Channel{42, 42, 42, 6, 10, 2, 8}, + `local_channel_nil`: debug.Channel{42, 0, 0, 0, 0, 2, 0}, `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_int8_r_int8`: program.Func{42}, - `local_func_int8_r_pint8`: program.Func{42}, - `local_func_bar`: program.Func{42}, - `local_func_nil`: program.Func{0}, + `local_func_int8_r_int8`: debug.Func{42}, + `local_func_int8_r_pint8`: debug.Func{42}, + `local_func_bar`: debug.Func{42}, + `local_func_nil`: debug.Func{0}, `local_int`: -21, `local_int16`: int16(-32321), `local_int32`: int32(-1987654321), `local_int64`: int64(-9012345678987654321), `local_int8`: int8(-121), `local_int_typedef`: int16(88), - `local_interface`: program.Interface{}, - `local_interface_nil`: program.Interface{}, - `local_interface_typed_nil`: program.Interface{}, - `local_map`: program.Map{42, 42, 1}, - `local_map_2`: program.Map{42, 42, 1}, - `local_map_3`: program.Map{42, 42, 2}, - `local_map_empty`: program.Map{42, 42, 0}, - `local_map_nil`: program.Map{42, 42, 0}, - `local_pointer`: program.Pointer{42, 42}, - `local_pointer_nil`: program.Pointer{42, 0}, - `local_slice`: program.Slice{program.Array{42, 42, 5, 8}, 5}, - `local_slice_2`: program.Slice{program.Array{42, 42, 2, 8}, 5}, - `local_slice_nil`: program.Slice{program.Array{42, 0, 0, 8}, 0}, - `local_string`: program.String{12, `I'm a string`}, - `local_struct`: program.Struct{[]program.StructField{{"a", program.Var{}}, {"b", program.Var{}}}}, + `local_interface`: debug.Interface{}, + `local_interface_nil`: debug.Interface{}, + `local_interface_typed_nil`: debug.Interface{}, + `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}, + `local_map_nil`: debug.Map{42, 42, 0}, + `local_pointer`: debug.Pointer{42, 42}, + `local_pointer_nil`: debug.Pointer{42, 0}, + `local_slice`: debug.Slice{debug.Array{42, 42, 5, 8}, 5}, + `local_slice_2`: debug.Slice{debug.Array{42, 42, 2, 8}, 5}, + `local_slice_nil`: debug.Slice{debug.Array{42, 0, 0, 8}, 0}, + `local_string`: debug.String{12, `I'm a string`}, + `local_struct`: debug.Struct{[]debug.StructField{{"a", debug.Var{}}, {"b", debug.Var{}}}}, `local_uint`: uint(21), `local_uint16`: uint16(54321), `local_uint32`: uint32(3217654321), `local_uint64`: uint64(12345678900987654321), `local_uint8`: uint8(231), `local_uintptr`: uint(21), - `local_unsafe_pointer`: program.Pointer{0, 42}, - `local_unsafe_pointer_nil`: program.Pointer{0, 0}, + `local_unsafe_pointer`: debug.Pointer{0, 42}, + `local_unsafe_pointer_nil`: debug.Pointer{0, 0}, `x + 5`: int16(47), `x - 5`: int16(37), `x / 5`: int16(8), @@ -156,9 +153,9 @@ `1e5`: 100000.0, `0x42`: 66, `'c'`: 'c', - `"de"`: program.String{2, `de`}, - "`ef`": program.String{2, `ef`}, - `"de" + "fg"`: program.String{4, `defg`}, + `"de"`: debug.String{2, `de`}, + "`ef`": debug.String{2, `ef`}, + `"de" + "fg"`: debug.String{4, `defg`}, `/* comment */ -5`: -5, `false`: false, `true`: true, @@ -182,16 +179,16 @@ `(6 + 8i) * (1 + 1i)`: -2 + 14i, `(6 + 8i) * (6 - 8i)`: complex128(100), `(6 + 8i) / (3 + 4i)`: complex128(2), - `local_string + "!"`: program.String{13, `I'm a string!`}, - `*local_pointer`: program.Struct{[]program.StructField{{"a", program.Var{}}, {"b", program.Var{}}}}, - `&local_int16`: program.Pointer{42, 42}, + `local_string + "!"`: debug.String{13, `I'm a string!`}, + `*local_pointer`: debug.Struct{[]debug.StructField{{"a", debug.Var{}}, {"b", debug.Var{}}}}, + `&local_int16`: debug.Pointer{42, 42}, `*&local_int16`: int16(-32321), `*&*&*&*&local_int16`: int16(-32321), `local_array[2]`: int8(3), `local_slice[1]`: uint8(108), `local_slice_2[1]`: int8(121), - `&local_array[1]`: program.Pointer{42, 42}, - `&local_slice[1]`: program.Pointer{42, 42}, + `&local_array[1]`: debug.Pointer{42, 42}, + `&local_slice[1]`: debug.Pointer{42, 42}, `local_map[-21]`: float32(3.54321), `local_map[+21]`: float32(0), `local_map_3[1024]`: int8(1), @@ -202,78 +199,78 @@ `"hello"[2]`: uint8('l'), `local_array[1:3][1]`: int8(3), `local_array[0:4][2:3][0]`: int8(3), - `local_array[:]`: program.Slice{program.Array{42, 42, 5, 8}, 5}, - `local_array[:2]`: program.Slice{program.Array{42, 42, 2, 8}, 5}, - `local_array[2:]`: program.Slice{program.Array{42, 42, 3, 8}, 3}, - `local_array[1:3]`: program.Slice{program.Array{42, 42, 2, 8}, 4}, - `local_array[:3:4]`: program.Slice{program.Array{42, 42, 3, 8}, 4}, - `local_array[1:3:4]`: program.Slice{program.Array{42, 42, 2, 8}, 3}, - `local_array[1:][1:][1:]`: program.Slice{program.Array{42, 42, 2, 8}, 2}, - `(&local_array)[:]`: program.Slice{program.Array{42, 42, 5, 8}, 5}, - `(&local_array)[:2]`: program.Slice{program.Array{42, 42, 2, 8}, 5}, - `(&local_array)[2:]`: program.Slice{program.Array{42, 42, 3, 8}, 3}, - `(&local_array)[1:3]`: program.Slice{program.Array{42, 42, 2, 8}, 4}, - `(&local_array)[:3:4]`: program.Slice{program.Array{42, 42, 3, 8}, 4}, - `(&local_array)[1:3:4]`: program.Slice{program.Array{42, 42, 2, 8}, 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}, `local_slice[1:5][0:3][1]`: uint8('i'), - `local_slice[:]`: program.Slice{program.Array{42, 42, 5, 8}, 5}, - `local_slice[:2]`: program.Slice{program.Array{42, 42, 2, 8}, 5}, - `local_slice[2:]`: program.Slice{program.Array{42, 42, 3, 8}, 3}, - `local_slice[1:3]`: program.Slice{program.Array{42, 42, 2, 8}, 4}, - `local_slice[:3:4]`: program.Slice{program.Array{42, 42, 3, 8}, 4}, - `local_slice[1:3:4]`: program.Slice{program.Array{42, 42, 2, 8}, 3}, + `local_slice[:]`: debug.Slice{debug.Array{42, 42, 5, 8}, 5}, + `local_slice[:2]`: debug.Slice{debug.Array{42, 42, 2, 8}, 5}, + `local_slice[2:]`: debug.Slice{debug.Array{42, 42, 3, 8}, 3}, + `local_slice[1:3]`: debug.Slice{debug.Array{42, 42, 2, 8}, 4}, + `local_slice[:3:4]`: debug.Slice{debug.Array{42, 42, 3, 8}, 4}, + `local_slice[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3}, `local_struct.a`: 21, `(&local_struct).a`: 21, `(*local_pointer).a`: 21, `(&*local_pointer).a`: 21, - `(*local_pointer).b`: program.String{2, `hi`}, + `(*local_pointer).b`: debug.String{2, `hi`}, `local_pointer.a`: 21, - `local_pointer.b`: program.String{2, `hi`}, - `lookup("main.Z_array")`: program.Array{42, 42, 5, 8}, - `lookup("main.Z_array_empty")`: program.Array{42, 42, 0, 8}, + `local_pointer.b`: debug.String{2, `hi`}, + `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")`: program.Channel{42, 42, 42, 0, 0, 2, 0}, - `lookup("main.Z_channel_buffered")`: program.Channel{42, 42, 42, 6, 10, 2, 8}, - `lookup("main.Z_channel_nil")`: program.Channel{42, 0, 0, 0, 0, 2, 0}, - `lookup("main.Z_array_of_empties")`: program.Array{42, 42, 2, 0}, + `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")`: program.Func{42}, - `lookup("main.Z_func_int8_r_pint8")`: program.Func{42}, - `lookup("main.Z_func_bar")`: program.Func{42}, - `lookup("main.Z_func_nil")`: program.Func{0}, + `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")`: program.Interface{}, - `lookup("main.Z_interface_nil")`: program.Interface{}, - `lookup("main.Z_interface_typed_nil")`: program.Interface{}, - `lookup("main.Z_map")`: program.Map{42, 42, 1}, - `lookup("main.Z_map_2")`: program.Map{42, 42, 1}, - `lookup("main.Z_map_3")`: program.Map{42, 42, 2}, - `lookup("main.Z_map_empty")`: program.Map{42, 42, 0}, - `lookup("main.Z_map_nil")`: program.Map{42, 42, 0}, - `lookup("main.Z_pointer")`: program.Pointer{42, 42}, - `lookup("main.Z_pointer_nil")`: program.Pointer{42, 0}, - `lookup("main.Z_slice")`: program.Slice{program.Array{42, 42, 5, 8}, 5}, - `lookup("main.Z_slice_2")`: program.Slice{program.Array{42, 42, 2, 8}, 5}, - `lookup("main.Z_slice_nil")`: program.Slice{program.Array{42, 0, 0, 8}, 0}, - `lookup("main.Z_string")`: program.String{12, `I'm a string`}, - `lookup("main.Z_struct")`: program.Struct{[]program.StructField{{"a", program.Var{}}, {"b", program.Var{}}}}, + `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")`: program.Pointer{0, 42}, - `lookup("main.Z_unsafe_pointer_nil")`: program.Pointer{0, 0}, + `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), @@ -285,7 +282,7 @@ `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]`: program.Struct{}, + `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), @@ -301,9 +298,9 @@ `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]`: program.Slice{program.Array{42, 42, 2, 8}, 3}, - `(&lookup("main.Z_array"))[1:3:4]`: program.Slice{program.Array{42, 42, 2, 8}, 3}, - `lookup("main.Z_string") + "!"`: program.String{13, `I'm a string!`}, + `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), @@ -314,16 +311,16 @@ `lookup("main.Z_pointer").a`: 21, `(*lookup("main.Z_pointer")).a`: 21, `(&*lookup("main.Z_pointer")).a`: 21, - `lookup("main.Z_pointer").b`: program.String{2, `hi`}, - `(*lookup("main.Z_pointer")).b`: program.String{2, `hi`}, - `(&*lookup("main.Z_pointer")).b`: program.String{2, `hi`}, + `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")`: program.Pointer{42, 42}, - `&lookup("main.Z_array")[1]`: program.Pointer{42, 42}, - `&lookup("main.Z_slice")[1]`: program.Pointer{42, 42}, + `&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")`: program.Pointer{42, 42}, + `lookup("time.Local")`: debug.Pointer{42, 42}, `5 + false`: nil, ``: nil, `x + ""`: nil, @@ -400,10 +397,10 @@ } const ( - proxySrc = "golang.org/x/debug/ogle/cmd/ogleproxy" - proxyBinary = "./ogleproxy" - traceeSrc = "golang.org/x/debug/ogle/demo/tracee" - traceeBinary = "./tracee" + proxySrc = "golang.org/x/debug/cmd/debugproxy" + proxyBinary = "./debugproxy.out" + traceeSrc = "golang.org/x/debug/tests/peek/testdata" + traceeBinary = "./tracee.out" ) func TestMain(m *testing.M) { @@ -415,7 +412,7 @@ fmt.Println(err) return 1 } - client.OgleproxyCmd = proxyBinary + remote.DebugproxyCmd = proxyBinary defer os.Remove(proxyBinary) if err := run("go", "build", "-o", traceeBinary, traceeSrc); err != nil { fmt.Println(err) @@ -434,14 +431,14 @@ } func TestRemoteProgram(t *testing.T) { - prog, err := client.New("localhost", traceeBinary) + prog, err := remote.New("localhost", traceeBinary) if err != nil { - t.Fatal("client.New:", err) + t.Fatal("remote.New:", err) } testProgram(t, prog) } -func testProgram(t *testing.T, prog program.Program) { +func testProgram(t *testing.T, prog debug.Program) { _, err := prog.Run("some", "arguments") if err != nil { log.Fatalf("Run: %v", err) @@ -595,8 +592,8 @@ if v != val { t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v) } - case program.Array: - val := val.(program.Array) + 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) } @@ -609,8 +606,8 @@ if v.Address != 0 && val.Address == 0 { t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) } - case program.Slice: - val := val.(program.Slice) + 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) } @@ -623,8 +620,8 @@ if v.Address != 0 && val.Address == 0 { t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) } - case program.Map: - val := val.(program.Map) + 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) } @@ -637,8 +634,8 @@ if v.Address != 0 && val.Address == 0 { t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) } - case program.Pointer: - val := val.(program.Pointer) + 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) } @@ -651,8 +648,8 @@ if v.Address != 0 && val.Address == 0 { t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) } - case program.Channel: - val := val.(program.Channel) + 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) } @@ -671,8 +668,8 @@ if v.Buffer != 0 && val.Buffer == 0 { t.Errorf("got Evaluate(%s) = %+v, expected non-zero Buffer", k, val) } - case program.Struct: - val := val.(program.Struct) + 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 @@ -685,8 +682,8 @@ break } } - case program.Func: - val := val.(program.Func) + 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) } @@ -729,9 +726,9 @@ if err != nil { t.Fatalf("Evaluate: %s", err) } - s, ok := val.(program.Struct) + s, ok := val.(debug.Struct) if !ok { - t.Fatalf("got Evaluate(`local_struct`) = %T(%v), expected program.Struct", val, val) + t.Fatalf("got Evaluate(`local_struct`) = %T(%v), expected debug.Struct", val, val) } // Check the values of its fields. if len(s.Fields) != 2 { @@ -744,7 +741,7 @@ } if v1, err := prog.Value(s.Fields[1].Var); err != nil { t.Errorf("Value: %s", err) - } else if v1 != (program.String{2, "hi"}) { + } else if v1 != (debug.String{2, "hi"}) { t.Errorf("Value: got %T(%v), expected `hi`", v1, v1) } @@ -791,7 +788,7 @@ if _, err = prog.VarByName("not a real name"); err == nil { t.Error("VarByName for invalid name: expected error") } - if _, err = prog.Value(program.Var{}); err == nil { + 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 { @@ -808,7 +805,7 @@ // 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 program.Value) error) { + 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 { @@ -818,7 +815,7 @@ } } - checkValue("main.Z_uintptr", func(val program.Value) error { + 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. @@ -827,29 +824,29 @@ return nil }) - checkValue("main.Z_int", func(val program.Value) error { + 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 program.Value) error { + 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 program.Value) error { - if _, ok := val.(program.Pointer); !ok { + 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 program.Value) error { - if p, ok := val.(program.Pointer); !ok { + 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) @@ -857,8 +854,8 @@ return nil }) - checkValue("main.Z_array", func(val program.Value) error { - a, ok := val.(program.Array) + 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) } @@ -876,8 +873,8 @@ return nil }) - checkValue("main.Z_slice", func(val program.Value) error { - s, ok := val.(program.Slice) + 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) } @@ -895,8 +892,8 @@ return nil }) - checkValue("main.Z_map_empty", func(val program.Value) error { - m, ok := val.(program.Map) + 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) } @@ -906,8 +903,8 @@ return nil }) - checkValue("main.Z_map_nil", func(val program.Value) error { - m, ok := val.(program.Map) + 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) } @@ -917,8 +914,8 @@ return nil }) - checkValue("main.Z_map_3", func(val program.Value) error { - m, ok := val.(program.Map) + 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) } @@ -962,8 +959,8 @@ return nil }) - checkValue("main.Z_string", func(val program.Value) error { - s, ok := val.(program.String) + 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) } @@ -977,8 +974,8 @@ return nil }) - checkValue("main.Z_channel", func(val program.Value) error { - c, ok := val.(program.Channel) + 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) } @@ -994,8 +991,8 @@ return nil }) - checkValue("main.Z_channel_2", func(val program.Value) error { - c, ok := val.(program.Channel) + 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) } @@ -1011,8 +1008,8 @@ return nil }) - checkValue("main.Z_channel_nil", func(val program.Value) error { - c, ok := val.(program.Channel) + 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) } @@ -1028,8 +1025,8 @@ return nil }) - checkValue("main.Z_channel_buffered", func(val program.Value) error { - c, ok := val.(program.Channel) + 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) } @@ -1060,8 +1057,8 @@ return nil }) - checkValue("main.Z_func_bar", func(val program.Value) error { - f, ok := val.(program.Func) + 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) } @@ -1071,8 +1068,8 @@ return nil }) - checkValue("main.Z_func_nil", func(val program.Value) error { - f, ok := val.(program.Func) + 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) }
diff --git a/ogle/demo/tracee/main.go b/tests/peek/testdata/main.go similarity index 98% rename from ogle/demo/tracee/main.go rename to tests/peek/testdata/main.go index 91b942e..61a568e 100644 --- a/ogle/demo/tracee/main.go +++ b/tests/peek/testdata/main.go
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Program for the Ogle demo to debug. - package main import (