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/Target/Process.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Target/ThreadSpec.h"
21 #include "lldb/Expression/ClangUserExpression.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 Watchpoint::Watchpoint (lldb::addr_t addr, size_t size, bool hardware) :
27     StoppointLocation (0, addr, size, hardware),
28     m_target(NULL),
29     m_enabled(false),
30     m_is_hardware(hardware),
31     m_is_watch_variable(false),
32     m_is_ephemeral(false),
33     m_disabled_count(0),
34     m_watch_read(0),
35     m_watch_write(0),
36     m_watch_was_read(0),
37     m_watch_was_written(0),
38     m_ignore_count(0),
39     m_false_alarms(0),
40     m_decl_str(),
41     m_watch_spec_str(),
42     m_snapshot_old_str(),
43     m_snapshot_new_str(),
44     m_snapshot_old_val(0),
45     m_snapshot_new_val(0),
46     m_error(),
47     m_options ()
48 {
49 }
50 
51 Watchpoint::~Watchpoint()
52 {
53 }
54 
55 // This function is used when "baton" doesn't need to be freed
56 void
57 Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous)
58 {
59     // The default "Baton" class will keep a copy of "baton" and won't free
60     // or delete it when it goes goes out of scope.
61     m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
62 
63     //SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
64 }
65 
66 // This function is used when a baton needs to be freed and therefore is
67 // contained in a "Baton" subclass.
68 void
69 Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
70 {
71     m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
72 }
73 
74 void
75 Watchpoint::ClearCallback ()
76 {
77     m_options.ClearCallback ();
78 }
79 
80 void
81 Watchpoint::SetDeclInfo (const std::string &str)
82 {
83     m_decl_str = str;
84     return;
85 }
86 
87 std::string
88 Watchpoint::GetWatchSpec()
89 {
90     return m_watch_spec_str;
91 }
92 
93 void
94 Watchpoint::SetWatchSpec (const std::string &str)
95 {
96     m_watch_spec_str = str;
97     return;
98 }
99 
100 // Strip at most one character from the end of the string.
101 static inline std::string
102 RStripOnce(const std::string &str, const char c)
103 {
104     std::string res = str;
105     size_t len = res.length();
106     if (len && res.at(len - 1) == '\n')
107         res.resize(len - 1);
108     return res;
109 }
110 
111 std::string
112 Watchpoint::GetOldSnapshot() const
113 {
114     return m_snapshot_old_str;
115 }
116 
117 void
118 Watchpoint::SetOldSnapshot (const std::string &str)
119 {
120     m_snapshot_old_str = RStripOnce(str, '\n');
121 }
122 
123 std::string
124 Watchpoint::GetNewSnapshot() const
125 {
126     return m_snapshot_new_str;
127 }
128 
129 void
130 Watchpoint::SetNewSnapshot (const std::string &str)
131 {
132     m_snapshot_old_str = m_snapshot_new_str;
133     m_snapshot_new_str = RStripOnce(str, '\n');
134 }
135 
136 uint64_t
137 Watchpoint::GetOldSnapshotVal() const
138 {
139     return m_snapshot_old_val;
140 }
141 
142 void
143 Watchpoint::SetOldSnapshotVal (uint64_t val)
144 {
145     m_snapshot_old_val = val;
146     return;
147 }
148 
149 uint64_t
150 Watchpoint::GetNewSnapshotVal() const
151 {
152     return m_snapshot_new_val;
153 }
154 
155 void
156 Watchpoint::SetNewSnapshotVal (uint64_t val)
157 {
158     m_snapshot_old_val = m_snapshot_new_val;
159     m_snapshot_new_val = val;
160     return;
161 }
162 
163 void
164 Watchpoint::ClearSnapshots()
165 {
166     m_snapshot_old_str.clear();
167     m_snapshot_new_str.clear();
168     m_snapshot_old_val = 0;
169     m_snapshot_new_val = 0;
170 }
171 
172 // Override default impl of StoppointLocation::IsHardware() since m_is_hardware
173 // member field is more accurate.
174 bool
175 Watchpoint::IsHardware () const
176 {
177     return m_is_hardware;
178 }
179 
180 bool
181 Watchpoint::IsWatchVariable() const
182 {
183     return m_is_watch_variable;
184 }
185 
186 void
187 Watchpoint::SetWatchVariable(bool val)
188 {
189     m_is_watch_variable = val;
190 }
191 
192 void
193 Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
194 {
195     ++m_false_alarms;
196     if (m_false_alarms)
197     {
198         if (m_hit_count >= m_false_alarms)
199         {
200             m_hit_count -= m_false_alarms;
201             m_false_alarms = 0;
202         }
203         else
204         {
205             m_false_alarms -= m_hit_count;
206             m_hit_count = 0;
207         }
208     }
209 }
210 
211 // RETURNS - true if we should stop at this breakpoint, false if we
212 // should continue.
213 
214 bool
215 Watchpoint::ShouldStop (StoppointCallbackContext *context)
216 {
217     IncrementHitCount();
218 
219     if (!IsEnabled())
220         return false;
221 
222     if (GetHitCount() <= GetIgnoreCount())
223         return false;
224 
225     return true;
226 }
227 
228 void
229 Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
230 {
231     DumpWithLevel(s, level);
232     return;
233 }
234 
235 void
236 Watchpoint::Dump(Stream *s) const
237 {
238     DumpWithLevel(s, lldb::eDescriptionLevelBrief);
239 }
240 
241 // If prefix is NULL, we display the watch id and ignore the prefix altogether.
242 void
243 Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const
244 {
245     if (!prefix)
246     {
247         s->Printf("\nWatchpoint %u hit:", GetID());
248         prefix = "";
249     }
250 
251     if (IsWatchVariable())
252     {
253         if (!m_snapshot_old_str.empty())
254             s->Printf("\n%sold value: %s", prefix, m_snapshot_old_str.c_str());
255         if (!m_snapshot_new_str.empty())
256             s->Printf("\n%snew value: %s", prefix, m_snapshot_new_str.c_str());
257     }
258     else
259     {
260         uint32_t num_hex_digits = GetByteSize() * 2;
261         s->Printf("\n%sold value: 0x%0*.*llx", prefix, num_hex_digits, num_hex_digits, m_snapshot_old_val);
262         s->Printf("\n%snew value: 0x%0*.*llx", prefix, num_hex_digits, num_hex_digits, m_snapshot_new_val);
263     }
264 }
265 
266 void
267 Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const
268 {
269     if (s == NULL)
270         return;
271 
272     assert(description_level >= lldb::eDescriptionLevelBrief &&
273            description_level <= lldb::eDescriptionLevelVerbose);
274 
275     s->Printf("Watchpoint %u: addr = 0x%8.8llx size = %u state = %s type = %s%s",
276               GetID(),
277               GetLoadAddress(),
278               m_byte_size,
279               IsEnabled() ? "enabled" : "disabled",
280               m_watch_read ? "r" : "",
281               m_watch_write ? "w" : "");
282 
283     if (description_level >= lldb::eDescriptionLevelFull) {
284         if (!m_decl_str.empty())
285             s->Printf("\n    declare @ '%s'", m_decl_str.c_str());
286         if (!m_watch_spec_str.empty())
287             s->Printf("\n    watchpoint spec = '%s'", m_watch_spec_str.c_str());
288 
289         // Dump the snapshots we have taken.
290         DumpSnapshots(s, "    ");
291 
292         if (GetConditionText())
293             s->Printf("\n    condition = '%s'", GetConditionText());
294         m_options.GetCallbackDescription(s, description_level);
295     }
296 
297     if (description_level >= lldb::eDescriptionLevelVerbose)
298     {
299         s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
300                   GetHardwareIndex(),
301                   GetHitCount(),
302                   GetIgnoreCount());
303     }
304 }
305 
306 bool
307 Watchpoint::IsEnabled() const
308 {
309     return m_enabled;
310 }
311 
312 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint
313 // in order to perform possible watchpoint actions without triggering further watchpoint events.
314 // After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode.
315 
316 void
317 Watchpoint::TurnOnEphemeralMode()
318 {
319     m_is_ephemeral = true;
320 }
321 
322 void
323 Watchpoint::TurnOffEphemeralMode()
324 {
325     m_is_ephemeral = false;
326     // Leaving ephemeral mode, reset the m_disabled_count!
327     m_disabled_count = 0;
328 }
329 
330 bool
331 Watchpoint::IsDisabledDuringEphemeralMode()
332 {
333     return m_disabled_count > 1;
334 }
335 
336 void
337 Watchpoint::SetEnabled(bool enabled)
338 {
339     if (!enabled)
340     {
341         if (!m_is_ephemeral)
342             SetHardwareIndex(LLDB_INVALID_INDEX32);
343         else
344             ++m_disabled_count;
345 
346         // Don't clear the snapshots for now.
347         // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions.
348         //ClearSnapshots();
349     }
350     m_enabled = enabled;
351 }
352 
353 void
354 Watchpoint::SetWatchpointType (uint32_t type)
355 {
356     m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
357     m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
358 }
359 
360 bool
361 Watchpoint::WatchpointRead () const
362 {
363     return m_watch_read != 0;
364 }
365 bool
366 Watchpoint::WatchpointWrite () const
367 {
368     return m_watch_write != 0;
369 }
370 uint32_t
371 Watchpoint::GetIgnoreCount () const
372 {
373     return m_ignore_count;
374 }
375 
376 void
377 Watchpoint::SetIgnoreCount (uint32_t n)
378 {
379     m_ignore_count = n;
380 }
381 
382 bool
383 Watchpoint::InvokeCallback (StoppointCallbackContext *context)
384 {
385     return m_options.InvokeCallback (context, GetID());
386 }
387 
388 void
389 Watchpoint::SetCondition (const char *condition)
390 {
391     if (condition == NULL || condition[0] == '\0')
392     {
393         if (m_condition_ap.get())
394             m_condition_ap.reset();
395     }
396     else
397     {
398         // Pass NULL for expr_prefix (no translation-unit level definitions).
399         m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
400     }
401 }
402 
403 const char *
404 Watchpoint::GetConditionText () const
405 {
406     if (m_condition_ap.get())
407         return m_condition_ap->GetUserText();
408     else
409         return NULL;
410 }
411 
412