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 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "lldb/Breakpoint/BreakpointOptions.h"
15 
16 #include "lldb/Breakpoint/StoppointCallbackContext.h"
17 #include "lldb/Core/Stream.h"
18 #include "lldb/Core/StringList.h"
19 #include "lldb/Core/Value.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Target/ThreadSpec.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 bool BreakpointOptions::NullCallback(void *baton,
28                                      StoppointCallbackContext *context,
29                                      lldb::user_id_t break_id,
30                                      lldb::user_id_t break_loc_id) {
31   return true;
32 }
33 
34 //----------------------------------------------------------------------
35 // BreakpointOptions constructor
36 //----------------------------------------------------------------------
37 BreakpointOptions::BreakpointOptions()
38     : m_callback(BreakpointOptions::NullCallback), m_callback_baton_sp(),
39       m_callback_is_synchronous(false), m_enabled(true), m_one_shot(false),
40       m_ignore_count(0), m_thread_spec_ap(), m_condition_text(),
41       m_condition_text_hash(0) {}
42 
43 //----------------------------------------------------------------------
44 // BreakpointOptions copy constructor
45 //----------------------------------------------------------------------
46 BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
47     : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
48       m_callback_is_synchronous(rhs.m_callback_is_synchronous),
49       m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
50       m_ignore_count(rhs.m_ignore_count), m_thread_spec_ap() {
51   if (rhs.m_thread_spec_ap.get() != nullptr)
52     m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
53   m_condition_text = rhs.m_condition_text;
54   m_condition_text_hash = rhs.m_condition_text_hash;
55 }
56 
57 //----------------------------------------------------------------------
58 // BreakpointOptions assignment operator
59 //----------------------------------------------------------------------
60 const BreakpointOptions &BreakpointOptions::
61 operator=(const BreakpointOptions &rhs) {
62   m_callback = rhs.m_callback;
63   m_callback_baton_sp = rhs.m_callback_baton_sp;
64   m_callback_is_synchronous = rhs.m_callback_is_synchronous;
65   m_enabled = rhs.m_enabled;
66   m_one_shot = rhs.m_one_shot;
67   m_ignore_count = rhs.m_ignore_count;
68   if (rhs.m_thread_spec_ap.get() != nullptr)
69     m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
70   m_condition_text = rhs.m_condition_text;
71   m_condition_text_hash = rhs.m_condition_text_hash;
72   return *this;
73 }
74 
75 BreakpointOptions *
76 BreakpointOptions::CopyOptionsNoCallback(BreakpointOptions &orig) {
77   BreakpointHitCallback orig_callback = orig.m_callback;
78   lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
79   bool orig_is_sync = orig.m_callback_is_synchronous;
80 
81   orig.ClearCallback();
82   BreakpointOptions *ret_val = new BreakpointOptions(orig);
83 
84   orig.SetCallback(orig_callback, orig_callback_baton_sp, orig_is_sync);
85 
86   return ret_val;
87 }
88 
89 //----------------------------------------------------------------------
90 // Destructor
91 //----------------------------------------------------------------------
92 BreakpointOptions::~BreakpointOptions() = default;
93 
94 //------------------------------------------------------------------
95 // Callbacks
96 //------------------------------------------------------------------
97 void BreakpointOptions::SetCallback(BreakpointHitCallback callback,
98                                     const BatonSP &callback_baton_sp,
99                                     bool callback_is_synchronous) {
100   m_callback_is_synchronous = callback_is_synchronous;
101   m_callback = callback;
102   m_callback_baton_sp = callback_baton_sp;
103 }
104 
105 void BreakpointOptions::ClearCallback() {
106   m_callback = BreakpointOptions::NullCallback;
107   m_callback_is_synchronous = false;
108   m_callback_baton_sp.reset();
109 }
110 
111 Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
112 
113 const Baton *BreakpointOptions::GetBaton() const {
114   return m_callback_baton_sp.get();
115 }
116 
117 bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context,
118                                        lldb::user_id_t break_id,
119                                        lldb::user_id_t break_loc_id) {
120   if (m_callback && context->is_synchronous == IsCallbackSynchronous()) {
121     return m_callback(m_callback_baton_sp ? m_callback_baton_sp->m_data
122                                           : nullptr,
123                       context, break_id, break_loc_id);
124   } else
125     return true;
126 }
127 
128 bool BreakpointOptions::HasCallback() const {
129   return m_callback != BreakpointOptions::NullCallback;
130 }
131 
132 void BreakpointOptions::SetCondition(const char *condition) {
133   if (!condition)
134     condition = "";
135 
136   m_condition_text.assign(condition);
137   std::hash<std::string> hasher;
138   m_condition_text_hash = hasher(m_condition_text);
139 }
140 
141 const char *BreakpointOptions::GetConditionText(size_t *hash) const {
142   if (!m_condition_text.empty()) {
143     if (hash)
144       *hash = m_condition_text_hash;
145 
146     return m_condition_text.c_str();
147   } else {
148     return nullptr;
149   }
150 }
151 
152 const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
153   return m_thread_spec_ap.get();
154 }
155 
156 ThreadSpec *BreakpointOptions::GetThreadSpec() {
157   if (m_thread_spec_ap.get() == nullptr)
158     m_thread_spec_ap.reset(new ThreadSpec());
159 
160   return m_thread_spec_ap.get();
161 }
162 
163 void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
164   GetThreadSpec()->SetTID(thread_id);
165 }
166 
167 void BreakpointOptions::GetDescription(Stream *s,
168                                        lldb::DescriptionLevel level) const {
169   // Figure out if there are any options not at their default value, and only
170   // print
171   // anything if there are:
172 
173   if (m_ignore_count != 0 || !m_enabled || m_one_shot ||
174       (GetThreadSpecNoCreate() != nullptr &&
175        GetThreadSpecNoCreate()->HasSpecification())) {
176     if (level == lldb::eDescriptionLevelVerbose) {
177       s->EOL();
178       s->IndentMore();
179       s->Indent();
180       s->PutCString("Breakpoint Options:\n");
181       s->IndentMore();
182       s->Indent();
183     } else
184       s->PutCString(" Options: ");
185 
186     if (m_ignore_count > 0)
187       s->Printf("ignore: %d ", m_ignore_count);
188     s->Printf("%sabled ", m_enabled ? "en" : "dis");
189 
190     if (m_one_shot)
191       s->Printf("one-shot ");
192 
193     if (m_thread_spec_ap.get())
194       m_thread_spec_ap->GetDescription(s, level);
195 
196     if (level == lldb::eDescriptionLevelFull) {
197       s->IndentLess();
198       s->IndentMore();
199     }
200   }
201 
202   if (m_callback_baton_sp.get()) {
203     if (level != eDescriptionLevelBrief) {
204       s->EOL();
205       m_callback_baton_sp->GetDescription(s, level);
206     }
207   }
208   if (!m_condition_text.empty()) {
209     if (level != eDescriptionLevelBrief) {
210       s->EOL();
211       s->Printf("Condition: %s\n", m_condition_text.c_str());
212     }
213   }
214 }
215 
216 void BreakpointOptions::CommandBaton::GetDescription(
217     Stream *s, lldb::DescriptionLevel level) const {
218   CommandData *data = (CommandData *)m_data;
219 
220   if (level == eDescriptionLevelBrief) {
221     s->Printf(", commands = %s",
222               (data && data->user_source.GetSize() > 0) ? "yes" : "no");
223     return;
224   }
225 
226   s->IndentMore();
227   s->Indent("Breakpoint commands:\n");
228 
229   s->IndentMore();
230   if (data && data->user_source.GetSize() > 0) {
231     const size_t num_strings = data->user_source.GetSize();
232     for (size_t i = 0; i < num_strings; ++i) {
233       s->Indent(data->user_source.GetStringAtIndex(i));
234       s->EOL();
235     }
236   } else {
237     s->PutCString("No commands.\n");
238   }
239   s->IndentLess();
240   s->IndentLess();
241 }
242