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