1dda28197Spatrick //===-- CommandObjectThread.cpp -------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "CommandObjectThread.h"
10061da546Spatrick
11be691f3bSpatrick #include <memory>
12*f6aab3d8Srobert #include <optional>
13be691f3bSpatrick #include <sstream>
14be691f3bSpatrick
15be691f3bSpatrick #include "CommandObjectThreadUtil.h"
16be691f3bSpatrick #include "CommandObjectTrace.h"
17be691f3bSpatrick #include "lldb/Core/PluginManager.h"
18061da546Spatrick #include "lldb/Core/ValueObject.h"
19061da546Spatrick #include "lldb/Host/OptionParser.h"
20061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
21*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
22061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
23061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
24061da546Spatrick #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
25061da546Spatrick #include "lldb/Interpreter/Options.h"
26061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
27061da546Spatrick #include "lldb/Symbol/Function.h"
28061da546Spatrick #include "lldb/Symbol/LineEntry.h"
29061da546Spatrick #include "lldb/Symbol/LineTable.h"
30061da546Spatrick #include "lldb/Target/Process.h"
31061da546Spatrick #include "lldb/Target/RegisterContext.h"
32061da546Spatrick #include "lldb/Target/SystemRuntime.h"
33061da546Spatrick #include "lldb/Target/Target.h"
34061da546Spatrick #include "lldb/Target/Thread.h"
35061da546Spatrick #include "lldb/Target/ThreadPlan.h"
36061da546Spatrick #include "lldb/Target/ThreadPlanStepInRange.h"
37be691f3bSpatrick #include "lldb/Target/Trace.h"
38*f6aab3d8Srobert #include "lldb/Target/TraceDumper.h"
39061da546Spatrick #include "lldb/Utility/State.h"
40061da546Spatrick
41061da546Spatrick using namespace lldb;
42061da546Spatrick using namespace lldb_private;
43061da546Spatrick
44061da546Spatrick // CommandObjectThreadBacktrace
45061da546Spatrick #define LLDB_OPTIONS_thread_backtrace
46061da546Spatrick #include "CommandOptions.inc"
47061da546Spatrick
48061da546Spatrick class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads {
49061da546Spatrick public:
50061da546Spatrick class CommandOptions : public Options {
51061da546Spatrick public:
CommandOptions()52*f6aab3d8Srobert CommandOptions() {
53061da546Spatrick // Keep default values of all options in one place: OptionParsingStarting
54061da546Spatrick // ()
55061da546Spatrick OptionParsingStarting(nullptr);
56061da546Spatrick }
57061da546Spatrick
58061da546Spatrick ~CommandOptions() override = default;
59061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)60061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
61061da546Spatrick ExecutionContext *execution_context) override {
62061da546Spatrick Status error;
63061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
64061da546Spatrick
65061da546Spatrick switch (short_option) {
66*f6aab3d8Srobert case 'c':
67061da546Spatrick if (option_arg.getAsInteger(0, m_count)) {
68061da546Spatrick m_count = UINT32_MAX;
69061da546Spatrick error.SetErrorStringWithFormat(
70061da546Spatrick "invalid integer value for option '%c'", short_option);
71*f6aab3d8Srobert }
72*f6aab3d8Srobert break;
73061da546Spatrick case 's':
74061da546Spatrick if (option_arg.getAsInteger(0, m_start))
75061da546Spatrick error.SetErrorStringWithFormat(
76061da546Spatrick "invalid integer value for option '%c'", short_option);
77061da546Spatrick break;
78061da546Spatrick case 'e': {
79061da546Spatrick bool success;
80061da546Spatrick m_extended_backtrace =
81061da546Spatrick OptionArgParser::ToBoolean(option_arg, false, &success);
82061da546Spatrick if (!success)
83061da546Spatrick error.SetErrorStringWithFormat(
84061da546Spatrick "invalid boolean value for option '%c'", short_option);
85061da546Spatrick } break;
86061da546Spatrick default:
87061da546Spatrick llvm_unreachable("Unimplemented option");
88061da546Spatrick }
89061da546Spatrick return error;
90061da546Spatrick }
91061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)92061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
93061da546Spatrick m_count = UINT32_MAX;
94061da546Spatrick m_start = 0;
95061da546Spatrick m_extended_backtrace = false;
96061da546Spatrick }
97061da546Spatrick
GetDefinitions()98061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
99*f6aab3d8Srobert return llvm::ArrayRef(g_thread_backtrace_options);
100061da546Spatrick }
101061da546Spatrick
102061da546Spatrick // Instance variables to hold the values for command options.
103061da546Spatrick uint32_t m_count;
104061da546Spatrick uint32_t m_start;
105061da546Spatrick bool m_extended_backtrace;
106061da546Spatrick };
107061da546Spatrick
CommandObjectThreadBacktrace(CommandInterpreter & interpreter)108061da546Spatrick CommandObjectThreadBacktrace(CommandInterpreter &interpreter)
109061da546Spatrick : CommandObjectIterateOverThreads(
110061da546Spatrick interpreter, "thread backtrace",
111061da546Spatrick "Show thread call stacks. Defaults to the current thread, thread "
112061da546Spatrick "indexes can be specified as arguments.\n"
113061da546Spatrick "Use the thread-index \"all\" to see all threads.\n"
114061da546Spatrick "Use the thread-index \"unique\" to see threads grouped by unique "
115061da546Spatrick "call stacks.\n"
116061da546Spatrick "Use 'settings set frame-format' to customize the printing of "
117061da546Spatrick "frames in the backtrace and 'settings set thread-format' to "
118061da546Spatrick "customize the thread header.",
119061da546Spatrick nullptr,
120061da546Spatrick eCommandRequiresProcess | eCommandRequiresThread |
121061da546Spatrick eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
122*f6aab3d8Srobert eCommandProcessMustBePaused) {}
123061da546Spatrick
124061da546Spatrick ~CommandObjectThreadBacktrace() override = default;
125061da546Spatrick
GetOptions()126061da546Spatrick Options *GetOptions() override { return &m_options; }
127061da546Spatrick
GetRepeatCommand(Args & current_args,uint32_t idx)128*f6aab3d8Srobert std::optional<std::string> GetRepeatCommand(Args ¤t_args,
129*f6aab3d8Srobert uint32_t idx) override {
130*f6aab3d8Srobert llvm::StringRef count_opt("--count");
131*f6aab3d8Srobert llvm::StringRef start_opt("--start");
132*f6aab3d8Srobert
133*f6aab3d8Srobert // If no "count" was provided, we are dumping the entire backtrace, so
134*f6aab3d8Srobert // there isn't a repeat command. So we search for the count option in
135*f6aab3d8Srobert // the args, and if we find it, we make a copy and insert or modify the
136*f6aab3d8Srobert // start option's value to start count indices greater.
137*f6aab3d8Srobert
138*f6aab3d8Srobert Args copy_args(current_args);
139*f6aab3d8Srobert size_t num_entries = copy_args.GetArgumentCount();
140*f6aab3d8Srobert // These two point at the index of the option value if found.
141*f6aab3d8Srobert size_t count_idx = 0;
142*f6aab3d8Srobert size_t start_idx = 0;
143*f6aab3d8Srobert size_t count_val = 0;
144*f6aab3d8Srobert size_t start_val = 0;
145*f6aab3d8Srobert
146*f6aab3d8Srobert for (size_t idx = 0; idx < num_entries; idx++) {
147*f6aab3d8Srobert llvm::StringRef arg_string = copy_args[idx].ref();
148*f6aab3d8Srobert if (arg_string.equals("-c") || count_opt.startswith(arg_string)) {
149*f6aab3d8Srobert idx++;
150*f6aab3d8Srobert if (idx == num_entries)
151*f6aab3d8Srobert return std::nullopt;
152*f6aab3d8Srobert count_idx = idx;
153*f6aab3d8Srobert if (copy_args[idx].ref().getAsInteger(0, count_val))
154*f6aab3d8Srobert return std::nullopt;
155*f6aab3d8Srobert } else if (arg_string.equals("-s") || start_opt.startswith(arg_string)) {
156*f6aab3d8Srobert idx++;
157*f6aab3d8Srobert if (idx == num_entries)
158*f6aab3d8Srobert return std::nullopt;
159*f6aab3d8Srobert start_idx = idx;
160*f6aab3d8Srobert if (copy_args[idx].ref().getAsInteger(0, start_val))
161*f6aab3d8Srobert return std::nullopt;
162*f6aab3d8Srobert }
163*f6aab3d8Srobert }
164*f6aab3d8Srobert if (count_idx == 0)
165*f6aab3d8Srobert return std::nullopt;
166*f6aab3d8Srobert
167*f6aab3d8Srobert std::string new_start_val = llvm::formatv("{0}", start_val + count_val);
168*f6aab3d8Srobert if (start_idx == 0) {
169*f6aab3d8Srobert copy_args.AppendArgument(start_opt);
170*f6aab3d8Srobert copy_args.AppendArgument(new_start_val);
171*f6aab3d8Srobert } else {
172*f6aab3d8Srobert copy_args.ReplaceArgumentAtIndex(start_idx, new_start_val);
173*f6aab3d8Srobert }
174*f6aab3d8Srobert std::string repeat_command;
175*f6aab3d8Srobert if (!copy_args.GetQuotedCommandString(repeat_command))
176*f6aab3d8Srobert return std::nullopt;
177*f6aab3d8Srobert return repeat_command;
178*f6aab3d8Srobert }
179*f6aab3d8Srobert
180061da546Spatrick protected:
DoExtendedBacktrace(Thread * thread,CommandReturnObject & result)181061da546Spatrick void DoExtendedBacktrace(Thread *thread, CommandReturnObject &result) {
182061da546Spatrick SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime();
183061da546Spatrick if (runtime) {
184061da546Spatrick Stream &strm = result.GetOutputStream();
185061da546Spatrick const std::vector<ConstString> &types =
186061da546Spatrick runtime->GetExtendedBacktraceTypes();
187061da546Spatrick for (auto type : types) {
188061da546Spatrick ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread(
189061da546Spatrick thread->shared_from_this(), type);
190061da546Spatrick if (ext_thread_sp && ext_thread_sp->IsValid()) {
191061da546Spatrick const uint32_t num_frames_with_source = 0;
192061da546Spatrick const bool stop_format = false;
193*f6aab3d8Srobert strm.PutChar('\n');
194061da546Spatrick if (ext_thread_sp->GetStatus(strm, m_options.m_start,
195061da546Spatrick m_options.m_count,
196061da546Spatrick num_frames_with_source, stop_format)) {
197061da546Spatrick DoExtendedBacktrace(ext_thread_sp.get(), result);
198061da546Spatrick }
199061da546Spatrick }
200061da546Spatrick }
201061da546Spatrick }
202061da546Spatrick }
203061da546Spatrick
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)204061da546Spatrick bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
205061da546Spatrick ThreadSP thread_sp =
206061da546Spatrick m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
207061da546Spatrick if (!thread_sp) {
208061da546Spatrick result.AppendErrorWithFormat(
209061da546Spatrick "thread disappeared while computing backtraces: 0x%" PRIx64 "\n",
210061da546Spatrick tid);
211061da546Spatrick return false;
212061da546Spatrick }
213061da546Spatrick
214061da546Spatrick Thread *thread = thread_sp.get();
215061da546Spatrick
216061da546Spatrick Stream &strm = result.GetOutputStream();
217061da546Spatrick
218061da546Spatrick // Only dump stack info if we processing unique stacks.
219061da546Spatrick const bool only_stacks = m_unique_stacks;
220061da546Spatrick
221061da546Spatrick // Don't show source context when doing backtraces.
222061da546Spatrick const uint32_t num_frames_with_source = 0;
223061da546Spatrick const bool stop_format = true;
224061da546Spatrick if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count,
225061da546Spatrick num_frames_with_source, stop_format, only_stacks)) {
226061da546Spatrick result.AppendErrorWithFormat(
227061da546Spatrick "error displaying backtrace for thread: \"0x%4.4x\"\n",
228061da546Spatrick thread->GetIndexID());
229061da546Spatrick return false;
230061da546Spatrick }
231061da546Spatrick if (m_options.m_extended_backtrace) {
232061da546Spatrick DoExtendedBacktrace(thread, result);
233061da546Spatrick }
234061da546Spatrick
235061da546Spatrick return true;
236061da546Spatrick }
237061da546Spatrick
238061da546Spatrick CommandOptions m_options;
239061da546Spatrick };
240061da546Spatrick
241061da546Spatrick enum StepScope { eStepScopeSource, eStepScopeInstruction };
242061da546Spatrick
243061da546Spatrick #define LLDB_OPTIONS_thread_step_scope
244061da546Spatrick #include "CommandOptions.inc"
245061da546Spatrick
246061da546Spatrick class ThreadStepScopeOptionGroup : public OptionGroup {
247061da546Spatrick public:
ThreadStepScopeOptionGroup()248*f6aab3d8Srobert ThreadStepScopeOptionGroup() {
249061da546Spatrick // Keep default values of all options in one place: OptionParsingStarting
250061da546Spatrick // ()
251061da546Spatrick OptionParsingStarting(nullptr);
252061da546Spatrick }
253061da546Spatrick
254061da546Spatrick ~ThreadStepScopeOptionGroup() override = default;
255061da546Spatrick
GetDefinitions()256061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
257*f6aab3d8Srobert return llvm::ArrayRef(g_thread_step_scope_options);
258061da546Spatrick }
259061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)260061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
261061da546Spatrick ExecutionContext *execution_context) override {
262061da546Spatrick Status error;
263061da546Spatrick const int short_option =
264061da546Spatrick g_thread_step_scope_options[option_idx].short_option;
265061da546Spatrick
266061da546Spatrick switch (short_option) {
267061da546Spatrick case 'a': {
268061da546Spatrick bool success;
269061da546Spatrick bool avoid_no_debug =
270061da546Spatrick OptionArgParser::ToBoolean(option_arg, true, &success);
271061da546Spatrick if (!success)
272061da546Spatrick error.SetErrorStringWithFormat("invalid boolean value for option '%c'",
273061da546Spatrick short_option);
274061da546Spatrick else {
275061da546Spatrick m_step_in_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
276061da546Spatrick }
277061da546Spatrick } break;
278061da546Spatrick
279061da546Spatrick case 'A': {
280061da546Spatrick bool success;
281061da546Spatrick bool avoid_no_debug =
282061da546Spatrick OptionArgParser::ToBoolean(option_arg, true, &success);
283061da546Spatrick if (!success)
284061da546Spatrick error.SetErrorStringWithFormat("invalid boolean value for option '%c'",
285061da546Spatrick short_option);
286061da546Spatrick else {
287061da546Spatrick m_step_out_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
288061da546Spatrick }
289061da546Spatrick } break;
290061da546Spatrick
291061da546Spatrick case 'c':
292061da546Spatrick if (option_arg.getAsInteger(0, m_step_count))
293061da546Spatrick error.SetErrorStringWithFormat("invalid step count '%s'",
294061da546Spatrick option_arg.str().c_str());
295061da546Spatrick break;
296061da546Spatrick
297061da546Spatrick case 'm': {
298061da546Spatrick auto enum_values = GetDefinitions()[option_idx].enum_values;
299061da546Spatrick m_run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
300061da546Spatrick option_arg, enum_values, eOnlyDuringStepping, error);
301061da546Spatrick } break;
302061da546Spatrick
303061da546Spatrick case 'e':
304061da546Spatrick if (option_arg == "block") {
305061da546Spatrick m_end_line_is_block_end = true;
306061da546Spatrick break;
307061da546Spatrick }
308061da546Spatrick if (option_arg.getAsInteger(0, m_end_line))
309061da546Spatrick error.SetErrorStringWithFormat("invalid end line number '%s'",
310061da546Spatrick option_arg.str().c_str());
311061da546Spatrick break;
312061da546Spatrick
313061da546Spatrick case 'r':
314061da546Spatrick m_avoid_regexp.clear();
315dda28197Spatrick m_avoid_regexp.assign(std::string(option_arg));
316061da546Spatrick break;
317061da546Spatrick
318061da546Spatrick case 't':
319061da546Spatrick m_step_in_target.clear();
320dda28197Spatrick m_step_in_target.assign(std::string(option_arg));
321061da546Spatrick break;
322061da546Spatrick
323061da546Spatrick default:
324061da546Spatrick llvm_unreachable("Unimplemented option");
325061da546Spatrick }
326061da546Spatrick return error;
327061da546Spatrick }
328061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)329061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
330061da546Spatrick m_step_in_avoid_no_debug = eLazyBoolCalculate;
331061da546Spatrick m_step_out_avoid_no_debug = eLazyBoolCalculate;
332061da546Spatrick m_run_mode = eOnlyDuringStepping;
333061da546Spatrick
334061da546Spatrick // Check if we are in Non-Stop mode
335061da546Spatrick TargetSP target_sp =
336061da546Spatrick execution_context ? execution_context->GetTargetSP() : TargetSP();
337be691f3bSpatrick ProcessSP process_sp =
338be691f3bSpatrick execution_context ? execution_context->GetProcessSP() : ProcessSP();
339be691f3bSpatrick if (process_sp && process_sp->GetSteppingRunsAllThreads())
340be691f3bSpatrick m_run_mode = eAllThreads;
341061da546Spatrick
342061da546Spatrick m_avoid_regexp.clear();
343061da546Spatrick m_step_in_target.clear();
344061da546Spatrick m_step_count = 1;
345061da546Spatrick m_end_line = LLDB_INVALID_LINE_NUMBER;
346061da546Spatrick m_end_line_is_block_end = false;
347061da546Spatrick }
348061da546Spatrick
349061da546Spatrick // Instance variables to hold the values for command options.
350061da546Spatrick LazyBool m_step_in_avoid_no_debug;
351061da546Spatrick LazyBool m_step_out_avoid_no_debug;
352061da546Spatrick RunMode m_run_mode;
353061da546Spatrick std::string m_avoid_regexp;
354061da546Spatrick std::string m_step_in_target;
355061da546Spatrick uint32_t m_step_count;
356061da546Spatrick uint32_t m_end_line;
357061da546Spatrick bool m_end_line_is_block_end;
358061da546Spatrick };
359061da546Spatrick
360061da546Spatrick class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
361061da546Spatrick public:
CommandObjectThreadStepWithTypeAndScope(CommandInterpreter & interpreter,const char * name,const char * help,const char * syntax,StepType step_type,StepScope step_scope)362061da546Spatrick CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter,
363061da546Spatrick const char *name, const char *help,
364061da546Spatrick const char *syntax,
365061da546Spatrick StepType step_type,
366061da546Spatrick StepScope step_scope)
367061da546Spatrick : CommandObjectParsed(interpreter, name, help, syntax,
368061da546Spatrick eCommandRequiresProcess | eCommandRequiresThread |
369061da546Spatrick eCommandTryTargetAPILock |
370061da546Spatrick eCommandProcessMustBeLaunched |
371061da546Spatrick eCommandProcessMustBePaused),
372*f6aab3d8Srobert m_step_type(step_type), m_step_scope(step_scope),
373061da546Spatrick m_class_options("scripted step") {
374061da546Spatrick CommandArgumentEntry arg;
375061da546Spatrick CommandArgumentData thread_id_arg;
376061da546Spatrick
377061da546Spatrick // Define the first (and only) variant of this arg.
378061da546Spatrick thread_id_arg.arg_type = eArgTypeThreadID;
379061da546Spatrick thread_id_arg.arg_repetition = eArgRepeatOptional;
380061da546Spatrick
381061da546Spatrick // There is only one variant this argument could be; put it into the
382061da546Spatrick // argument entry.
383061da546Spatrick arg.push_back(thread_id_arg);
384061da546Spatrick
385061da546Spatrick // Push the data for the first argument into the m_arguments vector.
386061da546Spatrick m_arguments.push_back(arg);
387061da546Spatrick
388061da546Spatrick if (step_type == eStepTypeScripted) {
389061da546Spatrick m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
390061da546Spatrick LLDB_OPT_SET_1);
391061da546Spatrick }
392061da546Spatrick m_all_options.Append(&m_options);
393061da546Spatrick m_all_options.Finalize();
394061da546Spatrick }
395061da546Spatrick
396061da546Spatrick ~CommandObjectThreadStepWithTypeAndScope() override = default;
397061da546Spatrick
398be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)399be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
400be691f3bSpatrick OptionElementVector &opt_element_vector) override {
401be691f3bSpatrick if (request.GetCursorIndex())
402be691f3bSpatrick return;
403be691f3bSpatrick
404be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
405be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
406be691f3bSpatrick request, nullptr);
407be691f3bSpatrick }
408be691f3bSpatrick
GetOptions()409061da546Spatrick Options *GetOptions() override { return &m_all_options; }
410061da546Spatrick
411061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)412061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
413061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
414061da546Spatrick bool synchronous_execution = m_interpreter.GetSynchronous();
415061da546Spatrick
416061da546Spatrick const uint32_t num_threads = process->GetThreadList().GetSize();
417061da546Spatrick Thread *thread = nullptr;
418061da546Spatrick
419061da546Spatrick if (command.GetArgumentCount() == 0) {
420061da546Spatrick thread = GetDefaultThread();
421061da546Spatrick
422061da546Spatrick if (thread == nullptr) {
423061da546Spatrick result.AppendError("no selected thread in process");
424061da546Spatrick return false;
425061da546Spatrick }
426061da546Spatrick } else {
427061da546Spatrick const char *thread_idx_cstr = command.GetArgumentAtIndex(0);
428dda28197Spatrick uint32_t step_thread_idx;
429dda28197Spatrick
430dda28197Spatrick if (!llvm::to_integer(thread_idx_cstr, step_thread_idx)) {
431061da546Spatrick result.AppendErrorWithFormat("invalid thread index '%s'.\n",
432061da546Spatrick thread_idx_cstr);
433061da546Spatrick return false;
434061da546Spatrick }
435061da546Spatrick thread =
436061da546Spatrick process->GetThreadList().FindThreadByIndexID(step_thread_idx).get();
437061da546Spatrick if (thread == nullptr) {
438061da546Spatrick result.AppendErrorWithFormat(
439061da546Spatrick "Thread index %u is out of range (valid values are 0 - %u).\n",
440061da546Spatrick step_thread_idx, num_threads);
441061da546Spatrick return false;
442061da546Spatrick }
443061da546Spatrick }
444061da546Spatrick
445061da546Spatrick if (m_step_type == eStepTypeScripted) {
446061da546Spatrick if (m_class_options.GetName().empty()) {
447061da546Spatrick result.AppendErrorWithFormat("empty class name for scripted step.");
448061da546Spatrick return false;
449061da546Spatrick } else if (!GetDebugger().GetScriptInterpreter()->CheckObjectExists(
450061da546Spatrick m_class_options.GetName().c_str())) {
451061da546Spatrick result.AppendErrorWithFormat(
452061da546Spatrick "class for scripted step: \"%s\" does not exist.",
453061da546Spatrick m_class_options.GetName().c_str());
454061da546Spatrick return false;
455061da546Spatrick }
456061da546Spatrick }
457061da546Spatrick
458061da546Spatrick if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER &&
459061da546Spatrick m_step_type != eStepTypeInto) {
460061da546Spatrick result.AppendErrorWithFormat(
461061da546Spatrick "end line option is only valid for step into");
462061da546Spatrick return false;
463061da546Spatrick }
464061da546Spatrick
465061da546Spatrick const bool abort_other_plans = false;
466061da546Spatrick const lldb::RunMode stop_other_threads = m_options.m_run_mode;
467061da546Spatrick
468061da546Spatrick // This is a bit unfortunate, but not all the commands in this command
469061da546Spatrick // object support only while stepping, so I use the bool for them.
470061da546Spatrick bool bool_stop_other_threads;
471061da546Spatrick if (m_options.m_run_mode == eAllThreads)
472061da546Spatrick bool_stop_other_threads = false;
473061da546Spatrick else if (m_options.m_run_mode == eOnlyDuringStepping)
474be691f3bSpatrick bool_stop_other_threads = (m_step_type != eStepTypeOut);
475061da546Spatrick else
476061da546Spatrick bool_stop_other_threads = true;
477061da546Spatrick
478061da546Spatrick ThreadPlanSP new_plan_sp;
479061da546Spatrick Status new_plan_status;
480061da546Spatrick
481061da546Spatrick if (m_step_type == eStepTypeInto) {
482061da546Spatrick StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
483061da546Spatrick assert(frame != nullptr);
484061da546Spatrick
485061da546Spatrick if (frame->HasDebugInformation()) {
486061da546Spatrick AddressRange range;
487061da546Spatrick SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything);
488061da546Spatrick if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) {
489061da546Spatrick Status error;
490061da546Spatrick if (!sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range,
491061da546Spatrick error)) {
492061da546Spatrick result.AppendErrorWithFormat("invalid end-line option: %s.",
493061da546Spatrick error.AsCString());
494061da546Spatrick return false;
495061da546Spatrick }
496061da546Spatrick } else if (m_options.m_end_line_is_block_end) {
497061da546Spatrick Status error;
498061da546Spatrick Block *block = frame->GetSymbolContext(eSymbolContextBlock).block;
499061da546Spatrick if (!block) {
500061da546Spatrick result.AppendErrorWithFormat("Could not find the current block.");
501061da546Spatrick return false;
502061da546Spatrick }
503061da546Spatrick
504061da546Spatrick AddressRange block_range;
505061da546Spatrick Address pc_address = frame->GetFrameCodeAddress();
506061da546Spatrick block->GetRangeContainingAddress(pc_address, block_range);
507061da546Spatrick if (!block_range.GetBaseAddress().IsValid()) {
508061da546Spatrick result.AppendErrorWithFormat(
509061da546Spatrick "Could not find the current block address.");
510061da546Spatrick return false;
511061da546Spatrick }
512061da546Spatrick lldb::addr_t pc_offset_in_block =
513061da546Spatrick pc_address.GetFileAddress() -
514061da546Spatrick block_range.GetBaseAddress().GetFileAddress();
515061da546Spatrick lldb::addr_t range_length =
516061da546Spatrick block_range.GetByteSize() - pc_offset_in_block;
517061da546Spatrick range = AddressRange(pc_address, range_length);
518061da546Spatrick } else {
519061da546Spatrick range = sc.line_entry.range;
520061da546Spatrick }
521061da546Spatrick
522061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepInRange(
523061da546Spatrick abort_other_plans, range,
524061da546Spatrick frame->GetSymbolContext(eSymbolContextEverything),
525061da546Spatrick m_options.m_step_in_target.c_str(), stop_other_threads,
526061da546Spatrick new_plan_status, m_options.m_step_in_avoid_no_debug,
527061da546Spatrick m_options.m_step_out_avoid_no_debug);
528061da546Spatrick
529061da546Spatrick if (new_plan_sp && !m_options.m_avoid_regexp.empty()) {
530061da546Spatrick ThreadPlanStepInRange *step_in_range_plan =
531061da546Spatrick static_cast<ThreadPlanStepInRange *>(new_plan_sp.get());
532061da546Spatrick step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str());
533061da546Spatrick }
534061da546Spatrick } else
535061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
536061da546Spatrick false, abort_other_plans, bool_stop_other_threads, new_plan_status);
537061da546Spatrick } else if (m_step_type == eStepTypeOver) {
538061da546Spatrick StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
539061da546Spatrick
540061da546Spatrick if (frame->HasDebugInformation())
541061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepOverRange(
542061da546Spatrick abort_other_plans,
543061da546Spatrick frame->GetSymbolContext(eSymbolContextEverything).line_entry,
544061da546Spatrick frame->GetSymbolContext(eSymbolContextEverything),
545061da546Spatrick stop_other_threads, new_plan_status,
546061da546Spatrick m_options.m_step_out_avoid_no_debug);
547061da546Spatrick else
548061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
549061da546Spatrick true, abort_other_plans, bool_stop_other_threads, new_plan_status);
550061da546Spatrick } else if (m_step_type == eStepTypeTrace) {
551061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
552061da546Spatrick false, abort_other_plans, bool_stop_other_threads, new_plan_status);
553061da546Spatrick } else if (m_step_type == eStepTypeTraceOver) {
554061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
555061da546Spatrick true, abort_other_plans, bool_stop_other_threads, new_plan_status);
556061da546Spatrick } else if (m_step_type == eStepTypeOut) {
557061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepOut(
558061da546Spatrick abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes,
559061da546Spatrick eVoteNoOpinion, thread->GetSelectedFrameIndex(), new_plan_status,
560061da546Spatrick m_options.m_step_out_avoid_no_debug);
561061da546Spatrick } else if (m_step_type == eStepTypeScripted) {
562061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepScripted(
563061da546Spatrick abort_other_plans, m_class_options.GetName().c_str(),
564061da546Spatrick m_class_options.GetStructuredData(), bool_stop_other_threads,
565061da546Spatrick new_plan_status);
566061da546Spatrick } else {
567061da546Spatrick result.AppendError("step type is not supported");
568061da546Spatrick return false;
569061da546Spatrick }
570061da546Spatrick
571*f6aab3d8Srobert // If we got a new plan, then set it to be a controlling plan (User level
572*f6aab3d8Srobert // Plans should be controlling plans so that they can be interruptible).
573*f6aab3d8Srobert // Then resume the process.
574061da546Spatrick
575061da546Spatrick if (new_plan_sp) {
576*f6aab3d8Srobert new_plan_sp->SetIsControllingPlan(true);
577061da546Spatrick new_plan_sp->SetOkayToDiscard(false);
578061da546Spatrick
579061da546Spatrick if (m_options.m_step_count > 1) {
580061da546Spatrick if (!new_plan_sp->SetIterationCount(m_options.m_step_count)) {
581061da546Spatrick result.AppendWarning(
582061da546Spatrick "step operation does not support iteration count.");
583061da546Spatrick }
584061da546Spatrick }
585061da546Spatrick
586061da546Spatrick process->GetThreadList().SetSelectedThreadByID(thread->GetID());
587061da546Spatrick
588061da546Spatrick const uint32_t iohandler_id = process->GetIOHandlerID();
589061da546Spatrick
590061da546Spatrick StreamString stream;
591061da546Spatrick Status error;
592061da546Spatrick if (synchronous_execution)
593061da546Spatrick error = process->ResumeSynchronous(&stream);
594061da546Spatrick else
595061da546Spatrick error = process->Resume();
596061da546Spatrick
597061da546Spatrick if (!error.Success()) {
598061da546Spatrick result.AppendMessage(error.AsCString());
599061da546Spatrick return false;
600061da546Spatrick }
601061da546Spatrick
602061da546Spatrick // There is a race condition where this thread will return up the call
603061da546Spatrick // stack to the main command handler and show an (lldb) prompt before
604061da546Spatrick // HandlePrivateEvent (from PrivateStateThread) has a chance to call
605061da546Spatrick // PushProcessIOHandler().
606061da546Spatrick process->SyncIOHandler(iohandler_id, std::chrono::seconds(2));
607061da546Spatrick
608061da546Spatrick if (synchronous_execution) {
609061da546Spatrick // If any state changed events had anything to say, add that to the
610061da546Spatrick // result
611061da546Spatrick if (stream.GetSize() > 0)
612061da546Spatrick result.AppendMessage(stream.GetString());
613061da546Spatrick
614061da546Spatrick process->GetThreadList().SetSelectedThreadByID(thread->GetID());
615061da546Spatrick result.SetDidChangeProcessState(true);
616061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
617061da546Spatrick } else {
618061da546Spatrick result.SetStatus(eReturnStatusSuccessContinuingNoResult);
619061da546Spatrick }
620061da546Spatrick } else {
621061da546Spatrick result.SetError(new_plan_status);
622061da546Spatrick }
623061da546Spatrick return result.Succeeded();
624061da546Spatrick }
625061da546Spatrick
626061da546Spatrick StepType m_step_type;
627061da546Spatrick StepScope m_step_scope;
628061da546Spatrick ThreadStepScopeOptionGroup m_options;
629061da546Spatrick OptionGroupPythonClassWithDict m_class_options;
630061da546Spatrick OptionGroupOptions m_all_options;
631061da546Spatrick };
632061da546Spatrick
633061da546Spatrick // CommandObjectThreadContinue
634061da546Spatrick
635061da546Spatrick class CommandObjectThreadContinue : public CommandObjectParsed {
636061da546Spatrick public:
CommandObjectThreadContinue(CommandInterpreter & interpreter)637061da546Spatrick CommandObjectThreadContinue(CommandInterpreter &interpreter)
638061da546Spatrick : CommandObjectParsed(
639061da546Spatrick interpreter, "thread continue",
640061da546Spatrick "Continue execution of the current target process. One "
641061da546Spatrick "or more threads may be specified, by default all "
642061da546Spatrick "threads continue.",
643061da546Spatrick nullptr,
644061da546Spatrick eCommandRequiresThread | eCommandTryTargetAPILock |
645061da546Spatrick eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
646061da546Spatrick CommandArgumentEntry arg;
647061da546Spatrick CommandArgumentData thread_idx_arg;
648061da546Spatrick
649061da546Spatrick // Define the first (and only) variant of this arg.
650061da546Spatrick thread_idx_arg.arg_type = eArgTypeThreadIndex;
651061da546Spatrick thread_idx_arg.arg_repetition = eArgRepeatPlus;
652061da546Spatrick
653061da546Spatrick // There is only one variant this argument could be; put it into the
654061da546Spatrick // argument entry.
655061da546Spatrick arg.push_back(thread_idx_arg);
656061da546Spatrick
657061da546Spatrick // Push the data for the first argument into the m_arguments vector.
658061da546Spatrick m_arguments.push_back(arg);
659061da546Spatrick }
660061da546Spatrick
661061da546Spatrick ~CommandObjectThreadContinue() override = default;
662061da546Spatrick
663be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)664be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
665be691f3bSpatrick OptionElementVector &opt_element_vector) override {
666be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
667be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
668be691f3bSpatrick request, nullptr);
669be691f3bSpatrick }
670be691f3bSpatrick
DoExecute(Args & command,CommandReturnObject & result)671061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
672061da546Spatrick bool synchronous_execution = m_interpreter.GetSynchronous();
673061da546Spatrick
674061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
675061da546Spatrick if (process == nullptr) {
676061da546Spatrick result.AppendError("no process exists. Cannot continue");
677061da546Spatrick return false;
678061da546Spatrick }
679061da546Spatrick
680061da546Spatrick StateType state = process->GetState();
681061da546Spatrick if ((state == eStateCrashed) || (state == eStateStopped) ||
682061da546Spatrick (state == eStateSuspended)) {
683061da546Spatrick const size_t argc = command.GetArgumentCount();
684061da546Spatrick if (argc > 0) {
685061da546Spatrick // These two lines appear at the beginning of both blocks in this
686061da546Spatrick // if..else, but that is because we need to release the lock before
687061da546Spatrick // calling process->Resume below.
688061da546Spatrick std::lock_guard<std::recursive_mutex> guard(
689061da546Spatrick process->GetThreadList().GetMutex());
690061da546Spatrick const uint32_t num_threads = process->GetThreadList().GetSize();
691061da546Spatrick std::vector<Thread *> resume_threads;
692061da546Spatrick for (auto &entry : command.entries()) {
693061da546Spatrick uint32_t thread_idx;
694061da546Spatrick if (entry.ref().getAsInteger(0, thread_idx)) {
695061da546Spatrick result.AppendErrorWithFormat(
696061da546Spatrick "invalid thread index argument: \"%s\".\n", entry.c_str());
697061da546Spatrick return false;
698061da546Spatrick }
699061da546Spatrick Thread *thread =
700061da546Spatrick process->GetThreadList().FindThreadByIndexID(thread_idx).get();
701061da546Spatrick
702061da546Spatrick if (thread) {
703061da546Spatrick resume_threads.push_back(thread);
704061da546Spatrick } else {
705061da546Spatrick result.AppendErrorWithFormat("invalid thread index %u.\n",
706061da546Spatrick thread_idx);
707061da546Spatrick return false;
708061da546Spatrick }
709061da546Spatrick }
710061da546Spatrick
711061da546Spatrick if (resume_threads.empty()) {
712061da546Spatrick result.AppendError("no valid thread indexes were specified");
713061da546Spatrick return false;
714061da546Spatrick } else {
715061da546Spatrick if (resume_threads.size() == 1)
716061da546Spatrick result.AppendMessageWithFormat("Resuming thread: ");
717061da546Spatrick else
718061da546Spatrick result.AppendMessageWithFormat("Resuming threads: ");
719061da546Spatrick
720061da546Spatrick for (uint32_t idx = 0; idx < num_threads; ++idx) {
721061da546Spatrick Thread *thread =
722061da546Spatrick process->GetThreadList().GetThreadAtIndex(idx).get();
723061da546Spatrick std::vector<Thread *>::iterator this_thread_pos =
724061da546Spatrick find(resume_threads.begin(), resume_threads.end(), thread);
725061da546Spatrick
726061da546Spatrick if (this_thread_pos != resume_threads.end()) {
727061da546Spatrick resume_threads.erase(this_thread_pos);
728061da546Spatrick if (!resume_threads.empty())
729061da546Spatrick result.AppendMessageWithFormat("%u, ", thread->GetIndexID());
730061da546Spatrick else
731061da546Spatrick result.AppendMessageWithFormat("%u ", thread->GetIndexID());
732061da546Spatrick
733061da546Spatrick const bool override_suspend = true;
734061da546Spatrick thread->SetResumeState(eStateRunning, override_suspend);
735061da546Spatrick } else {
736061da546Spatrick thread->SetResumeState(eStateSuspended);
737061da546Spatrick }
738061da546Spatrick }
739061da546Spatrick result.AppendMessageWithFormat("in process %" PRIu64 "\n",
740061da546Spatrick process->GetID());
741061da546Spatrick }
742061da546Spatrick } else {
743061da546Spatrick // These two lines appear at the beginning of both blocks in this
744061da546Spatrick // if..else, but that is because we need to release the lock before
745061da546Spatrick // calling process->Resume below.
746061da546Spatrick std::lock_guard<std::recursive_mutex> guard(
747061da546Spatrick process->GetThreadList().GetMutex());
748061da546Spatrick const uint32_t num_threads = process->GetThreadList().GetSize();
749061da546Spatrick Thread *current_thread = GetDefaultThread();
750061da546Spatrick if (current_thread == nullptr) {
751061da546Spatrick result.AppendError("the process doesn't have a current thread");
752061da546Spatrick return false;
753061da546Spatrick }
754061da546Spatrick // Set the actions that the threads should each take when resuming
755061da546Spatrick for (uint32_t idx = 0; idx < num_threads; ++idx) {
756061da546Spatrick Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
757061da546Spatrick if (thread == current_thread) {
758061da546Spatrick result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64
759061da546Spatrick " in process %" PRIu64 "\n",
760061da546Spatrick thread->GetID(), process->GetID());
761061da546Spatrick const bool override_suspend = true;
762061da546Spatrick thread->SetResumeState(eStateRunning, override_suspend);
763061da546Spatrick } else {
764061da546Spatrick thread->SetResumeState(eStateSuspended);
765061da546Spatrick }
766061da546Spatrick }
767061da546Spatrick }
768061da546Spatrick
769061da546Spatrick StreamString stream;
770061da546Spatrick Status error;
771061da546Spatrick if (synchronous_execution)
772061da546Spatrick error = process->ResumeSynchronous(&stream);
773061da546Spatrick else
774061da546Spatrick error = process->Resume();
775061da546Spatrick
776061da546Spatrick // We should not be holding the thread list lock when we do this.
777061da546Spatrick if (error.Success()) {
778061da546Spatrick result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
779061da546Spatrick process->GetID());
780061da546Spatrick if (synchronous_execution) {
781061da546Spatrick // If any state changed events had anything to say, add that to the
782061da546Spatrick // result
783061da546Spatrick if (stream.GetSize() > 0)
784061da546Spatrick result.AppendMessage(stream.GetString());
785061da546Spatrick
786061da546Spatrick result.SetDidChangeProcessState(true);
787061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
788061da546Spatrick } else {
789061da546Spatrick result.SetStatus(eReturnStatusSuccessContinuingNoResult);
790061da546Spatrick }
791061da546Spatrick } else {
792061da546Spatrick result.AppendErrorWithFormat("Failed to resume process: %s\n",
793061da546Spatrick error.AsCString());
794061da546Spatrick }
795061da546Spatrick } else {
796061da546Spatrick result.AppendErrorWithFormat(
797061da546Spatrick "Process cannot be continued from its current state (%s).\n",
798061da546Spatrick StateAsCString(state));
799061da546Spatrick }
800061da546Spatrick
801061da546Spatrick return result.Succeeded();
802061da546Spatrick }
803061da546Spatrick };
804061da546Spatrick
805061da546Spatrick // CommandObjectThreadUntil
806061da546Spatrick
807061da546Spatrick #define LLDB_OPTIONS_thread_until
808061da546Spatrick #include "CommandOptions.inc"
809061da546Spatrick
810061da546Spatrick class CommandObjectThreadUntil : public CommandObjectParsed {
811061da546Spatrick public:
812061da546Spatrick class CommandOptions : public Options {
813061da546Spatrick public:
814be691f3bSpatrick uint32_t m_thread_idx = LLDB_INVALID_THREAD_ID;
815be691f3bSpatrick uint32_t m_frame_idx = LLDB_INVALID_FRAME_ID;
816061da546Spatrick
CommandOptions()817*f6aab3d8Srobert CommandOptions() {
818061da546Spatrick // Keep default values of all options in one place: OptionParsingStarting
819061da546Spatrick // ()
820061da546Spatrick OptionParsingStarting(nullptr);
821061da546Spatrick }
822061da546Spatrick
823061da546Spatrick ~CommandOptions() override = default;
824061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)825061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
826061da546Spatrick ExecutionContext *execution_context) override {
827061da546Spatrick Status error;
828061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
829061da546Spatrick
830061da546Spatrick switch (short_option) {
831061da546Spatrick case 'a': {
832061da546Spatrick lldb::addr_t tmp_addr = OptionArgParser::ToAddress(
833061da546Spatrick execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
834061da546Spatrick if (error.Success())
835061da546Spatrick m_until_addrs.push_back(tmp_addr);
836061da546Spatrick } break;
837061da546Spatrick case 't':
838061da546Spatrick if (option_arg.getAsInteger(0, m_thread_idx)) {
839061da546Spatrick m_thread_idx = LLDB_INVALID_INDEX32;
840061da546Spatrick error.SetErrorStringWithFormat("invalid thread index '%s'",
841061da546Spatrick option_arg.str().c_str());
842061da546Spatrick }
843061da546Spatrick break;
844061da546Spatrick case 'f':
845061da546Spatrick if (option_arg.getAsInteger(0, m_frame_idx)) {
846061da546Spatrick m_frame_idx = LLDB_INVALID_FRAME_ID;
847061da546Spatrick error.SetErrorStringWithFormat("invalid frame index '%s'",
848061da546Spatrick option_arg.str().c_str());
849061da546Spatrick }
850061da546Spatrick break;
851061da546Spatrick case 'm': {
852061da546Spatrick auto enum_values = GetDefinitions()[option_idx].enum_values;
853061da546Spatrick lldb::RunMode run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
854061da546Spatrick option_arg, enum_values, eOnlyDuringStepping, error);
855061da546Spatrick
856061da546Spatrick if (error.Success()) {
857061da546Spatrick if (run_mode == eAllThreads)
858061da546Spatrick m_stop_others = false;
859061da546Spatrick else
860061da546Spatrick m_stop_others = true;
861061da546Spatrick }
862061da546Spatrick } break;
863061da546Spatrick default:
864061da546Spatrick llvm_unreachable("Unimplemented option");
865061da546Spatrick }
866061da546Spatrick return error;
867061da546Spatrick }
868061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)869061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
870061da546Spatrick m_thread_idx = LLDB_INVALID_THREAD_ID;
871061da546Spatrick m_frame_idx = 0;
872061da546Spatrick m_stop_others = false;
873061da546Spatrick m_until_addrs.clear();
874061da546Spatrick }
875061da546Spatrick
GetDefinitions()876061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
877*f6aab3d8Srobert return llvm::ArrayRef(g_thread_until_options);
878061da546Spatrick }
879061da546Spatrick
880*f6aab3d8Srobert uint32_t m_step_thread_idx = LLDB_INVALID_THREAD_ID;
881*f6aab3d8Srobert bool m_stop_others = false;
882061da546Spatrick std::vector<lldb::addr_t> m_until_addrs;
883061da546Spatrick
884061da546Spatrick // Instance variables to hold the values for command options.
885061da546Spatrick };
886061da546Spatrick
CommandObjectThreadUntil(CommandInterpreter & interpreter)887061da546Spatrick CommandObjectThreadUntil(CommandInterpreter &interpreter)
888061da546Spatrick : CommandObjectParsed(
889061da546Spatrick interpreter, "thread until",
890061da546Spatrick "Continue until a line number or address is reached by the "
891061da546Spatrick "current or specified thread. Stops when returning from "
892061da546Spatrick "the current function as a safety measure. "
893061da546Spatrick "The target line number(s) are given as arguments, and if more "
894061da546Spatrick "than one"
895061da546Spatrick " is provided, stepping will stop when the first one is hit.",
896061da546Spatrick nullptr,
897061da546Spatrick eCommandRequiresThread | eCommandTryTargetAPILock |
898*f6aab3d8Srobert eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
899061da546Spatrick CommandArgumentEntry arg;
900061da546Spatrick CommandArgumentData line_num_arg;
901061da546Spatrick
902061da546Spatrick // Define the first (and only) variant of this arg.
903061da546Spatrick line_num_arg.arg_type = eArgTypeLineNum;
904061da546Spatrick line_num_arg.arg_repetition = eArgRepeatPlain;
905061da546Spatrick
906061da546Spatrick // There is only one variant this argument could be; put it into the
907061da546Spatrick // argument entry.
908061da546Spatrick arg.push_back(line_num_arg);
909061da546Spatrick
910061da546Spatrick // Push the data for the first argument into the m_arguments vector.
911061da546Spatrick m_arguments.push_back(arg);
912061da546Spatrick }
913061da546Spatrick
914061da546Spatrick ~CommandObjectThreadUntil() override = default;
915061da546Spatrick
GetOptions()916061da546Spatrick Options *GetOptions() override { return &m_options; }
917061da546Spatrick
918061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)919061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
920061da546Spatrick bool synchronous_execution = m_interpreter.GetSynchronous();
921061da546Spatrick
922061da546Spatrick Target *target = &GetSelectedTarget();
923061da546Spatrick
924061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
925061da546Spatrick if (process == nullptr) {
926061da546Spatrick result.AppendError("need a valid process to step");
927061da546Spatrick } else {
928061da546Spatrick Thread *thread = nullptr;
929061da546Spatrick std::vector<uint32_t> line_numbers;
930061da546Spatrick
931061da546Spatrick if (command.GetArgumentCount() >= 1) {
932061da546Spatrick size_t num_args = command.GetArgumentCount();
933061da546Spatrick for (size_t i = 0; i < num_args; i++) {
934061da546Spatrick uint32_t line_number;
935dda28197Spatrick if (!llvm::to_integer(command.GetArgumentAtIndex(i), line_number)) {
936061da546Spatrick result.AppendErrorWithFormat("invalid line number: '%s'.\n",
937061da546Spatrick command.GetArgumentAtIndex(i));
938061da546Spatrick return false;
939061da546Spatrick } else
940061da546Spatrick line_numbers.push_back(line_number);
941061da546Spatrick }
942061da546Spatrick } else if (m_options.m_until_addrs.empty()) {
943061da546Spatrick result.AppendErrorWithFormat("No line number or address provided:\n%s",
944061da546Spatrick GetSyntax().str().c_str());
945061da546Spatrick return false;
946061da546Spatrick }
947061da546Spatrick
948061da546Spatrick if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) {
949061da546Spatrick thread = GetDefaultThread();
950061da546Spatrick } else {
951061da546Spatrick thread = process->GetThreadList()
952061da546Spatrick .FindThreadByIndexID(m_options.m_thread_idx)
953061da546Spatrick .get();
954061da546Spatrick }
955061da546Spatrick
956061da546Spatrick if (thread == nullptr) {
957061da546Spatrick const uint32_t num_threads = process->GetThreadList().GetSize();
958061da546Spatrick result.AppendErrorWithFormat(
959061da546Spatrick "Thread index %u is out of range (valid values are 0 - %u).\n",
960061da546Spatrick m_options.m_thread_idx, num_threads);
961061da546Spatrick return false;
962061da546Spatrick }
963061da546Spatrick
964061da546Spatrick const bool abort_other_plans = false;
965061da546Spatrick
966061da546Spatrick StackFrame *frame =
967061da546Spatrick thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
968061da546Spatrick if (frame == nullptr) {
969061da546Spatrick result.AppendErrorWithFormat(
970*f6aab3d8Srobert "Frame index %u is out of range for thread id %" PRIu64 ".\n",
971*f6aab3d8Srobert m_options.m_frame_idx, thread->GetID());
972061da546Spatrick return false;
973061da546Spatrick }
974061da546Spatrick
975061da546Spatrick ThreadPlanSP new_plan_sp;
976061da546Spatrick Status new_plan_status;
977061da546Spatrick
978061da546Spatrick if (frame->HasDebugInformation()) {
979061da546Spatrick // Finally we got here... Translate the given line number to a bunch
980061da546Spatrick // of addresses:
981061da546Spatrick SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit));
982061da546Spatrick LineTable *line_table = nullptr;
983061da546Spatrick if (sc.comp_unit)
984061da546Spatrick line_table = sc.comp_unit->GetLineTable();
985061da546Spatrick
986061da546Spatrick if (line_table == nullptr) {
987061da546Spatrick result.AppendErrorWithFormat("Failed to resolve the line table for "
988*f6aab3d8Srobert "frame %u of thread id %" PRIu64 ".\n",
989*f6aab3d8Srobert m_options.m_frame_idx, thread->GetID());
990061da546Spatrick return false;
991061da546Spatrick }
992061da546Spatrick
993061da546Spatrick LineEntry function_start;
994*f6aab3d8Srobert uint32_t index_ptr = 0, end_ptr = UINT32_MAX;
995061da546Spatrick std::vector<addr_t> address_list;
996061da546Spatrick
997*f6aab3d8Srobert // Find the beginning & end index of the function, but first make
998*f6aab3d8Srobert // sure it is valid:
999*f6aab3d8Srobert if (!sc.function) {
1000*f6aab3d8Srobert result.AppendErrorWithFormat("Have debug information but no "
1001*f6aab3d8Srobert "function info - can't get until range.");
1002*f6aab3d8Srobert return false;
1003*f6aab3d8Srobert }
1004*f6aab3d8Srobert
1005061da546Spatrick AddressRange fun_addr_range = sc.function->GetAddressRange();
1006061da546Spatrick Address fun_start_addr = fun_addr_range.GetBaseAddress();
1007061da546Spatrick line_table->FindLineEntryByAddress(fun_start_addr, function_start,
1008061da546Spatrick &index_ptr);
1009061da546Spatrick
1010061da546Spatrick Address fun_end_addr(fun_start_addr.GetSection(),
1011061da546Spatrick fun_start_addr.GetOffset() +
1012061da546Spatrick fun_addr_range.GetByteSize());
1013061da546Spatrick
1014061da546Spatrick bool all_in_function = true;
1015061da546Spatrick
1016061da546Spatrick line_table->FindLineEntryByAddress(fun_end_addr, function_start,
1017061da546Spatrick &end_ptr);
1018061da546Spatrick
1019*f6aab3d8Srobert // Since not all source lines will contribute code, check if we are
1020*f6aab3d8Srobert // setting the breakpoint on the exact line number or the nearest
1021*f6aab3d8Srobert // subsequent line number and set breakpoints at all the line table
1022*f6aab3d8Srobert // entries of the chosen line number (exact or nearest subsequent).
1023061da546Spatrick for (uint32_t line_number : line_numbers) {
1024061da546Spatrick LineEntry line_entry;
1025*f6aab3d8Srobert bool exact = false;
1026*f6aab3d8Srobert uint32_t start_idx_ptr = index_ptr;
1027*f6aab3d8Srobert start_idx_ptr = sc.comp_unit->FindLineEntry(
1028*f6aab3d8Srobert index_ptr, line_number, nullptr, exact, &line_entry);
1029*f6aab3d8Srobert if (start_idx_ptr != UINT32_MAX)
1030*f6aab3d8Srobert line_number = line_entry.line;
1031*f6aab3d8Srobert exact = true;
1032*f6aab3d8Srobert start_idx_ptr = index_ptr;
1033*f6aab3d8Srobert while (start_idx_ptr <= end_ptr) {
1034061da546Spatrick start_idx_ptr = sc.comp_unit->FindLineEntry(
1035061da546Spatrick start_idx_ptr, line_number, nullptr, exact, &line_entry);
1036061da546Spatrick if (start_idx_ptr == UINT32_MAX)
1037061da546Spatrick break;
1038061da546Spatrick
1039061da546Spatrick addr_t address =
1040061da546Spatrick line_entry.range.GetBaseAddress().GetLoadAddress(target);
1041061da546Spatrick if (address != LLDB_INVALID_ADDRESS) {
1042061da546Spatrick if (fun_addr_range.ContainsLoadAddress(address, target))
1043061da546Spatrick address_list.push_back(address);
1044061da546Spatrick else
1045061da546Spatrick all_in_function = false;
1046061da546Spatrick }
1047061da546Spatrick start_idx_ptr++;
1048061da546Spatrick }
1049061da546Spatrick }
1050061da546Spatrick
1051061da546Spatrick for (lldb::addr_t address : m_options.m_until_addrs) {
1052061da546Spatrick if (fun_addr_range.ContainsLoadAddress(address, target))
1053061da546Spatrick address_list.push_back(address);
1054061da546Spatrick else
1055061da546Spatrick all_in_function = false;
1056061da546Spatrick }
1057061da546Spatrick
1058061da546Spatrick if (address_list.empty()) {
1059061da546Spatrick if (all_in_function)
1060061da546Spatrick result.AppendErrorWithFormat(
1061061da546Spatrick "No line entries matching until target.\n");
1062061da546Spatrick else
1063061da546Spatrick result.AppendErrorWithFormat(
1064061da546Spatrick "Until target outside of the current function.\n");
1065061da546Spatrick
1066061da546Spatrick return false;
1067061da546Spatrick }
1068061da546Spatrick
1069061da546Spatrick new_plan_sp = thread->QueueThreadPlanForStepUntil(
1070061da546Spatrick abort_other_plans, &address_list.front(), address_list.size(),
1071061da546Spatrick m_options.m_stop_others, m_options.m_frame_idx, new_plan_status);
1072061da546Spatrick if (new_plan_sp) {
1073*f6aab3d8Srobert // User level plans should be controlling plans so they can be
1074*f6aab3d8Srobert // interrupted
1075061da546Spatrick // (e.g. by hitting a breakpoint) and other plans executed by the
1076061da546Spatrick // user (stepping around the breakpoint) and then a "continue" will
1077061da546Spatrick // resume the original plan.
1078*f6aab3d8Srobert new_plan_sp->SetIsControllingPlan(true);
1079061da546Spatrick new_plan_sp->SetOkayToDiscard(false);
1080061da546Spatrick } else {
1081061da546Spatrick result.SetError(new_plan_status);
1082061da546Spatrick return false;
1083061da546Spatrick }
1084061da546Spatrick } else {
1085*f6aab3d8Srobert result.AppendErrorWithFormat("Frame index %u of thread id %" PRIu64
1086*f6aab3d8Srobert " has no debug information.\n",
1087*f6aab3d8Srobert m_options.m_frame_idx, thread->GetID());
1088061da546Spatrick return false;
1089061da546Spatrick }
1090061da546Spatrick
1091*f6aab3d8Srobert if (!process->GetThreadList().SetSelectedThreadByID(thread->GetID())) {
1092*f6aab3d8Srobert result.AppendErrorWithFormat(
1093*f6aab3d8Srobert "Failed to set the selected thread to thread id %" PRIu64 ".\n",
1094*f6aab3d8Srobert thread->GetID());
1095*f6aab3d8Srobert return false;
1096*f6aab3d8Srobert }
1097061da546Spatrick
1098061da546Spatrick StreamString stream;
1099061da546Spatrick Status error;
1100061da546Spatrick if (synchronous_execution)
1101061da546Spatrick error = process->ResumeSynchronous(&stream);
1102061da546Spatrick else
1103061da546Spatrick error = process->Resume();
1104061da546Spatrick
1105061da546Spatrick if (error.Success()) {
1106061da546Spatrick result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
1107061da546Spatrick process->GetID());
1108061da546Spatrick if (synchronous_execution) {
1109061da546Spatrick // If any state changed events had anything to say, add that to the
1110061da546Spatrick // result
1111061da546Spatrick if (stream.GetSize() > 0)
1112061da546Spatrick result.AppendMessage(stream.GetString());
1113061da546Spatrick
1114061da546Spatrick result.SetDidChangeProcessState(true);
1115061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1116061da546Spatrick } else {
1117061da546Spatrick result.SetStatus(eReturnStatusSuccessContinuingNoResult);
1118061da546Spatrick }
1119061da546Spatrick } else {
1120061da546Spatrick result.AppendErrorWithFormat("Failed to resume process: %s.\n",
1121061da546Spatrick error.AsCString());
1122061da546Spatrick }
1123061da546Spatrick }
1124061da546Spatrick return result.Succeeded();
1125061da546Spatrick }
1126061da546Spatrick
1127061da546Spatrick CommandOptions m_options;
1128061da546Spatrick };
1129061da546Spatrick
1130061da546Spatrick // CommandObjectThreadSelect
1131061da546Spatrick
1132061da546Spatrick class CommandObjectThreadSelect : public CommandObjectParsed {
1133061da546Spatrick public:
CommandObjectThreadSelect(CommandInterpreter & interpreter)1134061da546Spatrick CommandObjectThreadSelect(CommandInterpreter &interpreter)
1135061da546Spatrick : CommandObjectParsed(interpreter, "thread select",
1136061da546Spatrick "Change the currently selected thread.", nullptr,
1137061da546Spatrick eCommandRequiresProcess | eCommandTryTargetAPILock |
1138061da546Spatrick eCommandProcessMustBeLaunched |
1139061da546Spatrick eCommandProcessMustBePaused) {
1140061da546Spatrick CommandArgumentEntry arg;
1141061da546Spatrick CommandArgumentData thread_idx_arg;
1142061da546Spatrick
1143061da546Spatrick // Define the first (and only) variant of this arg.
1144061da546Spatrick thread_idx_arg.arg_type = eArgTypeThreadIndex;
1145061da546Spatrick thread_idx_arg.arg_repetition = eArgRepeatPlain;
1146061da546Spatrick
1147061da546Spatrick // There is only one variant this argument could be; put it into the
1148061da546Spatrick // argument entry.
1149061da546Spatrick arg.push_back(thread_idx_arg);
1150061da546Spatrick
1151061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1152061da546Spatrick m_arguments.push_back(arg);
1153061da546Spatrick }
1154061da546Spatrick
1155061da546Spatrick ~CommandObjectThreadSelect() override = default;
1156061da546Spatrick
1157be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1158be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
1159be691f3bSpatrick OptionElementVector &opt_element_vector) override {
1160be691f3bSpatrick if (request.GetCursorIndex())
1161be691f3bSpatrick return;
1162be691f3bSpatrick
1163be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1164be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
1165be691f3bSpatrick request, nullptr);
1166be691f3bSpatrick }
1167be691f3bSpatrick
1168061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1169061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1170061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
1171061da546Spatrick if (process == nullptr) {
1172061da546Spatrick result.AppendError("no process");
1173061da546Spatrick return false;
1174061da546Spatrick } else if (command.GetArgumentCount() != 1) {
1175061da546Spatrick result.AppendErrorWithFormat(
1176061da546Spatrick "'%s' takes exactly one thread index argument:\nUsage: %s\n",
1177061da546Spatrick m_cmd_name.c_str(), m_cmd_syntax.c_str());
1178061da546Spatrick return false;
1179061da546Spatrick }
1180061da546Spatrick
1181dda28197Spatrick uint32_t index_id;
1182dda28197Spatrick if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) {
1183dda28197Spatrick result.AppendErrorWithFormat("Invalid thread index '%s'",
1184dda28197Spatrick command.GetArgumentAtIndex(0));
1185dda28197Spatrick return false;
1186dda28197Spatrick }
1187061da546Spatrick
1188061da546Spatrick Thread *new_thread =
1189061da546Spatrick process->GetThreadList().FindThreadByIndexID(index_id).get();
1190061da546Spatrick if (new_thread == nullptr) {
1191061da546Spatrick result.AppendErrorWithFormat("invalid thread #%s.\n",
1192061da546Spatrick command.GetArgumentAtIndex(0));
1193061da546Spatrick return false;
1194061da546Spatrick }
1195061da546Spatrick
1196061da546Spatrick process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);
1197061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1198061da546Spatrick
1199061da546Spatrick return result.Succeeded();
1200061da546Spatrick }
1201061da546Spatrick };
1202061da546Spatrick
1203061da546Spatrick // CommandObjectThreadList
1204061da546Spatrick
1205061da546Spatrick class CommandObjectThreadList : public CommandObjectParsed {
1206061da546Spatrick public:
CommandObjectThreadList(CommandInterpreter & interpreter)1207061da546Spatrick CommandObjectThreadList(CommandInterpreter &interpreter)
1208061da546Spatrick : CommandObjectParsed(
1209061da546Spatrick interpreter, "thread list",
1210061da546Spatrick "Show a summary of each thread in the current target process. "
1211061da546Spatrick "Use 'settings set thread-format' to customize the individual "
1212061da546Spatrick "thread listings.",
1213061da546Spatrick "thread list",
1214061da546Spatrick eCommandRequiresProcess | eCommandTryTargetAPILock |
1215061da546Spatrick eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
1216061da546Spatrick
1217061da546Spatrick ~CommandObjectThreadList() override = default;
1218061da546Spatrick
1219061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1220061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1221061da546Spatrick Stream &strm = result.GetOutputStream();
1222061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1223061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
1224061da546Spatrick const bool only_threads_with_stop_reason = false;
1225061da546Spatrick const uint32_t start_frame = 0;
1226061da546Spatrick const uint32_t num_frames = 0;
1227061da546Spatrick const uint32_t num_frames_with_source = 0;
1228061da546Spatrick process->GetStatus(strm);
1229061da546Spatrick process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame,
1230061da546Spatrick num_frames, num_frames_with_source, false);
1231061da546Spatrick return result.Succeeded();
1232061da546Spatrick }
1233061da546Spatrick };
1234061da546Spatrick
1235061da546Spatrick // CommandObjectThreadInfo
1236061da546Spatrick #define LLDB_OPTIONS_thread_info
1237061da546Spatrick #include "CommandOptions.inc"
1238061da546Spatrick
1239061da546Spatrick class CommandObjectThreadInfo : public CommandObjectIterateOverThreads {
1240061da546Spatrick public:
1241061da546Spatrick class CommandOptions : public Options {
1242061da546Spatrick public:
CommandOptions()1243*f6aab3d8Srobert CommandOptions() { OptionParsingStarting(nullptr); }
1244061da546Spatrick
1245061da546Spatrick ~CommandOptions() override = default;
1246061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1247061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1248061da546Spatrick m_json_thread = false;
1249061da546Spatrick m_json_stopinfo = false;
1250061da546Spatrick }
1251061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1252061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1253061da546Spatrick ExecutionContext *execution_context) override {
1254061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1255061da546Spatrick Status error;
1256061da546Spatrick
1257061da546Spatrick switch (short_option) {
1258061da546Spatrick case 'j':
1259061da546Spatrick m_json_thread = true;
1260061da546Spatrick break;
1261061da546Spatrick
1262061da546Spatrick case 's':
1263061da546Spatrick m_json_stopinfo = true;
1264061da546Spatrick break;
1265061da546Spatrick
1266061da546Spatrick default:
1267061da546Spatrick llvm_unreachable("Unimplemented option");
1268061da546Spatrick }
1269061da546Spatrick return error;
1270061da546Spatrick }
1271061da546Spatrick
GetDefinitions()1272061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1273*f6aab3d8Srobert return llvm::ArrayRef(g_thread_info_options);
1274061da546Spatrick }
1275061da546Spatrick
1276061da546Spatrick bool m_json_thread;
1277061da546Spatrick bool m_json_stopinfo;
1278061da546Spatrick };
1279061da546Spatrick
CommandObjectThreadInfo(CommandInterpreter & interpreter)1280061da546Spatrick CommandObjectThreadInfo(CommandInterpreter &interpreter)
1281061da546Spatrick : CommandObjectIterateOverThreads(
1282061da546Spatrick interpreter, "thread info",
1283061da546Spatrick "Show an extended summary of one or "
1284061da546Spatrick "more threads. Defaults to the "
1285061da546Spatrick "current thread.",
1286061da546Spatrick "thread info",
1287061da546Spatrick eCommandRequiresProcess | eCommandTryTargetAPILock |
1288*f6aab3d8Srobert eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
1289061da546Spatrick m_add_return = false;
1290061da546Spatrick }
1291061da546Spatrick
1292061da546Spatrick ~CommandObjectThreadInfo() override = default;
1293061da546Spatrick
1294be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1295be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
1296be691f3bSpatrick OptionElementVector &opt_element_vector) override {
1297be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1298be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
1299be691f3bSpatrick request, nullptr);
1300be691f3bSpatrick }
1301be691f3bSpatrick
GetOptions()1302061da546Spatrick Options *GetOptions() override { return &m_options; }
1303061da546Spatrick
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)1304061da546Spatrick bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
1305061da546Spatrick ThreadSP thread_sp =
1306061da546Spatrick m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
1307061da546Spatrick if (!thread_sp) {
1308061da546Spatrick result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
1309061da546Spatrick tid);
1310061da546Spatrick return false;
1311061da546Spatrick }
1312061da546Spatrick
1313061da546Spatrick Thread *thread = thread_sp.get();
1314061da546Spatrick
1315061da546Spatrick Stream &strm = result.GetOutputStream();
1316061da546Spatrick if (!thread->GetDescription(strm, eDescriptionLevelFull,
1317061da546Spatrick m_options.m_json_thread,
1318061da546Spatrick m_options.m_json_stopinfo)) {
1319061da546Spatrick result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",
1320061da546Spatrick thread->GetIndexID());
1321061da546Spatrick return false;
1322061da546Spatrick }
1323061da546Spatrick return true;
1324061da546Spatrick }
1325061da546Spatrick
1326061da546Spatrick CommandOptions m_options;
1327061da546Spatrick };
1328061da546Spatrick
1329061da546Spatrick // CommandObjectThreadException
1330061da546Spatrick
1331061da546Spatrick class CommandObjectThreadException : public CommandObjectIterateOverThreads {
1332061da546Spatrick public:
CommandObjectThreadException(CommandInterpreter & interpreter)1333061da546Spatrick CommandObjectThreadException(CommandInterpreter &interpreter)
1334061da546Spatrick : CommandObjectIterateOverThreads(
1335061da546Spatrick interpreter, "thread exception",
1336061da546Spatrick "Display the current exception object for a thread. Defaults to "
1337061da546Spatrick "the current thread.",
1338061da546Spatrick "thread exception",
1339061da546Spatrick eCommandRequiresProcess | eCommandTryTargetAPILock |
1340061da546Spatrick eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
1341061da546Spatrick
1342061da546Spatrick ~CommandObjectThreadException() override = default;
1343061da546Spatrick
1344be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1345be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
1346be691f3bSpatrick OptionElementVector &opt_element_vector) override {
1347be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1348be691f3bSpatrick GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
1349be691f3bSpatrick request, nullptr);
1350be691f3bSpatrick }
1351be691f3bSpatrick
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)1352061da546Spatrick bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
1353061da546Spatrick ThreadSP thread_sp =
1354061da546Spatrick m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
1355061da546Spatrick if (!thread_sp) {
1356061da546Spatrick result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
1357061da546Spatrick tid);
1358061da546Spatrick return false;
1359061da546Spatrick }
1360061da546Spatrick
1361061da546Spatrick Stream &strm = result.GetOutputStream();
1362061da546Spatrick ValueObjectSP exception_object_sp = thread_sp->GetCurrentException();
1363061da546Spatrick if (exception_object_sp) {
1364061da546Spatrick exception_object_sp->Dump(strm);
1365061da546Spatrick }
1366061da546Spatrick
1367061da546Spatrick ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace();
1368061da546Spatrick if (exception_thread_sp && exception_thread_sp->IsValid()) {
1369061da546Spatrick const uint32_t num_frames_with_source = 0;
1370061da546Spatrick const bool stop_format = false;
1371061da546Spatrick exception_thread_sp->GetStatus(strm, 0, UINT32_MAX,
1372061da546Spatrick num_frames_with_source, stop_format);
1373061da546Spatrick }
1374061da546Spatrick
1375061da546Spatrick return true;
1376061da546Spatrick }
1377061da546Spatrick };
1378061da546Spatrick
1379*f6aab3d8Srobert class CommandObjectThreadSiginfo : public CommandObjectIterateOverThreads {
1380*f6aab3d8Srobert public:
CommandObjectThreadSiginfo(CommandInterpreter & interpreter)1381*f6aab3d8Srobert CommandObjectThreadSiginfo(CommandInterpreter &interpreter)
1382*f6aab3d8Srobert : CommandObjectIterateOverThreads(
1383*f6aab3d8Srobert interpreter, "thread siginfo",
1384*f6aab3d8Srobert "Display the current siginfo object for a thread. Defaults to "
1385*f6aab3d8Srobert "the current thread.",
1386*f6aab3d8Srobert "thread siginfo",
1387*f6aab3d8Srobert eCommandRequiresProcess | eCommandTryTargetAPILock |
1388*f6aab3d8Srobert eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
1389*f6aab3d8Srobert
1390*f6aab3d8Srobert ~CommandObjectThreadSiginfo() override = default;
1391*f6aab3d8Srobert
1392*f6aab3d8Srobert void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1393*f6aab3d8Srobert HandleArgumentCompletion(CompletionRequest &request,
1394*f6aab3d8Srobert OptionElementVector &opt_element_vector) override {
1395*f6aab3d8Srobert CommandCompletions::InvokeCommonCompletionCallbacks(
1396*f6aab3d8Srobert GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
1397*f6aab3d8Srobert request, nullptr);
1398*f6aab3d8Srobert }
1399*f6aab3d8Srobert
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)1400*f6aab3d8Srobert bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
1401*f6aab3d8Srobert ThreadSP thread_sp =
1402*f6aab3d8Srobert m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
1403*f6aab3d8Srobert if (!thread_sp) {
1404*f6aab3d8Srobert result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
1405*f6aab3d8Srobert tid);
1406*f6aab3d8Srobert return false;
1407*f6aab3d8Srobert }
1408*f6aab3d8Srobert
1409*f6aab3d8Srobert Stream &strm = result.GetOutputStream();
1410*f6aab3d8Srobert if (!thread_sp->GetDescription(strm, eDescriptionLevelFull, false, false)) {
1411*f6aab3d8Srobert result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",
1412*f6aab3d8Srobert thread_sp->GetIndexID());
1413*f6aab3d8Srobert return false;
1414*f6aab3d8Srobert }
1415*f6aab3d8Srobert ValueObjectSP exception_object_sp = thread_sp->GetSiginfoValue();
1416*f6aab3d8Srobert if (exception_object_sp)
1417*f6aab3d8Srobert exception_object_sp->Dump(strm);
1418*f6aab3d8Srobert else
1419*f6aab3d8Srobert strm.Printf("(no siginfo)\n");
1420*f6aab3d8Srobert strm.PutChar('\n');
1421*f6aab3d8Srobert
1422*f6aab3d8Srobert return true;
1423*f6aab3d8Srobert }
1424*f6aab3d8Srobert };
1425*f6aab3d8Srobert
1426061da546Spatrick // CommandObjectThreadReturn
1427061da546Spatrick #define LLDB_OPTIONS_thread_return
1428061da546Spatrick #include "CommandOptions.inc"
1429061da546Spatrick
1430061da546Spatrick class CommandObjectThreadReturn : public CommandObjectRaw {
1431061da546Spatrick public:
1432061da546Spatrick class CommandOptions : public Options {
1433061da546Spatrick public:
CommandOptions()1434*f6aab3d8Srobert CommandOptions() {
1435061da546Spatrick // Keep default values of all options in one place: OptionParsingStarting
1436061da546Spatrick // ()
1437061da546Spatrick OptionParsingStarting(nullptr);
1438061da546Spatrick }
1439061da546Spatrick
1440061da546Spatrick ~CommandOptions() override = default;
1441061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1442061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1443061da546Spatrick ExecutionContext *execution_context) override {
1444061da546Spatrick Status error;
1445061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1446061da546Spatrick
1447061da546Spatrick switch (short_option) {
1448061da546Spatrick case 'x': {
1449061da546Spatrick bool success;
1450061da546Spatrick bool tmp_value =
1451061da546Spatrick OptionArgParser::ToBoolean(option_arg, false, &success);
1452061da546Spatrick if (success)
1453061da546Spatrick m_from_expression = tmp_value;
1454061da546Spatrick else {
1455061da546Spatrick error.SetErrorStringWithFormat(
1456061da546Spatrick "invalid boolean value '%s' for 'x' option",
1457061da546Spatrick option_arg.str().c_str());
1458061da546Spatrick }
1459061da546Spatrick } break;
1460061da546Spatrick default:
1461061da546Spatrick llvm_unreachable("Unimplemented option");
1462061da546Spatrick }
1463061da546Spatrick return error;
1464061da546Spatrick }
1465061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1466061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1467061da546Spatrick m_from_expression = false;
1468061da546Spatrick }
1469061da546Spatrick
GetDefinitions()1470061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1471*f6aab3d8Srobert return llvm::ArrayRef(g_thread_return_options);
1472061da546Spatrick }
1473061da546Spatrick
1474be691f3bSpatrick bool m_from_expression = false;
1475061da546Spatrick
1476061da546Spatrick // Instance variables to hold the values for command options.
1477061da546Spatrick };
1478061da546Spatrick
CommandObjectThreadReturn(CommandInterpreter & interpreter)1479061da546Spatrick CommandObjectThreadReturn(CommandInterpreter &interpreter)
1480061da546Spatrick : CommandObjectRaw(interpreter, "thread return",
1481061da546Spatrick "Prematurely return from a stack frame, "
1482061da546Spatrick "short-circuiting execution of newer frames "
1483061da546Spatrick "and optionally yielding a specified value. Defaults "
1484061da546Spatrick "to the exiting the current stack "
1485061da546Spatrick "frame.",
1486061da546Spatrick "thread return",
1487061da546Spatrick eCommandRequiresFrame | eCommandTryTargetAPILock |
1488061da546Spatrick eCommandProcessMustBeLaunched |
1489*f6aab3d8Srobert eCommandProcessMustBePaused) {
1490061da546Spatrick CommandArgumentEntry arg;
1491061da546Spatrick CommandArgumentData expression_arg;
1492061da546Spatrick
1493061da546Spatrick // Define the first (and only) variant of this arg.
1494061da546Spatrick expression_arg.arg_type = eArgTypeExpression;
1495061da546Spatrick expression_arg.arg_repetition = eArgRepeatOptional;
1496061da546Spatrick
1497061da546Spatrick // There is only one variant this argument could be; put it into the
1498061da546Spatrick // argument entry.
1499061da546Spatrick arg.push_back(expression_arg);
1500061da546Spatrick
1501061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1502061da546Spatrick m_arguments.push_back(arg);
1503061da546Spatrick }
1504061da546Spatrick
1505061da546Spatrick ~CommandObjectThreadReturn() override = default;
1506061da546Spatrick
GetOptions()1507061da546Spatrick Options *GetOptions() override { return &m_options; }
1508061da546Spatrick
1509061da546Spatrick protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)1510061da546Spatrick bool DoExecute(llvm::StringRef command,
1511061da546Spatrick CommandReturnObject &result) override {
1512061da546Spatrick // I am going to handle this by hand, because I don't want you to have to
1513061da546Spatrick // say:
1514061da546Spatrick // "thread return -- -5".
1515061da546Spatrick if (command.startswith("-x")) {
1516061da546Spatrick if (command.size() != 2U)
1517061da546Spatrick result.AppendWarning("Return values ignored when returning from user "
1518061da546Spatrick "called expressions");
1519061da546Spatrick
1520061da546Spatrick Thread *thread = m_exe_ctx.GetThreadPtr();
1521061da546Spatrick Status error;
1522061da546Spatrick error = thread->UnwindInnermostExpression();
1523061da546Spatrick if (!error.Success()) {
1524061da546Spatrick result.AppendErrorWithFormat("Unwinding expression failed - %s.",
1525061da546Spatrick error.AsCString());
1526061da546Spatrick } else {
1527061da546Spatrick bool success =
1528061da546Spatrick thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream());
1529061da546Spatrick if (success) {
1530061da546Spatrick m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
1531061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1532061da546Spatrick } else {
1533061da546Spatrick result.AppendErrorWithFormat(
1534061da546Spatrick "Could not select 0th frame after unwinding expression.");
1535061da546Spatrick }
1536061da546Spatrick }
1537061da546Spatrick return result.Succeeded();
1538061da546Spatrick }
1539061da546Spatrick
1540061da546Spatrick ValueObjectSP return_valobj_sp;
1541061da546Spatrick
1542061da546Spatrick StackFrameSP frame_sp = m_exe_ctx.GetFrameSP();
1543061da546Spatrick uint32_t frame_idx = frame_sp->GetFrameIndex();
1544061da546Spatrick
1545061da546Spatrick if (frame_sp->IsInlined()) {
1546061da546Spatrick result.AppendError("Don't know how to return from inlined frames.");
1547061da546Spatrick return false;
1548061da546Spatrick }
1549061da546Spatrick
1550061da546Spatrick if (!command.empty()) {
1551061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
1552061da546Spatrick EvaluateExpressionOptions options;
1553061da546Spatrick
1554061da546Spatrick options.SetUnwindOnError(true);
1555061da546Spatrick options.SetUseDynamic(eNoDynamicValues);
1556061da546Spatrick
1557061da546Spatrick ExpressionResults exe_results = eExpressionSetupError;
1558061da546Spatrick exe_results = target->EvaluateExpression(command, frame_sp.get(),
1559061da546Spatrick return_valobj_sp, options);
1560061da546Spatrick if (exe_results != eExpressionCompleted) {
1561061da546Spatrick if (return_valobj_sp)
1562061da546Spatrick result.AppendErrorWithFormat(
1563061da546Spatrick "Error evaluating result expression: %s",
1564061da546Spatrick return_valobj_sp->GetError().AsCString());
1565061da546Spatrick else
1566061da546Spatrick result.AppendErrorWithFormat(
1567061da546Spatrick "Unknown error evaluating result expression.");
1568061da546Spatrick return false;
1569061da546Spatrick }
1570061da546Spatrick }
1571061da546Spatrick
1572061da546Spatrick Status error;
1573061da546Spatrick ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
1574061da546Spatrick const bool broadcast = true;
1575061da546Spatrick error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast);
1576061da546Spatrick if (!error.Success()) {
1577061da546Spatrick result.AppendErrorWithFormat(
1578061da546Spatrick "Error returning from frame %d of thread %d: %s.", frame_idx,
1579061da546Spatrick thread_sp->GetIndexID(), error.AsCString());
1580061da546Spatrick return false;
1581061da546Spatrick }
1582061da546Spatrick
1583061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1584061da546Spatrick return true;
1585061da546Spatrick }
1586061da546Spatrick
1587061da546Spatrick CommandOptions m_options;
1588061da546Spatrick };
1589061da546Spatrick
1590061da546Spatrick // CommandObjectThreadJump
1591061da546Spatrick #define LLDB_OPTIONS_thread_jump
1592061da546Spatrick #include "CommandOptions.inc"
1593061da546Spatrick
1594061da546Spatrick class CommandObjectThreadJump : public CommandObjectParsed {
1595061da546Spatrick public:
1596061da546Spatrick class CommandOptions : public Options {
1597061da546Spatrick public:
CommandOptions()1598*f6aab3d8Srobert CommandOptions() { OptionParsingStarting(nullptr); }
1599061da546Spatrick
1600061da546Spatrick ~CommandOptions() override = default;
1601061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1602061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1603061da546Spatrick m_filenames.Clear();
1604061da546Spatrick m_line_num = 0;
1605061da546Spatrick m_line_offset = 0;
1606061da546Spatrick m_load_addr = LLDB_INVALID_ADDRESS;
1607061da546Spatrick m_force = false;
1608061da546Spatrick }
1609061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1610061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1611061da546Spatrick ExecutionContext *execution_context) override {
1612061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1613061da546Spatrick Status error;
1614061da546Spatrick
1615061da546Spatrick switch (short_option) {
1616061da546Spatrick case 'f':
1617061da546Spatrick m_filenames.AppendIfUnique(FileSpec(option_arg));
1618061da546Spatrick if (m_filenames.GetSize() > 1)
1619061da546Spatrick return Status("only one source file expected.");
1620061da546Spatrick break;
1621061da546Spatrick case 'l':
1622061da546Spatrick if (option_arg.getAsInteger(0, m_line_num))
1623061da546Spatrick return Status("invalid line number: '%s'.", option_arg.str().c_str());
1624061da546Spatrick break;
1625061da546Spatrick case 'b':
1626061da546Spatrick if (option_arg.getAsInteger(0, m_line_offset))
1627061da546Spatrick return Status("invalid line offset: '%s'.", option_arg.str().c_str());
1628061da546Spatrick break;
1629061da546Spatrick case 'a':
1630061da546Spatrick m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
1631061da546Spatrick LLDB_INVALID_ADDRESS, &error);
1632061da546Spatrick break;
1633061da546Spatrick case 'r':
1634061da546Spatrick m_force = true;
1635061da546Spatrick break;
1636061da546Spatrick default:
1637061da546Spatrick llvm_unreachable("Unimplemented option");
1638061da546Spatrick }
1639061da546Spatrick return error;
1640061da546Spatrick }
1641061da546Spatrick
GetDefinitions()1642061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1643*f6aab3d8Srobert return llvm::ArrayRef(g_thread_jump_options);
1644061da546Spatrick }
1645061da546Spatrick
1646061da546Spatrick FileSpecList m_filenames;
1647061da546Spatrick uint32_t m_line_num;
1648061da546Spatrick int32_t m_line_offset;
1649061da546Spatrick lldb::addr_t m_load_addr;
1650061da546Spatrick bool m_force;
1651061da546Spatrick };
1652061da546Spatrick
CommandObjectThreadJump(CommandInterpreter & interpreter)1653061da546Spatrick CommandObjectThreadJump(CommandInterpreter &interpreter)
1654061da546Spatrick : CommandObjectParsed(
1655061da546Spatrick interpreter, "thread jump",
1656061da546Spatrick "Sets the program counter to a new address.", "thread jump",
1657061da546Spatrick eCommandRequiresFrame | eCommandTryTargetAPILock |
1658*f6aab3d8Srobert eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
1659061da546Spatrick
1660061da546Spatrick ~CommandObjectThreadJump() override = default;
1661061da546Spatrick
GetOptions()1662061da546Spatrick Options *GetOptions() override { return &m_options; }
1663061da546Spatrick
1664061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)1665061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
1666061da546Spatrick RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
1667061da546Spatrick StackFrame *frame = m_exe_ctx.GetFramePtr();
1668061da546Spatrick Thread *thread = m_exe_ctx.GetThreadPtr();
1669061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
1670061da546Spatrick const SymbolContext &sym_ctx =
1671061da546Spatrick frame->GetSymbolContext(eSymbolContextLineEntry);
1672061da546Spatrick
1673061da546Spatrick if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) {
1674061da546Spatrick // Use this address directly.
1675061da546Spatrick Address dest = Address(m_options.m_load_addr);
1676061da546Spatrick
1677061da546Spatrick lldb::addr_t callAddr = dest.GetCallableLoadAddress(target);
1678061da546Spatrick if (callAddr == LLDB_INVALID_ADDRESS) {
1679061da546Spatrick result.AppendErrorWithFormat("Invalid destination address.");
1680061da546Spatrick return false;
1681061da546Spatrick }
1682061da546Spatrick
1683061da546Spatrick if (!reg_ctx->SetPC(callAddr)) {
1684061da546Spatrick result.AppendErrorWithFormat("Error changing PC value for thread %d.",
1685061da546Spatrick thread->GetIndexID());
1686061da546Spatrick return false;
1687061da546Spatrick }
1688061da546Spatrick } else {
1689061da546Spatrick // Pick either the absolute line, or work out a relative one.
1690061da546Spatrick int32_t line = (int32_t)m_options.m_line_num;
1691061da546Spatrick if (line == 0)
1692061da546Spatrick line = sym_ctx.line_entry.line + m_options.m_line_offset;
1693061da546Spatrick
1694061da546Spatrick // Try the current file, but override if asked.
1695061da546Spatrick FileSpec file = sym_ctx.line_entry.file;
1696061da546Spatrick if (m_options.m_filenames.GetSize() == 1)
1697061da546Spatrick file = m_options.m_filenames.GetFileSpecAtIndex(0);
1698061da546Spatrick
1699061da546Spatrick if (!file) {
1700061da546Spatrick result.AppendErrorWithFormat(
1701061da546Spatrick "No source file available for the current location.");
1702061da546Spatrick return false;
1703061da546Spatrick }
1704061da546Spatrick
1705061da546Spatrick std::string warnings;
1706061da546Spatrick Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings);
1707061da546Spatrick
1708061da546Spatrick if (err.Fail()) {
1709061da546Spatrick result.SetError(err);
1710061da546Spatrick return false;
1711061da546Spatrick }
1712061da546Spatrick
1713061da546Spatrick if (!warnings.empty())
1714061da546Spatrick result.AppendWarning(warnings.c_str());
1715061da546Spatrick }
1716061da546Spatrick
1717061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1718061da546Spatrick return true;
1719061da546Spatrick }
1720061da546Spatrick
1721061da546Spatrick CommandOptions m_options;
1722061da546Spatrick };
1723061da546Spatrick
1724061da546Spatrick // Next are the subcommands of CommandObjectMultiwordThreadPlan
1725061da546Spatrick
1726061da546Spatrick // CommandObjectThreadPlanList
1727061da546Spatrick #define LLDB_OPTIONS_thread_plan_list
1728061da546Spatrick #include "CommandOptions.inc"
1729061da546Spatrick
1730061da546Spatrick class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads {
1731061da546Spatrick public:
1732061da546Spatrick class CommandOptions : public Options {
1733061da546Spatrick public:
CommandOptions()1734*f6aab3d8Srobert CommandOptions() {
1735061da546Spatrick // Keep default values of all options in one place: OptionParsingStarting
1736061da546Spatrick // ()
1737061da546Spatrick OptionParsingStarting(nullptr);
1738061da546Spatrick }
1739061da546Spatrick
1740061da546Spatrick ~CommandOptions() override = default;
1741061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1742061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1743061da546Spatrick ExecutionContext *execution_context) override {
1744061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1745061da546Spatrick
1746061da546Spatrick switch (short_option) {
1747061da546Spatrick case 'i':
1748061da546Spatrick m_internal = true;
1749061da546Spatrick break;
1750dda28197Spatrick case 't':
1751dda28197Spatrick lldb::tid_t tid;
1752dda28197Spatrick if (option_arg.getAsInteger(0, tid))
1753dda28197Spatrick return Status("invalid tid: '%s'.", option_arg.str().c_str());
1754dda28197Spatrick m_tids.push_back(tid);
1755dda28197Spatrick break;
1756dda28197Spatrick case 'u':
1757dda28197Spatrick m_unreported = false;
1758dda28197Spatrick break;
1759061da546Spatrick case 'v':
1760061da546Spatrick m_verbose = true;
1761061da546Spatrick break;
1762061da546Spatrick default:
1763061da546Spatrick llvm_unreachable("Unimplemented option");
1764061da546Spatrick }
1765dda28197Spatrick return {};
1766061da546Spatrick }
1767061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1768061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1769061da546Spatrick m_verbose = false;
1770061da546Spatrick m_internal = false;
1771dda28197Spatrick m_unreported = true; // The variable is "skip unreported" and we want to
1772dda28197Spatrick // skip unreported by default.
1773dda28197Spatrick m_tids.clear();
1774061da546Spatrick }
1775061da546Spatrick
GetDefinitions()1776061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1777*f6aab3d8Srobert return llvm::ArrayRef(g_thread_plan_list_options);
1778061da546Spatrick }
1779061da546Spatrick
1780061da546Spatrick // Instance variables to hold the values for command options.
1781061da546Spatrick bool m_verbose;
1782061da546Spatrick bool m_internal;
1783dda28197Spatrick bool m_unreported;
1784dda28197Spatrick std::vector<lldb::tid_t> m_tids;
1785061da546Spatrick };
1786061da546Spatrick
CommandObjectThreadPlanList(CommandInterpreter & interpreter)1787061da546Spatrick CommandObjectThreadPlanList(CommandInterpreter &interpreter)
1788061da546Spatrick : CommandObjectIterateOverThreads(
1789061da546Spatrick interpreter, "thread plan list",
1790061da546Spatrick "Show thread plans for one or more threads. If no threads are "
1791061da546Spatrick "specified, show the "
1792061da546Spatrick "current thread. Use the thread-index \"all\" to see all threads.",
1793061da546Spatrick nullptr,
1794061da546Spatrick eCommandRequiresProcess | eCommandRequiresThread |
1795061da546Spatrick eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
1796*f6aab3d8Srobert eCommandProcessMustBePaused) {}
1797061da546Spatrick
1798061da546Spatrick ~CommandObjectThreadPlanList() override = default;
1799061da546Spatrick
GetOptions()1800061da546Spatrick Options *GetOptions() override { return &m_options; }
1801061da546Spatrick
DoExecute(Args & command,CommandReturnObject & result)1802dda28197Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1803dda28197Spatrick // If we are reporting all threads, dispatch to the Process to do that:
1804dda28197Spatrick if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) {
1805dda28197Spatrick Stream &strm = result.GetOutputStream();
1806dda28197Spatrick DescriptionLevel desc_level = m_options.m_verbose
1807dda28197Spatrick ? eDescriptionLevelVerbose
1808dda28197Spatrick : eDescriptionLevelFull;
1809dda28197Spatrick m_exe_ctx.GetProcessPtr()->DumpThreadPlans(
1810dda28197Spatrick strm, desc_level, m_options.m_internal, true, m_options.m_unreported);
1811dda28197Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1812dda28197Spatrick return true;
1813dda28197Spatrick } else {
1814dda28197Spatrick // Do any TID's that the user may have specified as TID, then do any
1815dda28197Spatrick // Thread Indexes...
1816dda28197Spatrick if (!m_options.m_tids.empty()) {
1817dda28197Spatrick Process *process = m_exe_ctx.GetProcessPtr();
1818dda28197Spatrick StreamString tmp_strm;
1819dda28197Spatrick for (lldb::tid_t tid : m_options.m_tids) {
1820dda28197Spatrick bool success = process->DumpThreadPlansForTID(
1821dda28197Spatrick tmp_strm, tid, eDescriptionLevelFull, m_options.m_internal,
1822dda28197Spatrick true /* condense_trivial */, m_options.m_unreported);
1823dda28197Spatrick // If we didn't find a TID, stop here and return an error.
1824dda28197Spatrick if (!success) {
1825be691f3bSpatrick result.AppendError("Error dumping plans:");
1826dda28197Spatrick result.AppendError(tmp_strm.GetString());
1827061da546Spatrick return false;
1828061da546Spatrick }
1829dda28197Spatrick // Otherwise, add our data to the output:
1830dda28197Spatrick result.GetOutputStream() << tmp_strm.GetString();
1831dda28197Spatrick }
1832dda28197Spatrick }
1833dda28197Spatrick return CommandObjectIterateOverThreads::DoExecute(command, result);
1834dda28197Spatrick }
1835dda28197Spatrick }
1836061da546Spatrick
1837dda28197Spatrick protected:
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)1838dda28197Spatrick bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
1839dda28197Spatrick // If we have already handled this from a -t option, skip it here.
1840be691f3bSpatrick if (llvm::is_contained(m_options.m_tids, tid))
1841dda28197Spatrick return true;
1842dda28197Spatrick
1843dda28197Spatrick Process *process = m_exe_ctx.GetProcessPtr();
1844061da546Spatrick
1845061da546Spatrick Stream &strm = result.GetOutputStream();
1846061da546Spatrick DescriptionLevel desc_level = eDescriptionLevelFull;
1847061da546Spatrick if (m_options.m_verbose)
1848061da546Spatrick desc_level = eDescriptionLevelVerbose;
1849061da546Spatrick
1850dda28197Spatrick process->DumpThreadPlansForTID(strm, tid, desc_level, m_options.m_internal,
1851dda28197Spatrick true /* condense_trivial */,
1852dda28197Spatrick m_options.m_unreported);
1853061da546Spatrick return true;
1854061da546Spatrick }
1855061da546Spatrick
1856061da546Spatrick CommandOptions m_options;
1857061da546Spatrick };
1858061da546Spatrick
1859061da546Spatrick class CommandObjectThreadPlanDiscard : public CommandObjectParsed {
1860061da546Spatrick public:
CommandObjectThreadPlanDiscard(CommandInterpreter & interpreter)1861061da546Spatrick CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter)
1862061da546Spatrick : CommandObjectParsed(interpreter, "thread plan discard",
1863061da546Spatrick "Discards thread plans up to and including the "
1864061da546Spatrick "specified index (see 'thread plan list'.) "
1865061da546Spatrick "Only user visible plans can be discarded.",
1866061da546Spatrick nullptr,
1867061da546Spatrick eCommandRequiresProcess | eCommandRequiresThread |
1868061da546Spatrick eCommandTryTargetAPILock |
1869061da546Spatrick eCommandProcessMustBeLaunched |
1870061da546Spatrick eCommandProcessMustBePaused) {
1871061da546Spatrick CommandArgumentEntry arg;
1872061da546Spatrick CommandArgumentData plan_index_arg;
1873061da546Spatrick
1874061da546Spatrick // Define the first (and only) variant of this arg.
1875061da546Spatrick plan_index_arg.arg_type = eArgTypeUnsignedInteger;
1876061da546Spatrick plan_index_arg.arg_repetition = eArgRepeatPlain;
1877061da546Spatrick
1878061da546Spatrick // There is only one variant this argument could be; put it into the
1879061da546Spatrick // argument entry.
1880061da546Spatrick arg.push_back(plan_index_arg);
1881061da546Spatrick
1882061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1883061da546Spatrick m_arguments.push_back(arg);
1884061da546Spatrick }
1885061da546Spatrick
1886061da546Spatrick ~CommandObjectThreadPlanDiscard() override = default;
1887061da546Spatrick
1888be691f3bSpatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1889be691f3bSpatrick HandleArgumentCompletion(CompletionRequest &request,
1890be691f3bSpatrick OptionElementVector &opt_element_vector) override {
1891be691f3bSpatrick if (!m_exe_ctx.HasThreadScope() || request.GetCursorIndex())
1892be691f3bSpatrick return;
1893be691f3bSpatrick
1894be691f3bSpatrick m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request);
1895be691f3bSpatrick }
1896be691f3bSpatrick
DoExecute(Args & args,CommandReturnObject & result)1897061da546Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
1898061da546Spatrick Thread *thread = m_exe_ctx.GetThreadPtr();
1899061da546Spatrick if (args.GetArgumentCount() != 1) {
1900061da546Spatrick result.AppendErrorWithFormat("Too many arguments, expected one - the "
1901061da546Spatrick "thread plan index - but got %zu.",
1902061da546Spatrick args.GetArgumentCount());
1903061da546Spatrick return false;
1904061da546Spatrick }
1905061da546Spatrick
1906dda28197Spatrick uint32_t thread_plan_idx;
1907dda28197Spatrick if (!llvm::to_integer(args.GetArgumentAtIndex(0), thread_plan_idx)) {
1908061da546Spatrick result.AppendErrorWithFormat(
1909061da546Spatrick "Invalid thread index: \"%s\" - should be unsigned int.",
1910061da546Spatrick args.GetArgumentAtIndex(0));
1911061da546Spatrick return false;
1912061da546Spatrick }
1913061da546Spatrick
1914061da546Spatrick if (thread_plan_idx == 0) {
1915061da546Spatrick result.AppendErrorWithFormat(
1916061da546Spatrick "You wouldn't really want me to discard the base thread plan.");
1917061da546Spatrick return false;
1918061da546Spatrick }
1919061da546Spatrick
1920061da546Spatrick if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) {
1921061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1922061da546Spatrick return true;
1923061da546Spatrick } else {
1924061da546Spatrick result.AppendErrorWithFormat(
1925061da546Spatrick "Could not find User thread plan with index %s.",
1926061da546Spatrick args.GetArgumentAtIndex(0));
1927061da546Spatrick return false;
1928061da546Spatrick }
1929061da546Spatrick }
1930061da546Spatrick };
1931061da546Spatrick
1932dda28197Spatrick class CommandObjectThreadPlanPrune : public CommandObjectParsed {
1933dda28197Spatrick public:
CommandObjectThreadPlanPrune(CommandInterpreter & interpreter)1934dda28197Spatrick CommandObjectThreadPlanPrune(CommandInterpreter &interpreter)
1935dda28197Spatrick : CommandObjectParsed(interpreter, "thread plan prune",
1936dda28197Spatrick "Removes any thread plans associated with "
1937dda28197Spatrick "currently unreported threads. "
1938dda28197Spatrick "Specify one or more TID's to remove, or if no "
1939dda28197Spatrick "TID's are provides, remove threads for all "
1940dda28197Spatrick "unreported threads",
1941dda28197Spatrick nullptr,
1942dda28197Spatrick eCommandRequiresProcess |
1943dda28197Spatrick eCommandTryTargetAPILock |
1944dda28197Spatrick eCommandProcessMustBeLaunched |
1945dda28197Spatrick eCommandProcessMustBePaused) {
1946dda28197Spatrick CommandArgumentEntry arg;
1947dda28197Spatrick CommandArgumentData tid_arg;
1948dda28197Spatrick
1949dda28197Spatrick // Define the first (and only) variant of this arg.
1950dda28197Spatrick tid_arg.arg_type = eArgTypeThreadID;
1951dda28197Spatrick tid_arg.arg_repetition = eArgRepeatStar;
1952dda28197Spatrick
1953dda28197Spatrick // There is only one variant this argument could be; put it into the
1954dda28197Spatrick // argument entry.
1955dda28197Spatrick arg.push_back(tid_arg);
1956dda28197Spatrick
1957dda28197Spatrick // Push the data for the first argument into the m_arguments vector.
1958dda28197Spatrick m_arguments.push_back(arg);
1959dda28197Spatrick }
1960dda28197Spatrick
1961dda28197Spatrick ~CommandObjectThreadPlanPrune() override = default;
1962dda28197Spatrick
DoExecute(Args & args,CommandReturnObject & result)1963dda28197Spatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
1964dda28197Spatrick Process *process = m_exe_ctx.GetProcessPtr();
1965dda28197Spatrick
1966dda28197Spatrick if (args.GetArgumentCount() == 0) {
1967dda28197Spatrick process->PruneThreadPlans();
1968dda28197Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1969dda28197Spatrick return true;
1970dda28197Spatrick }
1971dda28197Spatrick
1972dda28197Spatrick const size_t num_args = args.GetArgumentCount();
1973dda28197Spatrick
1974dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(
1975dda28197Spatrick process->GetThreadList().GetMutex());
1976dda28197Spatrick
1977dda28197Spatrick for (size_t i = 0; i < num_args; i++) {
1978dda28197Spatrick lldb::tid_t tid;
1979dda28197Spatrick if (!llvm::to_integer(args.GetArgumentAtIndex(i), tid)) {
1980dda28197Spatrick result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
1981dda28197Spatrick args.GetArgumentAtIndex(i));
1982dda28197Spatrick return false;
1983dda28197Spatrick }
1984dda28197Spatrick if (!process->PruneThreadPlansForTID(tid)) {
1985dda28197Spatrick result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n",
1986dda28197Spatrick args.GetArgumentAtIndex(i));
1987dda28197Spatrick return false;
1988dda28197Spatrick }
1989dda28197Spatrick }
1990dda28197Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1991dda28197Spatrick return true;
1992dda28197Spatrick }
1993dda28197Spatrick };
1994dda28197Spatrick
1995061da546Spatrick // CommandObjectMultiwordThreadPlan
1996061da546Spatrick
1997061da546Spatrick class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword {
1998061da546Spatrick public:
CommandObjectMultiwordThreadPlan(CommandInterpreter & interpreter)1999061da546Spatrick CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter)
2000061da546Spatrick : CommandObjectMultiword(
2001061da546Spatrick interpreter, "plan",
2002061da546Spatrick "Commands for managing thread plans that control execution.",
2003061da546Spatrick "thread plan <subcommand> [<subcommand objects]") {
2004061da546Spatrick LoadSubCommand(
2005061da546Spatrick "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter)));
2006061da546Spatrick LoadSubCommand(
2007061da546Spatrick "discard",
2008061da546Spatrick CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter)));
2009dda28197Spatrick LoadSubCommand(
2010dda28197Spatrick "prune",
2011dda28197Spatrick CommandObjectSP(new CommandObjectThreadPlanPrune(interpreter)));
2012061da546Spatrick }
2013061da546Spatrick
2014061da546Spatrick ~CommandObjectMultiwordThreadPlan() override = default;
2015061da546Spatrick };
2016061da546Spatrick
2017be691f3bSpatrick // Next are the subcommands of CommandObjectMultiwordTrace
2018be691f3bSpatrick
2019be691f3bSpatrick // CommandObjectTraceExport
2020be691f3bSpatrick
2021be691f3bSpatrick class CommandObjectTraceExport : public CommandObjectMultiword {
2022be691f3bSpatrick public:
CommandObjectTraceExport(CommandInterpreter & interpreter)2023be691f3bSpatrick CommandObjectTraceExport(CommandInterpreter &interpreter)
2024be691f3bSpatrick : CommandObjectMultiword(
2025be691f3bSpatrick interpreter, "trace thread export",
2026be691f3bSpatrick "Commands for exporting traces of the threads in the current "
2027be691f3bSpatrick "process to different formats.",
2028be691f3bSpatrick "thread trace export <export-plugin> [<subcommand objects>]") {
2029be691f3bSpatrick
2030*f6aab3d8Srobert unsigned i = 0;
2031*f6aab3d8Srobert for (llvm::StringRef plugin_name =
2032*f6aab3d8Srobert PluginManager::GetTraceExporterPluginNameAtIndex(i);
2033*f6aab3d8Srobert !plugin_name.empty();
2034*f6aab3d8Srobert plugin_name = PluginManager::GetTraceExporterPluginNameAtIndex(i++)) {
2035be691f3bSpatrick if (ThreadTraceExportCommandCreator command_creator =
2036be691f3bSpatrick PluginManager::GetThreadTraceExportCommandCreatorAtIndex(i)) {
2037be691f3bSpatrick LoadSubCommand(plugin_name, command_creator(interpreter));
2038be691f3bSpatrick }
2039be691f3bSpatrick }
2040be691f3bSpatrick }
2041be691f3bSpatrick };
2042be691f3bSpatrick
2043be691f3bSpatrick // CommandObjectTraceStart
2044be691f3bSpatrick
2045be691f3bSpatrick class CommandObjectTraceStart : public CommandObjectTraceProxy {
2046be691f3bSpatrick public:
CommandObjectTraceStart(CommandInterpreter & interpreter)2047be691f3bSpatrick CommandObjectTraceStart(CommandInterpreter &interpreter)
2048be691f3bSpatrick : CommandObjectTraceProxy(
2049be691f3bSpatrick /*live_debug_session_only=*/true, interpreter, "thread trace start",
2050be691f3bSpatrick "Start tracing threads with the corresponding trace "
2051be691f3bSpatrick "plug-in for the current process.",
2052be691f3bSpatrick "thread trace start [<trace-options>]") {}
2053be691f3bSpatrick
2054be691f3bSpatrick protected:
GetDelegateCommand(Trace & trace)2055be691f3bSpatrick lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {
2056be691f3bSpatrick return trace.GetThreadTraceStartCommand(m_interpreter);
2057be691f3bSpatrick }
2058be691f3bSpatrick };
2059be691f3bSpatrick
2060be691f3bSpatrick // CommandObjectTraceStop
2061be691f3bSpatrick
2062be691f3bSpatrick class CommandObjectTraceStop : public CommandObjectMultipleThreads {
2063be691f3bSpatrick public:
CommandObjectTraceStop(CommandInterpreter & interpreter)2064be691f3bSpatrick CommandObjectTraceStop(CommandInterpreter &interpreter)
2065be691f3bSpatrick : CommandObjectMultipleThreads(
2066be691f3bSpatrick interpreter, "thread trace stop",
2067be691f3bSpatrick "Stop tracing threads, including the ones traced with the "
2068be691f3bSpatrick "\"process trace start\" command."
2069be691f3bSpatrick "Defaults to the current thread. Thread indices can be "
2070be691f3bSpatrick "specified as arguments.\n Use the thread-index \"all\" to stop "
2071be691f3bSpatrick "tracing "
2072be691f3bSpatrick "for all existing threads.",
2073be691f3bSpatrick "thread trace stop [<thread-index> <thread-index> ...]",
2074be691f3bSpatrick eCommandRequiresProcess | eCommandTryTargetAPILock |
2075be691f3bSpatrick eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
2076be691f3bSpatrick eCommandProcessMustBeTraced) {}
2077be691f3bSpatrick
2078be691f3bSpatrick ~CommandObjectTraceStop() override = default;
2079be691f3bSpatrick
DoExecuteOnThreads(Args & command,CommandReturnObject & result,llvm::ArrayRef<lldb::tid_t> tids)2080be691f3bSpatrick bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
2081be691f3bSpatrick llvm::ArrayRef<lldb::tid_t> tids) override {
2082be691f3bSpatrick ProcessSP process_sp = m_exe_ctx.GetProcessSP();
2083be691f3bSpatrick
2084be691f3bSpatrick TraceSP trace_sp = process_sp->GetTarget().GetTrace();
2085be691f3bSpatrick
2086be691f3bSpatrick if (llvm::Error err = trace_sp->Stop(tids))
2087be691f3bSpatrick result.AppendError(toString(std::move(err)));
2088be691f3bSpatrick else
2089be691f3bSpatrick result.SetStatus(eReturnStatusSuccessFinishResult);
2090be691f3bSpatrick
2091be691f3bSpatrick return result.Succeeded();
2092be691f3bSpatrick }
2093be691f3bSpatrick };
2094be691f3bSpatrick
GetSingleThreadFromArgs(ExecutionContext & exe_ctx,Args & args,CommandReturnObject & result)2095*f6aab3d8Srobert static ThreadSP GetSingleThreadFromArgs(ExecutionContext &exe_ctx, Args &args,
2096*f6aab3d8Srobert CommandReturnObject &result) {
2097*f6aab3d8Srobert if (args.GetArgumentCount() == 0)
2098*f6aab3d8Srobert return exe_ctx.GetThreadSP();
2099*f6aab3d8Srobert
2100*f6aab3d8Srobert const char *arg = args.GetArgumentAtIndex(0);
2101*f6aab3d8Srobert uint32_t thread_idx;
2102*f6aab3d8Srobert
2103*f6aab3d8Srobert if (!llvm::to_integer(arg, thread_idx)) {
2104*f6aab3d8Srobert result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", arg);
2105*f6aab3d8Srobert return nullptr;
2106*f6aab3d8Srobert }
2107*f6aab3d8Srobert ThreadSP thread_sp =
2108*f6aab3d8Srobert exe_ctx.GetProcessRef().GetThreadList().FindThreadByIndexID(thread_idx);
2109*f6aab3d8Srobert if (!thread_sp)
2110*f6aab3d8Srobert result.AppendErrorWithFormat("no thread with index: \"%s\"\n", arg);
2111*f6aab3d8Srobert return thread_sp;
2112*f6aab3d8Srobert }
2113*f6aab3d8Srobert
2114*f6aab3d8Srobert // CommandObjectTraceDumpFunctionCalls
2115*f6aab3d8Srobert #define LLDB_OPTIONS_thread_trace_dump_function_calls
2116*f6aab3d8Srobert #include "CommandOptions.inc"
2117*f6aab3d8Srobert
2118*f6aab3d8Srobert class CommandObjectTraceDumpFunctionCalls : public CommandObjectParsed {
2119*f6aab3d8Srobert public:
2120*f6aab3d8Srobert class CommandOptions : public Options {
2121*f6aab3d8Srobert public:
CommandOptions()2122*f6aab3d8Srobert CommandOptions() { OptionParsingStarting(nullptr); }
2123*f6aab3d8Srobert
2124*f6aab3d8Srobert ~CommandOptions() override = default;
2125*f6aab3d8Srobert
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2126*f6aab3d8Srobert Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2127*f6aab3d8Srobert ExecutionContext *execution_context) override {
2128*f6aab3d8Srobert Status error;
2129*f6aab3d8Srobert const int short_option = m_getopt_table[option_idx].val;
2130*f6aab3d8Srobert
2131*f6aab3d8Srobert switch (short_option) {
2132*f6aab3d8Srobert case 'j': {
2133*f6aab3d8Srobert m_dumper_options.json = true;
2134*f6aab3d8Srobert break;
2135*f6aab3d8Srobert }
2136*f6aab3d8Srobert case 'J': {
2137*f6aab3d8Srobert m_dumper_options.json = true;
2138*f6aab3d8Srobert m_dumper_options.pretty_print_json = true;
2139*f6aab3d8Srobert break;
2140*f6aab3d8Srobert }
2141*f6aab3d8Srobert case 'F': {
2142*f6aab3d8Srobert m_output_file.emplace(option_arg);
2143*f6aab3d8Srobert break;
2144*f6aab3d8Srobert }
2145*f6aab3d8Srobert default:
2146*f6aab3d8Srobert llvm_unreachable("Unimplemented option");
2147*f6aab3d8Srobert }
2148*f6aab3d8Srobert return error;
2149*f6aab3d8Srobert }
2150*f6aab3d8Srobert
OptionParsingStarting(ExecutionContext * execution_context)2151*f6aab3d8Srobert void OptionParsingStarting(ExecutionContext *execution_context) override {
2152*f6aab3d8Srobert m_dumper_options = {};
2153*f6aab3d8Srobert m_output_file = std::nullopt;
2154*f6aab3d8Srobert }
2155*f6aab3d8Srobert
GetDefinitions()2156*f6aab3d8Srobert llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2157*f6aab3d8Srobert return llvm::ArrayRef(g_thread_trace_dump_function_calls_options);
2158*f6aab3d8Srobert }
2159*f6aab3d8Srobert
2160*f6aab3d8Srobert static const size_t kDefaultCount = 20;
2161*f6aab3d8Srobert
2162*f6aab3d8Srobert // Instance variables to hold the values for command options.
2163*f6aab3d8Srobert TraceDumperOptions m_dumper_options;
2164*f6aab3d8Srobert std::optional<FileSpec> m_output_file;
2165*f6aab3d8Srobert };
2166*f6aab3d8Srobert
CommandObjectTraceDumpFunctionCalls(CommandInterpreter & interpreter)2167*f6aab3d8Srobert CommandObjectTraceDumpFunctionCalls(CommandInterpreter &interpreter)
2168*f6aab3d8Srobert : CommandObjectParsed(
2169*f6aab3d8Srobert interpreter, "thread trace dump function-calls",
2170*f6aab3d8Srobert "Dump the traced function-calls for one thread. If no "
2171*f6aab3d8Srobert "thread is specified, the current thread is used.",
2172*f6aab3d8Srobert nullptr,
2173*f6aab3d8Srobert eCommandRequiresProcess | eCommandRequiresThread |
2174*f6aab3d8Srobert eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
2175*f6aab3d8Srobert eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {
2176*f6aab3d8Srobert CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional};
2177*f6aab3d8Srobert m_arguments.push_back({thread_arg});
2178*f6aab3d8Srobert }
2179*f6aab3d8Srobert
2180*f6aab3d8Srobert ~CommandObjectTraceDumpFunctionCalls() override = default;
2181*f6aab3d8Srobert
GetOptions()2182*f6aab3d8Srobert Options *GetOptions() override { return &m_options; }
2183*f6aab3d8Srobert
2184*f6aab3d8Srobert protected:
DoExecute(Args & args,CommandReturnObject & result)2185*f6aab3d8Srobert bool DoExecute(Args &args, CommandReturnObject &result) override {
2186*f6aab3d8Srobert ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
2187*f6aab3d8Srobert if (!thread_sp) {
2188*f6aab3d8Srobert result.AppendError("invalid thread\n");
2189*f6aab3d8Srobert return false;
2190*f6aab3d8Srobert }
2191*f6aab3d8Srobert
2192*f6aab3d8Srobert llvm::Expected<TraceCursorSP> cursor_or_error =
2193*f6aab3d8Srobert m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp);
2194*f6aab3d8Srobert
2195*f6aab3d8Srobert if (!cursor_or_error) {
2196*f6aab3d8Srobert result.AppendError(llvm::toString(cursor_or_error.takeError()));
2197*f6aab3d8Srobert return false;
2198*f6aab3d8Srobert }
2199*f6aab3d8Srobert TraceCursorSP &cursor_sp = *cursor_or_error;
2200*f6aab3d8Srobert
2201*f6aab3d8Srobert std::optional<StreamFile> out_file;
2202*f6aab3d8Srobert if (m_options.m_output_file) {
2203*f6aab3d8Srobert out_file.emplace(m_options.m_output_file->GetPath().c_str(),
2204*f6aab3d8Srobert File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
2205*f6aab3d8Srobert File::eOpenOptionTruncate);
2206*f6aab3d8Srobert }
2207*f6aab3d8Srobert
2208*f6aab3d8Srobert m_options.m_dumper_options.forwards = true;
2209*f6aab3d8Srobert
2210*f6aab3d8Srobert TraceDumper dumper(std::move(cursor_sp),
2211*f6aab3d8Srobert out_file ? *out_file : result.GetOutputStream(),
2212*f6aab3d8Srobert m_options.m_dumper_options);
2213*f6aab3d8Srobert
2214*f6aab3d8Srobert dumper.DumpFunctionCalls();
2215*f6aab3d8Srobert return true;
2216*f6aab3d8Srobert }
2217*f6aab3d8Srobert
2218*f6aab3d8Srobert CommandOptions m_options;
2219*f6aab3d8Srobert };
2220*f6aab3d8Srobert
2221be691f3bSpatrick // CommandObjectTraceDumpInstructions
2222be691f3bSpatrick #define LLDB_OPTIONS_thread_trace_dump_instructions
2223be691f3bSpatrick #include "CommandOptions.inc"
2224be691f3bSpatrick
2225*f6aab3d8Srobert class CommandObjectTraceDumpInstructions : public CommandObjectParsed {
2226be691f3bSpatrick public:
2227be691f3bSpatrick class CommandOptions : public Options {
2228be691f3bSpatrick public:
CommandOptions()2229*f6aab3d8Srobert CommandOptions() { OptionParsingStarting(nullptr); }
2230be691f3bSpatrick
2231be691f3bSpatrick ~CommandOptions() override = default;
2232be691f3bSpatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2233be691f3bSpatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2234be691f3bSpatrick ExecutionContext *execution_context) override {
2235be691f3bSpatrick Status error;
2236be691f3bSpatrick const int short_option = m_getopt_table[option_idx].val;
2237be691f3bSpatrick
2238be691f3bSpatrick switch (short_option) {
2239be691f3bSpatrick case 'c': {
2240be691f3bSpatrick int32_t count;
2241be691f3bSpatrick if (option_arg.empty() || option_arg.getAsInteger(0, count) ||
2242be691f3bSpatrick count < 0)
2243be691f3bSpatrick error.SetErrorStringWithFormat(
2244be691f3bSpatrick "invalid integer value for option '%s'",
2245be691f3bSpatrick option_arg.str().c_str());
2246be691f3bSpatrick else
2247be691f3bSpatrick m_count = count;
2248be691f3bSpatrick break;
2249be691f3bSpatrick }
2250*f6aab3d8Srobert case 'a': {
2251*f6aab3d8Srobert m_count = std::numeric_limits<decltype(m_count)>::max();
2252*f6aab3d8Srobert break;
2253*f6aab3d8Srobert }
2254be691f3bSpatrick case 's': {
2255be691f3bSpatrick int32_t skip;
2256be691f3bSpatrick if (option_arg.empty() || option_arg.getAsInteger(0, skip) || skip < 0)
2257be691f3bSpatrick error.SetErrorStringWithFormat(
2258be691f3bSpatrick "invalid integer value for option '%s'",
2259be691f3bSpatrick option_arg.str().c_str());
2260be691f3bSpatrick else
2261*f6aab3d8Srobert m_dumper_options.skip = skip;
2262*f6aab3d8Srobert break;
2263*f6aab3d8Srobert }
2264*f6aab3d8Srobert case 'i': {
2265*f6aab3d8Srobert uint64_t id;
2266*f6aab3d8Srobert if (option_arg.empty() || option_arg.getAsInteger(0, id))
2267*f6aab3d8Srobert error.SetErrorStringWithFormat(
2268*f6aab3d8Srobert "invalid integer value for option '%s'",
2269*f6aab3d8Srobert option_arg.str().c_str());
2270*f6aab3d8Srobert else
2271*f6aab3d8Srobert m_dumper_options.id = id;
2272*f6aab3d8Srobert break;
2273*f6aab3d8Srobert }
2274*f6aab3d8Srobert case 'F': {
2275*f6aab3d8Srobert m_output_file.emplace(option_arg);
2276be691f3bSpatrick break;
2277be691f3bSpatrick }
2278be691f3bSpatrick case 'r': {
2279*f6aab3d8Srobert m_dumper_options.raw = true;
2280be691f3bSpatrick break;
2281be691f3bSpatrick }
2282be691f3bSpatrick case 'f': {
2283*f6aab3d8Srobert m_dumper_options.forwards = true;
2284*f6aab3d8Srobert break;
2285*f6aab3d8Srobert }
2286*f6aab3d8Srobert case 'k': {
2287*f6aab3d8Srobert m_dumper_options.show_control_flow_kind = true;
2288be691f3bSpatrick break;
2289be691f3bSpatrick }
2290be691f3bSpatrick case 't': {
2291*f6aab3d8Srobert m_dumper_options.show_timestamps = true;
2292*f6aab3d8Srobert break;
2293*f6aab3d8Srobert }
2294*f6aab3d8Srobert case 'e': {
2295*f6aab3d8Srobert m_dumper_options.show_events = true;
2296*f6aab3d8Srobert break;
2297*f6aab3d8Srobert }
2298*f6aab3d8Srobert case 'j': {
2299*f6aab3d8Srobert m_dumper_options.json = true;
2300*f6aab3d8Srobert break;
2301*f6aab3d8Srobert }
2302*f6aab3d8Srobert case 'J': {
2303*f6aab3d8Srobert m_dumper_options.pretty_print_json = true;
2304*f6aab3d8Srobert m_dumper_options.json = true;
2305*f6aab3d8Srobert break;
2306*f6aab3d8Srobert }
2307*f6aab3d8Srobert case 'E': {
2308*f6aab3d8Srobert m_dumper_options.only_events = true;
2309*f6aab3d8Srobert m_dumper_options.show_events = true;
2310*f6aab3d8Srobert break;
2311*f6aab3d8Srobert }
2312*f6aab3d8Srobert case 'C': {
2313*f6aab3d8Srobert m_continue = true;
2314be691f3bSpatrick break;
2315be691f3bSpatrick }
2316be691f3bSpatrick default:
2317be691f3bSpatrick llvm_unreachable("Unimplemented option");
2318be691f3bSpatrick }
2319be691f3bSpatrick return error;
2320be691f3bSpatrick }
2321be691f3bSpatrick
OptionParsingStarting(ExecutionContext * execution_context)2322be691f3bSpatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
2323be691f3bSpatrick m_count = kDefaultCount;
2324*f6aab3d8Srobert m_continue = false;
2325*f6aab3d8Srobert m_output_file = std::nullopt;
2326*f6aab3d8Srobert m_dumper_options = {};
2327be691f3bSpatrick }
2328be691f3bSpatrick
GetDefinitions()2329be691f3bSpatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2330*f6aab3d8Srobert return llvm::ArrayRef(g_thread_trace_dump_instructions_options);
2331be691f3bSpatrick }
2332be691f3bSpatrick
2333be691f3bSpatrick static const size_t kDefaultCount = 20;
2334be691f3bSpatrick
2335be691f3bSpatrick // Instance variables to hold the values for command options.
2336be691f3bSpatrick size_t m_count;
2337*f6aab3d8Srobert size_t m_continue;
2338*f6aab3d8Srobert std::optional<FileSpec> m_output_file;
2339*f6aab3d8Srobert TraceDumperOptions m_dumper_options;
2340be691f3bSpatrick };
2341be691f3bSpatrick
CommandObjectTraceDumpInstructions(CommandInterpreter & interpreter)2342be691f3bSpatrick CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter)
2343*f6aab3d8Srobert : CommandObjectParsed(
2344be691f3bSpatrick interpreter, "thread trace dump instructions",
2345*f6aab3d8Srobert "Dump the traced instructions for one thread. If no "
2346*f6aab3d8Srobert "thread is specified, show the current thread.",
2347be691f3bSpatrick nullptr,
2348*f6aab3d8Srobert eCommandRequiresProcess | eCommandRequiresThread |
2349*f6aab3d8Srobert eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
2350*f6aab3d8Srobert eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {
2351*f6aab3d8Srobert CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional};
2352*f6aab3d8Srobert m_arguments.push_back({thread_arg});
2353*f6aab3d8Srobert }
2354be691f3bSpatrick
2355be691f3bSpatrick ~CommandObjectTraceDumpInstructions() override = default;
2356be691f3bSpatrick
GetOptions()2357be691f3bSpatrick Options *GetOptions() override { return &m_options; }
2358be691f3bSpatrick
GetRepeatCommand(Args & current_command_args,uint32_t index)2359*f6aab3d8Srobert std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
2360be691f3bSpatrick uint32_t index) override {
2361*f6aab3d8Srobert std::string cmd;
2362*f6aab3d8Srobert current_command_args.GetCommandString(cmd);
2363*f6aab3d8Srobert if (cmd.find(" --continue") == std::string::npos)
2364*f6aab3d8Srobert cmd += " --continue";
2365*f6aab3d8Srobert return cmd;
2366be691f3bSpatrick }
2367be691f3bSpatrick
2368be691f3bSpatrick protected:
DoExecute(Args & args,CommandReturnObject & result)2369be691f3bSpatrick bool DoExecute(Args &args, CommandReturnObject &result) override {
2370*f6aab3d8Srobert ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
2371*f6aab3d8Srobert if (!thread_sp) {
2372*f6aab3d8Srobert result.AppendError("invalid thread\n");
2373*f6aab3d8Srobert return false;
2374be691f3bSpatrick }
2375be691f3bSpatrick
2376*f6aab3d8Srobert if (m_options.m_continue && m_last_id) {
2377*f6aab3d8Srobert // We set up the options to continue one instruction past where
2378*f6aab3d8Srobert // the previous iteration stopped.
2379*f6aab3d8Srobert m_options.m_dumper_options.skip = 1;
2380*f6aab3d8Srobert m_options.m_dumper_options.id = m_last_id;
2381be691f3bSpatrick }
2382be691f3bSpatrick
2383*f6aab3d8Srobert llvm::Expected<TraceCursorSP> cursor_or_error =
2384*f6aab3d8Srobert m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp);
2385be691f3bSpatrick
2386*f6aab3d8Srobert if (!cursor_or_error) {
2387*f6aab3d8Srobert result.AppendError(llvm::toString(cursor_or_error.takeError()));
2388*f6aab3d8Srobert return false;
2389*f6aab3d8Srobert }
2390*f6aab3d8Srobert TraceCursorSP &cursor_sp = *cursor_or_error;
2391be691f3bSpatrick
2392*f6aab3d8Srobert if (m_options.m_dumper_options.id &&
2393*f6aab3d8Srobert !cursor_sp->HasId(*m_options.m_dumper_options.id)) {
2394*f6aab3d8Srobert result.AppendError("invalid instruction id\n");
2395*f6aab3d8Srobert return false;
2396be691f3bSpatrick }
2397be691f3bSpatrick
2398*f6aab3d8Srobert std::optional<StreamFile> out_file;
2399*f6aab3d8Srobert if (m_options.m_output_file) {
2400*f6aab3d8Srobert out_file.emplace(m_options.m_output_file->GetPath().c_str(),
2401*f6aab3d8Srobert File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
2402*f6aab3d8Srobert File::eOpenOptionTruncate);
2403*f6aab3d8Srobert }
2404*f6aab3d8Srobert
2405*f6aab3d8Srobert if (m_options.m_continue && !m_last_id) {
2406*f6aab3d8Srobert // We need to stop processing data when we already ran out of instructions
2407*f6aab3d8Srobert // in a previous command. We can fake this by setting the cursor past the
2408*f6aab3d8Srobert // end of the trace.
2409*f6aab3d8Srobert cursor_sp->Seek(1, lldb::eTraceCursorSeekTypeEnd);
2410*f6aab3d8Srobert }
2411*f6aab3d8Srobert
2412*f6aab3d8Srobert TraceDumper dumper(std::move(cursor_sp),
2413*f6aab3d8Srobert out_file ? *out_file : result.GetOutputStream(),
2414*f6aab3d8Srobert m_options.m_dumper_options);
2415*f6aab3d8Srobert
2416*f6aab3d8Srobert m_last_id = dumper.DumpInstructions(m_options.m_count);
2417be691f3bSpatrick return true;
2418be691f3bSpatrick }
2419be691f3bSpatrick
2420be691f3bSpatrick CommandOptions m_options;
2421*f6aab3d8Srobert // Last traversed id used to continue a repeat command. None means
2422*f6aab3d8Srobert // that all the trace has been consumed.
2423*f6aab3d8Srobert std::optional<lldb::user_id_t> m_last_id;
2424be691f3bSpatrick };
2425be691f3bSpatrick
2426be691f3bSpatrick // CommandObjectTraceDumpInfo
2427be691f3bSpatrick #define LLDB_OPTIONS_thread_trace_dump_info
2428be691f3bSpatrick #include "CommandOptions.inc"
2429be691f3bSpatrick
2430be691f3bSpatrick class CommandObjectTraceDumpInfo : public CommandObjectIterateOverThreads {
2431be691f3bSpatrick public:
2432be691f3bSpatrick class CommandOptions : public Options {
2433be691f3bSpatrick public:
CommandOptions()2434*f6aab3d8Srobert CommandOptions() { OptionParsingStarting(nullptr); }
2435be691f3bSpatrick
2436be691f3bSpatrick ~CommandOptions() override = default;
2437be691f3bSpatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2438be691f3bSpatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2439be691f3bSpatrick ExecutionContext *execution_context) override {
2440be691f3bSpatrick Status error;
2441be691f3bSpatrick const int short_option = m_getopt_table[option_idx].val;
2442be691f3bSpatrick
2443be691f3bSpatrick switch (short_option) {
2444be691f3bSpatrick case 'v': {
2445be691f3bSpatrick m_verbose = true;
2446be691f3bSpatrick break;
2447be691f3bSpatrick }
2448*f6aab3d8Srobert case 'j': {
2449*f6aab3d8Srobert m_json = true;
2450*f6aab3d8Srobert break;
2451*f6aab3d8Srobert }
2452be691f3bSpatrick default:
2453be691f3bSpatrick llvm_unreachable("Unimplemented option");
2454be691f3bSpatrick }
2455be691f3bSpatrick return error;
2456be691f3bSpatrick }
2457be691f3bSpatrick
OptionParsingStarting(ExecutionContext * execution_context)2458be691f3bSpatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
2459be691f3bSpatrick m_verbose = false;
2460*f6aab3d8Srobert m_json = false;
2461be691f3bSpatrick }
2462be691f3bSpatrick
GetDefinitions()2463be691f3bSpatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2464*f6aab3d8Srobert return llvm::ArrayRef(g_thread_trace_dump_info_options);
2465be691f3bSpatrick }
2466be691f3bSpatrick
2467be691f3bSpatrick // Instance variables to hold the values for command options.
2468be691f3bSpatrick bool m_verbose;
2469*f6aab3d8Srobert bool m_json;
2470be691f3bSpatrick };
2471be691f3bSpatrick
CommandObjectTraceDumpInfo(CommandInterpreter & interpreter)2472be691f3bSpatrick CommandObjectTraceDumpInfo(CommandInterpreter &interpreter)
2473be691f3bSpatrick : CommandObjectIterateOverThreads(
2474be691f3bSpatrick interpreter, "thread trace dump info",
2475be691f3bSpatrick "Dump the traced information for one or more threads. If no "
2476be691f3bSpatrick "threads are specified, show the current thread. Use the "
2477be691f3bSpatrick "thread-index \"all\" to see all threads.",
2478be691f3bSpatrick nullptr,
2479be691f3bSpatrick eCommandRequiresProcess | eCommandTryTargetAPILock |
2480be691f3bSpatrick eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
2481*f6aab3d8Srobert eCommandProcessMustBeTraced) {}
2482be691f3bSpatrick
2483be691f3bSpatrick ~CommandObjectTraceDumpInfo() override = default;
2484be691f3bSpatrick
GetOptions()2485be691f3bSpatrick Options *GetOptions() override { return &m_options; }
2486be691f3bSpatrick
2487be691f3bSpatrick protected:
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)2488be691f3bSpatrick bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
2489be691f3bSpatrick const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace();
2490be691f3bSpatrick ThreadSP thread_sp =
2491be691f3bSpatrick m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
2492be691f3bSpatrick trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(),
2493*f6aab3d8Srobert m_options.m_verbose, m_options.m_json);
2494be691f3bSpatrick return true;
2495be691f3bSpatrick }
2496be691f3bSpatrick
2497be691f3bSpatrick CommandOptions m_options;
2498be691f3bSpatrick };
2499be691f3bSpatrick
2500be691f3bSpatrick // CommandObjectMultiwordTraceDump
2501be691f3bSpatrick class CommandObjectMultiwordTraceDump : public CommandObjectMultiword {
2502be691f3bSpatrick public:
CommandObjectMultiwordTraceDump(CommandInterpreter & interpreter)2503be691f3bSpatrick CommandObjectMultiwordTraceDump(CommandInterpreter &interpreter)
2504be691f3bSpatrick : CommandObjectMultiword(
2505be691f3bSpatrick interpreter, "dump",
2506be691f3bSpatrick "Commands for displaying trace information of the threads "
2507be691f3bSpatrick "in the current process.",
2508be691f3bSpatrick "thread trace dump <subcommand> [<subcommand objects>]") {
2509be691f3bSpatrick LoadSubCommand(
2510be691f3bSpatrick "instructions",
2511be691f3bSpatrick CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter)));
2512be691f3bSpatrick LoadSubCommand(
2513*f6aab3d8Srobert "function-calls",
2514*f6aab3d8Srobert CommandObjectSP(new CommandObjectTraceDumpFunctionCalls(interpreter)));
2515*f6aab3d8Srobert LoadSubCommand(
2516be691f3bSpatrick "info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter)));
2517be691f3bSpatrick }
2518be691f3bSpatrick ~CommandObjectMultiwordTraceDump() override = default;
2519be691f3bSpatrick };
2520be691f3bSpatrick
2521be691f3bSpatrick // CommandObjectMultiwordTrace
2522be691f3bSpatrick class CommandObjectMultiwordTrace : public CommandObjectMultiword {
2523be691f3bSpatrick public:
CommandObjectMultiwordTrace(CommandInterpreter & interpreter)2524be691f3bSpatrick CommandObjectMultiwordTrace(CommandInterpreter &interpreter)
2525be691f3bSpatrick : CommandObjectMultiword(
2526be691f3bSpatrick interpreter, "trace",
2527be691f3bSpatrick "Commands for operating on traces of the threads in the current "
2528be691f3bSpatrick "process.",
2529be691f3bSpatrick "thread trace <subcommand> [<subcommand objects>]") {
2530be691f3bSpatrick LoadSubCommand("dump", CommandObjectSP(new CommandObjectMultiwordTraceDump(
2531be691f3bSpatrick interpreter)));
2532be691f3bSpatrick LoadSubCommand("start",
2533be691f3bSpatrick CommandObjectSP(new CommandObjectTraceStart(interpreter)));
2534be691f3bSpatrick LoadSubCommand("stop",
2535be691f3bSpatrick CommandObjectSP(new CommandObjectTraceStop(interpreter)));
2536be691f3bSpatrick LoadSubCommand("export",
2537be691f3bSpatrick CommandObjectSP(new CommandObjectTraceExport(interpreter)));
2538be691f3bSpatrick }
2539be691f3bSpatrick
2540be691f3bSpatrick ~CommandObjectMultiwordTrace() override = default;
2541be691f3bSpatrick };
2542be691f3bSpatrick
2543061da546Spatrick // CommandObjectMultiwordThread
2544061da546Spatrick
CommandObjectMultiwordThread(CommandInterpreter & interpreter)2545061da546Spatrick CommandObjectMultiwordThread::CommandObjectMultiwordThread(
2546061da546Spatrick CommandInterpreter &interpreter)
2547061da546Spatrick : CommandObjectMultiword(interpreter, "thread",
2548061da546Spatrick "Commands for operating on "
2549061da546Spatrick "one or more threads in "
2550061da546Spatrick "the current process.",
2551061da546Spatrick "thread <subcommand> [<subcommand-options>]") {
2552061da546Spatrick LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace(
2553061da546Spatrick interpreter)));
2554061da546Spatrick LoadSubCommand("continue",
2555061da546Spatrick CommandObjectSP(new CommandObjectThreadContinue(interpreter)));
2556061da546Spatrick LoadSubCommand("list",
2557061da546Spatrick CommandObjectSP(new CommandObjectThreadList(interpreter)));
2558061da546Spatrick LoadSubCommand("return",
2559061da546Spatrick CommandObjectSP(new CommandObjectThreadReturn(interpreter)));
2560061da546Spatrick LoadSubCommand("jump",
2561061da546Spatrick CommandObjectSP(new CommandObjectThreadJump(interpreter)));
2562061da546Spatrick LoadSubCommand("select",
2563061da546Spatrick CommandObjectSP(new CommandObjectThreadSelect(interpreter)));
2564061da546Spatrick LoadSubCommand("until",
2565061da546Spatrick CommandObjectSP(new CommandObjectThreadUntil(interpreter)));
2566061da546Spatrick LoadSubCommand("info",
2567061da546Spatrick CommandObjectSP(new CommandObjectThreadInfo(interpreter)));
2568061da546Spatrick LoadSubCommand("exception", CommandObjectSP(new CommandObjectThreadException(
2569061da546Spatrick interpreter)));
2570*f6aab3d8Srobert LoadSubCommand("siginfo",
2571*f6aab3d8Srobert CommandObjectSP(new CommandObjectThreadSiginfo(interpreter)));
2572061da546Spatrick LoadSubCommand("step-in",
2573061da546Spatrick CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
2574061da546Spatrick interpreter, "thread step-in",
2575061da546Spatrick "Source level single step, stepping into calls. Defaults "
2576061da546Spatrick "to current thread unless specified.",
2577061da546Spatrick nullptr, eStepTypeInto, eStepScopeSource)));
2578061da546Spatrick
2579061da546Spatrick LoadSubCommand("step-out",
2580061da546Spatrick CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
2581061da546Spatrick interpreter, "thread step-out",
2582061da546Spatrick "Finish executing the current stack frame and stop after "
2583061da546Spatrick "returning. Defaults to current thread unless specified.",
2584061da546Spatrick nullptr, eStepTypeOut, eStepScopeSource)));
2585061da546Spatrick
2586061da546Spatrick LoadSubCommand("step-over",
2587061da546Spatrick CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
2588061da546Spatrick interpreter, "thread step-over",
2589061da546Spatrick "Source level single step, stepping over calls. Defaults "
2590061da546Spatrick "to current thread unless specified.",
2591061da546Spatrick nullptr, eStepTypeOver, eStepScopeSource)));
2592061da546Spatrick
2593061da546Spatrick LoadSubCommand("step-inst",
2594061da546Spatrick CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
2595061da546Spatrick interpreter, "thread step-inst",
2596061da546Spatrick "Instruction level single step, stepping into calls. "
2597061da546Spatrick "Defaults to current thread unless specified.",
2598061da546Spatrick nullptr, eStepTypeTrace, eStepScopeInstruction)));
2599061da546Spatrick
2600061da546Spatrick LoadSubCommand("step-inst-over",
2601061da546Spatrick CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
2602061da546Spatrick interpreter, "thread step-inst-over",
2603061da546Spatrick "Instruction level single step, stepping over calls. "
2604061da546Spatrick "Defaults to current thread unless specified.",
2605061da546Spatrick nullptr, eStepTypeTraceOver, eStepScopeInstruction)));
2606061da546Spatrick
2607061da546Spatrick LoadSubCommand(
2608061da546Spatrick "step-scripted",
2609061da546Spatrick CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
2610061da546Spatrick interpreter, "thread step-scripted",
2611061da546Spatrick "Step as instructed by the script class passed in the -C option. "
2612061da546Spatrick "You can also specify a dictionary of key (-k) and value (-v) pairs "
2613061da546Spatrick "that will be used to populate an SBStructuredData Dictionary, which "
2614061da546Spatrick "will be passed to the constructor of the class implementing the "
2615061da546Spatrick "scripted step. See the Python Reference for more details.",
2616061da546Spatrick nullptr, eStepTypeScripted, eStepScopeSource)));
2617061da546Spatrick
2618061da546Spatrick LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan(
2619061da546Spatrick interpreter)));
2620be691f3bSpatrick LoadSubCommand("trace",
2621be691f3bSpatrick CommandObjectSP(new CommandObjectMultiwordTrace(interpreter)));
2622061da546Spatrick }
2623061da546Spatrick
2624061da546Spatrick CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default;
2625