[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