1 //===-- Watchpoint.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Breakpoint/Watchpoint.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/StoppointCallbackContext.h"
17 #include "lldb/Core/Stream.h"
18 #include "lldb/Core/Value.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectMemory.h"
21 #include "lldb/Symbol/ClangASTContext.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/ThreadSpec.h"
25 #include "lldb/Expression/ClangUserExpression.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 Watchpoint::Watchpoint (Target& target, lldb::addr_t addr, uint32_t size, const ClangASTType *type, bool hardware) :
31     StoppointLocation (0, addr, size, hardware),
32     m_target(target),
33     m_enabled(false),
34     m_is_hardware(hardware),
35     m_is_watch_variable(false),
36     m_is_ephemeral(false),
37     m_disabled_count(0),
38     m_watch_read(0),
39     m_watch_write(0),
40     m_watch_was_read(0),
41     m_watch_was_written(0),
42     m_ignore_count(0),
43     m_false_alarms(0),
44     m_decl_str(),
45     m_watch_spec_str(),
46     m_type(),
47     m_error(),
48     m_options (),
49     m_being_created(true)
50 {
51     if (type && type->IsValid())
52         m_type = *type;
53     else
54     {
55         // If we don't have a known type, then we force it to unsigned int of the right size.
56         ClangASTContext *ast_context = target.GetScratchClangASTContext();
57         clang_type_t clang_type = ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size);
58         m_type.SetClangType(ast_context->getASTContext(), clang_type);
59     }
60 
61     // Set the initial value of the watched variable:
62     if (m_target.GetProcessSP())
63     {
64         ExecutionContext exe_ctx;
65         m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
66         CaptureWatchedValue (exe_ctx);
67     }
68     m_being_created = false;
69 }
70 
71 Watchpoint::~Watchpoint()
72 {
73 }
74 
75 // This function is used when "baton" doesn't need to be freed
76 void
77 Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous)
78 {
79     // The default "Baton" class will keep a copy of "baton" and won't free
80     // or delete it when it goes goes out of scope.
81     m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
82 
83     SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
84 }
85 
86 // This function is used when a baton needs to be freed and therefore is
87 // contained in a "Baton" subclass.
88 void
89 Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
90 {
91     m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
92     SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
93 }
94 
95 void
96 Watchpoint::ClearCallback ()
97 {
98     m_options.ClearCallback ();
99     SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
100 }
101 
102 void
103 Watchpoint::SetDeclInfo (const std::string &str)
104 {
105     m_decl_str = str;
106     return;
107 }
108 
109 std::string
110 Watchpoint::GetWatchSpec()
111 {
112     return m_watch_spec_str;
113 }
114 
115 void
116 Watchpoint::SetWatchSpec (const std::string &str)
117 {
118     m_watch_spec_str = str;
119     return;
120 }
121 
122 // Override default impl of StoppointLocation::IsHardware() since m_is_hardware
123 // member field is more accurate.
124 bool
125 Watchpoint::IsHardware () const
126 {
127     return m_is_hardware;
128 }
129 
130 bool
131 Watchpoint::IsWatchVariable() const
132 {
133     return m_is_watch_variable;
134 }
135 
136 void
137 Watchpoint::SetWatchVariable(bool val)
138 {
139     m_is_watch_variable = val;
140 }
141 
142 bool
143 Watchpoint::CaptureWatchedValue (const ExecutionContext &exe_ctx)
144 {
145     ConstString watch_name("$__lldb__watch_value");
146     m_old_value_sp = m_new_value_sp;
147     Address watch_address(GetLoadAddress());
148     if (!m_type.IsValid())
149     {
150         // Don't know how to report new & old values, since we couldn't make a scalar type for this watchpoint.
151         // This works around an assert in ValueObjectMemory::Create.
152         // FIXME: This should not happen, but if it does in some case we care about,
153         // we can go grab the value raw and print it as unsigned.
154         return false;
155     }
156     m_new_value_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), watch_name.AsCString(), watch_address, m_type);
157     m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
158     if (m_new_value_sp && m_new_value_sp->GetError().Success())
159         return true;
160     else
161         return false;
162 }
163 
164 void
165 Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
166 {
167     ++m_false_alarms;
168     if (m_false_alarms)
169     {
170         if (m_hit_count >= m_false_alarms)
171         {
172             m_hit_count -= m_false_alarms;
173             m_false_alarms = 0;
174         }
175         else
176         {
177             m_false_alarms -= m_hit_count;
178             m_hit_count = 0;
179         }
180     }
181 }
182 
183 // RETURNS - true if we should stop at this breakpoint, false if we
184 // should continue.
185 
186 bool
187 Watchpoint::ShouldStop (StoppointCallbackContext *context)
188 {
189     IncrementHitCount();
190 
191     if (!IsEnabled())
192         return false;
193 
194     if (GetHitCount() <= GetIgnoreCount())
195         return false;
196 
197     return true;
198 }
199 
200 void
201 Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
202 {
203     DumpWithLevel(s, level);
204     return;
205 }
206 
207 void
208 Watchpoint::Dump(Stream *s) const
209 {
210     DumpWithLevel(s, lldb::eDescriptionLevelBrief);
211 }
212 
213 // If prefix is NULL, we display the watch id and ignore the prefix altogether.
214 void
215 Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const
216 {
217     if (!prefix)
218     {
219         s->Printf("\nWatchpoint %u hit:", GetID());
220         prefix = "";
221     }
222 
223     if (m_old_value_sp)
224     {
225         s->Printf("\n%sold value: %s", prefix, m_old_value_sp->GetValueAsCString());
226     }
227     if (m_new_value_sp)
228     {
229         s->Printf("\n%snew value: %s", prefix, m_new_value_sp->GetValueAsCString());
230     }
231 }
232 
233 void
234 Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const
235 {
236     if (s == NULL)
237         return;
238 
239     assert(description_level >= lldb::eDescriptionLevelBrief &&
240            description_level <= lldb::eDescriptionLevelVerbose);
241 
242     s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64 " size = %u state = %s type = %s%s",
243               GetID(),
244               GetLoadAddress(),
245               m_byte_size,
246               IsEnabled() ? "enabled" : "disabled",
247               m_watch_read ? "r" : "",
248               m_watch_write ? "w" : "");
249 
250     if (description_level >= lldb::eDescriptionLevelFull) {
251         if (!m_decl_str.empty())
252             s->Printf("\n    declare @ '%s'", m_decl_str.c_str());
253         if (!m_watch_spec_str.empty())
254             s->Printf("\n    watchpoint spec = '%s'", m_watch_spec_str.c_str());
255 
256         // Dump the snapshots we have taken.
257         DumpSnapshots(s, "    ");
258 
259         if (GetConditionText())
260             s->Printf("\n    condition = '%s'", GetConditionText());
261         m_options.GetCallbackDescription(s, description_level);
262     }
263 
264     if (description_level >= lldb::eDescriptionLevelVerbose)
265     {
266         s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
267                   GetHardwareIndex(),
268                   GetHitCount(),
269                   GetIgnoreCount());
270     }
271 }
272 
273 bool
274 Watchpoint::IsEnabled() const
275 {
276     return m_enabled;
277 }
278 
279 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint
280 // in order to perform possible watchpoint actions without triggering further watchpoint events.
281 // After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode.
282 
283 void
284 Watchpoint::TurnOnEphemeralMode()
285 {
286     m_is_ephemeral = true;
287 }
288 
289 void
290 Watchpoint::TurnOffEphemeralMode()
291 {
292     m_is_ephemeral = false;
293     // Leaving ephemeral mode, reset the m_disabled_count!
294     m_disabled_count = 0;
295 }
296 
297 bool
298 Watchpoint::IsDisabledDuringEphemeralMode()
299 {
300     return m_disabled_count > 1;
301 }
302 
303 void
304 Watchpoint::SetEnabled(bool enabled, bool notify)
305 {
306     if (!enabled)
307     {
308         if (!m_is_ephemeral)
309             SetHardwareIndex(LLDB_INVALID_INDEX32);
310         else
311             ++m_disabled_count;
312 
313         // Don't clear the snapshots for now.
314         // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions.
315     }
316     bool changed = enabled != m_enabled;
317     m_enabled = enabled;
318     if (notify && !m_is_ephemeral && changed)
319         SendWatchpointChangedEvent (enabled ? eWatchpointEventTypeEnabled : eWatchpointEventTypeDisabled);
320 }
321 
322 void
323 Watchpoint::SetWatchpointType (uint32_t type, bool notify)
324 {
325     int old_watch_read = m_watch_read;
326     int old_watch_write = m_watch_write;
327     m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
328     m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
329     if (notify && (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
330         SendWatchpointChangedEvent (eWatchpointEventTypeTypeChanged);
331 }
332 
333 bool
334 Watchpoint::WatchpointRead () const
335 {
336     return m_watch_read != 0;
337 }
338 bool
339 Watchpoint::WatchpointWrite () const
340 {
341     return m_watch_write != 0;
342 }
343 uint32_t
344 Watchpoint::GetIgnoreCount () const
345 {
346     return m_ignore_count;
347 }
348 
349 void
350 Watchpoint::SetIgnoreCount (uint32_t n)
351 {
352     bool changed = m_ignore_count != n;
353     m_ignore_count = n;
354     if (changed)
355         SendWatchpointChangedEvent (eWatchpointEventTypeIgnoreChanged);
356 }
357 
358 bool
359 Watchpoint::InvokeCallback (StoppointCallbackContext *context)
360 {
361     return m_options.InvokeCallback (context, GetID());
362 }
363 
364 void
365 Watchpoint::SetCondition (const char *condition)
366 {
367     if (condition == NULL || condition[0] == '\0')
368     {
369         if (m_condition_ap.get())
370             m_condition_ap.reset();
371     }
372     else
373     {
374         // Pass NULL for expr_prefix (no translation-unit level definitions).
375         m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
376     }
377     SendWatchpointChangedEvent (eWatchpointEventTypeConditionChanged);
378 }
379 
380 const char *
381 Watchpoint::GetConditionText () const
382 {
383     if (m_condition_ap.get())
384         return m_condition_ap->GetUserText();
385     else
386         return NULL;
387 }
388 
389 void
390 Watchpoint::SendWatchpointChangedEvent (lldb::WatchpointEventType eventKind)
391 {
392     if (!m_being_created
393         && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
394     {
395         WatchpointEventData *data = new Watchpoint::WatchpointEventData (eventKind, shared_from_this());
396         GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data);
397     }
398 }
399 
400 void
401 Watchpoint::SendWatchpointChangedEvent (WatchpointEventData *data)
402 {
403 
404     if (data == NULL)
405         return;
406 
407     if (!m_being_created
408         && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
409         GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data);
410     else
411         delete data;
412 }
413 
414 Watchpoint::WatchpointEventData::WatchpointEventData (WatchpointEventType sub_type,
415                                                       const WatchpointSP &new_watchpoint_sp) :
416     EventData (),
417     m_watchpoint_event (sub_type),
418     m_new_watchpoint_sp (new_watchpoint_sp)
419 {
420 }
421 
422 Watchpoint::WatchpointEventData::~WatchpointEventData ()
423 {
424 }
425 
426 const ConstString &
427 Watchpoint::WatchpointEventData::GetFlavorString ()
428 {
429     static ConstString g_flavor ("Watchpoint::WatchpointEventData");
430     return g_flavor;
431 }
432 
433 const ConstString &
434 Watchpoint::WatchpointEventData::GetFlavor () const
435 {
436     return WatchpointEventData::GetFlavorString ();
437 }
438 
439 
440 WatchpointSP &
441 Watchpoint::WatchpointEventData::GetWatchpoint ()
442 {
443     return m_new_watchpoint_sp;
444 }
445 
446 WatchpointEventType
447 Watchpoint::WatchpointEventData::GetWatchpointEventType () const
448 {
449     return m_watchpoint_event;
450 }
451 
452 void
453 Watchpoint::WatchpointEventData::Dump (Stream *s) const
454 {
455 }
456 
457 const Watchpoint::WatchpointEventData *
458 Watchpoint::WatchpointEventData::GetEventDataFromEvent (const Event *event)
459 {
460     if (event)
461     {
462         const EventData *event_data = event->GetData();
463         if (event_data && event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
464             return static_cast <const WatchpointEventData *> (event->GetData());
465     }
466     return NULL;
467 }
468 
469 WatchpointEventType
470 Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent (const EventSP &event_sp)
471 {
472     const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get());
473 
474     if (data == NULL)
475         return eWatchpointEventTypeInvalidType;
476     else
477         return data->GetWatchpointEventType();
478 }
479 
480 WatchpointSP
481 Watchpoint::WatchpointEventData::GetWatchpointFromEvent (const EventSP &event_sp)
482 {
483     WatchpointSP wp_sp;
484 
485     const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get());
486     if (data)
487         wp_sp = data->m_new_watchpoint_sp;
488 
489     return wp_sp;
490 }
491