[Lldb-commits] [lldb] r239991 - [LLDB][MIPS] Hardware Watchpoints for MIPS

Mohit K. Bhakkad mohit.bhakkad at gmail.com
Wed Jun 17 21:53:18 PDT 2015


Author: mohit.bhakkad
Date: Wed Jun 17 23:53:18 2015
New Revision: 239991

URL: http://llvm.org/viewvc/llvm-project?rev=239991&view=rev
Log:
[LLDB][MIPS] Hardware Watchpoints for MIPS

Reviewers: clayborg, jingham.
Subscribers: jaydeep, bhushan, dsanders, sagar, lldb-commits.
Differential Revision: http://reviews.llvm.org/D9142

Modified:
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp

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=239991&r1=239990&r2=239991&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Wed Jun 17 23:53:18 2015
@@ -2011,6 +2011,27 @@ NativeProcessLinux::MonitorSIGTRAP(const
         break;
 
     case SI_KERNEL:
+#if defined __mips__
+        // For mips there is no special signal for watchpoint
+        // So we check for watchpoint in kernel trap
+        if (thread_sp)
+        {
+            // If a watchpoint was hit, report it
+            uint32_t wp_index;
+            Error error = thread_sp->GetRegisterContext()->GetWatchpointHitIndex(wp_index, NULL);
+            if (error.Fail() && log)
+                log->Printf("NativeProcessLinux::%s() "
+                            "received error while checking for watchpoint hits, "
+                            "pid = %" PRIu64 " error = %s",
+                            __FUNCTION__, pid, error.AsCString());
+            if (wp_index != LLDB_INVALID_INDEX32)
+            {
+                MonitorWatchpoint(pid, thread_sp, wp_index);
+                break;
+            }
+        }
+        // NO BREAK
+#endif
     case TRAP_BRKPT:
         MonitorBreakpoint(pid, thread_sp);
         break;

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp?rev=239991&r1=239990&r2=239991&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp Wed Jun 17 23:53:18 2015
@@ -26,6 +26,53 @@
 #include "Plugins/Process/Utility/RegisterContextLinux_mips64.h"
 #include "Plugins/Process/Utility/RegisterContextLinux_mips.h"
 
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#ifndef PTRACE_GET_WATCH_REGS
+enum pt_watch_style
+{
+    pt_watch_style_mips32,
+    pt_watch_style_mips64
+};
+struct mips32_watch_regs
+{
+    uint32_t watchlo[8];
+    uint16_t watchhi[8];
+    uint16_t watch_masks[8];
+    uint32_t num_valid;
+} __attribute__((aligned(8)));
+
+struct mips64_watch_regs
+{
+    uint64_t watchlo[8];
+    uint16_t watchhi[8];
+    uint16_t watch_masks[8];
+    uint32_t num_valid;
+} __attribute__((aligned(8)));
+
+struct pt_watch_regs
+{
+    enum pt_watch_style style;
+    union
+    {
+        struct mips32_watch_regs mips32;
+        struct mips64_watch_regs mips64;
+    };
+};
+
+#define PTRACE_GET_WATCH_REGS 0xd0
+#define PTRACE_SET_WATCH_REGS 0xd1
+#endif
+
+#define W (1 << 0)
+#define R (1 << 1)
+#define I (1 << 2)
+
+#define IRW  (I | R | W)
+
+struct pt_watch_regs default_watch_regs;
+
 using namespace lldb_private;
 using namespace lldb_private::process_linux;
 
@@ -281,6 +328,47 @@ namespace
         const RegisterValue &m_value;
     };
 
