diff options
23 files changed, 589 insertions, 19 deletions
diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp index d893b89c6fc..4ebde16245e 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp +++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -47,6 +47,11 @@ #define PTRACE_SETREGSET 0x4205 #endif +// Support hardware breakpoints in case it has not been defined +#ifndef TRAP_HWBKPT + #define TRAP_HWBKPT 4 +#endif + using namespace lldb_private; // FIXME: this code is host-dependent with respect to types and @@ -1415,6 +1420,10 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, case TRAP_BRKPT: message = ProcessMessage::Break(pid); break; + + case TRAP_HWBKPT: + message = ProcessMessage::Watch(pid, (lldb::addr_t)info->si_addr); + break; } return message; diff --git a/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp b/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp index 8928d372c11..8e8f0c0024e 100644 --- a/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -15,6 +15,7 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Debugger.h" #include "lldb/Host/Host.h" #include "lldb/Target/Process.h" @@ -229,6 +230,10 @@ POSIXThread::Notify(const ProcessMessage &message) BreakNotify(message); break; + case ProcessMessage::eWatchpointMessage: + WatchNotify(message); + break; + case ProcessMessage::eCrashMessage: CrashNotify(message); break; @@ -239,6 +244,58 @@ POSIXThread::Notify(const ProcessMessage &message) } } +bool +POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp) +{ + bool result = false; + if (wp) + { + addr_t wp_addr = wp->GetLoadAddress(); + size_t wp_size = wp->GetByteSize(); + bool wp_read = wp->WatchpointRead(); + bool wp_write = wp->WatchpointWrite(); + uint32_t wp_hw_index; + lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); + if (reg_ctx_sp.get()) + { + wp_hw_index = reg_ctx_sp->SetHardwareWatchpoint(wp_addr, wp_size, + wp_read, wp_write); + if (wp_hw_index != LLDB_INVALID_INDEX32) + { + wp->SetHardwareIndex(wp_hw_index); + result = true; + } + } + } + return result; +} + +bool +POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp) +{ + bool result = false; + if (wp) + { + lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); + if (reg_ctx_sp.get()) + { + result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex()); + if (result == true) + wp->SetHardwareIndex(LLDB_INVALID_INDEX32); + } + } + return result; +} + +uint32_t +POSIXThread::NumSupportedHardwareWatchpoints() +{ + lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); + if (reg_ctx_sp.get()) + return reg_ctx_sp->NumSupportedHardwareWatchpoints(); + return 0; +} + void POSIXThread::BreakNotify(const ProcessMessage &message) { @@ -260,12 +317,50 @@ POSIXThread::BreakNotify(const ProcessMessage &message) lldb::break_id_t bp_id = bp_site->GetID(); assert(bp_site && bp_site->ValidForThisThread(this)); - m_breakpoint = bp_site; SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); } void +POSIXThread::WatchNotify(const ProcessMessage &message) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + + lldb::addr_t halt_addr = message.GetHWAddress(); + if (log) + log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8" + PRIx64, __FUNCTION__, halt_addr); + + RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX(); + if (reg_ctx) + { + uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); + uint32_t wp_idx; + for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) + { + if (reg_ctx->IsWatchpointHit(wp_idx)) + { + // Clear the watchpoint hit here + reg_ctx->ClearWatchpointHits(); + break; + } + } + + if (wp_idx == num_hw_wps) + return; + + Target &target = GetProcess()->GetTarget(); + lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx); + const WatchpointList &wp_list = target.GetWatchpointList(); + lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr); + + if (wp_sp) + SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this, + wp_sp->GetID())); + } +} + +void POSIXThread::TraceNotify(const ProcessMessage &message) { SetStopInfo (StopInfo::CreateStopReasonToTrace(*this)); diff --git a/lldb/source/Plugins/Process/POSIX/POSIXThread.h b/lldb/source/Plugins/Process/POSIX/POSIXThread.h index 3e14652bc25..69bca49839a 100644 --- a/lldb/source/Plugins/Process/POSIX/POSIXThread.h +++ b/lldb/source/Plugins/Process/POSIX/POSIXThread.h @@ -69,6 +69,15 @@ public: void Notify(const ProcessMessage &message); + //-------------------------------------------------------------------------- + // These methods provide an interface to watchpoints + // + bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp); + + bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp); + + uint32_t NumSupportedHardwareWatchpoints(); + private: RegisterContextPOSIX * GetRegisterContextPOSIX () @@ -92,6 +101,7 @@ private: GetPrivateStopReason(); void BreakNotify(const ProcessMessage &message); + void WatchNotify(const ProcessMessage &message); void TraceNotify(const ProcessMessage &message); void LimboNotify(const ProcessMessage &message); void SignalNotify(const ProcessMessage &message); diff --git a/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp b/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp index cefacc3ef8f..a33470b17d9 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp +++ b/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp @@ -221,6 +221,9 @@ ProcessMessage::PrintKind(Kind kind) case eBreakpointMessage: str = "eBreakpointMessage"; break; + case eWatchpointMessage: + str = "eWatchpointMessage"; + break; case eCrashMessage: str = "eCrashMessage"; break; diff --git a/lldb/source/Plugins/Process/POSIX/ProcessMessage.h b/lldb/source/Plugins/Process/POSIX/ProcessMessage.h index 7eca5c845a7..2a4c6121453 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessMessage.h +++ b/lldb/source/Plugins/Process/POSIX/ProcessMessage.h @@ -29,6 +29,7 @@ public: eSignalDeliveredMessage, eTraceMessage, eBreakpointMessage, + eWatchpointMessage, eCrashMessage, eNewThreadMessage }; @@ -104,6 +105,10 @@ public: return ProcessMessage(tid, eBreakpointMessage); } + static ProcessMessage Watch(lldb::tid_t tid, lldb::addr_t wp_addr) { + return ProcessMessage(tid, eWatchpointMessage, 0, wp_addr); + } + /// Indicates that the thread @p tid crashed. static ProcessMessage Crash(lldb::pid_t pid, CrashReason reason, int signo, lldb::addr_t fault_addr) { @@ -143,6 +148,11 @@ public: return m_addr; } + lldb::addr_t GetHWAddress() const { + assert(GetKind() == eWatchpointMessage); + return m_addr; + } + lldb::tid_t GetChildTID() const { assert(GetKind() == eNewThreadMessage); return m_child_tid; diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index 35c365f75c0..f0105685de5 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -14,6 +14,7 @@ // C++ Includes // Other libraries and framework includes +#include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" @@ -364,6 +365,7 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) case ProcessMessage::eTraceMessage: case ProcessMessage::eBreakpointMessage: + case ProcessMessage::eWatchpointMessage: SetPrivateState(eStateStopped); break; @@ -546,6 +548,132 @@ ProcessPOSIX::DisableBreakpointSite(BreakpointSite *bp_site) return DisableSoftwareBreakpoint(bp_site); } +Error +ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify) +{ + Error error; + if (wp) + { + user_id_t watchID = wp->GetID(); + addr_t addr = wp->GetLoadAddress(); + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + if (log) + log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (wp->IsEnabled()) + { + if (log) + log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", + watchID, (uint64_t)addr); + return error; + } + + bool wp_enabled = true; + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) + { + POSIXThread *thread = static_cast<POSIXThread*>( + m_thread_list.GetThreadAtIndex(i, false).get()); + if (thread) + wp_enabled &= thread->EnableHardwareWatchpoint(wp); + else + { + wp_enabled = false; + break; + } + } + if (wp_enabled) + { + wp->SetEnabled(true, notify); + return error; + } + else + { + // Watchpoint enabling failed on at least one + // of the threads so roll back all of them + DisableWatchpoint(wp, false); + error.SetErrorString("Setting hardware watchpoint failed"); + } + } + else + error.SetErrorString("Watchpoint argument was NULL."); + return error; +} + +Error +ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify) +{ + Error error; + if (wp) + { + user_id_t watchID = wp->GetID(); + addr_t addr = wp->GetLoadAddress(); + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + if (log) + log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (!wp->IsEnabled()) + { + if (log) + log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", + watchID, (uint64_t)addr); + // This is needed (for now) to keep watchpoints disabled correctly + wp->SetEnabled(false, notify); + return error; + } + + if (wp->IsHardware()) + { + bool wp_disabled = true; + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) + { + POSIXThread *thread = static_cast<POSIXThread*>( + m_thread_list.GetThreadAtIndex(i, false).get()); + if (thread) + wp_disabled &= thread->DisableHardwareWatchpoint(wp); + else + wp_disabled = false; + } + if (wp_disabled) + { + wp->SetEnabled(false, notify); + return error; + } + else + error.SetErrorString("Disabling hardware watchpoint failed"); + } + } + else + error.SetErrorString("Watchpoint argument was NULL."); + return error; +} + +Error +ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num) +{ + Error error; + POSIXThread *thread = static_cast<POSIXThread*>( + m_thread_list.GetThreadAtIndex(0, false).get()); + if (thread) + num = thread->NumSupportedHardwareWatchpoints(); + else + error.SetErrorString("Process does not exist."); + return error; +} + +Error +ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after) +{ + Error error = GetWatchpointSupportInfo(num); + // Watchpoints trigger and halt the inferior after + // the corresponding instruction has been executed. + after = true; + return error; +} + uint32_t ProcessPOSIX::UpdateThreadListIfNeeded() { diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h index 86c4ef33b3d..ce31d8f5a7c 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -108,6 +108,18 @@ public: virtual lldb_private::Error DisableBreakpointSite(lldb_private::BreakpointSite *bp_site); + virtual lldb_private::Error + EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true); + + virtual lldb_private::Error + DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true); + + virtual lldb_private::Error + GetWatchpointSupportInfo(uint32_t &num); + + virtual lldb_private::Error + GetWatchpointSupportInfo(uint32_t &num, bool &after); + virtual uint32_t UpdateThreadListIfNeeded(); diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp index c49bd62981b..477f748c14d 100644 --- a/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp @@ -25,6 +25,15 @@ do { \ m_register_infos[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \ } while(false); +#define DR_OFFSET(reg_index) \ + (offsetof(UserArea, u_debugreg[reg_index])) + +#define UPDATE_DR_INFO(reg_index) \ +do { \ + m_register_infos[dr##reg_index].byte_size = sizeof(UserArea::u_debugreg[0]); \ + m_register_infos[dr##reg_index].byte_offset = DR_OFFSET(reg_index); \ +} while(false); + typedef struct _GPR { uint64_t r15; @@ -155,5 +164,14 @@ RegisterContextLinux_x86_64::UpdateRegisterInfo() UPDATE_I386_GPR_INFO(esp, rsp); UPDATE_I386_GPR_INFO(eip, rip); UPDATE_I386_GPR_INFO(eflags, rflags); + + UPDATE_DR_INFO(0); + UPDATE_DR_INFO(1); + UPDATE_DR_INFO(2); + UPDATE_DR_INFO(3); + UPDATE_DR_INFO(4); + UPDATE_DR_INFO(5); + UPDATE_DR_INFO(6); + UPDATE_DR_INFO(7); } diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h index f97e710fcaa..46aa9ca154e 100644 --- a/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h +++ b/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h @@ -35,6 +35,20 @@ public: /// @return /// True if the operation succeeded and false otherwise. virtual bool UpdateAfterBreakpoint() { return true; } + + // Checks to see if a watchpoint specified by hw_index caused the inferior + // to stop. + virtual bool + IsWatchpointHit (uint32_t hw_index) { return false; } + + // Resets any watchpoints that have been hit. + virtual bool + ClearWatchpointHits () { return false; } + + // Returns the watchpoint address associated with a watchpoint hardware + // index. + virtual lldb::addr_t + GetWatchpointAddress (uint32_t hw_index) {return LLDB_INVALID_ADDRESS; } }; #endif // #ifndef liblldb_RegisterContextPOSIX_H_ diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp index 255cdd31617..e99c257d9d5 100644 --- a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp +++ b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp @@ -340,6 +340,11 @@ g_reg_sets[k_num_register_sets] = { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL } +#define DEFINE_DR(reg, i) \ + { #reg#i, NULL, 0, 0, eEncodingUint, eFormatHex, \ + { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL } + #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(RegisterContext_x86_64::FPR)) static RegisterInfo @@ -439,7 +444,17 @@ g_register_infos[k_num_registers] = DEFINE_YMM(ymm, 12), DEFINE_YMM(ymm, 13), DEFINE_YMM(ymm, 14), - DEFINE_YMM(ymm, 15) + DEFINE_YMM(ymm, 15), + + // Debug registers for lldb internal use + DEFINE_DR(dr, 0), + DEFINE_DR(dr, 1), + DEFINE_DR(dr, 2), + DEFINE_DR(dr, 3), + DEFINE_DR(dr, 4), + DEFINE_DR(dr, 5), + DEFINE_DR(dr, 6), + DEFINE_DR(dr, 7) }; RegisterInfo *RegisterContext_x86_64::m_register_infos = g_register_infos; @@ -869,6 +884,27 @@ RegisterContext_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp) } bool +RegisterContext_x86_64::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContext_x86_64::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + value); +} + +bool RegisterContext_x86_64::UpdateAfterBreakpoint() { // PC points one byte past the int3 responsible for the breakpoint. @@ -1178,6 +1214,183 @@ RegisterContext_x86_64::ConvertRegisterKindToRegisterNumber(uint32_t kind, return LLDB_INVALID_REGNUM; } +uint32_t +RegisterContext_x86_64::NumSupportedHardwareWatchpoints() +{ + // Available debug address registers: dr0, dr1, dr2, dr3 + return 4; +} + +bool +RegisterContext_x86_64::IsWatchpointVacant(uint32_t hw_index) +{ + bool is_vacant = false; + RegisterValue value; + + if (ReadRegister(dr7, value)) + { + uint64_t val = value.GetAsUInt64(); + is_vacant = (val & (3 << 2*hw_index)) == 0; + } + + return is_vacant; +} + +static uint32_t +size_and_rw_bits(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"); + } + + 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"); + } +} + +uint32_t +RegisterContext_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + + if (num_hw_watchpoints == 0) + return LLDB_INVALID_INDEX32; + + if (!(size == 1 || size == 2 || size == 4 || size == 8)) + return LLDB_INVALID_INDEX32; + + if (read == false && write == false) + return LLDB_INVALID_INDEX32; + + uint32_t hw_index = 0; + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + break; + } + + // 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} + if (hw_index < num_hw_watchpoints) + { + RegisterValue current_dr7_bits; + + if (ReadRegister(dr7, current_dr7_bits)) + { + uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() | + (1 << (2*hw_index) | + size_and_rw_bits(size, read, write) << + (16+4*hw_index)); + + if (WriteRegister(dr0 + hw_index, RegisterValue(addr)) && + WriteRegister(dr7, RegisterValue(new_dr7_bits))) + return hw_index; + } + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContext_x86_64::ClearHardwareWatchpoint(uint32_t hw_index) +{ + if (hw_index < NumSupportedHardwareWatchpoints()) + { + RegisterValue current_dr7_bits; + + if (ReadRegister(dr7, current_dr7_bits)) + { + uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index)); + + if (WriteRegister(dr7, RegisterValue(new_dr7_bits))) + return true; + } + } + + return false; +} + +bool +RegisterContext_x86_64::IsWatchpointHit(uint32_t hw_index) +{ + bool is_hit = false; + + if (hw_index < NumSupportedHardwareWatchpoints()) + { + RegisterValue value; + + if (ReadRegister(dr6, value)) + { + uint64_t val = value.GetAsUInt64(); + is_hit = val & (1 << hw_index); + } + } + + return is_hit; +} + +addr_t +RegisterContext_x86_64::GetWatchpointAddress(uint32_t hw_index) +{ + addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS; + + if (hw_index < NumSupportedHardwareWatchpoints()) + { + if (!IsWatchpointVacant(hw_index)) + { + RegisterValue value; + + if (ReadRegister(dr0 + hw_index, value)) + wp_monitor_addr = value.GetAsUInt64(); + } + } + + return wp_monitor_addr; +} + + +bool +RegisterContext_x86_64::ClearWatchpointHits() +{ + return WriteRegister(dr6, RegisterValue((uint64_t)0)); +} + bool RegisterContext_x86_64::HardwareSingleStep(bool enable) { diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h index efd5f1f2db2..8b6fa9d93b9 100644 --- a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h +++ b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h @@ -110,6 +110,15 @@ enum fpu_ymm15, k_last_avx = fpu_ymm15, + dr0, + dr1, + dr2, + dr3, + dr4, + dr5, + dr6, + dr7, + k_num_registers, k_num_gpr_registers = k_last_gpr - k_first_gpr + 1, k_num_fpr_registers = k_last_fpr - k_first_fpr + 1, @@ -175,15 +184,37 @@ public: uint32_t ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); + uint32_t + NumSupportedHardwareWatchpoints(); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + bool HardwareSingleStep(bool enable); bool UpdateAfterBreakpoint(); + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + IsWatchpointHit (uint32_t hw_index); + + lldb::addr_t + GetWatchpointAddress (uint32_t hw_index); + + bool + ClearWatchpointHits(); + //--------------------------------------------------------------------------- // Generic floating-point registers //--------------------------------------------------------------------------- + struct MMSReg { uint8_t bytes[10]; @@ -280,6 +311,12 @@ protected: virtual const lldb_private::RegisterInfo * GetRegisterInfo(); + virtual bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + private: static lldb_private::RegisterInfo *m_register_infos; diff --git a/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py b/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py index 02a29f55753..ff6b0b2d85c 100644 --- a/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py +++ b/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py @@ -22,7 +22,6 @@ class HelloWatchpointTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.hello_watchpoint() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_hello_watchpoint_with_dwarf_using_watchpoint_set(self): """Test a simple sequence of watchpoint creation and watchpoint hit.""" diff --git a/lldb/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py b/lldb/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py index 81a1e0b88c7..6af5f1a8507 100644 --- a/lldb/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py +++ b/lldb/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py @@ -20,7 +20,7 @@ class WatchedVariableHitWhenInScopeTestCase(TestBase): # clearer API to express this. # - @unittest2.expectedFailure + @expectedFailureDarwin @dsym_test def test_watched_var_should_only_hit_when_in_scope_with_dsym(self): """Test that a variable watchpoint should only hit when in scope.""" @@ -28,7 +28,7 @@ class WatchedVariableHitWhenInScopeTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.watched_var() - @unittest2.expectedFailure + @expectedFailureDarwin @dwarf_test def test_watched_var_should_only_hit_when_in_scope_with_dwarf(self): """Test that a variable watchpoint should only hit when in scope.""" diff --git a/lldb/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py b/lldb/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py index d8e5c865555..339e6330fab 100644 --- a/lldb/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py +++ b/lldb/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py @@ -34,7 +34,6 @@ class WatchpointCommandsTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.normal_read_write_watchpoint() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_rw_watchpoint_with_dwarf(self): """Test read_write watchpoint and expect to stop two times.""" @@ -50,7 +49,6 @@ class WatchpointCommandsTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.delete_read_write_watchpoint() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_rw_watchpoint_delete_with_dwarf(self): """Test delete watchpoint and expect not to stop for watchpoint.""" @@ -66,7 +64,6 @@ class WatchpointCommandsTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.ignore_read_write_watchpoint() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_rw_watchpoint_set_ignore_count_with_dwarf(self): """Test watchpoint ignore count and expect to not to stop at all.""" @@ -82,7 +79,6 @@ class WatchpointCommandsTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.read_write_watchpoint_disable_after_first_stop() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_rw_disable_after_first_stop__with_dwarf(self): """Test read_write watchpoint but disable it after the first stop.""" @@ -98,7 +94,6 @@ class WatchpointCommandsTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.read_write_watchpoint_disable_then_enable() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_rw_disable_then_enable_with_dwarf(self): """Test read_write watchpoint, disable initially, then enable it.""" diff --git a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py index 8da620a5a13..2a1911a33b2 100644 --- a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py +++ b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py @@ -33,7 +33,6 @@ class WatchpointLLDBCommandTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.watchpoint_command() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_watchpoint_command_with_dwarf(self): """Test 'watchpoint command'.""" @@ -49,7 +48,6 @@ class WatchpointLLDBCommandTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.watchpoint_command_can_disable_a_watchpoint() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_watchpoint_command_can_disable_a_watchpoint_with_dwarf(self): """Test that 'watchpoint command' action can disable a watchpoint after it is triggered.""" diff --git a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py index 96a3c619db5..c793a6a5598 100644 --- a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py +++ b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py @@ -33,7 +33,6 @@ class WatchpointPythonCommandTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.watchpoint_command() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_watchpoint_command_with_dwarf(self): """Test 'watchpoint command'.""" diff --git a/lldb/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py b/lldb/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py index f529ef969b1..b4fafdc8523 100644 --- a/lldb/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py +++ b/lldb/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py @@ -33,7 +33,6 @@ class WatchpointConditionCmdTestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.watchpoint_condition() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_watchpoint_cond_with_dwarf(self): """Test watchpoint condition.""" diff --git a/lldb/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py b/lldb/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py index b912981201d..1198ae0d092 100644 --- a/lldb/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py +++ b/lldb/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py @@ -18,7 +18,6 @@ class TestWatchpointEvents (TestBase): self.buildDsym() self.step_over_stepping() - @expectedFailureLinux # bugzilla 14437 @python_api_test @dwarf_test def test_with_dwarf_and_python_api(self): diff --git a/lldb/test/lldbtest.py b/lldb/test/lldbtest.py index 2343a8b7851..2391a6bba89 100644 --- a/lldb/test/lldbtest.py +++ b/lldb/test/lldbtest.py @@ -549,6 +549,42 @@ def expectedFailureLinux(bugnumber=None): return wrapper return expectedFailureLinux_impl +def expectedFailureDarwin(bugnumber=None): + if callable(bugnumber): + @wraps(bugnumber) + def expectedFailureDarwin_easy_wrapper(*args, **kwargs): + from unittest2 import case + self = args[0] + platform = sys.platform + try: + bugnumber(*args, **kwargs) + except Exception: + if "darwin" in platform: + raise case._ExpectedFailure(sys.exc_info(),None) + else: + raise + if "darwin" in platform: + raise case._UnexpectedSuccess(sys.exc_info(),None) + return expectedFailureDarwin_easy_wrapper + else: + def expectedFailureDarwin_impl(func): + @wraps(func) + def wrapper(*args, **kwargs): + from unittest2 import case + self = args[0] + platform = sys.platform + try: + func(*args, **kwargs) + except Exception: + if "darwin" in platform: + raise case._ExpectedFailure(sys.exc_info(),bugnumber) + else: + raise + if "darwin" in platform: + raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) + return wrapper + return expectedFailureDarwin_impl + def skipOnLinux(func): """Decorate the item to skip tests that should be skipped on Linux.""" if isinstance(func, type) and issubclass(func, unittest2.TestCase): diff --git a/lldb/test/python_api/watchpoint/TestSetWatchpoint.py b/lldb/test/python_api/watchpoint/TestSetWatchpoint.py index e52665b64b3..124dec11cbd 100644 --- a/lldb/test/python_api/watchpoint/TestSetWatchpoint.py +++ b/lldb/test/python_api/watchpoint/TestSetWatchpoint.py @@ -28,7 +28,6 @@ class SetWatchpointAPITestCase(TestBase): self.buildDsym() self.do_set_watchpoint() - @expectedFailureLinux # bugzilla 14416 @python_api_test @dwarf_test def test_watch_val_with_dwarf(self): diff --git a/lldb/test/python_api/watchpoint/TestWatchpointIgnoreCount.py b/lldb/test/python_api/watchpoint/TestWatchpointIgnoreCount.py index e369ef54e69..ffe770852e5 100644 --- a/lldb/test/python_api/watchpoint/TestWatchpointIgnoreCount.py +++ b/lldb/test/python_api/watchpoint/TestWatchpointIgnoreCount.py @@ -28,7 +28,6 @@ class WatchpointIgnoreCountTestCase(TestBase): self.buildDsym() self.do_watchpoint_ignore_count() - @expectedFailureLinux # bugzilla 14416 @python_api_test @dwarf_test def test_set_watch_ignore_count_with_dwarf(self): diff --git a/lldb/test/python_api/watchpoint/TestWatchpointIter.py b/lldb/test/python_api/watchpoint/TestWatchpointIter.py index f44864a8b70..c6d37502ec3 100644 --- a/lldb/test/python_api/watchpoint/TestWatchpointIter.py +++ b/lldb/test/python_api/watchpoint/TestWatchpointIter.py @@ -28,7 +28,6 @@ class WatchpointIteratorTestCase(TestBase): self.buildDsym() self.do_watchpoint_iter() - @expectedFailureLinux # bugzilla 14416 @python_api_test @dwarf_test def test_watch_iter_with_dwarf(self): diff --git a/lldb/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py b/lldb/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py index aac367a004e..d3707bad21e 100644 --- a/lldb/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py +++ b/lldb/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py @@ -33,7 +33,6 @@ class WatchpointConditionAPITestCase(TestBase): self.setTearDownCleanup(dictionary=self.d) self.watchpoint_condition_api() - @expectedFailureLinux # bugzilla 14416 @dwarf_test def test_watchpoint_cond_api_with_dwarf(self): """Test watchpoint condition API.""" |