Skip to content

Commit

Permalink
Fix arm64/musl gilstate addressing
Browse files Browse the repository at this point in the history
  • Loading branch information
gnurizen committed May 23, 2024
1 parent bf30888 commit 06fbe08
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 18 deletions.
18 changes: 14 additions & 4 deletions pkg/runtime/python/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
runtimedata "github.com/parca-dev/runtime-data/pkg/python"

"github.com/parca-dev/parca-agent/pkg/runtime"
"github.com/parca-dev/parca-agent/pkg/runtime/libc"
)

var (
Expand Down Expand Up @@ -168,7 +169,7 @@ func newInterpreter(proc procfs.Proc) (*interpreter, error) {
}, nil
}

func (i interpreter) threadStateAddress() (uint64, error) {
func (i interpreter) threadStateAddress(libcImp libc.LibcImplementation) (uint64, error) {
const37_11, err := semver.NewConstraint(">=3.7.x-0")
if err != nil {
return 0, fmt.Errorf("new constraint: %w", err)
Expand All @@ -190,7 +191,7 @@ func (i interpreter) threadStateAddress() (uint64, error) {
return 0, nil
}
fmt.Printf("python_new %s got addr = %p, tstate_current offset=%d\n", i.version.String(), unsafe.Pointer(uintptr(addr+uint64(initialState.ThreadStateCurrent))), initialState.ThreadStateCurrent)

Check failure on line 193 in pkg/runtime/python/interpreter.go

View workflow job for this annotation

GitHub Actions / Go Build

use of `fmt.Printf` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
return addr + uint64(initialState.ThreadStateCurrent), nil
return addr + uint64(initialState.ThreadStateCurrent) - interpreterGILAddressOffset(libcImp), nil
// Older versions (<3.7.0) of Python do not have the _PyRuntime struct.
default:
addr, err := i.findAddressOf(pythonThreadStateSymbol) // _PyThreadState_Current
Expand Down Expand Up @@ -225,7 +226,16 @@ func (i interpreter) interpreterAddress() (uint64, error) {
}
}

func (i interpreter) tlsKey() (uint64, error) {
// mutex are 8 bytes smaller on arm64/musl and there are two
// in the PyRuntime object in front of the gilstate.
func interpreterGILAddressOffset(libcImp libc.LibcImplementation) uint64 {
if libcImp == libc.LibcMusl && goruntime.GOARCH == "arm64" {
return 16
}
return 0
}

func (i interpreter) tlsKey(libcImp libc.LibcImplementation) (uint64, error) {
pyRuntimeAddr, err := i.findAddressOf(pythonRuntimeSymbol) // _PyRuntime
if err != nil {
return 0, fmt.Errorf("findAddressOf: %w", err)
Expand All @@ -234,7 +244,7 @@ func (i interpreter) tlsKey() (uint64, error) {
if err != nil {
return 0, fmt.Errorf("get initial state: %w", err)
}
tssKeyAddr := pyRuntimeAddr + uint64(initialState.AutoTSSKey)
tssKeyAddr := pyRuntimeAddr + uint64(initialState.AutoTSSKey) - interpreterGILAddressOffset(libcImp)
tssKeyLayout := initialState.PyTSS

tss := make([]byte, tssKeyLayout.Size)
Expand Down
33 changes: 19 additions & 14 deletions pkg/runtime/python/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,31 @@ func InterpreterInfo(proc procfs.Proc) (*Info, error) {
}
defer interpreter.Close()

threadStateAddress, err := interpreter.threadStateAddress()
libcInfo, err := libc.NewLibcInfo(proc)
if err != nil {
above312, err := semver.NewConstraint(">=3.12.0-0")
if err != nil {
return nil, fmt.Errorf("python version: %s, libc info: %w", interpreter.version.String(), err)
}
if above312.Check(interpreter.version) {
// It's only critical to have the libc info for Python 3.12 and above.
return nil, fmt.Errorf("python version: %s, libc info: %w", interpreter.version.String(), err)
}
}

libcImp := libc.LibcGlibc
if libcInfo != nil {
libcImp = libcInfo.Implementation
}

threadStateAddress, err := interpreter.threadStateAddress(libcImp)
if err != nil {
return nil, fmt.Errorf("python version: %s, thread state address: %w", interpreter.version.String(), err)
}

var tlsKey uint64
if threadStateAddress == 0 {
tlsKey, err = interpreter.tlsKey()
tlsKey, err = interpreter.tlsKey(libcImp)
if err != nil {
return nil, fmt.Errorf("python version: %s, tls key: %w", interpreter.version.String(), err)
}
Expand All @@ -175,18 +192,6 @@ func InterpreterInfo(proc procfs.Proc) (*Info, error) {
return nil, fmt.Errorf("invalid address, python version: %s, interpreter address: 0x%016x", interpreter.version.String(), interpreterAddress)
}

libcInfo, err := libc.NewLibcInfo(proc)
if err != nil {
above312, err := semver.NewConstraint(">=3.12.0-0")
if err != nil {
return nil, fmt.Errorf("python version: %s, libc info: %w", interpreter.version.String(), err)
}
if above312.Check(interpreter.version) {
// It's only critical to have the libc info for Python 3.12 and above.
return nil, fmt.Errorf("python version: %s, libc info: %w", interpreter.version.String(), err)
}
}

return &Info{
rt: runtime.Runtime{
Name: "Python",
Expand Down

0 comments on commit 06fbe08

Please sign in to comment.