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