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