1 //===-- StopInfo.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/Target/StopInfo.h" 11 12 // C Includes 13 // C++ Includes 14 #include <string> 15 16 // Other libraries and framework includes 17 // Project includes 18 #include "lldb/Core/Log.h" 19 #include "lldb/Breakpoint/Breakpoint.h" 20 #include "lldb/Breakpoint/BreakpointLocation.h" 21 #include "lldb/Breakpoint/StoppointCallbackContext.h" 22 #include "lldb/Core/StreamString.h" 23 #include "lldb/Target/Thread.h" 24 #include "lldb/Target/ThreadPlan.h" 25 #include "lldb/Target/Process.h" 26 #include "lldb/Target/UnixSignals.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 StopInfo::StopInfo (Thread &thread, uint64_t value) : 32 m_thread (thread), 33 m_stop_id (thread.GetProcess().GetStopID()), 34 m_value (value) 35 { 36 } 37 38 bool 39 StopInfo::IsValid () const 40 { 41 return m_thread.GetProcess().GetStopID() == m_stop_id; 42 } 43 44 void 45 StopInfo::MakeStopInfoValid () 46 { 47 m_stop_id = m_thread.GetProcess().GetStopID(); 48 } 49 50 //---------------------------------------------------------------------- 51 // StopInfoBreakpoint 52 //---------------------------------------------------------------------- 53 54 class StopInfoBreakpoint : public StopInfo 55 { 56 public: 57 58 StopInfoBreakpoint (Thread &thread, break_id_t break_id) : 59 StopInfo (thread, break_id), 60 m_description(), 61 m_should_stop (false), 62 m_should_stop_is_valid (false), 63 m_should_perform_action (true) 64 { 65 } 66 67 StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) : 68 StopInfo (thread, break_id), 69 m_description(), 70 m_should_stop (should_stop), 71 m_should_stop_is_valid (true), 72 m_should_perform_action (true) 73 { 74 } 75 76 virtual ~StopInfoBreakpoint () 77 { 78 } 79 80 virtual StopReason 81 GetStopReason () const 82 { 83 return eStopReasonBreakpoint; 84 } 85 86 virtual bool 87 ShouldStop (Event *event_ptr) 88 { 89 if (!m_should_stop_is_valid) 90 { 91 // Only check once if we should stop at a breakpoint 92 BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value)); 93 if (bp_site_sp) 94 { 95 StoppointCallbackContext context (event_ptr, 96 &m_thread.GetProcess(), 97 &m_thread, 98 m_thread.GetStackFrameAtIndex(0).get(), 99 true); 100 101 m_should_stop = bp_site_sp->ShouldStop (&context); 102 } 103 else 104 { 105 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); 106 107 if (log) 108 log->Printf ("Process::%s could not find breakpoint site id: %lld...", __FUNCTION__, m_value); 109 110 m_should_stop = true; 111 } 112 m_should_stop_is_valid = true; 113 } 114 return m_should_stop; 115 } 116 117 virtual void 118 PerformAction (Event *event_ptr) 119 { 120 if (!m_should_perform_action) 121 return; 122 m_should_perform_action = false; 123 124 BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value)); 125 if (bp_site_sp) 126 { 127 size_t num_owners = bp_site_sp->GetNumberOfOwners(); 128 for (size_t j = 0; j < num_owners; j++) 129 { 130 // The breakpoint action is an asynchronous breakpoint callback. If we ever need to have both 131 // callbacks and actions on the same breakpoint, we'll have to split this into two. 132 lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j); 133 StoppointCallbackContext context (event_ptr, 134 &m_thread.GetProcess(), 135 &m_thread, 136 m_thread.GetStackFrameAtIndex(0).get(), 137 false); 138 bp_loc_sp->InvokeCallback (&context); 139 } 140 } 141 else 142 { 143 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); 144 145 if (log) 146 log->Printf ("Process::%s could not find breakpoint site id: %lld...", __FUNCTION__, m_value); 147 } 148 } 149 150 virtual bool 151 ShouldNotify (Event *event_ptr) 152 { 153 BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value)); 154 if (bp_site_sp) 155 { 156 bool all_internal = true; 157 158 for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++) 159 { 160 if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) 161 { 162 all_internal = false; 163 break; 164 } 165 } 166 return all_internal == false; 167 } 168 return true; 169 } 170 171 virtual const char * 172 GetDescription () 173 { 174 if (m_description.empty()) 175 { 176 BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value)); 177 if (bp_site_sp) 178 { 179 StreamString strm; 180 strm.Printf("breakpoint "); 181 bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief); 182 m_description.swap (strm.GetString()); 183 } 184 else 185 { 186 StreamString strm; 187 strm.Printf("breakpoint site %lli", m_value); 188 m_description.swap (strm.GetString()); 189 } 190 } 191 return m_description.c_str(); 192 } 193 194 private: 195 std::string m_description; 196 bool m_should_stop; 197 bool m_should_stop_is_valid; 198 bool m_should_perform_action; // Since we are trying to preserve the "state" of the system even if we run functions 199 // etc. behind the users backs, we need to make sure we only REALLY perform the action once. 200 }; 201 202 203 //---------------------------------------------------------------------- 204 // StopInfoWatchpoint 205 //---------------------------------------------------------------------- 206 207 class StopInfoWatchpoint : public StopInfo 208 { 209 public: 210 211 StopInfoWatchpoint (Thread &thread, break_id_t watch_id) : 212 StopInfo (thread, watch_id), 213 m_description() 214 { 215 } 216 217 virtual ~StopInfoWatchpoint () 218 { 219 } 220 221 virtual StopReason 222 GetStopReason () const 223 { 224 return eStopReasonWatchpoint; 225 } 226 227 virtual const char * 228 GetDescription () 229 { 230 if (m_description.empty()) 231 { 232 StreamString strm; 233 strm.Printf("watchpoint %lli", m_value); 234 m_description.swap (strm.GetString()); 235 } 236 return m_description.c_str(); 237 } 238 239 240 241 private: 242 std::string m_description; 243 }; 244 245 246 247 //---------------------------------------------------------------------- 248 // StopInfoUnixSignal 249 //---------------------------------------------------------------------- 250 251 class StopInfoUnixSignal : public StopInfo 252 { 253 public: 254 255 StopInfoUnixSignal (Thread &thread, int signo) : 256 StopInfo (thread, signo) 257 { 258 } 259 260 virtual ~StopInfoUnixSignal () 261 { 262 } 263 264 265 virtual StopReason 266 GetStopReason () const 267 { 268 return eStopReasonSignal; 269 } 270 271 virtual bool 272 ShouldStop (Event *event_ptr) 273 { 274 return m_thread.GetProcess().GetUnixSignals().GetShouldStop (m_value); 275 } 276 277 278 // If should stop returns false, check if we should notify of this event 279 virtual bool 280 ShouldNotify (Event *event_ptr) 281 { 282 return m_thread.GetProcess().GetUnixSignals().GetShouldNotify (m_value); 283 } 284 285 286 virtual void 287 WillResume (lldb::StateType resume_state) 288 { 289 if (m_thread.GetProcess().GetUnixSignals().GetShouldSuppress(m_value) == false) 290 m_thread.SetResumeSignal(m_value); 291 } 292 293 virtual const char * 294 GetDescription () 295 { 296 if (m_description.empty()) 297 { 298 StreamString strm; 299 const char *signal_name = m_thread.GetProcess().GetUnixSignals().GetSignalAsCString (m_value); 300 if (signal_name) 301 strm.Printf("signal %s", signal_name); 302 else 303 strm.Printf("signal %lli", m_value); 304 m_description.swap (strm.GetString()); 305 } 306 return m_description.c_str(); 307 } 308 }; 309 310 //---------------------------------------------------------------------- 311 // StopInfoTrace 312 //---------------------------------------------------------------------- 313 314 class StopInfoTrace : public StopInfo 315 { 316 public: 317 318 StopInfoTrace (Thread &thread) : 319 StopInfo (thread, LLDB_INVALID_UID) 320 { 321 } 322 323 virtual ~StopInfoTrace () 324 { 325 } 326 327 virtual StopReason 328 GetStopReason () const 329 { 330 return eStopReasonTrace; 331 } 332 333 virtual const char * 334 GetDescription () 335 { 336 if (m_description.empty()) 337 return "trace"; 338 else 339 return m_description.c_str(); 340 } 341 }; 342 343 344 //---------------------------------------------------------------------- 345 // StopInfoException 346 //---------------------------------------------------------------------- 347 348 class StopInfoException : public StopInfo 349 { 350 public: 351 352 StopInfoException (Thread &thread, const char *description) : 353 StopInfo (thread, LLDB_INVALID_UID) 354 { 355 if (description) 356 SetDescription (description); 357 } 358 359 virtual 360 ~StopInfoException () 361 { 362 } 363 364 virtual StopReason 365 GetStopReason () const 366 { 367 return eStopReasonException; 368 } 369 370 virtual const char * 371 GetDescription () 372 { 373 if (m_description.empty()) 374 return "exception"; 375 else 376 return m_description.c_str(); 377 } 378 }; 379 380 381 //---------------------------------------------------------------------- 382 // StopInfoThreadPlan 383 //---------------------------------------------------------------------- 384 385 class StopInfoThreadPlan : public StopInfo 386 { 387 public: 388 389 StopInfoThreadPlan (ThreadPlanSP &plan_sp) : 390 StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID), 391 m_plan_sp (plan_sp) 392 { 393 } 394 395 virtual ~StopInfoThreadPlan () 396 { 397 } 398 399 virtual StopReason 400 GetStopReason () const 401 { 402 return eStopReasonPlanComplete; 403 } 404 405 virtual const char * 406 GetDescription () 407 { 408 if (m_description.empty()) 409 { 410 StreamString strm; 411 m_plan_sp->GetDescription (&strm, eDescriptionLevelBrief); 412 m_description.swap (strm.GetString()); 413 } 414 return m_description.c_str(); 415 } 416 417 private: 418 ThreadPlanSP m_plan_sp; 419 }; 420 421 StopInfoSP 422 StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id) 423 { 424 return StopInfoSP (new StopInfoBreakpoint (thread, break_id)); 425 } 426 427 StopInfoSP 428 StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id, bool should_stop) 429 { 430 return StopInfoSP (new StopInfoBreakpoint (thread, break_id, should_stop)); 431 } 432 433 StopInfoSP 434 StopInfo::CreateStopReasonWithWatchpointID (Thread &thread, break_id_t watch_id) 435 { 436 return StopInfoSP (new StopInfoWatchpoint (thread, watch_id)); 437 } 438 439 StopInfoSP 440 StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo) 441 { 442 return StopInfoSP (new StopInfoUnixSignal (thread, signo)); 443 } 444 445 StopInfoSP 446 StopInfo::CreateStopReasonToTrace (Thread &thread) 447 { 448 return StopInfoSP (new StopInfoTrace (thread)); 449 } 450 451 StopInfoSP 452 StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp) 453 { 454 return StopInfoSP (new StopInfoThreadPlan (plan_sp)); 455 } 456 457 StopInfoSP 458 StopInfo::CreateStopReasonWithException (Thread &thread, const char *description) 459 { 460 return StopInfoSP (new StopInfoException (thread, description)); 461 } 462