Cleanup tracepoint commit
* Cleanup comments * Cleanup naming in certain instances * Modify stacktrace to return current location
This commit is contained in:
parent
3a96d8eed7
commit
6b99c5f519
@ -18,14 +18,16 @@ type Breakpoint struct {
|
||||
OriginalData []byte // If software breakpoint, the data we replace with breakpoint instruction.
|
||||
ID int // Monotonically increasing ID.
|
||||
Temp bool // Whether this is a temp breakpoint (for next'ing).
|
||||
hardware bool // Breakpoint using CPU debug registers.
|
||||
reg int // If hardware breakpoint, what debug register it belongs to.
|
||||
|
||||
// Breakpoint informations
|
||||
Tracepoint bool // tracepoint flag
|
||||
Stacktrace int // number of stack frames to retrieve
|
||||
Goroutine bool // retrieve goroutine information
|
||||
Symbols []string // variables to evaluate
|
||||
// Breakpoint information
|
||||
Tracepoint bool // Tracepoint flag
|
||||
Stacktrace int // Number of stack frames to retrieve
|
||||
Goroutine bool // Retrieve goroutine information
|
||||
Variables []string // Variables to evaluate
|
||||
|
||||
hardware bool // Breakpoint using CPU debug registers.
|
||||
reg int // If hardware breakpoint, what debug register it belongs to.
|
||||
|
||||
}
|
||||
|
||||
func (bp *Breakpoint) String() string {
|
||||
|
@ -443,8 +443,8 @@ func (l1 *loc) match(l2 Location) bool {
|
||||
|
||||
func TestStacktrace(t *testing.T) {
|
||||
stacks := [][]loc{
|
||||
[]loc{{8, "main.func1"}, {16, "main.main"}},
|
||||
[]loc{{8, "main.func1"}, {12, "main.func2"}, {17, "main.main"}},
|
||||
[]loc{{3, "main.stacktraceme"}, {8, "main.func1"}, {16, "main.main"}},
|
||||
[]loc{{3, "main.stacktraceme"}, {8, "main.func1"}, {12, "main.func2"}, {17, "main.main"}},
|
||||
}
|
||||
withTestProcess("stacktraceprog", t, func(p *Process, fixture protest.Fixture) {
|
||||
bp, err := p.SetBreakpointByLocation("main.stacktraceme")
|
||||
@ -452,7 +452,7 @@ func TestStacktrace(t *testing.T) {
|
||||
|
||||
for i := range stacks {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
_, locations, err := p.CurrentThread.Stacktrace(40)
|
||||
locations, err := p.CurrentThread.Stacktrace(40)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
|
||||
if len(locations) != len(stacks[i])+2 {
|
||||
@ -484,8 +484,8 @@ func stackMatch(stack []loc, locations []Location) bool {
|
||||
}
|
||||
|
||||
func TestStacktraceGoroutine(t *testing.T) {
|
||||
mainStack := []loc{{21, "main.main"}}
|
||||
agoroutineStack := []loc{{-1, "runtime.goparkunlock"}, {-1, "runtime.chansend"}, {-1, "runtime.chansend1"}, {8, "main.agoroutine"}}
|
||||
mainStack := []loc{{11, "main.stacktraceme"}, {21, "main.main"}}
|
||||
agoroutineStack := []loc{{-1, "runtime.gopark"}, {-1, "runtime.goparkunlock"}, {-1, "runtime.chansend"}, {-1, "runtime.chansend1"}, {8, "main.agoroutine"}}
|
||||
|
||||
withTestProcess("goroutinestackprog", t, func(p *Process, fixture protest.Fixture) {
|
||||
bp, err := p.SetBreakpointByLocation("main.stacktraceme")
|
||||
@ -499,8 +499,8 @@ func TestStacktraceGoroutine(t *testing.T) {
|
||||
agoroutineCount := 0
|
||||
mainCount := 0
|
||||
|
||||
for _, g := range gs {
|
||||
_, locations, _ := p.GoroutineStacktrace(g, 40)
|
||||
for i, g := range gs {
|
||||
locations, err := p.GoroutineStacktrace(g, 40)
|
||||
assertNoError(err, t, "GoroutineStacktrace()")
|
||||
|
||||
if stackMatch(mainStack, locations) {
|
||||
@ -510,7 +510,7 @@ func TestStacktraceGoroutine(t *testing.T) {
|
||||
if stackMatch(agoroutineStack, locations) {
|
||||
agoroutineCount++
|
||||
} else {
|
||||
t.Logf("Non-goroutine stack: (%d)", len(locations))
|
||||
t.Logf("Non-goroutine stack: %d (%d)", i, len(locations))
|
||||
for i := range locations {
|
||||
name := ""
|
||||
if locations[i].Fn != nil {
|
||||
|
@ -7,39 +7,31 @@ import (
|
||||
// Takes an offset from RSP and returns the address of the
|
||||
// instruction the currect function is going to return to.
|
||||
func (thread *Thread) ReturnAddress() (uint64, error) {
|
||||
_, locations, err := thread.Stacktrace(1)
|
||||
locations, err := thread.Stacktrace(2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return locations[0].PC, nil
|
||||
return locations[1].PC, nil
|
||||
}
|
||||
|
||||
// Returns the stack trace for thread
|
||||
// Note that it doesn't include the current frame and the locations in the array are return addresses not call addresses
|
||||
func (thread *Thread) Stacktrace(depth int) (*Location, []Location, error) {
|
||||
loc, err := thread.Location()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Returns the stack trace for thread.
|
||||
// Note the locations in the array are return addresses not call addresses.
|
||||
func (thread *Thread) Stacktrace(depth int) ([]Location, error) {
|
||||
regs, err := thread.Registers()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
locations, err := thread.dbp.stacktrace(regs.PC(), regs.SP(), depth)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return loc, locations, nil
|
||||
return thread.dbp.stacktrace(regs.PC(), regs.SP(), depth)
|
||||
}
|
||||
|
||||
// Returns the stack trace for a goroutine
|
||||
// Note that it doesn't include the current frame and the locations in the array are return addresses not call addresses
|
||||
func (dbp *Process) GoroutineStacktrace(g *G, depth int) (*Location, []Location, error) {
|
||||
// Returns the stack trace for a goroutine.
|
||||
// Note the locations in the array are return addresses not call addresses.
|
||||
func (dbp *Process) GoroutineStacktrace(g *G, depth int) ([]Location, error) {
|
||||
if g.thread != nil {
|
||||
return g.thread.Stacktrace(depth)
|
||||
}
|
||||
locs, err := dbp.stacktrace(g.PC, g.SP, depth)
|
||||
return dbp.GoroutineLocation(g), locs, err
|
||||
return locs, err
|
||||
}
|
||||
|
||||
func (dbp *Process) GoroutineLocation(g *G) *Location {
|
||||
@ -61,6 +53,8 @@ func (dbp *Process) stacktrace(pc, sp uint64, depth int) ([]Location, error) {
|
||||
locations []Location
|
||||
retaddr uintptr
|
||||
)
|
||||
f, l, fn := dbp.PCToLine(pc)
|
||||
locations = append(locations, Location{PC: pc, File: f, Line: l, Fn: fn})
|
||||
for i := int64(0); i < int64(depth); i++ {
|
||||
fde, err := dbp.frameEntries.FDEForPC(ret)
|
||||
if err != nil {
|
||||
@ -79,7 +73,7 @@ func (dbp *Process) stacktrace(pc, sp uint64, depth int) ([]Location, error) {
|
||||
if ret <= 0 {
|
||||
break
|
||||
}
|
||||
f, l, fn := dbp.goSymTable.PCToLine(ret)
|
||||
f, l, fn = dbp.goSymTable.PCToLine(ret)
|
||||
locations = append(locations, Location{PC: ret, File: f, Line: l, Fn: fn})
|
||||
if fn != nil && fn.Name == "runtime.goexit" {
|
||||
break
|
||||
|
@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"debug/gosym"
|
||||
|
||||
"github.com/derekparker/delve/proc"
|
||||
)
|
||||
|
||||
@ -16,7 +17,7 @@ func ConvertBreakpoint(bp *proc.Breakpoint) *Breakpoint {
|
||||
Tracepoint: bp.Tracepoint,
|
||||
Stacktrace: bp.Stacktrace,
|
||||
Goroutine: bp.Goroutine,
|
||||
Symbols: bp.Symbols,
|
||||
Variables: bp.Variables,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ type Breakpoint struct {
|
||||
// retrieve goroutine information
|
||||
Goroutine bool `json:"goroutine"`
|
||||
// variables to evaluate
|
||||
Symbols []string `json:"symbols,omitempty"`
|
||||
Variables []string `json:"variables,omitempty"`
|
||||
}
|
||||
|
||||
// Thread is a thread within the debugged process.
|
||||
|
@ -108,7 +108,7 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoin
|
||||
bp.Tracepoint = requestedBp.Tracepoint
|
||||
bp.Goroutine = requestedBp.Goroutine
|
||||
bp.Stacktrace = requestedBp.Stacktrace
|
||||
bp.Symbols = requestedBp.Symbols
|
||||
bp.Variables = requestedBp.Variables
|
||||
createdBp = api.ConvertBreakpoint(bp)
|
||||
log.Printf("created breakpoint: %#v", createdBp)
|
||||
return createdBp, nil
|
||||
@ -178,7 +178,7 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
|
||||
|
||||
state, err := d.State()
|
||||
if err != nil {
|
||||
return state, err
|
||||
return nil, err
|
||||
}
|
||||
err = d.collectBreakpointInformation(state)
|
||||
return state, err
|
||||
@ -222,18 +222,18 @@ func (d *Debugger) collectBreakpointInformation(state *api.DebuggerState) error
|
||||
}
|
||||
|
||||
if bp.Stacktrace > 0 {
|
||||
rawloc, rawlocs, err := d.process.CurrentThread.Stacktrace(bp.Stacktrace)
|
||||
rawlocs, err := d.process.CurrentThread.Stacktrace(bp.Stacktrace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bpi.Stacktrace = convertStacktrace(rawloc, rawlocs)
|
||||
bpi.Stacktrace = convertStacktrace(rawlocs)
|
||||
}
|
||||
|
||||
if len(bp.Symbols) > 0 {
|
||||
bpi.Variables = make([]api.Variable, len(bp.Symbols))
|
||||
if len(bp.Variables) > 0 {
|
||||
bpi.Variables = make([]api.Variable, len(bp.Variables))
|
||||
}
|
||||
for i := range bp.Symbols {
|
||||
v, err := d.process.CurrentThread.EvalVariable(bp.Symbols[i])
|
||||
for i := range bp.Variables {
|
||||
v, err := d.process.CurrentThread.EvalVariable(bp.Variables[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -367,11 +367,10 @@ func (d *Debugger) Goroutines() ([]*api.Goroutine, error) {
|
||||
|
||||
func (d *Debugger) Stacktrace(goroutineId, depth int) ([]api.Location, error) {
|
||||
var rawlocs []proc.Location
|
||||
var rawloc *proc.Location
|
||||
var err error
|
||||
|
||||
if goroutineId < 0 {
|
||||
rawloc, rawlocs, err = d.process.CurrentThread.Stacktrace(depth)
|
||||
rawlocs, err = d.process.CurrentThread.Stacktrace(depth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -382,7 +381,7 @@ func (d *Debugger) Stacktrace(goroutineId, depth int) ([]api.Location, error) {
|
||||
}
|
||||
for _, g := range gs {
|
||||
if g.Id == goroutineId {
|
||||
rawloc, rawlocs, err = d.process.GoroutineStacktrace(g, depth)
|
||||
rawlocs, err = d.process.GoroutineStacktrace(g, depth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -395,13 +394,11 @@ func (d *Debugger) Stacktrace(goroutineId, depth int) ([]api.Location, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return convertStacktrace(rawloc, rawlocs), nil
|
||||
return convertStacktrace(rawlocs), nil
|
||||
}
|
||||
|
||||
func convertStacktrace(rawloc *proc.Location, rawlocs []proc.Location) []api.Location {
|
||||
locations := make([]api.Location, 0, len(rawlocs)+1)
|
||||
|
||||
locations = append(locations, api.ConvertLocation(*rawloc))
|
||||
func convertStacktrace(rawlocs []proc.Location) []api.Location {
|
||||
locations := make([]api.Location, 0, len(rawlocs))
|
||||
for i := range rawlocs {
|
||||
rawlocs[i].Line--
|
||||
locations = append(locations, api.ConvertLocation(rawlocs[i]))
|
||||
|
@ -96,8 +96,7 @@ func TestClientServer_step(t *testing.T) {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
statech := c.Continue()
|
||||
stateBefore := <-statech
|
||||
stateBefore := <-c.Continue()
|
||||
if stateBefore.Err != nil {
|
||||
t.Fatalf("Unexpected error: %v", stateBefore.Err)
|
||||
}
|
||||
@ -375,13 +374,13 @@ func TestClientServer_infoArgs(t *testing.T) {
|
||||
func TestClientServer_traceContinue(t *testing.T) {
|
||||
withTestClient("integrationprog", t, func(c service.Client) {
|
||||
fp := testProgPath(t, "integrationprog")
|
||||
_, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 15, Tracepoint: true, Goroutine: true, Stacktrace: 5, Symbols: []string{"i"}})
|
||||
_, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 15, Tracepoint: true, Goroutine: true, Stacktrace: 5, Variables: []string{"i"}})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v\n", err)
|
||||
}
|
||||
count := 0
|
||||
contch := c.Continue()
|
||||
for state := range contch {
|
||||
contChan := c.Continue()
|
||||
for state := range contChan {
|
||||
if state.Breakpoint != nil {
|
||||
count++
|
||||
|
||||
|
@ -47,7 +47,7 @@ func DebugCommands(client service.Client) *Commands {
|
||||
c.cmds = []command{
|
||||
{aliases: []string{"help"}, cmdFn: c.help, helpMsg: "Prints the help message."},
|
||||
{aliases: []string{"break", "b"}, cmdFn: breakpoint, helpMsg: "break <address> [-stack <n>|-goroutine|<variable name>]*\nSet break point at the entry point of a function, or at a specific file/line.\nWhen the breakpoint is reached the value of the specified variables will be printed, if -stack is specified the stack trace of the current goroutine will be printed, if -goroutine is specified informations about the current goroutine will be printed. Example: break foo.go:13"},
|
||||
{aliases: []string{"trace"}, cmdFn: tracepoint, helpMsg: "Set tracepoint, takes the same arguments as break"},
|
||||
{aliases: []string{"trace", "t"}, cmdFn: tracepoint, helpMsg: "Set tracepoint, takes the same arguments as break"},
|
||||
{aliases: []string{"continue", "c"}, cmdFn: cont, helpMsg: "Run until breakpoint or program termination."},
|
||||
{aliases: []string{"step", "si"}, cmdFn: step, helpMsg: "Single step through program."},
|
||||
{aliases: []string{"next", "n"}, cmdFn: next, helpMsg: "Step over to next source line."},
|
||||
@ -201,8 +201,8 @@ func formatGoroutine(g *api.Goroutine) string {
|
||||
}
|
||||
|
||||
func cont(client service.Client, args ...string) error {
|
||||
statech := client.Continue()
|
||||
for state := range statech {
|
||||
stateChan := client.Continue()
|
||||
for state := range stateChan {
|
||||
if state.Err != nil {
|
||||
return state.Err
|
||||
}
|
||||
@ -289,8 +289,8 @@ func breakpoints(client service.Client, args ...string) error {
|
||||
if bp.Goroutine {
|
||||
attrs = append(attrs, "-goroutine")
|
||||
}
|
||||
for i := range bp.Symbols {
|
||||
attrs = append(attrs, bp.Symbols[i])
|
||||
for i := range bp.Variables {
|
||||
attrs = append(attrs, bp.Variables[i])
|
||||
}
|
||||
|
||||
if len(attrs) > 0 {
|
||||
@ -301,7 +301,7 @@ func breakpoints(client service.Client, args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func breakpointIntl(client service.Client, tracepoint bool, args ...string) error {
|
||||
func setBreakpoint(client service.Client, tracepoint bool, args ...string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("address required, specify either a function name or <file:line>")
|
||||
}
|
||||
@ -335,7 +335,7 @@ func breakpointIntl(client service.Client, tracepoint bool, args ...string) erro
|
||||
case "-goroutine":
|
||||
requestedBp.Goroutine = true
|
||||
default:
|
||||
requestedBp.Symbols = append(requestedBp.Symbols, args[i])
|
||||
requestedBp.Variables = append(requestedBp.Variables, args[i])
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,11 +356,11 @@ func breakpointIntl(client service.Client, tracepoint bool, args ...string) erro
|
||||
}
|
||||
|
||||
func breakpoint(client service.Client, args ...string) error {
|
||||
return breakpointIntl(client, false, args...)
|
||||
return setBreakpoint(client, false, args...)
|
||||
}
|
||||
|
||||
func tracepoint(client service.Client, args ...string) error {
|
||||
return breakpointIntl(client, true, args...)
|
||||
return setBreakpoint(client, true, args...)
|
||||
}
|
||||
|
||||
func printVar(client service.Client, args ...string) error {
|
||||
|
Loading…
Reference in New Issue
Block a user