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 ## goroutines
List program 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: 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 -u displays location of topmost stackframe in user code
-r displays location of topmost stackframe (including frames inside private runtime functions) -r displays location of topmost stackframe (including frames inside private runtime functions)
-g displays location of go instruction that created the goroutine -g displays location of go instruction that created the goroutine
-s displays location of the start function
-t displays stack trace of goroutine -t displays stack trace of goroutine
If no flag is specified the default is -u. 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. SP uint64 // SP of goroutine when it was parked.
BP uint64 // BP of goroutine when it was parked (go >= 1.7). BP uint64 // BP of goroutine when it was parked (go >= 1.7).
GoPC uint64 // PC of 'go' statement that created this goroutine. 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. WaitReason string // Reason for goroutine being parked.
Status uint64 Status uint64
stkbarVar *Variable // stkbar field of g struct stkbarVar *Variable // stkbar field of g struct
@ -422,6 +423,7 @@ func (gvar *Variable) parseG() (*G, error) {
} }
id, _ := constant.Int64Val(gvar.fieldVariable("goid").Value) id, _ := constant.Int64Val(gvar.fieldVariable("goid").Value)
gopc, _ := constant.Int64Val(gvar.fieldVariable("gopc").Value) gopc, _ := constant.Int64Val(gvar.fieldVariable("gopc").Value)
startpc, _ := constant.Int64Val(gvar.fieldVariable("startpc").Value)
waitReason := "" waitReason := ""
if wrvar := gvar.fieldVariable("waitreason"); wrvar.Value != nil { if wrvar := gvar.fieldVariable("waitreason"); wrvar.Value != nil {
switch wrvar.Kind { switch wrvar.Kind {
@ -451,6 +453,7 @@ func (gvar *Variable) parseG() (*G, error) {
g := &G{ g := &G{
ID: int(id), ID: int(id),
GoPC: uint64(gopc), GoPC: uint64(gopc),
StartPC: uint64(startpc),
PC: uint64(pc), PC: uint64(pc),
SP: uint64(sp), SP: uint64(sp),
BP: uint64(bp), BP: uint64(bp),
@ -553,6 +556,12 @@ func (g *G) Go() Location {
return Location{PC: g.GoPC, File: f, Line: l, Fn: fn} 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 // Returns the list of saved return addresses used by stack barriers
func (g *G) stkbar() ([]savedLR, error) { func (g *G) stkbar() ([]savedLR, error) {
if g.stkbarVar == nil { // stack barriers were removed in Go 1.9 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.`}, 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. {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: 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 -u displays location of topmost stackframe in user code
-r displays location of topmost stackframe (including frames inside private runtime functions) -r displays location of topmost stackframe (including frames inside private runtime functions)
-g displays location of go instruction that created the goroutine -g displays location of go instruction that created the goroutine
-s displays location of the start function
-t displays stack trace of goroutine -t displays stack trace of goroutine
If no flag is specified the default is -u.`}, If no flag is specified the default is -u.`},
@ -544,6 +545,8 @@ func goroutines(t *Term, ctx callContext, argstr string) error {
fgl = fglRuntimeCurrent fgl = fglRuntimeCurrent
case "-g": case "-g":
fgl = fglGo fgl = fglGo
case "-s":
fgl = fglStart
case "-t": case "-t":
bPrintStack = true bPrintStack = true
case "": case "":
@ -706,6 +709,7 @@ const (
fglRuntimeCurrent = formatGoroutineLoc(iota) fglRuntimeCurrent = formatGoroutineLoc(iota)
fglUserCurrent fglUserCurrent
fglGo fglGo
fglStart
) )
func formatLocation(loc api.Location) string { func formatLocation(loc api.Location) string {
@ -732,6 +736,9 @@ func formatGoroutine(g *api.Goroutine, fgl formatGoroutineLoc) string {
case fglGo: case fglGo:
locname = "Go" locname = "Go"
loc = g.GoStatementLoc loc = g.GoStatementLoc
case fglStart:
locname = "Start"
loc = g.StartLoc
} }
thread := "" thread := ""
if g.ThreadID != 0 { 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) { 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, g.ID,
prefix, formatLocation(g.CurrentLoc), prefix, formatLocation(g.CurrentLoc),
prefix, formatLocation(g.UserCurrentLoc), prefix, formatLocation(g.UserCurrentLoc),
prefix, formatLocation(g.GoStatementLoc)) prefix, formatLocation(g.GoStatementLoc),
prefix, formatLocation(g.StartLoc))
} }
func parseArgs(args string) ([]string, error) { func parseArgs(args string) ([]string, error) {

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

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