diff options
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
4 files changed, 242 insertions, 88 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 2ac7d20c6c6..da2299a408c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -65,6 +65,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), + m_supports_QSaveRegisterState (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -208,6 +209,7 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_vCont_s = eLazyBoolCalculate; m_supports_vCont_S = eLazyBoolCalculate; m_supports_p = eLazyBoolCalculate; + m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; m_qProcessInfo_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; @@ -2809,3 +2811,134 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s } return false; } + +bool +GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) +{ + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[64]; + int packet_len = 0; + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid); + else + packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); + assert (packet_len < ((int)sizeof(packet) - 1)); + return SendPacketAndWaitForResponse(packet, response, false); + } + } + return false; + +} + + +bool +GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response) +{ + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[64]; + int packet_len = 0; + // Get all registers in one packet + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); + assert (packet_len < ((int)sizeof(packet) - 1)); + return SendPacketAndWaitForResponse(packet, response, false); + } + } + return false; +} +bool +GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id) +{ + save_id = 0; // Set to invalid save ID + if (m_supports_QSaveRegisterState == eLazyBoolNo) + return false; + + m_supports_QSaveRegisterState = eLazyBoolYes; + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[256]; + if (thread_suffix_supported) + ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid); + else + ::strncpy (packet, "QSaveRegisterState", sizeof(packet)); + + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false)) + { + if (response.IsUnsupportedResponse()) + { + // This packet isn't supported, don't try calling it again + m_supports_QSaveRegisterState = eLazyBoolNo; + } + + const uint32_t response_save_id = response.GetU32(0); + if (response_save_id != 0) + { + save_id = response_save_id; + return true; + } + } + } + } + return false; +} + +bool +GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) +{ + // We use the "m_supports_QSaveRegisterState" variable here becuase the + // QSaveRegisterState and QRestoreRegisterState packets must both be supported in + // order to be useful + if (m_supports_QSaveRegisterState == eLazyBoolNo) + return false; + + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[256]; + if (thread_suffix_supported) + ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid); + else + ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id); + + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false)) + { + if (response.IsOKResponse()) + { + return true; + } + else if (response.IsUnsupportedResponse()) + { + // This packet isn't supported, don't try calling this packet or + // QSaveRegisterState again... + m_supports_QSaveRegisterState = eLazyBoolNo; + } + } + } + } + return false; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index d5535bbb1df..530655bab6e 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -411,6 +411,21 @@ public: HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process, StringExtractorGDBRemote &inputStringExtractor); + bool + ReadRegister(lldb::tid_t tid, + uint32_t reg_num, + StringExtractorGDBRemote &response); + + bool + ReadAllRegisters (lldb::tid_t tid, + StringExtractorGDBRemote &response); + + bool + SaveRegisterState (lldb::tid_t tid, uint32_t &save_id); + + bool + RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); + protected: bool @@ -438,6 +453,7 @@ protected: lldb_private::LazyBool m_attach_or_wait_reply; lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; + lldb_private::LazyBool m_supports_QSaveRegisterState; bool m_supports_qProcessInfoPID:1, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index c4e468f89f3..c291df786d1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -153,20 +153,13 @@ bool GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { - char packet[64]; - StringExtractorGDBRemote response; - int packet_len = 0; const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (gdb_comm.GetThreadSuffixSupported()) - packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); - assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false)) + StringExtractorGDBRemote response; + if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), reg, response)) return PrivateSetRegisterValue (reg, response); - return false; } + bool GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data) { @@ -185,93 +178,51 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE if (!GetRegisterIsValid(reg)) { - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read register.")) + if (m_read_all_at_once) { - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) + StringExtractorGDBRemote response; + if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response)) + return false; + if (response.IsNormalResponse()) + if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) + SetAllRegisterValid (true); + } + else if (reg_info->value_regs) + { + // Process this composite register request by delegating to the constituent + // primordial registers. + + // Index of the primordial register. + bool success = true; + for (uint32_t idx = 0; success; ++idx) { - char packet[64]; - StringExtractorGDBRemote response; - int packet_len = 0; - if (m_read_all_at_once) - { - // Get all registers in one packet - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false)) - { - if (response.IsNormalResponse()) - if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) - SetAllRegisterValid (true); - } - } - else if (reg_info->value_regs) - { - // Process this composite register request by delegating to the constituent - // primordial registers. - - // Index of the primordial register. - bool success = true; - for (uint32_t idx = 0; success; ++idx) - { - const uint32_t prim_reg = reg_info->value_regs[idx]; - if (prim_reg == LLDB_INVALID_REGNUM) - break; - // We have a valid primordial regsiter as our constituent. - // Grab the corresponding register info. - const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); - if (prim_reg_info == NULL) - success = false; - else - { - // Read the containing register if it hasn't already been read - if (!GetRegisterIsValid(prim_reg)) - success = GetPrimordialRegister(prim_reg_info, gdb_comm); - } - } - - if (success) - { - // If we reach this point, all primordial register requests have succeeded. - // Validate this composite register. - SetRegisterIsValid (reg_info, true); - } - } + const uint32_t prim_reg = reg_info->value_regs[idx]; + if (prim_reg == LLDB_INVALID_REGNUM) + break; + // We have a valid primordial regsiter as our constituent. + // Grab the corresponding register info. + const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); + if (prim_reg_info == NULL) + success = false; else { - // Get each register individually - GetPrimordialRegister(reg_info, gdb_comm); + // Read the containing register if it hasn't already been read + if (!GetRegisterIsValid(prim_reg)) + success = GetPrimordialRegister(prim_reg_info, gdb_comm); } } + + if (success) + { + // If we reach this point, all primordial register requests have succeeded. + // Validate this composite register. + SetRegisterIsValid (reg_info, true); + } } else { -#if LLDB_CONFIGURATION_DEBUG - StreamString strm; - gdb_comm.DumpHistory(strm); - Host::SetCrashDescription (strm.GetData()); - assert (!"Didn't get sequence mutex for read register."); -#else - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\":\n%s", reg_info->name, strm.GetData()); - } - else - { - log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\"", reg_info->name); - } - } -#endif + // Get each register individually + GetPrimordialRegister(reg_info, gdb_comm); } // Make sure we got a valid register value after reading it @@ -488,6 +439,54 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * return false; } +bool +GDBRemoteRegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint) +{ + ExecutionContext exe_ctx (CalculateThread()); + + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; + + GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + + uint32_t save_id = 0; + if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) + { + reg_checkpoint.SetID(save_id); + reg_checkpoint.GetData().reset(); + return true; + } + else + { + reg_checkpoint.SetID(0); // Invalid save ID is zero + return ReadAllRegisterValues(reg_checkpoint.GetData()); + } +} + +bool +GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint) +{ + uint32_t save_id = reg_checkpoint.GetID(); + if (save_id != 0) + { + ExecutionContext exe_ctx (CalculateThread()); + + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; + + GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + + return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id); + } + else + { + return WriteAllRegisterValues(reg_checkpoint.GetData()); + } +} bool GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 7a49d693d44..38f29bbca0d 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -91,6 +91,12 @@ public: virtual bool WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + virtual bool + ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint); + + virtual bool + WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); + virtual uint32_t ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); |