+    //------------------------------------------------------------------------------
+    /// @class ReadWatchPointRegOperation
+    /// @brief Implements NativeProcessLinux::ReadWatchPointRegisterValue.
+    class ReadWatchPointRegOperation : public Operation
+    {
+    public:
+        ReadWatchPointRegOperation (
+            lldb::tid_t tid,
+            void* watch_readback) :
+            m_tid(tid),
+            m_watch_readback(watch_readback)
+            {
+            }
+
+        void Execute(NativeProcessLinux *monitor) override;
+
+    private:
+        lldb::tid_t m_tid;
+        void* m_watch_readback;
+    };
+
+    //------------------------------------------------------------------------------
+    /// @class SetWatchPointRegOperation
+    /// @brief Implements NativeProcessLinux::SetWatchPointRegisterValue.
+    class SetWatchPointRegOperation : public Operation
+    {
+    public:
+        SetWatchPointRegOperation (
+            lldb::tid_t tid,
+            void* watch_reg_value) :
+            m_tid(tid),
+            m_watch_reg_value(watch_reg_value)
+            {
+            }
+
+        void Execute(NativeProcessLinux *monitor) override;
+
+    private:
+        lldb::tid_t m_tid;
+        void* m_watch_reg_value;
+    };
 } // end of anonymous namespace
 
 void
@@ -310,6 +398,18 @@ WriteRegOperation::Execute(NativeProcess
     }
 }
 
+void
+ReadWatchPointRegOperation::Execute(NativeProcessLinux *monitor)
+{
+    NativeProcessLinux::PtraceWrapper(PTRACE_GET_WATCH_REGS, m_tid, m_watch_readback, NULL, NULL, m_error);
+}
+
+void
+SetWatchPointRegOperation::Execute(NativeProcessLinux *monitor)
+{
+    NativeProcessLinux::PtraceWrapper(PTRACE_SET_WATCH_REGS, m_tid, m_watch_reg_value, NULL, NULL, m_error);
+}
+
 NativeRegisterContextLinux*
 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
                                                                  NativeThreadProtocol &native_thread,
@@ -373,6 +473,10 @@ NativeRegisterContextLinux_mips64::Nativ
 
     // Clear out the FPR state.
     ::memset(&m_fpr, 0, sizeof(FPR_mips));
+
+    // init h/w watchpoint addr map
+    for (int index = 0;index <= MAX_NUM_WP; index++)
+        hw_addr_map[index] = LLDB_INVALID_ADDRESS;
 }
 
 uint32_t
@@ -655,11 +759,216 @@ NativeRegisterContextLinux_mips64::IsFPR
     return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr);
 }
 
