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