1 | //===-- Thread.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/Target/Thread.h" |
10 | #include "lldb/Breakpoint/BreakpointLocation.h" |
11 | #include "lldb/Core/Debugger.h" |
12 | #include "lldb/Core/FormatEntity.h" |
13 | #include "lldb/Core/Module.h" |
14 | #include "lldb/Core/StructuredDataImpl.h" |
15 | #include "lldb/Core/ValueObject.h" |
16 | #include "lldb/Core/ValueObjectConstResult.h" |
17 | #include "lldb/Host/Host.h" |
18 | #include "lldb/Interpreter/OptionValueFileSpecList.h" |
19 | #include "lldb/Interpreter/OptionValueProperties.h" |
20 | #include "lldb/Interpreter/Property.h" |
21 | #include "lldb/Symbol/Function.h" |
22 | #include "lldb/Target/ABI.h" |
23 | #include "lldb/Target/DynamicLoader.h" |
24 | #include "lldb/Target/ExecutionContext.h" |
25 | #include "lldb/Target/LanguageRuntime.h" |
26 | #include "lldb/Target/Process.h" |
27 | #include "lldb/Target/RegisterContext.h" |
28 | #include "lldb/Target/StackFrameRecognizer.h" |
29 | #include "lldb/Target/StopInfo.h" |
30 | #include "lldb/Target/SystemRuntime.h" |
31 | #include "lldb/Target/Target.h" |
32 | #include "lldb/Target/ThreadPlan.h" |
33 | #include "lldb/Target/ThreadPlanBase.h" |
34 | #include "lldb/Target/ThreadPlanCallFunction.h" |
35 | #include "lldb/Target/ThreadPlanPython.h" |
36 | #include "lldb/Target/ThreadPlanRunToAddress.h" |
37 | #include "lldb/Target/ThreadPlanStack.h" |
38 | #include "lldb/Target/ThreadPlanStepInRange.h" |
39 | #include "lldb/Target/ThreadPlanStepInstruction.h" |
40 | #include "lldb/Target/ThreadPlanStepOut.h" |
41 | #include "lldb/Target/ThreadPlanStepOverBreakpoint.h" |
42 | #include "lldb/Target/ThreadPlanStepOverRange.h" |
43 | #include "lldb/Target/ThreadPlanStepThrough.h" |
44 | #include "lldb/Target/ThreadPlanStepUntil.h" |
45 | #include "lldb/Target/ThreadSpec.h" |
46 | #include "lldb/Target/UnwindLLDB.h" |
47 | #include "lldb/Utility/LLDBLog.h" |
48 | #include "lldb/Utility/Log.h" |
49 | #include "lldb/Utility/RegularExpression.h" |
50 | #include "lldb/Utility/State.h" |
51 | #include "lldb/Utility/Stream.h" |
52 | #include "lldb/Utility/StreamString.h" |
53 | #include "lldb/lldb-enumerations.h" |
54 | |
55 | #include <memory> |
56 | #include <optional> |
57 | |
58 | using namespace lldb; |
59 | using namespace lldb_private; |
60 | |
61 | ThreadProperties &Thread::GetGlobalProperties() { |
62 | // NOTE: intentional leak so we don't crash if global destructor chain gets |
63 | // called as other threads still use the result of this function |
64 | static ThreadProperties *g_settings_ptr = new ThreadProperties(true); |
65 | return *g_settings_ptr; |
66 | } |
67 | |
68 | #define LLDB_PROPERTIES_thread |
69 | #include "TargetProperties.inc" |
70 | |
71 | enum { |
72 | #define LLDB_PROPERTIES_thread |
73 | #include "TargetPropertiesEnum.inc" |
74 | }; |
75 | |
76 | class ThreadOptionValueProperties |
77 | : public Cloneable<ThreadOptionValueProperties, OptionValueProperties> { |
78 | public: |
79 | ThreadOptionValueProperties(llvm::StringRef name) : Cloneable(name) {} |
80 | |
81 | const Property * |
82 | GetPropertyAtIndex(size_t idx, |
83 | const ExecutionContext *exe_ctx) const override { |
84 | // When getting the value for a key from the thread options, we will always |
85 | // try and grab the setting from the current thread if there is one. Else |
86 | // we just use the one from this instance. |
87 | if (exe_ctx) { |
88 | Thread *thread = exe_ctx->GetThreadPtr(); |
89 | if (thread) { |
90 | ThreadOptionValueProperties *instance_properties = |
91 | static_cast<ThreadOptionValueProperties *>( |
92 | thread->GetValueProperties().get()); |
93 | if (this != instance_properties) |
94 | return instance_properties->ProtectedGetPropertyAtIndex(idx); |
95 | } |
96 | } |
97 | return ProtectedGetPropertyAtIndex(idx); |
98 | } |
99 | }; |
100 | |
101 | ThreadProperties::ThreadProperties(bool is_global) : Properties() { |
102 | if (is_global) { |
103 | m_collection_sp = std::make_shared<ThreadOptionValueProperties>(args: "thread" ); |
104 | m_collection_sp->Initialize(setting_definitions: g_thread_properties); |
105 | } else |
106 | m_collection_sp = |
107 | OptionValueProperties::CreateLocalCopy(global_properties: Thread::GetGlobalProperties()); |
108 | } |
109 | |
110 | ThreadProperties::~ThreadProperties() = default; |
111 | |
112 | const RegularExpression *ThreadProperties::GetSymbolsToAvoidRegexp() { |
113 | const uint32_t idx = ePropertyStepAvoidRegex; |
114 | return GetPropertyAtIndexAs<const RegularExpression *>(idx); |
115 | } |
116 | |
117 | FileSpecList ThreadProperties::GetLibrariesToAvoid() const { |
118 | const uint32_t idx = ePropertyStepAvoidLibraries; |
119 | return GetPropertyAtIndexAs<FileSpecList>(idx, default_value: {}); |
120 | } |
121 | |
122 | bool ThreadProperties::GetTraceEnabledState() const { |
123 | const uint32_t idx = ePropertyEnableThreadTrace; |
124 | return GetPropertyAtIndexAs<bool>( |
125 | idx, g_thread_properties[idx].default_uint_value != 0); |
126 | } |
127 | |
128 | bool ThreadProperties::GetStepInAvoidsNoDebug() const { |
129 | const uint32_t idx = ePropertyStepInAvoidsNoDebug; |
130 | return GetPropertyAtIndexAs<bool>( |
131 | idx, g_thread_properties[idx].default_uint_value != 0); |
132 | } |
133 | |
134 | bool ThreadProperties::GetStepOutAvoidsNoDebug() const { |
135 | const uint32_t idx = ePropertyStepOutAvoidsNoDebug; |
136 | return GetPropertyAtIndexAs<bool>( |
137 | idx, g_thread_properties[idx].default_uint_value != 0); |
138 | } |
139 | |
140 | uint64_t ThreadProperties::GetMaxBacktraceDepth() const { |
141 | const uint32_t idx = ePropertyMaxBacktraceDepth; |
142 | return GetPropertyAtIndexAs<uint64_t>( |
143 | idx, g_thread_properties[idx].default_uint_value); |
144 | } |
145 | |
146 | // Thread Event Data |
147 | |
148 | llvm::StringRef Thread::ThreadEventData::GetFlavorString() { |
149 | return "Thread::ThreadEventData" ; |
150 | } |
151 | |
152 | Thread::ThreadEventData::ThreadEventData(const lldb::ThreadSP thread_sp) |
153 | : m_thread_sp(thread_sp), m_stack_id() {} |
154 | |
155 | Thread::ThreadEventData::ThreadEventData(const lldb::ThreadSP thread_sp, |
156 | const StackID &stack_id) |
157 | : m_thread_sp(thread_sp), m_stack_id(stack_id) {} |
158 | |
159 | Thread::ThreadEventData::ThreadEventData() : m_thread_sp(), m_stack_id() {} |
160 | |
161 | Thread::ThreadEventData::~ThreadEventData() = default; |
162 | |
163 | void Thread::ThreadEventData::Dump(Stream *s) const {} |
164 | |
165 | const Thread::ThreadEventData * |
166 | Thread::ThreadEventData::GetEventDataFromEvent(const Event *event_ptr) { |
167 | if (event_ptr) { |
168 | const EventData *event_data = event_ptr->GetData(); |
169 | if (event_data && |
170 | event_data->GetFlavor() == ThreadEventData::GetFlavorString()) |
171 | return static_cast<const ThreadEventData *>(event_ptr->GetData()); |
172 | } |
173 | return nullptr; |
174 | } |
175 | |
176 | ThreadSP Thread::ThreadEventData::GetThreadFromEvent(const Event *event_ptr) { |
177 | ThreadSP thread_sp; |
178 | const ThreadEventData *event_data = GetEventDataFromEvent(event_ptr); |
179 | if (event_data) |
180 | thread_sp = event_data->GetThread(); |
181 | return thread_sp; |
182 | } |
183 | |
184 | StackID Thread::ThreadEventData::GetStackIDFromEvent(const Event *event_ptr) { |
185 | StackID stack_id; |
186 | const ThreadEventData *event_data = GetEventDataFromEvent(event_ptr); |
187 | if (event_data) |
188 | stack_id = event_data->GetStackID(); |
189 | return stack_id; |
190 | } |
191 | |
192 | StackFrameSP |
193 | Thread::ThreadEventData::GetStackFrameFromEvent(const Event *event_ptr) { |
194 | const ThreadEventData *event_data = GetEventDataFromEvent(event_ptr); |
195 | StackFrameSP frame_sp; |
196 | if (event_data) { |
197 | ThreadSP thread_sp = event_data->GetThread(); |
198 | if (thread_sp) { |
199 | frame_sp = thread_sp->GetStackFrameList()->GetFrameWithStackID( |
200 | stack_id: event_data->GetStackID()); |
201 | } |
202 | } |
203 | return frame_sp; |
204 | } |
205 | |
206 | // Thread class |
207 | |
208 | ConstString &Thread::GetStaticBroadcasterClass() { |
209 | static ConstString class_name("lldb.thread" ); |
210 | return class_name; |
211 | } |
212 | |
213 | Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) |
214 | : ThreadProperties(false), UserID(tid), |
215 | Broadcaster(process.GetTarget().GetDebugger().GetBroadcasterManager(), |
216 | Thread::GetStaticBroadcasterClass().AsCString()), |
217 | m_process_wp(process.shared_from_this()), m_stop_info_sp(), |
218 | m_stop_info_stop_id(0), m_stop_info_override_stop_id(0), |
219 | m_should_run_before_public_stop(false), |
220 | m_index_id(use_invalid_index_id ? LLDB_INVALID_INDEX32 |
221 | : process.GetNextThreadIndexID(thread_id: tid)), |
222 | m_reg_context_sp(), m_state(eStateUnloaded), m_state_mutex(), |
223 | m_frame_mutex(), m_curr_frames_sp(), m_prev_frames_sp(), |
224 | m_prev_framezero_pc(), m_resume_signal(LLDB_INVALID_SIGNAL_NUMBER), |
225 | m_resume_state(eStateRunning), m_temporary_resume_state(eStateRunning), |
226 | m_unwinder_up(), m_destroy_called(false), |
227 | m_override_should_notify(eLazyBoolCalculate), |
228 | m_extended_info_fetched(false), m_extended_info() { |
229 | Log *log = GetLog(mask: LLDBLog::Object); |
230 | LLDB_LOGF(log, "%p Thread::Thread(tid = 0x%4.4" PRIx64 ")" , |
231 | static_cast<void *>(this), GetID()); |
232 | |
233 | CheckInWithManager(); |
234 | } |
235 | |
236 | Thread::~Thread() { |
237 | Log *log = GetLog(mask: LLDBLog::Object); |
238 | LLDB_LOGF(log, "%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")" , |
239 | static_cast<void *>(this), GetID()); |
240 | /// If you hit this assert, it means your derived class forgot to call |
241 | /// DoDestroy in its destructor. |
242 | assert(m_destroy_called); |
243 | } |
244 | |
245 | void Thread::DestroyThread() { |
246 | m_destroy_called = true; |
247 | m_stop_info_sp.reset(); |
248 | m_reg_context_sp.reset(); |
249 | m_unwinder_up.reset(); |
250 | std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); |
251 | m_curr_frames_sp.reset(); |
252 | m_prev_frames_sp.reset(); |
253 | m_prev_framezero_pc.reset(); |
254 | } |
255 | |
256 | void Thread::BroadcastSelectedFrameChange(StackID &new_frame_id) { |
257 | if (EventTypeHasListeners(event_type: eBroadcastBitSelectedFrameChanged)) { |
258 | auto data_sp = |
259 | std::make_shared<ThreadEventData>(args: shared_from_this(), args&: new_frame_id); |
260 | BroadcastEvent(event_type: eBroadcastBitSelectedFrameChanged, event_data_sp: data_sp); |
261 | } |
262 | } |
263 | |
264 | lldb::StackFrameSP |
265 | Thread::GetSelectedFrame(SelectMostRelevant select_most_relevant) { |
266 | StackFrameListSP stack_frame_list_sp(GetStackFrameList()); |
267 | StackFrameSP frame_sp = stack_frame_list_sp->GetFrameAtIndex( |
268 | idx: stack_frame_list_sp->GetSelectedFrameIndex(select_most_relevant_frame: select_most_relevant)); |
269 | FrameSelectedCallback(frame: frame_sp.get()); |
270 | return frame_sp; |
271 | } |
272 | |
273 | uint32_t Thread::SetSelectedFrame(lldb_private::StackFrame *frame, |
274 | bool broadcast) { |
275 | uint32_t ret_value = GetStackFrameList()->SetSelectedFrame(frame); |
276 | if (broadcast) |
277 | BroadcastSelectedFrameChange(new_frame_id&: frame->GetStackID()); |
278 | FrameSelectedCallback(frame); |
279 | return ret_value; |
280 | } |
281 | |
282 | bool Thread::SetSelectedFrameByIndex(uint32_t frame_idx, bool broadcast) { |
283 | StackFrameSP frame_sp(GetStackFrameList()->GetFrameAtIndex(idx: frame_idx)); |
284 | if (frame_sp) { |
285 | GetStackFrameList()->SetSelectedFrame(frame_sp.get()); |
286 | if (broadcast) |
287 | BroadcastSelectedFrameChange(new_frame_id&: frame_sp->GetStackID()); |
288 | FrameSelectedCallback(frame: frame_sp.get()); |
289 | return true; |
290 | } else |
291 | return false; |
292 | } |
293 | |
294 | bool Thread::SetSelectedFrameByIndexNoisily(uint32_t frame_idx, |
295 | Stream &output_stream) { |
296 | const bool broadcast = true; |
297 | bool success = SetSelectedFrameByIndex(frame_idx, broadcast); |
298 | if (success) { |
299 | StackFrameSP frame_sp = GetSelectedFrame(select_most_relevant: DoNoSelectMostRelevantFrame); |
300 | if (frame_sp) { |
301 | bool already_shown = false; |
302 | SymbolContext frame_sc( |
303 | frame_sp->GetSymbolContext(resolve_scope: eSymbolContextLineEntry)); |
304 | const Debugger &debugger = GetProcess()->GetTarget().GetDebugger(); |
305 | if (debugger.GetUseExternalEditor() && frame_sc.line_entry.GetFile() && |
306 | frame_sc.line_entry.line != 0) { |
307 | if (llvm::Error e = Host::OpenFileInExternalEditor( |
308 | editor: debugger.GetExternalEditor(), file_spec: frame_sc.line_entry.GetFile(), |
309 | line_no: frame_sc.line_entry.line)) { |
310 | LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(e), |
311 | "OpenFileInExternalEditor failed: {0}" ); |
312 | } else { |
313 | already_shown = true; |
314 | } |
315 | } |
316 | |
317 | bool show_frame_info = true; |
318 | bool show_source = !already_shown; |
319 | FrameSelectedCallback(frame: frame_sp.get()); |
320 | return frame_sp->GetStatus(strm&: output_stream, show_frame_info, show_source); |
321 | } |
322 | return false; |
323 | } else |
324 | return false; |
325 | } |
326 | |
327 | void Thread::FrameSelectedCallback(StackFrame *frame) { |
328 | if (!frame) |
329 | return; |
330 | |
331 | if (frame->HasDebugInformation() && |
332 | (GetProcess()->GetWarningsOptimization() || |
333 | GetProcess()->GetWarningsUnsupportedLanguage())) { |
334 | SymbolContext sc = |
335 | frame->GetSymbolContext(resolve_scope: eSymbolContextFunction | eSymbolContextModule); |
336 | GetProcess()->PrintWarningOptimization(sc); |
337 | GetProcess()->PrintWarningUnsupportedLanguage(sc); |
338 | } |
339 | } |
340 | |
341 | lldb::StopInfoSP Thread::GetStopInfo() { |
342 | if (m_destroy_called) |
343 | return m_stop_info_sp; |
344 | |
345 | ThreadPlanSP completed_plan_sp(GetCompletedPlan()); |
346 | ProcessSP process_sp(GetProcess()); |
347 | const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX; |
348 | |
349 | // Here we select the stop info according to priorirty: - m_stop_info_sp (if |
350 | // not trace) - preset value - completed plan stop info - new value with plan |
351 | // from completed plan stack - m_stop_info_sp (trace stop reason is OK now) - |
352 | // ask GetPrivateStopInfo to set stop info |
353 | |
354 | bool have_valid_stop_info = m_stop_info_sp && |
355 | m_stop_info_sp ->IsValid() && |
356 | m_stop_info_stop_id == stop_id; |
357 | bool have_valid_completed_plan = completed_plan_sp && completed_plan_sp->PlanSucceeded(); |
358 | bool plan_failed = completed_plan_sp && !completed_plan_sp->PlanSucceeded(); |
359 | bool plan_overrides_trace = |
360 | have_valid_stop_info && have_valid_completed_plan |
361 | && (m_stop_info_sp->GetStopReason() == eStopReasonTrace); |
362 | |
363 | if (have_valid_stop_info && !plan_overrides_trace && !plan_failed) { |
364 | return m_stop_info_sp; |
365 | } else if (completed_plan_sp) { |
366 | return StopInfo::CreateStopReasonWithPlan( |
367 | plan&: completed_plan_sp, return_valobj_sp: GetReturnValueObject(), expression_variable_sp: GetExpressionVariable()); |
368 | } else { |
369 | GetPrivateStopInfo(); |
370 | return m_stop_info_sp; |
371 | } |
372 | } |
373 | |
374 | void Thread::CalculatePublicStopInfo() { |
375 | ResetStopInfo(); |
376 | SetStopInfo(GetStopInfo()); |
377 | } |
378 | |
379 | lldb::StopInfoSP Thread::GetPrivateStopInfo(bool calculate) { |
380 | if (!calculate) |
381 | return m_stop_info_sp; |
382 | |
383 | if (m_destroy_called) |
384 | return m_stop_info_sp; |
385 | |
386 | ProcessSP process_sp(GetProcess()); |
387 | if (process_sp) { |
388 | const uint32_t process_stop_id = process_sp->GetStopID(); |
389 | if (m_stop_info_stop_id != process_stop_id) { |
390 | // We preserve the old stop info for a variety of reasons: |
391 | // 1) Someone has already updated it by the time we get here |
392 | // 2) We didn't get to execute the breakpoint instruction we stopped at |
393 | // 3) This is a virtual step so we didn't actually run |
394 | // 4) If this thread wasn't allowed to run the last time round. |
395 | if (m_stop_info_sp) { |
396 | if (m_stop_info_sp->IsValid() || IsStillAtLastBreakpointHit() || |
397 | GetCurrentPlan()->IsVirtualStep() |
398 | || GetTemporaryResumeState() == eStateSuspended) |
399 | SetStopInfo(m_stop_info_sp); |
400 | else |
401 | m_stop_info_sp.reset(); |
402 | } |
403 | |
404 | if (!m_stop_info_sp) { |
405 | if (!CalculateStopInfo()) |
406 | SetStopInfo(StopInfoSP()); |
407 | } |
408 | } |
409 | |
410 | // The stop info can be manually set by calling Thread::SetStopInfo() prior |
411 | // to this function ever getting called, so we can't rely on |
412 | // "m_stop_info_stop_id != process_stop_id" as the condition for the if |
413 | // statement below, we must also check the stop info to see if we need to |
414 | // override it. See the header documentation in |
415 | // Architecture::OverrideStopInfo() for more information on the stop |
416 | // info override callback. |
417 | if (m_stop_info_override_stop_id != process_stop_id) { |
418 | m_stop_info_override_stop_id = process_stop_id; |
419 | if (m_stop_info_sp) { |
420 | if (const Architecture *arch = |
421 | process_sp->GetTarget().GetArchitecturePlugin()) |
422 | arch->OverrideStopInfo(thread&: *this); |
423 | } |
424 | } |
425 | } |
426 | |
427 | // If we were resuming the process and it was interrupted, |
428 | // return no stop reason. This thread would like to resume. |
429 | if (m_stop_info_sp && m_stop_info_sp->WasContinueInterrupted(thread&: *this)) |
430 | return {}; |
431 | |
432 | return m_stop_info_sp; |
433 | } |
434 | |
435 | lldb::StopReason Thread::GetStopReason() { |
436 | lldb::StopInfoSP stop_info_sp(GetStopInfo()); |
437 | if (stop_info_sp) |
438 | return stop_info_sp->GetStopReason(); |
439 | return eStopReasonNone; |
440 | } |
441 | |
442 | bool Thread::StopInfoIsUpToDate() const { |
443 | ProcessSP process_sp(GetProcess()); |
444 | if (process_sp) |
445 | return m_stop_info_stop_id == process_sp->GetStopID(); |
446 | else |
447 | return true; // Process is no longer around so stop info is always up to |
448 | // date... |
449 | } |
450 | |
451 | void Thread::ResetStopInfo() { |
452 | if (m_stop_info_sp) { |
453 | m_stop_info_sp.reset(); |
454 | } |
455 | } |
456 | |
457 | void Thread::SetStopInfo(const lldb::StopInfoSP &stop_info_sp) { |
458 | m_stop_info_sp = stop_info_sp; |
459 | if (m_stop_info_sp) { |
460 | m_stop_info_sp->MakeStopInfoValid(); |
461 | // If we are overriding the ShouldReportStop, do that here: |
462 | if (m_override_should_notify != eLazyBoolCalculate) |
463 | m_stop_info_sp->OverrideShouldNotify(override_value: m_override_should_notify == |
464 | eLazyBoolYes); |
465 | } |
466 | |
467 | ProcessSP process_sp(GetProcess()); |
468 | if (process_sp) |
469 | m_stop_info_stop_id = process_sp->GetStopID(); |
470 | else |
471 | m_stop_info_stop_id = UINT32_MAX; |
472 | Log *log = GetLog(mask: LLDBLog::Thread); |
473 | LLDB_LOGF(log, "%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)" , |
474 | static_cast<void *>(this), GetID(), |
475 | stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>" , |
476 | m_stop_info_stop_id); |
477 | } |
478 | |
479 | void Thread::SetShouldReportStop(Vote vote) { |
480 | if (vote == eVoteNoOpinion) |
481 | return; |
482 | else { |
483 | m_override_should_notify = (vote == eVoteYes ? eLazyBoolYes : eLazyBoolNo); |
484 | if (m_stop_info_sp) |
485 | m_stop_info_sp->OverrideShouldNotify(override_value: m_override_should_notify == |
486 | eLazyBoolYes); |
487 | } |
488 | } |
489 | |
490 | void Thread::SetStopInfoToNothing() { |
491 | // Note, we can't just NULL out the private reason, or the native thread |
492 | // implementation will try to go calculate it again. For now, just set it to |
493 | // a Unix Signal with an invalid signal number. |
494 | SetStopInfo( |
495 | StopInfo::CreateStopReasonWithSignal(thread&: *this, LLDB_INVALID_SIGNAL_NUMBER)); |
496 | } |
497 | |
498 | bool Thread::ThreadStoppedForAReason() { return (bool)GetPrivateStopInfo(); } |
499 | |
500 | bool Thread::CheckpointThreadState(ThreadStateCheckpoint &saved_state) { |
501 | saved_state.register_backup_sp.reset(); |
502 | lldb::StackFrameSP frame_sp(GetStackFrameAtIndex(idx: 0)); |
503 | if (frame_sp) { |
504 | lldb::RegisterCheckpointSP reg_checkpoint_sp( |
505 | new RegisterCheckpoint(RegisterCheckpoint::Reason::eExpression)); |
506 | if (reg_checkpoint_sp) { |
507 | lldb::RegisterContextSP reg_ctx_sp(frame_sp->GetRegisterContext()); |
508 | if (reg_ctx_sp && reg_ctx_sp->ReadAllRegisterValues(reg_checkpoint&: *reg_checkpoint_sp)) |
509 | saved_state.register_backup_sp = reg_checkpoint_sp; |
510 | } |
511 | } |
512 | if (!saved_state.register_backup_sp) |
513 | return false; |
514 | |
515 | saved_state.stop_info_sp = GetStopInfo(); |
516 | ProcessSP process_sp(GetProcess()); |
517 | if (process_sp) |
518 | saved_state.orig_stop_id = process_sp->GetStopID(); |
519 | saved_state.current_inlined_depth = GetCurrentInlinedDepth(); |
520 | saved_state.m_completed_plan_checkpoint = |
521 | GetPlans().CheckpointCompletedPlans(); |
522 | |
523 | return true; |
524 | } |
525 | |
526 | bool Thread::RestoreRegisterStateFromCheckpoint( |
527 | ThreadStateCheckpoint &saved_state) { |
528 | if (saved_state.register_backup_sp) { |
529 | lldb::StackFrameSP frame_sp(GetStackFrameAtIndex(idx: 0)); |
530 | if (frame_sp) { |
531 | lldb::RegisterContextSP reg_ctx_sp(frame_sp->GetRegisterContext()); |
532 | if (reg_ctx_sp) { |
533 | bool ret = |
534 | reg_ctx_sp->WriteAllRegisterValues(reg_checkpoint: *saved_state.register_backup_sp); |
535 | |
536 | // Clear out all stack frames as our world just changed. |
537 | ClearStackFrames(); |
538 | reg_ctx_sp->InvalidateIfNeeded(force: true); |
539 | if (m_unwinder_up) |
540 | m_unwinder_up->Clear(); |
541 | return ret; |
542 | } |
543 | } |
544 | } |
545 | return false; |
546 | } |
547 | |
548 | void Thread::RestoreThreadStateFromCheckpoint( |
549 | ThreadStateCheckpoint &saved_state) { |
550 | if (saved_state.stop_info_sp) |
551 | saved_state.stop_info_sp->MakeStopInfoValid(); |
552 | SetStopInfo(saved_state.stop_info_sp); |
553 | GetStackFrameList()->SetCurrentInlinedDepth( |
554 | saved_state.current_inlined_depth); |
555 | GetPlans().RestoreCompletedPlanCheckpoint( |
556 | checkpoint: saved_state.m_completed_plan_checkpoint); |
557 | } |
558 | |
559 | StateType Thread::GetState() const { |
560 | // If any other threads access this we will need a mutex for it |
561 | std::lock_guard<std::recursive_mutex> guard(m_state_mutex); |
562 | return m_state; |
563 | } |
564 | |
565 | void Thread::SetState(StateType state) { |
566 | std::lock_guard<std::recursive_mutex> guard(m_state_mutex); |
567 | m_state = state; |
568 | } |
569 | |
570 | std::string Thread::GetStopDescription() { |
571 | StackFrameSP frame_sp = GetStackFrameAtIndex(idx: 0); |
572 | |
573 | if (!frame_sp) |
574 | return GetStopDescriptionRaw(); |
575 | |
576 | auto recognized_frame_sp = frame_sp->GetRecognizedFrame(); |
577 | |
578 | if (!recognized_frame_sp) |
579 | return GetStopDescriptionRaw(); |
580 | |
581 | std::string recognized_stop_description = |
582 | recognized_frame_sp->GetStopDescription(); |
583 | |
584 | if (!recognized_stop_description.empty()) |
585 | return recognized_stop_description; |
586 | |
587 | return GetStopDescriptionRaw(); |
588 | } |
589 | |
590 | std::string Thread::GetStopDescriptionRaw() { |
591 | StopInfoSP stop_info_sp = GetStopInfo(); |
592 | std::string raw_stop_description; |
593 | if (stop_info_sp && stop_info_sp->IsValid()) { |
594 | raw_stop_description = stop_info_sp->GetDescription(); |
595 | assert((!raw_stop_description.empty() || |
596 | stop_info_sp->GetStopReason() == eStopReasonNone) && |
597 | "StopInfo returned an empty description." ); |
598 | } |
599 | return raw_stop_description; |
600 | } |
601 | |
602 | void Thread::WillStop() { |
603 | ThreadPlan *current_plan = GetCurrentPlan(); |
604 | |
605 | // FIXME: I may decide to disallow threads with no plans. In which |
606 | // case this should go to an assert. |
607 | |
608 | if (!current_plan) |
609 | return; |
610 | |
611 | current_plan->WillStop(); |
612 | } |
613 | |
614 | void Thread::SetupForResume() { |
615 | if (GetResumeState() != eStateSuspended) { |
616 | // If we're at a breakpoint push the step-over breakpoint plan. Do this |
617 | // before telling the current plan it will resume, since we might change |
618 | // what the current plan is. |
619 | |
620 | lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext()); |
621 | if (reg_ctx_sp) { |
622 | const addr_t thread_pc = reg_ctx_sp->GetPC(); |
623 | BreakpointSiteSP bp_site_sp = |
624 | GetProcess()->GetBreakpointSiteList().FindByAddress(addr: thread_pc); |
625 | if (bp_site_sp) { |
626 | // Note, don't assume there's a ThreadPlanStepOverBreakpoint, the |
627 | // target may not require anything special to step over a breakpoint. |
628 | |
629 | ThreadPlan *cur_plan = GetCurrentPlan(); |
630 | |
631 | bool push_step_over_bp_plan = false; |
632 | if (cur_plan->GetKind() == ThreadPlan::eKindStepOverBreakpoint) { |
633 | ThreadPlanStepOverBreakpoint *bp_plan = |
634 | (ThreadPlanStepOverBreakpoint *)cur_plan; |
635 | if (bp_plan->GetBreakpointLoadAddress() != thread_pc) |
636 | push_step_over_bp_plan = true; |
637 | } else |
638 | push_step_over_bp_plan = true; |
639 | |
640 | if (push_step_over_bp_plan) { |
641 | ThreadPlanSP step_bp_plan_sp(new ThreadPlanStepOverBreakpoint(*this)); |
642 | if (step_bp_plan_sp) { |
643 | step_bp_plan_sp->SetPrivate(true); |
644 | |
645 | if (GetCurrentPlan()->RunState() != eStateStepping) { |
646 | ThreadPlanStepOverBreakpoint *step_bp_plan = |
647 | static_cast<ThreadPlanStepOverBreakpoint *>( |
648 | step_bp_plan_sp.get()); |
649 | step_bp_plan->SetAutoContinue(true); |
650 | } |
651 | QueueThreadPlan(plan_sp&: step_bp_plan_sp, abort_other_plans: false); |
652 | } |
653 | } |
654 | } |
655 | } |
656 | } |
657 | } |
658 | |
659 | bool Thread::ShouldResume(StateType resume_state) { |
660 | // At this point clear the completed plan stack. |
661 | GetPlans().WillResume(); |
662 | m_override_should_notify = eLazyBoolCalculate; |
663 | |
664 | StateType prev_resume_state = GetTemporaryResumeState(); |
665 | |
666 | SetTemporaryResumeState(resume_state); |
667 | |
668 | lldb::ThreadSP backing_thread_sp(GetBackingThread()); |
669 | if (backing_thread_sp) |
670 | backing_thread_sp->SetTemporaryResumeState(resume_state); |
671 | |
672 | // Make sure m_stop_info_sp is valid. Don't do this for threads we suspended |
673 | // in the previous run. |
674 | if (prev_resume_state != eStateSuspended) |
675 | GetPrivateStopInfo(); |
676 | |
677 | // This is a little dubious, but we are trying to limit how often we actually |
678 | // fetch stop info from the target, 'cause that slows down single stepping. |
679 | // So assume that if we got to the point where we're about to resume, and we |
680 | // haven't yet had to fetch the stop reason, then it doesn't need to know |
681 | // about the fact that we are resuming... |
682 | const uint32_t process_stop_id = GetProcess()->GetStopID(); |
683 | if (m_stop_info_stop_id == process_stop_id && |
684 | (m_stop_info_sp && m_stop_info_sp->IsValid())) { |
685 | StopInfo *stop_info = GetPrivateStopInfo().get(); |
686 | if (stop_info) |
687 | stop_info->WillResume(resume_state); |
688 | } |
689 | |
690 | // Tell all the plans that we are about to resume in case they need to clear |
691 | // any state. We distinguish between the plan on the top of the stack and the |
692 | // lower plans in case a plan needs to do any special business before it |
693 | // runs. |
694 | |
695 | bool need_to_resume = false; |
696 | ThreadPlan *plan_ptr = GetCurrentPlan(); |
697 | if (plan_ptr) { |
698 | need_to_resume = plan_ptr->WillResume(resume_state, current_plan: true); |
699 | |
700 | while ((plan_ptr = GetPreviousPlan(plan: plan_ptr)) != nullptr) { |
701 | plan_ptr->WillResume(resume_state, current_plan: false); |
702 | } |
703 | |
704 | // If the WillResume for the plan says we are faking a resume, then it will |
705 | // have set an appropriate stop info. In that case, don't reset it here. |
706 | |
707 | if (need_to_resume && resume_state != eStateSuspended) { |
708 | m_stop_info_sp.reset(); |
709 | } |
710 | } |
711 | |
712 | if (need_to_resume) { |
713 | ClearStackFrames(); |
714 | // Let Thread subclasses do any special work they need to prior to resuming |
715 | WillResume(resume_state); |
716 | } |
717 | |
718 | return need_to_resume; |
719 | } |
720 | |
721 | void Thread::DidResume() { |
722 | SetResumeSignal(LLDB_INVALID_SIGNAL_NUMBER); |
723 | // This will get recomputed each time when we stop. |
724 | SetShouldRunBeforePublicStop(false); |
725 | } |
726 | |
727 | void Thread::DidStop() { SetState(eStateStopped); } |
728 | |
729 | bool Thread::ShouldStop(Event *event_ptr) { |
730 | ThreadPlan *current_plan = GetCurrentPlan(); |
731 | |
732 | bool should_stop = true; |
733 | |
734 | Log *log = GetLog(mask: LLDBLog::Step); |
735 | |
736 | if (GetResumeState() == eStateSuspended) { |
737 | LLDB_LOGF(log, |
738 | "Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 |
739 | ", should_stop = 0 (ignore since thread was suspended)" , |
740 | __FUNCTION__, GetID(), GetProtocolID()); |
741 | return false; |
742 | } |
743 | |
744 | if (GetTemporaryResumeState() == eStateSuspended) { |
745 | LLDB_LOGF(log, |
746 | "Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 |
747 | ", should_stop = 0 (ignore since thread was suspended)" , |
748 | __FUNCTION__, GetID(), GetProtocolID()); |
749 | return false; |
750 | } |
751 | |
752 | // Based on the current thread plan and process stop info, check if this |
753 | // thread caused the process to stop. NOTE: this must take place before the |
754 | // plan is moved from the current plan stack to the completed plan stack. |
755 | if (!ThreadStoppedForAReason()) { |
756 | LLDB_LOGF(log, |
757 | "Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 |
758 | ", pc = 0x%16.16" PRIx64 |
759 | ", should_stop = 0 (ignore since no stop reason)" , |
760 | __FUNCTION__, GetID(), GetProtocolID(), |
761 | GetRegisterContext() ? GetRegisterContext()->GetPC() |
762 | : LLDB_INVALID_ADDRESS); |
763 | return false; |
764 | } |
765 | |
766 | // Clear the "must run me before stop" if it was set: |
767 | SetShouldRunBeforePublicStop(false); |
768 | |
769 | if (log) { |
770 | LLDB_LOGF(log, |
771 | "Thread::%s(%p) for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 |
772 | ", pc = 0x%16.16" PRIx64, |
773 | __FUNCTION__, static_cast<void *>(this), GetID(), GetProtocolID(), |
774 | GetRegisterContext() ? GetRegisterContext()->GetPC() |
775 | : LLDB_INVALID_ADDRESS); |
776 | LLDB_LOGF(log, "^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^" ); |
777 | StreamString s; |
778 | s.IndentMore(); |
779 | GetProcess()->DumpThreadPlansForTID( |
780 | strm&: s, tid: GetID(), desc_level: eDescriptionLevelVerbose, internal: true /* internal */, |
781 | condense_trivial: false /* condense_trivial */, skip_unreported_plans: true /* skip_unreported */); |
782 | LLDB_LOGF(log, "Plan stack initial state:\n%s" , s.GetData()); |
783 | } |
784 | |
785 | // The top most plan always gets to do the trace log... |
786 | current_plan->DoTraceLog(); |
787 | |
788 | // First query the stop info's ShouldStopSynchronous. This handles |
789 | // "synchronous" stop reasons, for example the breakpoint command on internal |
790 | // breakpoints. If a synchronous stop reason says we should not stop, then |
791 | // we don't have to do any more work on this stop. |
792 | StopInfoSP private_stop_info(GetPrivateStopInfo()); |
793 | if (private_stop_info && |
794 | !private_stop_info->ShouldStopSynchronous(event_ptr)) { |
795 | LLDB_LOGF(log, "StopInfo::ShouldStop async callback says we should not " |
796 | "stop, returning ShouldStop of false." ); |
797 | return false; |
798 | } |
799 | |
800 | // If we've already been restarted, don't query the plans since the state |
801 | // they would examine is not current. |
802 | if (Process::ProcessEventData::GetRestartedFromEvent(event_ptr)) |
803 | return false; |
804 | |
805 | // Before the plans see the state of the world, calculate the current inlined |
806 | // depth. |
807 | GetStackFrameList()->CalculateCurrentInlinedDepth(); |
808 | |
809 | // If the base plan doesn't understand why we stopped, then we have to find a |
810 | // plan that does. If that plan is still working, then we don't need to do |
811 | // any more work. If the plan that explains the stop is done, then we should |
812 | // pop all the plans below it, and pop it, and then let the plans above it |
813 | // decide whether they still need to do more work. |
814 | |
815 | bool done_processing_current_plan = false; |
816 | |
817 | if (!current_plan->PlanExplainsStop(event_ptr)) { |
818 | if (current_plan->TracerExplainsStop()) { |
819 | done_processing_current_plan = true; |
820 | should_stop = false; |
821 | } else { |
822 | // If the current plan doesn't explain the stop, then find one that does |
823 | // and let it handle the situation. |
824 | ThreadPlan *plan_ptr = current_plan; |
825 | while ((plan_ptr = GetPreviousPlan(plan: plan_ptr)) != nullptr) { |
826 | if (plan_ptr->PlanExplainsStop(event_ptr)) { |
827 | LLDB_LOGF(log, "Plan %s explains stop." , plan_ptr->GetName()); |
828 | |
829 | should_stop = plan_ptr->ShouldStop(event_ptr); |
830 | |
831 | // plan_ptr explains the stop, next check whether plan_ptr is done, |
832 | // if so, then we should take it and all the plans below it off the |
833 | // stack. |
834 | |
835 | if (plan_ptr->MischiefManaged()) { |
836 | // We're going to pop the plans up to and including the plan that |
837 | // explains the stop. |
838 | ThreadPlan *prev_plan_ptr = GetPreviousPlan(plan: plan_ptr); |
839 | |
840 | do { |
841 | if (should_stop) |
842 | current_plan->WillStop(); |
843 | PopPlan(); |
844 | } while ((current_plan = GetCurrentPlan()) != prev_plan_ptr); |
845 | // Now, if the responsible plan was not "Okay to discard" then |
846 | // we're done, otherwise we forward this to the next plan in the |
847 | // stack below. |
848 | done_processing_current_plan = |
849 | (plan_ptr->IsControllingPlan() && !plan_ptr->OkayToDiscard()); |
850 | } else { |
851 | bool should_force_run = plan_ptr->ShouldRunBeforePublicStop(); |
852 | if (should_force_run) { |
853 | SetShouldRunBeforePublicStop(true); |
854 | should_stop = false; |
855 | } |
856 | done_processing_current_plan = true; |
857 | } |
858 | break; |
859 | } |
860 | } |
861 | } |
862 | } |
863 | |
864 | if (!done_processing_current_plan) { |
865 | bool override_stop = false; |
866 | |
867 | // We're starting from the base plan, so just let it decide; |
868 | if (current_plan->IsBasePlan()) { |
869 | should_stop = current_plan->ShouldStop(event_ptr); |
870 | LLDB_LOGF(log, "Base plan says should stop: %i." , should_stop); |
871 | } else { |
872 | // Otherwise, don't let the base plan override what the other plans say |
873 | // to do, since presumably if there were other plans they would know what |
874 | // to do... |
875 | while (true) { |
876 | if (current_plan->IsBasePlan()) |
877 | break; |
878 | |
879 | should_stop = current_plan->ShouldStop(event_ptr); |
880 | LLDB_LOGF(log, "Plan %s should stop: %d." , current_plan->GetName(), |
881 | should_stop); |
882 | if (current_plan->MischiefManaged()) { |
883 | if (should_stop) |
884 | current_plan->WillStop(); |
885 | |
886 | if (current_plan->ShouldAutoContinue(event_ptr)) { |
887 | override_stop = true; |
888 | LLDB_LOGF(log, "Plan %s auto-continue: true." , |
889 | current_plan->GetName()); |
890 | } |
891 | |
892 | // If a Controlling Plan wants to stop, we let it. Otherwise, see if |
893 | // the plan's parent wants to stop. |
894 | |
895 | PopPlan(); |
896 | if (should_stop && current_plan->IsControllingPlan() && |
897 | !current_plan->OkayToDiscard()) { |
898 | break; |
899 | } |
900 | |
901 | current_plan = GetCurrentPlan(); |
902 | if (current_plan == nullptr) { |
903 | break; |
904 | } |
905 | } else { |
906 | break; |
907 | } |
908 | } |
909 | } |
910 | |
911 | if (override_stop) |
912 | should_stop = false; |
913 | } |
914 | |
915 | // One other potential problem is that we set up a controlling plan, then stop |
916 | // in before it is complete - for instance by hitting a breakpoint during a |
917 | // step-over - then do some step/finish/etc operations that wind up past the |
918 | // end point condition of the initial plan. We don't want to strand the |
919 | // original plan on the stack, This code clears stale plans off the stack. |
920 | |
921 | if (should_stop) { |
922 | ThreadPlan *plan_ptr = GetCurrentPlan(); |
923 | |
924 | // Discard the stale plans and all plans below them in the stack, plus move |
925 | // the completed plans to the completed plan stack |
926 | while (!plan_ptr->IsBasePlan()) { |
927 | bool stale = plan_ptr->IsPlanStale(); |
928 | ThreadPlan *examined_plan = plan_ptr; |
929 | plan_ptr = GetPreviousPlan(plan: examined_plan); |
930 | |
931 | if (stale) { |
932 | LLDB_LOGF( |
933 | log, |
934 | "Plan %s being discarded in cleanup, it says it is already done." , |
935 | examined_plan->GetName()); |
936 | while (GetCurrentPlan() != examined_plan) { |
937 | DiscardPlan(); |
938 | } |
939 | if (examined_plan->IsPlanComplete()) { |
940 | // plan is complete but does not explain the stop (example: step to a |
941 | // line with breakpoint), let us move the plan to |
942 | // completed_plan_stack anyway |
943 | PopPlan(); |
944 | } else |
945 | DiscardPlan(); |
946 | } |
947 | } |
948 | } |
949 | |
950 | if (log) { |
951 | StreamString s; |
952 | s.IndentMore(); |
953 | GetProcess()->DumpThreadPlansForTID( |
954 | strm&: s, tid: GetID(), desc_level: eDescriptionLevelVerbose, internal: true /* internal */, |
955 | condense_trivial: false /* condense_trivial */, skip_unreported_plans: true /* skip_unreported */); |
956 | LLDB_LOGF(log, "Plan stack final state:\n%s" , s.GetData()); |
957 | LLDB_LOGF(log, "vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv" , |
958 | should_stop); |
959 | } |
960 | return should_stop; |
961 | } |
962 | |
963 | Vote Thread::ShouldReportStop(Event *event_ptr) { |
964 | StateType thread_state = GetResumeState(); |
965 | StateType temp_thread_state = GetTemporaryResumeState(); |
966 | |
967 | Log *log = GetLog(mask: LLDBLog::Step); |
968 | |
969 | if (thread_state == eStateSuspended || thread_state == eStateInvalid) { |
970 | LLDB_LOGF(log, |
971 | "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 |
972 | ": returning vote %i (state was suspended or invalid)" , |
973 | GetID(), eVoteNoOpinion); |
974 | return eVoteNoOpinion; |
975 | } |
976 | |
977 | if (temp_thread_state == eStateSuspended || |
978 | temp_thread_state == eStateInvalid) { |
979 | LLDB_LOGF(log, |
980 | "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 |
981 | ": returning vote %i (temporary state was suspended or invalid)" , |
982 | GetID(), eVoteNoOpinion); |
983 | return eVoteNoOpinion; |
984 | } |
985 | |
986 | if (!ThreadStoppedForAReason()) { |
987 | LLDB_LOGF(log, |
988 | "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 |
989 | ": returning vote %i (thread didn't stop for a reason.)" , |
990 | GetID(), eVoteNoOpinion); |
991 | return eVoteNoOpinion; |
992 | } |
993 | |
994 | if (GetPlans().AnyCompletedPlans()) { |
995 | // Pass skip_private = false to GetCompletedPlan, since we want to ask |
996 | // the last plan, regardless of whether it is private or not. |
997 | LLDB_LOGF(log, |
998 | "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 |
999 | ": returning vote for complete stack's back plan" , |
1000 | GetID()); |
1001 | return GetPlans().GetCompletedPlan(skip_private: false)->ShouldReportStop(event_ptr); |
1002 | } else { |
1003 | Vote thread_vote = eVoteNoOpinion; |
1004 | ThreadPlan *plan_ptr = GetCurrentPlan(); |
1005 | while (true) { |
1006 | if (plan_ptr->PlanExplainsStop(event_ptr)) { |
1007 | thread_vote = plan_ptr->ShouldReportStop(event_ptr); |
1008 | break; |
1009 | } |
1010 | if (plan_ptr->IsBasePlan()) |
1011 | break; |
1012 | else |
1013 | plan_ptr = GetPreviousPlan(plan: plan_ptr); |
1014 | } |
1015 | LLDB_LOGF(log, |
1016 | "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 |
1017 | ": returning vote %i for current plan" , |
1018 | GetID(), thread_vote); |
1019 | |
1020 | return thread_vote; |
1021 | } |
1022 | } |
1023 | |
1024 | Vote Thread::ShouldReportRun(Event *event_ptr) { |
1025 | StateType thread_state = GetResumeState(); |
1026 | |
1027 | if (thread_state == eStateSuspended || thread_state == eStateInvalid) { |
1028 | return eVoteNoOpinion; |
1029 | } |
1030 | |
1031 | Log *log = GetLog(mask: LLDBLog::Step); |
1032 | if (GetPlans().AnyCompletedPlans()) { |
1033 | // Pass skip_private = false to GetCompletedPlan, since we want to ask |
1034 | // the last plan, regardless of whether it is private or not. |
1035 | LLDB_LOGF(log, |
1036 | "Current Plan for thread %d(%p) (0x%4.4" PRIx64 |
1037 | ", %s): %s being asked whether we should report run." , |
1038 | GetIndexID(), static_cast<void *>(this), GetID(), |
1039 | StateAsCString(GetTemporaryResumeState()), |
1040 | GetCompletedPlan()->GetName()); |
1041 | |
1042 | return GetPlans().GetCompletedPlan(skip_private: false)->ShouldReportRun(event_ptr); |
1043 | } else { |
1044 | LLDB_LOGF(log, |
1045 | "Current Plan for thread %d(%p) (0x%4.4" PRIx64 |
1046 | ", %s): %s being asked whether we should report run." , |
1047 | GetIndexID(), static_cast<void *>(this), GetID(), |
1048 | StateAsCString(GetTemporaryResumeState()), |
1049 | GetCurrentPlan()->GetName()); |
1050 | |
1051 | return GetCurrentPlan()->ShouldReportRun(event_ptr); |
1052 | } |
1053 | } |
1054 | |
1055 | bool Thread::MatchesSpec(const ThreadSpec *spec) { |
1056 | return (spec == nullptr) ? true : spec->ThreadPassesBasicTests(thread&: *this); |
1057 | } |
1058 | |
1059 | ThreadPlanStack &Thread::GetPlans() const { |
1060 | ThreadPlanStack *plans = GetProcess()->FindThreadPlans(tid: GetID()); |
1061 | if (plans) |
1062 | return *plans; |
1063 | |
1064 | // History threads don't have a thread plan, but they do ask get asked to |
1065 | // describe themselves, which usually involves pulling out the stop reason. |
1066 | // That in turn will check for a completed plan on the ThreadPlanStack. |
1067 | // Instead of special-casing at that point, we return a Stack with a |
1068 | // ThreadPlanNull as its base plan. That will give the right answers to the |
1069 | // queries GetDescription makes, and only assert if you try to run the thread. |
1070 | if (!m_null_plan_stack_up) |
1071 | m_null_plan_stack_up = std::make_unique<ThreadPlanStack>(args: *this, args: true); |
1072 | return *m_null_plan_stack_up; |
1073 | } |
1074 | |
1075 | void Thread::PushPlan(ThreadPlanSP thread_plan_sp) { |
1076 | assert(thread_plan_sp && "Don't push an empty thread plan." ); |
1077 | |
1078 | Log *log = GetLog(mask: LLDBLog::Step); |
1079 | if (log) { |
1080 | StreamString s; |
1081 | thread_plan_sp->GetDescription(s: &s, level: lldb::eDescriptionLevelFull); |
1082 | LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 "." , |
1083 | static_cast<void *>(this), s.GetData(), |
1084 | thread_plan_sp->GetThread().GetID()); |
1085 | } |
1086 | |
1087 | GetPlans().PushPlan(new_plan_sp: std::move(thread_plan_sp)); |
1088 | } |
1089 | |
1090 | void Thread::PopPlan() { |
1091 | Log *log = GetLog(mask: LLDBLog::Step); |
1092 | ThreadPlanSP popped_plan_sp = GetPlans().PopPlan(); |
1093 | if (log) { |
1094 | LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 "." , |
1095 | popped_plan_sp->GetName(), popped_plan_sp->GetThread().GetID()); |
1096 | } |
1097 | } |
1098 | |
1099 | void Thread::DiscardPlan() { |
1100 | Log *log = GetLog(mask: LLDBLog::Step); |
1101 | ThreadPlanSP discarded_plan_sp = GetPlans().DiscardPlan(); |
1102 | |
1103 | LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 "." , |
1104 | discarded_plan_sp->GetName(), |
1105 | discarded_plan_sp->GetThread().GetID()); |
1106 | } |
1107 | |
1108 | void Thread::AutoCompleteThreadPlans(CompletionRequest &request) const { |
1109 | const ThreadPlanStack &plans = GetPlans(); |
1110 | if (!plans.AnyPlans()) |
1111 | return; |
1112 | |
1113 | // Iterate from the second plan (index: 1) to skip the base plan. |
1114 | ThreadPlanSP p; |
1115 | uint32_t i = 1; |
1116 | while ((p = plans.GetPlanByIndex(plan_idx: i, skip_private: false))) { |
1117 | StreamString strm; |
1118 | p->GetDescription(s: &strm, level: eDescriptionLevelInitial); |
1119 | request.TryCompleteCurrentArg(completion: std::to_string(val: i), description: strm.GetString()); |
1120 | i++; |
1121 | } |
1122 | } |
1123 | |
1124 | ThreadPlan *Thread::GetCurrentPlan() const { |
1125 | return GetPlans().GetCurrentPlan().get(); |
1126 | } |
1127 | |
1128 | ThreadPlanSP Thread::GetCompletedPlan() const { |
1129 | return GetPlans().GetCompletedPlan(); |
1130 | } |
1131 | |
1132 | ValueObjectSP Thread::GetReturnValueObject() const { |
1133 | return GetPlans().GetReturnValueObject(); |
1134 | } |
1135 | |
1136 | ExpressionVariableSP Thread::GetExpressionVariable() const { |
1137 | return GetPlans().GetExpressionVariable(); |
1138 | } |
1139 | |
1140 | bool Thread::IsThreadPlanDone(ThreadPlan *plan) const { |
1141 | return GetPlans().IsPlanDone(plan); |
1142 | } |
1143 | |
1144 | bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) const { |
1145 | return GetPlans().WasPlanDiscarded(plan); |
1146 | } |
1147 | |
1148 | bool Thread::CompletedPlanOverridesBreakpoint() const { |
1149 | return GetPlans().AnyCompletedPlans(); |
1150 | } |
1151 | |
1152 | ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) const{ |
1153 | return GetPlans().GetPreviousPlan(current_plan); |
1154 | } |
1155 | |
1156 | Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, |
1157 | bool abort_other_plans) { |
1158 | Status status; |
1159 | StreamString s; |
1160 | if (!thread_plan_sp->ValidatePlan(error: &s)) { |
1161 | DiscardThreadPlansUpToPlan(up_to_plan_sp&: thread_plan_sp); |
1162 | thread_plan_sp.reset(); |
1163 | status.SetErrorString(s.GetString()); |
1164 | return status; |
1165 | } |
1166 | |
1167 | if (abort_other_plans) |
1168 | DiscardThreadPlans(force: true); |
1169 | |
1170 | PushPlan(thread_plan_sp); |
1171 | |
1172 | // This seems a little funny, but I don't want to have to split up the |
1173 | // constructor and the DidPush in the scripted plan, that seems annoying. |
1174 | // That means the constructor has to be in DidPush. So I have to validate the |
1175 | // plan AFTER pushing it, and then take it off again... |
1176 | if (!thread_plan_sp->ValidatePlan(error: &s)) { |
1177 | DiscardThreadPlansUpToPlan(up_to_plan_sp&: thread_plan_sp); |
1178 | thread_plan_sp.reset(); |
1179 | status.SetErrorString(s.GetString()); |
1180 | return status; |
1181 | } |
1182 | |
1183 | return status; |
1184 | } |
1185 | |
1186 | bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t plan_index) { |
1187 | // Count the user thread plans from the back end to get the number of the one |
1188 | // we want to discard: |
1189 | |
1190 | ThreadPlan *up_to_plan_ptr = GetPlans().GetPlanByIndex(plan_idx: plan_index).get(); |
1191 | if (up_to_plan_ptr == nullptr) |
1192 | return false; |
1193 | |
1194 | DiscardThreadPlansUpToPlan(up_to_plan_ptr); |
1195 | return true; |
1196 | } |
1197 | |
1198 | void Thread::DiscardThreadPlansUpToPlan(lldb::ThreadPlanSP &up_to_plan_sp) { |
1199 | DiscardThreadPlansUpToPlan(up_to_plan_ptr: up_to_plan_sp.get()); |
1200 | } |
1201 | |
1202 | void Thread::DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { |
1203 | Log *log = GetLog(mask: LLDBLog::Step); |
1204 | LLDB_LOGF(log, |
1205 | "Discarding thread plans for thread tid = 0x%4.4" PRIx64 |
1206 | ", up to %p" , |
1207 | GetID(), static_cast<void *>(up_to_plan_ptr)); |
1208 | GetPlans().DiscardPlansUpToPlan(up_to_plan_ptr); |
1209 | } |
1210 | |
1211 | void Thread::DiscardThreadPlans(bool force) { |
1212 | Log *log = GetLog(mask: LLDBLog::Step); |
1213 | if (log) { |
1214 | LLDB_LOGF(log, |
1215 | "Discarding thread plans for thread (tid = 0x%4.4" PRIx64 |
1216 | ", force %d)" , |
1217 | GetID(), force); |
1218 | } |
1219 | |
1220 | if (force) { |
1221 | GetPlans().DiscardAllPlans(); |
1222 | return; |
1223 | } |
1224 | GetPlans().DiscardConsultingControllingPlans(); |
1225 | } |
1226 | |
1227 | Status Thread::UnwindInnermostExpression() { |
1228 | Status error; |
1229 | ThreadPlan *innermost_expr_plan = GetPlans().GetInnermostExpression(); |
1230 | if (!innermost_expr_plan) { |
1231 | error.SetErrorString("No expressions currently active on this thread" ); |
1232 | return error; |
1233 | } |
1234 | DiscardThreadPlansUpToPlan(up_to_plan_ptr: innermost_expr_plan); |
1235 | return error; |
1236 | } |
1237 | |
1238 | ThreadPlanSP Thread::QueueBasePlan(bool abort_other_plans) { |
1239 | ThreadPlanSP thread_plan_sp(new ThreadPlanBase(*this)); |
1240 | QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1241 | return thread_plan_sp; |
1242 | } |
1243 | |
1244 | ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction( |
1245 | bool step_over, bool abort_other_plans, bool stop_other_threads, |
1246 | Status &status) { |
1247 | ThreadPlanSP thread_plan_sp(new ThreadPlanStepInstruction( |
1248 | *this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion)); |
1249 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1250 | return thread_plan_sp; |
1251 | } |
1252 | |
1253 | ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( |
1254 | bool abort_other_plans, const AddressRange &range, |
1255 | const SymbolContext &addr_context, lldb::RunMode stop_other_threads, |
1256 | Status &status, LazyBool step_out_avoids_code_withoug_debug_info) { |
1257 | ThreadPlanSP thread_plan_sp; |
1258 | thread_plan_sp = std::make_shared<ThreadPlanStepOverRange>( |
1259 | args&: *this, args: range, args: addr_context, args&: stop_other_threads, |
1260 | args&: step_out_avoids_code_withoug_debug_info); |
1261 | |
1262 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1263 | return thread_plan_sp; |
1264 | } |
1265 | |
1266 | // Call the QueueThreadPlanForStepOverRange method which takes an address |
1267 | // range. |
1268 | ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( |
1269 | bool abort_other_plans, const LineEntry &line_entry, |
1270 | const SymbolContext &addr_context, lldb::RunMode stop_other_threads, |
1271 | Status &status, LazyBool step_out_avoids_code_withoug_debug_info) { |
1272 | const bool include_inlined_functions = true; |
1273 | auto address_range = |
1274 | line_entry.GetSameLineContiguousAddressRange(include_inlined_functions); |
1275 | return QueueThreadPlanForStepOverRange( |
1276 | abort_other_plans, range: address_range, addr_context, stop_other_threads, |
1277 | status, step_out_avoids_code_withoug_debug_info); |
1278 | } |
1279 | |
1280 | ThreadPlanSP Thread::QueueThreadPlanForStepInRange( |
1281 | bool abort_other_plans, const AddressRange &range, |
1282 | const SymbolContext &addr_context, const char *step_in_target, |
1283 | lldb::RunMode stop_other_threads, Status &status, |
1284 | LazyBool step_in_avoids_code_without_debug_info, |
1285 | LazyBool step_out_avoids_code_without_debug_info) { |
1286 | ThreadPlanSP thread_plan_sp(new ThreadPlanStepInRange( |
1287 | *this, range, addr_context, step_in_target, stop_other_threads, |
1288 | step_in_avoids_code_without_debug_info, |
1289 | step_out_avoids_code_without_debug_info)); |
1290 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1291 | return thread_plan_sp; |
1292 | } |
1293 | |
1294 | // Call the QueueThreadPlanForStepInRange method which takes an address range. |
1295 | ThreadPlanSP Thread::QueueThreadPlanForStepInRange( |
1296 | bool abort_other_plans, const LineEntry &line_entry, |
1297 | const SymbolContext &addr_context, const char *step_in_target, |
1298 | lldb::RunMode stop_other_threads, Status &status, |
1299 | LazyBool step_in_avoids_code_without_debug_info, |
1300 | LazyBool step_out_avoids_code_without_debug_info) { |
1301 | const bool include_inlined_functions = false; |
1302 | return QueueThreadPlanForStepInRange( |
1303 | abort_other_plans, |
1304 | range: line_entry.GetSameLineContiguousAddressRange(include_inlined_functions), |
1305 | addr_context, step_in_target, stop_other_threads, status, |
1306 | step_in_avoids_code_without_debug_info, |
1307 | step_out_avoids_code_without_debug_info); |
1308 | } |
1309 | |
1310 | ThreadPlanSP Thread::QueueThreadPlanForStepOut( |
1311 | bool abort_other_plans, SymbolContext *addr_context, bool first_insn, |
1312 | bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote, |
1313 | uint32_t frame_idx, Status &status, |
1314 | LazyBool step_out_avoids_code_without_debug_info) { |
1315 | ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( |
1316 | *this, addr_context, first_insn, stop_other_threads, report_stop_vote, |
1317 | report_run_vote, frame_idx, step_out_avoids_code_without_debug_info)); |
1318 | |
1319 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1320 | return thread_plan_sp; |
1321 | } |
1322 | |
1323 | ThreadPlanSP Thread::QueueThreadPlanForStepOutNoShouldStop( |
1324 | bool abort_other_plans, SymbolContext *addr_context, bool first_insn, |
1325 | bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote, |
1326 | uint32_t frame_idx, Status &status, bool continue_to_next_branch) { |
1327 | const bool calculate_return_value = |
1328 | false; // No need to calculate the return value here. |
1329 | ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( |
1330 | *this, addr_context, first_insn, stop_other_threads, report_stop_vote, |
1331 | report_run_vote, frame_idx, eLazyBoolNo, continue_to_next_branch, |
1332 | calculate_return_value)); |
1333 | |
1334 | ThreadPlanStepOut *new_plan = |
1335 | static_cast<ThreadPlanStepOut *>(thread_plan_sp.get()); |
1336 | new_plan->ClearShouldStopHereCallbacks(); |
1337 | |
1338 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1339 | return thread_plan_sp; |
1340 | } |
1341 | |
1342 | ThreadPlanSP Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id, |
1343 | bool abort_other_plans, |
1344 | bool stop_other_threads, |
1345 | Status &status) { |
1346 | ThreadPlanSP thread_plan_sp( |
1347 | new ThreadPlanStepThrough(*this, return_stack_id, stop_other_threads)); |
1348 | if (!thread_plan_sp || !thread_plan_sp->ValidatePlan(error: nullptr)) |
1349 | return ThreadPlanSP(); |
1350 | |
1351 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1352 | return thread_plan_sp; |
1353 | } |
1354 | |
1355 | ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(bool abort_other_plans, |
1356 | Address &target_addr, |
1357 | bool stop_other_threads, |
1358 | Status &status) { |
1359 | ThreadPlanSP thread_plan_sp( |
1360 | new ThreadPlanRunToAddress(*this, target_addr, stop_other_threads)); |
1361 | |
1362 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1363 | return thread_plan_sp; |
1364 | } |
1365 | |
1366 | ThreadPlanSP Thread::QueueThreadPlanForStepUntil( |
1367 | bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses, |
1368 | bool stop_other_threads, uint32_t frame_idx, Status &status) { |
1369 | ThreadPlanSP thread_plan_sp(new ThreadPlanStepUntil( |
1370 | *this, address_list, num_addresses, stop_other_threads, frame_idx)); |
1371 | |
1372 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1373 | return thread_plan_sp; |
1374 | } |
1375 | |
1376 | lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( |
1377 | bool abort_other_plans, const char *class_name, |
1378 | StructuredData::ObjectSP , bool stop_other_threads, |
1379 | Status &status) { |
1380 | |
1381 | ThreadPlanSP thread_plan_sp(new ThreadPlanPython( |
1382 | *this, class_name, StructuredDataImpl(extra_args_sp))); |
1383 | thread_plan_sp->SetStopOthers(stop_other_threads); |
1384 | status = QueueThreadPlan(thread_plan_sp, abort_other_plans); |
1385 | return thread_plan_sp; |
1386 | } |
1387 | |
1388 | uint32_t Thread::GetIndexID() const { return m_index_id; } |
1389 | |
1390 | TargetSP Thread::CalculateTarget() { |
1391 | TargetSP target_sp; |
1392 | ProcessSP process_sp(GetProcess()); |
1393 | if (process_sp) |
1394 | target_sp = process_sp->CalculateTarget(); |
1395 | return target_sp; |
1396 | } |
1397 | |
1398 | ProcessSP Thread::CalculateProcess() { return GetProcess(); } |
1399 | |
1400 | ThreadSP Thread::CalculateThread() { return shared_from_this(); } |
1401 | |
1402 | StackFrameSP Thread::CalculateStackFrame() { return StackFrameSP(); } |
1403 | |
1404 | void Thread::CalculateExecutionContext(ExecutionContext &exe_ctx) { |
1405 | exe_ctx.SetContext(shared_from_this()); |
1406 | } |
1407 | |
1408 | StackFrameListSP Thread::GetStackFrameList() { |
1409 | std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); |
1410 | |
1411 | if (!m_curr_frames_sp) |
1412 | m_curr_frames_sp = |
1413 | std::make_shared<StackFrameList>(args&: *this, args&: m_prev_frames_sp, args: true); |
1414 | |
1415 | return m_curr_frames_sp; |
1416 | } |
1417 | |
1418 | std::optional<addr_t> Thread::GetPreviousFrameZeroPC() { |
1419 | return m_prev_framezero_pc; |
1420 | } |
1421 | |
1422 | void Thread::ClearStackFrames() { |
1423 | std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); |
1424 | |
1425 | GetUnwinder().Clear(); |
1426 | m_prev_framezero_pc.reset(); |
1427 | if (RegisterContextSP reg_ctx_sp = GetRegisterContext()) |
1428 | m_prev_framezero_pc = reg_ctx_sp->GetPC(); |
1429 | |
1430 | // Only store away the old "reference" StackFrameList if we got all its |
1431 | // frames: |
1432 | // FIXME: At some point we can try to splice in the frames we have fetched |
1433 | // into the new frame as we make it, but let's not try that now. |
1434 | if (m_curr_frames_sp && m_curr_frames_sp->GetAllFramesFetched()) |
1435 | m_prev_frames_sp.swap(other&: m_curr_frames_sp); |
1436 | m_curr_frames_sp.reset(); |
1437 | |
1438 | m_extended_info.reset(); |
1439 | m_extended_info_fetched = false; |
1440 | } |
1441 | |
1442 | lldb::StackFrameSP Thread::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) { |
1443 | return GetStackFrameList()->GetFrameWithConcreteFrameIndex(unwind_idx); |
1444 | } |
1445 | |
1446 | Status Thread::ReturnFromFrameWithIndex(uint32_t frame_idx, |
1447 | lldb::ValueObjectSP return_value_sp, |
1448 | bool broadcast) { |
1449 | StackFrameSP frame_sp = GetStackFrameAtIndex(idx: frame_idx); |
1450 | Status return_error; |
1451 | |
1452 | if (!frame_sp) { |
1453 | return_error.SetErrorStringWithFormat( |
1454 | "Could not find frame with index %d in thread 0x%" PRIx64 "." , |
1455 | frame_idx, GetID()); |
1456 | } |
1457 | |
1458 | return ReturnFromFrame(frame_sp, return_value_sp, broadcast); |
1459 | } |
1460 | |
1461 | Status Thread::ReturnFromFrame(lldb::StackFrameSP frame_sp, |
1462 | lldb::ValueObjectSP return_value_sp, |
1463 | bool broadcast) { |
1464 | Status return_error; |
1465 | |
1466 | if (!frame_sp) { |
1467 | return_error.SetErrorString("Can't return to a null frame." ); |
1468 | return return_error; |
1469 | } |
1470 | |
1471 | Thread *thread = frame_sp->GetThread().get(); |
1472 | uint32_t older_frame_idx = frame_sp->GetFrameIndex() + 1; |
1473 | StackFrameSP older_frame_sp = thread->GetStackFrameAtIndex(idx: older_frame_idx); |
1474 | if (!older_frame_sp) { |
1475 | return_error.SetErrorString("No older frame to return to." ); |
1476 | return return_error; |
1477 | } |
1478 | |
1479 | if (return_value_sp) { |
1480 | lldb::ABISP abi = thread->GetProcess()->GetABI(); |
1481 | if (!abi) { |
1482 | return_error.SetErrorString("Could not find ABI to set return value." ); |
1483 | return return_error; |
1484 | } |
1485 | SymbolContext sc = frame_sp->GetSymbolContext(resolve_scope: eSymbolContextFunction); |
1486 | |
1487 | // FIXME: ValueObject::Cast doesn't currently work correctly, at least not |
1488 | // for scalars. |
1489 | // Turn that back on when that works. |
1490 | if (/* DISABLES CODE */ (false) && sc.function != nullptr) { |
1491 | Type *function_type = sc.function->GetType(); |
1492 | if (function_type) { |
1493 | CompilerType return_type = |
1494 | sc.function->GetCompilerType().GetFunctionReturnType(); |
1495 | if (return_type) { |
1496 | StreamString s; |
1497 | return_type.DumpTypeDescription(s: &s); |
1498 | ValueObjectSP cast_value_sp = return_value_sp->Cast(compiler_type: return_type); |
1499 | if (cast_value_sp) { |
1500 | cast_value_sp->SetFormat(eFormatHex); |
1501 | return_value_sp = cast_value_sp; |
1502 | } |
1503 | } |
1504 | } |
1505 | } |
1506 | |
1507 | return_error = abi->SetReturnValueObject(frame_sp&: older_frame_sp, new_value&: return_value_sp); |
1508 | if (!return_error.Success()) |
1509 | return return_error; |
1510 | } |
1511 | |
1512 | // Now write the return registers for the chosen frame: Note, we can't use |
1513 | // ReadAllRegisterValues->WriteAllRegisterValues, since the read & write cook |
1514 | // their data |
1515 | |
1516 | StackFrameSP youngest_frame_sp = thread->GetStackFrameAtIndex(idx: 0); |
1517 | if (youngest_frame_sp) { |
1518 | lldb::RegisterContextSP reg_ctx_sp(youngest_frame_sp->GetRegisterContext()); |
1519 | if (reg_ctx_sp) { |
1520 | bool copy_success = reg_ctx_sp->CopyFromRegisterContext( |
1521 | context: older_frame_sp->GetRegisterContext()); |
1522 | if (copy_success) { |
1523 | thread->DiscardThreadPlans(force: true); |
1524 | thread->ClearStackFrames(); |
1525 | if (broadcast && EventTypeHasListeners(event_type: eBroadcastBitStackChanged)) { |
1526 | auto data_sp = std::make_shared<ThreadEventData>(args: shared_from_this()); |
1527 | BroadcastEvent(event_type: eBroadcastBitStackChanged, event_data_sp: data_sp); |
1528 | } |
1529 | } else { |
1530 | return_error.SetErrorString("Could not reset register values." ); |
1531 | } |
1532 | } else { |
1533 | return_error.SetErrorString("Frame has no register context." ); |
1534 | } |
1535 | } else { |
1536 | return_error.SetErrorString("Returned past top frame." ); |
1537 | } |
1538 | return return_error; |
1539 | } |
1540 | |
1541 | static void DumpAddressList(Stream &s, const std::vector<Address> &list, |
1542 | ExecutionContextScope *exe_scope) { |
1543 | for (size_t n = 0; n < list.size(); n++) { |
1544 | s << "\t" ; |
1545 | list[n].Dump(s: &s, exe_scope, style: Address::DumpStyleResolvedDescription, |
1546 | fallback_style: Address::DumpStyleSectionNameOffset); |
1547 | s << "\n" ; |
1548 | } |
1549 | } |
1550 | |
1551 | Status Thread::JumpToLine(const FileSpec &file, uint32_t line, |
1552 | bool can_leave_function, std::string *warnings) { |
1553 | ExecutionContext exe_ctx(GetStackFrameAtIndex(idx: 0)); |
1554 | Target *target = exe_ctx.GetTargetPtr(); |
1555 | TargetSP target_sp = exe_ctx.GetTargetSP(); |
1556 | RegisterContext *reg_ctx = exe_ctx.GetRegisterContext(); |
1557 | StackFrame *frame = exe_ctx.GetFramePtr(); |
1558 | const SymbolContext &sc = frame->GetSymbolContext(resolve_scope: eSymbolContextFunction); |
1559 | |
1560 | // Find candidate locations. |
1561 | std::vector<Address> candidates, within_function, outside_function; |
1562 | target->GetImages().FindAddressesForLine(target_sp, file, line, function: sc.function, |
1563 | output_local&: within_function, output_extern&: outside_function); |
1564 | |
1565 | // If possible, we try and stay within the current function. Within a |
1566 | // function, we accept multiple locations (optimized code may do this, |
1567 | // there's no solution here so we do the best we can). However if we're |
1568 | // trying to leave the function, we don't know how to pick the right |
1569 | // location, so if there's more than one then we bail. |
1570 | if (!within_function.empty()) |
1571 | candidates = within_function; |
1572 | else if (outside_function.size() == 1 && can_leave_function) |
1573 | candidates = outside_function; |
1574 | |
1575 | // Check if we got anything. |
1576 | if (candidates.empty()) { |
1577 | if (outside_function.empty()) { |
1578 | return Status("Cannot locate an address for %s:%i." , |
1579 | file.GetFilename().AsCString(), line); |
1580 | } else if (outside_function.size() == 1) { |
1581 | return Status("%s:%i is outside the current function." , |
1582 | file.GetFilename().AsCString(), line); |
1583 | } else { |
1584 | StreamString sstr; |
1585 | DumpAddressList(s&: sstr, list: outside_function, exe_scope: target); |
1586 | return Status("%s:%i has multiple candidate locations:\n%s" , |
1587 | file.GetFilename().AsCString(), line, sstr.GetData()); |
1588 | } |
1589 | } |
1590 | |
1591 | // Accept the first location, warn about any others. |
1592 | Address dest = candidates[0]; |
1593 | if (warnings && candidates.size() > 1) { |
1594 | StreamString sstr; |
1595 | sstr.Printf(format: "%s:%i appears multiple times in this function, selecting the " |
1596 | "first location:\n" , |
1597 | file.GetFilename().AsCString(), line); |
1598 | DumpAddressList(s&: sstr, list: candidates, exe_scope: target); |
1599 | *warnings = std::string(sstr.GetString()); |
1600 | } |
1601 | |
1602 | if (!reg_ctx->SetPC(dest)) |
1603 | return Status("Cannot change PC to target address." ); |
1604 | |
1605 | return Status(); |
1606 | } |
1607 | |
1608 | bool Thread::DumpUsingFormat(Stream &strm, uint32_t frame_idx, |
1609 | const FormatEntity::Entry *format) { |
1610 | ExecutionContext exe_ctx(shared_from_this()); |
1611 | Process *process = exe_ctx.GetProcessPtr(); |
1612 | if (!process || !format) |
1613 | return false; |
1614 | |
1615 | StackFrameSP frame_sp; |
1616 | SymbolContext frame_sc; |
1617 | if (frame_idx != LLDB_INVALID_FRAME_ID) { |
1618 | frame_sp = GetStackFrameAtIndex(idx: frame_idx); |
1619 | if (frame_sp) { |
1620 | exe_ctx.SetFrameSP(frame_sp); |
1621 | frame_sc = frame_sp->GetSymbolContext(resolve_scope: eSymbolContextEverything); |
1622 | } |
1623 | } |
1624 | |
1625 | return FormatEntity::Format(entry: *format, s&: strm, sc: frame_sp ? &frame_sc : nullptr, |
1626 | exe_ctx: &exe_ctx, addr: nullptr, valobj: nullptr, function_changed: false, initial_function: false); |
1627 | } |
1628 | |
1629 | void Thread::DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx, |
1630 | bool stop_format) { |
1631 | ExecutionContext exe_ctx(shared_from_this()); |
1632 | |
1633 | const FormatEntity::Entry *thread_format; |
1634 | if (stop_format) |
1635 | thread_format = exe_ctx.GetTargetRef().GetDebugger().GetThreadStopFormat(); |
1636 | else |
1637 | thread_format = exe_ctx.GetTargetRef().GetDebugger().GetThreadFormat(); |
1638 | |
1639 | assert(thread_format); |
1640 | |
1641 | DumpUsingFormat(strm, frame_idx, format: thread_format); |
1642 | } |
1643 | |
1644 | void Thread::SettingsInitialize() {} |
1645 | |
1646 | void Thread::SettingsTerminate() {} |
1647 | |
1648 | lldb::addr_t Thread::GetThreadPointer() { |
1649 | if (m_reg_context_sp) |
1650 | return m_reg_context_sp->GetThreadPointer(); |
1651 | return LLDB_INVALID_ADDRESS; |
1652 | } |
1653 | |
1654 | addr_t Thread::GetThreadLocalData(const ModuleSP module, |
1655 | lldb::addr_t tls_file_addr) { |
1656 | // The default implementation is to ask the dynamic loader for it. This can |
1657 | // be overridden for specific platforms. |
1658 | DynamicLoader *loader = GetProcess()->GetDynamicLoader(); |
1659 | if (loader) |
1660 | return loader->GetThreadLocalData(module, thread: shared_from_this(), |
1661 | tls_file_addr); |
1662 | else |
1663 | return LLDB_INVALID_ADDRESS; |
1664 | } |
1665 | |
1666 | bool Thread::SafeToCallFunctions() { |
1667 | Process *process = GetProcess().get(); |
1668 | if (process) { |
1669 | DynamicLoader *loader = GetProcess()->GetDynamicLoader(); |
1670 | if (loader && loader->IsFullyInitialized() == false) |
1671 | return false; |
1672 | |
1673 | SystemRuntime *runtime = process->GetSystemRuntime(); |
1674 | if (runtime) { |
1675 | return runtime->SafeToCallFunctionsOnThisThread(thread_sp: shared_from_this()); |
1676 | } |
1677 | } |
1678 | return true; |
1679 | } |
1680 | |
1681 | lldb::StackFrameSP |
1682 | Thread::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) { |
1683 | return GetStackFrameList()->GetStackFrameSPForStackFramePtr(stack_frame_ptr); |
1684 | } |
1685 | |
1686 | std::string Thread::StopReasonAsString(lldb::StopReason reason) { |
1687 | switch (reason) { |
1688 | case eStopReasonInvalid: |
1689 | return "invalid" ; |
1690 | case eStopReasonNone: |
1691 | return "none" ; |
1692 | case eStopReasonTrace: |
1693 | return "trace" ; |
1694 | case eStopReasonBreakpoint: |
1695 | return "breakpoint" ; |
1696 | case eStopReasonWatchpoint: |
1697 | return "watchpoint" ; |
1698 | case eStopReasonSignal: |
1699 | return "signal" ; |
1700 | case eStopReasonException: |
1701 | return "exception" ; |
1702 | case eStopReasonExec: |
1703 | return "exec" ; |
1704 | case eStopReasonFork: |
1705 | return "fork" ; |
1706 | case eStopReasonVFork: |
1707 | return "vfork" ; |
1708 | case eStopReasonVForkDone: |
1709 | return "vfork done" ; |
1710 | case eStopReasonPlanComplete: |
1711 | return "plan complete" ; |
1712 | case eStopReasonThreadExiting: |
1713 | return "thread exiting" ; |
1714 | case eStopReasonInstrumentation: |
1715 | return "instrumentation break" ; |
1716 | case eStopReasonProcessorTrace: |
1717 | return "processor trace" ; |
1718 | } |
1719 | |
1720 | return "StopReason = " + std::to_string(val: reason); |
1721 | } |
1722 | |
1723 | std::string Thread::RunModeAsString(lldb::RunMode mode) { |
1724 | switch (mode) { |
1725 | case eOnlyThisThread: |
1726 | return "only this thread" ; |
1727 | case eAllThreads: |
1728 | return "all threads" ; |
1729 | case eOnlyDuringStepping: |
1730 | return "only during stepping" ; |
1731 | } |
1732 | |
1733 | return "RunMode = " + std::to_string(val: mode); |
1734 | } |
1735 | |
1736 | size_t Thread::GetStatus(Stream &strm, uint32_t start_frame, |
1737 | uint32_t num_frames, uint32_t num_frames_with_source, |
1738 | bool stop_format, bool only_stacks) { |
1739 | |
1740 | if (!only_stacks) { |
1741 | ExecutionContext exe_ctx(shared_from_this()); |
1742 | Target *target = exe_ctx.GetTargetPtr(); |
1743 | Process *process = exe_ctx.GetProcessPtr(); |
1744 | strm.Indent(); |
1745 | bool is_selected = false; |
1746 | if (process) { |
1747 | if (process->GetThreadList().GetSelectedThread().get() == this) |
1748 | is_selected = true; |
1749 | } |
1750 | strm.Printf(format: "%c " , is_selected ? '*' : ' '); |
1751 | if (target && target->GetDebugger().GetUseExternalEditor()) { |
1752 | StackFrameSP frame_sp = GetStackFrameAtIndex(idx: start_frame); |
1753 | if (frame_sp) { |
1754 | SymbolContext frame_sc( |
1755 | frame_sp->GetSymbolContext(resolve_scope: eSymbolContextLineEntry)); |
1756 | if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.GetFile()) { |
1757 | if (llvm::Error e = Host::OpenFileInExternalEditor( |
1758 | editor: target->GetDebugger().GetExternalEditor(), |
1759 | file_spec: frame_sc.line_entry.GetFile(), line_no: frame_sc.line_entry.line)) { |
1760 | LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(e), |
1761 | "OpenFileInExternalEditor failed: {0}" ); |
1762 | } |
1763 | } |
1764 | } |
1765 | } |
1766 | |
1767 | DumpUsingSettingsFormat(strm, frame_idx: start_frame, stop_format); |
1768 | } |
1769 | |
1770 | size_t num_frames_shown = 0; |
1771 | if (num_frames > 0) { |
1772 | strm.IndentMore(); |
1773 | |
1774 | const bool show_frame_info = true; |
1775 | const bool show_frame_unique = only_stacks; |
1776 | const char *selected_frame_marker = nullptr; |
1777 | if (num_frames == 1 || only_stacks || |
1778 | (GetID() != GetProcess()->GetThreadList().GetSelectedThread()->GetID())) |
1779 | strm.IndentMore(); |
1780 | else |
1781 | selected_frame_marker = "* " ; |
1782 | |
1783 | num_frames_shown = GetStackFrameList()->GetStatus( |
1784 | strm, first_frame: start_frame, num_frames, show_frame_info, num_frames_with_source, |
1785 | show_unique: show_frame_unique, frame_marker: selected_frame_marker); |
1786 | if (num_frames == 1) |
1787 | strm.IndentLess(); |
1788 | strm.IndentLess(); |
1789 | } |
1790 | return num_frames_shown; |
1791 | } |
1792 | |
1793 | bool Thread::GetDescription(Stream &strm, lldb::DescriptionLevel level, |
1794 | bool print_json_thread, bool print_json_stopinfo) { |
1795 | const bool stop_format = false; |
1796 | DumpUsingSettingsFormat(strm, frame_idx: 0, stop_format); |
1797 | strm.Printf(format: "\n" ); |
1798 | |
1799 | StructuredData::ObjectSP thread_info = GetExtendedInfo(); |
1800 | |
1801 | if (print_json_thread || print_json_stopinfo) { |
1802 | if (thread_info && print_json_thread) { |
1803 | thread_info->Dump(s&: strm); |
1804 | strm.Printf(format: "\n" ); |
1805 | } |
1806 | |
1807 | if (print_json_stopinfo && m_stop_info_sp) { |
1808 | StructuredData::ObjectSP stop_info = m_stop_info_sp->GetExtendedInfo(); |
1809 | if (stop_info) { |
1810 | stop_info->Dump(s&: strm); |
1811 | strm.Printf(format: "\n" ); |
1812 | } |
1813 | } |
1814 | |
1815 | return true; |
1816 | } |
1817 | |
1818 | if (thread_info) { |
1819 | StructuredData::ObjectSP activity = |
1820 | thread_info->GetObjectForDotSeparatedPath(path: "activity" ); |
1821 | StructuredData::ObjectSP breadcrumb = |
1822 | thread_info->GetObjectForDotSeparatedPath(path: "breadcrumb" ); |
1823 | StructuredData::ObjectSP messages = |
1824 | thread_info->GetObjectForDotSeparatedPath(path: "trace_messages" ); |
1825 | |
1826 | bool printed_activity = false; |
1827 | if (activity && activity->GetType() == eStructuredDataTypeDictionary) { |
1828 | StructuredData::Dictionary *activity_dict = activity->GetAsDictionary(); |
1829 | StructuredData::ObjectSP id = activity_dict->GetValueForKey(key: "id" ); |
1830 | StructuredData::ObjectSP name = activity_dict->GetValueForKey(key: "name" ); |
1831 | if (name && name->GetType() == eStructuredDataTypeString && id && |
1832 | id->GetType() == eStructuredDataTypeInteger) { |
1833 | strm.Format(format: " Activity '{0}', {1:x}\n" , |
1834 | args: name->GetAsString()->GetValue(), |
1835 | args: id->GetUnsignedIntegerValue()); |
1836 | } |
1837 | printed_activity = true; |
1838 | } |
1839 | bool printed_breadcrumb = false; |
1840 | if (breadcrumb && breadcrumb->GetType() == eStructuredDataTypeDictionary) { |
1841 | if (printed_activity) |
1842 | strm.Printf(format: "\n" ); |
1843 | StructuredData::Dictionary *breadcrumb_dict = |
1844 | breadcrumb->GetAsDictionary(); |
1845 | StructuredData::ObjectSP breadcrumb_text = |
1846 | breadcrumb_dict->GetValueForKey(key: "name" ); |
1847 | if (breadcrumb_text && |
1848 | breadcrumb_text->GetType() == eStructuredDataTypeString) { |
1849 | strm.Format(format: " Current Breadcrumb: {0}\n" , |
1850 | args: breadcrumb_text->GetAsString()->GetValue()); |
1851 | } |
1852 | printed_breadcrumb = true; |
1853 | } |
1854 | if (messages && messages->GetType() == eStructuredDataTypeArray) { |
1855 | if (printed_breadcrumb) |
1856 | strm.Printf(format: "\n" ); |
1857 | StructuredData::Array *messages_array = messages->GetAsArray(); |
1858 | const size_t msg_count = messages_array->GetSize(); |
1859 | if (msg_count > 0) { |
1860 | strm.Printf(format: " %zu trace messages:\n" , msg_count); |
1861 | for (size_t i = 0; i < msg_count; i++) { |
1862 | StructuredData::ObjectSP message = messages_array->GetItemAtIndex(idx: i); |
1863 | if (message && message->GetType() == eStructuredDataTypeDictionary) { |
1864 | StructuredData::Dictionary *message_dict = |
1865 | message->GetAsDictionary(); |
1866 | StructuredData::ObjectSP message_text = |
1867 | message_dict->GetValueForKey(key: "message" ); |
1868 | if (message_text && |
1869 | message_text->GetType() == eStructuredDataTypeString) { |
1870 | strm.Format(format: " {0}\n" , args: message_text->GetAsString()->GetValue()); |
1871 | } |
1872 | } |
1873 | } |
1874 | } |
1875 | } |
1876 | } |
1877 | |
1878 | return true; |
1879 | } |
1880 | |
1881 | size_t Thread::GetStackFrameStatus(Stream &strm, uint32_t first_frame, |
1882 | uint32_t num_frames, bool show_frame_info, |
1883 | uint32_t num_frames_with_source) { |
1884 | return GetStackFrameList()->GetStatus( |
1885 | strm, first_frame, num_frames, show_frame_info, num_frames_with_source); |
1886 | } |
1887 | |
1888 | Unwind &Thread::GetUnwinder() { |
1889 | if (!m_unwinder_up) |
1890 | m_unwinder_up = std::make_unique<UnwindLLDB>(args&: *this); |
1891 | return *m_unwinder_up; |
1892 | } |
1893 | |
1894 | void Thread::Flush() { |
1895 | ClearStackFrames(); |
1896 | m_reg_context_sp.reset(); |
1897 | } |
1898 | |
1899 | bool Thread::IsStillAtLastBreakpointHit() { |
1900 | // If we are currently stopped at a breakpoint, always return that stopinfo |
1901 | // and don't reset it. This allows threads to maintain their breakpoint |
1902 | // stopinfo, such as when thread-stepping in multithreaded programs. |
1903 | if (m_stop_info_sp) { |
1904 | StopReason stop_reason = m_stop_info_sp->GetStopReason(); |
1905 | if (stop_reason == lldb::eStopReasonBreakpoint) { |
1906 | uint64_t value = m_stop_info_sp->GetValue(); |
1907 | lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext()); |
1908 | if (reg_ctx_sp) { |
1909 | lldb::addr_t pc = reg_ctx_sp->GetPC(); |
1910 | BreakpointSiteSP bp_site_sp = |
1911 | GetProcess()->GetBreakpointSiteList().FindByAddress(addr: pc); |
1912 | if (bp_site_sp && static_cast<break_id_t>(value) == bp_site_sp->GetID()) |
1913 | return true; |
1914 | } |
1915 | } |
1916 | } |
1917 | return false; |
1918 | } |
1919 | |
1920 | Status Thread::StepIn(bool source_step, |
1921 | LazyBool step_in_avoids_code_without_debug_info, |
1922 | LazyBool step_out_avoids_code_without_debug_info) |
1923 | |
1924 | { |
1925 | Status error; |
1926 | Process *process = GetProcess().get(); |
1927 | if (StateIsStoppedState(state: process->GetState(), must_exist: true)) { |
1928 | StackFrameSP frame_sp = GetStackFrameAtIndex(idx: 0); |
1929 | ThreadPlanSP new_plan_sp; |
1930 | const lldb::RunMode run_mode = eOnlyThisThread; |
1931 | const bool abort_other_plans = false; |
1932 | |
1933 | if (source_step && frame_sp && frame_sp->HasDebugInformation()) { |
1934 | SymbolContext sc(frame_sp->GetSymbolContext(resolve_scope: eSymbolContextEverything)); |
1935 | new_plan_sp = QueueThreadPlanForStepInRange( |
1936 | abort_other_plans, line_entry: sc.line_entry, addr_context: sc, step_in_target: nullptr, stop_other_threads: run_mode, status&: error, |
1937 | step_in_avoids_code_without_debug_info, |
1938 | step_out_avoids_code_without_debug_info); |
1939 | } else { |
1940 | new_plan_sp = QueueThreadPlanForStepSingleInstruction( |
1941 | step_over: false, abort_other_plans, stop_other_threads: run_mode, status&: error); |
1942 | } |
1943 | |
1944 | new_plan_sp->SetIsControllingPlan(true); |
1945 | new_plan_sp->SetOkayToDiscard(false); |
1946 | |
1947 | // Why do we need to set the current thread by ID here??? |
1948 | process->GetThreadList().SetSelectedThreadByID(tid: GetID()); |
1949 | error = process->Resume(); |
1950 | } else { |
1951 | error.SetErrorString("process not stopped" ); |
1952 | } |
1953 | return error; |
1954 | } |
1955 | |
1956 | Status Thread::StepOver(bool source_step, |
1957 | LazyBool step_out_avoids_code_without_debug_info) { |
1958 | Status error; |
1959 | Process *process = GetProcess().get(); |
1960 | if (StateIsStoppedState(state: process->GetState(), must_exist: true)) { |
1961 | StackFrameSP frame_sp = GetStackFrameAtIndex(idx: 0); |
1962 | ThreadPlanSP new_plan_sp; |
1963 | |
1964 | const lldb::RunMode run_mode = eOnlyThisThread; |
1965 | const bool abort_other_plans = false; |
1966 | |
1967 | if (source_step && frame_sp && frame_sp->HasDebugInformation()) { |
1968 | SymbolContext sc(frame_sp->GetSymbolContext(resolve_scope: eSymbolContextEverything)); |
1969 | new_plan_sp = QueueThreadPlanForStepOverRange( |
1970 | abort_other_plans, line_entry: sc.line_entry, addr_context: sc, stop_other_threads: run_mode, status&: error, |
1971 | step_out_avoids_code_withoug_debug_info: step_out_avoids_code_without_debug_info); |
1972 | } else { |
1973 | new_plan_sp = QueueThreadPlanForStepSingleInstruction( |
1974 | step_over: true, abort_other_plans, stop_other_threads: run_mode, status&: error); |
1975 | } |
1976 | |
1977 | new_plan_sp->SetIsControllingPlan(true); |
1978 | new_plan_sp->SetOkayToDiscard(false); |
1979 | |
1980 | // Why do we need to set the current thread by ID here??? |
1981 | process->GetThreadList().SetSelectedThreadByID(tid: GetID()); |
1982 | error = process->Resume(); |
1983 | } else { |
1984 | error.SetErrorString("process not stopped" ); |
1985 | } |
1986 | return error; |
1987 | } |
1988 | |
1989 | Status Thread::StepOut(uint32_t frame_idx) { |
1990 | Status error; |
1991 | Process *process = GetProcess().get(); |
1992 | if (StateIsStoppedState(state: process->GetState(), must_exist: true)) { |
1993 | const bool first_instruction = false; |
1994 | const bool stop_other_threads = false; |
1995 | const bool abort_other_plans = false; |
1996 | |
1997 | ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut( |
1998 | abort_other_plans, addr_context: nullptr, first_insn: first_instruction, stop_other_threads, |
1999 | report_stop_vote: eVoteYes, report_run_vote: eVoteNoOpinion, frame_idx, status&: error)); |
2000 | |
2001 | new_plan_sp->SetIsControllingPlan(true); |
2002 | new_plan_sp->SetOkayToDiscard(false); |
2003 | |
2004 | // Why do we need to set the current thread by ID here??? |
2005 | process->GetThreadList().SetSelectedThreadByID(tid: GetID()); |
2006 | error = process->Resume(); |
2007 | } else { |
2008 | error.SetErrorString("process not stopped" ); |
2009 | } |
2010 | return error; |
2011 | } |
2012 | |
2013 | ValueObjectSP Thread::GetCurrentException() { |
2014 | if (auto frame_sp = GetStackFrameAtIndex(idx: 0)) |
2015 | if (auto recognized_frame = frame_sp->GetRecognizedFrame()) |
2016 | if (auto e = recognized_frame->GetExceptionObject()) |
2017 | return e; |
2018 | |
2019 | // NOTE: Even though this behavior is generalized, only ObjC is actually |
2020 | // supported at the moment. |
2021 | for (LanguageRuntime *runtime : GetProcess()->GetLanguageRuntimes()) { |
2022 | if (auto e = runtime->GetExceptionObjectForThread(thread_sp: shared_from_this())) |
2023 | return e; |
2024 | } |
2025 | |
2026 | return ValueObjectSP(); |
2027 | } |
2028 | |
2029 | ThreadSP Thread::GetCurrentExceptionBacktrace() { |
2030 | ValueObjectSP exception = GetCurrentException(); |
2031 | if (!exception) |
2032 | return ThreadSP(); |
2033 | |
2034 | // NOTE: Even though this behavior is generalized, only ObjC is actually |
2035 | // supported at the moment. |
2036 | for (LanguageRuntime *runtime : GetProcess()->GetLanguageRuntimes()) { |
2037 | if (auto bt = runtime->GetBacktraceThreadFromException(thread_sp: exception)) |
2038 | return bt; |
2039 | } |
2040 | |
2041 | return ThreadSP(); |
2042 | } |
2043 | |
2044 | lldb::ValueObjectSP Thread::GetSiginfoValue() { |
2045 | ProcessSP process_sp = GetProcess(); |
2046 | assert(process_sp); |
2047 | Target &target = process_sp->GetTarget(); |
2048 | PlatformSP platform_sp = target.GetPlatform(); |
2049 | assert(platform_sp); |
2050 | ArchSpec arch = target.GetArchitecture(); |
2051 | |
2052 | CompilerType type = platform_sp->GetSiginfoType(triple: arch.GetTriple()); |
2053 | if (!type.IsValid()) |
2054 | return ValueObjectConstResult::Create(exe_scope: &target, error: Status("no siginfo_t for the platform" )); |
2055 | |
2056 | std::optional<uint64_t> type_size = type.GetByteSize(exe_scope: nullptr); |
2057 | assert(type_size); |
2058 | llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> data = |
2059 | GetSiginfo(max_size: *type_size); |
2060 | if (!data) |
2061 | return ValueObjectConstResult::Create(exe_scope: &target, error: Status(data.takeError())); |
2062 | |
2063 | DataExtractor {data.get()->getBufferStart(), data.get()->getBufferSize(), |
2064 | process_sp->GetByteOrder(), arch.GetAddressByteSize()}; |
2065 | return ValueObjectConstResult::Create(exe_scope: &target, compiler_type: type, name: ConstString("__lldb_siginfo" ), data: data_extractor); |
2066 | } |
2067 | |