`go tool pprof` web UI Disassemble sends `^func$`, but `disasm` matches PrintableName
Summary
I hit this through go tool pprof (Go's vendored copy of this repo), not the standalone pprof binary.
In the web UI (go tool pprof -http=...), clicking a function and then Disassemble fails with
no matches found for regexp ^mypkg\.MyFunc$Source for the same f= works. Unanchored disasm MyFunc in the CLI also works.
This is not darwin PIE / missing-binary. The binary is passed in, and list ^MyFunc$ succeeds.
Environment
go version go1.24.4 darwin/arm64(also reproduced with toolchaingo1.26.2)- Invocation:
go tool pprof -http=:8080 ./foo.test cpu.prof
When it broke
Until Go 1.22, the web UI escaped the selected name but did not anchor it
// Go 1.22 and earlier (vendored pprof)
function quotemeta(str) {
return str.replace(/([\\\.?+*\[\](){}|^$])/g, '\\$1');
}Click → Disassemble produced f=mypkg.MyFunc, which still matched as a substring of PrintableName (ADDRESS mypkg.MyFunc file.go:N).
Exact-match quoting was added in google/pprof on 2023-08-16:
- PR: https://github.com/google/pprof/pull/796
- Commit: https://github.com/google/pprof/commit/76846d4d6a3b69af9b9331821b7d40d2f5f4b58d (
Fix flamegraph name matching)
// convert a string to a regexp that matches exactly that string.
function pprofQuoteMeta(str) {
return '^' + str.replace(/([\\\.?+*\[\](){}|^$])/g, '\\$1') + '$';
}The intent was Focus/Hide on flame graphs (UniqueName vs FunctionName). The same helper is used for the Disassemble button.
Go vendored that snapshot on 2024-02-16
- Commit: https://github.com/golang/go/commit/63dd79c07b0026b58f421a5273c41e705ccb73d1 (
cmd/pprof: update vendored github.com/google/pprof) - CL: https://go-review.googlesource.com/c/go/+/564636
github.com/google/pprofv0.0.0-20230811205829-9131a7e9cc17→v0.0.0-20240207164012-fb44976bdcd5
That landed on tip during the 1.23 cycle. Go 1.22 still has unanchored quotemeta. Go 1.23.0 (2024-08-13) is the first release where go tool pprof web UI Disassemble is broken this way. Still present in 1.24 / 1.26.
disasm matching PrintableName (address granularity) is older; the UI change is what made click → Disassemble fail.
Reproduction (go tool pprof)
package foo
import "testing"
func work() int {
s := 0
for i := 0; i < 1_000_000; i++ {
s += i
}
return s
}
func BenchmarkWork(b *testing.B) {
for i := 0; i < b.N; i++ {
work()
}
}go test -c -o foo.test
./foo.test -test.bench=BenchmarkWork -test.cpuprofile=cpu.prof
go tool pprof -http=:8080 ./foo.test cpu.prof- Open Top, click
example.com/foo.BenchmarkWork. - Click Source → annotated source appears.
- Click Disassemble →
no matches found for regexp ^example.com/foo\.BenchmarkWork$.
CLI:
$ go tool pprof ./foo.test cpu.prof
(pprof) list ^example.com/foo\.BenchmarkWork$ # works
(pprof) disasm ^example.com/foo\.BenchmarkWork$ # fails
(pprof) disasm example.com/foo.BenchmarkWork # worksgo tool nm ./foo.test shows the symbol.
Expected
The regexp the web UI puts in f= (^name$) should work for both Source and Disassemble.
Actual
disasm matches NodeInfo.PrintableName(). With address granularity that string is
000000010010bfb4 example.com/foo.BenchmarkWork /tmp/foo_test.go:14so ^example.com/foo\.BenchmarkWork$ cannot match.
list / weblist compare n.Info.Name only, which is why Source still works.
internal/report.symbolsFromBinaries skips mappings unless PrintableName matches:
if name := n.Info.PrintableName(); rx.MatchString(name) && n.Info.Objfile != "" {
fileHasSamplesAndMatched[n.Info.Objfile] = true
}For disasm, applyCommandOverrides sets Granularity = "addresses". If that filter fails, ObjFile.Symbols(rx) is never called. That API matches binary symbol names (mypkg.MyFunc), which would match ^mypkg\.MyFunc$.
The function is in the profile and in the binary; the filter uses the wrong name.
Related (not duplicates)
- google/pprof#789:
/disasmwith empty/nilf=. This report isf=^funcname$from thego tool pprofweb UI; Source still works. - golang/go#50891 / google/pprof#709: darwin PIE address mapping. Unanchored
go tool pprofdisasm Funcworks here once the test binary is passed. - google/pprof#914: OSX weblist vs
_-prefixed Mach-O names. - google/pprof#230: inlined functions have no standalone symbol.
- google/pprof#796: introduced
pprofQuoteMeta(^name$) for Focus; that is what the Disassemble button now sends.
Source: google/pprof