diff --git a/lldb/include/lldb/Host/common/NativeRegisterContext.h b/lldb/include/lldb/Host/common/NativeRegisterContext.h --- a/lldb/include/lldb/Host/common/NativeRegisterContext.h +++ b/lldb/include/lldb/Host/common/NativeRegisterContext.h @@ -48,6 +48,8 @@ virtual Status ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) = 0; + virtual Status ReadThreadPointer(uint64_t &tp); + virtual Status WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value) = 0; diff --git a/lldb/include/lldb/Target/RegisterContext.h b/lldb/include/lldb/Target/RegisterContext.h --- a/lldb/include/lldb/Target/RegisterContext.h +++ b/lldb/include/lldb/Target/RegisterContext.h @@ -37,6 +37,15 @@ virtual lldb::ByteOrder GetByteOrder(); + /// Retrieves the per-thread data area. + /// Most OSs maintain a per-thread pointer (e.g. the FS register on + /// x64), which we return the value of here. + /// + /// \return + /// LLDB_INVALID_ADDRESS if not supported, otherwise the thread + /// pointer value. + virtual uint64_t GetThreadPointer(); + virtual bool ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) = 0; diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -109,6 +109,7 @@ eServerPacketType_jThreadsInfo, eServerPacketType_qsThreadInfo, eServerPacketType_qfThreadInfo, + eServerPacketType_qGetTLSAddr, eServerPacketType_qGetPid, eServerPacketType_qGetProfileData, eServerPacketType_qGDBServerVersion, diff --git a/lldb/source/Host/common/NativeRegisterContext.cpp b/lldb/source/Host/common/NativeRegisterContext.cpp --- a/lldb/source/Host/common/NativeRegisterContext.cpp +++ b/lldb/source/Host/common/NativeRegisterContext.cpp @@ -120,6 +120,12 @@ return nullptr; } +Status NativeRegisterContext::ReadThreadPointer(uint64_t& tp) { + tp = LLDB_INVALID_ADDRESS; + Status error; + return error; +} + lldb::addr_t NativeRegisterContext::GetPC(lldb::addr_t fail_value) { Log *log = GetLog(LLDBLog::Thread); diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -183,14 +183,7 @@ LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()", __FUNCTION__); - - if (!SetRendezvousBreakpoint()) { - // If we cannot establish rendezvous breakpoint right now we'll try again - // at entry point. - ProbeEntry(); - } - - LoadVDSO(); + ProbeEntry(); m_process->GetTarget().ModulesDidLoad(module_list); } } @@ -738,7 +731,6 @@ const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); if (!metadata.valid) return LLDB_INVALID_ADDRESS; - // Get the thread pointer. addr_t tp = thread->GetThreadPointer(); if (tp == LLDB_INVALID_ADDRESS) @@ -747,7 +739,7 @@ // 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); + link_map + metadata.modid_offset, modid_size); if (modid == -1) return LLDB_INVALID_ADDRESS; @@ -763,11 +755,11 @@ Log *log = GetLog(LLDBLog::DynamicLoader); LLDB_LOGF(log, - "DynamicLoaderPOSIXDYLD::Performed TLS lookup: " - "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 - ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n", - module_sp->GetObjectName().AsCString(""), link_map, tp, - (int64_t)modid, tls_block); + "DynamicLoaderPOSIXDYLD::Performed TLS lookup: " + "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 + ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n", + module_sp->GetObjectName().AsCString(""), link_map, tp, + (int64_t)modid, tls_block); if (tls_block == LLDB_INVALID_ADDRESS) return LLDB_INVALID_ADDRESS; diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h @@ -82,6 +82,8 @@ "Architecture does not support memory tagging"); } + virtual Status ReadThreadPointer(uint64_t &tp) override; + protected: // NB: This constructor is here only because gcc<=6.5 requires a virtual base // class initializer on abstract class (even though it is never used). It can @@ -105,7 +107,6 @@ virtual Status ReadGPR(); virtual Status WriteGPR(); - virtual Status ReadFPR(); virtual Status WriteFPR(); diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -112,6 +112,12 @@ GetFPRSize()); } +Status NativeRegisterContextLinux::ReadThreadPointer(uint64_t &tp) { + tp = LLDB_INVALID_ADDRESS; + Status error; + return error; +} + Status NativeRegisterContextLinux::WriteFPR() { return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), nullptr, GetFPRBuffer(), diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -37,6 +37,8 @@ uint32_t GetUserRegisterCount() const override; + Status ReadThreadPointer(uint64_t &tp) override; + Status ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) override; diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -13,6 +13,7 @@ #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/linux/Ptrace.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" @@ -373,6 +374,16 @@ m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset; } +Status NativeRegisterContextLinux_x86_64::ReadThreadPointer(uint64_t& tp) { + Status error; + errno = 0; + auto ret= ptrace(static_cast<__ptrace_request>(PTRACE_ARCH_PRCTL), m_thread.GetID(), + &tp, (void *)ARCH_GET_FS, 0); + if (ret == -1) + error.SetErrorToErrno(); + return error; +} + // CONSIDER after local and llgs debugging are merged, register set support can // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual. uint32_t NativeRegisterContextLinux_x86_64::GetRegisterSetCount() const { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -443,6 +443,8 @@ /// one value in the offsets field. std::optional GetQOffsets(); + lldb::addr_t GetQGetTLSAddr(lldb::tid_t tid, lldb::addr_t offset, lldb::addr_t lms); + bool GetModuleInfo(const FileSpec &module_file_spec, const ArchSpec &arch_spec, ModuleSpec &module_spec); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3752,6 +3752,28 @@ return std::nullopt; } +lldb::addr_t GDBRemoteCommunicationClient::GetQGetTLSAddr(lldb::tid_t tid, lldb::addr_t offset, lldb::addr_t lm) { + StreamString packet; + packet.PutCString("qGetTLSAddr:"); + packet.PutHex64(tid, lldb::eByteOrderBig); + packet.PutCString(","); + packet.PutHex64(offset, lldb::eByteOrderBig); + packet.PutCString(","); + packet.PutHex64(lm, lldb::eByteOrderBig); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response) != + PacketResult::Success) + return LLDB_INVALID_ADDRESS; + if (response.IsErrorResponse()) + return LLDB_INVALID_ADDRESS; + if (response.IsUnsupportedResponse()) + return LLDB_INVALID_ADDRESS; + llvm::StringRef ref = response.GetStringRef(); + uint64_t addr = LLDB_INVALID_ADDRESS; + ref.consumeInteger(16, addr); + return addr; +} + bool GDBRemoteCommunicationClient::GetModuleInfo( const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec, ModuleSpec &module_spec) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -185,6 +185,8 @@ PacketResult Handle_qsThreadInfo(StringExtractorGDBRemote &packet); + PacketResult Handle_qGetTLSAddr(StringExtractorGDBRemote &packet); + PacketResult Handle_p(StringExtractorGDBRemote &packet); PacketResult Handle_P(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -148,6 +148,9 @@ RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qsThreadInfo, &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qGetTLSAddr, + &GDBRemoteCommunicationServerLLGS::Handle_qGetTLSAddr); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo, &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo); @@ -2108,6 +2111,30 @@ return SendPacketNoLock("l"); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qGetTLSAddr( + StringExtractorGDBRemote &packet) { + llvm::StringRef s = packet.GetStringRef(); + if (!s.consume_front("qGetTLSAddr:")) + return SendErrorResponse(8); + llvm::SmallVector argv; + s.split(argv, ','); + lldb::tid_t tid = StringExtractor(argv[0]).GetU64(LLDB_INVALID_ADDRESS, 16); + lldb::addr_t offset = StringExtractor(argv[1]).GetU64(LLDB_INVALID_ADDRESS, 16); + lldb::addr_t lm = StringExtractor(argv[2]).GetU64(LLDB_INVALID_ADDRESS, 16); + (void) offset; + (void) lm; + NativeThreadProtocol *ntp = m_current_process->GetThreadByID(tid); + NativeRegisterContext ®_ctx = ntp->GetRegisterContext(); + lldb::addr_t tp = LLDB_INVALID_ADDRESS; + StreamGDBRemote response; + if(!reg_ctx.ReadThreadPointer(tp).Fail()) { + response.PutHex64(tp, lldb::eByteOrderBig); + return SendPacketNoLock(response.GetString()); + } else + return SendErrorResponse(8); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Thread); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -55,6 +55,8 @@ const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; + uint64_t GetThreadPointer() override; + size_t GetRegisterSetCount() override; const RegisterSet *GetRegisterSet(size_t reg_set) override; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -80,6 +80,19 @@ return m_reg_info_sp->GetRegisterSet(reg_set); } +uint64_t GDBRemoteRegisterContext::GetThreadPointer() { + ExecutionContext exe_ctx(CalculateThread()); + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == nullptr || thread == nullptr) + return LLDB_INVALID_ADDRESS; + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); + uint64_t tid = thread->GetProtocolID(); + // Return thread pointer here, offset and link_map will be filled by GetThreadLocalData in DYLD + return gdb_comm.GetQGetTLSAddr(tid, LLDB_INVALID_ADDRESS /* offset */, LLDB_INVALID_ADDRESS /* lm */); +} + bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { // Read the register diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp --- a/lldb/source/Target/RegisterContext.cpp +++ b/lldb/source/Target/RegisterContext.cpp @@ -29,6 +29,10 @@ RegisterContext::~RegisterContext() = default; +uint64_t RegisterContext::GetThreadPointer() { + return UINT64_MAX; +} + void RegisterContext::InvalidateIfNeeded(bool force) { ProcessSP process_sp(m_thread.GetProcess()); bool invalidate = force; diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -1623,7 +1623,11 @@ void Thread::SettingsTerminate() {} -lldb::addr_t Thread::GetThreadPointer() { return LLDB_INVALID_ADDRESS; } +lldb::addr_t Thread::GetThreadPointer() { + RegisterContext *reg_ctx = this->GetRegisterContext().get(); + auto tp = reg_ctx->GetThreadPointer(); + return tp; +} addr_t Thread::GetThreadLocalData(const ModuleSP module, lldb::addr_t tls_file_addr) { diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -210,6 +210,8 @@ return eServerPacketType_qGetProfileData; if (PACKET_MATCHES("qGDBServerVersion")) return eServerPacketType_qGDBServerVersion; + if (PACKET_STARTS_WITH("qGetTLSAddr")) + return eServerPacketType_qGetTLSAddr; break; case 'H': diff --git a/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py b/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py --- a/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py +++ b/lldb/test/API/lang/c/tls_globals/TestTlsGlobals.py @@ -37,11 +37,7 @@ # TLS works differently on Windows, this would need to be implemented # separately. - @skipIfWindows - @expectedFailureAll( - bugnumber="llvm.org/pr28392", - oslist=no_match(lldbplatformutil.getDarwinOSTriples()), - ) + @skipIf(archs=no_match(['x86_64']), oslist=no_match(['linux'])) def test(self): """Test thread-local storage.""" self.build()