Fix tls for aarch64 and arm (#2626)

* fix tls for aarch64 and arm

* fix comment

* arm register

* fix
pull/2629/head
patryk4815 12 months ago committed by GitHub
parent f351f27780
commit 6a6203148b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -249,7 +249,6 @@ class module(ModuleType):
def gsbase(self) -> int:
return self._fs_gs_helper("gs_base", ARCH_GET_GS)
@pwndbg.lib.cache.cache_until("stop")
def _fs_gs_helper(self, regname: str, which: int) -> int:
"""Supports fetching based on segmented addressing, a la fs:[0x30].
Requires ptrace'ing the child directory if i386."""

@ -12,7 +12,11 @@ import pwndbg.aglib.vmmap
def __call_pthread_self() -> int:
"""Get the address of TLS by calling pthread_self()."""
"""
Retrieve the address of the `struct pthread_t` for the current thread by
calling pthread_self(). This address can be used to locate the base address
of the Thread Local Storage (TLS).
"""
if pwndbg.dbg.selected_inferior().symbol_address_from_name("pthread_self") is None:
return 0
try:
@ -26,10 +30,14 @@ def __call_pthread_self() -> int:
def find_address_with_pthread_self() -> int:
"""Get the address of TLS with pthread_self()."""
if pwndbg.aglib.arch.current not in ("x86-64", "i386", "arm"):
# Note: we should support aarch64 if it's possible that TPIDR_EL0 register can not be accessed.
"""
Get the base address of the Thread Local Storage (TLS) for the current thread using
the pthread_self() function. The returned address points to the `struct tcbhead_t`,
which serves as the header for TLS and thread-specific metadata.
"""
if pwndbg.aglib.arch.current not in ("x86-64", "i386", "arm", "aarch64"):
return 0
result = __call_pthread_self()
if result <= 0:
# pthread_self() is not valid
@ -43,20 +51,34 @@ def find_address_with_pthread_self() -> int:
# For i386 and x86-64, the return value of the pthread_self() is the address of TLS, because the value is self reference of the TLS: https://elixir.bootlin.com/glibc/glibc-2.37/source/nptl/pthread_create.c#L671
# But for arm, the implementation of THREAD_SELF is different, we need to add sizeof(struct pthread) to the result to get the address of TLS.
if pwndbg.aglib.arch.current == "arm":
# 0x4c0 is sizeof(struct pthread)
# TODO: we might need to adjust the value if the size of struct pthread is changed in the future.
result += 0x4C0
if pwndbg.aglib.arch.current in ("arm", "aarch64"):
pthread_type = pwndbg.aglib.typeinfo.load("struct pthread")
if pthread_type is None:
# Type 'pthread' not found
return 0
result += pthread_type.sizeof
return result
def find_address_with_register() -> int:
"""Get the address of TLS with register."""
"""
Get the base address of the Thread Local Storage (TLS) for the current thread using
a CPU register. The returned address points to the `struct tcbhead_t`, which is the
entry point for TLS and thread-specific metadata.
"""
if pwndbg.aglib.arch.current == "x86-64":
return int(pwndbg.aglib.regs.fsbase)
elif pwndbg.aglib.arch.current == "i386":
return int(pwndbg.aglib.regs.gsbase)
elif pwndbg.aglib.arch.current == "aarch64":
return int(pwndbg.aglib.regs.TPIDR_EL0)
# TODO: is it possible that we can get the address of TLS with register on arm?
# FIXME: cleanup/remove `TPIDR_EL0` register, it was renamed to `tpidr` since GDB13+
return int(pwndbg.aglib.regs.tpidr or pwndbg.aglib.regs.TPIDR_EL0 or 0)
elif pwndbg.aglib.arch.current == "arm":
# TODO: linux ptrace for 64bit kernel?
# In FreeBSD tls is under `tpidruro` register.
# In Linux, the `tpidruro` register isn't available via ptrace in the 32-bit
# kernel but it is available for an aarch32 program running under an arm64
# kernel via the ptrace compat interface.
return int(pwndbg.aglib.regs.tpidruro or 0)
return 0

Loading…
Cancel
Save