aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp270
1 files changed, 176 insertions, 94 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 9648f1f..fb67151 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -24,6 +24,7 @@
#include <sys/types.h>
#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
@@ -1798,24 +1799,29 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
bool silently_continue = false;
- WatchpointSP wp_sp;
+ WatchpointResourceSP wp_resource_sp;
if (wp_hit_addr != LLDB_INVALID_ADDRESS) {
- wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr);
+ wp_resource_sp =
+ m_watchpoint_resource_list.FindByAddress(wp_hit_addr);
// On MIPS, \a wp_hit_addr outside the range of a watched
// region means we should silently continue, it is a false hit.
ArchSpec::Core core = GetTarget().GetArchitecture().GetCore();
- if (!wp_sp && core >= ArchSpec::kCore_mips_first &&
+ if (!wp_resource_sp && core >= ArchSpec::kCore_mips_first &&
core <= ArchSpec::kCore_mips_last)
silently_continue = true;
}
- if (!wp_sp && wp_addr != LLDB_INVALID_ADDRESS)
- wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
- if (wp_sp) {
- watch_id = wp_sp->GetID();
- }
- if (watch_id == LLDB_INVALID_WATCH_ID) {
+ if (!wp_resource_sp && wp_addr != LLDB_INVALID_ADDRESS)
+ wp_resource_sp = m_watchpoint_resource_list.FindByAddress(wp_addr);
+ if (!wp_resource_sp) {
Log *log(GetLog(GDBRLog::Watchpoints));
LLDB_LOGF(log, "failed to find watchpoint");
+ watch_id = LLDB_INVALID_SITE_ID;
+ } else {
+ // LWP_TODO: This is hardcoding a single Watchpoint in a
+ // Resource, need to add
+ // StopInfo::CreateStopReasonWithWatchpointResource which
+ // represents all watchpoints that were tripped at this stop.
+ watch_id = wp_resource_sp->GetConstituentAtIndex(0)->GetID();
}
thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID(
*thread_sp, watch_id, silently_continue));
@@ -2239,8 +2245,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
lldb::addr_t wp_addr = LLDB_INVALID_ADDRESS;
value.getAsInteger(16, wp_addr);
- WatchpointSP wp_sp =
- GetTarget().GetWatchpointList().FindByAddress(wp_addr);
+ WatchpointResourceSP wp_resource_sp =
+ m_watchpoint_resource_list.FindByAddress(wp_addr);
// Rewrite gdb standard watch/rwatch/awatch to
// "reason:watchpoint" + "description:ADDR",
@@ -3109,102 +3115,182 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {
}
// Pre-requisite: wp != NULL.
-static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) {
- assert(wp);
- bool watch_read = wp->WatchpointRead();
- bool watch_write = wp->WatchpointWrite();
- bool watch_modify = wp->WatchpointModify();
-
- // watch_read, watch_write, watch_modify cannot all be false.
- assert((watch_read || watch_write || watch_modify) &&
- "watch_read, watch_write, watch_modify cannot all be false.");
- if (watch_read && (watch_write || watch_modify))
+static GDBStoppointType
+GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) {
+ assert(wp_res_sp);
+ bool read = wp_res_sp->WatchpointResourceRead();
+ bool write = wp_res_sp->WatchpointResourceWrite();
+
+ assert((read || write) &&
+ "WatchpointResource type is neither read nor write");
+ if (read && write)
return eWatchpointReadWrite;
- else if (watch_read)
+ else if (read)
return eWatchpointRead;
- else // Must be watch_write or watch_modify, then.
+ else
return eWatchpointWrite;
}
-Status ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) {
+Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
Status error;
- if (wp) {
- user_id_t watchID = wp->GetID();
- addr_t addr = wp->GetLoadAddress();
- Log *log(GetLog(GDBRLog::Watchpoints));
- LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")",
- watchID);
- if (wp->IsEnabled()) {
- LLDB_LOGF(log,
- "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64
- ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
- watchID, (uint64_t)addr);
- return error;
- }
+ if (!wp_sp) {
+ error.SetErrorString("No watchpoint specified");
+ return error;
+ }
+ user_id_t watchID = wp_sp->GetID();
+ addr_t addr = wp_sp->GetLoadAddress();
+ Log *log(GetLog(GDBRLog::Watchpoints));
+ LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (wp_sp->IsEnabled()) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+ watchID, (uint64_t)addr);
+ return error;
+ }
- GDBStoppointType type = GetGDBStoppointType(wp);
- // Pass down an appropriate z/Z packet...
- if (m_gdb_comm.SupportsGDBStoppointPacket(type)) {
- if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr,
- wp->GetByteSize(),
- GetInterruptTimeout()) == 0) {
- wp->SetEnabled(true, notify);
- return error;
- } else
- error.SetErrorString("sending gdb watchpoint packet failed");
- } else
- error.SetErrorString("watchpoints not supported");
+ bool read = wp_sp->WatchpointRead();
+ bool write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify();
+ size_t size = wp_sp->GetByteSize();
+
+ // New WatchpointResources needed to implement this Watchpoint.
+ std::vector<WatchpointResourceSP> resources;
+
+ // LWP_TODO: Break up the user's request into pieces that can be watched
+ // given the capabilities of the target cpu / stub software.
+ // As a default, breaking the watched region up into target-pointer-sized,
+ // aligned, groups.
+ //
+ // Beyond the default, a stub can / should inform us of its capabilities,
+ // e.g. a stub that can do AArch64 power-of-2 MASK watchpoints.
+ //
+ // And the cpu may have unique capabilities. AArch64 BAS watchpoints
+ // can watch any sequential bytes in a doubleword, but Intel watchpoints
+ // can only watch 1, 2, 4, 8 bytes within a doubleword.
+ WatchpointResourceSP wp_res_sp =
+ std::make_shared<WatchpointResource>(addr, size, read, write);
+ resources.push_back(wp_res_sp);
+
+ // LWP_TODO: Now that we know the WP Resources needed to implement this
+ // Watchpoint, we need to look at currently allocated Resources in the
+ // Process and if they match, or are within the same memory granule, or
+ // overlapping memory ranges, then we need to combine them. e.g. one
+ // Watchpoint watching 1 byte at 0x1002 and a second watchpoint watching 1
+ // byte at 0x1003, they must use the same hardware watchpoint register
+ // (Resource) to watch them.
+
+ // This may mean that an existing resource changes its type (read to
+ // read+write) or address range it is watching, in which case the old
+ // watchpoint needs to be disabled and the new Resource addr/size/type
+ // watchpoint enabled.
+
+ // If we modify a shared Resource to accomodate this newly added Watchpoint,
+ // and we are unable to set all of the Resources for it in the inferior, we
+ // will return an error for this Watchpoint and the shared Resource should
+ // be restored. e.g. this Watchpoint requires three Resources, one which
+ // is shared with another Watchpoint. We extend the shared Resouce to
+ // handle both Watchpoints and we try to set two new ones. But if we don't
+ // have sufficient watchpoint register for all 3, we need to show an error
+ // for creating this Watchpoint and we should reset the shared Resource to
+ // its original configuration because it is no longer shared.
+
+ bool set_all_resources = true;
+ std::vector<WatchpointResourceSP> succesfully_set_resources;
+ for (const auto &wp_res_sp : resources) {
+ addr_t addr = wp_res_sp->GetLoadAddress();
+ size_t size = wp_res_sp->GetByteSize();
+ GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+ if (!m_gdb_comm.SupportsGDBStoppointPacket(type) ||
+ m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
+ GetInterruptTimeout())) {
+ set_all_resources = false;
+ break;
+ } else {
+ succesfully_set_resources.push_back(wp_res_sp);
+ }
+ }
+ if (set_all_resources) {
+ wp_sp->SetEnabled(true, notify);
+ for (const auto &wp_res_sp : resources) {
+ // LWP_TODO: If we expanded/reused an existing Resource,
+ // it's already in the WatchpointResourceList.
+ wp_res_sp->AddConstituent(wp_sp);
+ m_watchpoint_resource_list.Add(wp_res_sp);
+ }
+ return error;
} else {
- error.SetErrorString("Watchpoint argument was NULL.");
+ // We failed to allocate one of the resources. Unset all
+ // of the new resources we did successfully set in the
+ // process.
+ for (const auto &wp_res_sp : succesfully_set_resources) {
+ addr_t addr = wp_res_sp->GetLoadAddress();
+ size_t size = wp_res_sp->GetByteSize();
+ GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+ m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
+ GetInterruptTimeout());
+ }
+ error.SetErrorString("Setting one of the watchpoint resources failed");
}
- if (error.Success())
- error.SetErrorToGenericError();
return error;
}
-Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) {
+Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
Status error;
- if (wp) {
- user_id_t watchID = wp->GetID();
+ if (!wp_sp) {
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+ }
+
+ user_id_t watchID = wp_sp->GetID();
- Log *log(GetLog(GDBRLog::Watchpoints));
+ Log *log(GetLog(GDBRLog::Watchpoints));
- addr_t addr = wp->GetLoadAddress();
+ addr_t addr = wp_sp->GetLoadAddress();
+
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64,
+ watchID, (uint64_t)addr);
+ if (!wp_sp->IsEnabled()) {
LLDB_LOGF(log,
"ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
- ") addr = 0x%8.8" PRIx64,
+ ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)",
watchID, (uint64_t)addr);
+ // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling
+ // attempt might come from the user-supplied actions, we'll route it in
+ // order for the watchpoint object to intelligently process this action.
+ wp_sp->SetEnabled(false, notify);
+ return error;
+ }
- if (!wp->IsEnabled()) {
- LLDB_LOGF(log,
- "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
- ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)",
- watchID, (uint64_t)addr);
- // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling
- // attempt might come from the user-supplied actions, we'll route it in
- // order for the watchpoint object to intelligently process this action.
- wp->SetEnabled(false, notify);
- return error;
- }
+ if (wp_sp->IsHardware()) {
+ bool disabled_all = true;
- if (wp->IsHardware()) {
- GDBStoppointType type = GetGDBStoppointType(wp);
- // Pass down an appropriate z/Z packet...
- if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr,
- wp->GetByteSize(),
- GetInterruptTimeout()) == 0) {
- wp->SetEnabled(false, notify);
- return error;
- } else
- error.SetErrorString("sending gdb watchpoint packet failed");
+ std::vector<WatchpointResourceSP> unused_resources;
+ for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) {
+ if (wp_res_sp->ConstituentsContains(wp_sp)) {
+ GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+ addr_t addr = wp_res_sp->GetLoadAddress();
+ size_t size = wp_res_sp->GetByteSize();
+ if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
+ GetInterruptTimeout())) {
+ disabled_all = false;
+ } else {
+ wp_res_sp->RemoveConstituent(wp_sp);
+ if (wp_res_sp->GetNumberOfConstituents() == 0)
+ unused_resources.push_back(wp_res_sp);
+ }
+ }
}
- // TODO: clear software watchpoints if we implement them
- } else {
- error.SetErrorString("Watchpoint argument was NULL.");
+ for (auto &wp_res_sp : unused_resources)
+ m_watchpoint_resource_list.Remove(wp_res_sp->GetID());
+
+ wp_sp->SetEnabled(false, notify);
+ if (!disabled_all)
+ error.SetErrorString("Failure disabling one of the watchpoint locations");
}
- if (error.Success())
- error.SetErrorToGenericError();
return error;
}
@@ -5456,16 +5542,12 @@ void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) {
});
}
- WatchpointList &wps = GetTarget().GetWatchpointList();
- size_t wp_count = wps.GetSize();
- for (size_t i = 0; i < wp_count; ++i) {
- WatchpointSP wp = wps.GetByIndex(i);
- if (wp->IsEnabled()) {
- GDBStoppointType type = GetGDBStoppointType(wp.get());
- m_gdb_comm.SendGDBStoppointTypePacket(type, enable, wp->GetLoadAddress(),
- wp->GetByteSize(),
- GetInterruptTimeout());
- }
+ for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) {
+ addr_t addr = wp_res_sp->GetLoadAddress();
+ size_t size = wp_res_sp->GetByteSize();
+ GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+ m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
+ GetInterruptTimeout());
}
}