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