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, size_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 {
50     if (type && type->IsValid())
51         m_type = *type;
52     else
53     {
54         // If we don't have a known type, then we force it to unsigned int of the right size.
55         ClangASTContext *ast_context = target.GetScratchClangASTContext();
56         clang_type_t clang_type = ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size);
57         m_type.SetClangType(ast_context->getASTContext(), clang_type);
58     }
59 
60     // Set the initial value of the watched variable:
61     if (m_target.GetProcessSP())
62     {
63         ExecutionContext exe_ctx;
64         m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
65         CaptureWatchedValue (exe_ctx);
66     }
67 }
68 
69 Watchpoint::~Watchpoint()
70 {
71 }
72 
73 // This function is used when "baton" doesn't need to be freed
74 void
75 Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous)
76 {
77     // The default "Baton" class will keep a copy of "baton" and won't free
78     // or delete it when it goes goes out of scope.
79     m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
80 
81     //SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
82 }
83 
84 // This function is used when a baton needs to be freed and therefore is
85 // contained in a "Baton" subclass.
86 void
87 Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
88 {
89     m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
90 }
91 
92 void
93 Watchpoint::ClearCallback ()
94 {
95     m_options.ClearCallback ();
96 }
97 
98 void
99 Watchpoint::SetDeclInfo (const std::string &str)
100 {
101     m_decl_str = str;
102     return;
103 }
104 
105 std::string
106 Watchpoint::GetWatchSpec()
107 {
108     return m_watch_spec_str;
109 }
110 
111 void
112 Watchpoint::SetWatchSpec (const std::string &str)
113 {
114     m_watch_spec_str = str;
115     return;
116 }
117 
118 // Override default impl of StoppointLocation::IsHardware() since m_is_hardware
119 // member field is more accurate.
120 bool
121 Watchpoint::IsHardware () const
122 {
123     return m_is_hardware;
124 }
125 
126 bool
127 Watchpoint::IsWatchVariable() const
128 {
129     return m_is_watch_variable;
130 }
131 
132 void
133 Watchpoint::SetWatchVariable(bool val)
134 {
135     m_is_watch_variable = val;
136 }
137 
138 bool
139 Watchpoint::CaptureWatchedValue (const ExecutionContext &exe_ctx)
140 {
141     ConstString watch_name("$__lldb__watch_value");
142     m_old_value_sp = m_new_value_sp;
143     Address watch_address(GetLoadAddress());
144     if (!m_type.IsValid())
145     {
146         // Don't know how to report new & old values, since we couldn't make a scalar type for this watchpoint.
147         // This works around an assert in ValueObjectMemory::Create.
148         // FIXME: This should not happen, but if it does in some case we care about,
149         // we can go grab the value raw and print it as unsigned.
150         return false;
151     }
152     m_new_value_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), watch_name.AsCString(), watch_address, m_type);
153     m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
154     if (m_new_value_sp && m_new_value_sp->GetError().Success())
155         return true;
156     else
157         return false;
158 }
159 
160 void
161 Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
162 {
163     ++m_false_alarms;
164     if (m_false_alarms)
165     {
166         if (m_hit_count >= m_false_alarms)
167         {
168             m_hit_count -= m_false_alarms;
169             m_false_alarms = 0;
170         }
171         else
172         {
173             m_false_alarms -= m_hit_count;
174             m_hit_count = 0;
175         }
176     }
177 }
178 
179 // RETURNS - true if we should stop at this breakpoint, false if we
180 // should continue.
181 
182 bool
183 Watchpoint::ShouldStop (StoppointCallbackContext *context)
184 {
185     IncrementHitCount();
186 
187     if (!IsEnabled())
188         return false;
189 
190     if (GetHitCount() <= GetIgnoreCount())
191         return false;
192 
193     return true;
194 }
195 
196 void
197 Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
198 {
199     DumpWithLevel(s, level);
200     return;
201 }
202 
203 void
204 Watchpoint::Dump(Stream *s) const
205 {
206     DumpWithLevel(s, lldb::eDescriptionLevelBrief);
207 }
208 
209 // If prefix is NULL, we display the watch id and ignore the prefix altogether.
210 void
211 Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const
212 {
213     if (!prefix)
214     {
215         s->Printf("\nWatchpoint %u hit:", GetID());
216         prefix = "";
217     }
218 
219     if (m_old_value_sp)
220     {
221         s->Printf("\n%sold value: %s", prefix, m_old_value_sp->GetValueAsCString());
222     }
223     if (m_new_value_sp)
224     {
225         s->Printf("\n%snew value: %s", prefix, m_new_value_sp->GetValueAsCString());
226     }
227 }
228 
229 void
230 Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const
231 {
232     if (s == NULL)
233         return;
234 
235     assert(description_level >= lldb::eDescriptionLevelBrief &&
236            description_level <= lldb::eDescriptionLevelVerbose);
237 
238     s->Printf("Watchpoint %u: addr = 0x%8.8llx size = %u state = %s type = %s%s",
239               GetID(),
240               GetLoadAddress(),
241               m_byte_size,
242               IsEnabled() ? "enabled" : "disabled",
243               m_watch_read ? "r" : "",
244               m_watch_write ? "w" : "");
245 
246     if (description_level >= lldb::eDescriptionLevelFull) {
247         if (!m_decl_str.empty())
248             s->Printf("\n    declare @ '%s'", m_decl_str.c_str());
249         if (!m_watch_spec_str.empty())
250             s->Printf("\n    watchpoint spec = '%s'", m_watch_spec_str.c_str());
251 
252         // Dump the snapshots we have taken.
253         DumpSnapshots(s, "    ");
254 
255         if (GetConditionText())
256             s->Printf("\n    condition = '%s'", GetConditionText());
257         m_options.GetCallbackDescription(s, description_level);
258     }
259 
260     if (description_level >= lldb::eDescriptionLevelVerbose)
261     {
262         s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
263                   GetHardwareIndex(),
264                   GetHitCount(),
265                   GetIgnoreCount());
266     }
267 }
268 
269 bool
270 Watchpoint::IsEnabled() const
271 {
272     return m_enabled;
273 }
274 
275 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint
276 // in order to perform possible watchpoint actions without triggering further watchpoint events.
277 // After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode.
278 
279 void
280 Watchpoint::TurnOnEphemeralMode()
281 {
282     m_is_ephemeral = true;
283 }
284 
285 void
286 Watchpoint::TurnOffEphemeralMode()
287 {
288     m_is_ephemeral = false;
289     // Leaving ephemeral mode, reset the m_disabled_count!
290     m_disabled_count = 0;
291 }
292 
293 bool
294 Watchpoint::IsDisabledDuringEphemeralMode()
295 {
296     return m_disabled_count > 1;
297 }
298 
299 void
300 Watchpoint::SetEnabled(bool enabled)
301 {
302     if (!enabled)
303     {
304         if (!m_is_ephemeral)
305             SetHardwareIndex(LLDB_INVALID_INDEX32);
306         else
307             ++m_disabled_count;
308 
309         // Don't clear the snapshots for now.
310         // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions.
311     }
312     m_enabled = enabled;
313 }
314 
315 void
316 Watchpoint::SetWatchpointType (uint32_t type)
317 {
318     m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
319     m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
320 }
321 
322 bool
323 Watchpoint::WatchpointRead () const
324 {
325     return m_watch_read != 0;
326 }
327 bool
328 Watchpoint::WatchpointWrite () const
329 {
330     return m_watch_write != 0;
331 }
332 uint32_t
333 Watchpoint::GetIgnoreCount () const
334 {
335     return m_ignore_count;
336 }
337 
338 void
339 Watchpoint::SetIgnoreCount (uint32_t n)
340 {
341     m_ignore_count = n;
342 }
343 
344 bool
345 Watchpoint::InvokeCallback (StoppointCallbackContext *context)
346 {
347     return m_options.InvokeCallback (context, GetID());
348 }
349 
350 void
351 Watchpoint::SetCondition (const char *condition)
352 {
353     if (condition == NULL || condition[0] == '\0')
354     {
355         if (m_condition_ap.get())
356             m_condition_ap.reset();
357     }
358     else
359     {
360         // Pass NULL for expr_prefix (no translation-unit level definitions).
361         m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
362     }
363 }
364 
365 const char *
366 Watchpoint::GetConditionText () const
367 {
368     if (m_condition_ap.get())
369         return m_condition_ap->GetUserText();
370     else
371         return NULL;
372 }
373 
374