diff options
28 files changed, 822 insertions, 311 deletions
diff --git a/lldb/include/lldb/Target/RegisterCheckpoint.h b/lldb/include/lldb/Target/RegisterCheckpoint.h new file mode 100644 index 00000000000..3e61e1490d4 --- /dev/null +++ b/lldb/include/lldb/Target/RegisterCheckpoint.h @@ -0,0 +1,71 @@ +//===-- RegisterCheckpoint.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterCheckpoint_h_ +#define liblldb_RegisterCheckpoint_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Core/UserID.h" +#include "lldb/Target/StackID.h" + +namespace lldb_private { + + // Inherit from UserID in case pushing/popping all register values can be + // done using a 64 bit integer that holds a baton/cookie instead of actually + // having to read all register values into a buffer + class RegisterCheckpoint : public UserID + { + public: + + enum class Reason { + // An expression is about to be run on the thread if the protocol that + // talks to the debuggee supports checkpointing the registers using a + // push/pop then the UserID base class in the RegisterCheckpoint can + // be used to store the baton/cookie that refers to the remote saved + // state. + eExpression, + // The register checkpoint wants the raw register bytes, so they must + // be read into m_data_sp, or the save/restore checkpoint should fail. + eDataBackup + }; + + RegisterCheckpoint(Reason reason) : + UserID(0), + m_data_sp (), + m_reason(reason) + { + } + + ~RegisterCheckpoint() + { + } + + lldb::DataBufferSP & + GetData() + { + return m_data_sp; + } + + const lldb::DataBufferSP & + GetData() const + { + return m_data_sp; + } + + protected: + lldb::DataBufferSP m_data_sp; + Reason m_reason; + + // Make RegisterCheckpointSP if you wish to share the data in this class. + DISALLOW_COPY_AND_ASSIGN(RegisterCheckpoint); + }; + +} // namespace lldb_private + +#endif // liblldb_RegisterCheckpoint_h_ diff --git a/lldb/include/lldb/Target/RegisterContext.h b/lldb/include/lldb/Target/RegisterContext.h index 7da46270011..421acc03cb2 100644 --- a/lldb/include/lldb/Target/RegisterContext.h +++ b/lldb/include/lldb/Target/RegisterContext.h @@ -59,6 +59,18 @@ public: virtual bool WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) = 0; + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp) + { + return false; + } + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) + { + return false; + } + // These two functions are used to implement "push" and "pop" of register states. They are used primarily // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues. @@ -67,10 +79,10 @@ public: // so these API's should only be used when this behavior is needed. virtual bool - ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0; - + ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint); + virtual bool - WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0; + WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); bool CopyFromRegisterContext (lldb::RegisterContextSP context); diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index bc4b1176deb..a5962bb284a 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -17,6 +17,7 @@ #include "lldb/Core/UserID.h" #include "lldb/Core/UserSettingsController.h" #include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/RegisterCheckpoint.h" #include "lldb/Target/StackFrameList.h" #define LLDB_THREAD_MAX_STOP_EXC_DATA 8 @@ -130,79 +131,12 @@ public: DISALLOW_COPY_AND_ASSIGN (ThreadEventData); }; - // TODO: You shouldn't just checkpoint the register state alone, so this should get - // moved to protected. To do that ThreadStateCheckpoint needs to be returned as a token... - class RegisterCheckpoint - { - public: - - RegisterCheckpoint() : - m_stack_id (), - m_data_sp () - { - } - - RegisterCheckpoint (const StackID &stack_id) : - m_stack_id (stack_id), - m_data_sp () - { - } - - ~RegisterCheckpoint() - { - } - - const RegisterCheckpoint& - operator= (const RegisterCheckpoint &rhs) - { - if (this != &rhs) - { - this->m_stack_id = rhs.m_stack_id; - this->m_data_sp = rhs.m_data_sp; - } - return *this; - } - - RegisterCheckpoint (const RegisterCheckpoint &rhs) : - m_stack_id (rhs.m_stack_id), - m_data_sp (rhs.m_data_sp) - { - } - - const StackID & - GetStackID() - { - return m_stack_id; - } - - void - SetStackID (const StackID &stack_id) - { - m_stack_id = stack_id; - } - - lldb::DataBufferSP & - GetData() - { - return m_data_sp; - } - - const lldb::DataBufferSP & - GetData() const - { - return m_data_sp; - } - - protected: - StackID m_stack_id; - lldb::DataBufferSP m_data_sp; - }; struct ThreadStateCheckpoint { uint32_t orig_stop_id; // Dunno if I need this yet but it is an interesting bit of data. lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you might continue with the wrong signals. - RegisterCheckpoint register_backup; // You need to restore the registers, of course... + lldb::RegisterCheckpointSP register_backup_sp; // You need to restore the registers, of course... uint32_t current_inlined_depth; lldb::addr_t current_inlined_pc; }; @@ -1004,16 +938,6 @@ protected: typedef std::vector<lldb::ThreadPlanSP> plan_stack; - virtual bool - SaveFrameZeroState (RegisterCheckpoint &checkpoint); - - virtual bool - RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint); - - // register_data_sp must be a DataSP passed to ReadAllRegisterValues. - bool - ResetFrameZeroRegisters (lldb::DataBufferSP register_data_sp); - virtual lldb_private::Unwind * GetUnwinder (); @@ -1035,12 +959,6 @@ protected: lldb::StackFrameListSP GetStackFrameList (); - struct ThreadState - { - uint32_t orig_stop_id; - lldb::StopInfoSP stop_info_sp; - RegisterCheckpoint register_backup; - }; //------------------------------------------------------------------ // Classes that inherit from Process can see and modify these diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h index 63e780f3841..18f1d0facbf 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -163,7 +163,6 @@ private: Address m_function_addr; Address m_start_addr; lldb::addr_t m_function_sp; - Thread::RegisterCheckpoint m_register_backup; lldb::ThreadPlanSP m_subplan_sp; LanguageRuntime *m_cxx_language_runtime; LanguageRuntime *m_objc_language_runtime; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index cd8a5c2e813..a72e2e9303c 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -162,6 +162,7 @@ class PythonDictionary; class PythonInteger; class PythonObject; class PythonString; +class RegisterCheckpoint; class RegisterContext; class RegisterLocation; class RegisterLocationList; @@ -329,6 +330,7 @@ namespace lldb { typedef std::shared_ptr<lldb_private::ProcessLaunchInfo> ProcessLaunchInfoSP; typedef std::weak_ptr<lldb_private::Process> ProcessWP; typedef std::shared_ptr<lldb_private::Property> PropertySP; + typedef std::shared_ptr<lldb_private::RegisterCheckpoint> RegisterCheckpointSP; typedef std::shared_ptr<lldb_private::RegisterContext> RegisterContextSP; typedef std::shared_ptr<lldb_private::RegularExpression> RegularExpressionSP; typedef std::shared_ptr<lldb_private::ScriptInterpreterObject> ScriptInterpreterObjectSP; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 3c86070cb9b..89bc003bc28 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -427,6 +427,7 @@ 26A527C414E24F5F00F3A14A /* ThreadMachCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 26A527C014E24F5F00F3A14A /* ThreadMachCore.h */; }; 26A69C5F137A17A500262477 /* RegisterValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C6886E137880C400407EDF /* RegisterValue.cpp */; }; 26A7A035135E6E4200FB369E /* OptionValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A7A034135E6E4200FB369E /* OptionValue.cpp */; }; + 26AB54121832DC3400EADFF3 /* RegisterCheckpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 26AB54111832DC3400EADFF3 /* RegisterCheckpoint.h */; }; 26AB92121819D74600E63F3E /* DWARFDataExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26AB92101819D74600E63F3E /* DWARFDataExtractor.cpp */; }; 26AB92131819D74600E63F3E /* DWARFDataExtractor.h in Headers */ = {isa = PBXBuildFile; fileRef = 26AB92111819D74600E63F3E /* DWARFDataExtractor.h */; }; 26ACEC2815E077AE00E94760 /* Property.h in Headers */ = {isa = PBXBuildFile; fileRef = 26ACEC2715E077AE00E94760 /* Property.h */; }; @@ -1090,6 +1091,7 @@ 26A527C014E24F5F00F3A14A /* ThreadMachCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadMachCore.h; sourceTree = "<group>"; }; 26A7A034135E6E4200FB369E /* OptionValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionValue.cpp; path = source/Interpreter/OptionValue.cpp; sourceTree = "<group>"; }; 26A7A036135E6E5300FB369E /* OptionValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OptionValue.h; path = include/lldb/Interpreter/OptionValue.h; sourceTree = "<group>"; }; + 26AB54111832DC3400EADFF3 /* RegisterCheckpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterCheckpoint.h; path = include/lldb/Target/RegisterCheckpoint.h; sourceTree = "<group>"; }; 26AB92101819D74600E63F3E /* DWARFDataExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDataExtractor.cpp; sourceTree = "<group>"; }; 26AB92111819D74600E63F3E /* DWARFDataExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDataExtractor.h; sourceTree = "<group>"; }; 26ACEC2715E077AE00E94760 /* Property.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Property.h; path = include/lldb/Interpreter/Property.h; sourceTree = "<group>"; }; @@ -3118,6 +3120,7 @@ 264A43BD1320BCEB005B4096 /* Platform.cpp */, 26BC7DF310F1B81A00F91463 /* Process.h */, 26BC7F3610F1B90C00F91463 /* Process.cpp */, + 26AB54111832DC3400EADFF3 /* RegisterCheckpoint.h */, 26BC7DF410F1B81A00F91463 /* RegisterContext.h */, 26BC7F3710F1B90C00F91463 /* RegisterContext.cpp */, 2618D78F1240115500F2B8FE /* SectionLoadList.h */, @@ -3611,6 +3614,7 @@ AF254E32170CCC33007AE5C9 /* PlatformDarwinKernel.h in Headers */, 2694E99E14FC0BB30076DE67 /* PlatformFreeBSD.h in Headers */, 2694E9A514FC0BBD0076DE67 /* PlatformLinux.h in Headers */, + 26AB54121832DC3400EADFF3 /* RegisterCheckpoint.h in Headers */, 26AB92131819D74600E63F3E /* DWARFDataExtractor.h in Headers */, 2663E379152BD1890091EC22 /* ReadWriteLock.h in Headers */, 945759681534941F005A9070 /* PlatformPOSIX.h in Headers */, 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); diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp index 3d68ba8706c..93dce3ea0ed 100644 --- a/lldb/source/Target/RegisterContext.cpp +++ b/lldb/source/Target/RegisterContext.cpp @@ -440,6 +440,18 @@ RegisterContext::WriteRegisterValueToMemory (const RegisterInfo *reg_info, } +bool +RegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint) +{ + return ReadAllRegisterValues(reg_checkpoint.GetData()); +} + +bool +RegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint) +{ + return WriteAllRegisterValues(reg_checkpoint.GetData()); +} + TargetSP RegisterContext::CalculateTarget () { diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index a43301f6d97..07f5321990b 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -496,7 +496,19 @@ Thread::ThreadStoppedForAReason (void) bool Thread::CheckpointThreadState (ThreadStateCheckpoint &saved_state) { - if (!SaveFrameZeroState(saved_state.register_backup)) + saved_state.register_backup_sp.reset(); + lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); + if (frame_sp) + { + lldb::RegisterCheckpointSP reg_checkpoint_sp(new RegisterCheckpoint(RegisterCheckpoint::Reason::eExpression)); + if (reg_checkpoint_sp) + { + lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); + if (reg_ctx_sp && reg_ctx_sp->ReadAllRegisterValues (*reg_checkpoint_sp)) + saved_state.register_backup_sp = reg_checkpoint_sp; + } + } + if (!saved_state.register_backup_sp) return false; saved_state.stop_info_sp = GetStopInfo(); @@ -511,7 +523,26 @@ Thread::CheckpointThreadState (ThreadStateCheckpoint &saved_state) bool Thread::RestoreRegisterStateFromCheckpoint (ThreadStateCheckpoint &saved_state) { - return RestoreSaveFrameZero(saved_state.register_backup); + if (saved_state.register_backup_sp) + { + lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); + if (frame_sp) + { + lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); + if (reg_ctx_sp) + { + bool ret = reg_ctx_sp->WriteAllRegisterValues (*saved_state.register_backup_sp); + + // Clear out all stack frames as our world just changed. + ClearStackFrames(); + reg_ctx_sp->InvalidateIfNeeded(true); + if (m_unwinder_ap.get()) + m_unwinder_ap->Clear(); + return ret; + } + } + } + return false; } bool @@ -1966,48 +1997,6 @@ Thread::GetStackFrameStatus (Stream& strm, num_frames_with_source); } -bool -Thread::SaveFrameZeroState (RegisterCheckpoint &checkpoint) -{ - lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); - if (frame_sp) - { - checkpoint.SetStackID(frame_sp->GetStackID()); - lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); - if (reg_ctx_sp) - return reg_ctx_sp->ReadAllRegisterValues (checkpoint.GetData()); - } - return false; -} - -bool -Thread::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint) -{ - return ResetFrameZeroRegisters (checkpoint.GetData()); -} - -bool -Thread::ResetFrameZeroRegisters (lldb::DataBufferSP register_data_sp) -{ - lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); - if (frame_sp) - { - lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); - if (reg_ctx_sp) - { - bool ret = reg_ctx_sp->WriteAllRegisterValues (register_data_sp); - - // Clear out all stack frames as our world just changed. - ClearStackFrames(); - reg_ctx_sp->InvalidateIfNeeded(true); - if (m_unwinder_ap.get()) - m_unwinder_ap->Clear(); - return ret; - } - } - return false; -} - Unwind * Thread::GetUnwinder () { diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp index dd54c6a7b09..b7feeb3a249 100644 --- a/lldb/tools/debugserver/source/DNB.cpp +++ b/lldb/tools/debugserver/source/DNB.cpp @@ -1765,6 +1765,31 @@ DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *bu return 0; } +uint32_t +DNBThreadSaveRegisterState (nub_process_t pid, nub_thread_t tid) +{ + if (tid != INVALID_NUB_THREAD) + { + MachProcessSP procSP; + if (GetProcessSP (pid, procSP)) + return procSP->GetThreadList().SaveRegisterState (tid); + } + return 0; +} +nub_bool_t +DNBThreadRestoreRegisterState (nub_process_t pid, nub_thread_t tid, uint32_t save_id) +{ + if (tid != INVALID_NUB_THREAD) + { + MachProcessSP procSP; + if (GetProcessSP (pid, procSP)) + return procSP->GetThreadList().RestoreRegisterState (tid, save_id); + } + return false; +} + + + //---------------------------------------------------------------------- // Read a register value by name. //---------------------------------------------------------------------- diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h index 986cab9becb..c70ede989d5 100644 --- a/lldb/tools/debugserver/source/DNB.h +++ b/lldb/tools/debugserver/source/DNB.h @@ -18,8 +18,6 @@ #include <mach/thread_info.h> #include <string> -#define DNB_EXPORT __attribute__((visibility("default"))) - typedef bool (*DNBShouldCancelCallback) (void *); void DNBInitialize (); @@ -41,11 +39,11 @@ nub_process_t DNBProcessLaunch (const char *path, nub_launch_flavor_t launch_flavor, int disable_aslr, char *err_str, - size_t err_len) DNB_EXPORT; + size_t err_len); -nub_process_t DNBProcessAttach (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT; -nub_process_t DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT; -nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavor_t launch_flavor, bool ignore_existing, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT; +nub_process_t DNBProcessAttach (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len); +nub_process_t DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len); +nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavor_t launch_flavor, bool ignore_existing, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL); // Resume a process with exact instructions on what to do with each thread: // - If no thread actions are supplied (actions is NULL or num_actions is zero), // then all threads are continued. @@ -54,97 +52,99 @@ nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavo // explicit thread action can be made by making a thread action with a tid of // INVALID_NUB_THREAD. If there is no default action, those threads will // remain stopped. -nub_bool_t DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions) DNB_EXPORT; -nub_bool_t DNBProcessHalt (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessDetach (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessSignal (nub_process_t pid, int signal) DNB_EXPORT; -nub_bool_t DNBProcessKill (nub_process_t pid) DNB_EXPORT; -nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) DNB_EXPORT; -nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) DNB_EXPORT; -nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT; -nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; -int DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info) DNB_EXPORT; -std::string DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType) DNB_EXPORT; -nub_bool_t DNBProcessSetEnableAsyncProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) DNB_EXPORT; +nub_bool_t DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions); +nub_bool_t DNBProcessHalt (nub_process_t pid); +nub_bool_t DNBProcessDetach (nub_process_t pid); +nub_bool_t DNBProcessSignal (nub_process_t pid, int signal); +nub_bool_t DNBProcessKill (nub_process_t pid); +nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf); +nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf); +nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions); +nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr); +int DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info); +std::string DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType); +nub_bool_t DNBProcessSetEnableAsyncProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type); //---------------------------------------------------------------------- // Process status //---------------------------------------------------------------------- -nub_bool_t DNBProcessIsAlive (nub_process_t pid) DNB_EXPORT; -nub_state_t DNBProcessGetState (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessGetExitStatus (nub_process_t pid, int *status) DNB_EXPORT; -nub_bool_t DNBProcessSetExitStatus (nub_process_t pid, int status) DNB_EXPORT; -nub_size_t DNBProcessGetNumThreads (nub_process_t pid) DNB_EXPORT; -nub_thread_t DNBProcessGetCurrentThread (nub_process_t pid) DNB_EXPORT; -nub_thread_t DNBProcessGetCurrentThreadMachPort (nub_process_t pid) DNB_EXPORT; -nub_thread_t DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; -nub_thread_t DNBProcessGetThreadAtIndex (nub_process_t pid, nub_size_t thread_idx) DNB_EXPORT; -nub_bool_t DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; -nub_addr_t DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessSharedLibrariesUpdated (nub_process_t pid) DNB_EXPORT; -nub_size_t DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos) DNB_EXPORT; -nub_bool_t DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton) DNB_EXPORT; -nub_bool_t DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton) DNB_EXPORT; -nub_addr_t DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib) DNB_EXPORT; -nub_size_t DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; -nub_size_t DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; -nub_size_t DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; -nub_size_t DNBProcessGetStopCount (nub_process_t pid) DNB_EXPORT; -uint32_t DNBProcessGetCPUType (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessIsAlive (nub_process_t pid); +nub_state_t DNBProcessGetState (nub_process_t pid); +nub_bool_t DNBProcessGetExitStatus (nub_process_t pid, int *status); +nub_bool_t DNBProcessSetExitStatus (nub_process_t pid, int status); +nub_size_t DNBProcessGetNumThreads (nub_process_t pid); +nub_thread_t DNBProcessGetCurrentThread (nub_process_t pid); +nub_thread_t DNBProcessGetCurrentThreadMachPort (nub_process_t pid); +nub_thread_t DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid); +nub_thread_t DNBProcessGetThreadAtIndex (nub_process_t pid, nub_size_t thread_idx); +nub_bool_t DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid); +nub_addr_t DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid); +nub_bool_t DNBProcessSharedLibrariesUpdated (nub_process_t pid); +nub_size_t DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos); +nub_bool_t DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton); +nub_bool_t DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton); +nub_addr_t DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib); +nub_size_t DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size); +nub_size_t DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size); +nub_size_t DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size); +nub_size_t DNBProcessGetStopCount (nub_process_t pid); +uint32_t DNBProcessGetCPUType (nub_process_t pid); //---------------------------------------------------------------------- // Process executable and arguments //---------------------------------------------------------------------- -const char * DNBProcessGetExecutablePath (nub_process_t pid) DNB_EXPORT; -const char * DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx) DNB_EXPORT; -nub_size_t DNBProcessGetArgumentCount (nub_process_t pid) DNB_EXPORT; +const char * DNBProcessGetExecutablePath (nub_process_t pid); +const char * DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx); +nub_size_t DNBProcessGetArgumentCount (nub_process_t pid); //---------------------------------------------------------------------- // Process events //---------------------------------------------------------------------- -nub_event_t DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout) DNB_EXPORT; -void DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask) DNB_EXPORT; +nub_event_t DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout); +void DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask); //---------------------------------------------------------------------- // Thread functions //---------------------------------------------------------------------- -const char * DNBThreadGetName (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; -nub_bool_t DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info) DNB_EXPORT; -nub_state_t DNBThreadGetState (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; -nub_bool_t DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value) DNB_EXPORT; -nub_bool_t DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value) DNB_EXPORT; -nub_size_t DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len) DNB_EXPORT; -nub_size_t DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len) DNB_EXPORT; -nub_bool_t DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t set, const char *name, DNBRegisterValue *value) DNB_EXPORT; -nub_bool_t DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, DNBThreadStopInfo *stop_info) DNB_EXPORT; -const char * DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; +const char * DNBThreadGetName (nub_process_t pid, nub_thread_t tid); +nub_bool_t DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info); +nub_state_t DNBThreadGetState (nub_process_t pid, nub_thread_t tid); +nub_bool_t DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value); +nub_bool_t DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value); +nub_size_t DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len); +nub_size_t DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len); +uint32_t DNBThreadSaveRegisterState (nub_process_t pid, nub_thread_t tid); +nub_bool_t DNBThreadRestoreRegisterState (nub_process_t pid, nub_thread_t tid, uint32_t save_id); +nub_bool_t DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t set, const char *name, DNBRegisterValue *value); +nub_bool_t DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, DNBThreadStopInfo *stop_info); +const char * DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid); //---------------------------------------------------------------------- // Breakpoint functions //---------------------------------------------------------------------- -nub_bool_t DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware) DNB_EXPORT; -nub_bool_t DNBBreakpointClear (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; +nub_bool_t DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware); +nub_bool_t DNBBreakpointClear (nub_process_t pid, nub_addr_t addr); //---------------------------------------------------------------------- // Watchpoint functions //---------------------------------------------------------------------- -nub_bool_t DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware) DNB_EXPORT; -nub_bool_t DNBWatchpointClear (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; -uint32_t DNBWatchpointGetNumSupportedHWP (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware); +nub_bool_t DNBWatchpointClear (nub_process_t pid, nub_addr_t addr); +uint32_t DNBWatchpointGetNumSupportedHWP (nub_process_t pid); const DNBRegisterSetInfo * - DNBGetRegisterSetInfo (nub_size_t *num_reg_sets) DNB_EXPORT; -nub_bool_t DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info) DNB_EXPORT; + DNBGetRegisterSetInfo (nub_size_t *num_reg_sets); +nub_bool_t DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info); //---------------------------------------------------------------------- // Printf style formatting for printing values in the inferior memory // space and registers. //---------------------------------------------------------------------- -nub_size_t DNBPrintf (nub_process_t pid, nub_thread_t tid, nub_addr_t addr, FILE *file, const char *format) DNB_EXPORT; +nub_size_t DNBPrintf (nub_process_t pid, nub_thread_t tid, nub_addr_t addr, FILE *file, const char *format); //---------------------------------------------------------------------- // Other static nub information calls. //---------------------------------------------------------------------- -const char * DNBStateAsString (nub_state_t state) DNB_EXPORT; -nub_bool_t DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size) DNB_EXPORT; +const char * DNBStateAsString (nub_state_t state); +nub_bool_t DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size); #endif diff --git a/lldb/tools/debugserver/source/DNBArch.h b/lldb/tools/debugserver/source/DNBArch.h index 1c5c5b2db6f..e4f6bd2fada 100644 --- a/lldb/tools/debugserver/source/DNBArch.h +++ b/lldb/tools/debugserver/source/DNBArch.h @@ -58,10 +58,22 @@ public: static bool SetArchitecture (uint32_t cpu_type); + DNBArchProtocol () : + m_save_id(0) + { + + } + + virtual ~DNBArchProtocol () + { + + } virtual bool GetRegisterValue (int set, int reg, DNBRegisterValue *value) = 0; virtual bool SetRegisterValue (int set, int reg, const DNBRegisterValue *value) = 0; virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len) = 0; virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len) = 0; + virtual uint32_t SaveRegisterState () = 0; + virtual bool RestoreRegisterState (uint32_t save_id) = 0; virtual kern_return_t GetRegisterState (int set, bool force) = 0; virtual kern_return_t SetRegisterState (int set) = 0; @@ -85,6 +97,11 @@ public: protected: friend class MachThread; + uint32_t GetNextRegisterStateSaveID () + { + return ++m_save_id; + } + enum { Trans_Pending = 0, // Transaction is pending, and checkpoint state has been snapshotted. @@ -94,6 +111,9 @@ protected: virtual bool StartTransForHWP() { return true; } virtual bool RollbackTransForHWP() { return true; } virtual bool FinishTransForHWP() { return true; } + + uint32_t m_save_id; // An always incrementing integer ID used with SaveRegisterState/RestoreRegisterState + }; diff --git a/lldb/tools/debugserver/source/DNBLog.h b/lldb/tools/debugserver/source/DNBLog.h index d019e2d1a1f..01add065abc 100644 --- a/lldb/tools/debugserver/source/DNBLog.h +++ b/lldb/tools/debugserver/source/DNBLog.h @@ -34,29 +34,27 @@ extern "C" { #if defined (DNBLOG_ENABLED) -#define DNB_EXPORT __attribute__((visibility("default"))) - -void _DNBLog(uint32_t flags, const char *format, ...) __attribute__ ((format (printf, 2, 3))) DNB_EXPORT; -void _DNBLogDebug (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT; -void _DNBLogDebugVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT; -void _DNBLogThreaded (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT; -void _DNBLogThreadedIf (uint32_t mask, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) DNB_EXPORT; -void _DNBLogError (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT; -void _DNBLogFatalError (int err, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) DNB_EXPORT; -void _DNBLogVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT; -void _DNBLogWarning (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT; -void _DNBLogWarningVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT; -bool DNBLogCheckLogBit (uint32_t bit) DNB_EXPORT; -uint32_t DNBLogSetLogMask (uint32_t mask) DNB_EXPORT; -uint32_t DNBLogGetLogMask () DNB_EXPORT; -void DNBLogSetLogCallback (DNBCallbackLog callback, void *baton) DNB_EXPORT; -DNBCallbackLog DNBLogGetLogCallback () DNB_EXPORT; -bool DNBLogEnabled () DNB_EXPORT; -bool DNBLogEnabledForAny (uint32_t mask) DNB_EXPORT; -int DNBLogGetDebug () DNB_EXPORT; -void DNBLogSetDebug (int g) DNB_EXPORT; -int DNBLogGetVerbose () DNB_EXPORT; -void DNBLogSetVerbose (int g) DNB_EXPORT; +void _DNBLog(uint32_t flags, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +void _DNBLogDebug (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void _DNBLogDebugVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) ; +void _DNBLogThreaded (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void _DNBLogThreadedIf (uint32_t mask, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +void _DNBLogError (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void _DNBLogFatalError (int err, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +void _DNBLogVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void _DNBLogWarning (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void _DNBLogWarningVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +bool DNBLogCheckLogBit (uint32_t bit); +uint32_t DNBLogSetLogMask (uint32_t mask); +uint32_t DNBLogGetLogMask (); +void DNBLogSetLogCallback (DNBCallbackLog callback, void *baton); +DNBCallbackLog DNBLogGetLogCallback (); +bool DNBLogEnabled (); +bool DNBLogEnabledForAny (uint32_t mask); +int DNBLogGetDebug (); +void DNBLogSetDebug (int g); +int DNBLogGetVerbose (); +void DNBLogSetVerbose (int g); #define DNBLog(fmt, ...) do { if (DNBLogEnabled()) { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) #define DNBLogDebug(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogDebug(fmt, ## __VA_ARGS__); } } while (0) diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp index c11d2c2ca82..f3a9d51c808 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp @@ -617,6 +617,18 @@ MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len) } uint32_t +MachThread::SaveRegisterState () +{ + return m_arch_ap->SaveRegisterState(); + +} +bool +MachThread::RestoreRegisterState (uint32_t save_id) +{ + return m_arch_ap->RestoreRegisterState(save_id); +} + +uint32_t MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp) { if (bp != NULL && bp->IsBreakpoint()) diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.h b/lldb/tools/debugserver/source/MacOSX/MachThread.h index 7e16d49b78c..c3121112980 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThread.h +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.h @@ -92,6 +92,9 @@ public: bool SetRegisterValue ( uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value ); nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); + uint32_t SaveRegisterState (); + bool RestoreRegisterState (uint32_t save_id); + void NotifyBreakpointChanged (const DNBBreakpoint *bp) { } diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp index b5ce58d3438..adad95f2f7c 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp @@ -200,6 +200,25 @@ MachThreadList::SetRegisterContext (nub_thread_t tid, const void *buf, size_t bu return 0; } +uint32_t +MachThreadList::SaveRegisterState (nub_thread_t tid) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->SaveRegisterState (); + return 0; +} + +bool +MachThreadList::RestoreRegisterState (nub_thread_t tid, uint32_t save_id) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->RestoreRegisterState (save_id); + return 0; +} + + nub_size_t MachThreadList::NumThreads () const { diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.h b/lldb/tools/debugserver/source/MacOSX/MachThreadList.h index 85097314b02..46bccfee8de 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.h +++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.h @@ -30,6 +30,8 @@ public: bool SetRegisterValue (nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value) const; nub_size_t GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len); nub_size_t SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len); + uint32_t SaveRegisterState (nub_thread_t tid); + bool RestoreRegisterState (nub_thread_t tid, uint32_t save_id); const char * GetThreadInfo (nub_thread_t tid) const; void ProcessWillResume (MachProcess *process, const DNBThreadResumeActions &thread_actions); uint32_t ProcessDidStop (MachProcess *process); diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp index 75282c5966c..88073afee00 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp @@ -1805,5 +1805,57 @@ DNBArchMachARM::SetRegisterContext (const void *buf, nub_size_t buf_len) } +uint32_t +DNBArchMachARM::SaveRegisterState () +{ + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + // Always re-read the registers because above we call thread_abort_safely(); + bool force = true; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::SaveRegisterState () error: GPR regs failed to read: %u ", kret); + } + else if ((kret = GetFPUState(force)) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::SaveRegisterState () error: %s regs failed to read: %u", CPUHasAVX() ? "AVX" : "FPU", kret); + } + else + { + const uint32_t save_id = GetNextRegisterStateSaveID (); + m_saved_register_states[save_id] = m_state.context; + return save_id; + } + return UINT32_MAX; +} +bool +DNBArchMachARM::RestoreRegisterState (uint32_t save_id) +{ + SaveRegiterStates::iterator pos = m_saved_register_states.find(save_id); + if (pos != m_saved_register_states.end()) + { + m_state.context.gpr = pos->second.gpr; + m_state.context.vfp = pos->second.vfp; + kern_return_t kret; + bool success = true; + if ((kret = SetGPRState()) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret); + success = false; + } + else if ((kret = SetFPUState()) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, CPUHasAVX() ? "AVX" : "FPU", kret); + success = false; + } + m_saved_register_states.erase(pos); + return success; + } + return false; +} + + #endif // #if defined (__arm__) diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h index 7aeba6e9f18..4021fd5668e 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h @@ -18,6 +18,8 @@ #include "DNBArch.h" +#include <map> + class MachThread; class DNBArchMachARM : public DNBArchProtocol diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp index f76ec0da021..9c708f31359 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp @@ -515,6 +515,10 @@ DNBArchImplI386::GetEXCState(bool force) kern_return_t DNBArchImplI386::SetGPRState() { + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->MachPortNumber(), __i386_THREAD_STATE, (thread_state_t)&m_state.context.gpr, e_regSetWordSizeGPR)); return m_state.GetError(e_regSetGPR, Write); } @@ -1793,6 +1797,60 @@ DNBArchImplI386::SetRegisterContext (const void *buf, nub_size_t buf_len) } +uint32_t +DNBArchImplI386::SaveRegisterState () +{ + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + bool force = true; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: GPR regs failed to read: %u ", kret); + } + else if ((kret = GetFPUState(force)) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: %s regs failed to read: %u", CPUHasAVX() ? "AVX" : "FPU", kret); + } + else + { + const uint32_t save_id = GetNextRegisterStateSaveID (); + m_saved_register_states[save_id] = m_state.context; + return save_id; + } + return 0; +} +bool +DNBArchImplI386::RestoreRegisterState (uint32_t save_id) +{ + SaveRegiterStates::iterator pos = m_saved_register_states.find(save_id); + if (pos != m_saved_register_states.end()) + { + m_state.context.gpr = pos->second.gpr; + m_state.context.fpu = pos->second.fpu; + m_state.context.exc = pos->second.exc; + m_state.SetError(e_regSetGPR, Read, 0); + m_state.SetError(e_regSetFPU, Read, 0); + m_state.SetError(e_regSetEXC, Read, 0); + kern_return_t kret; + bool success = true; + if ((kret = SetGPRState()) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret); + success = false; + } + else if ((kret = SetFPUState()) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, CPUHasAVX() ? "AVX" : "FPU", kret); + success = false; + } + m_saved_register_states.erase(pos); + return success; + } + return false; +} + kern_return_t DNBArchImplI386::GetRegisterState(int set, bool force) diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h index 6b526f35914..ae9ef4980fc 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h @@ -20,16 +20,20 @@ #include "../HasAVX.h" #include "MachRegisterStatesI386.h" +#include <map> + class MachThread; class DNBArchImplI386 : public DNBArchProtocol { public: DNBArchImplI386(MachThread *thread) : + DNBArchProtocol(), m_thread(thread), m_state(), m_2pc_dbg_checkpoint(), - m_2pc_trans_state(Trans_Done) + m_2pc_trans_state(Trans_Done), + m_saved_register_states() { } virtual ~DNBArchImplI386() @@ -42,6 +46,9 @@ public: virtual bool SetRegisterValue(int set, int reg, const DNBRegisterValue *value); virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); + virtual uint32_t SaveRegisterState (); + virtual bool RestoreRegisterState (uint32_t save_id); + virtual kern_return_t GetRegisterState (int set, bool force); virtual kern_return_t SetRegisterState (int set); virtual bool RegisterSetStateIsValid (int set) const; @@ -240,6 +247,8 @@ protected: State m_state; DBG m_2pc_dbg_checkpoint; uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)? + typedef std::map<uint32_t, Context> SaveRegiterStates; + SaveRegiterStates m_saved_register_states; }; #endif // #if defined (__i386__) || defined (__x86_64__) diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp index 20e91961b47..0ceabc56547 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp @@ -447,7 +447,7 @@ kern_return_t DNBArchImplX86_64::SetGPRState() { kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); - DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->MachPortNumber(), __x86_64_THREAD_STATE, (thread_state_t)&m_state.context.gpr, e_regSetWordSizeGPR)); DNBLogThreadedIf (LOG_THREAD, "::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x" @@ -2189,6 +2189,59 @@ DNBArchImplX86_64::SetRegisterContext (const void *buf, nub_size_t buf_len) return size; } +uint32_t +DNBArchImplX86_64::SaveRegisterState () +{ + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + // Always re-read the registers because above we call thread_abort_safely(); + bool force = true; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SaveRegisterState () error: GPR regs failed to read: %u ", kret); + } + else if ((kret = GetFPUState(force)) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SaveRegisterState () error: %s regs failed to read: %u", CPUHasAVX() ? "AVX" : "FPU", kret); + } + else + { + const uint32_t save_id = GetNextRegisterStateSaveID (); + m_saved_register_states[save_id] = m_state.context; + return save_id; + } + return 0; +} +bool +DNBArchImplX86_64::RestoreRegisterState (uint32_t save_id) +{ + SaveRegiterStates::iterator pos = m_saved_register_states.find(save_id); + if (pos != m_saved_register_states.end()) + { + m_state.context.gpr = pos->second.gpr; + m_state.context.fpu = pos->second.fpu; + m_state.SetError(e_regSetGPR, Read, 0); + m_state.SetError(e_regSetFPU, Read, 0); + kern_return_t kret; + bool success = true; + if ((kret = SetGPRState()) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret); + success = false; + } + else if ((kret = SetFPUState()) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, CPUHasAVX() ? "AVX" : "FPU", kret); + success = false; + } + m_saved_register_states.erase(pos); + return success; + } + return false; +} + kern_return_t DNBArchImplX86_64::GetRegisterState(int set, bool force) diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h index 895bfa97491..4302c6b319d 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h @@ -19,16 +19,20 @@ #include "../HasAVX.h" #include "MachRegisterStatesX86_64.h" +#include <map> + class MachThread; class DNBArchImplX86_64 : public DNBArchProtocol { public: DNBArchImplX86_64(MachThread *thread) : + DNBArchProtocol(), m_thread(thread), m_state(), m_2pc_dbg_checkpoint(), - m_2pc_trans_state(Trans_Done) + m_2pc_trans_state(Trans_Done), + m_saved_register_states() { } virtual ~DNBArchImplX86_64() @@ -36,10 +40,13 @@ public: } static void Initialize(); + virtual bool GetRegisterValue(int set, int reg, DNBRegisterValue *value); virtual bool SetRegisterValue(int set, int reg, const DNBRegisterValue *value); virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); + virtual uint32_t SaveRegisterState (); + virtual bool RestoreRegisterState (uint32_t save_id); virtual kern_return_t GetRegisterState (int set, bool force); virtual kern_return_t SetRegisterState (int set); @@ -246,6 +253,8 @@ protected: State m_state; DBG m_2pc_dbg_checkpoint; uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)? + typedef std::map<uint32_t, Context> SaveRegiterStates; + SaveRegiterStates m_saved_register_states; }; #endif // #if defined (__i386__) || defined (__x86_64__) diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 2a94c6cc55b..22db738cfea 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -191,6 +191,8 @@ RNBRemote::CreatePacketTable () // t.push_back (Packet (pass_signals_to_inferior, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify which signals are passed to the inferior")); t.push_back (Packet (allocate_memory, &RNBRemote::HandlePacket_AllocateMemory, NULL, "_M", "Allocate memory in the inferior process.")); t.push_back (Packet (deallocate_memory, &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", "Deallocate memory in the inferior process.")); + t.push_back (Packet (save_register_state, &RNBRemote::HandlePacket_SaveRegisterState, NULL, "QSaveRegisterState", "Save the register state for the current thread and return a decimal save ID.")); + t.push_back (Packet (restore_register_state, &RNBRemote::HandlePacket_RestoreRegisterState, NULL, "QRestoreRegisterState:", "Restore the register state given a save ID previosly returned from a call to QSaveRegisterState.")); t.push_back (Packet (memory_region_info, &RNBRemote::HandlePacket_MemoryRegionInfo, NULL, "qMemoryRegionInfo", "Return size and attributes of a memory region that contains the given address")); t.push_back (Packet (get_profile_data, &RNBRemote::HandlePacket_GetProfileData, NULL, "qGetProfileData", "Return profiling data of the current target.")); t.push_back (Packet (set_enable_profiling, &RNBRemote::HandlePacket_SetEnableAsyncProfiling, NULL, "QSetEnableAsyncProfiling", "Enable or disable the profiling of current target.")); @@ -2730,6 +2732,88 @@ RNBRemote::HandlePacket_DeallocateMemory (const char *p) return SendPacket ("E54"); } + +// FORMAT: QSaveRegisterState;thread:TTTT; (when thread suffix is supported) +// FORMAT: QSaveRegisterState (when thread suffix is NOT supported) +// TTTT: thread ID in hex +// +// RESPONSE: +// SAVEID: Where SAVEID is a decimal number that represents the save ID +// that can be passed back into a "QRestoreRegisterState" packet +// EXX: error code +// +// EXAMPLES: +// QSaveRegisterState;thread:1E34; (when thread suffix is supported) +// QSaveRegisterState (when thread suffix is NOT supported) + +rnb_err_t +RNBRemote::HandlePacket_SaveRegisterState (const char *p) +{ + nub_process_t pid = m_ctx.ProcessID (); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p); + if (tid == INVALID_NUB_THREAD) + { + if (m_thread_suffix_supported) + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in QSaveRegisterState packet"); + else + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread was is set with the Hg packet"); + } + + // Get the register context size first by calling with NULL buffer + const uint32_t save_id = DNBThreadSaveRegisterState(pid, tid); + if (save_id != 0) + { + char response[64]; + snprintf (response, sizeof(response), "%u", save_id); + return SendPacket (response); + } + else + { + return SendPacket ("E75"); + } +} +// FORMAT: QRestoreRegisterState:SAVEID;thread:TTTT; (when thread suffix is supported) +// FORMAT: QRestoreRegisterState:SAVEID (when thread suffix is NOT supported) +// TTTT: thread ID in hex +// SAVEID: a decimal number that represents the save ID that was +// returned from a call to "QSaveRegisterState" +// +// RESPONSE: +// OK: successfully restored registers for the specified thread +// EXX: error code +// +// EXAMPLES: +// QRestoreRegisterState:1;thread:1E34; (when thread suffix is supported) +// QRestoreRegisterState:1 (when thread suffix is NOT supported) + +rnb_err_t +RNBRemote::HandlePacket_RestoreRegisterState (const char *p) +{ + nub_process_t pid = m_ctx.ProcessID (); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p); + if (tid == INVALID_NUB_THREAD) + { + if (m_thread_suffix_supported) + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in QSaveRegisterState packet"); + else + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread was is set with the Hg packet"); + } + + StringExtractor packet (p); + packet.SetFilePos(strlen("QRestoreRegisterState:")); // Skip the "QRestoreRegisterState:" + const uint32_t save_id = packet.GetU32(0); + + if (save_id != 0) + { + // Get the register context size first by calling with NULL buffer + if (DNBThreadRestoreRegisterState(pid, tid, save_id)) + return SendPacket ("OK"); + else + return SendPacket ("E77"); + } + return SendPacket ("E76"); +} + static bool GetProcessNameFrom_vAttach (const char *&p, std::string &attach_name) { diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h index 1d5cf012e0b..ca70c7f4271 100644 --- a/lldb/tools/debugserver/source/RNBRemote.h +++ b/lldb/tools/debugserver/source/RNBRemote.h @@ -119,7 +119,9 @@ public: watchpoint_support_info, // 'qWatchpointSupportInfo:' allocate_memory, // '_M' deallocate_memory, // '_m' - + save_register_state, // '_g' + restore_register_state, // '_G' + unknown_type } PacketEnum; @@ -216,6 +218,8 @@ public: rnb_err_t HandlePacket_ILLFORMED (const char *file, int line, const char *p, const char *description); rnb_err_t HandlePacket_AllocateMemory (const char *p); rnb_err_t HandlePacket_DeallocateMemory (const char *p); + rnb_err_t HandlePacket_SaveRegisterState (const char *p); + rnb_err_t HandlePacket_RestoreRegisterState (const char *p); rnb_err_t HandlePacket_MemoryRegionInfo (const char *p); rnb_err_t HandlePacket_GetProfileData(const char *p); rnb_err_t HandlePacket_SetEnableAsyncProfiling(const char *p); |