1 | //===-- SBThread.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 "Utils.h" |
11 | #include "lldb/API/SBAddress.h" |
12 | #include "lldb/API/SBDebugger.h" |
13 | #include "lldb/API/SBEvent.h" |
14 | #include "lldb/API/SBFileSpec.h" |
15 | #include "lldb/API/SBFormat.h" |
16 | #include "lldb/API/SBFrame.h" |
17 | #include "lldb/API/SBProcess.h" |
18 | #include "lldb/API/SBStream.h" |
19 | #include "lldb/API/SBStructuredData.h" |
20 | #include "lldb/API/SBSymbolContext.h" |
21 | #include "lldb/API/SBThreadCollection.h" |
22 | #include "lldb/API/SBThreadPlan.h" |
23 | #include "lldb/API/SBValue.h" |
24 | #include "lldb/Breakpoint/BreakpointLocation.h" |
25 | #include "lldb/Core/Debugger.h" |
26 | #include "lldb/Core/StructuredDataImpl.h" |
27 | #include "lldb/Interpreter/CommandInterpreter.h" |
28 | #include "lldb/Symbol/CompileUnit.h" |
29 | #include "lldb/Symbol/SymbolContext.h" |
30 | #include "lldb/Target/Process.h" |
31 | #include "lldb/Target/Queue.h" |
32 | #include "lldb/Target/StopInfo.h" |
33 | #include "lldb/Target/SystemRuntime.h" |
34 | #include "lldb/Target/Target.h" |
35 | #include "lldb/Target/Thread.h" |
36 | #include "lldb/Target/ThreadPlan.h" |
37 | #include "lldb/Target/ThreadPlanStepInRange.h" |
38 | #include "lldb/Target/ThreadPlanStepInstruction.h" |
39 | #include "lldb/Target/ThreadPlanStepOut.h" |
40 | #include "lldb/Target/ThreadPlanStepRange.h" |
41 | #include "lldb/Utility/Instrumentation.h" |
42 | #include "lldb/Utility/State.h" |
43 | #include "lldb/Utility/Stream.h" |
44 | #include "lldb/Utility/StructuredData.h" |
45 | #include "lldb/ValueObject/ValueObject.h" |
46 | #include "lldb/lldb-enumerations.h" |
47 | |
48 | #include <memory> |
49 | |
50 | using namespace lldb; |
51 | using namespace lldb_private; |
52 | |
53 | const char *SBThread::GetBroadcasterClassName() { |
54 | LLDB_INSTRUMENT(); |
55 | |
56 | return ConstString(Thread::GetStaticBroadcasterClass()).AsCString(); |
57 | } |
58 | |
59 | // Constructors |
60 | SBThread::SBThread() : m_opaque_sp(new ExecutionContextRef()) { |
61 | LLDB_INSTRUMENT_VA(this); |
62 | } |
63 | |
64 | SBThread::SBThread(const ThreadSP &lldb_object_sp) |
65 | : m_opaque_sp(new ExecutionContextRef(lldb_object_sp)) { |
66 | LLDB_INSTRUMENT_VA(this, lldb_object_sp); |
67 | } |
68 | |
69 | SBThread::SBThread(const SBThread &rhs) { |
70 | LLDB_INSTRUMENT_VA(this, rhs); |
71 | |
72 | m_opaque_sp = clone(src: rhs.m_opaque_sp); |
73 | } |
74 | |
75 | // Assignment operator |
76 | |
77 | const lldb::SBThread &SBThread::operator=(const SBThread &rhs) { |
78 | LLDB_INSTRUMENT_VA(this, rhs); |
79 | |
80 | if (this != &rhs) |
81 | m_opaque_sp = clone(src: rhs.m_opaque_sp); |
82 | return *this; |
83 | } |
84 | |
85 | // Destructor |
86 | SBThread::~SBThread() = default; |
87 | |
88 | lldb::SBQueue SBThread::GetQueue() const { |
89 | LLDB_INSTRUMENT_VA(this); |
90 | |
91 | SBQueue sb_queue; |
92 | QueueSP queue_sp; |
93 | std::unique_lock<std::recursive_mutex> lock; |
94 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
95 | |
96 | if (exe_ctx.HasThreadScope()) { |
97 | Process::StopLocker stop_locker; |
98 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
99 | queue_sp = exe_ctx.GetThreadPtr()->GetQueue(); |
100 | if (queue_sp) { |
101 | sb_queue.SetQueue(queue_sp); |
102 | } |
103 | } |
104 | } |
105 | |
106 | return sb_queue; |
107 | } |
108 | |
109 | bool SBThread::IsValid() const { |
110 | LLDB_INSTRUMENT_VA(this); |
111 | return this->operator bool(); |
112 | } |
113 | SBThread::operator bool() const { |
114 | LLDB_INSTRUMENT_VA(this); |
115 | |
116 | std::unique_lock<std::recursive_mutex> lock; |
117 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
118 | |
119 | Target *target = exe_ctx.GetTargetPtr(); |
120 | Process *process = exe_ctx.GetProcessPtr(); |
121 | if (target && process) { |
122 | Process::StopLocker stop_locker; |
123 | if (stop_locker.TryLock(lock: &process->GetRunLock())) |
124 | return m_opaque_sp->GetThreadSP().get() != nullptr; |
125 | } |
126 | // Without a valid target & process, this thread can't be valid. |
127 | return false; |
128 | } |
129 | |
130 | void SBThread::Clear() { |
131 | LLDB_INSTRUMENT_VA(this); |
132 | |
133 | m_opaque_sp->Clear(); |
134 | } |
135 | |
136 | StopReason SBThread::GetStopReason() { |
137 | LLDB_INSTRUMENT_VA(this); |
138 | |
139 | StopReason reason = eStopReasonInvalid; |
140 | std::unique_lock<std::recursive_mutex> lock; |
141 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
142 | |
143 | if (exe_ctx.HasThreadScope()) { |
144 | Process::StopLocker stop_locker; |
145 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
146 | return exe_ctx.GetThreadPtr()->GetStopReason(); |
147 | } |
148 | } |
149 | |
150 | return reason; |
151 | } |
152 | |
153 | size_t SBThread::GetStopReasonDataCount() { |
154 | LLDB_INSTRUMENT_VA(this); |
155 | |
156 | std::unique_lock<std::recursive_mutex> lock; |
157 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
158 | |
159 | if (exe_ctx.HasThreadScope()) { |
160 | Process::StopLocker stop_locker; |
161 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
162 | StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo(); |
163 | if (stop_info_sp) { |
164 | StopReason reason = stop_info_sp->GetStopReason(); |
165 | switch (reason) { |
166 | case eStopReasonInvalid: |
167 | case eStopReasonNone: |
168 | case eStopReasonTrace: |
169 | case eStopReasonExec: |
170 | case eStopReasonPlanComplete: |
171 | case eStopReasonThreadExiting: |
172 | case eStopReasonInstrumentation: |
173 | case eStopReasonProcessorTrace: |
174 | case eStopReasonVForkDone: |
175 | case eStopReasonHistoryBoundary: |
176 | // There is no data for these stop reasons. |
177 | return 0; |
178 | |
179 | case eStopReasonBreakpoint: { |
180 | break_id_t site_id = stop_info_sp->GetValue(); |
181 | lldb::BreakpointSiteSP bp_site_sp( |
182 | exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID( |
183 | site_id)); |
184 | if (bp_site_sp) |
185 | return bp_site_sp->GetNumberOfConstituents() * 2; |
186 | else |
187 | return 0; // Breakpoint must have cleared itself... |
188 | } break; |
189 | |
190 | case eStopReasonWatchpoint: |
191 | return 1; |
192 | |
193 | case eStopReasonSignal: |
194 | return 1; |
195 | |
196 | case eStopReasonInterrupt: |
197 | return 1; |
198 | |
199 | case eStopReasonException: |
200 | return 1; |
201 | |
202 | case eStopReasonFork: |
203 | return 1; |
204 | |
205 | case eStopReasonVFork: |
206 | return 1; |
207 | } |
208 | } |
209 | } |
210 | } |
211 | return 0; |
212 | } |
213 | |
214 | uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) { |
215 | LLDB_INSTRUMENT_VA(this, idx); |
216 | |
217 | std::unique_lock<std::recursive_mutex> lock; |
218 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
219 | |
220 | if (exe_ctx.HasThreadScope()) { |
221 | Process::StopLocker stop_locker; |
222 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
223 | Thread *thread = exe_ctx.GetThreadPtr(); |
224 | StopInfoSP stop_info_sp = thread->GetStopInfo(); |
225 | if (stop_info_sp) { |
226 | StopReason reason = stop_info_sp->GetStopReason(); |
227 | switch (reason) { |
228 | case eStopReasonInvalid: |
229 | case eStopReasonNone: |
230 | case eStopReasonTrace: |
231 | case eStopReasonExec: |
232 | case eStopReasonPlanComplete: |
233 | case eStopReasonThreadExiting: |
234 | case eStopReasonInstrumentation: |
235 | case eStopReasonProcessorTrace: |
236 | case eStopReasonVForkDone: |
237 | case eStopReasonHistoryBoundary: |
238 | // There is no data for these stop reasons. |
239 | return 0; |
240 | |
241 | case eStopReasonBreakpoint: { |
242 | break_id_t site_id = stop_info_sp->GetValue(); |
243 | lldb::BreakpointSiteSP bp_site_sp( |
244 | exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID( |
245 | site_id)); |
246 | if (bp_site_sp) { |
247 | uint32_t bp_index = idx / 2; |
248 | BreakpointLocationSP bp_loc_sp( |
249 | bp_site_sp->GetConstituentAtIndex(idx: bp_index)); |
250 | if (bp_loc_sp) { |
251 | if (idx & 1) { |
252 | // Odd idx, return the breakpoint location ID |
253 | return bp_loc_sp->GetID(); |
254 | } else { |
255 | // Even idx, return the breakpoint ID |
256 | return bp_loc_sp->GetBreakpoint().GetID(); |
257 | } |
258 | } |
259 | } |
260 | return LLDB_INVALID_BREAK_ID; |
261 | } break; |
262 | |
263 | case eStopReasonWatchpoint: |
264 | return stop_info_sp->GetValue(); |
265 | |
266 | case eStopReasonSignal: |
267 | return stop_info_sp->GetValue(); |
268 | |
269 | case eStopReasonInterrupt: |
270 | return stop_info_sp->GetValue(); |
271 | |
272 | case eStopReasonException: |
273 | return stop_info_sp->GetValue(); |
274 | |
275 | case eStopReasonFork: |
276 | return stop_info_sp->GetValue(); |
277 | |
278 | case eStopReasonVFork: |
279 | return stop_info_sp->GetValue(); |
280 | } |
281 | } |
282 | } |
283 | } |
284 | return 0; |
285 | } |
286 | |
287 | bool SBThread::GetStopReasonExtendedInfoAsJSON(lldb::SBStream &stream) { |
288 | LLDB_INSTRUMENT_VA(this, stream); |
289 | |
290 | Stream &strm = stream.ref(); |
291 | |
292 | std::unique_lock<std::recursive_mutex> lock; |
293 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
294 | |
295 | if (!exe_ctx.HasThreadScope()) |
296 | return false; |
297 | |
298 | StopInfoSP stop_info = exe_ctx.GetThreadPtr()->GetStopInfo(); |
299 | StructuredData::ObjectSP info = stop_info->GetExtendedInfo(); |
300 | if (!info) |
301 | return false; |
302 | |
303 | info->Dump(s&: strm); |
304 | |
305 | return true; |
306 | } |
307 | |
308 | SBThreadCollection |
309 | SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) { |
310 | LLDB_INSTRUMENT_VA(this, type); |
311 | |
312 | SBThreadCollection threads; |
313 | |
314 | std::unique_lock<std::recursive_mutex> lock; |
315 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
316 | |
317 | if (!exe_ctx.HasThreadScope()) |
318 | return SBThreadCollection(); |
319 | |
320 | ProcessSP process_sp = exe_ctx.GetProcessSP(); |
321 | |
322 | StopInfoSP stop_info = exe_ctx.GetThreadPtr()->GetStopInfo(); |
323 | StructuredData::ObjectSP info = stop_info->GetExtendedInfo(); |
324 | if (!info) |
325 | return threads; |
326 | |
327 | threads = process_sp->GetInstrumentationRuntime(type) |
328 | ->GetBacktracesFromExtendedStopInfo(info); |
329 | return threads; |
330 | } |
331 | |
332 | size_t SBThread::GetStopDescription(char *dst, size_t dst_len) { |
333 | LLDB_INSTRUMENT_VA(this, dst, dst_len); |
334 | |
335 | std::unique_lock<std::recursive_mutex> lock; |
336 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
337 | |
338 | if (dst) |
339 | *dst = 0; |
340 | |
341 | if (!exe_ctx.HasThreadScope()) |
342 | return 0; |
343 | |
344 | Process::StopLocker stop_locker; |
345 | if (!stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) |
346 | return 0; |
347 | |
348 | std::string thread_stop_desc = exe_ctx.GetThreadPtr()->GetStopDescription(); |
349 | if (thread_stop_desc.empty()) |
350 | return 0; |
351 | |
352 | if (dst) |
353 | return ::snprintf(s: dst, maxlen: dst_len, format: "%s", thread_stop_desc.c_str()) + 1; |
354 | |
355 | // NULL dst passed in, return the length needed to contain the |
356 | // description. |
357 | return thread_stop_desc.size() + 1; // Include the NULL byte for size |
358 | } |
359 | |
360 | SBValue SBThread::GetStopReturnValue() { |
361 | LLDB_INSTRUMENT_VA(this); |
362 | |
363 | ValueObjectSP return_valobj_sp; |
364 | std::unique_lock<std::recursive_mutex> lock; |
365 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
366 | |
367 | if (exe_ctx.HasThreadScope()) { |
368 | Process::StopLocker stop_locker; |
369 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
370 | StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo(); |
371 | if (stop_info_sp) { |
372 | return_valobj_sp = StopInfo::GetReturnValueObject(stop_info_sp); |
373 | } |
374 | } |
375 | } |
376 | |
377 | return SBValue(return_valobj_sp); |
378 | } |
379 | |
380 | void SBThread::SetThread(const ThreadSP &lldb_object_sp) { |
381 | m_opaque_sp->SetThreadSP(lldb_object_sp); |
382 | } |
383 | |
384 | lldb::tid_t SBThread::GetThreadID() const { |
385 | LLDB_INSTRUMENT_VA(this); |
386 | |
387 | ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); |
388 | if (thread_sp) |
389 | return thread_sp->GetID(); |
390 | return LLDB_INVALID_THREAD_ID; |
391 | } |
392 | |
393 | uint32_t SBThread::GetIndexID() const { |
394 | LLDB_INSTRUMENT_VA(this); |
395 | |
396 | ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); |
397 | if (thread_sp) |
398 | return thread_sp->GetIndexID(); |
399 | return LLDB_INVALID_INDEX32; |
400 | } |
401 | |
402 | const char *SBThread::GetName() const { |
403 | LLDB_INSTRUMENT_VA(this); |
404 | |
405 | std::unique_lock<std::recursive_mutex> lock; |
406 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
407 | |
408 | if (!exe_ctx.HasThreadScope()) |
409 | return nullptr; |
410 | |
411 | Process::StopLocker stop_locker; |
412 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) |
413 | return ConstString(exe_ctx.GetThreadPtr()->GetName()).GetCString(); |
414 | |
415 | return nullptr; |
416 | } |
417 | |
418 | const char *SBThread::GetQueueName() const { |
419 | LLDB_INSTRUMENT_VA(this); |
420 | |
421 | std::unique_lock<std::recursive_mutex> lock; |
422 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
423 | |
424 | if (!exe_ctx.HasThreadScope()) |
425 | return nullptr; |
426 | |
427 | Process::StopLocker stop_locker; |
428 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) |
429 | return ConstString(exe_ctx.GetThreadPtr()->GetQueueName()).GetCString(); |
430 | |
431 | return nullptr; |
432 | } |
433 | |
434 | lldb::queue_id_t SBThread::GetQueueID() const { |
435 | LLDB_INSTRUMENT_VA(this); |
436 | |
437 | queue_id_t id = LLDB_INVALID_QUEUE_ID; |
438 | std::unique_lock<std::recursive_mutex> lock; |
439 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
440 | |
441 | if (exe_ctx.HasThreadScope()) { |
442 | Process::StopLocker stop_locker; |
443 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
444 | id = exe_ctx.GetThreadPtr()->GetQueueID(); |
445 | } |
446 | } |
447 | |
448 | return id; |
449 | } |
450 | |
451 | bool SBThread::GetInfoItemByPathAsString(const char *path, SBStream &strm) { |
452 | LLDB_INSTRUMENT_VA(this, path, strm); |
453 | |
454 | bool success = false; |
455 | std::unique_lock<std::recursive_mutex> lock; |
456 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
457 | |
458 | if (exe_ctx.HasThreadScope()) { |
459 | Process::StopLocker stop_locker; |
460 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
461 | Thread *thread = exe_ctx.GetThreadPtr(); |
462 | StructuredData::ObjectSP info_root_sp = thread->GetExtendedInfo(); |
463 | if (info_root_sp) { |
464 | StructuredData::ObjectSP node = |
465 | info_root_sp->GetObjectForDotSeparatedPath(path); |
466 | if (node) { |
467 | if (node->GetType() == eStructuredDataTypeString) { |
468 | strm.ref() << node->GetAsString()->GetValue(); |
469 | success = true; |
470 | } |
471 | if (node->GetType() == eStructuredDataTypeInteger) { |
472 | strm.Printf(format: "0x%"PRIx64, node->GetUnsignedIntegerValue()); |
473 | success = true; |
474 | } |
475 | if (node->GetType() == eStructuredDataTypeFloat) { |
476 | strm.Printf(format: "0x%f", node->GetAsFloat()->GetValue()); |
477 | success = true; |
478 | } |
479 | if (node->GetType() == eStructuredDataTypeBoolean) { |
480 | if (node->GetAsBoolean()->GetValue()) |
481 | strm.Printf(format: "true"); |
482 | else |
483 | strm.Printf(format: "false"); |
484 | success = true; |
485 | } |
486 | if (node->GetType() == eStructuredDataTypeNull) { |
487 | strm.Printf(format: "null"); |
488 | success = true; |
489 | } |
490 | } |
491 | } |
492 | } |
493 | } |
494 | |
495 | return success; |
496 | } |
497 | |
498 | SBError SBThread::ResumeNewPlan(ExecutionContext &exe_ctx, |
499 | ThreadPlan *new_plan) { |
500 | SBError sb_error; |
501 | |
502 | Process *process = exe_ctx.GetProcessPtr(); |
503 | if (!process) { |
504 | sb_error = Status::FromErrorString(str: "No process in SBThread::ResumeNewPlan"); |
505 | return sb_error; |
506 | } |
507 | |
508 | Thread *thread = exe_ctx.GetThreadPtr(); |
509 | if (!thread) { |
510 | sb_error = Status::FromErrorString(str: "No thread in SBThread::ResumeNewPlan"); |
511 | return sb_error; |
512 | } |
513 | |
514 | // User level plans should be Controlling Plans so they can be interrupted, |
515 | // other plans executed, and then a "continue" will resume the plan. |
516 | if (new_plan != nullptr) { |
517 | new_plan->SetIsControllingPlan(true); |
518 | new_plan->SetOkayToDiscard(false); |
519 | } |
520 | |
521 | // Why do we need to set the current thread by ID here??? |
522 | process->GetThreadList().SetSelectedThreadByID(tid: thread->GetID()); |
523 | |
524 | if (process->GetTarget().GetDebugger().GetAsyncExecution()) |
525 | sb_error.ref() = process->Resume(); |
526 | else |
527 | sb_error.ref() = process->ResumeSynchronous(stream: nullptr); |
528 | |
529 | return sb_error; |
530 | } |
531 | |
532 | void SBThread::StepOver(lldb::RunMode stop_other_threads) { |
533 | LLDB_INSTRUMENT_VA(this, stop_other_threads); |
534 | |
535 | SBError error; // Ignored |
536 | StepOver(stop_other_threads, error); |
537 | } |
538 | |
539 | void SBThread::StepOver(lldb::RunMode stop_other_threads, SBError &error) { |
540 | LLDB_INSTRUMENT_VA(this, stop_other_threads, error); |
541 | |
542 | std::unique_lock<std::recursive_mutex> lock; |
543 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
544 | |
545 | if (!exe_ctx.HasThreadScope()) { |
546 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
547 | return; |
548 | } |
549 | |
550 | Thread *thread = exe_ctx.GetThreadPtr(); |
551 | bool abort_other_plans = false; |
552 | StackFrameSP frame_sp(thread->GetStackFrameAtIndex(idx: 0)); |
553 | |
554 | Status new_plan_status; |
555 | ThreadPlanSP new_plan_sp; |
556 | if (frame_sp) { |
557 | if (frame_sp->HasDebugInformation()) { |
558 | const LazyBool avoid_no_debug = eLazyBoolCalculate; |
559 | SymbolContext sc(frame_sp->GetSymbolContext(resolve_scope: eSymbolContextEverything)); |
560 | new_plan_sp = thread->QueueThreadPlanForStepOverRange( |
561 | abort_other_plans, line_entry: sc.line_entry, addr_context: sc, stop_other_threads, |
562 | status&: new_plan_status, step_out_avoids_code_without_debug_info: avoid_no_debug); |
563 | } else { |
564 | new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( |
565 | step_over: true, abort_other_plans, stop_other_threads, status&: new_plan_status); |
566 | } |
567 | } |
568 | error = ResumeNewPlan(exe_ctx, new_plan: new_plan_sp.get()); |
569 | } |
570 | |
571 | void SBThread::StepInto(lldb::RunMode stop_other_threads) { |
572 | LLDB_INSTRUMENT_VA(this, stop_other_threads); |
573 | |
574 | StepInto(target_name: nullptr, stop_other_threads); |
575 | } |
576 | |
577 | void SBThread::StepInto(const char *target_name, |
578 | lldb::RunMode stop_other_threads) { |
579 | LLDB_INSTRUMENT_VA(this, target_name, stop_other_threads); |
580 | |
581 | SBError error; // Ignored |
582 | StepInto(target_name, LLDB_INVALID_LINE_NUMBER, error, stop_other_threads); |
583 | } |
584 | |
585 | void SBThread::StepInto(const char *target_name, uint32_t end_line, |
586 | SBError &error, lldb::RunMode stop_other_threads) { |
587 | LLDB_INSTRUMENT_VA(this, target_name, end_line, error, stop_other_threads); |
588 | |
589 | std::unique_lock<std::recursive_mutex> lock; |
590 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
591 | |
592 | if (!exe_ctx.HasThreadScope()) { |
593 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
594 | return; |
595 | } |
596 | |
597 | bool abort_other_plans = false; |
598 | |
599 | Thread *thread = exe_ctx.GetThreadPtr(); |
600 | StackFrameSP frame_sp(thread->GetStackFrameAtIndex(idx: 0)); |
601 | ThreadPlanSP new_plan_sp; |
602 | Status new_plan_status; |
603 | |
604 | if (frame_sp && frame_sp->HasDebugInformation()) { |
605 | SymbolContext sc(frame_sp->GetSymbolContext(resolve_scope: eSymbolContextEverything)); |
606 | AddressRange range; |
607 | if (end_line == LLDB_INVALID_LINE_NUMBER) |
608 | range = sc.line_entry.range; |
609 | else { |
610 | llvm::Error err = sc.GetAddressRangeFromHereToEndLine(end_line, range); |
611 | if (err) { |
612 | error = Status::FromErrorString(str: llvm::toString(E: std::move(err)).c_str()); |
613 | return; |
614 | } |
615 | } |
616 | |
617 | const LazyBool step_out_avoids_code_without_debug_info = |
618 | eLazyBoolCalculate; |
619 | const LazyBool step_in_avoids_code_without_debug_info = |
620 | eLazyBoolCalculate; |
621 | new_plan_sp = thread->QueueThreadPlanForStepInRange( |
622 | abort_other_plans, range, addr_context: sc, step_in_target: target_name, stop_other_threads, |
623 | status&: new_plan_status, step_in_avoids_code_without_debug_info, |
624 | step_out_avoids_code_without_debug_info); |
625 | } else { |
626 | new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( |
627 | step_over: false, abort_other_plans, stop_other_threads, status&: new_plan_status); |
628 | } |
629 | |
630 | if (new_plan_status.Success()) |
631 | error = ResumeNewPlan(exe_ctx, new_plan: new_plan_sp.get()); |
632 | else |
633 | error = Status::FromErrorString(str: new_plan_status.AsCString()); |
634 | } |
635 | |
636 | void SBThread::StepOut() { |
637 | LLDB_INSTRUMENT_VA(this); |
638 | |
639 | SBError error; // Ignored |
640 | StepOut(error); |
641 | } |
642 | |
643 | void SBThread::StepOut(SBError &error) { |
644 | LLDB_INSTRUMENT_VA(this, error); |
645 | |
646 | std::unique_lock<std::recursive_mutex> lock; |
647 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
648 | |
649 | if (!exe_ctx.HasThreadScope()) { |
650 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
651 | return; |
652 | } |
653 | |
654 | bool abort_other_plans = false; |
655 | bool stop_other_threads = false; |
656 | |
657 | Thread *thread = exe_ctx.GetThreadPtr(); |
658 | |
659 | const LazyBool avoid_no_debug = eLazyBoolCalculate; |
660 | Status new_plan_status; |
661 | ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut( |
662 | abort_other_plans, addr_context: nullptr, first_insn: false, stop_other_threads, report_stop_vote: eVoteYes, |
663 | report_run_vote: eVoteNoOpinion, frame_idx: 0, status&: new_plan_status, step_out_avoids_code_without_debug_info: avoid_no_debug)); |
664 | |
665 | if (new_plan_status.Success()) |
666 | error = ResumeNewPlan(exe_ctx, new_plan: new_plan_sp.get()); |
667 | else |
668 | error = Status::FromErrorString(str: new_plan_status.AsCString()); |
669 | } |
670 | |
671 | void SBThread::StepOutOfFrame(SBFrame &sb_frame) { |
672 | LLDB_INSTRUMENT_VA(this, sb_frame); |
673 | |
674 | SBError error; // Ignored |
675 | StepOutOfFrame(frame&: sb_frame, error); |
676 | } |
677 | |
678 | void SBThread::StepOutOfFrame(SBFrame &sb_frame, SBError &error) { |
679 | LLDB_INSTRUMENT_VA(this, sb_frame, error); |
680 | |
681 | std::unique_lock<std::recursive_mutex> lock; |
682 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
683 | |
684 | if (!sb_frame.IsValid()) { |
685 | error = Status::FromErrorString(str: "passed invalid SBFrame object"); |
686 | return; |
687 | } |
688 | |
689 | StackFrameSP frame_sp(sb_frame.GetFrameSP()); |
690 | |
691 | if (!exe_ctx.HasThreadScope()) { |
692 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
693 | return; |
694 | } |
695 | |
696 | bool abort_other_plans = false; |
697 | bool stop_other_threads = false; |
698 | Thread *thread = exe_ctx.GetThreadPtr(); |
699 | if (sb_frame.GetThread().GetThreadID() != thread->GetID()) { |
700 | error = Status::FromErrorString(str: "passed a frame from another thread"); |
701 | return; |
702 | } |
703 | |
704 | Status new_plan_status; |
705 | ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut( |
706 | abort_other_plans, addr_context: nullptr, first_insn: false, stop_other_threads, report_stop_vote: eVoteYes, |
707 | report_run_vote: eVoteNoOpinion, frame_idx: frame_sp->GetFrameIndex(), status&: new_plan_status)); |
708 | |
709 | if (new_plan_status.Success()) |
710 | error = ResumeNewPlan(exe_ctx, new_plan: new_plan_sp.get()); |
711 | else |
712 | error = Status::FromErrorString(str: new_plan_status.AsCString()); |
713 | } |
714 | |
715 | void SBThread::StepInstruction(bool step_over) { |
716 | LLDB_INSTRUMENT_VA(this, step_over); |
717 | |
718 | SBError error; // Ignored |
719 | StepInstruction(step_over, error); |
720 | } |
721 | |
722 | void SBThread::StepInstruction(bool step_over, SBError &error) { |
723 | LLDB_INSTRUMENT_VA(this, step_over, error); |
724 | |
725 | std::unique_lock<std::recursive_mutex> lock; |
726 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
727 | |
728 | if (!exe_ctx.HasThreadScope()) { |
729 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
730 | return; |
731 | } |
732 | |
733 | Thread *thread = exe_ctx.GetThreadPtr(); |
734 | Status new_plan_status; |
735 | ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction( |
736 | step_over, abort_other_plans: false, stop_other_threads: true, status&: new_plan_status)); |
737 | |
738 | if (new_plan_status.Success()) |
739 | error = ResumeNewPlan(exe_ctx, new_plan: new_plan_sp.get()); |
740 | else |
741 | error = Status::FromErrorString(str: new_plan_status.AsCString()); |
742 | } |
743 | |
744 | void SBThread::RunToAddress(lldb::addr_t addr) { |
745 | LLDB_INSTRUMENT_VA(this, addr); |
746 | |
747 | SBError error; // Ignored |
748 | RunToAddress(addr, error); |
749 | } |
750 | |
751 | void SBThread::RunToAddress(lldb::addr_t addr, SBError &error) { |
752 | LLDB_INSTRUMENT_VA(this, addr, error); |
753 | |
754 | std::unique_lock<std::recursive_mutex> lock; |
755 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
756 | |
757 | if (!exe_ctx.HasThreadScope()) { |
758 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
759 | return; |
760 | } |
761 | |
762 | bool abort_other_plans = false; |
763 | bool stop_other_threads = true; |
764 | |
765 | Address target_addr(addr); |
766 | |
767 | Thread *thread = exe_ctx.GetThreadPtr(); |
768 | |
769 | Status new_plan_status; |
770 | ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress( |
771 | abort_other_plans, target_addr, stop_other_threads, status&: new_plan_status)); |
772 | |
773 | if (new_plan_status.Success()) |
774 | error = ResumeNewPlan(exe_ctx, new_plan: new_plan_sp.get()); |
775 | else |
776 | error = Status::FromErrorString(str: new_plan_status.AsCString()); |
777 | } |
778 | |
779 | SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, |
780 | lldb::SBFileSpec &sb_file_spec, uint32_t line) { |
781 | LLDB_INSTRUMENT_VA(this, sb_frame, sb_file_spec, line); |
782 | |
783 | SBError sb_error; |
784 | char path[PATH_MAX]; |
785 | |
786 | std::unique_lock<std::recursive_mutex> lock; |
787 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
788 | |
789 | StackFrameSP frame_sp(sb_frame.GetFrameSP()); |
790 | |
791 | if (exe_ctx.HasThreadScope()) { |
792 | Target *target = exe_ctx.GetTargetPtr(); |
793 | Thread *thread = exe_ctx.GetThreadPtr(); |
794 | |
795 | if (line == 0) { |
796 | sb_error = Status::FromErrorString(str: "invalid line argument"); |
797 | return sb_error; |
798 | } |
799 | |
800 | if (!frame_sp) { |
801 | // We don't want to run SelectMostRelevantFrame here, for instance if |
802 | // you called a sequence of StepOverUntil's you wouldn't want the |
803 | // frame changed out from under you because you stepped into a |
804 | // recognized frame. |
805 | frame_sp = thread->GetSelectedFrame(select_most_relevant: DoNoSelectMostRelevantFrame); |
806 | if (!frame_sp) |
807 | frame_sp = thread->GetStackFrameAtIndex(idx: 0); |
808 | } |
809 | |
810 | SymbolContext frame_sc; |
811 | if (!frame_sp) { |
812 | sb_error = Status::FromErrorString(str: "no valid frames in thread to step"); |
813 | return sb_error; |
814 | } |
815 | |
816 | // If we have a frame, get its line |
817 | frame_sc = frame_sp->GetSymbolContext( |
818 | resolve_scope: eSymbolContextCompUnit | eSymbolContextFunction | |
819 | eSymbolContextLineEntry | eSymbolContextSymbol); |
820 | |
821 | if (frame_sc.comp_unit == nullptr) { |
822 | sb_error = Status::FromErrorStringWithFormat( |
823 | format: "frame %u doesn't have debug information", frame_sp->GetFrameIndex()); |
824 | return sb_error; |
825 | } |
826 | |
827 | FileSpec step_file_spec; |
828 | if (sb_file_spec.IsValid()) { |
829 | // The file spec passed in was valid, so use it |
830 | step_file_spec = sb_file_spec.ref(); |
831 | } else { |
832 | if (frame_sc.line_entry.IsValid()) |
833 | step_file_spec = frame_sc.line_entry.GetFile(); |
834 | else { |
835 | sb_error = Status::FromErrorString( |
836 | str: "invalid file argument or no file for frame"); |
837 | return sb_error; |
838 | } |
839 | } |
840 | |
841 | // Grab the current function, then we will make sure the "until" address is |
842 | // within the function. We discard addresses that are out of the current |
843 | // function, and then if there are no addresses remaining, give an |
844 | // appropriate error message. |
845 | |
846 | bool all_in_function = true; |
847 | |
848 | std::vector<addr_t> step_over_until_addrs; |
849 | const bool abort_other_plans = false; |
850 | const bool stop_other_threads = false; |
851 | // TODO: Handle SourceLocationSpec column information |
852 | SourceLocationSpec location_spec( |
853 | step_file_spec, line, /*column=*/std::nullopt, /*check_inlines=*/true, |
854 | /*exact_match=*/false); |
855 | |
856 | SymbolContextList sc_list; |
857 | frame_sc.comp_unit->ResolveSymbolContext(src_location_spec: location_spec, |
858 | resolve_scope: eSymbolContextLineEntry, sc_list); |
859 | for (const SymbolContext &sc : sc_list) { |
860 | addr_t step_addr = |
861 | sc.line_entry.range.GetBaseAddress().GetLoadAddress(target); |
862 | if (step_addr != LLDB_INVALID_ADDRESS) { |
863 | AddressRange unused_range; |
864 | if (frame_sc.function->GetRangeContainingLoadAddress(load_addr: step_addr, target&: *target, |
865 | range&: unused_range)) |
866 | step_over_until_addrs.push_back(x: step_addr); |
867 | else |
868 | all_in_function = false; |
869 | } |
870 | } |
871 | |
872 | if (step_over_until_addrs.empty()) { |
873 | if (all_in_function) { |
874 | step_file_spec.GetPath(path, max_path_length: sizeof(path)); |
875 | sb_error = Status::FromErrorStringWithFormat( |
876 | format: "No line entries for %s:%u", path, line); |
877 | } else |
878 | sb_error = Status::FromErrorString( |
879 | str: "step until target not in current function"); |
880 | } else { |
881 | Status new_plan_status; |
882 | ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepUntil( |
883 | abort_other_plans, address_list: &step_over_until_addrs[0], |
884 | num_addresses: step_over_until_addrs.size(), stop_others: stop_other_threads, |
885 | frame_idx: frame_sp->GetFrameIndex(), status&: new_plan_status)); |
886 | |
887 | if (new_plan_status.Success()) |
888 | sb_error = ResumeNewPlan(exe_ctx, new_plan: new_plan_sp.get()); |
889 | else |
890 | sb_error = Status::FromErrorString(str: new_plan_status.AsCString()); |
891 | } |
892 | } else { |
893 | sb_error = Status::FromErrorString(str: "this SBThread object is invalid"); |
894 | } |
895 | return sb_error; |
896 | } |
897 | |
898 | SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name) { |
899 | LLDB_INSTRUMENT_VA(this, script_class_name); |
900 | |
901 | return StepUsingScriptedThreadPlan(script_class_name, resume_immediately: true); |
902 | } |
903 | |
904 | SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name, |
905 | bool resume_immediately) { |
906 | LLDB_INSTRUMENT_VA(this, script_class_name, resume_immediately); |
907 | |
908 | lldb::SBStructuredData no_data; |
909 | return StepUsingScriptedThreadPlan(script_class_name, args_data&: no_data, |
910 | resume_immediately); |
911 | } |
912 | |
913 | SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name, |
914 | SBStructuredData &args_data, |
915 | bool resume_immediately) { |
916 | LLDB_INSTRUMENT_VA(this, script_class_name, args_data, resume_immediately); |
917 | |
918 | SBError error; |
919 | |
920 | std::unique_lock<std::recursive_mutex> lock; |
921 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
922 | |
923 | if (!exe_ctx.HasThreadScope()) { |
924 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
925 | return error; |
926 | } |
927 | |
928 | Thread *thread = exe_ctx.GetThreadPtr(); |
929 | Status new_plan_status; |
930 | StructuredData::ObjectSP obj_sp = args_data.m_impl_up->GetObjectSP(); |
931 | |
932 | ThreadPlanSP new_plan_sp = thread->QueueThreadPlanForStepScripted( |
933 | abort_other_plans: false, class_name: script_class_name, extra_args_sp: obj_sp, stop_other_threads: false, status&: new_plan_status); |
934 | |
935 | if (new_plan_status.Fail()) { |
936 | error = Status::FromErrorString(str: new_plan_status.AsCString()); |
937 | return error; |
938 | } |
939 | |
940 | if (!resume_immediately) |
941 | return error; |
942 | |
943 | if (new_plan_status.Success()) |
944 | error = ResumeNewPlan(exe_ctx, new_plan: new_plan_sp.get()); |
945 | else |
946 | error = Status::FromErrorString(str: new_plan_status.AsCString()); |
947 | |
948 | return error; |
949 | } |
950 | |
951 | SBError SBThread::JumpToLine(lldb::SBFileSpec &file_spec, uint32_t line) { |
952 | LLDB_INSTRUMENT_VA(this, file_spec, line); |
953 | |
954 | SBError sb_error; |
955 | |
956 | std::unique_lock<std::recursive_mutex> lock; |
957 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
958 | |
959 | if (!exe_ctx.HasThreadScope()) { |
960 | sb_error = Status::FromErrorString(str: "this SBThread object is invalid"); |
961 | return sb_error; |
962 | } |
963 | |
964 | Thread *thread = exe_ctx.GetThreadPtr(); |
965 | |
966 | Status err = thread->JumpToLine(file: file_spec.ref(), line, can_leave_function: true); |
967 | sb_error.SetError(std::move(err)); |
968 | return sb_error; |
969 | } |
970 | |
971 | SBError SBThread::ReturnFromFrame(SBFrame &frame, SBValue &return_value) { |
972 | LLDB_INSTRUMENT_VA(this, frame, return_value); |
973 | |
974 | SBError sb_error; |
975 | |
976 | std::unique_lock<std::recursive_mutex> lock; |
977 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
978 | |
979 | if (exe_ctx.HasThreadScope()) { |
980 | Thread *thread = exe_ctx.GetThreadPtr(); |
981 | sb_error.SetError( |
982 | thread->ReturnFromFrame(frame_sp: frame.GetFrameSP(), return_value_sp: return_value.GetSP())); |
983 | } |
984 | |
985 | return sb_error; |
986 | } |
987 | |
988 | SBError SBThread::UnwindInnermostExpression() { |
989 | LLDB_INSTRUMENT_VA(this); |
990 | |
991 | SBError sb_error; |
992 | |
993 | std::unique_lock<std::recursive_mutex> lock; |
994 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
995 | |
996 | if (exe_ctx.HasThreadScope()) { |
997 | Thread *thread = exe_ctx.GetThreadPtr(); |
998 | sb_error.SetError(thread->UnwindInnermostExpression()); |
999 | if (sb_error.Success()) |
1000 | thread->SetSelectedFrameByIndex(frame_idx: 0, broadcast: false); |
1001 | } |
1002 | |
1003 | return sb_error; |
1004 | } |
1005 | |
1006 | bool SBThread::Suspend() { |
1007 | LLDB_INSTRUMENT_VA(this); |
1008 | |
1009 | SBError error; // Ignored |
1010 | return Suspend(error); |
1011 | } |
1012 | |
1013 | bool SBThread::Suspend(SBError &error) { |
1014 | LLDB_INSTRUMENT_VA(this, error); |
1015 | |
1016 | std::unique_lock<std::recursive_mutex> lock; |
1017 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1018 | |
1019 | bool result = false; |
1020 | if (exe_ctx.HasThreadScope()) { |
1021 | Process::StopLocker stop_locker; |
1022 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
1023 | exe_ctx.GetThreadPtr()->SetResumeState(state: eStateSuspended); |
1024 | result = true; |
1025 | } else { |
1026 | error = Status::FromErrorString(str: "process is running"); |
1027 | } |
1028 | } else |
1029 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
1030 | return result; |
1031 | } |
1032 | |
1033 | bool SBThread::Resume() { |
1034 | LLDB_INSTRUMENT_VA(this); |
1035 | |
1036 | SBError error; // Ignored |
1037 | return Resume(error); |
1038 | } |
1039 | |
1040 | bool SBThread::Resume(SBError &error) { |
1041 | LLDB_INSTRUMENT_VA(this, error); |
1042 | |
1043 | std::unique_lock<std::recursive_mutex> lock; |
1044 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1045 | |
1046 | bool result = false; |
1047 | if (exe_ctx.HasThreadScope()) { |
1048 | Process::StopLocker stop_locker; |
1049 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
1050 | const bool override_suspend = true; |
1051 | exe_ctx.GetThreadPtr()->SetResumeState(state: eStateRunning, override_suspend); |
1052 | result = true; |
1053 | } else { |
1054 | error = Status::FromErrorString(str: "process is running"); |
1055 | } |
1056 | } else |
1057 | error = Status::FromErrorString(str: "this SBThread object is invalid"); |
1058 | return result; |
1059 | } |
1060 | |
1061 | bool SBThread::IsSuspended() { |
1062 | LLDB_INSTRUMENT_VA(this); |
1063 | |
1064 | std::unique_lock<std::recursive_mutex> lock; |
1065 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1066 | |
1067 | if (exe_ctx.HasThreadScope()) |
1068 | return exe_ctx.GetThreadPtr()->GetResumeState() == eStateSuspended; |
1069 | return false; |
1070 | } |
1071 | |
1072 | bool SBThread::IsStopped() { |
1073 | LLDB_INSTRUMENT_VA(this); |
1074 | |
1075 | std::unique_lock<std::recursive_mutex> lock; |
1076 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1077 | |
1078 | if (exe_ctx.HasThreadScope()) |
1079 | return StateIsStoppedState(state: exe_ctx.GetThreadPtr()->GetState(), must_exist: true); |
1080 | return false; |
1081 | } |
1082 | |
1083 | SBProcess SBThread::GetProcess() { |
1084 | LLDB_INSTRUMENT_VA(this); |
1085 | |
1086 | SBProcess sb_process; |
1087 | std::unique_lock<std::recursive_mutex> lock; |
1088 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1089 | |
1090 | if (exe_ctx.HasThreadScope()) { |
1091 | // Have to go up to the target so we can get a shared pointer to our |
1092 | // process... |
1093 | sb_process.SetSP(exe_ctx.GetProcessSP()); |
1094 | } |
1095 | |
1096 | return sb_process; |
1097 | } |
1098 | |
1099 | uint32_t SBThread::GetNumFrames() { |
1100 | LLDB_INSTRUMENT_VA(this); |
1101 | |
1102 | uint32_t num_frames = 0; |
1103 | std::unique_lock<std::recursive_mutex> lock; |
1104 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1105 | |
1106 | if (exe_ctx.HasThreadScope()) { |
1107 | Process::StopLocker stop_locker; |
1108 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
1109 | num_frames = exe_ctx.GetThreadPtr()->GetStackFrameCount(); |
1110 | } |
1111 | } |
1112 | |
1113 | return num_frames; |
1114 | } |
1115 | |
1116 | SBFrame SBThread::GetFrameAtIndex(uint32_t idx) { |
1117 | LLDB_INSTRUMENT_VA(this, idx); |
1118 | |
1119 | SBFrame sb_frame; |
1120 | StackFrameSP frame_sp; |
1121 | std::unique_lock<std::recursive_mutex> lock; |
1122 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1123 | |
1124 | if (exe_ctx.HasThreadScope()) { |
1125 | Process::StopLocker stop_locker; |
1126 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
1127 | frame_sp = exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(idx); |
1128 | sb_frame.SetFrameSP(frame_sp); |
1129 | } |
1130 | } |
1131 | |
1132 | return sb_frame; |
1133 | } |
1134 | |
1135 | lldb::SBFrame SBThread::GetSelectedFrame() { |
1136 | LLDB_INSTRUMENT_VA(this); |
1137 | |
1138 | SBFrame sb_frame; |
1139 | StackFrameSP frame_sp; |
1140 | std::unique_lock<std::recursive_mutex> lock; |
1141 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1142 | |
1143 | if (exe_ctx.HasThreadScope()) { |
1144 | Process::StopLocker stop_locker; |
1145 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
1146 | frame_sp = |
1147 | exe_ctx.GetThreadPtr()->GetSelectedFrame(select_most_relevant: SelectMostRelevantFrame); |
1148 | sb_frame.SetFrameSP(frame_sp); |
1149 | } |
1150 | } |
1151 | |
1152 | return sb_frame; |
1153 | } |
1154 | |
1155 | lldb::SBFrame SBThread::SetSelectedFrame(uint32_t idx) { |
1156 | LLDB_INSTRUMENT_VA(this, idx); |
1157 | |
1158 | SBFrame sb_frame; |
1159 | StackFrameSP frame_sp; |
1160 | std::unique_lock<std::recursive_mutex> lock; |
1161 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1162 | |
1163 | if (exe_ctx.HasThreadScope()) { |
1164 | Process::StopLocker stop_locker; |
1165 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
1166 | Thread *thread = exe_ctx.GetThreadPtr(); |
1167 | frame_sp = thread->GetStackFrameAtIndex(idx); |
1168 | if (frame_sp) { |
1169 | thread->SetSelectedFrame(frame: frame_sp.get()); |
1170 | sb_frame.SetFrameSP(frame_sp); |
1171 | } |
1172 | } |
1173 | } |
1174 | |
1175 | return sb_frame; |
1176 | } |
1177 | |
1178 | bool SBThread::EventIsThreadEvent(const SBEvent &event) { |
1179 | LLDB_INSTRUMENT_VA(event); |
1180 | |
1181 | return Thread::ThreadEventData::GetEventDataFromEvent(event_ptr: event.get()) != nullptr; |
1182 | } |
1183 | |
1184 | SBFrame SBThread::GetStackFrameFromEvent(const SBEvent &event) { |
1185 | LLDB_INSTRUMENT_VA(event); |
1186 | |
1187 | return Thread::ThreadEventData::GetStackFrameFromEvent(event_ptr: event.get()); |
1188 | } |
1189 | |
1190 | SBThread SBThread::GetThreadFromEvent(const SBEvent &event) { |
1191 | LLDB_INSTRUMENT_VA(event); |
1192 | |
1193 | return Thread::ThreadEventData::GetThreadFromEvent(event_ptr: event.get()); |
1194 | } |
1195 | |
1196 | bool SBThread::operator==(const SBThread &rhs) const { |
1197 | LLDB_INSTRUMENT_VA(this, rhs); |
1198 | |
1199 | return m_opaque_sp->GetThreadSP().get() == |
1200 | rhs.m_opaque_sp->GetThreadSP().get(); |
1201 | } |
1202 | |
1203 | bool SBThread::operator!=(const SBThread &rhs) const { |
1204 | LLDB_INSTRUMENT_VA(this, rhs); |
1205 | |
1206 | return m_opaque_sp->GetThreadSP().get() != |
1207 | rhs.m_opaque_sp->GetThreadSP().get(); |
1208 | } |
1209 | |
1210 | bool SBThread::GetStatus(SBStream &status) const { |
1211 | LLDB_INSTRUMENT_VA(this, status); |
1212 | |
1213 | Stream &strm = status.ref(); |
1214 | |
1215 | std::unique_lock<std::recursive_mutex> lock; |
1216 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1217 | |
1218 | if (exe_ctx.HasThreadScope()) { |
1219 | exe_ctx.GetThreadPtr()->GetStatus(strm, start_frame: 0, num_frames: 1, num_frames_with_source: 1, stop_format: true, |
1220 | /*show_hidden=*/true); |
1221 | } else |
1222 | strm.PutCString(cstr: "No status"); |
1223 | |
1224 | return true; |
1225 | } |
1226 | |
1227 | bool SBThread::GetDescription(SBStream &description) const { |
1228 | LLDB_INSTRUMENT_VA(this, description); |
1229 | |
1230 | return GetDescription(description, stop_format: false); |
1231 | } |
1232 | |
1233 | bool SBThread::GetDescription(SBStream &description, bool stop_format) const { |
1234 | LLDB_INSTRUMENT_VA(this, description, stop_format); |
1235 | |
1236 | Stream &strm = description.ref(); |
1237 | |
1238 | std::unique_lock<std::recursive_mutex> lock; |
1239 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1240 | |
1241 | if (exe_ctx.HasThreadScope()) { |
1242 | exe_ctx.GetThreadPtr()->DumpUsingSettingsFormat( |
1243 | strm, LLDB_INVALID_THREAD_ID, stop_format); |
1244 | } else |
1245 | strm.PutCString(cstr: "No value"); |
1246 | |
1247 | return true; |
1248 | } |
1249 | |
1250 | SBError SBThread::GetDescriptionWithFormat(const SBFormat &format, |
1251 | SBStream &output) { |
1252 | Stream &strm = output.ref(); |
1253 | |
1254 | SBError error; |
1255 | if (!format) { |
1256 | error = Status::FromErrorString(str: "The provided SBFormat object is invalid"); |
1257 | return error; |
1258 | } |
1259 | |
1260 | std::unique_lock<std::recursive_mutex> lock; |
1261 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1262 | |
1263 | if (exe_ctx.HasThreadScope()) { |
1264 | if (exe_ctx.GetThreadPtr()->DumpUsingFormat( |
1265 | strm, LLDB_INVALID_THREAD_ID, format: format.GetFormatEntrySP().get())) { |
1266 | return error; |
1267 | } |
1268 | } |
1269 | |
1270 | error = Status::FromErrorStringWithFormat( |
1271 | format: "It was not possible to generate a thread description with the given " |
1272 | "format string '%s'", |
1273 | format.GetFormatEntrySP()->string.c_str()); |
1274 | return error; |
1275 | } |
1276 | |
1277 | SBThread SBThread::GetExtendedBacktraceThread(const char *type) { |
1278 | LLDB_INSTRUMENT_VA(this, type); |
1279 | |
1280 | std::unique_lock<std::recursive_mutex> lock; |
1281 | ExecutionContext exe_ctx(m_opaque_sp.get(), lock); |
1282 | SBThread sb_origin_thread; |
1283 | |
1284 | Process::StopLocker stop_locker; |
1285 | if (stop_locker.TryLock(lock: &exe_ctx.GetProcessPtr()->GetRunLock())) { |
1286 | if (exe_ctx.HasThreadScope()) { |
1287 | ThreadSP real_thread(exe_ctx.GetThreadSP()); |
1288 | if (real_thread) { |
1289 | ConstString type_const(type); |
1290 | Process *process = exe_ctx.GetProcessPtr(); |
1291 | if (process) { |
1292 | SystemRuntime *runtime = process->GetSystemRuntime(); |
1293 | if (runtime) { |
1294 | ThreadSP new_thread_sp( |
1295 | runtime->GetExtendedBacktraceThread(thread: real_thread, type: type_const)); |
1296 | if (new_thread_sp) { |
1297 | // Save this in the Process' ExtendedThreadList so a strong |
1298 | // pointer retains the object. |
1299 | process->GetExtendedThreadList().AddThread(thread_sp: new_thread_sp); |
1300 | sb_origin_thread.SetThread(new_thread_sp); |
1301 | } |
1302 | } |
1303 | } |
1304 | } |
1305 | } |
1306 | } |
1307 | |
1308 | return sb_origin_thread; |
1309 | } |
1310 | |
1311 | uint32_t SBThread::GetExtendedBacktraceOriginatingIndexID() { |
1312 | LLDB_INSTRUMENT_VA(this); |
1313 | |
1314 | ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); |
1315 | if (thread_sp) |
1316 | return thread_sp->GetExtendedBacktraceOriginatingIndexID(); |
1317 | return LLDB_INVALID_INDEX32; |
1318 | } |
1319 | |
1320 | SBValue SBThread::GetCurrentException() { |
1321 | LLDB_INSTRUMENT_VA(this); |
1322 | |
1323 | ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); |
1324 | if (!thread_sp) |
1325 | return SBValue(); |
1326 | |
1327 | return SBValue(thread_sp->GetCurrentException()); |
1328 | } |
1329 | |
1330 | SBThread SBThread::GetCurrentExceptionBacktrace() { |
1331 | LLDB_INSTRUMENT_VA(this); |
1332 | |
1333 | ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); |
1334 | if (!thread_sp) |
1335 | return SBThread(); |
1336 | |
1337 | return SBThread(thread_sp->GetCurrentExceptionBacktrace()); |
1338 | } |
1339 | |
1340 | bool SBThread::SafeToCallFunctions() { |
1341 | LLDB_INSTRUMENT_VA(this); |
1342 | |
1343 | ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); |
1344 | if (thread_sp) |
1345 | return thread_sp->SafeToCallFunctions(); |
1346 | return true; |
1347 | } |
1348 | |
1349 | lldb::ThreadSP SBThread::GetSP() const { return m_opaque_sp->GetThreadSP(); } |
1350 | |
1351 | lldb_private::Thread *SBThread::operator->() { |
1352 | return get(); |
1353 | } |
1354 | |
1355 | lldb_private::Thread *SBThread::get() { |
1356 | return m_opaque_sp->GetThreadSP().get(); |
1357 | } |
1358 | |
1359 | SBValue SBThread::GetSiginfo() { |
1360 | LLDB_INSTRUMENT_VA(this); |
1361 | |
1362 | ThreadSP thread_sp = m_opaque_sp->GetThreadSP(); |
1363 | if (!thread_sp) |
1364 | return SBValue(); |
1365 | return thread_sp->GetSiginfoValue(); |
1366 | } |
1367 |
Definitions
- GetBroadcasterClassName
- SBThread
- SBThread
- SBThread
- operator=
- ~SBThread
- GetQueue
- IsValid
- operator bool
- Clear
- GetStopReason
- GetStopReasonDataCount
- GetStopReasonDataAtIndex
- GetStopReasonExtendedInfoAsJSON
- GetStopReasonExtendedBacktraces
- GetStopDescription
- GetStopReturnValue
- SetThread
- GetThreadID
- GetIndexID
- GetName
- GetQueueName
- GetQueueID
- GetInfoItemByPathAsString
- ResumeNewPlan
- StepOver
- StepOver
- StepInto
- StepInto
- StepInto
- StepOut
- StepOut
- StepOutOfFrame
- StepOutOfFrame
- StepInstruction
- StepInstruction
- RunToAddress
- RunToAddress
- StepOverUntil
- StepUsingScriptedThreadPlan
- StepUsingScriptedThreadPlan
- StepUsingScriptedThreadPlan
- JumpToLine
- ReturnFromFrame
- UnwindInnermostExpression
- Suspend
- Suspend
- Resume
- Resume
- IsSuspended
- IsStopped
- GetProcess
- GetNumFrames
- GetFrameAtIndex
- GetSelectedFrame
- SetSelectedFrame
- EventIsThreadEvent
- GetStackFrameFromEvent
- GetThreadFromEvent
- operator==
- operator!=
- GetStatus
- GetDescription
- GetDescription
- GetDescriptionWithFormat
- GetExtendedBacktraceThread
- GetExtendedBacktraceOriginatingIndexID
- GetCurrentException
- GetCurrentExceptionBacktrace
- SafeToCallFunctions
- GetSP
- operator->
- get
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more