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