Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 36 additions & 19 deletions gostackparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,35 +253,52 @@ func parseFunc(line []byte, state parserState) *Frame {
//
// Example Update:
// &Frame{File: "/root/go1.15.6.linux.amd64/src/net/http/server.go", Line: 2969}
func parseFile(line []byte, f *Frame) bool {
if len(line) == 0 || line[0] != '\t' {
//
// Note: The +0x36c is the relative pc offset from the function entry pc. It's
// omitted if it's 0.
func parseFile(line []byte, f *Frame) (ret bool) {
if len(line) < 2 || line[0] != '\t' {
return false
}

line = line[1:]

const (
stateFilename = iota
stateColon
stateLine
)

var state = stateFilename
for i, c := range line {
if c == ':' {
if f.File != "" {
return false
switch state {
case stateFilename:
if c == ':' {
state = stateColon
}
f.File = string(line[0:i])
} else if c == ' ' || i+1 == len(line) {
if f.File == "" {
return false
case stateColon:
if isDigit(c) {
f.File = string(line[0 : i-1])
f.Line = int(c - '0')
state = stateLine
ret = true
} else {
state = stateFilename
}
var end int
case stateLine:
if c == ' ' {
end = i
} else {
end = i + 1
return true
} else if !isDigit(c) {
return false
}

var err error
f.Line, err = strconv.Atoi(string(line[len(f.File)+1 : end]))
return err == nil
f.Line = f.Line*10 + int(c-'0')
}

}
return false
return
}

func isDigit(c byte) bool {
return c >= '0' && c <= '9'
}

// Goroutine represents a single goroutine and its stack after extracting it
Expand Down
72 changes: 72 additions & 0 deletions gostackparse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,75 @@ func TestFuzzCorupus(t *testing.T) {
require.NoError(t, ioutil.WriteFile(name, []byte(dump.String()), 0666))
}
}

func Test_parseFile(t *testing.T) {
tests := []struct {
name string
line string
wantFrame Frame
wantReturn bool
}{
{
name: "empty",
line: "",
wantFrame: Frame{},
wantReturn: false,
},
{
name: "simple",
line: "\t/root/go1.15.6.linux.amd64/src/net/http/server.go:2969 +0x36c",
wantFrame: Frame{
File: "/root/go1.15.6.linux.amd64/src/net/http/server.go",
Line: 2969,
},
wantReturn: true,
},
{
name: "simple+space",
line: "\t/root/go1.15.6.linux.amd64/src/net/http/cool server.go:2969 +0x36c",
wantFrame: Frame{
File: "/root/go1.15.6.linux.amd64/src/net/http/cool server.go",
Line: 2969,
},
wantReturn: true,
},
{
name: "no-relative-pc",
line: "\t/root/go1.15.6.linux.amd64/src/net/http/server.go:2969",
wantFrame: Frame{
File: "/root/go1.15.6.linux.amd64/src/net/http/server.go",
Line: 2969,
},
wantReturn: true,
},
{
name: "no-relative-pc+space",
line: "\t/root/go1.15.6.linux.amd64/src/net/http/cool server.go:2969",
wantFrame: Frame{
File: "/root/go1.15.6.linux.amd64/src/net/http/cool server.go",
Line: 2969,
},
wantReturn: true,
},
}
for _, tt := range tests {
if len(tt.line) > 1 {
tt.name = "windows+" + tt.name
tt.line = "\tC:" + tt.line[1:]
tt.wantFrame.File = "C:" + tt.wantFrame.File
tests = append(tests, tt)
}
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var f Frame
got := parseFile([]byte(tt.line), &f)
if got != tt.wantReturn {
t.Fatalf("got=%v want=%v", got, tt.wantReturn)
} else if f != tt.wantFrame {
t.Fatalf("got=%+v want=%+v", f, tt.wantFrame)
}
})
}
}
20 changes: 20 additions & 0 deletions test-fixtures/windows.golden.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"Errors": null,
"Goroutines": [
{
"ID": 1,
"State": "running",
"Wait": 0,
"LockedToThread": false,
"Stack": [
{
"Func": "runtime/pprof.writeGoroutineStacks",
"File": "C:/Users/felixge/pprof.go",
"Line": 693
}
],
"FramesElided": false,
"CreatedBy": null
}
]
}
3 changes: 3 additions & 0 deletions test-fixtures/windows.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
goroutine 1 [running]:
runtime/pprof.writeGoroutineStacks(0x14e5940, 0xc0000abc50, 0x101b8a5, 0xc000333d20)
C:/Users/felixge/pprof.go:693 +0x9f