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
Watchpoint(Target & target,lldb::addr_t addr,uint32_t size,const CompilerType * type,bool hardware)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_was_read(0), m_watch_was_written(0),
33 m_ignore_count(0), m_false_alarms(0), m_being_created(true) {
34
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.");
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.");
52 }
53 }
54
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);
60 }
61 m_being_created = false;
62 }
63
64 Watchpoint::~Watchpoint() = default;
65
66 // This function is used when "baton" doesn't need to be freed
SetCallback(WatchpointHitCallback callback,void * baton,bool is_synchronous)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 goes out of scope.
71 m_options.SetCallback(callback, std::make_shared<UntypedBaton>(baton),
72 is_synchronous);
73
74 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
75 }
76
77 // This function is used when a baton needs to be freed and therefore is
78 // contained in a "Baton" subclass.
SetCallback(WatchpointHitCallback callback,const BatonSP & callback_baton_sp,bool is_synchronous)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);
84 }
85
ClearCallback()86 void Watchpoint::ClearCallback() {
87 m_options.ClearCallback();
88 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
89 }
90
SetDeclInfo(const std::string & str)91 void Watchpoint::SetDeclInfo(const std::string &str) { m_decl_str = str; }
92
GetWatchSpec()93 std::string Watchpoint::GetWatchSpec() { return m_watch_spec_str; }
94
SetWatchSpec(const std::string & str)95 void Watchpoint::SetWatchSpec(const std::string &str) {
96 m_watch_spec_str = str;
97 }
98
IsHardware() const99 bool Watchpoint::IsHardware() const {
100 lldbassert(m_is_hardware || !HardwareRequired());
101 return m_is_hardware;
102 }
103
IsWatchVariable() const104 bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; }
105
SetWatchVariable(bool val)106 void Watchpoint::SetWatchVariable(bool val) { m_is_watch_variable = val; }
107
CaptureWatchedValue(const ExecutionContext & exe_ctx)108 bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
109 ConstString watch_name("$__lldb__watch_value");
110 m_old_value_sp = m_new_value_sp;
111 Address watch_address(GetLoadAddress());
112 if (!m_type.IsValid()) {
113 // Don't know how to report new & old values, since we couldn't make a
114 // scalar type for this watchpoint. This works around an assert in
115 // ValueObjectMemory::Create.
116 // FIXME: This should not happen, but if it does in some case we care about,
117 // we can go grab the value raw and print it as unsigned.
118 return false;
119 }
120 m_new_value_sp = ValueObjectMemory::Create(
121 exe_ctx.GetBestExecutionContextScope(), watch_name.GetStringRef(),
122 watch_address, m_type);
123 m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
124 return (m_new_value_sp && m_new_value_sp->GetError().Success());
125 }
126
IncrementFalseAlarmsAndReviseHitCount()127 void Watchpoint::IncrementFalseAlarmsAndReviseHitCount() {
128 ++m_false_alarms;
129 if (m_false_alarms) {
130 if (m_hit_counter.GetValue() >= m_false_alarms) {
131 m_hit_counter.Decrement(m_false_alarms);
132 m_false_alarms = 0;
133 } else {
134 m_false_alarms -= m_hit_counter.GetValue();
135 m_hit_counter.Reset();
136 }
137 }
138 }
139
140 // RETURNS - true if we should stop at this breakpoint, false if we
141 // should continue.
142
ShouldStop(StoppointCallbackContext * context)143 bool Watchpoint::ShouldStop(StoppointCallbackContext *context) {
144 m_hit_counter.Increment();
145
146 return IsEnabled();
147 }
148
GetDescription(Stream * s,lldb::DescriptionLevel level)149 void Watchpoint::GetDescription(Stream *s, lldb::DescriptionLevel level) {
150 DumpWithLevel(s, level);
151 }
152
Dump(Stream * s) const153 void Watchpoint::Dump(Stream *s) const {
154 DumpWithLevel(s, lldb::eDescriptionLevelBrief);
155 }
156
157 // If prefix is nullptr, we display the watch id and ignore the prefix
158 // altogether.
DumpSnapshots(Stream * s,const char * prefix) const159 void Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
160 if (!prefix) {
161 s->Printf("\nWatchpoint %u hit:", GetID());
162 prefix = "";
163 }
164
165 if (m_old_value_sp) {
166 const char *old_value_cstr = m_old_value_sp->GetValueAsCString();
167 if (old_value_cstr && old_value_cstr[0])
168 s->Printf("\n%sold value: %s", prefix, old_value_cstr);
169 else {
170 const char *old_summary_cstr = m_old_value_sp->GetSummaryAsCString();
171 if (old_summary_cstr && old_summary_cstr[0])
172 s->Printf("\n%sold value: %s", prefix, old_summary_cstr);
173 }
174 }
175
176 if (m_new_value_sp) {
177 const char *new_value_cstr = m_new_value_sp->GetValueAsCString();
178 if (new_value_cstr && new_value_cstr[0])
179 s->Printf("\n%snew value: %s", prefix, new_value_cstr);
180 else {
181 const char *new_summary_cstr = m_new_value_sp->GetSummaryAsCString();
182 if (new_summary_cstr && new_summary_cstr[0])
183 s->Printf("\n%snew value: %s", prefix, new_summary_cstr);
184 }
185 }
186 }
187
DumpWithLevel(Stream * s,lldb::DescriptionLevel description_level) const188 void Watchpoint::DumpWithLevel(Stream *s,
189 lldb::DescriptionLevel description_level) const {
190 if (s == nullptr)
191 return;
192
193 assert(description_level >= lldb::eDescriptionLevelBrief &&
194 description_level <= lldb::eDescriptionLevelVerbose);
195
196 s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64
197 " size = %u state = %s type = %s%s",
198 GetID(), GetLoadAddress(), m_byte_size,
199 IsEnabled() ? "enabled" : "disabled", m_watch_read ? "r" : "",
200 m_watch_write ? "w" : "");
201
202 if (description_level >= lldb::eDescriptionLevelFull) {
203 if (!m_decl_str.empty())
204 s->Printf("\n declare @ '%s'", m_decl_str.c_str());
205 if (!m_watch_spec_str.empty())
206 s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str());
207
208 // Dump the snapshots we have taken.
209 DumpSnapshots(s, " ");
210
211 if (GetConditionText())
212 s->Printf("\n condition = '%s'", GetConditionText());
213 m_options.GetCallbackDescription(s, description_level);
214 }
215
216 if (description_level >= lldb::eDescriptionLevelVerbose) {
217 s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u",
218 GetHardwareIndex(), GetHitCount(), GetIgnoreCount());
219 }
220 }
221
IsEnabled() const222 bool Watchpoint::IsEnabled() const { return m_enabled; }
223
224 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
225 // temporarily disable the watchpoint in order to perform possible watchpoint
226 // actions without triggering further watchpoint events. After the temporary
227 // disabled watchpoint is enabled, we then turn off the ephemeral mode.
228
TurnOnEphemeralMode()229 void Watchpoint::TurnOnEphemeralMode() { m_is_ephemeral = true; }
230
TurnOffEphemeralMode()231 void Watchpoint::TurnOffEphemeralMode() {
232 m_is_ephemeral = false;
233 // Leaving ephemeral mode, reset the m_disabled_count!
234 m_disabled_count = 0;
235 }
236
IsDisabledDuringEphemeralMode()237 bool Watchpoint::IsDisabledDuringEphemeralMode() {
238 return m_disabled_count > 1 && m_is_ephemeral;
239 }
240
SetEnabled(bool enabled,bool notify)241 void Watchpoint::SetEnabled(bool enabled, bool notify) {
242 if (!enabled) {
243 if (!m_is_ephemeral)
244 SetHardwareIndex(LLDB_INVALID_INDEX32);
245 else
246 ++m_disabled_count;
247
248 // Don't clear the snapshots for now.
249 // Within StopInfo.cpp, we purposely do disable/enable watchpoint while
250 // performing watchpoint actions.
251 }
252 bool changed = enabled != m_enabled;
253 m_enabled = enabled;
254 if (notify && !m_is_ephemeral && changed)
255 SendWatchpointChangedEvent(enabled ? eWatchpointEventTypeEnabled
256 : eWatchpointEventTypeDisabled);
257 }
258
SetWatchpointType(uint32_t type,bool notify)259 void Watchpoint::SetWatchpointType(uint32_t type, bool notify) {
260 int old_watch_read = m_watch_read;
261 int old_watch_write = m_watch_write;
262 m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
263 m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
264 if (notify &&
265 (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
266 SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged);
267 }
268
WatchpointRead() const269 bool Watchpoint::WatchpointRead() const { return m_watch_read != 0; }
270
WatchpointWrite() const271 bool Watchpoint::WatchpointWrite() const { return m_watch_write != 0; }
272
GetIgnoreCount() const273 uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count; }
274
SetIgnoreCount(uint32_t n)275 void Watchpoint::SetIgnoreCount(uint32_t n) {
276 bool changed = m_ignore_count != n;
277 m_ignore_count = n;
278 if (changed)
279 SendWatchpointChangedEvent(eWatchpointEventTypeIgnoreChanged);
280 }
281
InvokeCallback(StoppointCallbackContext * context)282 bool Watchpoint::InvokeCallback(StoppointCallbackContext *context) {
283 return m_options.InvokeCallback(context, GetID());
284 }
285
SetCondition(const char * condition)286 void Watchpoint::SetCondition(const char *condition) {
287 if (condition == nullptr || condition[0] == '\0') {
288 if (m_condition_up)
289 m_condition_up.reset();
290 } else {
291 // Pass nullptr for expr_prefix (no translation-unit level definitions).
292 Status error;
293 m_condition_up.reset(m_target.GetUserExpressionForLanguage(
294 condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
295 UserExpression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
296 error));
297 if (error.Fail()) {
298 // FIXME: Log something...
299 m_condition_up.reset();
300 }
301 }
302 SendWatchpointChangedEvent(eWatchpointEventTypeConditionChanged);
303 }
304
GetConditionText() const305 const char *Watchpoint::GetConditionText() const {
306 if (m_condition_up)
307 return m_condition_up->GetUserText();
308 else
309 return nullptr;
310 }
311
SendWatchpointChangedEvent(lldb::WatchpointEventType eventKind)312 void Watchpoint::SendWatchpointChangedEvent(
313 lldb::WatchpointEventType eventKind) {
314 if (!m_being_created &&
315 GetTarget().EventTypeHasListeners(
316 Target::eBroadcastBitWatchpointChanged)) {
317 WatchpointEventData *data =
318 new Watchpoint::WatchpointEventData(eventKind, shared_from_this());
319 GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data);
320 }
321 }
322
SendWatchpointChangedEvent(WatchpointEventData * data)323 void Watchpoint::SendWatchpointChangedEvent(WatchpointEventData *data) {
324 if (data == nullptr)
325 return;
326
327 if (!m_being_created &&
328 GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
329 GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data);
330 else
331 delete data;
332 }
333
WatchpointEventData(WatchpointEventType sub_type,const WatchpointSP & new_watchpoint_sp)334 Watchpoint::WatchpointEventData::WatchpointEventData(
335 WatchpointEventType sub_type, const WatchpointSP &new_watchpoint_sp)
336 : m_watchpoint_event(sub_type), m_new_watchpoint_sp(new_watchpoint_sp) {}
337
338 Watchpoint::WatchpointEventData::~WatchpointEventData() = default;
339
GetFlavorString()340 ConstString Watchpoint::WatchpointEventData::GetFlavorString() {
341 static ConstString g_flavor("Watchpoint::WatchpointEventData");
342 return g_flavor;
343 }
344
GetFlavor() const345 ConstString Watchpoint::WatchpointEventData::GetFlavor() const {
346 return WatchpointEventData::GetFlavorString();
347 }
348
GetWatchpoint()349 WatchpointSP &Watchpoint::WatchpointEventData::GetWatchpoint() {
350 return m_new_watchpoint_sp;
351 }
352
353 WatchpointEventType
GetWatchpointEventType() const354 Watchpoint::WatchpointEventData::GetWatchpointEventType() const {
355 return m_watchpoint_event;
356 }
357
Dump(Stream * s) const358 void Watchpoint::WatchpointEventData::Dump(Stream *s) const {}
359
360 const Watchpoint::WatchpointEventData *
GetEventDataFromEvent(const Event * event)361 Watchpoint::WatchpointEventData::GetEventDataFromEvent(const Event *event) {
362 if (event) {
363 const EventData *event_data = event->GetData();
364 if (event_data &&
365 event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
366 return static_cast<const WatchpointEventData *>(event->GetData());
367 }
368 return nullptr;
369 }
370
371 WatchpointEventType
GetWatchpointEventTypeFromEvent(const EventSP & event_sp)372 Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent(
373 const EventSP &event_sp) {
374 const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
375
376 if (data == nullptr)
377 return eWatchpointEventTypeInvalidType;
378 else
379 return data->GetWatchpointEventType();
380 }
381
GetWatchpointFromEvent(const EventSP & event_sp)382 WatchpointSP Watchpoint::WatchpointEventData::GetWatchpointFromEvent(
383 const EventSP &event_sp) {
384 WatchpointSP wp_sp;
385
386 const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
387 if (data)
388 wp_sp = data->m_new_watchpoint_sp;
389
390 return wp_sp;
391 }
392