Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: PC values from Callers do not correspond to symbol table on Darwin #45853

Closed
eandre opened this issue Apr 29, 2021 · 10 comments
Closed

Comments

@eandre
Copy link

eandre commented Apr 29, 2021

What version of Go are you using (go version)?

$ go version
go version go1.16.3 darwin/arm64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="on"
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/eandre/Library/Caches/go-build"
GOENV="/Users/eandre/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/eandre/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/eandre"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.16.3/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.16.3/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.16.3"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/eandre/src/app.encore.dev/emailer/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/hc/w9bwjfwd69dd6_6thw6xqmkw0000gn/T/go-build1741436854=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I called runtime.Callers and tried to match the PCs with the information in the symbol table (using debug/macho and debug/gosym).

This program works as expected on linux: https://play.golang.org/p/p8KzmTQw_WQ

PC 4927879 -> main.myPC
main.myPC is at PC range [4927840, 4927968]

What did you expect to see?

I expected similar output to the linux version.

What did you see instead?

On darwin/arm64 (https://play.golang.org/p/tOBx2Bvl5VA):

PC 4372428961 -> <nil>
main.myPC is at PC range [4295669888, 4295669984]
@randall77
Copy link
Contributor

Doesn't work at all on darwin/amd64. Binaries are macho, not elf. What are darwin/arm64 binaries?
You should check the error result of elf.NewFile regardless.

@eandre
Copy link
Author

eandre commented Apr 29, 2021

I linked to the corresponding darwin program above: https://play.golang.org/p/tOBx2Bvl5VA. I elided error handling for simplicity, that's not the source of the issue.

@eandre
Copy link
Author

eandre commented Apr 29, 2021

@heschi suggested it might be due to ASLR. If that is the case, is it possible to determine some constant symbol table-offset that is ASLR-independent?

@heschi
Copy link
Contributor

heschi commented Apr 29, 2021

No, I hadn't seen the actual values in question. That's not ASLR.

@randall77
Copy link
Contributor

Ok, sorry I didn't realize those were two separate programs.

It works on darwin/amd64.

If it is ASLR, it should report a different PC on each run. Does it? (On amd64 it doesn't.)

@randall77
Copy link
Contributor

Also, if it is ASLR you should be able to check two different functions and see if the error delta is the same.

@cherrymui
Copy link
Member

Yes, on darwin/arm64 everything must be PIE. It is ASLR.

@cherrymui
Copy link
Member

I expected similar output to the linux version.

On other platforms if you used -buildmode=pie, you will see similar results.

As @randall77 said, you can check for address differences. I'm not sure if there is anything else we could do. Thanks.

@eandre
Copy link
Author

eandre commented Apr 30, 2021

Thanks, that makes sense. I did some playing around and it seems that taking the address of the text segment at runtime and computing PC - textSegmentAddr should produce a constant offset that can be looked up in the symbol table (by adding it with the static text segment address). Does that make sense?

When playing with this I noticed the runtime looks this up using in the moduledata struct, and it's a linked list starting at firstmoduledata. Am I understanding it correctly that I should be able to do this using firstmoduledata.text in all circumstances, or do I need to resolve the appropriate module for each PC to do this sort of mapping?

@randall77
Copy link
Contributor

Thanks, that makes sense. I did some playing around and it seems that taking the address of the text segment at runtime and computing PC - textSegmentAddr should produce a constant offset that can be looked up in the symbol table (by adding it with the static text segment address). Does that make sense?

Yes, that should work. (But see below.)

When playing with this I noticed the runtime looks this up using in the moduledata struct, and it's a linked list starting at firstmoduledata. Am I understanding it correctly that I should be able to do this using firstmoduledata.text in all circumstances, or do I need to resolve the appropriate module for each PC to do this sort of mapping?

In a standard executable there should only be one module. You'll get more than one module only if you use the plugin package, or use other alternate linking modes. In those cases, yes, you would need to resolve the module first (because there would be multiple text segments in your address space).

I'm going to close, there's no bug in Go here.

@golang golang locked and limited conversation to collaborators Apr 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants