[Lldb-commits] [lldb] r227930 - Implement setting and clearing watchpoints.
Chaoren Lin
chaorenl at google.com
Mon Feb 2 17:51:47 PST 2015
Author: chaoren
Date: Mon Feb 2 19:51:47 2015
New Revision: 227930
URL: http://llvm.org/viewvc/llvm-project?rev=227930&view=rev
Log:
Implement setting and clearing watchpoints.
Added:
lldb/trunk/include/lldb/Host/common/NativeWatchpointList.h
lldb/trunk/source/Host/common/NativeWatchpointList.cpp
Modified:
lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h
lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h
lldb/trunk/source/Host/CMakeLists.txt
lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
lldb/trunk/source/Host/common/NativeRegisterContext.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Modified: lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h (original)
+++ lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h Mon Feb 2 19:51:47 2015
@@ -18,6 +18,7 @@
#include "lldb/Host/Mutex.h"
#include "NativeBreakpointList.h"
+#include "NativeWatchpointList.h"
namespace lldb_private
{
@@ -130,6 +131,9 @@ namespace lldb_private
//----------------------------------------------------------------------
// Watchpoint functions
//----------------------------------------------------------------------
+ virtual const NativeWatchpointList::WatchpointMap&
+ GetWatchpointMap () const;
+
virtual uint32_t
GetMaxWatchpoints () const;
@@ -295,6 +299,7 @@ namespace lldb_private
Mutex m_delegates_mutex;
std::vector<NativeDelegate*> m_delegates;
NativeBreakpointList m_breakpoint_list;
+ NativeWatchpointList m_watchpoint_list;
int m_terminal_fd;
uint32_t m_stop_id;
Modified: lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h (original)
+++ lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h Mon Feb 2 19:51:47 2015
@@ -15,6 +15,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private.h"
+#include "lldb/Host/common/NativeWatchpointList.h"
namespace lldb_private {
@@ -95,6 +96,9 @@ public:
virtual bool
ClearHardwareWatchpoint (uint32_t hw_index);
+ virtual Error
+ ClearAllHardwareWatchpoints ();
+
virtual bool
HardwareSingleStep (bool enable);
Added: lldb/trunk/include/lldb/Host/common/NativeWatchpointList.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/common/NativeWatchpointList.h?rev=227930&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Host/common/NativeWatchpointList.h (added)
+++ lldb/trunk/include/lldb/Host/common/NativeWatchpointList.h Mon Feb 2 19:51:47 2015
@@ -0,0 +1,47 @@
+//===-- NativeWatchpointList.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_NativeWatchpointList_h_
+#define liblldb_NativeWatchpointList_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Error.h"
+
+#include <map>
+
+namespace lldb_private
+{
+ struct NativeWatchpoint
+ {
+ lldb::addr_t m_addr;
+ size_t m_size;
+ uint32_t m_watch_flags;
+ bool m_hardware;
+ };
+
+ class NativeWatchpointList
+ {
+ public:
+ Error
+ Add (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware);
+
+ Error
+ Remove (lldb::addr_t addr);
+
+ using WatchpointMap = std::map<lldb::addr_t, NativeWatchpoint>;
+
+ const WatchpointMap&
+ GetWatchpointMap () const;
+
+ private:
+ WatchpointMap m_watchpoints;
+ };
+}
+
+#endif // ifndef liblldb_NativeWatchpointList_h_
Modified: lldb/trunk/source/Host/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/CMakeLists.txt?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Host/CMakeLists.txt (original)
+++ lldb/trunk/source/Host/CMakeLists.txt Mon Feb 2 19:51:47 2015
@@ -18,6 +18,7 @@ add_host_subdirectory(common
common/MonitoringProcessLauncher.cpp
common/NativeBreakpoint.cpp
common/NativeBreakpointList.cpp
+ common/NativeWatchpointList.cpp
common/NativeProcessProtocol.cpp
common/NativeRegisterContext.cpp
common/NativeRegisterContextRegisterInfo.cpp
Modified: lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeProcessProtocol.cpp?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/NativeProcessProtocol.cpp (original)
+++ lldb/trunk/source/Host/common/NativeProcessProtocol.cpp Mon Feb 2 19:51:47 2015
@@ -39,6 +39,7 @@ NativeProcessProtocol::NativeProcessProt
m_delegates_mutex (Mutex::eMutexTypeRecursive),
m_delegates (),
m_breakpoint_list (),
+ m_watchpoint_list (),
m_terminal_fd (-1),
m_stop_id (0)
{
@@ -159,6 +160,12 @@ NativeProcessProtocol::GetByteOrder (lld
return true;
}
+const NativeWatchpointList::WatchpointMap&
+NativeProcessProtocol::GetWatchpointMap () const
+{
+ return m_watchpoint_list.GetWatchpointMap();
+}
+
uint32_t
NativeProcessProtocol::GetMaxWatchpoints () const
{
@@ -199,9 +206,6 @@ NativeProcessProtocol::SetWatchpoint (ll
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- // FIXME save the watchpoint on the set of process watchpoint vars
- // so we can add them to a thread each time a new thread is registered.
-
// Update the thread list
UpdateThreads ();
@@ -261,15 +265,12 @@ NativeProcessProtocol::SetWatchpoint (ll
return thread_error;
}
}
- return Error ();
+ return m_watchpoint_list.Add (addr, size, watch_flags, hardware);
}
Error
NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr)
{
- // FIXME remove the watchpoint on the set of process watchpoint vars
- // so we can add them to a thread each time a new thread is registered.
-
// Update the thread list
UpdateThreads ();
@@ -292,7 +293,8 @@ NativeProcessProtocol::RemoveWatchpoint
overall_error = thread_error;
}
}
- return overall_error;
+ const Error error = m_watchpoint_list.Remove(addr);
+ return overall_error.Fail() ? overall_error : error;
}
bool
Modified: lldb/trunk/source/Host/common/NativeRegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeRegisterContext.cpp?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/NativeRegisterContext.cpp (original)
+++ lldb/trunk/source/Host/common/NativeRegisterContext.cpp Mon Feb 2 19:51:47 2015
@@ -297,6 +297,12 @@ NativeRegisterContext::ClearHardwareWatc
return false;
}
+Error
+NativeRegisterContext::ClearAllHardwareWatchpoints ()
+{
+ return Error ("not implemented");
+}
+
bool
NativeRegisterContext::HardwareSingleStep (bool enable)
{
Added: lldb/trunk/source/Host/common/NativeWatchpointList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeWatchpointList.cpp?rev=227930&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeWatchpointList.cpp (added)
+++ lldb/trunk/source/Host/common/NativeWatchpointList.cpp Mon Feb 2 19:51:47 2015
@@ -0,0 +1,35 @@
+//===-- NativeWatchpointList.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/NativeWatchpointList.h"
+
+#include "lldb/Core/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Error
+NativeWatchpointList::Add (addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+ m_watchpoints[addr] = {addr, size, watch_flags, hardware};
+ return Error ();
+}
+
+Error
+NativeWatchpointList::Remove (addr_t addr)
+{
+ m_watchpoints.erase(addr);
+ return Error ();
+}
+
+const NativeWatchpointList::WatchpointMap&
+NativeWatchpointList::GetWatchpointMap () const
+{
+ return m_watchpoints;
+}
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Mon Feb 2 19:51:47 2015
@@ -2316,7 +2316,7 @@ NativeProcessLinux::MonitorSIGTRAP(const
// Mark the thread as stopped at watchpoint.
// The address is at (lldb::addr_t)info->si_addr if we need it.
if (thread_sp)
- reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedByWatchpoint ();
else
{
if (log)
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp Mon Feb 2 19:51:47 2015
@@ -1032,3 +1032,170 @@ NativeRegisterContextLinux_x86_64::Write
return process_p->WriteGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
}
+Error
+NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint8_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Error ("Watchpoint index out of range");
+
+ RegisterValue reg_value;
+ Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value);
+ if (error.Fail()) return error;
+
+ uint64_t status_bits = reg_value.GetAsUInt64();
+
+ bool is_hit = status_bits & (1 << wp_index);
+
+ error.SetError (!is_hit, lldb::eErrorTypeInvalid);
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Error ("Watchpoint index out of range");
+
+ RegisterValue reg_value;
+ Error error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value);
+ if (error.Fail()) return error;
+
+ uint64_t control_bits = reg_value.GetAsUInt64();
+
+ bool is_vacant = !(control_bits & (1 << (2 * wp_index)));
+
+ error.SetError (!is_vacant, lldb::eErrorTypeInvalid);
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
+
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Error ("Watchpoint index out of range");
+
+ if (watch_flags != 0x1 && watch_flags != 0x3)
+ return Error ("Invalid read/write bits for watchpoint");
+
+ if (size != 1 && size != 2 && size != 4 && size != 8)
+ return Error ("Invalid size for watchpoint");
+
+ Error error = IsWatchpointVacant (wp_index);
+ if (error.Fail()) return error;
+
+ RegisterValue reg_value;
+ error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value);
+ if (error.Fail()) return error;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // set bits 1, 3, 5, or 7
+ uint64_t enable_bit = 1 << (2 * wp_index);
+
+ // set bits 16-17, 20-21, 24-25, or 28-29
+ // with 0b01 for write, and 0b11 for read/write
+ uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
+
+ // set bits 18-19, 22-23, 26-27, or 30-31
+ // with 0b00, 0b01, 0b10, or 0b11
+ // for 1, 2, 8 (if supported), or 4 bytes, respectively
+ uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
+
+ uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
+
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+
+ control_bits |= enable_bit | rw_bits | size_bits;
+
+ error = WriteRegister(m_reg_info.first_dr + wp_index, RegisterValue(addr));
+ if (error.Fail()) return error;
+
+ error = WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits));
+ if (error.Fail()) return error;
+
+ error.Clear();
+ return error;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return false;
+
+ RegisterValue reg_value;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // clear bits 0, 1, 2, or 3 of the debug status register (DR6)
+ Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value);
+ if (error.Fail()) return false;
+ uint64_t bit_mask = 1 << wp_index;
+ uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ error = WriteRegister(lldb_dr6_x86_64, RegisterValue(status_bits));
+ if (error.Fail()) return false;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
+ // of the debug control register (DR7)
+ error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value);
+ if (error.Fail()) return false;
+ bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ return WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits)).Success();
+}
+
+Error
+NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints()
+{
+ RegisterValue reg_value;
+
+ // clear bits {0-4} of the debug status register (DR6)
+ Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value);
+ if (error.Fail()) return error;
+ uint64_t bit_mask = 0xF;
+ uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ error = WriteRegister(lldb_dr6_x86_64, RegisterValue(status_bits));
+ if (error.Fail()) return error;
+
+ // clear bits {0-7,16-31} of the debug control register (DR7)
+ error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value);
+ if (error.Fail()) return error;
+ bit_mask = 0xFF | (0xFFFF << 16);
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ return WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits));
+}
+
+uint32_t
+NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index)
+ if (IsWatchpointVacant(wp_index).Success())
+ {
+ if (SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index).Fail())
+ continue;
+ return wp_index;
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+lldb::addr_t
+NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return LLDB_INVALID_ADDRESS;
+ RegisterValue reg_value;
+ if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail())
+ return LLDB_INVALID_ADDRESS;
+ return reg_value.GetAsUInt64();
+}
+
+uint32_t
+NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints ()
+{
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h Mon Feb 2 19:51:47 2015
@@ -42,6 +42,32 @@ namespace lldb_private
Error
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
+ Error
+ IsWatchpointHit(uint8_t wp_index);
+
+ Error
+ IsWatchpointVacant(uint32_t wp_index);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t wp_index);
+
+ Error
+ ClearAllHardwareWatchpoints ();
+
+ Error
+ SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, uint32_t wp_index);
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags);
+
+ lldb::addr_t
+ GetWatchpointAddress(uint32_t wp_index);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
private:
// Private member types.
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp Mon Feb 2 19:51:47 2015
@@ -10,6 +10,7 @@
#include "NativeThreadLinux.h"
#include <signal.h>
+#include <sstream>
#include "NativeProcessLinux.h"
#include "NativeRegisterContextLinux_x86_64.h"
@@ -101,8 +102,15 @@ NativeThreadLinux::GetStopReason (Thread
if (log)
LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread:");
stop_info = m_stop_info;
- if (m_stop_info.reason == StopReason::eStopReasonException)
- description = m_stop_description;
+ switch (m_stop_info.reason)
+ {
+ case StopReason::eStopReasonException:
+ case StopReason::eStopReasonBreakpoint:
+ case StopReason::eStopReasonWatchpoint:
+ description = m_stop_description;
+ default:
+ break;
+ }
if (log)
LogThreadStopInfo (*log, stop_info, "returned stop_info:");
@@ -209,15 +217,30 @@ NativeThreadLinux::GetRegisterContext ()
Error
NativeThreadLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
{
- // TODO implement
- return Error ("not implemented");
+ if (!hardware)
+ return Error ("not implemented");
+ Error error = RemoveWatchpoint(addr);
+ if (error.Fail()) return error;
+ NativeRegisterContextSP reg_ctx = GetRegisterContext ();
+ uint32_t wp_index =
+ reg_ctx->SetHardwareWatchpoint (addr, size, watch_flags);
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return Error ("Setting hardware watchpoint failed.");
+ m_watchpoint_index_map.insert({addr, wp_index});
+ return Error ();
}
Error
NativeThreadLinux::RemoveWatchpoint (lldb::addr_t addr)
{
- // TODO implement
- return Error ("not implemented");
+ auto wp = m_watchpoint_index_map.find(addr);
+ if (wp == m_watchpoint_index_map.end())
+ return Error ();
+ uint32_t wp_index = wp->second;
+ m_watchpoint_index_map.erase(wp);
+ if (GetRegisterContext()->ClearHardwareWatchpoint(wp_index))
+ return Error ();
+ return Error ("Clearing hardware watchpoint failed.");
}
void
@@ -243,6 +266,20 @@ NativeThreadLinux::SetRunning ()
m_stop_info.reason = StopReason::eStopReasonNone;
m_stop_description.clear();
+
+ // If watchpoints have been set, but none on this thread,
+ // then this is a new thread. So set all existing watchpoints.
+ if (m_watchpoint_index_map.empty())
+ {
+ const auto &watchpoint_map = GetProcess()->GetWatchpointMap();
+ if (watchpoint_map.empty()) return;
+ GetRegisterContext()->ClearAllHardwareWatchpoints();
+ for (const auto &pair : watchpoint_map)
+ {
+ const auto& wp = pair.second;
+ SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware);
+ }
+ }
}
void
@@ -313,18 +350,56 @@ NativeThreadLinux::SetStoppedByBreakpoin
m_stop_info.reason = StopReason::eStopReasonBreakpoint;
m_stop_info.details.signal.signo = SIGTRAP;
+ m_stop_description.clear();
+}
+
+void
+NativeThreadLinux::SetStoppedByWatchpoint ()
+{
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonWatchpoint;
+ m_stop_info.details.signal.signo = SIGTRAP;
+
+ NativeRegisterContextLinux_x86_64 *reg_ctx =
+ reinterpret_cast<NativeRegisterContextLinux_x86_64*> (GetRegisterContext().get());
+ const uint32_t num_hw_watchpoints =
+ reg_ctx->NumSupportedHardwareWatchpoints();
+
+ m_stop_description.clear ();
+ for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index)
+ if (reg_ctx->IsWatchpointHit(wp_index).Success())
+ {
+ std::ostringstream ostr;
+ ostr << reg_ctx->GetWatchpointAddress(wp_index) << " " << wp_index;
+ m_stop_description = ostr.str();
+ return;
+ }
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ {
+ NativeProcessProtocolSP m_process_sp = m_process_wp.lock ();
+ lldb::pid_t pid = m_process_sp ? m_process_sp->GetID () : LLDB_INVALID_PROCESS_ID;
+ log->Printf ("NativeThreadLinux: thread (pid=%" PRIu64 ", tid=%" PRIu64 ") "
+ "stopped by a watchpoint, but failed to find it",
+ pid, GetID ());
+ }
}
bool
NativeThreadLinux::IsStoppedAtBreakpoint ()
{
- // Are we stopped? If not, this can't be a breakpoint.
- if (GetState () != StateType::eStateStopped)
- return false;
+ return GetState () == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonBreakpoint;
+}
- // Was the stop reason a signal with signal number SIGTRAP? If not, not a breakpoint.
- return (m_stop_info.reason == StopReason::eStopReasonBreakpoint) &&
- (m_stop_info.details.signal.signo == SIGTRAP);
+bool
+NativeThreadLinux::IsStoppedAtWatchpoint ()
+{
+ return GetState () == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonWatchpoint;
}
void
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h Mon Feb 2 19:51:47 2015
@@ -13,6 +13,8 @@
#include "lldb/lldb-private-forward.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
+#include <map>
+
namespace lldb_private
{
class NativeProcessLinux;
@@ -73,9 +75,15 @@ namespace lldb_private
void
SetStoppedByBreakpoint ();
+ void
+ SetStoppedByWatchpoint ();
+
bool
IsStoppedAtBreakpoint ();
+ bool
+ IsStoppedAtWatchpoint ();
+
void
SetStoppedByTrace ();
@@ -101,6 +109,8 @@ namespace lldb_private
ThreadStopInfo m_stop_info;
NativeRegisterContextSP m_reg_context_sp;
std::string m_stop_description;
+ using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+ WatchpointIndexMap m_watchpoint_index_map;
};
}
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h Mon Feb 2 19:51:47 2015
@@ -27,6 +27,16 @@
#include "Utility/StringExtractorGDBRemote.h"
+typedef enum
+{
+ eStoppointInvalid = -1,
+ eBreakpointSoftware = 0,
+ eBreakpointHardware,
+ eWatchpointWrite,
+ eWatchpointRead,
+ eWatchpointReadWrite
+} GDBStoppointType;
+
class ProcessGDBRemote;
class GDBRemoteCommunication : public lldb_private::Communication
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h Mon Feb 2 19:51:47 2015
@@ -21,15 +21,6 @@
#include "GDBRemoteCommunication.h"
-typedef enum
-{
- eBreakpointSoftware = 0,
- eBreakpointHardware,
- eWatchpointWrite,
- eWatchpointRead,
- eWatchpointReadWrite
-} GDBStoppointType;
-
class GDBRemoteCommunicationClient : public GDBRemoteCommunication
{
public:
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Mon Feb 2 19:51:47 2015
@@ -278,6 +278,10 @@ GDBRemoteCommunicationServer::GetPacketA
packet_result = Handle_qPlatform_shell (packet);
break;
+ case StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo:
+ packet_result = Handle_qWatchpointSupportInfo (packet);
+ break;
+
case StringExtractorGDBRemote::eServerPacketType_C:
packet_result = Handle_C (packet);
break;
@@ -3726,8 +3730,6 @@ GDBRemoteCommunicationServer::Handle_qMe
GDBRemoteCommunicationServer::PacketResult
GDBRemoteCommunicationServer::Handle_Z (StringExtractorGDBRemote &packet)
{
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
-
// We don't support if we're not llgs.
if (!IsGdbServer())
return SendUnimplementedResponse ("");
@@ -3735,12 +3737,13 @@ GDBRemoteCommunicationServer::Handle_Z (
// Ensure we have a process.
if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
return SendErrorResponse (0x15);
}
- // Parse out software or hardware breakpoint requested.
+ // Parse out software or hardware breakpoint or watchpoint requested.
packet.SetFilePos (strlen("Z"));
if (packet.GetBytesLeft() < 1)
return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier");
@@ -3748,61 +3751,85 @@ GDBRemoteCommunicationServer::Handle_Z (
bool want_breakpoint = true;
bool want_hardware = false;
- const char breakpoint_type_char = packet.GetChar ();
- switch (breakpoint_type_char)
- {
- case '0': want_hardware = false; want_breakpoint = true; break;
- case '1': want_hardware = true; want_breakpoint = true; break;
- case '2': want_breakpoint = false; break;
- case '3': want_breakpoint = false; break;
+ const GDBStoppointType stoppoint_type =
+ GDBStoppointType(packet.GetS32 (eStoppointInvalid));
+ switch (stoppoint_type)
+ {
+ case eBreakpointSoftware:
+ want_hardware = false; want_breakpoint = true; break;
+ case eBreakpointHardware:
+ want_hardware = true; want_breakpoint = true; break;
+ case eWatchpointWrite:
+ want_hardware = true; want_breakpoint = false; break;
+ case eWatchpointRead:
+ want_hardware = true; want_breakpoint = false; break;
+ case eWatchpointReadWrite:
+ want_hardware = true; want_breakpoint = false; break;
default:
return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier");
}
if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
- return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after breakpoint type");
+ return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after stoppoint type");
- // FIXME implement watchpoint support.
- if (!want_breakpoint)
- return SendUnimplementedResponse ("watchpoint support not yet implemented");
-
- // Parse out the breakpoint address.
+ // Parse out the stoppoint address.
if (packet.GetBytesLeft() < 1)
return SendIllFormedResponse(packet, "Too short Z packet, missing address");
- const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0);
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address");
- // Parse out the breakpoint kind (i.e. size hint for opcode size).
- const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
- if (kind == std::numeric_limits<uint32_t>::max ())
- return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse kind argument");
+ // Parse out the stoppoint size (i.e. size hint for opcode size).
+ const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (size == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse size argument");
if (want_breakpoint)
{
// Try to set the breakpoint.
- const Error error = m_debugged_process_sp->SetBreakpoint (breakpoint_addr, kind, want_hardware);
+ const Error error = m_debugged_process_sp->SetBreakpoint (addr, size, want_hardware);
if (error.Success ())
return SendOKResponse ();
- else
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64
+ " failed to set breakpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+ else
+ {
+ uint32_t watch_flags = 0x0;
+ switch (stoppoint_type)
{
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to set breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
- return SendErrorResponse (0x09);
+ case eWatchpointWrite: watch_flags = 0x1; break;
+ case eWatchpointRead: watch_flags = 0x3; break;
+ case eWatchpointReadWrite: watch_flags = 0x3; break;
}
- }
- // FIXME fix up after watchpoints are handled.
- return SendUnimplementedResponse ("");
+ // Try to set the watchpoint.
+ const Error error = m_debugged_process_sp->SetWatchpoint (
+ addr, size, watch_flags, want_hardware);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64
+ " failed to set watchpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
}
GDBRemoteCommunicationServer::PacketResult
GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet)
{
- Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
-
// We don't support if we're not llgs.
if (!IsGdbServer())
return SendUnimplementedResponse ("");
@@ -3810,66 +3837,81 @@ GDBRemoteCommunicationServer::Handle_z (
// Ensure we have a process.
if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
return SendErrorResponse (0x15);
}
- // Parse out software or hardware breakpoint requested.
+ // Parse out software or hardware breakpoint or watchpoint requested.
packet.SetFilePos (strlen("z"));
if (packet.GetBytesLeft() < 1)
return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier");
bool want_breakpoint = true;
- const char breakpoint_type_char = packet.GetChar ();
- switch (breakpoint_type_char)
- {
- case '0': want_breakpoint = true; break;
- case '1': want_breakpoint = true; break;
- case '2': want_breakpoint = false; break;
- case '3': want_breakpoint = false; break;
+ const GDBStoppointType stoppoint_type =
+ GDBStoppointType(packet.GetS32 (eStoppointInvalid));
+ switch (stoppoint_type)
+ {
+ case eBreakpointHardware: want_breakpoint = true; break;
+ case eBreakpointSoftware: want_breakpoint = true; break;
+ case eWatchpointWrite: want_breakpoint = false; break;
+ case eWatchpointRead: want_breakpoint = false; break;
+ case eWatchpointReadWrite: want_breakpoint = false; break;
default:
return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier");
}
if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
- return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after breakpoint type");
-
- // FIXME implement watchpoint support.
- if (!want_breakpoint)
- return SendUnimplementedResponse ("watchpoint support not yet implemented");
+ return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after stoppoint type");
- // Parse out the breakpoint address.
+ // Parse out the stoppoint address.
if (packet.GetBytesLeft() < 1)
return SendIllFormedResponse(packet, "Too short z packet, missing address");
- const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0);
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address");
- // Parse out the breakpoint kind (i.e. size hint for opcode size).
- const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
- if (kind == std::numeric_limits<uint32_t>::max ())
- return SendIllFormedResponse(packet, "Malformed z packet, failed to parse kind argument");
+ /*
+ // Parse out the stoppoint size (i.e. size hint for opcode size).
+ const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (size == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed z packet, failed to parse size argument");
+ */
if (want_breakpoint)
{
// Try to clear the breakpoint.
- const Error error = m_debugged_process_sp->RemoveBreakpoint (breakpoint_addr);
+ const Error error = m_debugged_process_sp->RemoveBreakpoint (addr);
if (error.Success ())
return SendOKResponse ();
- else
- {
- if (log)
- log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to remove breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
- return SendErrorResponse (0x09);
- }
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64
+ " failed to remove breakpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+ else
+ {
+ // Try to clear the watchpoint.
+ const Error error = m_debugged_process_sp->RemoveWatchpoint (addr);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64
+ " failed to remove watchpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
}
-
- // FIXME fix up after watchpoints are handled.
- return SendUnimplementedResponse ("");
}
GDBRemoteCommunicationServer::PacketResult
@@ -4305,6 +4347,30 @@ GDBRemoteCommunicationServer::Handle_qTh
return SendStopReplyPacketForThread (tid);
}
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet)
+{
+ // Only the gdb server handles this.
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse (packet.GetStringRef ().c_str ());
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp ||
+ m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse (68);
+
+ packet.SetFilePos(strlen("qWatchpointSupportInfo"));
+ if (packet.GetBytesLeft() == 0)
+ return SendOKResponse();
+ if (packet.GetChar() != ':')
+ return SendErrorResponse(67);
+
+ uint32_t num = m_debugged_process_sp->GetMaxWatchpoints();
+ StreamGDBRemote response;
+ response.Printf ("num:%d;", num);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
void
GDBRemoteCommunicationServer::FlushInferiorOutput ()
{
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h Mon Feb 2 19:51:47 2015
@@ -465,6 +465,9 @@ protected:
PacketResult
Handle_qThreadStopInfo (StringExtractorGDBRemote &packet);
+ PacketResult
+ Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet);
+
void
SetCurrentThreadID (lldb::tid_t tid);
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=227930&r1=227929&r2=227930&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Mon Feb 2 19:51:47 2015
@@ -1844,8 +1844,24 @@ ProcessGDBRemote::SetThreadStopInfo (Str
}
else if (reason.compare("watchpoint") == 0)
{
- break_id_t watch_id = LLDB_INVALID_WATCH_ID;
- // TODO: locate the watchpoint somehow...
+ StringExtractor desc_extractor(description.c_str());
+ addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
+ uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32);
+ watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
+ if (wp_addr != LLDB_INVALID_ADDRESS)
+ {
+ WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
+ if (wp_sp)
+ {
+ wp_sp->SetHardwareIndex(wp_index);
+ watch_id = wp_sp->GetID();
+ }
+ }
+ if (watch_id == LLDB_INVALID_WATCH_ID)
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS));
+ if (log) log->Printf ("failed to find watchpoint");
+ }
thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id));
handled = true;
}
More information about the lldb-commits
mailing list