Author: jmolenda Date: Thu Dec 17 18:45:35 2015 New Revision: 255942 URL: http://llvm.org/viewvc/llvm-project?rev=255942&view=rev Log: The lldb side changes to go along with r255711 where a new "thread-pcs" key is added to the T (questionmark) packet in gdb-remote protocol so that lldb doesn't need to query the pc values of every thread before it resumes a process.
The only odd part with this is that I'm sending the pc values in big endian order, so we need to know the endianness of the remote process before we can use them. All other register values in gdb-remote protocol are sent in native-endian format so this requirement doesn't exist. This addition is a performance enhancement -- lldb will fall back to querying the pc of each thread individually if it needs to -- so when we don't have the byte order for the process yet, we don't use these values. Practically speaking, the only way I've been able to elicit this condition is for the first T packet when we attach to a process. <rdar://problem/21963031> Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp?rev=255942&r1=255941&r2=255942&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp Thu Dec 17 18:45:35 2015 @@ -147,6 +147,52 @@ GDBRemoteRegisterContext::PrivateSetRegi return success; } +bool +GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, uint64_t new_reg_val) +{ + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); + if (reg_info == NULL) + return false; + + // Early in process startup, we can get a thread that has an invalid byte order + // because the process hasn't been completely set up yet (see the ctor where the + // byte order is setfrom the process). If that's the case, we can't set the + // value here. + if (m_reg_data.GetByteOrder() == eByteOrderInvalid) + { + return false; + } + + // Invalidate if needed + InvalidateIfNeeded (false); + + DataBufferSP buffer_sp (new DataBufferHeap (&new_reg_val, sizeof (new_reg_val))); + DataExtractor data (buffer_sp, endian::InlHostByteOrder(), sizeof (void*)); + + // If our register context and our register info disagree, which should never happen, don't + // overwrite past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + + // Grab a pointer to where we are going to put this register + uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); + + if (dst == NULL) + return false; + + + if (data.CopyByteOrderedData (0, // src offset + reg_info->byte_size, // src length + dst, // dst + reg_info->byte_size, // dst length + m_reg_data.GetByteOrder())) // dst byte order + { + SetRegisterIsValid (reg, true); + return true; + } + return false; +} + // Helper function for GDBRemoteRegisterContext::ReadRegisterBytes(). bool GDBRemoteRegisterContext::GetPrimordialRegister(const RegisterInfo *reg_info, Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h?rev=255942&r1=255941&r2=255942&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h Thu Dec 17 18:45:35 2015 @@ -109,6 +109,9 @@ protected: bool PrivateSetRegisterValue (uint32_t reg, StringExtractor &response); + bool + PrivateSetRegisterValue (uint32_t reg, uint64_t val); + void SetAllRegisterValid (bool b); Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=255942&r1=255941&r2=255942&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Thu Dec 17 18:45:35 2015 @@ -390,6 +390,7 @@ ProcessGDBRemote::ProcessGDBRemote(lldb: m_async_listener("lldb.process.gdb-remote.async-listener"), m_async_thread_state_mutex(Mutex::eMutexTypeRecursive), m_thread_ids (), + m_thread_pcs (), m_jstopinfo_sp (), m_jthreadsinfo_sp (), m_continue_c_tids (), @@ -1751,12 +1752,14 @@ ProcessGDBRemote::ClearThreadIDList () { Mutex::Locker locker(m_thread_list_real.GetMutex()); m_thread_ids.clear(); + m_thread_pcs.clear(); } size_t ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue (std::string &value) { m_thread_ids.clear(); + m_thread_pcs.clear(); size_t comma_pos; lldb::tid_t tid; while ((comma_pos = value.find(',')) != std::string::npos) @@ -1774,6 +1777,26 @@ ProcessGDBRemote::UpdateThreadIDsFromSto return m_thread_ids.size(); } +size_t +ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue (std::string &value) +{ + m_thread_pcs.clear(); + size_t comma_pos; + lldb::addr_t pc; + while ((comma_pos = value.find(',')) != std::string::npos) + { + value[comma_pos] = '\0'; + pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); + if (pc != LLDB_INVALID_ADDRESS) + m_thread_pcs.push_back (pc); + value.erase(0, comma_pos + 1); + } + pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); + if (pc != LLDB_INVALID_THREAD_ID) + m_thread_pcs.push_back (pc); + return m_thread_pcs.size(); +} + bool ProcessGDBRemote::UpdateThreadIDList () { @@ -1786,6 +1809,7 @@ ProcessGDBRemote::UpdateThreadIDList () if (thread_infos && thread_infos->GetSize() > 0) { m_thread_ids.clear(); + m_thread_pcs.clear(); thread_infos->ForEach([this](StructuredData::Object* object) -> bool { StructuredData::Dictionary *thread_dict = object->GetAsDictionary(); if (thread_dict) @@ -1820,6 +1844,20 @@ ProcessGDBRemote::UpdateThreadIDList () // Get the thread stop info StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; const std::string &stop_info_str = stop_info.GetStringRef(); + + m_thread_pcs.clear(); + const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:"); + if (thread_pcs_pos != std::string::npos) + { + const size_t start = thread_pcs_pos + strlen(";thread-pcs:"); + const size_t end = stop_info_str.find(';', start); + if (end != std::string::npos) + { + std::string value = stop_info_str.substr(start, end - start); + UpdateThreadPCsFromStopReplyThreadsValue(value); + } + } + const size_t threads_pos = stop_info_str.find(";threads:"); if (threads_pos != std::string::npos) { @@ -1887,6 +1925,25 @@ ProcessGDBRemote::UpdateThreadList (Thre __FUNCTION__, static_cast<void*>(thread_sp.get()), thread_sp->GetID()); } + // The m_thread_pcs vector has pc values in big-endian order, not target-endian, unlike most + // of the register read/write packets in gdb-remote protocol. + // Early in the process startup, we may not yet have set the process ByteOrder so we ignore these; + // they are a performance improvement over fetching thread register values individually, the + // method we will fall back to if needed. + if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() && GetByteOrder() != eByteOrderInvalid) + { + ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get()); + RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext()); + if (reg_ctx_sp) + { + uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber + (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + if (pc_regnum != LLDB_INVALID_REGNUM) + { + gdb_thread->PrivateSetRegisterValue (pc_regnum, m_thread_pcs[i]); + } + } + } new_thread_list.AddThread(thread_sp); } } @@ -2447,6 +2504,27 @@ ProcessGDBRemote::SetThreadStopInfo (Str if (tid != LLDB_INVALID_THREAD_ID) m_thread_ids.push_back (tid); } + else if (key.compare("thread-pcs") == 0) + { + m_thread_pcs.clear(); + // A comma separated list of all threads in the current + // process that includes the thread for this stop reply + // packet + size_t comma_pos; + lldb::addr_t pc; + while ((comma_pos = value.find(',')) != std::string::npos) + { + value[comma_pos] = '\0'; + // thread in big endian hex + pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); + if (pc != LLDB_INVALID_ADDRESS) + m_thread_pcs.push_back (pc); + value.erase(0, comma_pos + 1); + } + pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); + if (pc != LLDB_INVALID_ADDRESS) + m_thread_pcs.push_back (pc); + } else if (key.compare("jstopinfo") == 0) { StringExtractor json_extractor; @@ -2624,6 +2702,7 @@ ProcessGDBRemote::RefreshStateAfterStop { Mutex::Locker locker(m_thread_list_real.GetMutex()); m_thread_ids.clear(); + m_thread_pcs.clear(); // Set the thread stop info. It might have a "threads" key whose value is // a list of all thread IDs in the current process, so m_thread_ids might // get set. Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=255942&r1=255941&r2=255942&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Thu Dec 17 18:45:35 2015 @@ -288,6 +288,7 @@ protected: typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap; typedef std::map<uint32_t, std::string> ExpeditedRegisterMap; tid_collection m_thread_ids; // Thread IDs for all threads. This list gets updated after stopping + std::vector<lldb::addr_t> m_thread_pcs; // PC values for all the threads. StructuredData::ObjectSP m_jstopinfo_sp; // Stop info only for any threads that have valid stop infos StructuredData::ObjectSP m_jthreadsinfo_sp; // Full stop info, expedited registers and memory for all threads if "jThreadsInfo" packet is supported tid_collection m_continue_c_tids; // 'c' for continue @@ -384,6 +385,9 @@ protected: CalculateThreadStopInfo (ThreadGDBRemote *thread); size_t + UpdateThreadPCsFromStopReplyThreadsValue (std::string &value); + + size_t UpdateThreadIDsFromStopReplyThreadsValue (std::string &value); bool Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp?rev=255942&r1=255941&r2=255942&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp Thu Dec 17 18:45:35 2015 @@ -313,6 +313,14 @@ ThreadGDBRemote::PrivateSetRegisterValue } bool +ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, uint64_t regval) +{ + GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get()); + assert (gdb_reg_ctx); + return gdb_reg_ctx->PrivateSetRegisterValue (reg, regval); +} + +bool ThreadGDBRemote::CalculateStopInfo () { ProcessSP process_sp (GetProcess()); Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h?rev=255942&r1=255941&r2=255942&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h Thu Dec 17 18:45:35 2015 @@ -117,6 +117,10 @@ protected: StringExtractor &response); bool + PrivateSetRegisterValue (uint32_t reg, + uint64_t regval); + + bool CachedQueueInfoIsValid() const { return m_queue_kind != lldb::eQueueKindUnknown; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits