Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Breakpoint / Watchpoint.cpp
blob14144214faea74798a00fa07779c4df83ca12a4d
1 //===-- Watchpoint.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Breakpoint/Watchpoint.h"
11 #include "lldb/Breakpoint/StoppointCallbackContext.h"
12 #include "lldb/Core/Value.h"
13 #include "lldb/Core/ValueObject.h"
14 #include "lldb/Core/ValueObjectMemory.h"
15 #include "lldb/Expression/UserExpression.h"
16 #include "lldb/Symbol/TypeSystem.h"
17 #include "lldb/Target/Process.h"
18 #include "lldb/Target/Target.h"
19 #include "lldb/Target/ThreadSpec.h"
20 #include "lldb/Utility/LLDBLog.h"
21 #include "lldb/Utility/Log.h"
22 #include "lldb/Utility/Stream.h"
24 using namespace lldb;
25 using namespace lldb_private;
27 Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size,
28 const CompilerType *type, bool hardware)
29 : StoppointSite(0, addr, size, hardware), m_target(target),
30 m_enabled(false), m_is_hardware(hardware), m_is_watch_variable(false),
31 m_is_ephemeral(false), m_disabled_count(0), m_watch_read(0),
32 m_watch_write(0), m_watch_modify(0), m_ignore_count(0),
33 m_being_created(true) {
35 if (type && type->IsValid())
36 m_type = *type;
37 else {
38 // If we don't have a known type, then we force it to unsigned int of the
39 // right size.
40 auto type_system_or_err =
41 target.GetScratchTypeSystemForLanguage(eLanguageTypeC);
42 if (auto err = type_system_or_err.takeError()) {
43 LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err),
44 "Failed to set type: {0}");
45 } else {
46 if (auto ts = *type_system_or_err)
47 m_type =
48 ts->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size);
49 else
50 LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err),
51 "Failed to set type: Typesystem is no longer live: {0}");
55 // Set the initial value of the watched variable:
56 if (m_target.GetProcessSP()) {
57 ExecutionContext exe_ctx;
58 m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
59 CaptureWatchedValue(exe_ctx);
61 m_being_created = false;
64 Watchpoint::~Watchpoint() = default;
66 // This function is used when "baton" doesn't need to be freed
67 void Watchpoint::SetCallback(WatchpointHitCallback callback, void *baton,
68 bool is_synchronous) {
69 // The default "Baton" class will keep a copy of "baton" and won't free or
70 // delete it when it goes out of scope.
71 m_options.SetCallback(callback, std::make_shared<UntypedBaton>(baton),
72 is_synchronous);
74 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
77 // This function is used when a baton needs to be freed and therefore is
78 // contained in a "Baton" subclass.
79 void Watchpoint::SetCallback(WatchpointHitCallback callback,
80 const BatonSP &callback_baton_sp,
81 bool is_synchronous) {
82 m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
83 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
86 bool Watchpoint::SetupVariableWatchpointDisabler(StackFrameSP frame_sp) const {
87 if (!frame_sp)
88 return false;
90 ThreadSP thread_sp = frame_sp->GetThread();
91 if (!thread_sp)
92 return false;
94 uint32_t return_frame_index =
95 thread_sp->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame) + 1;
96 if (return_frame_index >= LLDB_INVALID_FRAME_ID)
97 return false;
99 StackFrameSP return_frame_sp(
100 thread_sp->GetStackFrameAtIndex(return_frame_index));
101 if (!return_frame_sp)
102 return false;
104 ExecutionContext exe_ctx(return_frame_sp);
105 TargetSP target_sp = exe_ctx.GetTargetSP();
106 if (!target_sp)
107 return false;
109 Address return_address(return_frame_sp->GetFrameCodeAddress());
110 lldb::addr_t return_addr = return_address.GetLoadAddress(target_sp.get());
111 if (return_addr == LLDB_INVALID_ADDRESS)
112 return false;
114 BreakpointSP bp_sp = target_sp->CreateBreakpoint(
115 return_addr, /*internal=*/true, /*request_hardware=*/false);
116 if (!bp_sp || !bp_sp->HasResolvedLocations())
117 return false;
119 auto wvc_up = std::make_unique<WatchpointVariableContext>(GetID(), exe_ctx);
120 auto baton_sp = std::make_shared<WatchpointVariableBaton>(std::move(wvc_up));
121 bp_sp->SetCallback(VariableWatchpointDisabler, baton_sp);
122 bp_sp->SetOneShot(true);
123 bp_sp->SetBreakpointKind("variable watchpoint disabler");
124 return true;
127 bool Watchpoint::VariableWatchpointDisabler(void *baton,
128 StoppointCallbackContext *context,
129 user_id_t break_id,
130 user_id_t break_loc_id) {
131 assert(baton && "null baton");
132 if (!baton || !context)
133 return false;
135 Log *log = GetLog(LLDBLog::Watchpoints);
137 WatchpointVariableContext *wvc =
138 static_cast<WatchpointVariableContext *>(baton);
140 LLDB_LOGF(log, "called by breakpoint %" PRIu64 ".%" PRIu64, break_id,
141 break_loc_id);
143 if (wvc->watch_id == LLDB_INVALID_WATCH_ID)
144 return false;
146 TargetSP target_sp = context->exe_ctx_ref.GetTargetSP();
147 if (!target_sp)
148 return false;
150 ProcessSP process_sp = target_sp->GetProcessSP();
151 if (!process_sp)
152 return false;
154 WatchpointSP watch_sp =
155 target_sp->GetWatchpointList().FindByID(wvc->watch_id);
156 if (!watch_sp)
157 return false;
159 if (wvc->exe_ctx == context->exe_ctx_ref) {
160 LLDB_LOGF(log,
161 "callback for watchpoint %" PRId32
162 " matched internal breakpoint execution context",
163 watch_sp->GetID());
164 process_sp->DisableWatchpoint(watch_sp.get());
165 return false;
167 LLDB_LOGF(log,
168 "callback for watchpoint %" PRId32
169 " didn't match internal breakpoint execution context",
170 watch_sp->GetID());
171 return false;
174 void Watchpoint::ClearCallback() {
175 m_options.ClearCallback();
176 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
179 void Watchpoint::SetDeclInfo(const std::string &str) { m_decl_str = str; }
181 std::string Watchpoint::GetWatchSpec() { return m_watch_spec_str; }
183 void Watchpoint::SetWatchSpec(const std::string &str) {
184 m_watch_spec_str = str;
187 bool Watchpoint::IsHardware() const {
188 lldbassert(m_is_hardware || !HardwareRequired());
189 return m_is_hardware;
192 bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; }
194 void Watchpoint::SetWatchVariable(bool val) { m_is_watch_variable = val; }
196 bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
197 ConstString g_watch_name("$__lldb__watch_value");
198 m_old_value_sp = m_new_value_sp;
199 Address watch_address(GetLoadAddress());
200 if (!m_type.IsValid()) {
201 // Don't know how to report new & old values, since we couldn't make a
202 // scalar type for this watchpoint. This works around an assert in
203 // ValueObjectMemory::Create.
204 // FIXME: This should not happen, but if it does in some case we care about,
205 // we can go grab the value raw and print it as unsigned.
206 return false;
208 m_new_value_sp = ValueObjectMemory::Create(
209 exe_ctx.GetBestExecutionContextScope(), g_watch_name.GetStringRef(),
210 watch_address, m_type);
211 m_new_value_sp = m_new_value_sp->CreateConstantValue(g_watch_name);
212 return (m_new_value_sp && m_new_value_sp->GetError().Success());
215 bool Watchpoint::WatchedValueReportable(const ExecutionContext &exe_ctx) {
216 if (!m_watch_modify || m_watch_read)
217 return true;
218 if (!m_type.IsValid())
219 return true;
221 ConstString g_watch_name("$__lldb__watch_value");
222 Address watch_address(GetLoadAddress());
223 ValueObjectSP newest_valueobj_sp = ValueObjectMemory::Create(
224 exe_ctx.GetBestExecutionContextScope(), g_watch_name.GetStringRef(),
225 watch_address, m_type);
226 newest_valueobj_sp = newest_valueobj_sp->CreateConstantValue(g_watch_name);
227 Status error;
229 DataExtractor new_data;
230 DataExtractor old_data;
232 newest_valueobj_sp->GetData(new_data, error);
233 if (error.Fail())
234 return true;
235 m_new_value_sp->GetData(old_data, error);
236 if (error.Fail())
237 return true;
239 if (new_data.GetByteSize() != old_data.GetByteSize() ||
240 new_data.GetByteSize() == 0)
241 return true;
243 if (memcmp(new_data.GetDataStart(), old_data.GetDataStart(),
244 old_data.GetByteSize()) == 0)
245 return false; // Value has not changed, user requested modify watchpoint
247 return true;
250 // RETURNS - true if we should stop at this breakpoint, false if we
251 // should continue.
253 bool Watchpoint::ShouldStop(StoppointCallbackContext *context) {
254 m_hit_counter.Increment();
256 return IsEnabled();
259 void Watchpoint::GetDescription(Stream *s, lldb::DescriptionLevel level) {
260 DumpWithLevel(s, level);
263 void Watchpoint::Dump(Stream *s) const {
264 DumpWithLevel(s, lldb::eDescriptionLevelBrief);
267 // If prefix is nullptr, we display the watch id and ignore the prefix
268 // altogether.
269 void Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
270 if (!prefix) {
271 s->Printf("\nWatchpoint %u hit:", GetID());
272 prefix = "";
275 if (m_old_value_sp) {
276 const char *old_value_cstr = m_old_value_sp->GetValueAsCString();
277 if (old_value_cstr && old_value_cstr[0])
278 s->Printf("\n%sold value: %s", prefix, old_value_cstr);
279 else {
280 const char *old_summary_cstr = m_old_value_sp->GetSummaryAsCString();
281 if (old_summary_cstr && old_summary_cstr[0])
282 s->Printf("\n%sold value: %s", prefix, old_summary_cstr);
286 if (m_new_value_sp) {
287 const char *new_value_cstr = m_new_value_sp->GetValueAsCString();
288 if (new_value_cstr && new_value_cstr[0])
289 s->Printf("\n%snew value: %s", prefix, new_value_cstr);
290 else {
291 const char *new_summary_cstr = m_new_value_sp->GetSummaryAsCString();
292 if (new_summary_cstr && new_summary_cstr[0])
293 s->Printf("\n%snew value: %s", prefix, new_summary_cstr);
298 void Watchpoint::DumpWithLevel(Stream *s,
299 lldb::DescriptionLevel description_level) const {
300 if (s == nullptr)
301 return;
303 assert(description_level >= lldb::eDescriptionLevelBrief &&
304 description_level <= lldb::eDescriptionLevelVerbose);
306 s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64
307 " size = %u state = %s type = %s%s%s",
308 GetID(), GetLoadAddress(), m_byte_size,
309 IsEnabled() ? "enabled" : "disabled", m_watch_read ? "r" : "",
310 m_watch_write ? "w" : "", m_watch_modify ? "m" : "");
312 if (description_level >= lldb::eDescriptionLevelFull) {
313 if (!m_decl_str.empty())
314 s->Printf("\n declare @ '%s'", m_decl_str.c_str());
315 if (!m_watch_spec_str.empty())
316 s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str());
318 // Dump the snapshots we have taken.
319 DumpSnapshots(s, " ");
321 if (GetConditionText())
322 s->Printf("\n condition = '%s'", GetConditionText());
323 m_options.GetCallbackDescription(s, description_level);
326 if (description_level >= lldb::eDescriptionLevelVerbose) {
327 s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u",
328 GetHardwareIndex(), GetHitCount(), GetIgnoreCount());
332 bool Watchpoint::IsEnabled() const { return m_enabled; }
334 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
335 // temporarily disable the watchpoint in order to perform possible watchpoint
336 // actions without triggering further watchpoint events. After the temporary
337 // disabled watchpoint is enabled, we then turn off the ephemeral mode.
339 void Watchpoint::TurnOnEphemeralMode() { m_is_ephemeral = true; }
341 void Watchpoint::TurnOffEphemeralMode() {
342 m_is_ephemeral = false;
343 // Leaving ephemeral mode, reset the m_disabled_count!
344 m_disabled_count = 0;
347 bool Watchpoint::IsDisabledDuringEphemeralMode() {
348 return m_disabled_count > 1 && m_is_ephemeral;
351 void Watchpoint::SetEnabled(bool enabled, bool notify) {
352 if (!enabled) {
353 if (!m_is_ephemeral)
354 SetHardwareIndex(LLDB_INVALID_INDEX32);
355 else
356 ++m_disabled_count;
358 // Don't clear the snapshots for now.
359 // Within StopInfo.cpp, we purposely do disable/enable watchpoint while
360 // performing watchpoint actions.
362 bool changed = enabled != m_enabled;
363 m_enabled = enabled;
364 if (notify && !m_is_ephemeral && changed)
365 SendWatchpointChangedEvent(enabled ? eWatchpointEventTypeEnabled
366 : eWatchpointEventTypeDisabled);
369 void Watchpoint::SetWatchpointType(uint32_t type, bool notify) {
370 int old_watch_read = m_watch_read;
371 int old_watch_write = m_watch_write;
372 int old_watch_modify = m_watch_modify;
373 m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
374 m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
375 m_watch_modify = (type & LLDB_WATCH_TYPE_MODIFY) != 0;
376 if (notify &&
377 (old_watch_read != m_watch_read || old_watch_write != m_watch_write ||
378 old_watch_modify != m_watch_modify))
379 SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged);
382 bool Watchpoint::WatchpointRead() const { return m_watch_read != 0; }
384 bool Watchpoint::WatchpointWrite() const { return m_watch_write != 0; }
386 bool Watchpoint::WatchpointModify() const { return m_watch_modify != 0; }
388 uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count; }
390 void Watchpoint::SetIgnoreCount(uint32_t n) {
391 bool changed = m_ignore_count != n;
392 m_ignore_count = n;
393 if (changed)
394 SendWatchpointChangedEvent(eWatchpointEventTypeIgnoreChanged);
397 bool Watchpoint::InvokeCallback(StoppointCallbackContext *context) {
398 return m_options.InvokeCallback(context, GetID());
401 void Watchpoint::SetCondition(const char *condition) {
402 if (condition == nullptr || condition[0] == '\0') {
403 if (m_condition_up)
404 m_condition_up.reset();
405 } else {
406 // Pass nullptr for expr_prefix (no translation-unit level definitions).
407 Status error;
408 m_condition_up.reset(m_target.GetUserExpressionForLanguage(
409 condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
410 UserExpression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
411 error));
412 if (error.Fail()) {
413 // FIXME: Log something...
414 m_condition_up.reset();
417 SendWatchpointChangedEvent(eWatchpointEventTypeConditionChanged);
420 const char *Watchpoint::GetConditionText() const {
421 if (m_condition_up)
422 return m_condition_up->GetUserText();
423 else
424 return nullptr;
427 void Watchpoint::SendWatchpointChangedEvent(
428 lldb::WatchpointEventType eventKind) {
429 if (!m_being_created &&
430 GetTarget().EventTypeHasListeners(
431 Target::eBroadcastBitWatchpointChanged)) {
432 WatchpointEventData *data =
433 new Watchpoint::WatchpointEventData(eventKind, shared_from_this());
434 GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data);
438 void Watchpoint::SendWatchpointChangedEvent(WatchpointEventData *data) {
439 if (data == nullptr)
440 return;
442 if (!m_being_created &&
443 GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
444 GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data);
445 else
446 delete data;
449 Watchpoint::WatchpointEventData::WatchpointEventData(
450 WatchpointEventType sub_type, const WatchpointSP &new_watchpoint_sp)
451 : m_watchpoint_event(sub_type), m_new_watchpoint_sp(new_watchpoint_sp) {}
453 Watchpoint::WatchpointEventData::~WatchpointEventData() = default;
455 llvm::StringRef Watchpoint::WatchpointEventData::GetFlavorString() {
456 return "Watchpoint::WatchpointEventData";
459 llvm::StringRef Watchpoint::WatchpointEventData::GetFlavor() const {
460 return WatchpointEventData::GetFlavorString();
463 WatchpointSP &Watchpoint::WatchpointEventData::GetWatchpoint() {
464 return m_new_watchpoint_sp;
467 WatchpointEventType
468 Watchpoint::WatchpointEventData::GetWatchpointEventType() const {
469 return m_watchpoint_event;
472 void Watchpoint::WatchpointEventData::Dump(Stream *s) const {}
474 const Watchpoint::WatchpointEventData *
475 Watchpoint::WatchpointEventData::GetEventDataFromEvent(const Event *event) {
476 if (event) {
477 const EventData *event_data = event->GetData();
478 if (event_data &&
479 event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
480 return static_cast<const WatchpointEventData *>(event->GetData());
482 return nullptr;
485 WatchpointEventType
486 Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent(
487 const EventSP &event_sp) {
488 const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
490 if (data == nullptr)
491 return eWatchpointEventTypeInvalidType;
492 else
493 return data->GetWatchpointEventType();
496 WatchpointSP Watchpoint::WatchpointEventData::GetWatchpointFromEvent(
497 const EventSP &event_sp) {
498 WatchpointSP wp_sp;
500 const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
501 if (data)
502 wp_sp = data->m_new_watchpoint_sp;
504 return wp_sp;