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 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Breakpoint/Watchpoint.h"
10 
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"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
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_ignore_count(0), m_being_created(true) {
33 
34   if (type && type->IsValid())
35     m_type = *type;
36   else {
37     // If we don't have a known type, then we force it to unsigned int of the
38     // right size.
39     auto type_system_or_err =
40         target.GetScratchTypeSystemForLanguage(eLanguageTypeC);
41     if (auto err = type_system_or_err.takeError()) {
42       LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err),
43                      "Failed to set type: {0}");
44     } else {
45       if (auto ts = *type_system_or_err)
46         m_type =
47             ts->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size);
48       else
49         LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err),
50                        "Failed to set type: Typesystem is no longer live: {0}");
51     }
52   }
53 
54   // Set the initial value of the watched variable:
55   if (m_target.GetProcessSP()) {
56     ExecutionContext exe_ctx;
57     m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
58     CaptureWatchedValue(exe_ctx);
59   }
60   m_being_created = false;
61 }
62 
63 Watchpoint::~Watchpoint() = default;
64 
65 // This function is used when "baton" doesn't need to be freed
66 void Watchpoint::SetCallback(WatchpointHitCallback callback, void *baton,
67                              bool is_synchronous) {
68   // The default "Baton" class will keep a copy of "baton" and won't free or
69   // delete it when it goes goes out of scope.
70   m_options.SetCallback(callback, std::make_shared<UntypedBaton>(baton),
71                         is_synchronous);
72 
73   SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
74 }
75 
76 // This function is used when a baton needs to be freed and therefore is
77 // contained in a "Baton" subclass.
78 void Watchpoint::SetCallback(WatchpointHitCallback callback,
79                              const BatonSP &callback_baton_sp,
80                              bool is_synchronous) {
81   m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
82   SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
83 }
84 
85 bool Watchpoint::SetupVariableWatchpointDisabler(StackFrameSP frame_sp) const {
86   if (!frame_sp)
87     return false;
88 
89   ThreadSP thread_sp = frame_sp->GetThread();
90   if (!thread_sp)
91     return false;
92 
93   uint32_t return_frame_index =
94       thread_sp->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame) + 1;
95   if (return_frame_index >= LLDB_INVALID_FRAME_ID)
96     return false;
97 
98   StackFrameSP return_frame_sp(
99       thread_sp->GetStackFrameAtIndex(return_frame_index));
100   if (!return_frame_sp)
101     return false;
102 
103   ExecutionContext exe_ctx(return_frame_sp);
104   TargetSP target_sp = exe_ctx.GetTargetSP();
105   if (!target_sp)
106     return false;
107 
108   Address return_address(return_frame_sp->GetFrameCodeAddress());
109   lldb::addr_t return_addr = return_address.GetLoadAddress(target_sp.get());
110   if (return_addr == LLDB_INVALID_ADDRESS)
111     return false;
112 
113   BreakpointSP bp_sp = target_sp->CreateBreakpoint(
114       return_addr, /*internal=*/true, /*request_hardware=*/false);
115   if (!bp_sp || !bp_sp->HasResolvedLocations())
116     return false;
117 
118   auto wvc_up = std::make_unique<WatchpointVariableContext>(GetID(), exe_ctx);
119   auto baton_sp = std::make_shared<WatchpointVariableBaton>(std::move(wvc_up));
120   bp_sp->SetCallback(VariableWatchpointDisabler, baton_sp);
121   bp_sp->SetOneShot(true);
122   bp_sp->SetBreakpointKind("variable watchpoint disabler");
123   return true;
124 }
125 
126 bool Watchpoint::VariableWatchpointDisabler(void *baton,
127                                             StoppointCallbackContext *context,
128                                             user_id_t break_id,
129                                             user_id_t break_loc_id) {
130   assert(baton && "null baton");
131   if (!baton || !context)
132     return false;
133 
134   Log *log = GetLog(LLDBLog::Watchpoints);
135 
136   WatchpointVariableContext *wvc =
137       static_cast<WatchpointVariableContext *>(baton);
138 
139   LLDB_LOGF(log, "called by breakpoint %" PRIu64 ".%" PRIu64, break_id,
140             break_loc_id);
141 
142   if (wvc->watch_id == LLDB_INVALID_WATCH_ID)
143     return false;
144 
145   TargetSP target_sp = context->exe_ctx_ref.GetTargetSP();
146   if (!target_sp)
147     return false;
148 
149   ProcessSP process_sp = target_sp->GetProcessSP();
150   if (!process_sp)
151     return false;
152 
153   WatchpointSP watch_sp =
154       target_sp->GetWatchpointList().FindByID(wvc->watch_id);
155   if (!watch_sp)
156     return false;
157 
158   if (wvc->exe_ctx == context->exe_ctx_ref) {
159     LLDB_LOGF(log,
160               "callback for watchpoint %" PRId32
161               " matched internal breakpoint execution context",
162               watch_sp->GetID());
163     process_sp->DisableWatchpoint(watch_sp.get());
164     return false;
165   }
166   LLDB_LOGF(log,
167             "callback for watchpoint %" PRId32
168             " didn't match internal breakpoint execution context",
169             watch_sp->GetID());
170   return false;
171 }
172 
173 void Watchpoint::ClearCallback() {
174   m_options.ClearCallback();
175   SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
176 }
177 
178 void Watchpoint::SetDeclInfo(const std::string &str) { m_decl_str = str; }
179 
180 std::string Watchpoint::GetWatchSpec() { return m_watch_spec_str; }
181 
182 void Watchpoint::SetWatchSpec(const std::string &str) {
183   m_watch_spec_str = str;
184 }
185 
186 bool Watchpoint::IsHardware() const {
187   lldbassert(m_is_hardware || !HardwareRequired());
188   return m_is_hardware;
189 }
190 
191 bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; }
192 
193 void Watchpoint::SetWatchVariable(bool val) { m_is_watch_variable = val; }
194 
195 bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
196   ConstString watch_name("$__lldb__watch_value");
197   m_old_value_sp = m_new_value_sp;
198   Address watch_address(GetLoadAddress());
199   if (!m_type.IsValid()) {
200     // Don't know how to report new & old values, since we couldn't make a
201     // scalar type for this watchpoint. This works around an assert in
202     // ValueObjectMemory::Create.
203     // FIXME: This should not happen, but if it does in some case we care about,
204     // we can go grab the value raw and print it as unsigned.
205     return false;
206   }
207   m_new_value_sp = ValueObjectMemory::Create(
208       exe_ctx.GetBestExecutionContextScope(), watch_name.GetStringRef(),
209       watch_address, m_type);
210   m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
211   return (m_new_value_sp && m_new_value_sp->GetError().Success());
212 }
213 
214 // RETURNS - true if we should stop at this breakpoint, false if we
215 // should continue.
216 
217 bool Watchpoint::ShouldStop(StoppointCallbackContext *context) {
218   m_hit_counter.Increment();
219 
220   return IsEnabled();
221 }
222 
223 void Watchpoint::GetDescription(Stream *s, lldb::DescriptionLevel level) {
224   DumpWithLevel(s, level);
225 }
226 
227 void Watchpoint::Dump(Stream *s) const {
228   DumpWithLevel(s, lldb::eDescriptionLevelBrief);
229 }
230 
231 // If prefix is nullptr, we display the watch id and ignore the prefix
232 // altogether.
233 void Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
234   if (!prefix) {
235     s->Printf("\nWatchpoint %u hit:", GetID());
236     prefix = "";
237   }
238 
239   if (m_old_value_sp) {
240     const char *old_value_cstr = m_old_value_sp->GetValueAsCString();
241     if (old_value_cstr && old_value_cstr[0])
242       s->Printf("\n%sold value: %s", prefix, old_value_cstr);
243     else {
244       const char *old_summary_cstr = m_old_value_sp->GetSummaryAsCString();
245       if (old_summary_cstr && old_summary_cstr[0])
246         s->Printf("\n%sold value: %s", prefix, old_summary_cstr);
247     }
248   }
249 
250   if (m_new_value_sp) {
251     const char *new_value_cstr = m_new_value_sp->GetValueAsCString();
252     if (new_value_cstr && new_value_cstr[0])
253       s->Printf("\n%snew value: %s", prefix, new_value_cstr);
254     else {
255       const char *new_summary_cstr = m_new_value_sp->GetSummaryAsCString();
256       if (new_summary_cstr && new_summary_cstr[0])
257         s->Printf("\n%snew value: %s", prefix, new_summary_cstr);
258     }
259   }
260 }
261 
262 void Watchpoint::DumpWithLevel(Stream *s,
263                                lldb::DescriptionLevel description_level) const {
264   if (s == nullptr)
265     return;
266 
267   assert(description_level >= lldb::eDescriptionLevelBrief &&
268          description_level <= lldb::eDescriptionLevelVerbose);
269 
270   s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64
271             " size = %u state = %s type = %s%s",
272             GetID(), GetLoadAddress(), m_byte_size,
273             IsEnabled() ? "enabled" : "disabled", m_watch_read ? "r" : "",
274             m_watch_write ? "w" : "");
275 
276   if (description_level >= lldb::eDescriptionLevelFull) {
277     if (!m_decl_str.empty())
278       s->Printf("\n    declare @ '%s'", m_decl_str.c_str());
279     if (!m_watch_spec_str.empty())
280       s->Printf("\n    watchpoint spec = '%s'", m_watch_spec_str.c_str());
281 
282     // Dump the snapshots we have taken.
283     DumpSnapshots(s, "    ");
284 
285     if (GetConditionText())
286       s->Printf("\n    condition = '%s'", GetConditionText());
287     m_options.GetCallbackDescription(s, description_level);
288   }
289 
290   if (description_level >= lldb::eDescriptionLevelVerbose) {
291     s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
292               GetHardwareIndex(), GetHitCount(), GetIgnoreCount());
293   }
294 }
295 
296 bool Watchpoint::IsEnabled() const { return m_enabled; }
297 
298 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
299 // temporarily disable the watchpoint in order to perform possible watchpoint
300 // actions without triggering further watchpoint events. After the temporary
301 // disabled watchpoint is enabled, we then turn off the ephemeral mode.
302 
303 void Watchpoint::TurnOnEphemeralMode() { m_is_ephemeral = true; }
304 
305 void Watchpoint::TurnOffEphemeralMode() {
306   m_is_ephemeral = false;
307   // Leaving ephemeral mode, reset the m_disabled_count!
308   m_disabled_count = 0;
309 }
310 
311 bool Watchpoint::IsDisabledDuringEphemeralMode() {
312   return m_disabled_count > 1 && m_is_ephemeral;
313 }
314 
315 void Watchpoint::SetEnabled(bool enabled, bool notify) {
316   if (!enabled) {
317     if (!m_is_ephemeral)
318       SetHardwareIndex(LLDB_INVALID_INDEX32);
319     else
320       ++m_disabled_count;
321 
322     // Don't clear the snapshots for now.
323     // Within StopInfo.cpp, we purposely do disable/enable watchpoint while
324     // performing watchpoint actions.
325   }
326   bool changed = enabled != m_enabled;
327   m_enabled = enabled;
328   if (notify && !m_is_ephemeral && changed)
329     SendWatchpointChangedEvent(enabled ? eWatchpointEventTypeEnabled
330                                        : eWatchpointEventTypeDisabled);
331 }
332 
333 void Watchpoint::SetWatchpointType(uint32_t type, bool notify) {
334   int old_watch_read = m_watch_read;
335   int old_watch_write = m_watch_write;
336   m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
337   m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
338   if (notify &&
339       (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
340     SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged);
341 }
342 
343 bool Watchpoint::WatchpointRead() const { return m_watch_read != 0; }
344 
345 bool Watchpoint::WatchpointWrite() const { return m_watch_write != 0; }
346 
347 uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count; }
348 
349 void Watchpoint::SetIgnoreCount(uint32_t n) {
350   bool changed = m_ignore_count != n;
351   m_ignore_count = n;
352   if (changed)
353     SendWatchpointChangedEvent(eWatchpointEventTypeIgnoreChanged);
354 }
355 
356 bool Watchpoint::InvokeCallback(StoppointCallbackContext *context) {
357   return m_options.InvokeCallback(context, GetID());
358 }
359 
360 void Watchpoint::SetCondition(const char *condition) {
361   if (condition == nullptr || condition[0] == '\0') {
362     if (m_condition_up)
363       m_condition_up.reset();
364   } else {
365     // Pass nullptr for expr_prefix (no translation-unit level definitions).
366     Status error;
367     m_condition_up.reset(m_target.GetUserExpressionForLanguage(
368         condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
369         UserExpression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
370         error));
371     if (error.Fail()) {
372       // FIXME: Log something...
373       m_condition_up.reset();
374     }
375   }
376   SendWatchpointChangedEvent(eWatchpointEventTypeConditionChanged);
377 }
378 
379 const char *Watchpoint::GetConditionText() const {
380   if (m_condition_up)
381     return m_condition_up->GetUserText();
382   else
383     return nullptr;
384 }
385 
386 void Watchpoint::SendWatchpointChangedEvent(
387     lldb::WatchpointEventType eventKind) {
388   if (!m_being_created &&
389       GetTarget().EventTypeHasListeners(
390           Target::eBroadcastBitWatchpointChanged)) {
391     WatchpointEventData *data =
392         new Watchpoint::WatchpointEventData(eventKind, shared_from_this());
393     GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data);
394   }
395 }
396 
397 void Watchpoint::SendWatchpointChangedEvent(WatchpointEventData *data) {
398   if (data == nullptr)
399     return;
400 
401   if (!m_being_created &&
402       GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
403     GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data);
404   else
405     delete data;
406 }
407 
408 Watchpoint::WatchpointEventData::WatchpointEventData(
409     WatchpointEventType sub_type, const WatchpointSP &new_watchpoint_sp)
410     : m_watchpoint_event(sub_type), m_new_watchpoint_sp(new_watchpoint_sp) {}
411 
412 Watchpoint::WatchpointEventData::~WatchpointEventData() = default;
413 
414 llvm::StringRef Watchpoint::WatchpointEventData::GetFlavorString() {
415   return "Watchpoint::WatchpointEventData";
416 }
417 
418 llvm::StringRef Watchpoint::WatchpointEventData::GetFlavor() const {
419   return WatchpointEventData::GetFlavorString();
420 }
421 
422 WatchpointSP &Watchpoint::WatchpointEventData::GetWatchpoint() {
423   return m_new_watchpoint_sp;
424 }
425 
426 WatchpointEventType
427 Watchpoint::WatchpointEventData::GetWatchpointEventType() const {
428   return m_watchpoint_event;
429 }
430 
431 void Watchpoint::WatchpointEventData::Dump(Stream *s) const {}
432 
433 const Watchpoint::WatchpointEventData *
434 Watchpoint::WatchpointEventData::GetEventDataFromEvent(const Event *event) {
435   if (event) {
436     const EventData *event_data = event->GetData();
437     if (event_data &&
438         event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
439       return static_cast<const WatchpointEventData *>(event->GetData());
440   }
441   return nullptr;
442 }
443 
444 WatchpointEventType
445 Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent(
446     const EventSP &event_sp) {
447   const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
448 
449   if (data == nullptr)
450     return eWatchpointEventTypeInvalidType;
451   else
452     return data->GetWatchpointEventType();
453 }
454 
455 WatchpointSP Watchpoint::WatchpointEventData::GetWatchpointFromEvent(
456     const EventSP &event_sp) {
457   WatchpointSP wp_sp;
458 
459   const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
460   if (data)
461     wp_sp = data->m_new_watchpoint_sp;
462 
463   return wp_sp;
464 }
465