proc,service,terminal: propagate g.startpc

Adds StartPC to proc.G, StartLoc to api.Goroutine and show the start
location in the command line client when appropriate.

Updates #1104
This commit is contained in:
aarzilli 2018-07-05 13:06:12 +02:00 committed by Derek Parker
parent bdcbd8a846
commit 2309f728c1
5 changed files with 25 additions and 4 deletions

@ -203,13 +203,14 @@ Called with more arguments it will execute a command on the specified goroutine.
## goroutines
List program goroutines.
goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location) ] [ -t (stack trace)]
goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location)|-s (start location)] [ -t (stack trace)]
Print out info for every goroutine. The flag controls what information is shown along with each goroutine:
-u displays location of topmost stackframe in user code
-r displays location of topmost stackframe (including frames inside private runtime functions)
-g displays location of go instruction that created the goroutine
-s displays location of the start function
-t displays stack trace of goroutine
If no flag is specified the default is -u.

@ -143,6 +143,7 @@ type G struct {
SP uint64 // SP of goroutine when it was parked.
BP uint64 // BP of goroutine when it was parked (go >= 1.7).
GoPC uint64 // PC of 'go' statement that created this goroutine.
StartPC uint64 // PC of the first function run on this goroutine.
WaitReason string // Reason for goroutine being parked.
Status uint64
stkbarVar *Variable // stkbar field of g struct
@ -422,6 +423,7 @@ func (gvar *Variable) parseG() (*G, error) {
}
id, _ := constant.Int64Val(gvar.fieldVariable("goid").Value)
gopc, _ := constant.Int64Val(gvar.fieldVariable("gopc").Value)
startpc, _ := constant.Int64Val(gvar.fieldVariable("startpc").Value)
waitReason := ""
if wrvar := gvar.fieldVariable("waitreason"); wrvar.Value != nil {
switch wrvar.Kind {
@ -451,6 +453,7 @@ func (gvar *Variable) parseG() (*G, error) {
g := &G{
ID: int(id),
GoPC: uint64(gopc),
StartPC: uint64(startpc),
PC: uint64(pc),
SP: uint64(sp),
BP: uint64(bp),
@ -553,6 +556,12 @@ func (g *G) Go() Location {
return Location{PC: g.GoPC, File: f, Line: l, Fn: fn}
}
// StartLoc returns the starting location of the goroutine.
func (g *G) StartLoc() Location {
f, l, fn := g.variable.bi.PCToLine(g.StartPC)
return Location{PC: g.StartPC, File: f, Line: l, Fn: fn}
}
// Returns the list of saved return addresses used by stack barriers
func (g *G) stkbar() ([]savedLR, error) {
if g.stkbarVar == nil { // stack barriers were removed in Go 1.9

@ -142,13 +142,14 @@ See also: "help on", "help cond" and "help clear"`},
If called with the linespec argument it will delete all the breakpoints matching the linespec. If linespec is omitted all breakpoints are deleted.`},
{aliases: []string{"goroutines"}, cmdFn: goroutines, helpMsg: `List program goroutines.
goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location) ] [ -t (stack trace)]
goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location)|-s (start location)] [ -t (stack trace)]
Print out info for every goroutine. The flag controls what information is shown along with each goroutine:
-u displays location of topmost stackframe in user code
-r displays location of topmost stackframe (including frames inside private runtime functions)
-g displays location of go instruction that created the goroutine
-s displays location of the start function
-t displays stack trace of goroutine
If no flag is specified the default is -u.`},
@ -544,6 +545,8 @@ func goroutines(t *Term, ctx callContext, argstr string) error {
fgl = fglRuntimeCurrent
case "-g":
fgl = fglGo
case "-s":
fgl = fglStart
case "-t":
bPrintStack = true
case "":
@ -706,6 +709,7 @@ const (
fglRuntimeCurrent = formatGoroutineLoc(iota)
fglUserCurrent
fglGo
fglStart
)
func formatLocation(loc api.Location) string {
@ -732,6 +736,9 @@ func formatGoroutine(g *api.Goroutine, fgl formatGoroutineLoc) string {
case fglGo:
locname = "Go"
loc = g.GoStatementLoc
case fglStart:
locname = "Start"
loc = g.StartLoc
}
thread := ""
if g.ThreadID != 0 {
@ -741,11 +748,12 @@ func formatGoroutine(g *api.Goroutine, fgl formatGoroutineLoc) string {
}
func writeGoroutineLong(w io.Writer, g *api.Goroutine, prefix string) {
fmt.Fprintf(w, "%sGoroutine %d:\n%s\tRuntime: %s\n%s\tUser: %s\n%s\tGo: %s\n",
fmt.Fprintf(w, "%sGoroutine %d:\n%s\tRuntime: %s\n%s\tUser: %s\n%s\tGo: %s\n%s\tStart: %s\n",
prefix, g.ID,
prefix, formatLocation(g.CurrentLoc),
prefix, formatLocation(g.UserCurrentLoc),
prefix, formatLocation(g.GoStatementLoc))
prefix, formatLocation(g.GoStatementLoc),
prefix, formatLocation(g.StartLoc))
}
func parseArgs(args string) ([]string, error) {

@ -235,6 +235,7 @@ func ConvertGoroutine(g *proc.G) *Goroutine {
CurrentLoc: ConvertLocation(g.CurrentLoc),
UserCurrentLoc: ConvertLocation(g.UserCurrent()),
GoStatementLoc: ConvertLocation(g.Go()),
StartLoc: ConvertLocation(g.StartLoc()),
ThreadID: tid,
}
}

@ -256,6 +256,8 @@ type Goroutine struct {
UserCurrentLoc Location `json:"userCurrentLoc"`
// Location of the go instruction that started this goroutine
GoStatementLoc Location `json:"goStatementLoc"`
// Location of the starting function
StartLoc Location `json:"startLoc"`
// ID of the associated thread for running goroutines
ThreadID int `json:"threadID"`
}