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 llvm::Expected ReadThreadPointer(); + virtual Status WriteRegister(const RegisterInfo *reg_info, const 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; } +llvm::Expected NativeRegisterContext::ReadThreadPointer() { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Architecture does not implement Reading Thread Pointer"); +} + 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); } } 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 @@ -105,7 +105,6 @@ virtual Status ReadGPR(); virtual Status WriteGPR(); - virtual Status ReadFPR(); virtual Status WriteFPR(); 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; + llvm::Expected ReadThreadPointer() 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,19 @@ m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset; } +llvm::Expected NativeRegisterContextLinux_x86_64::ReadThreadPointer() { + Status error; + uint64_t tp; + 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.ToError(); + } + return tp; +} + // 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,36 @@ 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(); + StreamGDBRemote response; + llvm::Expected tp = reg_ctx.ReadThreadPointer(); + if (llvm::Error E = tp.takeError()) { + std::string Str; + raw_string_ostream OS(Str); + OS << E << "\n"; + Log *log = GetLog(LLDBLog::Thread); + LLDB_LOG(log, "{0}", Str); + return SendErrorResponse(8); + } else { + response.PutHex64(*tp, lldb::eByteOrderBig); + return SendPacketNoLock(response.GetString()); + } +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) { Log *log = GetLog(LLDBLog::Thread); diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -71,6 +71,8 @@ m_thread_name.clear(); } + lldb::addr_t GetThreadPointer() override; + lldb::addr_t GetThreadDispatchQAddr() { return m_thread_dispatch_qaddr; } void SetThreadDispatchQAddr(lldb::addr_t thread_dispatch_qaddr) { diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -66,6 +66,15 @@ return m_thread_name.c_str(); } +lldb::addr_t ThreadGDBRemote::GetThreadPointer() { + ProcessSP process_sp(GetProcess()); + ProcessGDBRemote *gdb_process = + static_cast(process_sp.get()); + uint64_t tid = this->GetProtocolID(); + // Return thread pointer here, offset and link_map will be filled by GetThreadLocalData in DYLD + return gdb_process->m_gdb_comm.GetQGetTLSAddr(tid, LLDB_INVALID_ADDRESS /* offset */, LLDB_INVALID_ADDRESS /* lm */); +} + void ThreadGDBRemote::ClearQueueInfo() { m_dispatch_queue_name.clear(); m_queue_kind = eQueueKindUnknown; 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()