diff options
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
5 files changed, 113 insertions, 50 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 978daa7e9ca..eaf91eb98b1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -39,7 +39,6 @@ GDBRemoteRegisterContext::GDBRemoteRegisterContext RegisterContext (thread, concrete_frame_idx), m_reg_info (reg_info), m_reg_valid (), - m_reg_valid_stop_id (), m_reg_data (), m_read_all_at_once (read_all_at_once) { @@ -74,7 +73,7 @@ GDBRemoteRegisterContext::GetGDBThread() } void -GDBRemoteRegisterContext::Invalidate () +GDBRemoteRegisterContext::InvalidateAllRegisters () { SetAllRegisterValid (false); } @@ -179,25 +178,41 @@ GDBRemoteRegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value) return false; } +void +GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response) +{ + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); + assert (reg_info); + + // Invalidate if needed + InvalidateIfNeeded(false); + + const uint32_t reg_byte_size = reg_info->byte_size; + const size_t bytes_copied = response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc'); + bool success = bytes_copied == reg_byte_size; + if (success) + { + m_reg_valid[reg] = true; + } + else if (bytes_copied > 0) + { + // Only set register is valid to false if we copied some bytes, else + // leave it as it was. + m_reg_valid[reg] = false; + } +} + bool GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data) { GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote(); -// FIXME: This check isn't right because IsRunning checks the Public state, but this -// is work you need to do - for instance in ShouldStop & friends - before the public -// state has been changed. -// if (gdb_comm.IsRunning()) -// return false; - if (m_reg_valid_stop_id != m_thread.GetProcess().GetStopID()) - { - Invalidate(); - m_reg_valid_stop_id = m_thread.GetProcess().GetStopID(); - } + InvalidateIfNeeded(false); + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); assert (reg_info); - if (m_reg_valid[reg] == false) + if (!m_reg_valid[reg]) { Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker)) @@ -225,28 +240,27 @@ GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data) packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); assert (packet_len < (sizeof(packet) - 1)); if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false)) - if (response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)), reg_info->byte_size, '\xcc') == reg_info->byte_size) - m_reg_valid[reg] = true; + PrivateSetRegisterValue (reg, response); } } } + + // Make sure we got a valid register value after reading it + if (!m_reg_valid[reg]) + return false; } - bool reg_is_valid = m_reg_valid[reg]; - if (reg_is_valid) + if (&data != &m_reg_data) { - if (&data != &m_reg_data) - { - // If we aren't extracting into our own buffer (which - // only happens when this function is called from - // ReadRegisterValue(uint32_t, Scalar&)) then - // we transfer bytes from our buffer into the data - // buffer that was passed in - data.SetByteOrder (m_reg_data.GetByteOrder()); - data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size); - } + // If we aren't extracting into our own buffer (which + // only happens when this function is called from + // ReadRegisterValue(uint32_t, Scalar&)) then + // we transfer bytes from our buffer into the data + // buffer that was passed in + data.SetByteOrder (m_reg_data.GetByteOrder()); + data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size); } - return reg_is_valid; + return true; } @@ -323,8 +337,8 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, eByteOrderHost); // Invalidate all register values - Invalidate (); - + InvalidateIfNeeded (true); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index e20da52527b..72c640ff7a8 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -25,6 +25,7 @@ class ThreadGDBRemote; class ProcessGDBRemote; +class StringExtractor; class GDBRemoteDynamicRegisterInfo { @@ -189,7 +190,7 @@ public: // Subclasses must override these functions //------------------------------------------------------------------ virtual void - Invalidate (); + InvalidateAllRegisters (); virtual size_t GetRegisterCount (); @@ -225,8 +226,12 @@ public: ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); protected: + friend class ThreadGDBRemote; void + PrivateSetRegisterValue (uint32_t reg, StringExtractor &response); + + void SetAllRegisterValid (bool b); ProcessGDBRemote & @@ -237,7 +242,6 @@ protected: GDBRemoteDynamicRegisterInfo &m_reg_info; std::vector<bool> m_reg_valid; - uint32_t m_reg_valid_stop_id; lldb_private::DataExtractor m_reg_data; bool m_read_all_at_once; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 3775d5b9ff6..cee3e6fd8b9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -975,9 +975,7 @@ ProcessGDBRemote::UpdateThreadListIfNeeded () if (tid != LLDB_INVALID_THREAD_ID) { ThreadSP thread_sp (GetThreadList().FindThreadByID (tid, false)); - if (thread_sp) - thread_sp->GetRegisterContext()->Invalidate(); - else + if (!thread_sp) thread_sp.reset (new ThreadGDBRemote (*this, tid)); curr_thread_list.AddThread(thread_sp); } @@ -1014,6 +1012,8 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) uint32_t tid = LLDB_INVALID_THREAD_ID; addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; uint32_t exc_data_count = 0; + ThreadSP thread_sp; + while (stop_packet.GetNameColonValue(name, value)) { if (name.compare("metype") == 0) @@ -1035,6 +1035,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) { // thread in big endian hex tid = Args::StringToUInt32 (value.c_str(), 0, 16); + thread_sp = m_thread_list.FindThreadByID(tid, false); } else if (name.compare("hexname") == 0) { @@ -1053,8 +1054,25 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) { thread_dispatch_qaddr = Args::StringToUInt64 (value.c_str(), 0, 16); } + else if (name.size() == 2 && ::isxdigit(name[0]) && ::isxdigit(name[1])) + { + // We have a register number that contains an expedited + // register value. Lets supply this register to our thread + // so it won't have to go and read it. + if (thread_sp) + { + uint32_t reg = Args::StringToUInt32 (name.c_str(), UINT32_MAX, 16); + + if (reg != UINT32_MAX) + { + StringExtractor reg_value_extractor; + // Swap "value" over into "reg_value_extractor" + reg_value_extractor.GetStringRef().swap(value); + static_cast<ThreadGDBRemote *> (thread_sp.get())->PrivateSetRegisterValue (reg, reg_value_extractor); + } + } + } } - ThreadSP thread_sp (m_thread_list.FindThreadByID(tid, false)); if (thread_sp) { diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 091feb9e649..b8108bfd383 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -37,7 +37,8 @@ ThreadGDBRemote::ThreadGDBRemote (ProcessGDBRemote &process, lldb::tid_t tid) : Thread(process, tid), m_thread_name (), m_dispatch_queue_name (), - m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS) + m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS), + m_thread_stop_reason_stop_id (0) { // ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD | GDBR_LOG_VERBOSE, "ThreadGDBRemote::ThreadGDBRemote ( pid = %i, tid = 0x%4.4x, )", m_process.GetID(), GetID()); ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID()); @@ -116,14 +117,18 @@ ThreadGDBRemote::WillResume (StateType resume_state) void ThreadGDBRemote::RefreshStateAfterStop() { - // Invalidate all registers in our register context - GetRegisterContext()->Invalidate(); + // Invalidate all registers in our register context. We don't set "force" to + // true because the stop reply packet might have had some register values + // that were expedited and these will already be copied into the register + // context by the time this function gets called. The GDBRemoteRegisterContext + // class has been made smart enough to detect when it needs to invalidate + // which registers are valid by putting hooks in the register read and + // register supply functions where they check the process stop ID and do + // the right thing. + const bool force = false; + GetRegisterContext()->InvalidateIfNeeded (force); } -// Whether to use the new native unwinder (UnwindLLDB) or the libunwind-remote based unwinder for -// stack walks on i386/x86_64 -#define USE_NATIVE_UNWINDER - Unwind * ThreadGDBRemote::GetUnwinder () { @@ -132,11 +137,7 @@ ThreadGDBRemote::GetUnwinder () const ArchSpec target_arch (GetProcess().GetTarget().GetArchitecture ()); if (target_arch == ArchSpec("x86_64") || target_arch == ArchSpec("i386")) { -#if defined (USE_NATIVE_UNWINDER) m_unwinder_ap.reset (new UnwindLLDB (*this)); -#else - m_unwinder_ap.reset (new UnwindLibUnwind (*this, GetGDBProcess().GetLibUnwindAddressSpace())); -#endif } else { @@ -198,6 +199,14 @@ ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame) return reg_ctx_sp; } +void +ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response) +{ + GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get()); + assert (gdb_reg_ctx); + gdb_reg_ctx->PrivateSetRegisterValue (reg, response); +} + bool ThreadGDBRemote::SaveFrameZeroState (RegisterCheckpoint &checkpoint) { @@ -217,7 +226,7 @@ ThreadGDBRemote::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint) if (frame_sp) { bool ret = frame_sp->GetRegisterContext()->WriteAllRegisterValues (checkpoint.GetData()); - frame_sp->GetRegisterContext()->Invalidate(); + frame_sp->GetRegisterContext()->InvalidateIfNeeded(true); ClearStackFrames(); return ret; } @@ -227,8 +236,19 @@ ThreadGDBRemote::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint) lldb::StopInfoSP ThreadGDBRemote::GetPrivateStopReason () { - if (m_actual_stop_info_sp.get() == NULL || m_actual_stop_info_sp->IsValid() == false) + const uint32_t process_stop_id = GetProcess().GetStopID(); + if (m_thread_stop_reason_stop_id != process_stop_id || + (m_actual_stop_info_sp && !m_actual_stop_info_sp->IsValid())) { + // If GetGDBProcess().SetThreadStopInfo() doesn't find a stop reason + // for this thread, then m_actual_stop_info_sp will not ever contain + // a valid stop reason and the "m_actual_stop_info_sp->IsValid() == false" + // check will never be able to tell us if we have the correct stop info + // for this thread and we will continually send qThreadStopInfo packets + // down to the remote GDB server, so we need to keep our own notion + // of the stop ID that m_actual_stop_info_sp is valid for (even if it + // contains nothing). We use m_thread_stop_reason_stop_id for this below. + m_thread_stop_reason_stop_id = process_stop_id; m_actual_stop_info_sp.reset(); char packet[256]; @@ -236,7 +256,6 @@ ThreadGDBRemote::GetPrivateStopReason () StringExtractorGDBRemote stop_packet; if (GetGDBProcess().GetGDBRemote().SendPacketAndWaitForResponse(packet, stop_packet, 1, false)) { - std::string copy(stop_packet.GetStringRef()); GetGDBProcess().SetThreadStopInfo (stop_packet); } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 37aae88ed34..3bf54afa9be 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -108,12 +108,20 @@ public: } protected: + + friend class ProcessGDBRemote; + + void + PrivateSetRegisterValue (uint32_t reg, + StringExtractor &response); + //------------------------------------------------------------------ // Member variables. //------------------------------------------------------------------ std::string m_thread_name; std::string m_dispatch_queue_name; lldb::addr_t m_thread_dispatch_qaddr; + uint32_t m_thread_stop_reason_stop_id; //------------------------------------------------------------------ // Member variables. //------------------------------------------------------------------ |

