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,8 @@ virtual lldb::ByteOrder GetByteOrder(); + 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 @@ -108,6 +108,7 @@ eServerPacketType_jThreadsInfo, eServerPacketType_qsThreadInfo, eServerPacketType_qfThreadInfo, + eServerPacketType_qGetTLSAddr, eServerPacketType_qGetPid, eServerPacketType_qGetProfileData, eServerPacketType_qGDBServerVersion, diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -2498,7 +2498,7 @@ error_ptr->SetErrorString("No thread to evaluate TLS within."); return false; } - + // Lookup the TLS block address for this thread and module. const addr_t tls_file_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); 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 @@ -182,14 +182,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); } } @@ -199,7 +192,7 @@ void DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr, - bool base_addr_is_offset) { + bool base_addr_is_offset) { m_loaded_modules[module] = link_map_addr; UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); } @@ -734,48 +727,48 @@ if (it == m_loaded_modules.end()) return LLDB_INVALID_ADDRESS; - addr_t link_map = it->second; - if (link_map == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - 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) - 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) - 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) - 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 - ", 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; - else - return tls_block + tls_file_addr; + addr_t link_map = it->second; + if (link_map == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + 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) + 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) + 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) + 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 + ", 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; + else + return tls_block + tls_file_addr; } void DynamicLoaderPOSIXDYLD::ResolveExecutableModule( 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 @@ -81,6 +81,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 @@ -104,7 +106,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 @@ -110,6 +110,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 @@ -35,6 +35,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" @@ -371,6 +372,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 @@ -445,7 +445,9 @@ /// executable. If successful, the returned structure will contain at least /// one value in the offsets field. llvm::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 @@ -3759,6 +3759,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 @@ -179,6 +179,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 @@ -149,6 +149,9 @@ RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qsThreadInfo, &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qGetTLSAddr, + &GDBRemoteCommunicationServerLLGS::Handle_qGetTLSAddr); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo, &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo); @@ -2110,6 +2113,28 @@ 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); + NativeThreadProtocol *ntp = m_current_process->GetThreadByID(tid); + NativeRegisterContext ®_ctx = ntp->GetRegisterContext(); + lldb::addr_t tls_addr = LLDB_INVALID_ADDRESS; + StreamGDBRemote response; + if(!reg_ctx.ReadThreadPointer(tls_addr).Fail()) { + response.PutHex64(tls_addr, 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 @@ -1646,7 +1646,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 @@ -209,6 +209,8 @@ return eServerPacketType_qGetProfileData; if (PACKET_MATCHES("qGDBServerVersion")) return eServerPacketType_qGDBServerVersion; + if (PACKET_STARTS_WITH("qGetTLSAddr")) + return eServerPacketType_qGetTLSAddr; break; case 'H':