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/Target/ThreadPlanTestCondition.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 (GetNextID(), addr, size, hardware),
28     m_target(NULL),
29     m_enabled(0),
30     m_is_hardware(hardware),
31     m_watch_read(0),
32     m_watch_write(0),
33     m_watch_was_read(0),
34     m_watch_was_written(0),
35     m_ignore_count(0),
36     m_callback(NULL),
37     m_callback_baton(NULL),
38     m_decl_str(),
39     m_error()
40 {
41 }
42 
43 Watchpoint::~Watchpoint()
44 {
45 }
46 
47 break_id_t
48 Watchpoint::GetNextID()
49 {
50     static break_id_t g_next_ID = 0;
51     return ++g_next_ID;
52 }
53 
54 bool
55 Watchpoint::SetCallback (WatchpointHitCallback callback, void *callback_baton)
56 {
57     m_callback = callback;
58     m_callback_baton = callback_baton;
59     return true;
60 }
61 
62 void
63 Watchpoint::SetDeclInfo (std::string &str)
64 {
65     m_decl_str = str;
66     return;
67 }
68 
69 // Override default impl of StoppointLocation::IsHardware() since m_is_hardware
70 // member field is more accurate.
71 bool
72 Watchpoint::IsHardware () const
73 {
74     return m_is_hardware;
75 }
76 
77 // RETURNS - true if we should stop at this breakpoint, false if we
78 // should continue.
79 
80 bool
81 Watchpoint::ShouldStop (StoppointCallbackContext *context)
82 {
83     IncrementHitCount();
84 
85     if (!IsEnabled())
86         return false;
87 
88     if (GetHitCount() <= GetIgnoreCount())
89         return false;
90 
91     return true;
92 }
93 
94 void
95 Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
96 {
97     DumpWithLevel(s, level);
98     return;
99 }
100 
101 void
102 Watchpoint::Dump(Stream *s) const
103 {
104     DumpWithLevel(s, lldb::eDescriptionLevelBrief);
105 }
106 
107 void
108 Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const
109 {
110     if (s == NULL)
111         return;
112 
113     assert(description_level >= lldb::eDescriptionLevelBrief &&
114            description_level <= lldb::eDescriptionLevelVerbose);
115 
116     s->Printf("Watchpoint %u: addr = 0x%8.8llx size = %u state = %s type = %s%s",
117               GetID(),
118               GetLoadAddress(),
119               m_byte_size,
120               m_enabled ? "enabled" : "disabled",
121               m_watch_read ? "r" : "",
122               m_watch_write ? "w" : "");
123 
124     if (description_level >= lldb::eDescriptionLevelFull) {
125         if (!m_decl_str.empty())
126             s->Printf("\n    declare @ '%s'", m_decl_str.c_str());
127         if (GetConditionText())
128             s->Printf("\n    condition = '%s'", GetConditionText());
129     }
130 
131     if (description_level >= lldb::eDescriptionLevelVerbose)
132         if (m_callback)
133             s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u  callback = %8p baton = %8p",
134                       GetHardwareIndex(),
135                       GetHitCount(),
136                       GetIgnoreCount(),
137                       m_callback,
138                       m_callback_baton);
139         else
140             s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
141                       GetHardwareIndex(),
142                       GetHitCount(),
143                       GetIgnoreCount());
144 }
145 
146 bool
147 Watchpoint::IsEnabled() const
148 {
149     return m_enabled;
150 }
151 
152 void
153 Watchpoint::SetEnabled(bool enabled)
154 {
155     if (!enabled)
156         SetHardwareIndex(LLDB_INVALID_INDEX32);
157     m_enabled = enabled;
158 }
159 
160 void
161 Watchpoint::SetWatchpointType (uint32_t type)
162 {
163     m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
164     m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
165 }
166 
167 bool
168 Watchpoint::WatchpointRead () const
169 {
170     return m_watch_read != 0;
171 }
172 bool
173 Watchpoint::WatchpointWrite () const
174 {
175     return m_watch_write != 0;
176 }
177 uint32_t
178 Watchpoint::GetIgnoreCount () const
179 {
180     return m_ignore_count;
181 }
182 
183 void
184 Watchpoint::SetIgnoreCount (uint32_t n)
185 {
186     m_ignore_count = n;
187 }
188 
189 bool
190 Watchpoint::InvokeCallback (StoppointCallbackContext *context)
191 {
192     if (m_callback && context->is_synchronous)
193     {
194         uint32_t access = 0;
195         if (m_watch_was_read)
196             access |= LLDB_WATCH_TYPE_READ;
197         if (m_watch_was_written)
198             access |= LLDB_WATCH_TYPE_WRITE;
199         return m_callback(m_callback_baton, context, GetID(), access);
200     }
201     else
202         return true;
203 }
204 
205 void
206 Watchpoint::SetCondition (const char *condition)
207 {
208     if (condition == NULL || condition[0] == '\0')
209     {
210         if (m_condition_ap.get())
211             m_condition_ap.reset();
212     }
213     else
214     {
215         // Pass NULL for expr_prefix (no translation-unit level definitions).
216         m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
217     }
218 }
219 
220 const char *
221 Watchpoint::GetConditionText () const
222 {
223     if (m_condition_ap.get())
224         return m_condition_ap->GetUserText();
225     else
226         return NULL;
227 }
228 
229