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