1 //===-- BreakpointOptions.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/BreakpointOptions.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Core/Stream.h"
17 #include "lldb/Core/StringList.h"
18 #include "lldb/Core/Value.h"
19 #include "lldb/Breakpoint/StoppointCallbackContext.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/ThreadSpec.h"
22 #include "lldb/Target/ThreadPlanTestCondition.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 bool
28 BreakpointOptions::NullCallback (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
29 {
30     return true;
31 }
32 
33 //----------------------------------------------------------------------
34 // BreakpointOptions constructor
35 //----------------------------------------------------------------------
36 BreakpointOptions::BreakpointOptions() :
37     m_callback (BreakpointOptions::NullCallback),
38     m_callback_baton_sp (),
39     m_callback_is_synchronous (false),
40     m_enabled (true),
41     m_ignore_count (0),
42     m_thread_spec_ap (NULL),
43     m_condition_ap()
44 {
45 }
46 
47 //----------------------------------------------------------------------
48 // BreakpointOptions copy constructor
49 //----------------------------------------------------------------------
50 BreakpointOptions::BreakpointOptions(const BreakpointOptions& rhs) :
51     m_callback (rhs.m_callback),
52     m_callback_baton_sp (rhs.m_callback_baton_sp),
53     m_callback_is_synchronous (rhs.m_callback_is_synchronous),
54     m_enabled (rhs.m_enabled),
55     m_ignore_count (rhs.m_ignore_count),
56     m_thread_spec_ap (NULL),
57     m_condition_ap (NULL)
58 {
59     if (rhs.m_thread_spec_ap.get() != NULL)
60         m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
61     if (rhs.m_condition_ap.get())
62         m_condition_ap.reset (new ClangUserExpression (rhs.m_condition_ap->GetUserText()));
63 }
64 
65 //----------------------------------------------------------------------
66 // BreakpointOptions assignment operator
67 //----------------------------------------------------------------------
68 const BreakpointOptions&
69 BreakpointOptions::operator=(const BreakpointOptions& rhs)
70 {
71     m_callback = rhs.m_callback;
72     m_callback_baton_sp = rhs.m_callback_baton_sp;
73     m_callback_is_synchronous = rhs.m_callback_is_synchronous;
74     m_enabled = rhs.m_enabled;
75     m_ignore_count = rhs.m_ignore_count;
76     if (rhs.m_thread_spec_ap.get() != NULL)
77         m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
78     if (rhs.m_condition_ap.get())
79         m_condition_ap.reset (new ClangUserExpression (rhs.m_condition_ap->GetUserText()));
80     return *this;
81 }
82 
83 BreakpointOptions *
84 BreakpointOptions::CopyOptionsNoCallback (BreakpointOptions &orig)
85 {
86     BreakpointHitCallback orig_callback = orig.m_callback;
87     lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
88     bool orig_is_sync = orig.m_callback_is_synchronous;
89 
90     orig.ClearCallback();
91     BreakpointOptions *ret_val = new BreakpointOptions(orig);
92 
93     orig.SetCallback (orig_callback, orig_callback_baton_sp, orig_is_sync);
94 
95     return ret_val;
96 }
97 
98 //----------------------------------------------------------------------
99 // Destructor
100 //----------------------------------------------------------------------
101 BreakpointOptions::~BreakpointOptions()
102 {
103 }
104 
105 //------------------------------------------------------------------
106 // Callbacks
107 //------------------------------------------------------------------
108 void
109 BreakpointOptions::SetCallback (BreakpointHitCallback callback, const BatonSP &callback_baton_sp, bool callback_is_synchronous)
110 {
111     m_callback_is_synchronous = callback_is_synchronous;
112     m_callback = callback;
113     m_callback_baton_sp = callback_baton_sp;
114 }
115 
116 void
117 BreakpointOptions::ClearCallback ()
118 {
119     m_callback = BreakpointOptions::NullCallback;
120     m_callback_is_synchronous = false;
121     m_callback_baton_sp.reset();
122 }
123 
124 Baton *
125 BreakpointOptions::GetBaton ()
126 {
127     return m_callback_baton_sp.get();
128 }
129 
130 const Baton *
131 BreakpointOptions::GetBaton () const
132 {
133     return m_callback_baton_sp.get();
134 }
135 
136 bool
137 BreakpointOptions::InvokeCallback (StoppointCallbackContext *context,
138                                    lldb::user_id_t break_id,
139                                    lldb::user_id_t break_loc_id)
140 {
141     if (m_callback && context->is_synchronous == IsCallbackSynchronous())
142     {
143         return m_callback (m_callback_baton_sp ? m_callback_baton_sp->m_data : NULL,
144                            context,
145                            break_id,
146                            break_loc_id);
147     }
148     else
149         return true;
150 }
151 
152 bool
153 BreakpointOptions::HasCallback ()
154 {
155     return m_callback != BreakpointOptions::NullCallback;
156 }
157 
158 void
159 BreakpointOptions::SetCondition (const char *condition)
160 {
161     if (condition == NULL || condition[0] == '\0')
162     {
163         if (m_condition_ap.get())
164             m_condition_ap.reset();
165     }
166     else
167     {
168         m_condition_ap.reset(new ClangUserExpression (condition));
169     }
170 }
171 
172 ThreadPlan *
173 BreakpointOptions::GetThreadPlanToTestCondition (ExecutionContext &exe_ctx,
174                                                  lldb::BreakpointLocationSP break_loc_sp,
175                                                  Stream &error_stream)
176 {
177     // No condition means we should stop, so return NULL.
178     if (!m_condition_ap.get())
179         return NULL;
180 
181     // FIXME: I shouldn't have to do this, the process should handle it for me:
182     if (!exe_ctx.process->GetDynamicCheckers())
183     {
184         DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions();
185 
186         StreamString install_errors;
187 
188         if (!dynamic_checkers->Install(install_errors, exe_ctx))
189         {
190             error_stream.Printf("Couldn't install dynamic checkers into the execution context: %s\n", install_errors.GetData());
191             return NULL;
192         }
193 
194         exe_ctx.process->SetDynamicCheckers(dynamic_checkers);
195     }
196 
197     if (!m_condition_ap->Parse (error_stream, exe_ctx))
198     {
199         // Errors mean we should stop.
200         return NULL;
201     }
202     // FIXME: When we can execute static expressions without running the target, we should check that here,
203     // and return something to indicate we should stop or just continue.
204 
205     ThreadPlan *new_plan = new ThreadPlanTestCondition (*exe_ctx.thread,
206                                                         exe_ctx,
207                                                         m_condition_ap.get(),
208                                                         break_loc_sp,
209                                                         true);
210 
211     return new_plan;
212 }
213 
214 const char *
215 BreakpointOptions::GetConditionText ()
216 {
217     if (m_condition_ap.get())
218         return m_condition_ap->GetUserText();
219     else
220         return "<No Condition>";
221 }
222 
223 //------------------------------------------------------------------
224 // Enabled/Ignore Count
225 //------------------------------------------------------------------
226 bool
227 BreakpointOptions::IsEnabled () const
228 {
229     return m_enabled;
230 }
231 
232 void
233 BreakpointOptions::SetEnabled (bool enabled)
234 {
235     m_enabled = enabled;
236 }
237 
238 uint32_t
239 BreakpointOptions::GetIgnoreCount () const
240 {
241     return m_ignore_count;
242 }
243 
244 void
245 BreakpointOptions::SetIgnoreCount (uint32_t n)
246 {
247     m_ignore_count = n;
248 }
249 
250 const ThreadSpec *
251 BreakpointOptions::GetThreadSpecNoCreate () const
252 {
253     return m_thread_spec_ap.get();
254 }
255 
256 ThreadSpec *
257 BreakpointOptions::GetThreadSpec ()
258 {
259     if (m_thread_spec_ap.get() == NULL)
260         m_thread_spec_ap.reset (new ThreadSpec());
261 
262     return m_thread_spec_ap.get();
263 }
264 
265 void
266 BreakpointOptions::SetThreadID (lldb::tid_t thread_id)
267 {
268     GetThreadSpec()->SetTID(thread_id);
269 }
270 
271 void
272 BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) const
273 {
274 
275     // Figure out if there are any options not at their default value, and only print
276     // anything if there are:
277 
278     if (m_ignore_count != 0 || !m_enabled || (GetThreadSpecNoCreate() != NULL && GetThreadSpecNoCreate()->HasSpecification ()))
279     {
280         if (level == lldb::eDescriptionLevelVerbose)
281         {
282             s->EOL ();
283             s->IndentMore();
284             s->Indent();
285             s->PutCString("Breakpoint Options:\n");
286             s->IndentMore();
287             s->Indent();
288         }
289         else
290             s->PutCString(" Options: ");
291 
292         if (m_ignore_count > 0)
293             s->Printf("ignore: %d ", m_ignore_count);
294         s->Printf("%sabled ", m_enabled ? "en" : "dis");
295 
296         if (m_thread_spec_ap.get())
297             m_thread_spec_ap->GetDescription (s, level);
298         else if (level == eDescriptionLevelBrief)
299             s->PutCString ("thread spec: no ");
300         if (level == lldb::eDescriptionLevelFull)
301         {
302             s->IndentLess();
303             s->IndentMore();
304         }
305     }
306 
307     if (m_callback_baton_sp.get())
308     {
309         if (level != eDescriptionLevelBrief)
310             s->EOL();
311         m_callback_baton_sp->GetDescription (s, level);
312     }
313     if (m_condition_ap.get())
314     {
315        if (level != eDescriptionLevelBrief)
316        {
317             s->EOL();
318             s->Printf("Condition: %s\n", m_condition_ap->GetUserText());
319         }
320     }
321 }
322 
323 void
324 BreakpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
325 {
326     CommandData *data = (CommandData *)m_data;
327 
328     if (level == eDescriptionLevelBrief)
329     {
330         s->Printf (", commands = %s", (data && data->user_source.GetSize() > 0) ? "yes" : "no");
331         return;
332     }
333 
334     s->IndentMore ();
335     s->Indent("Breakpoint commands:\n");
336 
337     s->IndentMore ();
338     if (data && data->user_source.GetSize() > 0)
339     {
340         const size_t num_strings = data->user_source.GetSize();
341         for (size_t i = 0; i < num_strings; ++i)
342         {
343             s->Indent(data->user_source.GetStringAtIndex(i));
344             s->EOL();
345         }
346     }
347     else
348     {
349         s->PutCString ("No commands.\n");
350     }
351     s->IndentLess ();
352     s->IndentLess ();
353 }
354 
355