diff options
9 files changed, 105 insertions, 5 deletions
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 5ca697e1c7e..c876d75248d 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2786,6 +2786,14 @@ public: return error; } + virtual Error + GetWatchpointSupportInfo (uint32_t &num, bool& after) + { + Error error; + error.SetErrorString ("Process::GetWatchpointSupportInfo() not supported"); + return error; + } + lldb::ModuleSP ReadModuleFromMemory (const FileSpec& file_spec, lldb::addr_t header_addr, diff --git a/lldb/include/lldb/Target/StopInfo.h b/lldb/include/lldb/Target/StopInfo.h index 3ed6d804c24..a4933af6312 100644 --- a/lldb/include/lldb/Target/StopInfo.h +++ b/lldb/include/lldb/Target/StopInfo.h @@ -161,14 +161,15 @@ protected: // N.B. running to evaluate a user expression does not count. bool HasTargetRunSinceMe (); -private: - friend class Thread; - - // MakeStopInfoValid is necessary to allow saved stop infos to resurrect themselves as valid. It should - // only need to be called by Thread::RestoreThreadStateFromCheckpoint. + // MakeStopInfoValid is necessary to allow saved stop infos to resurrect themselves as valid. + // It should only be used by Thread::RestoreThreadStateFromCheckpoint and to make sure the one-step + // needed for before-the-fact watchpoints does not prevent us from stopping void MakeStopInfoValid (); +private: + friend class Thread; + DISALLOW_COPY_AND_ASSIGN (StopInfo); }; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 83d2843309a..4fac83d334c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -49,6 +49,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_alloc_dealloc_memory (eLazyBoolCalculate), m_supports_memory_region_info (eLazyBoolCalculate), m_supports_watchpoint_support_info (eLazyBoolCalculate), + m_watchpoints_trigger_after_instruction(eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -1019,6 +1020,17 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) if (m_os_version_major != UINT32_MAX) ++num_keys_decoded; } + else if (name.compare("watchpoint_exceptions_received") == 0) + { + ++num_keys_decoded; + if (strcmp(value.c_str(),"before") == 0) + m_watchpoints_trigger_after_instruction = eLazyBoolNo; + else if (strcmp(value.c_str(),"after") == 0) + m_watchpoints_trigger_after_instruction = eLazyBoolYes; + else + --num_keys_decoded; + } + } if (num_keys_decoded > 0) @@ -1352,6 +1364,30 @@ GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num) } +lldb_private::Error +GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num, bool& after) +{ + Error error(GetWatchpointSupportInfo(num)); + if (error.Success()) + error = GetWatchpointsTriggerAfterInstruction(after); + return error; +} + +lldb_private::Error +GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after) +{ + Error error; + + // we assume watchpoints will happen after running the relevant opcode + // and we only want to override this behavior if we have explicitly + // received a qHostInfo telling us otherwise + if (m_qHostInfo_is_valid != eLazyBoolYes) + after = true; + else + after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo); + return error; +} + int GDBRemoteCommunicationClient::SetSTDIN (char const *path) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index fb578001dc3..a283389d220 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -209,6 +209,12 @@ public: lldb_private::Error GetWatchpointSupportInfo (uint32_t &num); + lldb_private::Error + GetWatchpointSupportInfo (uint32_t &num, bool& after); + + lldb_private::Error + GetWatchpointsTriggerAfterInstruction (bool &after); + const lldb_private::ArchSpec & GetHostArchitecture (); @@ -358,6 +364,7 @@ protected: lldb_private::LazyBool m_supports_alloc_dealloc_memory; lldb_private::LazyBool m_supports_memory_region_info; lldb_private::LazyBool m_supports_watchpoint_support_info; + lldb_private::LazyBool m_watchpoints_trigger_after_instruction; bool m_supports_qProcessInfoPID:1, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 3f8677d1c7e..70d73d3c38a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -223,6 +223,11 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet if (sub != LLDB_INVALID_CPUTYPE) response.Printf ("cpusubtype:%u;", sub); + if (cpu == CPU_TYPE_ARM) + response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. + else + response.Printf("watchpoint_exceptions_received:after;"); + switch (lldb::endian::InlHostByteOrder()) { case eByteOrderBig: response.PutCString ("endian:big;"); break; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index e0d22360156..06d19e40033 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -2015,6 +2015,13 @@ ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num) } Error +ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num, bool& after) +{ + Error error (m_gdb_comm.GetWatchpointSupportInfo (num, after)); + return error; +} + +Error ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr) { Error error; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 04d6ff2e7a8..563b89963fa 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -207,6 +207,9 @@ public: virtual lldb_private::Error GetWatchpointSupportInfo (uint32_t &num); + virtual lldb_private::Error + GetWatchpointSupportInfo (uint32_t &num, bool& after); + virtual bool StartNoticingNewThreads(); diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 113aa57aacb..5b782beb4bd 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -461,6 +461,36 @@ public: if (wp_sp) { ExecutionContext exe_ctx (m_thread.GetStackFrameAtIndex(0)); + { + // check if this process is running on an architecture where watchpoints trigger + // before the associated instruction runs. if so, disable the WP, single-step and then + // re-enable the watchpoint + Process* process = exe_ctx.GetProcessPtr(); + if (process) + { + uint32_t num; bool wp_triggers_after; + if (process->GetWatchpointSupportInfo(num, wp_triggers_after).Success()) + { + if (!wp_triggers_after) + { + process->DisableWatchpoint(wp_sp.get()); + + ThreadPlan *new_plan = m_thread.QueueThreadPlanForStepSingleInstruction(false, // step-over + false, // abort_other_plans + true); // stop_other_threads + new_plan->SetIsMasterPlan (true); + new_plan->SetOkayToDiscard (false); + process->GetThreadList().SetSelectedThreadByID (m_thread.GetID()); + process->Resume (); + process->WaitForProcessToStop (NULL); + process->GetThreadList().SetSelectedThreadByID (m_thread.GetID()); + MakeStopInfoValid(); // make sure we do not fail to stop because of the single-step taken above + + process->EnableWatchpoint(wp_sp.get()); + } + } + } + } StoppointCallbackContext context (event_ptr, exe_ctx, false); bool stop_requested = wp_sp->InvokeCallback (&context); // Also make sure that the callback hasn't continued the target. diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index d1c66150d58..c66e6f6c93f 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -3587,10 +3587,13 @@ RNBRemote::HandlePacket_qHostInfo (const char *p) if (cputype == CPU_TYPE_ARM) { strm << "ostype:ios;"; + // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. + strm << "watchpoint_exceptions_received:before;"; } else { strm << "ostype:macosx;"; + strm << "watchpoint_exceptions_received:after;"; } // char ostype[64]; // len = sizeof(ostype); |