blob: 2012eef8785cd108018926b797f60cdce534ce51 [file] [log] [blame]
Johnny Chen01a67862011-10-14 00:42:25 +00001//===-- Watchpoint.cpp ------------------------------------------*- C++ -*-===//
Chris Lattner30fdc8d2010-06-08 16:52:24 +00002//
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
Johnny Chen01a67862011-10-14 00:42:25 +000010#include "lldb/Breakpoint/Watchpoint.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000011
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
Johnny Chen16dcf712011-10-17 18:58:00 +000016#include "lldb/Breakpoint/StoppointCallbackContext.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017#include "lldb/Core/Stream.h"
Jim Inghama7dfb662012-10-23 07:20:06 +000018#include "lldb/Core/Value.h"
19#include "lldb/Core/ValueObject.h"
20#include "lldb/Core/ValueObjectMemory.h"
21#include "lldb/Symbol/ClangASTContext.h"
Johnny Chen16dcf712011-10-17 18:58:00 +000022#include "lldb/Target/Process.h"
23#include "lldb/Target/Target.h"
24#include "lldb/Target/ThreadSpec.h"
Jim Inghamc7dccb72012-05-02 00:30:53 +000025#include "lldb/Expression/ClangUserExpression.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026
27using namespace lldb;
28using namespace lldb_private;
29
Jim Inghama7dfb662012-10-23 07:20:06 +000030Watchpoint::Watchpoint (Target& target, lldb::addr_t addr, size_t size, const ClangASTType *type, bool hardware) :
Johnny Chena4d6bc92012-02-25 06:44:30 +000031 StoppointLocation (0, addr, size, hardware),
Jim Inghama7dfb662012-10-23 07:20:06 +000032 m_target(target),
Johnny Chena4d6bc92012-02-25 06:44:30 +000033 m_enabled(false),
Johnny Chenf04ee932011-09-22 18:04:58 +000034 m_is_hardware(hardware),
Johnny Chen209bd652012-08-13 21:09:54 +000035 m_is_watch_variable(false),
Johnny Chen4fe23022012-08-21 23:17:04 +000036 m_is_ephemeral(false),
Johnny Chen892943f2012-08-23 22:28:26 +000037 m_disabled_count(0),
Chris Lattner30fdc8d2010-06-08 16:52:24 +000038 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),
Johnny Chen25c0eb42012-08-14 20:56:37 +000043 m_false_alarms(0),
Johnny Chened456eb2011-10-14 19:15:48 +000044 m_decl_str(),
Johnny Chena4d6bc92012-02-25 06:44:30 +000045 m_watch_spec_str(),
Jim Inghama7dfb662012-10-23 07:20:06 +000046 m_type(),
Johnny Chene9a56272012-08-09 23:09:42 +000047 m_error(),
48 m_options ()
Chris Lattner30fdc8d2010-06-08 16:52:24 +000049{
Jim Inghama7dfb662012-10-23 07:20:06 +000050 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, 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 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000067}
68
Johnny Chen01a67862011-10-14 00:42:25 +000069Watchpoint::~Watchpoint()
Chris Lattner30fdc8d2010-06-08 16:52:24 +000070{
71}
72
Johnny Chene9a56272012-08-09 23:09:42 +000073// This function is used when "baton" doesn't need to be freed
74void
75Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000076{
Johnny Chene9a56272012-08-09 23:09:42 +000077 // 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.
86void
87Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
88{
89 m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
90}
91
92void
93Watchpoint::ClearCallback ()
94{
95 m_options.ClearCallback ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +000096}
97
Johnny Chende6bd242011-09-16 21:41:42 +000098void
Johnny Chen209bd652012-08-13 21:09:54 +000099Watchpoint::SetDeclInfo (const std::string &str)
Johnny Chende6bd242011-09-16 21:41:42 +0000100{
101 m_decl_str = str;
102 return;
103}
104
Johnny Chen209bd652012-08-13 21:09:54 +0000105std::string
106Watchpoint::GetWatchSpec()
107{
108 return m_watch_spec_str;
109}
110
Johnny Chena4d6bc92012-02-25 06:44:30 +0000111void
Johnny Chen209bd652012-08-13 21:09:54 +0000112Watchpoint::SetWatchSpec (const std::string &str)
Johnny Chena4d6bc92012-02-25 06:44:30 +0000113{
114 m_watch_spec_str = str;
115 return;
116}
117
Johnny Chenfab7a912012-01-23 23:03:59 +0000118// Override default impl of StoppointLocation::IsHardware() since m_is_hardware
119// member field is more accurate.
Johnny Chenf04ee932011-09-22 18:04:58 +0000120bool
Johnny Chen01a67862011-10-14 00:42:25 +0000121Watchpoint::IsHardware () const
Johnny Chenf04ee932011-09-22 18:04:58 +0000122{
123 return m_is_hardware;
124}
125
Johnny Chen209bd652012-08-13 21:09:54 +0000126bool
127Watchpoint::IsWatchVariable() const
128{
129 return m_is_watch_variable;
130}
131
132void
133Watchpoint::SetWatchVariable(bool val)
134{
135 m_is_watch_variable = val;
136}
137
Jim Inghama7dfb662012-10-23 07:20:06 +0000138bool
139Watchpoint::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 m_new_value_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), watch_name.AsCString(), watch_address, m_type);
145 m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
146 if (m_new_value_sp && m_new_value_sp->GetError().Success())
147 return true;
148 else
149 return false;
150}
151
Johnny Chen25c0eb42012-08-14 20:56:37 +0000152void
153Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
154{
155 ++m_false_alarms;
156 if (m_false_alarms)
157 {
158 if (m_hit_count >= m_false_alarms)
159 {
160 m_hit_count -= m_false_alarms;
161 m_false_alarms = 0;
162 }
163 else
164 {
165 m_false_alarms -= m_hit_count;
166 m_hit_count = 0;
167 }
168 }
169}
170
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000171// RETURNS - true if we should stop at this breakpoint, false if we
172// should continue.
173
174bool
Johnny Chen01a67862011-10-14 00:42:25 +0000175Watchpoint::ShouldStop (StoppointCallbackContext *context)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000176{
Johnny Chenfab7a912012-01-23 23:03:59 +0000177 IncrementHitCount();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000178
Johnny Chenf04ee932011-09-22 18:04:58 +0000179 if (!IsEnabled())
180 return false;
Johnny Chenfd158f42011-09-21 22:47:15 +0000181
Johnny Chenfab7a912012-01-23 23:03:59 +0000182 if (GetHitCount() <= GetIgnoreCount())
Johnny Chenf04ee932011-09-22 18:04:58 +0000183 return false;
184
Johnny Chen16dcf712011-10-17 18:58:00 +0000185 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000186}
187
188void
Johnny Chen01a67862011-10-14 00:42:25 +0000189Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
Johnny Chen887062a2011-09-12 23:38:44 +0000190{
Johnny Chende6bd242011-09-16 21:41:42 +0000191 DumpWithLevel(s, level);
Johnny Chen887062a2011-09-12 23:38:44 +0000192 return;
193}
194
195void
Johnny Chen01a67862011-10-14 00:42:25 +0000196Watchpoint::Dump(Stream *s) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000197{
Johnny Chende6bd242011-09-16 21:41:42 +0000198 DumpWithLevel(s, lldb::eDescriptionLevelBrief);
199}
200
Johnny Chen88fc73b2012-08-13 23:27:50 +0000201// If prefix is NULL, we display the watch id and ignore the prefix altogether.
Johnny Chende6bd242011-09-16 21:41:42 +0000202void
Johnny Chen88fc73b2012-08-13 23:27:50 +0000203Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const
Johnny Chen209bd652012-08-13 21:09:54 +0000204{
Johnny Chen88fc73b2012-08-13 23:27:50 +0000205 if (!prefix)
206 {
207 s->Printf("\nWatchpoint %u hit:", GetID());
208 prefix = "";
209 }
Jim Inghama7dfb662012-10-23 07:20:06 +0000210
211 if (m_old_value_sp)
Johnny Chen209bd652012-08-13 21:09:54 +0000212 {
Jim Inghama7dfb662012-10-23 07:20:06 +0000213 s->Printf("\n%sold value: %s", prefix, m_old_value_sp->GetValueAsCString());
Johnny Chen209bd652012-08-13 21:09:54 +0000214 }
Jim Inghama7dfb662012-10-23 07:20:06 +0000215 if (m_new_value_sp)
Johnny Chen209bd652012-08-13 21:09:54 +0000216 {
Jim Inghama7dfb662012-10-23 07:20:06 +0000217 s->Printf("\n%snew value: %s", prefix, m_new_value_sp->GetValueAsCString());
Johnny Chen209bd652012-08-13 21:09:54 +0000218 }
219}
220
221void
Johnny Chen01a67862011-10-14 00:42:25 +0000222Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const
Johnny Chende6bd242011-09-16 21:41:42 +0000223{
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000224 if (s == NULL)
225 return;
226
Johnny Chende6bd242011-09-16 21:41:42 +0000227 assert(description_level >= lldb::eDescriptionLevelBrief &&
228 description_level <= lldb::eDescriptionLevelVerbose);
229
Greg Claytonc91d8042011-12-03 00:46:21 +0000230 s->Printf("Watchpoint %u: addr = 0x%8.8llx size = %u state = %s type = %s%s",
Johnny Chende6bd242011-09-16 21:41:42 +0000231 GetID(),
Johnny Chena5cde262012-01-24 00:11:02 +0000232 GetLoadAddress(),
Johnny Chende6bd242011-09-16 21:41:42 +0000233 m_byte_size,
Johnny Chena4d6bc92012-02-25 06:44:30 +0000234 IsEnabled() ? "enabled" : "disabled",
Johnny Chende6bd242011-09-16 21:41:42 +0000235 m_watch_read ? "r" : "",
236 m_watch_write ? "w" : "");
237
Johnny Chen16dcf712011-10-17 18:58:00 +0000238 if (description_level >= lldb::eDescriptionLevelFull) {
Johnny Chendedb67a2012-01-30 21:46:17 +0000239 if (!m_decl_str.empty())
Johnny Chen16dcf712011-10-17 18:58:00 +0000240 s->Printf("\n declare @ '%s'", m_decl_str.c_str());
Johnny Chena4d6bc92012-02-25 06:44:30 +0000241 if (!m_watch_spec_str.empty())
Johnny Chen209bd652012-08-13 21:09:54 +0000242 s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str());
243
244 // Dump the snapshots we have taken.
Johnny Chen88fc73b2012-08-13 23:27:50 +0000245 DumpSnapshots(s, " ");
Johnny Chen209bd652012-08-13 21:09:54 +0000246
Johnny Chen16dcf712011-10-17 18:58:00 +0000247 if (GetConditionText())
248 s->Printf("\n condition = '%s'", GetConditionText());
Johnny Chene9a56272012-08-09 23:09:42 +0000249 m_options.GetCallbackDescription(s, description_level);
Johnny Chen16dcf712011-10-17 18:58:00 +0000250 }
Johnny Chende6bd242011-09-16 21:41:42 +0000251
252 if (description_level >= lldb::eDescriptionLevelVerbose)
Jason Molenda7e1f45f2012-02-23 22:32:13 +0000253 {
Johnny Chene9a56272012-08-09 23:09:42 +0000254 s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u",
255 GetHardwareIndex(),
256 GetHitCount(),
257 GetIgnoreCount());
Jason Molenda7e1f45f2012-02-23 22:32:13 +0000258 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000259}
260
261bool
Johnny Chen01a67862011-10-14 00:42:25 +0000262Watchpoint::IsEnabled() const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000263{
264 return m_enabled;
265}
266
Johnny Chen4fe23022012-08-21 23:17:04 +0000267// Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint
268// in order to perform possible watchpoint actions without triggering further watchpoint events.
269// After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode.
270
271void
272Watchpoint::TurnOnEphemeralMode()
273{
274 m_is_ephemeral = true;
275}
276
277void
278Watchpoint::TurnOffEphemeralMode()
279{
280 m_is_ephemeral = false;
Johnny Chen892943f2012-08-23 22:28:26 +0000281 // Leaving ephemeral mode, reset the m_disabled_count!
282 m_disabled_count = 0;
283}
284
285bool
286Watchpoint::IsDisabledDuringEphemeralMode()
287{
288 return m_disabled_count > 1;
Johnny Chen4fe23022012-08-21 23:17:04 +0000289}
290
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000291void
Johnny Chen01a67862011-10-14 00:42:25 +0000292Watchpoint::SetEnabled(bool enabled)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000293{
294 if (!enabled)
Johnny Chen88fc73b2012-08-13 23:27:50 +0000295 {
Johnny Chen4fe23022012-08-21 23:17:04 +0000296 if (!m_is_ephemeral)
297 SetHardwareIndex(LLDB_INVALID_INDEX32);
Johnny Chen892943f2012-08-23 22:28:26 +0000298 else
299 ++m_disabled_count;
300
Johnny Chen0f7ad8d2012-08-21 22:06:34 +0000301 // Don't clear the snapshots for now.
302 // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions.
Johnny Chen88fc73b2012-08-13 23:27:50 +0000303 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000304 m_enabled = enabled;
305}
306
307void
Johnny Chen01a67862011-10-14 00:42:25 +0000308Watchpoint::SetWatchpointType (uint32_t type)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000309{
310 m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
311 m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
312}
313
314bool
Johnny Chen01a67862011-10-14 00:42:25 +0000315Watchpoint::WatchpointRead () const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000316{
317 return m_watch_read != 0;
318}
319bool
Johnny Chen01a67862011-10-14 00:42:25 +0000320Watchpoint::WatchpointWrite () const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000321{
322 return m_watch_write != 0;
323}
Greg Claytonc982c762010-07-09 20:39:50 +0000324uint32_t
Johnny Chen01a67862011-10-14 00:42:25 +0000325Watchpoint::GetIgnoreCount () const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000326{
327 return m_ignore_count;
328}
329
330void
Johnny Chen01a67862011-10-14 00:42:25 +0000331Watchpoint::SetIgnoreCount (uint32_t n)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000332{
333 m_ignore_count = n;
334}
Johnny Chen16dcf712011-10-17 18:58:00 +0000335
336bool
337Watchpoint::InvokeCallback (StoppointCallbackContext *context)
338{
Johnny Chene9a56272012-08-09 23:09:42 +0000339 return m_options.InvokeCallback (context, GetID());
Johnny Chen16dcf712011-10-17 18:58:00 +0000340}
341
342void
343Watchpoint::SetCondition (const char *condition)
344{
345 if (condition == NULL || condition[0] == '\0')
346 {
347 if (m_condition_ap.get())
348 m_condition_ap.reset();
349 }
350 else
351 {
352 // Pass NULL for expr_prefix (no translation-unit level definitions).
Sean Callanan20bb3aa2011-12-21 22:22:58 +0000353 m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
Johnny Chen16dcf712011-10-17 18:58:00 +0000354 }
355}
356
357const char *
358Watchpoint::GetConditionText () const
359{
360 if (m_condition_ap.get())
361 return m_condition_ap->GetUserText();
362 else
363 return NULL;
364}
365