1 //===-- SBThreadPlan.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SBReproducerPrivate.h" 10 #include "lldb/API/SBThread.h" 11 12 #include "lldb/API/SBFileSpec.h" 13 #include "lldb/API/SBStream.h" 14 #include "lldb/API/SBSymbolContext.h" 15 #include "lldb/Breakpoint/BreakpointLocation.h" 16 #include "lldb/Core/Debugger.h" 17 #include "lldb/Core/StreamFile.h" 18 #include "lldb/Interpreter/CommandInterpreter.h" 19 #include "lldb/Symbol/CompileUnit.h" 20 #include "lldb/Symbol/SymbolContext.h" 21 #include "lldb/Target/Process.h" 22 #include "lldb/Target/Queue.h" 23 #include "lldb/Target/StopInfo.h" 24 #include "lldb/Target/SystemRuntime.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 #include "lldb/Target/ThreadPlan.h" 28 #include "lldb/Target/ThreadPlanPython.h" 29 #include "lldb/Target/ThreadPlanStepInRange.h" 30 #include "lldb/Target/ThreadPlanStepInstruction.h" 31 #include "lldb/Target/ThreadPlanStepOut.h" 32 #include "lldb/Target/ThreadPlanStepRange.h" 33 #include "lldb/Utility/State.h" 34 #include "lldb/Utility/Stream.h" 35 #include "lldb/Utility/StructuredData.h" 36 37 #include "lldb/API/SBAddress.h" 38 #include "lldb/API/SBDebugger.h" 39 #include "lldb/API/SBEvent.h" 40 #include "lldb/API/SBFrame.h" 41 #include "lldb/API/SBProcess.h" 42 #include "lldb/API/SBThreadPlan.h" 43 #include "lldb/API/SBValue.h" 44 45 #include <memory> 46 47 using namespace lldb; 48 using namespace lldb_private; 49 50 //---------------------------------------------------------------------- 51 // Constructors 52 //---------------------------------------------------------------------- 53 SBThreadPlan::SBThreadPlan() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBThreadPlan); } 54 55 SBThreadPlan::SBThreadPlan(const ThreadPlanSP &lldb_object_sp) 56 : m_opaque_sp(lldb_object_sp) { 57 LLDB_RECORD_CONSTRUCTOR(SBThreadPlan, (const lldb::ThreadPlanSP &), 58 lldb_object_sp); 59 } 60 61 SBThreadPlan::SBThreadPlan(const SBThreadPlan &rhs) 62 : m_opaque_sp(rhs.m_opaque_sp) { 63 LLDB_RECORD_CONSTRUCTOR(SBThreadPlan, (const lldb::SBThreadPlan &), rhs); 64 } 65 66 SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name) { 67 LLDB_RECORD_CONSTRUCTOR(SBThreadPlan, (lldb::SBThread &, const char *), 68 sb_thread, class_name); 69 70 Thread *thread = sb_thread.get(); 71 if (thread) 72 m_opaque_sp = std::make_shared<ThreadPlanPython>(*thread, class_name); 73 } 74 75 //---------------------------------------------------------------------- 76 // Assignment operator 77 //---------------------------------------------------------------------- 78 79 const lldb::SBThreadPlan &SBThreadPlan::operator=(const SBThreadPlan &rhs) { 80 LLDB_RECORD_METHOD(const lldb::SBThreadPlan &, 81 SBThreadPlan, operator=,(const lldb::SBThreadPlan &), rhs); 82 83 if (this != &rhs) 84 m_opaque_sp = rhs.m_opaque_sp; 85 return LLDB_RECORD_RESULT(*this); 86 } 87 //---------------------------------------------------------------------- 88 // Destructor 89 //---------------------------------------------------------------------- 90 SBThreadPlan::~SBThreadPlan() {} 91 92 lldb_private::ThreadPlan *SBThreadPlan::get() { return m_opaque_sp.get(); } 93 94 bool SBThreadPlan::IsValid() const { 95 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBThreadPlan, IsValid); 96 return this->operator bool(); 97 } 98 SBThreadPlan::operator bool() const { 99 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBThreadPlan, operator bool); 100 101 return m_opaque_sp.get() != NULL; 102 } 103 104 void SBThreadPlan::Clear() { 105 LLDB_RECORD_METHOD_NO_ARGS(void, SBThreadPlan, Clear); 106 107 m_opaque_sp.reset(); 108 } 109 110 lldb::StopReason SBThreadPlan::GetStopReason() { 111 LLDB_RECORD_METHOD_NO_ARGS(lldb::StopReason, SBThreadPlan, GetStopReason); 112 113 return eStopReasonNone; 114 } 115 116 size_t SBThreadPlan::GetStopReasonDataCount() { 117 LLDB_RECORD_METHOD_NO_ARGS(size_t, SBThreadPlan, GetStopReasonDataCount); 118 119 return 0; 120 } 121 122 uint64_t SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx) { 123 LLDB_RECORD_METHOD(uint64_t, SBThreadPlan, GetStopReasonDataAtIndex, 124 (uint32_t), idx); 125 126 return 0; 127 } 128 129 SBThread SBThreadPlan::GetThread() const { 130 LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::SBThread, SBThreadPlan, GetThread); 131 132 if (m_opaque_sp) { 133 return LLDB_RECORD_RESULT( 134 SBThread(m_opaque_sp->GetThread().shared_from_this())); 135 } else 136 return LLDB_RECORD_RESULT(SBThread()); 137 } 138 139 bool SBThreadPlan::GetDescription(lldb::SBStream &description) const { 140 LLDB_RECORD_METHOD_CONST(bool, SBThreadPlan, GetDescription, 141 (lldb::SBStream &), description); 142 143 if (m_opaque_sp) { 144 m_opaque_sp->GetDescription(description.get(), eDescriptionLevelFull); 145 } else { 146 description.Printf("Empty SBThreadPlan"); 147 } 148 return true; 149 } 150 151 void SBThreadPlan::SetThreadPlan(const ThreadPlanSP &lldb_object_sp) { 152 m_opaque_sp = lldb_object_sp; 153 } 154 155 void SBThreadPlan::SetPlanComplete(bool success) { 156 LLDB_RECORD_METHOD(void, SBThreadPlan, SetPlanComplete, (bool), success); 157 158 if (m_opaque_sp) 159 m_opaque_sp->SetPlanComplete(success); 160 } 161 162 bool SBThreadPlan::IsPlanComplete() { 163 LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, IsPlanComplete); 164 165 if (m_opaque_sp) 166 return m_opaque_sp->IsPlanComplete(); 167 else 168 return true; 169 } 170 171 bool SBThreadPlan::IsPlanStale() { 172 LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, IsPlanStale); 173 174 if (m_opaque_sp) 175 return m_opaque_sp->IsPlanStale(); 176 else 177 return true; 178 } 179 180 bool SBThreadPlan::IsValid() { 181 LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, IsValid); 182 183 if (m_opaque_sp) 184 return m_opaque_sp->ValidatePlan(nullptr); 185 else 186 return false; 187 } 188 189 // This section allows an SBThreadPlan to push another of the common types of 190 // plans... 191 // 192 // FIXME, you should only be able to queue thread plans from inside the methods 193 // of a Scripted Thread Plan. Need a way to enforce that. 194 195 SBThreadPlan 196 SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address, 197 lldb::addr_t size) { 198 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 199 QueueThreadPlanForStepOverRange, 200 (lldb::SBAddress &, lldb::addr_t), sb_start_address, size); 201 202 SBError error; 203 return LLDB_RECORD_RESULT( 204 QueueThreadPlanForStepOverRange(sb_start_address, size, error)); 205 } 206 207 SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOverRange( 208 SBAddress &sb_start_address, lldb::addr_t size, SBError &error) { 209 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 210 QueueThreadPlanForStepOverRange, 211 (lldb::SBAddress &, lldb::addr_t, lldb::SBError &), 212 sb_start_address, size, error); 213 214 if (m_opaque_sp) { 215 Address *start_address = sb_start_address.get(); 216 if (!start_address) { 217 return LLDB_RECORD_RESULT(SBThreadPlan()); 218 } 219 220 AddressRange range(*start_address, size); 221 SymbolContext sc; 222 start_address->CalculateSymbolContext(&sc); 223 Status plan_status; 224 225 SBThreadPlan plan = 226 SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange( 227 false, range, sc, eAllThreads, plan_status)); 228 229 if (plan_status.Fail()) 230 error.SetErrorString(plan_status.AsCString()); 231 232 return LLDB_RECORD_RESULT(plan); 233 } else { 234 return LLDB_RECORD_RESULT(SBThreadPlan()); 235 } 236 } 237 238 SBThreadPlan 239 SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, 240 lldb::addr_t size) { 241 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 242 QueueThreadPlanForStepInRange, 243 (lldb::SBAddress &, lldb::addr_t), sb_start_address, size); 244 245 SBError error; 246 return LLDB_RECORD_RESULT( 247 QueueThreadPlanForStepInRange(sb_start_address, size, error)); 248 } 249 250 SBThreadPlan 251 SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, 252 lldb::addr_t size, SBError &error) { 253 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 254 QueueThreadPlanForStepInRange, 255 (lldb::SBAddress &, lldb::addr_t, lldb::SBError &), 256 sb_start_address, size, error); 257 258 if (m_opaque_sp) { 259 Address *start_address = sb_start_address.get(); 260 if (!start_address) { 261 return LLDB_RECORD_RESULT(SBThreadPlan()); 262 } 263 264 AddressRange range(*start_address, size); 265 SymbolContext sc; 266 start_address->CalculateSymbolContext(&sc); 267 268 Status plan_status; 269 SBThreadPlan plan = 270 SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange( 271 false, range, sc, NULL, eAllThreads, plan_status)); 272 273 if (plan_status.Fail()) 274 error.SetErrorString(plan_status.AsCString()); 275 276 return LLDB_RECORD_RESULT(plan); 277 } else { 278 return LLDB_RECORD_RESULT(SBThreadPlan()); 279 } 280 } 281 282 SBThreadPlan 283 SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, 284 bool first_insn) { 285 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 286 QueueThreadPlanForStepOut, (uint32_t, bool), 287 frame_idx_to_step_to, first_insn); 288 289 SBError error; 290 return LLDB_RECORD_RESULT( 291 QueueThreadPlanForStepOut(frame_idx_to_step_to, first_insn, error)); 292 } 293 294 SBThreadPlan 295 SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, 296 bool first_insn, SBError &error) { 297 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 298 QueueThreadPlanForStepOut, 299 (uint32_t, bool, lldb::SBError &), frame_idx_to_step_to, 300 first_insn, error); 301 302 if (m_opaque_sp) { 303 SymbolContext sc; 304 sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext( 305 lldb::eSymbolContextEverything); 306 307 Status plan_status; 308 SBThreadPlan plan = 309 SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut( 310 false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion, 311 frame_idx_to_step_to, plan_status)); 312 313 if (plan_status.Fail()) 314 error.SetErrorString(plan_status.AsCString()); 315 316 return LLDB_RECORD_RESULT(plan); 317 } else { 318 return LLDB_RECORD_RESULT(SBThreadPlan()); 319 } 320 } 321 322 SBThreadPlan 323 SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) { 324 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 325 QueueThreadPlanForRunToAddress, (lldb::SBAddress), 326 sb_address); 327 328 SBError error; 329 return LLDB_RECORD_RESULT(QueueThreadPlanForRunToAddress(sb_address, error)); 330 } 331 332 SBThreadPlan SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address, 333 SBError &error) { 334 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 335 QueueThreadPlanForRunToAddress, 336 (lldb::SBAddress, lldb::SBError &), sb_address, error); 337 338 if (m_opaque_sp) { 339 Address *address = sb_address.get(); 340 if (!address) 341 return LLDB_RECORD_RESULT(SBThreadPlan()); 342 343 Status plan_status; 344 SBThreadPlan plan = 345 SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress( 346 false, *address, false, plan_status)); 347 348 if (plan_status.Fail()) 349 error.SetErrorString(plan_status.AsCString()); 350 351 return LLDB_RECORD_RESULT(plan); 352 } else { 353 return LLDB_RECORD_RESULT(SBThreadPlan()); 354 } 355 } 356 357 SBThreadPlan 358 SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name) { 359 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 360 QueueThreadPlanForStepScripted, (const char *), 361 script_class_name); 362 363 SBError error; 364 return LLDB_RECORD_RESULT( 365 QueueThreadPlanForStepScripted(script_class_name, error)); 366 } 367 368 SBThreadPlan 369 SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name, 370 SBError &error) { 371 LLDB_RECORD_METHOD(lldb::SBThreadPlan, SBThreadPlan, 372 QueueThreadPlanForStepScripted, 373 (const char *, lldb::SBError &), script_class_name, error); 374 375 if (m_opaque_sp) { 376 Status plan_status; 377 SBThreadPlan plan = 378 SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted( 379 false, script_class_name, false, plan_status)); 380 381 if (plan_status.Fail()) 382 error.SetErrorString(plan_status.AsCString()); 383 384 return LLDB_RECORD_RESULT(plan); 385 } else { 386 return LLDB_RECORD_RESULT(SBThreadPlan()); 387 } 388 } 389 390 namespace lldb_private { 391 namespace repro { 392 393 template <> 394 void RegisterMethods<SBThreadPlan>(Registry &R) { 395 LLDB_REGISTER_CONSTRUCTOR(SBThreadPlan, ()); 396 LLDB_REGISTER_CONSTRUCTOR(SBThreadPlan, (const lldb::ThreadPlanSP &)); 397 LLDB_REGISTER_CONSTRUCTOR(SBThreadPlan, (const lldb::SBThreadPlan &)); 398 LLDB_REGISTER_CONSTRUCTOR(SBThreadPlan, (lldb::SBThread &, const char *)); 399 LLDB_REGISTER_METHOD(const lldb::SBThreadPlan &, 400 SBThreadPlan, operator=,(const lldb::SBThreadPlan &)); 401 LLDB_REGISTER_METHOD_CONST(bool, SBThreadPlan, IsValid, ()); 402 LLDB_REGISTER_METHOD_CONST(bool, SBThreadPlan, operator bool, ()); 403 LLDB_REGISTER_METHOD(void, SBThreadPlan, Clear, ()); 404 LLDB_REGISTER_METHOD(lldb::StopReason, SBThreadPlan, GetStopReason, ()); 405 LLDB_REGISTER_METHOD(size_t, SBThreadPlan, GetStopReasonDataCount, ()); 406 LLDB_REGISTER_METHOD(uint64_t, SBThreadPlan, GetStopReasonDataAtIndex, 407 (uint32_t)); 408 LLDB_REGISTER_METHOD_CONST(lldb::SBThread, SBThreadPlan, GetThread, ()); 409 LLDB_REGISTER_METHOD_CONST(bool, SBThreadPlan, GetDescription, 410 (lldb::SBStream &)); 411 LLDB_REGISTER_METHOD(void, SBThreadPlan, SetPlanComplete, (bool)); 412 LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsPlanComplete, ()); 413 LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsPlanStale, ()); 414 LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsValid, ()); 415 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 416 QueueThreadPlanForStepOverRange, 417 (lldb::SBAddress &, lldb::addr_t)); 418 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 419 QueueThreadPlanForStepOverRange, 420 (lldb::SBAddress &, lldb::addr_t, lldb::SBError &)); 421 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 422 QueueThreadPlanForStepInRange, 423 (lldb::SBAddress &, lldb::addr_t)); 424 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 425 QueueThreadPlanForStepInRange, 426 (lldb::SBAddress &, lldb::addr_t, lldb::SBError &)); 427 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 428 QueueThreadPlanForStepOut, (uint32_t, bool)); 429 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 430 QueueThreadPlanForStepOut, 431 (uint32_t, bool, lldb::SBError &)); 432 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 433 QueueThreadPlanForRunToAddress, (lldb::SBAddress)); 434 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 435 QueueThreadPlanForRunToAddress, 436 (lldb::SBAddress, lldb::SBError &)); 437 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 438 QueueThreadPlanForStepScripted, (const char *)); 439 LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, 440 QueueThreadPlanForStepScripted, 441 (const char *, lldb::SBError &)); 442 } 443 444 } 445 } 446