Description
Go version
1.22.5
Output of go env
in your module/workspace:
$ go env
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/aalexand/.cache/go-build'
GOENV='/home/aalexand/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/aalexand/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/aalexand/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/aalexand/.gimme/versions/go1.22.5.linux.amd64'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/aalexand/.gimme/versions/go1.22.5.linux.amd64/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.5'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build4077799602=/tmp/go-build -gno-record-gcc-switches'
What did you do?
I'm using this self-profiling toy program:
$ cat main.go
package main
import (
"log"
"os"
"runtime/pprof"
)
func main() {
f, err := os.Create("profile.pb.gz")
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
var i int64
for i = 0; i < (1 << 33); i++ {
}
}
When I build it with go build main.go
, I can see that, as expected by default, this pure Go binary only has the Go build ID and not the GNU build ID:
$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=llrn1go725_F2vCvvETz/OITeRu6kDScHG6FVjdK8/R7ABD8hl4lkeyDfz55iM/uoTostDrfB5kdwhy6UpG, with debug_info, not stripped
$ readelf -n main
Displaying notes found in: .note.go.buildid
Owner Data size Description
Go 0x00000053 GO BUILDID
description data: 6c 6c 72 6e 31 67 6f 37 32 35 5f 46 32 76 43 76 76 45 54 7a 2f 4f 49 54 65 52 75 36 6b 44 53 63 48 47 36 46 56 6a 64 4b 38 2f 52 37 41 42 44 38 68 6c 34 6c 6b 65 79 44 66 7a 35 35 69 4d 2f 75 6f 54 6f 73 74 44 72 66 42 35 6b 64 77 68 79 36 55 70 47
Unexpectedly, when I run this program, the recorded profile does not capture the build ID:
$ ./main
$ pprof -raw profile.pb.gz | grep -A10 Mappings
Mappings
1: 0x400000/0x4ac000/0x0 /tmp/main [FN]
If I ask Go linker to generate the GNU build ID for the binary using the -B gobuildid
linker flag added in #61469, then the profile records the build ID as expected:
$ go build -ldflags "-B gobuildid" main.go
$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=f4b5d514bc46fad9417898216b23910ae874a85d, with debug_info, not stripped
$ readelf -n main
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: f4b5d514bc46fad9417898216b23910ae874a85d
Displaying notes found in: .note.go.buildid
Owner Data size Description
Go 0x00000053 GO BUILDID
description data: 45 72 5a 36 6f 30 30 37 79 53 35 48 4c 67 41 7a 51 66 6e 52 2f 42 5a 53 51 58 54 4b 49 35 53 61 61 4f 4d 6e 65 49 36 63 56 2f 52 37 41 42 44 38 68 6c 34 6c 6b 65 79 44 66 7a 35 35 69 4d 2f 73 58 6a 56 4b 38 6d 52 58 79 35 4d 79 41 73 46 46 52 6d 74
$ ./main
$ pprof -raw profile.pb.gz | grep -A10 Mappings
Mappings
1: 0x400000/0x4ac000/0x0 /tmp/main f4b5d514bc46fad9417898216b23910ae874a85d [FN]
What did you see happen?
See above.
What did you expect to see?
This happens because src/runtime/pprof/elf.go only reads the GNU build ID, not the Go build ID. I would expect instead to see runtime/pprof record the Go build ID when it's present and fall back to the GNU build ID when the Go build ID is missing. This would be similar to the behavior of the file
utility.
A related issue is that as far as I know Linux perf has its own logic for extracting the build ID as well and it does not record the Go build ID either. I think we in general should be careful with introducing private extensions to recording build ID in the binary since this may have cascade effects on the compatibility of existing profiling and debugging toolchains. It would be good if everything would just record the build ID as the standard GNU build ID.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status