summaryrefslogtreecommitdiff
path: root/source/Commands/CommandObjectThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Commands/CommandObjectThread.cpp')
-rw-r--r--source/Commands/CommandObjectThread.cpp187
1 files changed, 122 insertions, 65 deletions
diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp
index 3be559963df1..e792887d4ff3 100644
--- a/source/Commands/CommandObjectThread.cpp
+++ b/source/Commands/CommandObjectThread.cpp
@@ -9,12 +9,7 @@
#include "CommandObjectThread.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/SourceManager.h"
-#include "lldb/Core/State.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/OptionParser.h"
@@ -37,6 +32,7 @@
#include "lldb/Target/ThreadPlanStepInstruction.h"
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Utility/State.h"
#include "lldb/lldb-private.h"
using namespace lldb;
@@ -247,11 +243,11 @@ protected:
// CommandObjectThreadBacktrace
//-------------------------------------------------------------------------
-static OptionDefinition g_thread_backtrace_options[] = {
+static constexpr OptionDefinition g_thread_backtrace_options[] = {
// clang-format off
- { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "How many frames to display (-1 for all)" },
- { LLDB_OPT_SET_1, false, "start", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace" },
- { LLDB_OPT_SET_1, false, "extended", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Show the extended backtrace, if available" }
+ { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCount, "How many frames to display (-1 for all)" },
+ { LLDB_OPT_SET_1, false, "start", 's', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace" },
+ { LLDB_OPT_SET_1, false, "extended", 'e', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Show the extended backtrace, if available" }
// clang-format on
};
@@ -402,28 +398,26 @@ protected:
enum StepScope { eStepScopeSource, eStepScopeInstruction };
-static OptionEnumValueElement g_tri_running_mode[] = {
+static constexpr OptionEnumValueElement g_tri_running_mode[] = {
{eOnlyThisThread, "this-thread", "Run only this thread"},
{eAllThreads, "all-threads", "Run all threads"},
{eOnlyDuringStepping, "while-stepping",
- "Run only this thread while stepping"},
- {0, nullptr, nullptr}};
+ "Run only this thread while stepping"} };
-static OptionEnumValueElement g_duo_running_mode[] = {
- {eOnlyThisThread, "this-thread", "Run only this thread"},
- {eAllThreads, "all-threads", "Run all threads"},
- {0, nullptr, nullptr}};
+static constexpr OptionEnumValues TriRunningModes() {
+ return OptionEnumValues(g_tri_running_mode);
+}
-static OptionDefinition g_thread_step_scope_options[] = {
+static constexpr OptionDefinition g_thread_step_scope_options[] = {
// clang-format off
- { LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information." },
- { LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information." },
- { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst." },
- { LLDB_OPT_SET_1, false, "end-linenumber", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 1, eArgTypeLineNum, "The line at which to stop stepping - defaults to the next line and only supported for step-in and step-over. You can also pass the string 'block' to step to the end of the current block. This is particularly useful in conjunction with --step-target to step through a complex calling sequence." },
- { LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, nullptr, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread." },
- { LLDB_OPT_SET_1, false, "step-over-regexp", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in." },
- { LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into." },
- { LLDB_OPT_SET_2, false, "python-class", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "The name of the class that will manage this step - only supported for Scripted Step." }
+ { LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information." },
+ { LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information." },
+ { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, {}, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst." },
+ { LLDB_OPT_SET_1, false, "end-linenumber", 'e', OptionParser::eRequiredArgument, nullptr, {}, 1, eArgTypeLineNum, "The line at which to stop stepping - defaults to the next line and only supported for step-in and step-over. You can also pass the string 'block' to step to the end of the current block. This is particularly useful in conjunction with --step-target to step through a complex calling sequence." },
+ { LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, nullptr, TriRunningModes(), 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread." },
+ { LLDB_OPT_SET_1, false, "step-over-regexp", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in." },
+ { LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into." },
+ { LLDB_OPT_SET_2, false, "python-class", 'C', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePythonClass, "The name of the class that will manage this step - only supported for Scripted Step." }
// clang-format on
};
@@ -483,8 +477,7 @@ public:
break;
case 'm': {
- OptionEnumValueElement *enum_values =
- GetDefinitions()[option_idx].enum_values;
+ auto enum_values = GetDefinitions()[option_idx].enum_values;
m_run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
option_arg, enum_values, eOnlyDuringStepping, error);
} break;
@@ -657,6 +650,7 @@ protected:
bool_stop_other_threads = true;
ThreadPlanSP new_plan_sp;
+ Status new_plan_status;
if (m_step_type == eStepTypeInto) {
StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
@@ -706,7 +700,7 @@ protected:
abort_other_plans, range,
frame->GetSymbolContext(eSymbolContextEverything),
m_options.m_step_in_target.c_str(), stop_other_threads,
- m_options.m_step_in_avoid_no_debug,
+ new_plan_status, m_options.m_step_in_avoid_no_debug,
m_options.m_step_out_avoid_no_debug);
if (new_plan_sp && !m_options.m_avoid_regexp.empty()) {
@@ -716,7 +710,7 @@ protected:
}
} else
new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
- false, abort_other_plans, bool_stop_other_threads);
+ false, abort_other_plans, bool_stop_other_threads, new_plan_status);
} else if (m_step_type == eStepTypeOver) {
StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
@@ -725,25 +719,26 @@ protected:
abort_other_plans,
frame->GetSymbolContext(eSymbolContextEverything).line_entry,
frame->GetSymbolContext(eSymbolContextEverything),
- stop_other_threads, m_options.m_step_out_avoid_no_debug);
+ stop_other_threads, new_plan_status,
+ m_options.m_step_out_avoid_no_debug);
else
new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
- true, abort_other_plans, bool_stop_other_threads);
+ true, abort_other_plans, bool_stop_other_threads, new_plan_status);
} else if (m_step_type == eStepTypeTrace) {
new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
- false, abort_other_plans, bool_stop_other_threads);
+ false, abort_other_plans, bool_stop_other_threads, new_plan_status);
} else if (m_step_type == eStepTypeTraceOver) {
new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
- true, abort_other_plans, bool_stop_other_threads);
+ true, abort_other_plans, bool_stop_other_threads, new_plan_status);
} else if (m_step_type == eStepTypeOut) {
new_plan_sp = thread->QueueThreadPlanForStepOut(
abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes,
- eVoteNoOpinion, thread->GetSelectedFrameIndex(),
+ eVoteNoOpinion, thread->GetSelectedFrameIndex(), new_plan_status,
m_options.m_step_out_avoid_no_debug);
} else if (m_step_type == eStepTypeScripted) {
new_plan_sp = thread->QueueThreadPlanForStepScripted(
abort_other_plans, m_options.m_class_name.c_str(),
- bool_stop_other_threads);
+ bool_stop_other_threads, new_plan_status);
} else {
result.AppendError("step type is not supported");
result.SetStatus(eReturnStatusFailed);
@@ -801,7 +796,7 @@ protected:
result.SetStatus(eReturnStatusSuccessContinuingNoResult);
}
} else {
- result.AppendError("Couldn't find thread plan to implement step type.");
+ result.SetError(new_plan_status);
result.SetStatus(eReturnStatusFailed);
}
return result.Succeeded();
@@ -997,12 +992,20 @@ public:
// CommandObjectThreadUntil
//-------------------------------------------------------------------------
-static OptionDefinition g_thread_until_options[] = {
+static constexpr OptionEnumValueElement g_duo_running_mode[] = {
+ {eOnlyThisThread, "this-thread", "Run only this thread"},
+ {eAllThreads, "all-threads", "Run all threads"} };
+
+static constexpr OptionEnumValues DuoRunningModes() {
+ return OptionEnumValues(g_duo_running_mode);
+}
+
+static constexpr OptionDefinition g_thread_until_options[] = {
// clang-format off
- { LLDB_OPT_SET_1, false, "frame", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0" },
- { LLDB_OPT_SET_1, false, "thread", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation" },
- { LLDB_OPT_SET_1, false, "run-mode",'m', OptionParser::eRequiredArgument, nullptr, g_duo_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping this one" },
- { LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Run until we reach the specified address, or leave the function - can be specified multiple times." }
+ { LLDB_OPT_SET_1, false, "frame", 'f', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0" },
+ { LLDB_OPT_SET_1, false, "thread", 't', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation" },
+ { LLDB_OPT_SET_1, false, "run-mode",'m', OptionParser::eRequiredArgument, nullptr, DuoRunningModes(), 0, eArgTypeRunMode, "Determine how to run other threads while stepping this one" },
+ { LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddressOrExpression, "Run until we reach the specified address, or leave the function - can be specified multiple times." }
// clang-format on
};
@@ -1050,8 +1053,7 @@ public:
}
break;
case 'm': {
- OptionEnumValueElement *enum_values =
- GetDefinitions()[option_idx].enum_values;
+ auto enum_values = GetDefinitions()[option_idx].enum_values;
lldb::RunMode run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
option_arg, enum_values, eOnlyDuringStepping, error);
@@ -1190,6 +1192,7 @@ protected:
}
ThreadPlanSP new_plan_sp;
+ Status new_plan_status;
if (frame->HasDebugInformation()) {
// Finally we got here... Translate the given line number to a bunch
@@ -1270,13 +1273,19 @@ protected:
new_plan_sp = thread->QueueThreadPlanForStepUntil(
abort_other_plans, &address_list.front(), address_list.size(),
- m_options.m_stop_others, m_options.m_frame_idx);
- // User level plans should be master plans so they can be interrupted
- // (e.g. by hitting a breakpoint) and other plans executed by the user
- // (stepping around the breakpoint) and then a "continue" will resume
- // the original plan.
- new_plan_sp->SetIsMasterPlan(true);
- new_plan_sp->SetOkayToDiscard(false);
+ m_options.m_stop_others, m_options.m_frame_idx, new_plan_status);
+ if (new_plan_sp) {
+ // User level plans should be master plans so they can be interrupted
+ // (e.g. by hitting a breakpoint) and other plans executed by the
+ // user (stepping around the breakpoint) and then a "continue" will
+ // resume the original plan.
+ new_plan_sp->SetIsMasterPlan(true);
+ new_plan_sp->SetOkayToDiscard(false);
+ } else {
+ result.SetError(new_plan_status);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
} else {
result.AppendErrorWithFormat(
"Frame index %u of thread %u has no debug information.\n",
@@ -1419,10 +1428,10 @@ protected:
// CommandObjectThreadInfo
//-------------------------------------------------------------------------
-static OptionDefinition g_thread_info_options[] = {
+static constexpr OptionDefinition g_thread_info_options[] = {
// clang-format off
- { LLDB_OPT_SET_ALL, false, "json", 'j', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display the thread info in JSON format." },
- { LLDB_OPT_SET_ALL, false, "stop-info", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display the extended stop info in JSON format." }
+ { LLDB_OPT_SET_ALL, false, "json", 'j', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Display the thread info in JSON format." },
+ { LLDB_OPT_SET_ALL, false, "stop-info", 's', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Display the extended stop info in JSON format." }
// clang-format on
};
@@ -1511,12 +1520,57 @@ public:
};
//-------------------------------------------------------------------------
+// CommandObjectThreadException
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadException : public CommandObjectIterateOverThreads {
+ public:
+ CommandObjectThreadException(CommandInterpreter &interpreter)
+ : CommandObjectIterateOverThreads(
+ interpreter, "thread exception",
+ "Display the current exception object for a thread. Defaults to "
+ "the current thread.",
+ "thread exception",
+ eCommandRequiresProcess | eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
+
+ ~CommandObjectThreadException() override = default;
+
+ bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
+ ThreadSP thread_sp =
+ m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
+ if (!thread_sp) {
+ result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
+ tid);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Stream &strm = result.GetOutputStream();
+ ValueObjectSP exception_object_sp = thread_sp->GetCurrentException();
+ if (exception_object_sp) {
+ exception_object_sp->Dump(strm);
+ }
+
+ ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace();
+ if (exception_thread_sp && exception_thread_sp->IsValid()) {
+ const uint32_t num_frames_with_source = 0;
+ const bool stop_format = false;
+ exception_thread_sp->GetStatus(strm, 0, UINT32_MAX,
+ num_frames_with_source, stop_format);
+ }
+
+ return true;
+ }
+};
+
+//-------------------------------------------------------------------------
// CommandObjectThreadReturn
//-------------------------------------------------------------------------
-static OptionDefinition g_thread_return_options[] = {
+static constexpr OptionDefinition g_thread_return_options[] = {
// clang-format off
- { LLDB_OPT_SET_ALL, false, "from-expression", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Return from the innermost expression evaluation." }
+ { LLDB_OPT_SET_ALL, false, "from-expression", 'x', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Return from the innermost expression evaluation." }
// clang-format on
};
@@ -1692,13 +1746,13 @@ protected:
// CommandObjectThreadJump
//-------------------------------------------------------------------------
-static OptionDefinition g_thread_jump_options[] = {
+static constexpr OptionDefinition g_thread_jump_options[] = {
// clang-format off
- { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specifies the source file to jump to." },
- { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "Specifies the line number to jump to." },
- { LLDB_OPT_SET_2, true, "by", 'b', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "Jumps by a relative line offset from the current line." },
- { LLDB_OPT_SET_3, true, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Jumps to a specific address." },
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "force", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allows the PC to leave the current function." }
+ { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specifies the source file to jump to." },
+ { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeLineNum, "Specifies the line number to jump to." },
+ { LLDB_OPT_SET_2, true, "by", 'b', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "Jumps by a relative line offset from the current line." },
+ { LLDB_OPT_SET_3, true, "address", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddressOrExpression, "Jumps to a specific address." },
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "force", 'r', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Allows the PC to leave the current function." }
// clang-format on
};
@@ -1725,7 +1779,7 @@ public:
switch (short_option) {
case 'f':
- m_filenames.AppendIfUnique(FileSpec(option_arg, false));
+ m_filenames.AppendIfUnique(FileSpec(option_arg));
if (m_filenames.GetSize() > 1)
return Status("only one source file expected.");
break;
@@ -1844,10 +1898,10 @@ protected:
// CommandObjectThreadPlanList
//-------------------------------------------------------------------------
-static OptionDefinition g_thread_plan_list_options[] = {
+static constexpr OptionDefinition g_thread_plan_list_options[] = {
// clang-format off
- { LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display more information about the thread plans" },
- { LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display internal as well as user thread plans" }
+ { LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Display more information about the thread plans" },
+ { LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Display internal as well as user thread plans" }
// clang-format on
};
@@ -2055,6 +2109,9 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread(
CommandObjectSP(new CommandObjectThreadUntil(interpreter)));
LoadSubCommand("info",
CommandObjectSP(new CommandObjectThreadInfo(interpreter)));
+ LoadSubCommand(
+ "exception",
+ CommandObjectSP(new CommandObjectThreadException(interpreter)));
LoadSubCommand("step-in",
CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
interpreter, "thread step-in",