https://github.com/jeffreytan81 created https://github.com/llvm/llvm-project/pull/67470
None >From 5e8b4a44bf48216785f5ecb412e145a7ac4d3a55 Mon Sep 17 00:00:00 2001 From: jeffreytan81 <jeffrey...@fb.com> Date: Tue, 26 Sep 2023 11:04:08 -0700 Subject: [PATCH] Implement thread local storage for linux --- lldb/include/lldb/Target/RegisterContext.h | 2 + lldb/include/lldb/lldb-defines.h | 1 + .../POSIX-DYLD/DYLDRendezvous.cpp | 11 ++--- .../POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp | 49 +++++++++++++++---- .../Utility/RegisterInfos_x86_64_with_base.h | 13 +---- .../GDBRemoteCommunicationServerLLGS.cpp | 2 + lldb/source/Target/RegisterContext.cpp | 6 +++ lldb/source/Target/Thread.cpp | 6 ++- lldb/source/Utility/Args.cpp | 1 + .../API/lang/c/tls_globals/TestTlsGlobals.py | 5 +- 10 files changed, 65 insertions(+), 31 deletions(-) diff --git a/lldb/include/lldb/Target/RegisterContext.h b/lldb/include/lldb/Target/RegisterContext.h index de0efd982daaa71..b2626928f142604 100644 --- a/lldb/include/lldb/Target/RegisterContext.h +++ b/lldb/include/lldb/Target/RegisterContext.h @@ -144,6 +144,8 @@ class RegisterContext : public std::enable_shared_from_this<RegisterContext>, uint64_t GetPC(uint64_t fail_value = LLDB_INVALID_ADDRESS); + uint64_t GetThreadPointer(uint64_t fail_value = LLDB_INVALID_ADDRESS); + /// Get an address suitable for symbolication. /// When symbolicating -- computing line, block, function -- /// for a function in the middle of the stack, using the return diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h index ce7fd6f3754516e..aaf0b04e4fb86e9 100644 --- a/lldb/include/lldb/lldb-defines.h +++ b/lldb/include/lldb/lldb-defines.h @@ -71,6 +71,7 @@ 11 // The register that would contain pointer size or less argument 7 (if any) #define LLDB_REGNUM_GENERIC_ARG8 \ 12 // The register that would contain pointer size or less argument 8 (if any) +#define LLDB_REGNUM_GENERIC_TP 13 // Thread pointer /// Invalid value definitions #define LLDB_INVALID_STOP_ID 0 #define LLDB_INVALID_ADDRESS UINT64_MAX diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index 68e4ac0cc4007c4..cb174d31b86dfe6 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -710,16 +710,13 @@ bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field, target.GetImages().FindSymbolsWithNameAndType(ConstString(name), eSymbolTypeAny, list); if (list.IsEmpty()) - return false; - - Address address = list[0].symbol->GetAddress(); - addr_t addr = address.GetLoadAddress(&target); - if (addr == LLDB_INVALID_ADDRESS) return false; + Address address = list[0].symbol->GetAddress(); + address.SetOffset(address.GetOffset() + field * sizeof(uint32_t)); Status error; - value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory( - addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error); + value = + target.ReadUnsignedIntegerFromMemory(address, sizeof(uint32_t), 0, error); if (error.Fail()) return false; diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index b4b38a88e1b9c7a..85d7ae9dac75d1e 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -420,6 +420,11 @@ void DynamicLoaderPOSIXDYLD::RefreshModules() { if (!m_rendezvous.Resolve()) return; + // The rendezvous class doesn't enumerate the main module, so track that + // ourselves here. + ModuleSP executable = GetTargetExecutable(); + m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); + DYLDRendezvous::iterator I; DYLDRendezvous::iterator E; @@ -727,41 +732,66 @@ lldb::addr_t DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr) { + Log *log = GetLog(LLDBLog::DynamicLoader); auto it = m_loaded_modules.find(module_sp); - if (it == m_loaded_modules.end()) + if (it == m_loaded_modules.end()) { + LLDB_LOGF( + log, "GetThreadLocalData error: module(%s) not found in loaded modules", + module_sp->GetObjectName().AsCString()); return LLDB_INVALID_ADDRESS; + } addr_t link_map = it->second; - if (link_map == LLDB_INVALID_ADDRESS) + if (link_map == LLDB_INVALID_ADDRESS || link_map == 0) { + LLDB_LOGF(log, + "GetThreadLocalData error: invalid link map address=0x%" PRIx64, + link_map); return LLDB_INVALID_ADDRESS; + } const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); - if (!metadata.valid) + if (!metadata.valid) { + LLDB_LOGF(log, + "GetThreadLocalData error: fail to read thread info metadata"); return LLDB_INVALID_ADDRESS; + } + + LLDB_LOGF(log, + "GetThreadLocalData info: link_map=0x%" PRIx64 + ", thread info metadata: " + "modid_offset=0x%" PRIx32 ", dtv_offset=0x%" PRIx32 + ", tls_offset=0x%" PRIx32 ", dtv_slot_size=%" PRIx32 "\n", + link_map, metadata.modid_offset, metadata.dtv_offset, + metadata.tls_offset, metadata.dtv_slot_size); // Get the thread pointer. addr_t tp = thread->GetThreadPointer(); - if (tp == LLDB_INVALID_ADDRESS) + if (tp == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, "GetThreadLocalData error: fail to read thread pointer"); return LLDB_INVALID_ADDRESS; + } // Find the module's modid. int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit int64_t modid = ReadUnsignedIntWithSizeInBytes( link_map + metadata.modid_offset, modid_size); - if (modid == -1) + if (modid == -1) { + LLDB_LOGF(log, "GetThreadLocalData error: fail to read modid"); return LLDB_INVALID_ADDRESS; + } // Lookup the DTV structure for this thread. addr_t dtv_ptr = tp + metadata.dtv_offset; addr_t dtv = ReadPointer(dtv_ptr); - if (dtv == LLDB_INVALID_ADDRESS) + if (dtv == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, "GetThreadLocalData error: fail to read dtv"); return LLDB_INVALID_ADDRESS; + } // Find the TLS block for this module. addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid; addr_t tls_block = ReadPointer(dtv_slot + metadata.tls_offset); - Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::Performed TLS lookup: " "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 @@ -769,9 +799,10 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp, module_sp->GetObjectName().AsCString(""), link_map, tp, (int64_t)modid, tls_block); - if (tls_block == LLDB_INVALID_ADDRESS) + if (tls_block == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, "GetThreadLocalData error: fail to read tls_block"); return LLDB_INVALID_ADDRESS; - else + } else return tls_block + tls_file_addr; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h index 39428bdd0a08640..b111d8f62d1f3d7 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h @@ -71,15 +71,6 @@ nullptr, nullptr, \ } -// Note that the size and offset will be updated by platform-specific classes. -#define DEFINE_GPR_WITH_BASE(reg, alt, kind1, kind2, kind3, kind4) \ - { \ - #reg, alt, sizeof(((GPR *)nullptr)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, \ - {kind1, kind2, kind3, kind4, x86_64_with_base::lldb_##reg}, nullptr, \ - nullptr, nullptr, \ - } - #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ { \ #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ @@ -224,8 +215,8 @@ static RegisterInfo g_register_infos_x86_64_with_base[] = { DEFINE_GPR(fs, nullptr, dwarf_fs_x86_64, dwarf_fs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(gs, nullptr, dwarf_gs_x86_64, dwarf_gs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ss, nullptr, dwarf_ss_x86_64, dwarf_ss_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(fs_base, nullptr, dwarf_fs_base_x86_64, dwarf_fs_base_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(gs_base, nullptr, dwarf_gs_base_x86_64, dwarf_gs_base_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(fs_base,nullptr, dwarf_fs_base_x86_64, dwarf_fs_base_x86_64, LLDB_REGNUM_GENERIC_TP, LLDB_INVALID_REGNUM), + DEFINE_GPR(gs_base,nullptr, dwarf_gs_base_x86_64, dwarf_gs_base_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ds, nullptr, dwarf_ds_x86_64, dwarf_ds_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(es, nullptr, dwarf_es_x86_64, dwarf_es_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 65c7a0fabe90ffc..23c2f18cd388a86 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -595,6 +595,8 @@ static llvm::StringRef GetKindGenericOrEmpty(const RegisterInfo ®_info) { return "arg7"; case LLDB_REGNUM_GENERIC_ARG8: return "arg8"; + case LLDB_REGNUM_GENERIC_TP: + return "tp"; default: return ""; } diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp index 7236a45bff3b948..47c50b8a0154852 100644 --- a/lldb/source/Target/RegisterContext.cpp +++ b/lldb/source/Target/RegisterContext.cpp @@ -109,6 +109,12 @@ uint64_t RegisterContext::GetPC(uint64_t fail_value) { return pc; } +uint64_t RegisterContext::GetThreadPointer(uint64_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_TP); + return ReadRegisterAsUnsigned(reg, fail_value); +} + bool RegisterContext::SetPC(uint64_t pc) { uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index b6c19a2e0b3626a..6731b76c87b88b6 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -1622,7 +1622,11 @@ void Thread::SettingsInitialize() {} void Thread::SettingsTerminate() {} -lldb::addr_t Thread::GetThreadPointer() { return LLDB_INVALID_ADDRESS; } +lldb::addr_t Thread::GetThreadPointer() { + if (m_reg_context_sp) + return m_reg_context_sp->GetThreadPointer(); + return LLDB_INVALID_ADDRESS; +} addr_t Thread::GetThreadLocalData(const ModuleSP module, lldb::addr_t tls_file_addr) { diff --git a/lldb/source/Utility/Args.cpp b/lldb/source/Utility/Args.cpp index 000321b73694524..152be96a22128b7 100644 --- a/lldb/source/Utility/Args.cpp +++ b/lldb/source/Utility/Args.cpp @@ -445,6 +445,7 @@ uint32_t Args::StringToGenericRegister(llvm::StringRef s) { .Case("arg6", LLDB_REGNUM_GENERIC_ARG6) .Case("arg7", LLDB_REGNUM_GENERIC_ARG7) .Case("arg8", LLDB_REGNUM_GENERIC_ARG8) + .Case("tp", LLDB_REGNUM_GENERIC_TP) .Default(LLDB_INVALID_REGNUM); return result; } diff --git a/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py b/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py index 863477f9f211051..571b0eac2b46c1a 100644 --- a/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py +++ b/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py @@ -38,9 +38,8 @@ def setUp(self): # TLS works differently on Windows, this would need to be implemented # separately. @skipIfWindows - @expectedFailureAll( - bugnumber="llvm.org/pr28392", - oslist=no_match(lldbplatformutil.getDarwinOSTriples()), + @skipIf( + oslist=no_match([lldbplatformutil.getDarwinOSTriples(), "linux"]) ) def test(self): """Test thread-local storage.""" _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits