Fix setting of watchpoints on inferior thread creation for Linux.
llvm-svn: 183139
diff --git a/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp b/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp
index bdc874e..0f86f30 100644
--- a/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp
+++ b/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp
@@ -46,6 +46,20 @@
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
log->Printf ("POSIXThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid);
+
+ // Set the current watchpoints for this thread.
+ Target &target = GetProcess()->GetTarget();
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ size_t wp_size = wp_list.GetSize();
+
+ for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++)
+ {
+ lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx);
+ if (wp.get() && wp->IsEnabled())
+ {
+ assert(EnableHardwareWatchpoint(wp.get()));
+ }
+ }
}
POSIXThread::~POSIXThread()
@@ -272,27 +286,21 @@
bool
POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp)
{
- bool result = false;
+ bool wp_set = 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;
- }
- }
+ uint32_t wp_hw_index = wp->GetHardwareIndex();
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size,
+ wp_read, wp_write,
+ wp_hw_index);
}
- return result;
+ return wp_set;
}
bool
@@ -303,11 +311,7 @@
{
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;
}
@@ -321,6 +325,27 @@
return 0;
}
+uint32_t
+POSIXThread::FindVacantWatchpointIndex()
+{
+ uint32_t hw_index = LLDB_INVALID_INDEX32;
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ {
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointVacant(wp_idx))
+ {
+ hw_index = wp_idx;
+ break;
+ }
+ }
+ }
+ return hw_index;
+}
+
void
POSIXThread::BreakNotify(const ProcessMessage &message)
{
diff --git a/lldb/source/Plugins/Process/POSIX/POSIXThread.h b/lldb/source/Plugins/Process/POSIX/POSIXThread.h
index fca9ea9..251281e 100644
--- a/lldb/source/Plugins/Process/POSIX/POSIXThread.h
+++ b/lldb/source/Plugins/Process/POSIX/POSIXThread.h
@@ -82,6 +82,8 @@
uint32_t NumSupportedHardwareWatchpoints();
+ uint32_t FindVacantWatchpointIndex();
+
private:
RegisterContextPOSIX *
GetRegisterContextPOSIX ()
diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index 1e0fa05..32dfdd7 100644
--- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -654,31 +654,44 @@
return error;
}
- bool wp_enabled = true;
- uint32_t thread_count = m_thread_list.GetSize(false);
- for (uint32_t i = 0; i < thread_count; ++i)
+ // Try to find a vacant watchpoint slot in the inferiors' main thread
+ uint32_t wp_hw_index = LLDB_INVALID_INDEX32;
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+
+ if (thread)
+ wp_hw_index = thread->FindVacantWatchpointIndex();
+
+ if (wp_hw_index == LLDB_INVALID_INDEX32)
{
- 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;
+ error.SetErrorString("Setting hardware watchpoint failed.");
}
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");
+ wp->SetHardwareIndex(wp_hw_index);
+ bool wp_enabled = true;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_enabled &= thread->EnableHardwareWatchpoint(wp);
+ else
+ wp_enabled = false;
+ }
+ 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
@@ -724,6 +737,7 @@
}
if (wp_disabled)
{
+ wp->SetHardwareIndex(LLDB_INVALID_INDEX32);
wp->SetEnabled(false, notify);
return error;
}
diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
index bd26a31..63ae01e 100644
--- a/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
+++ b/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
@@ -25,7 +25,8 @@
public:
RegisterContextPOSIX(lldb_private::Thread &thread,
uint32_t concrete_frame_idx)
- : RegisterContext(thread, concrete_frame_idx) { }
+ : RegisterContext(thread, concrete_frame_idx)
+ { m_watchpoints_initialized = false; }
/// Updates the register state of the associated thread after hitting a
/// breakpoint (if that make sense for the architecture). Default
@@ -52,7 +53,18 @@
// Returns the watchpoint address associated with a watchpoint hardware
// index.
virtual lldb::addr_t
- GetWatchpointAddress (uint32_t hw_index) {return LLDB_INVALID_ADDRESS; }
+ GetWatchpointAddress (uint32_t hw_index) { return LLDB_INVALID_ADDRESS; }
+
+ virtual bool
+ IsWatchpointVacant (uint32_t hw_index) { return false; }
+
+ virtual bool
+ SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index) { return false; }
+
+protected:
+ bool m_watchpoints_initialized;
};
#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 ec7c41f..03bccd2 100644
--- a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
+++ b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
@@ -1242,6 +1242,8 @@
bool is_vacant = false;
RegisterValue value;
+ assert(hw_index < NumSupportedHardwareWatchpoints());
+
if (ReadRegister(dr7, value))
{
uint64_t val = value.GetAsUInt64();
@@ -1282,23 +1284,47 @@
bool read, bool write)
{
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
- 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;
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
}
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints)
+ return false;
+
+ if (!(size == 1 || size == 2 || size == 4 || size == 8))
+ return false;
+
+ if (read == false && write == false)
+ return false;
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits))
+ return false;
+ m_watchpoints_initialized = true;
+ }
+
+ if (!IsWatchpointVacant(hw_index))
+ return false;
+
// Set both dr7 (debug control register) and dri (debug address register).
// dr7{7-0} encodes the local/gloabl enable bits:
@@ -1335,11 +1361,11 @@
if (WriteRegister(dr0 + hw_index, RegisterValue(addr)) &&
WriteRegister(dr7, RegisterValue(new_dr7_bits)))
- return hw_index;
+ return true;
}
}
- return LLDB_INVALID_INDEX32;
+ return false;
}
bool
diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
index 08ce682..9d59bd7 100644
--- a/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
+++ b/lldb/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
@@ -193,6 +193,10 @@
SetHardwareWatchpoint(lldb::addr_t, size_t size, bool read, bool write);
bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t, size_t size, bool read,
+ bool write, uint32_t hw_index);
+
+ bool
ClearHardwareWatchpoint(uint32_t hw_index);
bool