提交 708cf2f2 编写于 作者: A aarzilli

service,terminal: propagating simultaneous breakpoints

上级 a9e2696f
......@@ -193,18 +193,23 @@ starts and attaches to it, and enables you to immediately begin debugging your p
fmt.Fprintln(os.Stderr, state.Err)
return 0
}
var args []string
var fname string
if state.CurrentThread != nil && state.CurrentThread.Function != nil {
fname = state.CurrentThread.Function.Name
}
if state.BreakpointInfo != nil {
for _, arg := range state.BreakpointInfo.Arguments {
args = append(args, arg.SinglelineString())
for i := range state.Threads {
th := state.Threads[i]
if th.Breakpoint == nil {
continue
}
var args []string
var fname string
if th.Function != nil {
fname = th.Function.Name
}
if th.BreakpointInfo != nil {
for _, arg := range th.BreakpointInfo.Arguments {
args = append(args, arg.SinglelineString())
}
}
fmt.Printf("%s(%s) %s:%d\n", fname, strings.Join(args, ", "), terminal.ShortenFilePath(th.File), th.Line)
}
fp := terminal.ShortenFilePath(state.CurrentThread.File)
fmt.Printf("%s(%s) %s:%d\n", fname, strings.Join(args, ", "), fp, state.CurrentThread.Line)
case <-sigChan:
server.Stop(traceAttachPid == 0)
return 1
......
......@@ -37,6 +37,7 @@ func ConvertThread(th *proc.Thread) *Thread {
file string
line int
pc uint64
gid int
)
loc, err := th.Location()
......@@ -47,12 +48,24 @@ func ConvertThread(th *proc.Thread) *Thread {
function = ConvertFunction(loc.Fn)
}
var bp *Breakpoint
if th.CurrentBreakpoint != nil {
bp = ConvertBreakpoint(th.CurrentBreakpoint)
}
if g, _ := th.GetG(); g != nil {
gid = g.Id
}
return &Thread{
ID: th.Id,
PC: pc,
File: file,
Line: line,
Function: function,
ID: th.Id,
PC: pc,
File: file,
Line: line,
Function: function,
GoroutineID: gid,
Breakpoint: bp,
}
}
......
......@@ -4,19 +4,15 @@ import "reflect"
// DebuggerState represents the current context of the debugger.
type DebuggerState struct {
// Breakpoint is the current breakpoint at which the debugged process is
// suspended, and may be empty if the process is not suspended.
Breakpoint *Breakpoint `json:"breakPoint,omitempty"`
// CurrentThread is the currently selected debugger thread.
CurrentThread *Thread `json:"currentThread,omitempty"`
// SelectedGoroutine is the currently selected goroutine
SelectedGoroutine *Goroutine `json:"currentGoroutine,omitempty"`
// Information requested by the current breakpoint
BreakpointInfo *BreakpointInfo `json:"breakPointInfo,omitrempty"`
// List of all the process threads
Threads []*Thread
// Exited indicates whether the debugged process has exited.
Exited bool `json:"exited"`
ExitStatus int `json:"exitStatus"`
// Filled by RPCClient.Continue, indicates an error
Err error `json:"-"`
}
......@@ -62,6 +58,14 @@ type Thread struct {
Line int `json:"line"`
// Function is function information at the program counter. May be nil.
Function *Function `json:"function,omitempty"`
// ID of the goroutine running on this thread
GoroutineID int `json:"goroutineID"`
// Breakpoint this thread is stopped at
Breakpoint *Breakpoint `json:"breakPoint,omitempty"`
// Informations requested by the current breakpoint
BreakpointInfo *BreakpointInfo `json:"breakPointInfo,omitrempty"`
}
type Location struct {
......
......@@ -111,31 +111,26 @@ func (d *Debugger) State() (*api.DebuggerState, error) {
var (
state *api.DebuggerState
thread *api.Thread
goroutine *api.Goroutine
)
if d.process.CurrentThread != nil {
thread = api.ConvertThread(d.process.CurrentThread)
}
if d.process.SelectedGoroutine != nil {
goroutine = api.ConvertGoroutine(d.process.SelectedGoroutine)
}
var breakpoint *api.Breakpoint
bp := d.process.CurrentBreakpoint()
if bp != nil {
breakpoint = api.ConvertBreakpoint(bp)
}
state = &api.DebuggerState{
Breakpoint: breakpoint,
CurrentThread: thread,
SelectedGoroutine: goroutine,
Exited: d.process.Exited(),
}
for i := range d.process.Threads {
th := api.ConvertThread(d.process.Threads[i])
state.Threads = append(state.Threads, th)
if i == d.process.CurrentThread.Id {
state.CurrentThread = th
}
}
return state, nil
}
......@@ -272,52 +267,59 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
}
func (d *Debugger) collectBreakpointInformation(state *api.DebuggerState) error {
if state == nil || state.Breakpoint == nil {
if state == nil {
return nil
}
bp := state.Breakpoint
bpi := &api.BreakpointInfo{}
state.BreakpointInfo = bpi
for i := range state.Threads {
if state.Threads[i].Breakpoint == nil {
continue
}
bp := state.Threads[i].Breakpoint
bpi := &api.BreakpointInfo{}
state.Threads[i].BreakpointInfo = bpi
if bp.Goroutine {
g, err := d.process.CurrentThread.GetG()
if err != nil {
return err
if bp.Goroutine {
g, err := d.process.CurrentThread.GetG()
if err != nil {
return err
}
bpi.Goroutine = api.ConvertGoroutine(g)
}
bpi.Goroutine = api.ConvertGoroutine(g)
}
if bp.Stacktrace > 0 {
rawlocs, err := d.process.CurrentThread.Stacktrace(bp.Stacktrace)
if err != nil {
return err
if bp.Stacktrace > 0 {
rawlocs, err := d.process.CurrentThread.Stacktrace(bp.Stacktrace)
if err != nil {
return err
}
bpi.Stacktrace, err = d.convertStacktrace(rawlocs, false)
if err != nil {
return err
}
}
bpi.Stacktrace, err = d.convertStacktrace(rawlocs, false)
s, err := d.process.CurrentThread.Scope()
if err != nil {
return err
}
}
s, err := d.process.CurrentThread.Scope()
if err != nil {
return err
}
if len(bp.Variables) > 0 {
bpi.Variables = make([]api.Variable, len(bp.Variables))
}
for i := range bp.Variables {
v, err := s.EvalVariable(bp.Variables[i])
if err != nil {
return err
if len(bp.Variables) > 0 {
bpi.Variables = make([]api.Variable, len(bp.Variables))
}
for i := range bp.Variables {
v, err := s.EvalVariable(bp.Variables[i])
if err != nil {
return err
}
bpi.Variables[i] = *api.ConvertVar(v)
}
vars, err := s.FunctionArguments()
if err == nil {
bpi.Arguments = convertVars(vars)
}
bpi.Variables[i] = *api.ConvertVar(v)
}
args, err := s.FunctionArguments()
if err == nil {
bpi.Arguments = convertVars(args)
}
return nil
}
......
......@@ -66,7 +66,21 @@ func (c *RPCClient) Continue() <-chan *api.DebuggerState {
state.Err = fmt.Errorf("Process %d has exited with status %d", c.ProcessPid(), state.ExitStatus)
}
ch <- state
if err != nil || state.Exited || state.Breakpoint == nil || !state.Breakpoint.Tracepoint {
if err != nil || state.Exited {
close(ch)
return
}
isbreakpoint := false
istracepoint := true
for i := range state.Threads {
if state.Threads[i].Breakpoint != nil {
isbreakpoint = true
istracepoint = istracepoint && state.Threads[i].Breakpoint.Tracepoint
}
}
if !isbreakpoint || !istracepoint {
close(ch)
return
}
......
......@@ -96,7 +96,7 @@ func TestRestart_duringStop(t *testing.T) {
t.Fatal(err)
}
state := <-c.Continue()
if state.Breakpoint == nil {
if state.CurrentThread.Breakpoint == nil {
t.Fatal("did not hit breakpoint")
}
if err := c.Restart(); err != nil {
......@@ -433,12 +433,12 @@ func TestClientServer_traceContinue(t *testing.T) {
count := 0
contChan := c.Continue()
for state := range contChan {
if state.Breakpoint != nil {
if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil {
count++
t.Logf("%v", state)
bpi := state.BreakpointInfo
bpi := state.CurrentThread.BreakpointInfo
if bpi.Goroutine == nil {
t.Fatalf("No goroutine information")
......@@ -494,8 +494,8 @@ func TestClientServer_traceContinue2(t *testing.T) {
countSayhi := 0
contChan := c.Continue()
for state := range contChan {
if state.Breakpoint != nil {
switch state.Breakpoint.ID {
if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil {
switch state.CurrentThread.Breakpoint.ID {
case bp1.ID:
countMain++
case bp2.ID:
......
......@@ -837,6 +837,15 @@ func printStack(stack []api.Stackframe, ind string) {
}
func printcontext(t *Term, state *api.DebuggerState) error {
for i := range state.Threads {
if (state.CurrentThread != nil) && (state.Threads[i].ID == state.CurrentThread.ID) {
continue
}
if state.Threads[i].Breakpoint != nil {
printcontextThread(t, state.Threads[i])
}
}
if state.CurrentThread == nil {
fmt.Println("No current thread available")
return nil
......@@ -846,64 +855,70 @@ func printcontext(t *Term, state *api.DebuggerState) error {
t.Println("=>", "no source available")
return nil
}
var fn *api.Function
if state.CurrentThread.Function != nil {
fn = state.CurrentThread.Function
printcontextThread(t, state.CurrentThread)
if state.CurrentThread.Breakpoint == nil || !state.CurrentThread.Breakpoint.Tracepoint {
return printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
}
return nil
}
if state.Breakpoint != nil {
args := ""
if state.Breakpoint.Tracepoint {
var arg []string
for _, ar := range state.CurrentThread.Function.Args {
arg = append(arg, ar.SinglelineString())
}
args = strings.Join(arg, ", ")
}
if hitCount, ok := state.Breakpoint.HitCount[strconv.Itoa(state.SelectedGoroutine.ID)]; ok {
fmt.Printf("> %s(%s) %s:%d (hits goroutine(%d):%d total:%d)\n",
fn.Name,
args,
ShortenFilePath(state.CurrentThread.File),
state.CurrentThread.Line,
state.SelectedGoroutine.ID,
hitCount,
state.Breakpoint.TotalHitCount)
} else {
fmt.Printf("> %s(%s) %s:%d (hits total:%d)\n",
fn.Name,
args,
ShortenFilePath(state.CurrentThread.File),
state.CurrentThread.Line,
state.Breakpoint.TotalHitCount)
func printcontextThread(t *Term, th *api.Thread) {
fn := th.Function
if th.Breakpoint == nil {
fmt.Printf("> %s() %s:%d\n", fn.Name, ShortenFilePath(th.File), th.Line)
return
}
args := ""
if th.Breakpoint.Tracepoint && fn != nil {
var arg []string
for _, ar := range fn.Args {
arg = append(arg, ar.SinglelineString())
}
args = strings.Join(arg, ", ")
}
if hitCount, ok := th.Breakpoint.HitCount[strconv.Itoa(th.GoroutineID)]; ok {
fmt.Printf("> %s(%s) %s:%d (hits goroutine(%d):%d total:%d)\n",
fn.Name,
args,
ShortenFilePath(th.File),
th.Line,
th.GoroutineID,
hitCount,
th.Breakpoint.TotalHitCount)
} else {
fmt.Printf("> %s() %s:%d\n", fn.Name, ShortenFilePath(state.CurrentThread.File), state.CurrentThread.Line)
fmt.Printf("> %s(%s) %s:%d (hits total:%d)\n",
fn.Name,
args,
ShortenFilePath(th.File),
th.Line,
th.Breakpoint.TotalHitCount)
}
if state.BreakpointInfo != nil {
bpi := state.BreakpointInfo
if th.BreakpointInfo != nil {
bpi := th.BreakpointInfo
if bpi.Goroutine != nil {
writeGoroutineLong(os.Stdout, bpi.Goroutine, "\t")
}
ss := make([]string, len(bpi.Variables))
for i, v := range bpi.Variables {
ss[i] = fmt.Sprintf("%s: %v", v.Name, v.MultilineString(""))
if len(bpi.Variables) > 0 {
ss := make([]string, len(bpi.Variables))
for i, v := range bpi.Variables {
ss[i] = fmt.Sprintf("%s: %s", v.Name, v.MultilineString(""))
}
fmt.Printf("\t%s\n", strings.Join(ss, ", "))
}
fmt.Printf("\t%s\n", strings.Join(ss, ", "))
if bpi.Stacktrace != nil {
fmt.Printf("\tStack:\n")
printStack(bpi.Stacktrace, "\t\t")
}
}
if state.Breakpoint != nil && state.Breakpoint.Tracepoint {
return nil
}
return printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
}
func printfile(t *Term, filename string, line int, showArrow bool) error {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册