diff --git a/pwndbg/aglib/regs.py b/pwndbg/aglib/regs.py index 14487b49c..566482e9c 100644 --- a/pwndbg/aglib/regs.py +++ b/pwndbg/aglib/regs.py @@ -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.""" diff --git a/pwndbg/aglib/tls.py b/pwndbg/aglib/tls.py index 4ac60ad5f..ab3fef5d6 100644 --- a/pwndbg/aglib/tls.py +++ b/pwndbg/aglib/tls.py @@ -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