diff options
3 files changed, 122 insertions, 48 deletions
diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp index 8a1738725db..68d6b33af9c 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp @@ -625,26 +625,111 @@ DNBArchImplI386::NotifyException(MachException::Data& exc) return false; } -#ifndef DR_FIRSTADDR -#define DR_FIRSTADDR 0 -#endif +uint32_t +DNBArchImplI386::NumSupportedHardwareWatchpoints() +{ + // Available debug address registers: dr0, dr1, dr2, dr3. + return 4; +} -#ifndef DR_LASTADDR -#define DR_LASTADDR 3 -#endif +static uint32_t +size_and_rw_bits(nub_size_t size, bool read, bool write) +{ + uint32_t rw; + if (read) { + rw = 0x3; // READ or READ/WRITE + } else if (write) { + rw = 0x1; // WRITE + } else { + assert(0 && "read and write cannot both be false"); + } -#ifndef DR_STATUS -#define DR_STATUS 6 -#endif + switch (size) { + case 1: + return rw; + case 2: + return (0x1 << 2) | rw; + case 4: + return (0x3 << 2) | rw; + case 8: + return (0x2 << 2) | rw; + default: + assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); + } +} +void +DNBArchImplI386::SetWatchpoint(DBG &debug_state, uint32_t hw_index, nub_addr_t addr, nub_size_t size, bool read, bool write) +{ + // Set both dr7 (debug control register) and dri (debug address register). + + // dr7{7-0} encodes the local/gloabl enable bits: + // global enable --. .-- local enable + // | | + // v v + // dr0 -> bits{1-0} + // dr1 -> bits{3-2} + // dr2 -> bits{5-4} + // dr3 -> bits{7-6} + // + // dr7{31-16} encodes the rw/len bits: + // b_x+3, b_x+2, b_x+1, b_x + // where bits{x+1, x} => rw + // 0b00: execute, 0b01: write, 0b11: read-or-write, 0b10: io read-or-write (unused) + // and bits{x+3, x+2} => len + // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte + // + // dr0 -> bits{19-16} + // dr1 -> bits{23-20} + // dr2 -> bits{27-24} + // dr3 -> bits{31-28} + debug_state.__dr7 |= (1 << (2*hw_index) | size_and_rw_bits(size, read, write) << 16); + uint32_t addr_32 = addr & 0xffffffff; + switch (hw_index) { + case 0: + debug_state.__dr0 == addr_32; break; + case 1: + debug_state.__dr1 == addr_32; break; + case 2: + debug_state.__dr2 == addr_32; break; + case 3: + debug_state.__dr3 == addr_32; break; + default: + assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); + } + return; +} -#ifndef DR_CONTROL -#define DR_CONTROL 7 -#endif +void +DNBArchImplI386::ClearWatchpoint(DBG &debug_state, uint32_t hw_index) +{ + debug_state.__dr7 &= ~(3 << (2*hw_index)); + switch (hw_index) { + case 0: + debug_state.__dr0 == 0; break; + case 1: + debug_state.__dr1 == 0; break; + case 2: + debug_state.__dr2 == 0; break; + case 3: + debug_state.__dr3 == 0; break; + default: + assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); + } + return; +} -uint32_t -DNBArchImplI386::NumSupportedHardwareWatchpoints() +bool +DNBArchImplI386::IsVacantWatchpoint(const DBG &debug_state, uint32_t hw_index) { - return DR_LASTADDR - DR_FIRSTADDR + 1; + // Check dr7 (debug control register) for local/global enable bits: + // global enable --. .-- local enable + // | | + // v v + // dr0 -> bits{1-0} + // dr1 -> bits{3-2} + // dr2 -> bits{5-4} + // dr3 -> bits{7-6} + return (debug_state.__dr7 & (3 << (2*hw_index))) == 0; } uint32_t @@ -654,18 +739,14 @@ DNBArchImplI386::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, boo const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - // Can't watch zero bytes - if (size == 0) + // Can only watch 1, 2, 4, or 8 bytes. + if (!(size == 1 || size == 2 || size == 4 || size == 8)) return INVALID_NUB_HW_INDEX; // We must watch for either read or write if (read == false && write == false) return INVALID_NUB_HW_INDEX; - // - // FIXME: Add implmentation. - // - // Read the debug state kern_return_t kret = GetDBGState(false); @@ -675,37 +756,27 @@ DNBArchImplI386::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, boo uint32_t i = 0; DBG debug_state = m_state.context.dbg; - for (i=0; i<num_hw_watchpoints; ++i) + for (i = 0; i < num_hw_watchpoints; ++i) { - uint64_t dr_val = 0; - switch (i) { - case 0: - dr_val = debug_state.__dr0; break; - case 1: - dr_val = debug_state.__dr1; break; - case 2: - dr_val = debug_state.__dr2; break; - case 3: - dr_val = debug_state.__dr3; break; - default: + if (IsVacantWatchpoint(debug_state, i)) break; - } - if (dr_val == 0) - break; // We found an available hw breakpoint slot (in i) } // See if we found an available hw breakpoint slot above if (i < num_hw_watchpoints) { + // Modify our local copy of the debug state, first. + SetWatchpoint(debug_state, i, addr, size, read, write); + // Ready to set the watch point in the inferior. kret = SetDBGState(); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImpI386::EnableHardwareWatchpoint() SetDBGState() => 0x%8.8x.", kret); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::EnableHardwareWatchpoint() SetDBGState() => 0x%8.8x.", kret); if (kret == KERN_SUCCESS) return i; } else { - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImpl386::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); } } return INVALID_NUB_HW_INDEX; @@ -719,17 +790,16 @@ DNBArchImplI386::DisableHardwareWatchpoint (uint32_t hw_index) const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); if (kret == KERN_SUCCESS) { - if (hw_index < num_hw_points) + DBG debug_state = m_state.context.dbg; + if (hw_index < num_hw_points && !IsVacantWatchpoint(debug_state, hw_index)) { - // - // FIXEME: Add implementation. - // - + // Modify our local copy of the debug state, first. + ClearWatchpoint(debug_state, hw_index); + // Ready to disable the watch point in the inferior. + kret = SetDBGState(); DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::DisableHardwareWatchpoint( %u )", hw_index); - kret = SetDBGState(); - if (kret == KERN_SUCCESS) return true; } diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h index 83a41530da9..1478992824f 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h @@ -226,6 +226,11 @@ protected: return (s_has_avx == kAVXPresent); } + // Helper functions for watchpoint manipulations. + static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, nub_addr_t addr, nub_size_t size, bool read, bool write); + static void ClearWatchpoint(DBG &debug_state, uint32_t hw_index); + static bool IsVacantWatchpoint(const DBG &debug_state, uint32_t hw_index); + MachThread *m_thread; State m_state; diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h index 606f7db96e3..e329e11c7e0 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h @@ -105,9 +105,8 @@ protected: struct Context { - GPR gpr; - union - { + GPR gpr; + union { FPU no_avx; AVX avx; } fpu; |

