From 49667f2302f139f7c89516d86d0b460fdf90300c Mon Sep 17 00:00:00 2001 From: Derek Parker Date: Wed, 27 May 2015 12:16:45 -0500 Subject: [PATCH] Rename thread.Process -> thread.dbp Process is an incorrect name for the DebuggedProcess struct that the thread is "a part" of. Also, no need to export that field. --- command/command.go | 9 +++--- proctl/proctl_darwin.go | 6 ++-- proctl/proctl_linux.go | 6 ++-- proctl/proctl_test.go | 2 +- proctl/stack.go | 2 +- proctl/threads.go | 62 ++++++++++++++++++++++++------------ proctl/threads_darwin.go | 10 +++--- proctl/threads_linux.go | 4 +-- proctl/variables.go | 40 +++++++++++------------ service/debugger/debugger.go | 26 ++++++++------- 10 files changed, 95 insertions(+), 72 deletions(-) diff --git a/command/command.go b/command/command.go index e53e88e1..db5053bf 100644 --- a/command/command.go +++ b/command/command.go @@ -124,15 +124,14 @@ func threads(p *proctl.DebuggedProcess, args ...string) error { if th == p.CurrentThread { prefix = "* " } - pc, err := th.PC() + loc, err := th.Location() if err != nil { return err } - f, l, fn := th.Process.PCToLine(pc) - if fn != nil { - fmt.Printf("%sThread %d at %#v %s:%d %s\n", prefix, th.Id, pc, f, l, fn.Name) + if loc.Fn != nil { + fmt.Printf("%sThread %d at %#v %s:%d %s\n", prefix, th.Id, loc.PC, loc.File, loc.Line, loc.Fn.Name) } else { - fmt.Printf("%sThread %d at %#v\n", prefix, th.Id, pc) + fmt.Printf("%sThread %d at %#v\n", prefix, th.Id, loc.PC) } } return nil diff --git a/proctl/proctl_darwin.go b/proctl/proctl_darwin.go index 5acb9bb1..a1a04387 100644 --- a/proctl/proctl_darwin.go +++ b/proctl/proctl_darwin.go @@ -121,9 +121,9 @@ func (dbp *DebuggedProcess) addThread(port int, attach bool) (*ThreadContext, er return thread, nil } thread := &ThreadContext{ - Id: port, - Process: dbp, - os: new(OSSpecificDetails), + Id: port, + dbp: dbp, + os: new(OSSpecificDetails), } dbp.Threads[port] = thread thread.os.thread_act = C.thread_act_t(port) diff --git a/proctl/proctl_linux.go b/proctl/proctl_linux.go index 0da0c105..9ff87017 100644 --- a/proctl/proctl_linux.go +++ b/proctl/proctl_linux.go @@ -100,9 +100,9 @@ func (dbp *DebuggedProcess) addThread(tid int, attach bool) (*ThreadContext, err } dbp.Threads[tid] = &ThreadContext{ - Id: tid, - Process: dbp, - os: new(OSSpecificDetails), + Id: tid, + dbp: dbp, + os: new(OSSpecificDetails), } if dbp.CurrentThread == nil { diff --git a/proctl/proctl_test.go b/proctl/proctl_test.go index 02f76700..d22a2350 100644 --- a/proctl/proctl_test.go +++ b/proctl/proctl_test.go @@ -443,7 +443,7 @@ func TestFunctionCall(t *testing.T) { if err != nil { t.Fatal(err) } - f := th.Process.goSymTable.LookupFunc("runtime.getg") + f := th.dbp.goSymTable.LookupFunc("runtime.getg") if f == nil { t.Fatalf("could not find function %s", "runtime.getg") } diff --git a/proctl/stack.go b/proctl/stack.go index 16a2e5d2..7770a166 100644 --- a/proctl/stack.go +++ b/proctl/stack.go @@ -19,7 +19,7 @@ func (thread *ThreadContext) ReturnAddress() (uint64, error) { if err != nil { return 0, err } - locations, err := thread.Process.stacktrace(regs.PC(), regs.SP(), 1) + locations, err := thread.dbp.stacktrace(regs.PC(), regs.SP(), 1) if err != nil { return 0, err } diff --git a/proctl/threads.go b/proctl/threads.go index 01c59d7f..3840f136 100644 --- a/proctl/threads.go +++ b/proctl/threads.go @@ -1,6 +1,7 @@ package proctl import ( + "debug/gosym" "fmt" "path/filepath" @@ -16,14 +17,21 @@ import ( // on this thread. type ThreadContext struct { Id int - Process *DebuggedProcess Status *sys.WaitStatus CurrentBreakpoint *BreakPoint + dbp *DebuggedProcess singleStepping bool running bool os *OSSpecificDetails } +type Location struct { + PC uint64 + File string + Line int + Fn *gosym.Func +} + // Continue the execution of this thread. This method takes // software breakpoints into consideration and ensures that // we step over any breakpoints. It will restore the instruction, @@ -36,7 +44,7 @@ func (thread *ThreadContext) Continue() error { // Check whether we are stopped at a breakpoint, and // if so, single step over it before continuing. - if _, ok := thread.Process.BreakPoints[pc]; ok { + if _, ok := thread.dbp.BreakPoints[pc]; ok { if err := thread.Step(); err != nil { return err } @@ -54,10 +62,10 @@ func (thread *ThreadContext) Step() (err error) { return err } - bp, ok := thread.Process.BreakPoints[pc] + bp, ok := thread.dbp.BreakPoints[pc] if ok { // Clear the breakpoint so that we can continue execution. - _, err = thread.Process.Clear(bp.Addr) + _, err = thread.dbp.Clear(bp.Addr) if err != nil { return err } @@ -65,7 +73,7 @@ func (thread *ThreadContext) Step() (err error) { // Restore breakpoint now that we have passed it. defer func() { var nbp *BreakPoint - nbp, err = thread.Process.Break(bp.Addr) + nbp, err = thread.dbp.Break(bp.Addr) nbp.Temp = bp.Temp }() } @@ -79,7 +87,7 @@ func (thread *ThreadContext) Step() (err error) { // Call a function named `name`. This is currently _NOT_ safe. func (thread *ThreadContext) CallFn(name string, fn func() error) error { - f := thread.Process.goSymTable.LookupFunc(name) + f := thread.dbp.goSymTable.LookupFunc(name) if f == nil { return fmt.Errorf("could not find function %s", name) } @@ -89,7 +97,7 @@ func (thread *ThreadContext) CallFn(name string, fn func() error) error { if err != nil { return err } - defer thread.Process.Clear(bp.Addr) + defer thread.dbp.Clear(bp.Addr) regs, err := thread.saveRegisters() if err != nil { @@ -110,7 +118,7 @@ func (thread *ThreadContext) CallFn(name string, fn func() error) error { if err = thread.Continue(); err != nil { return err } - th, err := thread.Process.trapWait(-1) + th, err := thread.dbp.trapWait(-1) if err != nil { return err } @@ -120,17 +128,26 @@ func (thread *ThreadContext) CallFn(name string, fn func() error) error { // Set breakpoint using this thread. func (thread *ThreadContext) Break(addr uint64) (*BreakPoint, error) { - return thread.Process.setBreakpoint(thread.Id, addr, false) + return thread.dbp.setBreakpoint(thread.Id, addr, false) } // Set breakpoint using this thread. func (thread *ThreadContext) TempBreak(addr uint64) (*BreakPoint, error) { - return thread.Process.setBreakpoint(thread.Id, addr, true) + return thread.dbp.setBreakpoint(thread.Id, addr, true) } // Clear breakpoint using this thread. func (thread *ThreadContext) Clear(addr uint64) (*BreakPoint, error) { - return thread.Process.clearBreakpoint(thread.Id, addr) + return thread.dbp.clearBreakpoint(thread.Id, addr) +} + +func (thread *ThreadContext) Location() (*Location, error) { + pc, err := thread.PC() + if err != nil { + return nil, err + } + f, l, fn := thread.dbp.PCToLine(pc) + return &Location{PC: pc, File: f, Line: l, Fn: fn}, nil } // Step to next source line. @@ -149,15 +166,18 @@ func (thread *ThreadContext) Next() (err error) { // Grab info on our current stack frame. Used to determine // whether we may be stepping outside of the current function. - fde, err := thread.Process.frameEntries.FDEForPC(curpc) + fde, err := thread.dbp.frameEntries.FDEForPC(curpc) if err != nil { return err } // Get current file/line. - f, l, _ := thread.Process.goSymTable.PCToLine(curpc) - if filepath.Ext(f) == ".go" { - if err = thread.next(curpc, fde, f, l); err != nil { + loc, err := thread.Location() + if err != nil { + return err + } + if filepath.Ext(loc.File) == ".go" { + if err = thread.next(curpc, fde, loc.File, loc.Line); err != nil { return err } } else { @@ -180,7 +200,7 @@ func (ge GoroutineExitingError) Error() string { // This version of next uses the AST from the current source file to figure out all of the potential source lines // we could end up at. func (thread *ThreadContext) next(curpc uint64, fde *frame.FrameDescriptionEntry, file string, line int) error { - lines, err := thread.Process.ast.NextLines(file, line) + lines, err := thread.dbp.ast.NextLines(file, line) if err != nil { if _, ok := err.(source.NoNodeError); !ok { return err @@ -194,7 +214,7 @@ func (thread *ThreadContext) next(curpc uint64, fde *frame.FrameDescriptionEntry pcs := make([]uint64, 0, len(lines)) for i := range lines { - pcs = append(pcs, thread.Process.lineInfo.AllPCsForFileLine(file, lines[i])...) + pcs = append(pcs, thread.dbp.lineInfo.AllPCsForFileLine(file, lines[i])...) } var covered bool @@ -206,7 +226,7 @@ func (thread *ThreadContext) next(curpc uint64, fde *frame.FrameDescriptionEntry } if !covered { - fn := thread.Process.goSymTable.PCToFunc(ret) + fn := thread.dbp.goSymTable.PCToFunc(ret) if fn != nil && fn.Name == "runtime.goexit" { g, err := thread.curG() if err != nil { @@ -223,7 +243,7 @@ func (thread *ThreadContext) next(curpc uint64, fde *frame.FrameDescriptionEntry // the benefit of an AST we can't be sure we're not at a branching statement and thus // cannot accurately predict where we may end up. func (thread *ThreadContext) cnext(curpc uint64, fde *frame.FrameDescriptionEntry) error { - pcs := thread.Process.lineInfo.AllPCsBetween(fde.Begin(), fde.End()) + pcs := thread.dbp.lineInfo.AllPCsBetween(fde.Begin(), fde.End()) ret, err := thread.ReturnAddress() if err != nil { return err @@ -237,7 +257,7 @@ func (thread *ThreadContext) setNextTempBreakpoints(curpc uint64, pcs []uint64) if pcs[i] == curpc || pcs[i] == curpc-1 { continue } - if _, err := thread.Process.TempBreak(pcs[i]); err != nil { + if _, err := thread.dbp.TempBreak(pcs[i]); err != nil { if err, ok := err.(BreakPointExistsError); !ok { return err } @@ -262,7 +282,7 @@ func (thread *ThreadContext) curG() (*G, error) { if err != nil { return err } - g, err = parseG(thread, regs.SP()+uint64(thread.Process.arch.PtrSize())) + g, err = parseG(thread, regs.SP()+uint64(thread.dbp.arch.PtrSize())) return err }) return g, err diff --git a/proctl/threads_darwin.go b/proctl/threads_darwin.go index 00b656f0..f6aee81b 100644 --- a/proctl/threads_darwin.go +++ b/proctl/threads_darwin.go @@ -26,7 +26,7 @@ func (t *ThreadContext) singleStep() error { if kret != C.KERN_SUCCESS { return fmt.Errorf("could not single step") } - t.Process.trapWait(0) + t.dbp.trapWait(0) kret = C.clear_trap_flag(t.os.thread_act) if kret != C.KERN_SUCCESS { return fmt.Errorf("could not clear CPU trap flag") @@ -36,7 +36,7 @@ func (t *ThreadContext) singleStep() error { func (t *ThreadContext) resume() error { // TODO(dp) set flag for ptrace stops - if PtraceCont(t.Process.Pid, 0) == nil { + if PtraceCont(t.dbp.Pid, 0) == nil { return nil } kret := C.resume_thread(t.os.thread_act) @@ -49,7 +49,7 @@ func (t *ThreadContext) resume() error { func (t *ThreadContext) blocked() bool { // TODO(dp) cache the func pc to remove this lookup pc, _ := t.PC() - fn := t.Process.goSymTable.PCToFunc(pc) + fn := t.dbp.goSymTable.PCToFunc(pc) if fn != nil && (fn.Name == "runtime.mach_semaphore_wait" || fn.Name == "runtime.usleep") { return true } @@ -63,7 +63,7 @@ func writeMemory(thread *ThreadContext, addr uintptr, data []byte) (int, error) length = C.mach_msg_type_number_t(len(data)) ) - if ret := C.write_memory(thread.Process.os.task, vm_addr, vm_data, length); ret < 0 { + if ret := C.write_memory(thread.dbp.os.task, vm_addr, vm_data, length); ret < 0 { return 0, fmt.Errorf("could not write memory") } return len(data), nil @@ -76,7 +76,7 @@ func readMemory(thread *ThreadContext, addr uintptr, data []byte) (int, error) { length = C.mach_msg_type_number_t(len(data)) ) - ret := C.read_memory(thread.Process.os.task, vm_addr, vm_data, length) + ret := C.read_memory(thread.dbp.os.task, vm_addr, vm_data, length) if ret < 0 { return 0, fmt.Errorf("could not read memory") } diff --git a/proctl/threads_linux.go b/proctl/threads_linux.go index eca030d6..f7e5dca7 100644 --- a/proctl/threads_linux.go +++ b/proctl/threads_linux.go @@ -16,7 +16,7 @@ func (t *ThreadContext) Halt() error { if stopped(t.Id) { return nil } - err := sys.Tgkill(t.Process.Pid, t.Id, sys.SIGSTOP) + err := sys.Tgkill(t.dbp.Pid, t.Id, sys.SIGSTOP) if err != nil { return fmt.Errorf("Halt err %s %d", err, t.Id) } @@ -43,7 +43,7 @@ func (t *ThreadContext) singleStep() error { func (t *ThreadContext) blocked() bool { // TODO(dp) cache the func pc to remove this lookup pc, _ := t.PC() - fn := t.Process.goSymTable.PCToFunc(pc) + fn := t.dbp.goSymTable.PCToFunc(pc) if fn != nil && ((fn.Name == "runtime.futex") || (fn.Name == "runtime.usleep") || (fn.Name == "runtime.clone")) { return true } diff --git a/proctl/variables.go b/proctl/variables.go index a0892637..93e2c166 100644 --- a/proctl/variables.go +++ b/proctl/variables.go @@ -80,7 +80,7 @@ func (ng NoGError) Error() string { } func parseG(thread *ThreadContext, addr uint64) (*G, error) { - gaddrbytes, err := thread.readMemory(uintptr(addr), thread.Process.arch.PtrSize()) + gaddrbytes, err := thread.readMemory(uintptr(addr), thread.dbp.arch.PtrSize()) if err != nil { return nil, fmt.Errorf("error derefing *G %s", err) } @@ -90,7 +90,7 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) { return nil, NoGError{tid: thread.Id} } - rdr := thread.Process.DwarfReader() + rdr := thread.dbp.DwarfReader() rdr.Seek(0) entry, err := rdr.SeekToTypeNamed("runtime.g") if err != nil { @@ -107,7 +107,7 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) { } var deferPC uint64 // Dereference *defer pointer - deferAddrBytes, err := thread.readMemory(uintptr(deferAddr), thread.Process.arch.PtrSize()) + deferAddrBytes, err := thread.readMemory(uintptr(deferAddr), thread.dbp.arch.PtrSize()) if err != nil { return nil, fmt.Errorf("error derefing *G %s", err) } @@ -141,7 +141,7 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) { if err != nil { return nil, err } - pc, err := thread.readUintRaw(uintptr(schedAddr+uint64(thread.Process.arch.PtrSize())), 8) + pc, err := thread.readUintRaw(uintptr(schedAddr+uint64(thread.dbp.arch.PtrSize())), 8) if err != nil { return nil, err } @@ -173,7 +173,7 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) { return nil, err } - f, l, fn := thread.Process.goSymTable.PCToLine(gopc) + f, l, fn := thread.dbp.goSymTable.PCToLine(gopc) g := &G{ Id: int(goid), GoPC: gopc, @@ -195,7 +195,7 @@ func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) { return nil, err } - reader := thread.Process.DwarfReader() + reader := thread.dbp.DwarfReader() _, err = reader.SeekToFunction(pc) if err != nil { @@ -243,7 +243,7 @@ func (thread *ThreadContext) FunctionArguments() ([]*Variable, error) { // PackageVariables returns the name, value, and type of all package variables in the application. func (thread *ThreadContext) PackageVariables() ([]*Variable, error) { - reader := thread.Process.DwarfReader() + reader := thread.dbp.DwarfReader() vars := make([]*Variable, 0) @@ -308,7 +308,7 @@ func (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, rdr return nil, fmt.Errorf("type assertion failed") } - data := thread.Process.dwarf + data := thread.dbp.dwarf t, err := data.Type(offset) if err != nil { return nil, err @@ -349,7 +349,7 @@ func (thread *ThreadContext) extractVariableFromEntry(entry *dwarf.Entry) (*Vari return nil, fmt.Errorf("type assertion failed") } - data := thread.Process.dwarf + data := thread.dbp.dwarf t, err := data.Type(offset) if err != nil { return nil, err @@ -375,7 +375,7 @@ func (thread *ThreadContext) executeStackProgram(instructions []byte) (int64, er return 0, err } - fde, err := thread.Process.frameEntries.FDEForPC(regs.PC()) + fde, err := thread.dbp.frameEntries.FDEForPC(regs.PC()) if err != nil { return 0, err } @@ -413,7 +413,7 @@ func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, rdr ptraddress := uintptr(address) - ptr, err := thread.readMemory(ptraddress, thread.Process.arch.PtrSize()) + ptr, err := thread.readMemory(ptraddress, thread.dbp.arch.PtrSize()) if err != nil { return 0, err } @@ -453,7 +453,7 @@ func (thread *ThreadContext) extractValueInternal(instructions []byte, addr int6 ptraddress := uintptr(addr) switch t := typ.(type) { case *dwarf.PtrType: - ptr, err := thread.readMemory(ptraddress, thread.Process.arch.PtrSize()) + ptr, err := thread.readMemory(ptraddress, thread.dbp.arch.PtrSize()) if err != nil { return "", err } @@ -528,14 +528,14 @@ func (thread *ThreadContext) readString(addr uintptr) (string, error) { // http://research.swtch.com/godata // read len - val, err := thread.readMemory(addr+uintptr(thread.Process.arch.PtrSize()), thread.Process.arch.PtrSize()) + val, err := thread.readMemory(addr+uintptr(thread.dbp.arch.PtrSize()), thread.dbp.arch.PtrSize()) if err != nil { return "", err } strlen := int(binary.LittleEndian.Uint64(val)) // read addr - val, err = thread.readMemory(addr, thread.Process.arch.PtrSize()) + val, err = thread.readMemory(addr, thread.dbp.arch.PtrSize()) if err != nil { return "", err } @@ -559,7 +559,7 @@ func (thread *ThreadContext) readSlice(addr uintptr, t *dwarf.StructType) (strin for _, f := range t.Field { switch f.Name { case "array": - val, err := thread.readMemory(addr+uintptr(f.ByteOffset), thread.Process.arch.PtrSize()) + val, err := thread.readMemory(addr+uintptr(f.ByteOffset), thread.dbp.arch.PtrSize()) if err != nil { return "", err } @@ -593,7 +593,7 @@ func (thread *ThreadContext) readSlice(addr uintptr, t *dwarf.StructType) (strin stride := arrayType.Size() if _, ok := arrayType.(*dwarf.PtrType); ok { - stride = int64(thread.Process.arch.PtrSize()) + stride = int64(thread.dbp.arch.PtrSize()) } vals, err := thread.readArrayValues(arrayAddr, sliceLen, stride, arrayType) if err != nil { @@ -729,7 +729,7 @@ func (thread *ThreadContext) readBool(addr uintptr) (string, error) { } func (thread *ThreadContext) readFunctionPtr(addr uintptr) (string, error) { - val, err := thread.readMemory(addr, thread.Process.arch.PtrSize()) + val, err := thread.readMemory(addr, thread.dbp.arch.PtrSize()) if err != nil { return "", err } @@ -740,13 +740,13 @@ func (thread *ThreadContext) readFunctionPtr(addr uintptr) (string, error) { return "nil", nil } - val, err = thread.readMemory(addr, thread.Process.arch.PtrSize()) + val, err = thread.readMemory(addr, thread.dbp.arch.PtrSize()) if err != nil { return "", err } funcAddr := binary.LittleEndian.Uint64(val) - fn := thread.Process.goSymTable.PCToFunc(uint64(funcAddr)) + fn := thread.dbp.goSymTable.PCToFunc(uint64(funcAddr)) if fn == nil { return "", fmt.Errorf("could not find function for %#v", funcAddr) } @@ -774,7 +774,7 @@ func (thread *ThreadContext) variablesByTag(tag dwarf.Tag) ([]*Variable, error) return nil, err } - reader := thread.Process.DwarfReader() + reader := thread.dbp.DwarfReader() _, err = reader.SeekToFunction(pc) if err != nil { diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index e3686d56..b70966f4 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -474,20 +474,24 @@ func convertBreakPoint(bp *proctl.BreakPoint) *api.BreakPoint { // convertThread converts an internal thread to an API Thread. func convertThread(th *proctl.ThreadContext) *api.Thread { - var function *api.Function - file, line := "", 0 + var ( + function *api.Function + file string + line int + pc uint64 + ) - pc, err := th.PC() + loc, err := th.Location() if err == nil { - f, l, fn := th.Process.PCToLine(pc) - file = f - line = l - if fn != nil { + pc = loc.PC + file = loc.File + line = loc.Line + if loc.Fn != nil { function = &api.Function{ - Name: fn.Name, - Type: fn.Type, - Value: fn.Value, - GoType: fn.GoType, + Name: loc.Fn.Name, + Type: loc.Fn.Type, + Value: loc.Fn.Value, + GoType: loc.Fn.GoType, } } }