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