summaryrefslogtreecommitdiff
path: root/lldb/source/Target/Thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Target/Thread.cpp')
-rw-r--r--lldb/source/Target/Thread.cpp551
1 files changed, 170 insertions, 381 deletions
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index e12b90501103e..24cf4bf3ee1ed 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -1,4 +1,4 @@
-//===-- Thread.cpp ----------------------------------------------*- C++ -*-===//
+//===-- Thread.cpp --------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,8 +7,6 @@
//===----------------------------------------------------------------------===//
#include "lldb/Target/Thread.h"
-#include "Plugins/Process/Utility/UnwindLLDB.h"
-#include "Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FormatEntity.h"
@@ -35,6 +33,7 @@
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Target/ThreadPlanPython.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/ThreadPlanStack.h"
#include "lldb/Target/ThreadPlanStepInRange.h"
#include "lldb/Target/ThreadPlanStepInstruction.h"
#include "lldb/Target/ThreadPlanStepOut.h"
@@ -43,7 +42,7 @@
#include "lldb/Target/ThreadPlanStepThrough.h"
#include "lldb/Target/ThreadPlanStepUntil.h"
#include "lldb/Target/ThreadSpec.h"
-#include "lldb/Target/Unwind.h"
+#include "lldb/Target/UnwindLLDB.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/State.h"
@@ -230,8 +229,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id)
m_index_id(use_invalid_index_id ? LLDB_INVALID_INDEX32
: process.GetNextThreadIndexID(tid)),
m_reg_context_sp(), m_state(eStateUnloaded), m_state_mutex(),
- m_plan_stack(), m_completed_plan_stack(), m_frame_mutex(),
- m_curr_frames_sp(), m_prev_frames_sp(),
+ m_frame_mutex(), m_curr_frames_sp(), m_prev_frames_sp(),
m_resume_signal(LLDB_INVALID_SIGNAL_NUMBER),
m_resume_state(eStateRunning), m_temporary_resume_state(eStateRunning),
m_unwinder_up(), m_destroy_called(false),
@@ -242,8 +240,6 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id)
static_cast<void *>(this), GetID());
CheckInWithManager();
-
- QueueFundamentalPlan(true);
}
Thread::~Thread() {
@@ -256,30 +252,7 @@ Thread::~Thread() {
}
void Thread::DestroyThread() {
- // Tell any plans on the plan stacks that the thread is being destroyed since
- // any plans that have a thread go away in the middle of might need to do
- // cleanup, or in some cases NOT do cleanup...
- for (auto plan : m_plan_stack)
- plan->ThreadDestroyed();
-
- for (auto plan : m_discarded_plan_stack)
- plan->ThreadDestroyed();
-
- for (auto plan : m_completed_plan_stack)
- plan->ThreadDestroyed();
-
m_destroy_called = true;
- m_plan_stack.clear();
- m_discarded_plan_stack.clear();
- m_completed_plan_stack.clear();
-
- // Push a ThreadPlanNull on the plan stack. That way we can continue
- // assuming that the plan stack is never empty, but if somebody errantly asks
- // questions of a destroyed thread without checking first whether it is
- // destroyed, they won't crash.
- ThreadPlanSP null_plan_sp(new ThreadPlanNull(*this));
- m_plan_stack.push_back(null_plan_sp);
-
m_stop_info_sp.reset();
m_reg_context_sp.reset();
m_unwinder_up.reset();
@@ -298,7 +271,7 @@ lldb::StackFrameSP Thread::GetSelectedFrame() {
StackFrameListSP stack_frame_list_sp(GetStackFrameList());
StackFrameSP frame_sp = stack_frame_list_sp->GetFrameAtIndex(
stack_frame_list_sp->GetSelectedFrameIndex());
- FunctionOptimizationWarning(frame_sp.get());
+ FrameSelectedCallback(frame_sp.get());
return frame_sp;
}
@@ -307,7 +280,7 @@ uint32_t Thread::SetSelectedFrame(lldb_private::StackFrame *frame,
uint32_t ret_value = GetStackFrameList()->SetSelectedFrame(frame);
if (broadcast)
BroadcastSelectedFrameChange(frame->GetStackID());
- FunctionOptimizationWarning(frame);
+ FrameSelectedCallback(frame);
return ret_value;
}
@@ -317,7 +290,7 @@ bool Thread::SetSelectedFrameByIndex(uint32_t frame_idx, bool broadcast) {
GetStackFrameList()->SetSelectedFrame(frame_sp.get());
if (broadcast)
BroadcastSelectedFrameChange(frame_sp->GetStackID());
- FunctionOptimizationWarning(frame_sp.get());
+ FrameSelectedCallback(frame_sp.get());
return true;
} else
return false;
@@ -341,7 +314,7 @@ bool Thread::SetSelectedFrameByIndexNoisily(uint32_t frame_idx,
bool show_frame_info = true;
bool show_source = !already_shown;
- FunctionOptimizationWarning(frame_sp.get());
+ FrameSelectedCallback(frame_sp.get());
return frame_sp->GetStatus(output_stream, show_frame_info, show_source);
}
return false;
@@ -349,12 +322,17 @@ bool Thread::SetSelectedFrameByIndexNoisily(uint32_t frame_idx,
return false;
}
-void Thread::FunctionOptimizationWarning(StackFrame *frame) {
- if (frame && frame->HasDebugInformation() &&
- GetProcess()->GetWarningsOptimization()) {
+void Thread::FrameSelectedCallback(StackFrame *frame) {
+ if (!frame)
+ return;
+
+ if (frame->HasDebugInformation() &&
+ (GetProcess()->GetWarningsOptimization() ||
+ GetProcess()->GetWarningsUnsupportedLanguage())) {
SymbolContext sc =
frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextModule);
GetProcess()->PrintWarningOptimization(sc);
+ GetProcess()->PrintWarningUnsupportedLanguage(sc);
}
}
@@ -423,7 +401,7 @@ lldb::StopInfoSP Thread::GetPrivateStopInfo() {
// "m_stop_info_stop_id != process_stop_id" as the condition for the if
// statement below, we must also check the stop info to see if we need to
// override it. See the header documentation in
- // Process::GetStopInfoOverrideCallback() for more information on the stop
+ // Architecture::OverrideStopInfo() for more information on the stop
// info override callback.
if (m_stop_info_override_stop_id != process_stop_id) {
m_stop_info_override_stop_id = process_stop_id;
@@ -524,7 +502,8 @@ bool Thread::CheckpointThreadState(ThreadStateCheckpoint &saved_state) {
if (process_sp)
saved_state.orig_stop_id = process_sp->GetStopID();
saved_state.current_inlined_depth = GetCurrentInlinedDepth();
- saved_state.m_completed_plan_stack = m_completed_plan_stack;
+ saved_state.m_completed_plan_checkpoint =
+ GetPlans().CheckpointCompletedPlans();
return true;
}
@@ -558,7 +537,8 @@ bool Thread::RestoreThreadStateFromCheckpoint(
SetStopInfo(saved_state.stop_info_sp);
GetStackFrameList()->SetCurrentInlinedDepth(
saved_state.current_inlined_depth);
- m_completed_plan_stack = saved_state.m_completed_plan_stack;
+ GetPlans().RestoreCompletedPlanCheckpoint(
+ saved_state.m_completed_plan_checkpoint);
return true;
}
@@ -573,9 +553,68 @@ void Thread::SetState(StateType state) {
m_state = state;
}
+std::string Thread::GetStopDescription() {
+ StackFrameSP frame_sp = GetStackFrameAtIndex(0);
+
+ if (!frame_sp)
+ return GetStopDescriptionRaw();
+
+ auto recognized_frame_sp = frame_sp->GetRecognizedFrame();
+
+ if (!recognized_frame_sp)
+ return GetStopDescriptionRaw();
+
+ std::string recognized_stop_description =
+ recognized_frame_sp->GetStopDescription();
+
+ if (!recognized_stop_description.empty())
+ return recognized_stop_description;
+
+ return GetStopDescriptionRaw();
+}
+
+std::string Thread::GetStopDescriptionRaw() {
+ StopInfoSP stop_info_sp = GetStopInfo();
+ std::string raw_stop_description;
+ if (stop_info_sp && stop_info_sp->IsValid()) {
+ raw_stop_description = stop_info_sp->GetDescription();
+ assert((!raw_stop_description.empty() ||
+ stop_info_sp->GetStopReason() == eStopReasonNone) &&
+ "StopInfo returned an empty description.");
+ }
+ return raw_stop_description;
+}
+
+void Thread::SelectMostRelevantFrame() {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD);
+
+ auto frames_list_sp = GetStackFrameList();
+
+ // Only the top frame should be recognized.
+ auto frame_sp = frames_list_sp->GetFrameAtIndex(0);
+
+ auto recognized_frame_sp = frame_sp->GetRecognizedFrame();
+
+ if (!recognized_frame_sp) {
+ LLDB_LOG(log, "Frame #0 not recognized");
+ return;
+ }
+
+ if (StackFrameSP most_relevant_frame_sp =
+ recognized_frame_sp->GetMostRelevantFrame()) {
+ LLDB_LOG(log, "Found most relevant frame at index {0}",
+ most_relevant_frame_sp->GetFrameIndex());
+ SetSelectedFrame(most_relevant_frame_sp.get());
+ } else {
+ LLDB_LOG(log, "No relevant frame!");
+ }
+}
+
void Thread::WillStop() {
ThreadPlan *current_plan = GetCurrentPlan();
+ SelectMostRelevantFrame();
+
// FIXME: I may decide to disallow threads with no plans. In which
// case this should go to an assert.
@@ -632,8 +671,7 @@ void Thread::SetupForResume() {
bool Thread::ShouldResume(StateType resume_state) {
// At this point clear the completed plan stack.
- m_completed_plan_stack.clear();
- m_discarded_plan_stack.clear();
+ GetPlans().WillResume();
m_override_should_notify = eLazyBoolCalculate;
StateType prev_resume_state = GetTemporaryResumeState();
@@ -744,7 +782,9 @@ bool Thread::ShouldStop(Event *event_ptr) {
LLDB_LOGF(log, "^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^");
StreamString s;
s.IndentMore();
- DumpThreadPlans(&s);
+ GetProcess()->DumpThreadPlansForTID(
+ s, GetID(), eDescriptionLevelVerbose, true /* internal */,
+ false /* condense_trivial */, true /* skip_unreported */);
LLDB_LOGF(log, "Plan stack initial state:\n%s", s.GetData());
}
@@ -827,7 +867,7 @@ bool Thread::ShouldStop(Event *event_ptr) {
current_plan->GetName(), over_ride_stop);
// We're starting from the base plan, so just let it decide;
- if (PlanIsBasePlan(current_plan)) {
+ if (current_plan->IsBasePlan()) {
should_stop = current_plan->ShouldStop(event_ptr);
LLDB_LOGF(log, "Base plan says should stop: %i.", should_stop);
} else {
@@ -835,7 +875,7 @@ bool Thread::ShouldStop(Event *event_ptr) {
// to do, since presumably if there were other plans they would know what
// to do...
while (true) {
- if (PlanIsBasePlan(current_plan))
+ if (current_plan->IsBasePlan())
break;
should_stop = current_plan->ShouldStop(event_ptr);
@@ -881,7 +921,7 @@ bool Thread::ShouldStop(Event *event_ptr) {
// Discard the stale plans and all plans below them in the stack, plus move
// the completed plans to the completed plan stack
- while (!PlanIsBasePlan(plan_ptr)) {
+ while (!plan_ptr->IsBasePlan()) {
bool stale = plan_ptr->IsPlanStale();
ThreadPlan *examined_plan = plan_ptr;
plan_ptr = GetPreviousPlan(examined_plan);
@@ -908,7 +948,9 @@ bool Thread::ShouldStop(Event *event_ptr) {
if (log) {
StreamString s;
s.IndentMore();
- DumpThreadPlans(&s);
+ GetProcess()->DumpThreadPlansForTID(
+ s, GetID(), eDescriptionLevelVerbose, true /* internal */,
+ false /* condense_trivial */, true /* skip_unreported */);
LLDB_LOGF(log, "Plan stack final state:\n%s", s.GetData());
LLDB_LOGF(log, "vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv",
should_stop);
@@ -947,13 +989,14 @@ Vote Thread::ShouldReportStop(Event *event_ptr) {
return eVoteNoOpinion;
}
- if (m_completed_plan_stack.size() > 0) {
- // Don't use GetCompletedPlan here, since that suppresses private plans.
+ if (GetPlans().AnyCompletedPlans()) {
+ // Pass skip_private = false to GetCompletedPlan, since we want to ask
+ // the last plan, regardless of whether it is private or not.
LLDB_LOGF(log,
"Thread::ShouldReportStop() tid = 0x%4.4" PRIx64
": returning vote for complete stack's back plan",
GetID());
- return m_completed_plan_stack.back()->ShouldReportStop(event_ptr);
+ return GetPlans().GetCompletedPlan(false)->ShouldReportStop(event_ptr);
} else {
Vote thread_vote = eVoteNoOpinion;
ThreadPlan *plan_ptr = GetCurrentPlan();
@@ -962,7 +1005,7 @@ Vote Thread::ShouldReportStop(Event *event_ptr) {
thread_vote = plan_ptr->ShouldReportStop(event_ptr);
break;
}
- if (PlanIsBasePlan(plan_ptr))
+ if (plan_ptr->IsBasePlan())
break;
else
plan_ptr = GetPreviousPlan(plan_ptr);
@@ -984,16 +1027,17 @@ Vote Thread::ShouldReportRun(Event *event_ptr) {
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- if (m_completed_plan_stack.size() > 0) {
- // Don't use GetCompletedPlan here, since that suppresses private plans.
+ if (GetPlans().AnyCompletedPlans()) {
+ // Pass skip_private = false to GetCompletedPlan, since we want to ask
+ // the last plan, regardless of whether it is private or not.
LLDB_LOGF(log,
"Current Plan for thread %d(%p) (0x%4.4" PRIx64
", %s): %s being asked whether we should report run.",
GetIndexID(), static_cast<void *>(this), GetID(),
StateAsCString(GetTemporaryResumeState()),
- m_completed_plan_stack.back()->GetName());
+ GetCompletedPlan()->GetName());
- return m_completed_plan_stack.back()->ShouldReportRun(event_ptr);
+ return GetPlans().GetCompletedPlan(false)->ShouldReportRun(event_ptr);
} else {
LLDB_LOGF(log,
"Current Plan for thread %d(%p) (0x%4.4" PRIx64
@@ -1010,148 +1054,85 @@ bool Thread::MatchesSpec(const ThreadSpec *spec) {
return (spec == nullptr) ? true : spec->ThreadPassesBasicTests(*this);
}
-void Thread::PushPlan(ThreadPlanSP &thread_plan_sp) {
- if (thread_plan_sp) {
- // If the thread plan doesn't already have a tracer, give it its parent's
- // tracer:
- if (!thread_plan_sp->GetThreadPlanTracer()) {
- assert(!m_plan_stack.empty());
- thread_plan_sp->SetThreadPlanTracer(
- m_plan_stack.back()->GetThreadPlanTracer());
- }
- m_plan_stack.push_back(thread_plan_sp);
+ThreadPlanStack &Thread::GetPlans() const {
+ ThreadPlanStack *plans = GetProcess()->FindThreadPlans(GetID());
+ if (plans)
+ return *plans;
- thread_plan_sp->DidPush();
+ // History threads don't have a thread plan, but they do ask get asked to
+ // describe themselves, which usually involves pulling out the stop reason.
+ // That in turn will check for a completed plan on the ThreadPlanStack.
+ // Instead of special-casing at that point, we return a Stack with a
+ // ThreadPlanNull as its base plan. That will give the right answers to the
+ // queries GetDescription makes, and only assert if you try to run the thread.
+ if (!m_null_plan_stack_up)
+ m_null_plan_stack_up = std::make_unique<ThreadPlanStack>(*this, true);
+ return *(m_null_plan_stack_up.get());
+}
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- if (log) {
- StreamString s;
- thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
- LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".",
- static_cast<void *>(this), s.GetData(),
- thread_plan_sp->GetThread().GetID());
- }
+void Thread::PushPlan(ThreadPlanSP thread_plan_sp) {
+ assert(thread_plan_sp && "Don't push an empty thread plan.");
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
+ if (log) {
+ StreamString s;
+ thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
+ LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".",
+ static_cast<void *>(this), s.GetData(),
+ thread_plan_sp->GetThread().GetID());
}
+
+ GetPlans().PushPlan(std::move(thread_plan_sp));
}
void Thread::PopPlan() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
-
- if (m_plan_stack.size() <= 1)
- return;
- else {
- ThreadPlanSP &plan = m_plan_stack.back();
- if (log) {
- LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".",
- plan->GetName(), plan->GetThread().GetID());
- }
- m_completed_plan_stack.push_back(plan);
- plan->WillPop();
- m_plan_stack.pop_back();
+ ThreadPlanSP popped_plan_sp = GetPlans().PopPlan();
+ if (log) {
+ LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".",
+ popped_plan_sp->GetName(), popped_plan_sp->GetThread().GetID());
}
}
void Thread::DiscardPlan() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
- if (m_plan_stack.size() > 1) {
- ThreadPlanSP &plan = m_plan_stack.back();
- LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".",
- plan->GetName(), plan->GetThread().GetID());
-
- m_discarded_plan_stack.push_back(plan);
- plan->WillPop();
- m_plan_stack.pop_back();
- }
-}
+ ThreadPlanSP discarded_plan_sp = GetPlans().PopPlan();
-ThreadPlan *Thread::GetCurrentPlan() {
- // There will always be at least the base plan. If somebody is mucking with
- // a thread with an empty plan stack, we should assert right away.
- return m_plan_stack.empty() ? nullptr : m_plan_stack.back().get();
+ LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".",
+ discarded_plan_sp->GetName(),
+ discarded_plan_sp->GetThread().GetID());
}
-ThreadPlanSP Thread::GetCompletedPlan() {
- ThreadPlanSP empty_plan_sp;
- if (!m_completed_plan_stack.empty()) {
- for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) {
- ThreadPlanSP completed_plan_sp;
- completed_plan_sp = m_completed_plan_stack[i];
- if (!completed_plan_sp->GetPrivate())
- return completed_plan_sp;
- }
- }
- return empty_plan_sp;
+ThreadPlan *Thread::GetCurrentPlan() const {
+ return GetPlans().GetCurrentPlan().get();
}
-ValueObjectSP Thread::GetReturnValueObject() {
- if (!m_completed_plan_stack.empty()) {
- for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) {
- ValueObjectSP return_valobj_sp;
- return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject();
- if (return_valobj_sp)
- return return_valobj_sp;
- }
- }
- return ValueObjectSP();
+ThreadPlanSP Thread::GetCompletedPlan() const {
+ return GetPlans().GetCompletedPlan();
}
-ExpressionVariableSP Thread::GetExpressionVariable() {
- if (!m_completed_plan_stack.empty()) {
- for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) {
- ExpressionVariableSP expression_variable_sp;
- expression_variable_sp =
- m_completed_plan_stack[i]->GetExpressionVariable();
- if (expression_variable_sp)
- return expression_variable_sp;
- }
- }
- return ExpressionVariableSP();
+ValueObjectSP Thread::GetReturnValueObject() const {
+ return GetPlans().GetReturnValueObject();
}
-bool Thread::IsThreadPlanDone(ThreadPlan *plan) {
- if (!m_completed_plan_stack.empty()) {
- for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) {
- if (m_completed_plan_stack[i].get() == plan)
- return true;
- }
- }
- return false;
+ExpressionVariableSP Thread::GetExpressionVariable() const {
+ return GetPlans().GetExpressionVariable();
}
-bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) {
- if (!m_discarded_plan_stack.empty()) {
- for (int i = m_discarded_plan_stack.size() - 1; i >= 0; i--) {
- if (m_discarded_plan_stack[i].get() == plan)
- return true;
- }
- }
- return false;
+bool Thread::IsThreadPlanDone(ThreadPlan *plan) const {
+ return GetPlans().IsPlanDone(plan);
}
-bool Thread::CompletedPlanOverridesBreakpoint() {
- return (!m_completed_plan_stack.empty()) ;
+bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) const {
+ return GetPlans().WasPlanDiscarded(plan);
}
-ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) {
- if (current_plan == nullptr)
- return nullptr;
-
- int stack_size = m_completed_plan_stack.size();
- for (int i = stack_size - 1; i > 0; i--) {
- if (current_plan == m_completed_plan_stack[i].get())
- return m_completed_plan_stack[i - 1].get();
- }
-
- if (stack_size > 0 && m_completed_plan_stack[0].get() == current_plan) {
- return GetCurrentPlan();
- }
+bool Thread::CompletedPlanOverridesBreakpoint() const {
+ return GetPlans().AnyCompletedPlans();
+}
- stack_size = m_plan_stack.size();
- for (int i = stack_size - 1; i > 0; i--) {
- if (current_plan == m_plan_stack[i].get())
- return m_plan_stack[i - 1].get();
- }
- return nullptr;
+ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) const{
+ return GetPlans().GetPreviousPlan(current_plan);
}
Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp,
@@ -1185,38 +1166,18 @@ Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp,
}
void Thread::EnableTracer(bool value, bool single_stepping) {
- int stack_size = m_plan_stack.size();
- for (int i = 0; i < stack_size; i++) {
- if (m_plan_stack[i]->GetThreadPlanTracer()) {
- m_plan_stack[i]->GetThreadPlanTracer()->EnableTracing(value);
- m_plan_stack[i]->GetThreadPlanTracer()->EnableSingleStep(single_stepping);
- }
- }
+ GetPlans().EnableTracer(value, single_stepping);
}
void Thread::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) {
- int stack_size = m_plan_stack.size();
- for (int i = 0; i < stack_size; i++)
- m_plan_stack[i]->SetThreadPlanTracer(tracer_sp);
+ GetPlans().SetTracer(tracer_sp);
}
-bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t thread_index) {
+bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t plan_index) {
// Count the user thread plans from the back end to get the number of the one
// we want to discard:
- uint32_t idx = 0;
- ThreadPlan *up_to_plan_ptr = nullptr;
-
- for (ThreadPlanSP plan_sp : m_plan_stack) {
- if (plan_sp->GetPrivate())
- continue;
- if (idx == thread_index) {
- up_to_plan_ptr = plan_sp.get();
- break;
- } else
- idx++;
- }
-
+ ThreadPlan *up_to_plan_ptr = GetPlans().GetPlanByIndex(plan_index).get();
if (up_to_plan_ptr == nullptr)
return false;
@@ -1234,30 +1195,7 @@ void Thread::DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr) {
"Discarding thread plans for thread tid = 0x%4.4" PRIx64
", up to %p",
GetID(), static_cast<void *>(up_to_plan_ptr));
-
- int stack_size = m_plan_stack.size();
-
- // If the input plan is nullptr, discard all plans. Otherwise make sure this
- // plan is in the stack, and if so discard up to and including it.
-
- if (up_to_plan_ptr == nullptr) {
- for (int i = stack_size - 1; i > 0; i--)
- DiscardPlan();
- } else {
- bool found_it = false;
- for (int i = stack_size - 1; i > 0; i--) {
- if (m_plan_stack[i].get() == up_to_plan_ptr)
- found_it = true;
- }
- if (found_it) {
- bool last_one = false;
- for (int i = stack_size - 1; i > 0 && !last_one; i--) {
- if (GetCurrentPlan() == up_to_plan_ptr)
- last_one = true;
- DiscardPlan();
- }
- }
- }
+ GetPlans().DiscardPlansUpToPlan(up_to_plan_ptr);
}
void Thread::DiscardThreadPlans(bool force) {
@@ -1270,73 +1208,20 @@ void Thread::DiscardThreadPlans(bool force) {
}
if (force) {
- int stack_size = m_plan_stack.size();
- for (int i = stack_size - 1; i > 0; i--) {
- DiscardPlan();
- }
+ GetPlans().DiscardAllPlans();
return;
}
-
- while (true) {
- int master_plan_idx;
- bool discard = true;
-
- // Find the first master plan, see if it wants discarding, and if yes
- // discard up to it.
- for (master_plan_idx = m_plan_stack.size() - 1; master_plan_idx >= 0;
- master_plan_idx--) {
- if (m_plan_stack[master_plan_idx]->IsMasterPlan()) {
- discard = m_plan_stack[master_plan_idx]->OkayToDiscard();
- break;
- }
- }
-
- if (discard) {
- // First pop all the dependent plans:
- for (int i = m_plan_stack.size() - 1; i > master_plan_idx; i--) {
- // FIXME: Do we need a finalize here, or is the rule that
- // "PrepareForStop"
- // for the plan leaves it in a state that it is safe to pop the plan
- // with no more notice?
- DiscardPlan();
- }
-
- // Now discard the master plan itself.
- // The bottom-most plan never gets discarded. "OkayToDiscard" for it
- // means discard it's dependent plans, but not it...
- if (master_plan_idx > 0) {
- DiscardPlan();
- }
- } else {
- // If the master plan doesn't want to get discarded, then we're done.
- break;
- }
- }
-}
-
-bool Thread::PlanIsBasePlan(ThreadPlan *plan_ptr) {
- if (plan_ptr->IsBasePlan())
- return true;
- else if (m_plan_stack.size() == 0)
- return false;
- else
- return m_plan_stack[0].get() == plan_ptr;
+ GetPlans().DiscardConsultingMasterPlans();
}
Status Thread::UnwindInnermostExpression() {
Status error;
- int stack_size = m_plan_stack.size();
-
- // If the input plan is nullptr, discard all plans. Otherwise make sure this
- // plan is in the stack, and if so discard up to and including it.
-
- for (int i = stack_size - 1; i > 0; i--) {
- if (m_plan_stack[i]->GetKind() == ThreadPlan::eKindCallFunction) {
- DiscardThreadPlansUpToPlan(m_plan_stack[i].get());
- return error;
- }
- }
- error.SetErrorString("No expressions currently active on this thread");
+ ThreadPlan *innermost_expr_plan = GetPlans().GetInnermostExpression();
+ if (!innermost_expr_plan) {
+ error.SetErrorString("No expressions currently active on this thread");
+ return error;
+ }
+ DiscardThreadPlansUpToPlan(innermost_expr_plan);
return error;
}
@@ -1502,73 +1387,6 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted(
uint32_t Thread::GetIndexID() const { return m_index_id; }
-static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan,
- lldb::DescriptionLevel desc_level,
- int32_t elem_idx) {
- s->IndentMore();
- s->Indent();
- s->Printf("Element %d: ", elem_idx);
- plan->GetDescription(s, desc_level);
- s->EOL();
- s->IndentLess();
-}
-
-static void PrintPlanStack(Stream *s,
- const std::vector<lldb::ThreadPlanSP> &plan_stack,
- lldb::DescriptionLevel desc_level,
- bool include_internal) {
- int32_t print_idx = 0;
- for (ThreadPlanSP plan_sp : plan_stack) {
- if (include_internal || !plan_sp->GetPrivate()) {
- PrintPlanElement(s, plan_sp, desc_level, print_idx++);
- }
- }
-}
-
-void Thread::DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level,
- bool include_internal,
- bool ignore_boring_threads) const {
- uint32_t stack_size;
-
- if (ignore_boring_threads) {
- uint32_t stack_size = m_plan_stack.size();
- uint32_t completed_stack_size = m_completed_plan_stack.size();
- uint32_t discarded_stack_size = m_discarded_plan_stack.size();
- if (stack_size == 1 && completed_stack_size == 0 &&
- discarded_stack_size == 0) {
- s->Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID());
- s->IndentMore();
- s->Indent();
- s->Printf("No active thread plans\n");
- s->IndentLess();
- return;
- }
- }
-
- s->Indent();
- s->Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID());
- s->IndentMore();
- s->Indent();
- s->Printf("Active plan stack:\n");
- PrintPlanStack(s, m_plan_stack, desc_level, include_internal);
-
- stack_size = m_completed_plan_stack.size();
- if (stack_size > 0) {
- s->Indent();
- s->Printf("Completed Plan Stack:\n");
- PrintPlanStack(s, m_completed_plan_stack, desc_level, include_internal);
- }
-
- stack_size = m_discarded_plan_stack.size();
- if (stack_size > 0) {
- s->Indent();
- s->Printf("Discarded Plan Stack:\n");
- PrintPlanStack(s, m_discarded_plan_stack, desc_level, include_internal);
- }
-
- s->IndentLess();
-}
-
TargetSP Thread::CalculateTarget() {
TargetSP target_sp;
ProcessSP process_sp(GetProcess());
@@ -1600,9 +1418,7 @@ StackFrameListSP Thread::GetStackFrameList() {
void Thread::ClearStackFrames() {
std::lock_guard<std::recursive_mutex> guard(m_frame_mutex);
- Unwind *unwinder = GetUnwinder();
- if (unwinder)
- unwinder->Clear();
+ GetUnwinder().Clear();
// Only store away the old "reference" StackFrameList if we got all its
// frames:
@@ -1773,7 +1589,7 @@ Status Thread::JumpToLine(const FileSpec &file, uint32_t line,
"first location:\n",
file.GetFilename().AsCString(), line);
DumpAddressList(sstr, candidates, target);
- *warnings = sstr.GetString();
+ *warnings = std::string(sstr.GetString());
}
if (!reg_ctx->SetPC(dest))
@@ -2041,37 +1857,10 @@ size_t Thread::GetStackFrameStatus(Stream &strm, uint32_t first_frame,
strm, first_frame, num_frames, show_frame_info, num_frames_with_source);
}
-Unwind *Thread::GetUnwinder() {
- if (!m_unwinder_up) {
- const ArchSpec target_arch(CalculateTarget()->GetArchitecture());
- const llvm::Triple::ArchType machine = target_arch.GetMachine();
- switch (machine) {
- case llvm::Triple::x86_64:
- case llvm::Triple::x86:
- case llvm::Triple::arm:
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- case llvm::Triple::thumb:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::systemz:
- case llvm::Triple::hexagon:
- case llvm::Triple::arc:
- m_unwinder_up.reset(new UnwindLLDB(*this));
- break;
-
- default:
- if (target_arch.GetTriple().getVendor() == llvm::Triple::Apple)
- m_unwinder_up.reset(new UnwindMacOSXFrameBackchain(*this));
- break;
- }
- }
- return m_unwinder_up.get();
+Unwind &Thread::GetUnwinder() {
+ if (!m_unwinder_up)
+ m_unwinder_up = std::make_unique<UnwindLLDB>(*this);
+ return *m_unwinder_up;
}
void Thread::Flush() {