google / google/pprof

`go tool pprof` web UI Disassemble sends `^func$`, but `disasm` matches PrintableName

Open
#1,015 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
9.3k
Forks
671
Avg merge
1d 11h
Merged PRs (30d)
10

Description

## 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 toolchain `go1.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

```js
// 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`)

```js
// 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/pprof` `v0.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`)

```go
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()
}
}
```

```bash
go test -c -o foo.test
./foo.test -test.bench=BenchmarkWork -test.cpuprofile=cpu.prof
go tool pprof -http=:8080 ./foo.test cpu.prof
```

1. Open Top, click `example.com/foo.BenchmarkWork`.
2. Click Source → annotated source appears.
3. 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 # works
```

`go 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:14
```

so `^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:

```go
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: `/disasm` with empty/nil `f=`. This report is `f=^funcname$` from the `go tool pprof` web UI; Source still works.
- golang/go#50891 / google/pprof#709: darwin PIE address mapping. Unanchored `go tool pprof` `disasm Func` works 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.

Contributor guide

Open the contributing guide

Research direction

Trace internal/report.symbolsFromBinaries and applyCommandOverrides, then inspect how the web UI's pprofQuoteMeta-generated f= value reaches Disassemble. Run the provided go test -c and go tool pprof reproduction; done means clicking Disassemble works for the selected function while Source and existing CLI matching remain functional.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, javascript
Domain
cli, performance, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
75/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.