+static uint32_t
+GetWatchHi (struct pt_watch_regs *regs, uint32_t index)
+{
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+    if (regs->style == pt_watch_style_mips32)
+        return regs->mips32.watchhi[index];
+    else if (regs->style == pt_watch_style_mips64)
+        return regs->mips64.watchhi[index];
+    else
+        log->Printf("Invalid watch register style");
+}
+
+static void
+SetWatchHi (struct pt_watch_regs *regs, uint32_t index, uint16_t value)
+{
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+    if (regs->style == pt_watch_style_mips32)
+        regs->mips32.watchhi[index] = value;
+    else if (regs->style == pt_watch_style_mips64)
+        regs->mips64.watchhi[index] = value;
+    else
+        log->Printf("Invalid watch register style");
+}
+
+static lldb::addr_t
+GetWatchLo (struct pt_watch_regs *regs, uint32_t index)
+{
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+    if (regs->style == pt_watch_style_mips32)
+        return regs->mips32.watchlo[index];
+    else if (regs->style == pt_watch_style_mips64)
+        return regs->mips64.watchlo[index];
+    else
+        log->Printf("Invalid watch register style");
+}
+
+static void
+SetWatchLo (struct pt_watch_regs *regs, uint32_t index, uint64_t value)
+{
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+    if (regs->style == pt_watch_style_mips32)
+        regs->mips32.watchlo[index] = (uint32_t) value;
+    else if (regs->style == pt_watch_style_mips64)
+        regs->mips64.watchlo[index] = value;
+    else
+        log->Printf("Invalid watch register style");
+}
+
+static uint32_t
+GetIRWMask (struct pt_watch_regs *regs, uint32_t index)
+{
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+    if (regs->style == pt_watch_style_mips32)
+        return regs->mips32.watch_masks[index] & IRW;
+    else if (regs->style == pt_watch_style_mips64)
+        return regs->mips64.watch_masks[index] & IRW;
+    else
+        log->Printf("Invalid watch register style");
+}
+
+static uint32_t
+GetRegMask (struct pt_watch_regs *regs, uint32_t index)
+{
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+    if (regs->style == pt_watch_style_mips32)
+        return regs->mips32.watch_masks[index] & ~IRW;
+    else if (regs->style == pt_watch_style_mips64)
+        return regs->mips64.watch_masks[index] & ~IRW;
+    else
+        log->Printf("Invalid watch register style");
+}
+
+static lldb::addr_t
+GetRangeMask (lldb::addr_t mask)
+{
+    lldb::addr_t mask_bit = 1;
+    while (mask_bit < mask)
+    {
+        mask = mask | mask_bit;
+        mask_bit <<= 1;
+    }
+    return mask;
+}
+
+static int
+GetVacantWatchIndex (struct pt_watch_regs *regs, lldb::addr_t addr, uint32_t size, uint32_t irw, uint32_t num_valid)
+{
+    lldb::addr_t last_byte = addr + size - 1;
+    lldb::addr_t mask = GetRangeMask (addr ^ last_byte) | IRW;
+    lldb::addr_t base_addr = addr & ~mask;
+
+    // Check if this address is already watched by previous watch points.
+    lldb::addr_t lo;
+    uint16_t hi;
+    uint32_t vacant_watches = 0;
+    for (uint32_t index = 0; index < num_valid; index++)
+    {
+        lo = GetWatchLo (regs, index);
+        if (lo != 0 && irw == ((uint32_t) lo & irw))
+        {
+            hi = GetWatchHi (regs, index) | IRW;
+            lo &= ~(lldb::addr_t) hi;
+            if (addr >= lo && last_byte <= (lo + hi))
+                return index;
+        }
+        else
+            vacant_watches++;
+    }
+
+    // Now try to find a vacant index
+    if(vacant_watches > 0)
+    {
+        vacant_watches = 0;
+        for (uint32_t index = 0; index < num_valid; index++)
+        {
+            lo = GetWatchLo (regs, index);
+            if (lo == 0
+              && irw == (GetIRWMask (regs, index) & irw))
+            {
+                if (mask <= (GetRegMask (regs, index) | IRW))
+                {
+                    // It fits, we can use it. 
+                    SetWatchLo (regs, index, base_addr | irw);
+                    SetWatchHi (regs, index, mask & ~IRW);
+                    return index;
+                }
+                else
+                {
+                    // It doesn't fit, but has the proper IRW capabilities
+                    vacant_watches++;
+                }
+            }
+        }
+
+        if (vacant_watches > 1)
+        {
+            // Split this watchpoint accross several registers
+            struct pt_watch_regs regs_copy;
+            regs_copy = *regs;
+            lldb::addr_t break_addr;
+            uint32_t segment_size;
+            for (uint32_t index = 0; index < num_valid; index++)
+            {
+                lo = GetWatchLo (&regs_copy, index);
+                hi = GetRegMask (&regs_copy, index) | IRW;
+                if (lo == 0 && irw == (hi & irw))
+                {
+                    lo = addr & ~(lldb::addr_t) hi;
+                    break_addr = lo + hi + 1;
+                    if (break_addr >= addr + size)
+                        segment_size = size;
+                    else
+                        segment_size = break_addr - addr;
+                    mask = GetRangeMask (addr ^ (addr + segment_size - 1));
+                    SetWatchLo (&regs_copy, index, (addr & ~mask) | irw);
+                    SetWatchHi (&regs_copy, index, mask & ~IRW);
+                    if (break_addr >= addr + size)
+                    {
+                        *regs = regs_copy;
+                        return index;
+                    }
+                    size = addr + size - break_addr;
+                    addr = break_addr;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
 Error
 NativeRegisterContextLinux_mips64::IsWatchpointHit (uint32_t wp_index, bool &is_hit)
 {
+    if (wp_index >= NumSupportedHardwareWatchpoints())
+        return Error("Watchpoint index out of range");
+
+    // reading the current state of watch regs
+    struct pt_watch_regs watch_readback;
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+    Error error = process_p->DoOperation(GetReadWatchPointRegisterValueOperation(m_thread.GetID(),(void*)&watch_readback));
+
+    if (GetWatchHi (&watch_readback, wp_index) & (IRW))
+    {
+        // clear hit flag in watchhi 
+        SetWatchHi (&watch_readback, wp_index, (GetWatchHi (&watch_readback, wp_index) & ~(IRW)));
+        process_p->DoOperation(GetWriteWatchPointRegisterValueOperation(m_thread.GetID(), (void*)&watch_readback));
+     
+        is_hit = true;
+        return error;
+    }
     is_hit = false;
-    return Error("MIPS TODO: NativeRegisterContextLinux_mips64::IsWatchpointHit not implemented");
+    return error;
+}
+
+Error
+NativeRegisterContextLinux_mips64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) {
+    uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+    for (wp_index = 0; wp_index < num_hw_wps; ++wp_index)
+    {
+        bool is_hit;
+        Error error = IsWatchpointHit(wp_index, is_hit);
+        if (error.Fail()) {
+            wp_index = LLDB_INVALID_INDEX32;
+        } else if (is_hit) {
+            return error;
+        }
+    }
+    wp_index = LLDB_INVALID_INDEX32;
+    return Error();
 }
 
 Error
@@ -670,17 +979,45 @@ NativeRegisterContextLinux_mips64::IsWat
 }
 
 bool
-NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint (uint32_t wp_index)
+NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint(uint32_t wp_index)
 {
+    if (wp_index >= NumSupportedHardwareWatchpoints())
+        return false;
+
+    struct pt_watch_regs regs;
+    // First reading the current state of watch regs
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+    process_p->DoOperation(GetReadWatchPointRegisterValueOperation(m_thread.GetID(),(void*)&regs));
+
+    if (regs.style == pt_watch_style_mips32)
+    {
+        regs.mips32.watchlo[wp_index] = default_watch_regs.mips32.watchlo[wp_index];
+        regs.mips32.watchhi[wp_index] = default_watch_regs.mips32.watchhi[wp_index];
+        regs.mips32.watch_masks[wp_index] = default_watch_regs.mips32.watch_masks[wp_index];
+    }
+    else // pt_watch_style_mips64
+    {
+        regs.mips64.watchlo[wp_index] = default_watch_regs.mips64.watchlo[wp_index];
+        regs.mips64.watchhi[wp_index] = default_watch_regs.mips64.watchhi[wp_index];
+        regs.mips64.watch_masks[wp_index] = default_watch_regs.mips64.watch_masks[wp_index];
+    }
+
+    Error error = process_p->DoOperation(GetWriteWatchPointRegisterValueOperation(m_thread.GetID(), (void*)&regs));
+    if(!error.Fail())
+    {
+        hw_addr_map[wp_index] = LLDB_INVALID_ADDRESS;
+        return true;
+    }
     return false;
 }
 
 Error
-NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints ()
+NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints()
 {
-    Error error;
-    error.SetErrorString ("MIPS TODO: NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints not implemented");
-    return error;
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+    return process_p->DoOperation(GetWriteWatchPointRegisterValueOperation(m_thread.GetID(), (void*)&default_watch_regs));
 }
 
 Error
@@ -696,19 +1033,70 @@ uint32_t
 NativeRegisterContextLinux_mips64::SetHardwareWatchpoint (
         lldb::addr_t addr, size_t size, uint32_t watch_flags)
 {
+    struct pt_watch_regs regs;
+
+    // First reading the current state of watch regs
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+    process_p->DoOperation(GetReadWatchPointRegisterValueOperation(m_thread.GetID(),(void*)&regs));
+
+    // Try if a new watch point fits in this state
+    int index = GetVacantWatchIndex (&regs, addr, size, watch_flags, NumSupportedHardwareWatchpoints());
+
+    // New watchpoint doesn't fit
+    if (!index)
     return LLDB_INVALID_INDEX32;
+
+
+    // It fits, so we go ahead with updating the state of watch regs 
+    process_p->DoOperation(GetWriteWatchPointRegisterValueOperation(m_thread.GetID(), (void*)&regs));
+
+    // Storing exact address  
+    hw_addr_map[index] = addr; 
+    return index;
 }
 
 lldb::addr_t
 NativeRegisterContextLinux_mips64::GetWatchpointAddress (uint32_t wp_index)
 {
-    return LLDB_INVALID_ADDRESS;
+    if (wp_index >= NumSupportedHardwareWatchpoints())
+        return LLDB_INVALID_ADDRESS;
+
+    return hw_addr_map[wp_index];
 }
 
 uint32_t
 NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints ()
 {
-    return 0;
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+    struct pt_watch_regs regs;
+    static int num_valid = 0;
+    if (!num_valid)
+    {
+        NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+        if (!process_sp)
+        {
+            printf ("NativeProcessProtocol is NULL");
+            return 0;
+        }
+
+        NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+        process_p->DoOperation(GetReadWatchPointRegisterValueOperation(m_thread.GetID(),(void*)&regs));
+        default_watch_regs = regs; // Keeping default watch regs values for future use
+        switch (regs.style)
+        {
+            case pt_watch_style_mips32:
+                num_valid = regs.mips32.num_valid; // Using num_valid as cache
+                return num_valid;
+            case pt_watch_style_mips64:
+                num_valid = regs.mips64.num_valid;
+                return num_valid;
+            default:
+                log->Printf("NativeRegisterContextLinux_mips64::%s Error: Unrecognized watch register style", __FUNCTION__);
+        }
+        return 0;
+    }
+    return num_valid;
 }
 
 NativeProcessLinux::OperationUP
@@ -728,4 +1116,16 @@ NativeRegisterContextLinux_mips64::GetWr
     return NativeProcessLinux::OperationUP(new WriteRegOperation(m_thread.GetID(), offset, reg_name, value));
 }
 
+NativeProcessLinux::OperationUP
+NativeRegisterContextLinux_mips64::GetReadWatchPointRegisterValue(lldb::tid_t tid, void* watch_readback)
+{
+    return NativeProcessLinux::OperationUP(new ReadWatchPointRegOperation(m_thread.GetID(), watch_readback));
+}
+
+NativeProcessLinux::OperationUP
+NativeRegisterContextLinux_mips64::GetWriteWatchPointRegisterValue(lldb::tid_t tid, void* watch_reg_value)
+{
+    return NativeProcessLinux::OperationUP(new SetWatchPointRegOperation(m_thread.GetID(), watch_readback));
+}
+
 #endif // defined (__mips__)

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h?rev=239991&r1=239990&r2=239991&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h Wed Jun 17 23:53:18 2015
@@ -16,6 +16,8 @@
 #include "Plugins/Process/Utility/RegisterContext_mips64.h"
 #include "Plugins/Process/Utility/lldb-mips64-register-enums.h"
 
+#define MAX_NUM_WP 8
+
 namespace lldb_private {
 namespace process_linux {
 
@@ -56,6 +58,9 @@ namespace process_linux {
         IsWatchpointHit (uint32_t wp_index, bool &is_hit) override;
 
         Error
+        GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override;
+
+        Error
         IsWatchpointVacant (uint32_t wp_index, bool &is_vacant) override;
 
         bool
@@ -90,6 +95,14 @@ namespace process_linux {
                                        const char* reg_name,
                                        const RegisterValue &value) override;
 
+        NativeProcessLinux::OperationUP
+        GetReadWatchPointRegisterValue(lldb::tid_t tid,
+                                       void* watch_readback);
+
+        NativeProcessLinux::OperationUP
+        GetWriteWatchPointRegisterValue(lldb::tid_t tid,
+                                       void* watch_readback);
+
         bool
         IsFR0();
 
@@ -123,6 +136,8 @@ namespace process_linux {
         uint64_t m_gpr_mips64[k_num_gpr_registers_mips64];
 
         FPR_mips m_fpr;
+
+        lldb::addr_t hw_addr_map[MAX_NUM_WP];
     };
 
 } // namespace process_linux

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp?rev=239991&r1=239990&r2=239991&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp Wed Jun 17 23:53:18 2015
@@ -185,7 +185,11 @@ GDBRemoteCommunicationServerCommon::Hand
     else
         response.Printf("watchpoint_exceptions_received:after;");
 #else
-    response.Printf("watchpoint_exceptions_received:after;");
+    if (host_arch.GetMachine() == llvm::Triple::mips64 ||
+        host_arch.GetMachine() == llvm::Triple::mips64el)
+        response.Printf("watchpoint_exceptions_received:before;");
+    else
+        response.Printf("watchpoint_exceptions_received:after;");
 #endif
 
     switch (lldb::endian::InlHostByteOrder())





More information about the lldb-commits mailing list