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

debug/gosym: extraced entry address not met the symbol value with elf format #65232

Closed
Zxilly opened this issue Jan 23, 2024 · 7 comments
Closed
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. Documentation NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@Zxilly
Copy link
Contributor

Zxilly commented Jan 23, 2024

Go version

go version go1.22rc1 windows/amd64

Output of go env in your module/workspace:

set GO111MODULE=on
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\zxilly\AppData\Local\go-build
set GOENV=C:\Users\zxilly\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\zxilly\go\pkg\mod
set GONOPROXY=1
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\zxilly\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:/Program Files/Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.22rc1
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=0
set GOMOD=E:\Project\CS_Project\gsv\go.mod
set GOWORK=
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\zxilly\AppData\Local\Temp\go-build1340255059=/tmp/go-build -gno-record-gcc-switches

What did you do?

When using the debug/gosym and debug/elf extract the same function, it didn't produce the same address, but as elf document and gosym comment suggest, they both mean the virtual address for function at runtime, and should be the same.

I write a script to reproduce the question.

I test it with the binary compiled from k8s/kubelet. You can get the file at kubelet-linux-1.21-arm64. The compile command can be found at kube.yml

package main

import (
	"debug/elf"
	"debug/gosym"
	"log"
	"os"
)

const Target = "internal/abi.(*RegArgs).Dump"

func main() {
	if len(os.Args) != 2 {
		log.Fatalf("Usage: %s <binary>", os.Args[0])
	}

	binary := os.Args[1]

	f, err := os.Open(binary)
	if err != nil {
		log.Fatalf("Error: %v", err)
	}
	defer f.Close()

	ef, err := elf.NewFile(f)
	if err != nil {
		log.Fatalf("Error: %v", err)
	}

	pcln := ef.Section(".gopclntab")
	if pcln == nil {
		log.Fatalf("Error: %v", err)
	}

	data, err := pcln.Data()
	if err != nil {
		log.Fatalf("Error: %v", err)
	}

	pclntab := gosym.NewLineTable(data, ef.Section(".text").Addr)

	table, err := gosym.NewTable(make([]byte, 0), pclntab)
	if err != nil {
		log.Fatalf("Error: %v", err)
	}

	pclntabAddr := uint64(0)

	for _, fn := range table.Funcs {
		if fn.Name == Target {
			pclntabAddr = fn.Entry
			break
		}
	}

	if pclntabAddr == 0 {
		log.Fatalf("Target not found in pclntab")
	}

	symbols, err := ef.Symbols()
	if err != nil {
		log.Fatalf("Error: %v", err)
	}

	symbolAddr := uint64(0)

	for _, s := range symbols {
		if s.Name == Target {
			symbolAddr = s.Value
			break
		}
	}

	if pclntabAddr != symbolAddr {
		log.Fatalf("pclntabAddr %x != symbolAddr %x", pclntabAddr, symbolAddr)
	} else {
		log.Printf("pclntabAddr %x == symbolAddr %x", pclntabAddr, symbolAddr)
	}
}

What did you see happen?

2024/01/23 19:36:53 pclntabAddr 402420 != symbolAddr 402520

What did you expect to see?

pclntabAddr == symbolAddr
@Zxilly Zxilly changed the title debug/gosym: extraced entry address not met the symbol value debug/gosym: extraced entry address not met the symbol value with elf format Jan 23, 2024
@Zxilly
Copy link
Contributor Author

Zxilly commented Jan 23, 2024

I also test it with other binary, and I found if the cgo is enabled, the gclntab address will always diff from symbol address.

@cherrymui
Copy link
Member

cherrymui commented Jan 23, 2024

Try passing the address of runtime.text symbol as the text parameter to NewLineTable. I think the code expects that instead of the start of the segment. For a pure-Go binary they are the same, but for cgo binary they can be different. We probably need to fix the documentation.

@cherrymui cherrymui added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Documentation labels Jan 23, 2024
@cherrymui cherrymui added this to the Backlog milestone Jan 23, 2024
@cherrymui cherrymui added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jan 23, 2024
@Zxilly
Copy link
Contributor Author

Zxilly commented Jan 23, 2024

Do you mean but for cgo binary they can be different?

@cherrymui
Copy link
Member

Yes... corrected

@Zxilly
Copy link
Contributor Author

Zxilly commented Jan 23, 2024

Can you give advice about where in the golang source code cause For a pure-Go binary they are the same, but for cgo binary they can be different.? I'm new to golang source code and it's hard to find out exact position.

@cherrymui
Copy link
Member

In the Go linker we put all Go functions together, after the runtime.text symbol. For a pure Go binary, we put it at the start o f the text section and text segment. But for a cgo binary, the C linker doesn't necessarily to do so. It can put some C functions in the text section before the runtime.text symbol.

The Go pclntab contains only relative addresses, relative to runtime.text, which is Go's knowledge of the start of Go text. (There can be C functions before or after, but it is irrelevant to Go.) So the debug/gosym package can only compute the PCs given the start address.

In general, the debug/gosym package is not meant to be a reverse engineering tool. If one strips the symbol table, they can also smash the Go pclntab.

@gopherbot
Copy link

Change https://go.dev/cl/557957 mentions this issue: debug/gosym: add detailed doc for text argument in NewLineTable

ezz-no pushed a commit to ezz-no/go-ezzno that referenced this issue Feb 18, 2024
Fixes golang#65232

Change-Id: I9ef76355cec4bea2d77811a69c61c1806c486be8
GitHub-Last-Rev: 9c617b6
GitHub-Pull-Request: golang#65263
Reviewed-on: https://go-review.googlesource.com/c/go/+/557957
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. Documentation NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants