diff options
author | Michael Christensen <chmdko@gmail.com> | 2023-12-14 15:19:38 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-14 15:19:38 -0800 |
commit | 405194257506685ca11848fbaff79c4333c18c3b (patch) | |
tree | c4ea80f4cc75c870aba43719194404bcae658d9f /lldb/source/Commands/CommandObjectThread.cpp | |
parent | a590387a1295e8845506359cd95b7c3b3cc98996 (diff) | |
download | llvm-405194257506685ca11848fbaff79c4333c18c3b.zip llvm-405194257506685ca11848fbaff79c4333c18c3b.tar.gz llvm-405194257506685ca11848fbaff79c4333c18c3b.tar.bz2 |
Add option to pass thread ID to thread select command (#73596)
We'd like a way to select the current thread by its thread ID (rather
than its internal LLDB thread index).
This PR adds a `-t` option (`--thread_id` long option) that tells the
`thread select` command to interpret the `<thread-index>` argument as a
thread ID.
Here's an example of it working:
```
michristensen@devbig356 llvm/llvm-project (thread-select-tid) ยป ../Debug/bin/lldb ~/scratch/cpp/threading/a.out
(lldb) target create "/home/michristensen/scratch/cpp/threading/a.out"
Current executable set to '/home/michristensen/scratch/cpp/threading/a.out' (x86_64).
(lldb) b 18
Breakpoint 1: where = a.out`main + 80 at main.cpp:18:12, address = 0x0000000000000850
(lldb) run
Process 215715 launched: '/home/michristensen/scratch/cpp/threading/a.out' (x86_64)
This is a thread, i=1
This is a thread, i=2
This is a thread, i=3
This is a thread, i=4
This is a thread, i=5
Process 215715 stopped
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
frame #0: 0x0000555555400850 a.out`main at main.cpp:18:12
15 for (int i = 0; i < 5; i++) {
16 pthread_create(&thread_ids[i], NULL, foo, NULL);
17 }
-> 18 for (int i = 0; i < 5; i++) {
19 pthread_join(thread_ids[i], NULL);
20 }
21 return 0;
(lldb) thread select 2
* thread #2, name = 'a.out'
frame #0: 0x00007ffff68f9918 libc.so.6`__nanosleep + 72
libc.so.6`__nanosleep:
-> 0x7ffff68f9918 <+72>: cmpq $-0x1000, %rax ; imm = 0xF000
0x7ffff68f991e <+78>: ja 0x7ffff68f9952 ; <+130>
0x7ffff68f9920 <+80>: movl %edx, %edi
0x7ffff68f9922 <+82>: movl %eax, 0xc(%rsp)
(lldb) thread info
thread #2: tid = 216047, 0x00007ffff68f9918 libc.so.6`__nanosleep + 72, name = 'a.out'
(lldb) thread list
Process 215715 stopped
thread #1: tid = 215715, 0x0000555555400850 a.out`main at main.cpp:18:12, name = 'a.out', stop reason = breakpoint 1.1
* thread #2: tid = 216047, 0x00007ffff68f9918 libc.so.6`__nanosleep + 72, name = 'a.out'
thread #3: tid = 216048, 0x00007ffff68f9918 libc.so.6`__nanosleep + 72, name = 'a.out'
thread #4: tid = 216049, 0x00007ffff68f9918 libc.so.6`__nanosleep + 72, name = 'a.out'
thread #5: tid = 216050, 0x00007ffff68f9918 libc.so.6`__nanosleep + 72, name = 'a.out'
thread #6: tid = 216051, 0x00007ffff68f9918 libc.so.6`__nanosleep + 72, name = 'a.out'
(lldb) thread select 215715
error: invalid thread #215715.
(lldb) thread select -t 215715
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
frame #0: 0x0000555555400850 a.out`main at main.cpp:18:12
15 for (int i = 0; i < 5; i++) {
16 pthread_create(&thread_ids[i], NULL, foo, NULL);
17 }
-> 18 for (int i = 0; i < 5; i++) {
19 pthread_join(thread_ids[i], NULL);
20 }
21 return 0;
(lldb) thread select -t 216051
* thread #6, name = 'a.out'
frame #0: 0x00007ffff68f9918 libc.so.6`__nanosleep + 72
libc.so.6`__nanosleep:
-> 0x7ffff68f9918 <+72>: cmpq $-0x1000, %rax ; imm = 0xF000
0x7ffff68f991e <+78>: ja 0x7ffff68f9952 ; <+130>
0x7ffff68f9920 <+80>: movl %edx, %edi
0x7ffff68f9922 <+82>: movl %eax, 0xc(%rsp)
(lldb) thread select 3
* thread #3, name = 'a.out'
frame #0: 0x00007ffff68f9918 libc.so.6`__nanosleep + 72
libc.so.6`__nanosleep:
-> 0x7ffff68f9918 <+72>: cmpq $-0x1000, %rax ; imm = 0xF000
0x7ffff68f991e <+78>: ja 0x7ffff68f9952 ; <+130>
0x7ffff68f9920 <+80>: movl %edx, %edi
0x7ffff68f9922 <+82>: movl %eax, 0xc(%rsp)
(lldb) thread select -t 216048
* thread #3, name = 'a.out'
frame #0: 0x00007ffff68f9918 libc.so.6`__nanosleep + 72
libc.so.6`__nanosleep:
-> 0x7ffff68f9918 <+72>: cmpq $-0x1000, %rax ; imm = 0xF000
0x7ffff68f991e <+78>: ja 0x7ffff68f9952 ; <+130>
0x7ffff68f9920 <+80>: movl %edx, %edi
0x7ffff68f9922 <+82>: movl %eax, 0xc(%rsp)
(lldb) thread select --thread_id 216048
* thread #3, name = 'a.out'
frame #0: 0x00007ffff68f9918 libc.so.6`__nanosleep + 72
libc.so.6`__nanosleep:
-> 0x7ffff68f9918 <+72>: cmpq $-0x1000, %rax ; imm = 0xF000
0x7ffff68f991e <+78>: ja 0x7ffff68f9952 ; <+130>
0x7ffff68f9920 <+80>: movl %edx, %edi
0x7ffff68f9922 <+82>: movl %eax, 0xc(%rsp)
(lldb) help thread select
Change the currently selected thread.
Syntax: thread select <cmd-options> <thread-index>
Command Options Usage:
thread select [-t] <thread-index>
-t ( --thread_id )
Provide a thread ID instead of a thread index.
This command takes options and free-form arguments. If your arguments
resemble option specifiers (i.e., they start with a - or --), you must use
' -- ' between the end of the command options and the beginning of the
arguments.
(lldb) c
Process 215715 resuming
Process 215715 exited with status = 0 (0x00000000)
```
Diffstat (limited to 'lldb/source/Commands/CommandObjectThread.cpp')
-rw-r--r-- | lldb/source/Commands/CommandObjectThread.cpp | 96 |
1 files changed, 81 insertions, 15 deletions
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index a9f5a4f..dd9fab4 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1129,11 +1129,51 @@ protected: // CommandObjectThreadSelect +#define LLDB_OPTIONS_thread_select +#include "CommandOptions.inc" + class CommandObjectThreadSelect : public CommandObjectParsed { public: + class OptionGroupThreadSelect : public OptionGroup { + public: + OptionGroupThreadSelect() { OptionParsingStarting(nullptr); } + + ~OptionGroupThreadSelect() override = default; + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_thread_id = LLDB_INVALID_THREAD_ID; + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + const int short_option = g_thread_select_options[option_idx].short_option; + switch (short_option) { + case 't': { + if (option_arg.getAsInteger(0, m_thread_id)) { + m_thread_id = LLDB_INVALID_THREAD_ID; + return Status("Invalid thread ID: '%s'.", option_arg.str().c_str()); + } + break; + } + + default: + llvm_unreachable("Unimplemented option"); + } + + return {}; + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::ArrayRef(g_thread_select_options); + } + + lldb::tid_t m_thread_id; + }; + CommandObjectThreadSelect(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "thread select", - "Change the currently selected thread.", nullptr, + "Change the currently selected thread.", + "thread select <thread-index> (or -t <thread-id>)", eCommandRequiresProcess | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { @@ -1143,6 +1183,7 @@ public: // Define the first (and only) variant of this arg. thread_idx_arg.arg_type = eArgTypeThreadIndex; thread_idx_arg.arg_repetition = eArgRepeatPlain; + thread_idx_arg.arg_opt_set_association = LLDB_OPT_SET_1; // There is only one variant this argument could be; put it into the // argument entry. @@ -1150,6 +1191,9 @@ public: // Push the data for the first argument into the m_arguments vector. m_arguments.push_back(arg); + + m_option_group.Append(&m_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2); + m_option_group.Finalize(); } ~CommandObjectThreadSelect() override = default; @@ -1165,37 +1209,59 @@ public: nullptr); } + Options *GetOptions() override { return &m_option_group; } + protected: void DoExecute(Args &command, CommandReturnObject &result) override { Process *process = m_exe_ctx.GetProcessPtr(); if (process == nullptr) { result.AppendError("no process"); return; - } else if (command.GetArgumentCount() != 1) { + } else if (m_options.m_thread_id == LLDB_INVALID_THREAD_ID && + command.GetArgumentCount() != 1) { result.AppendErrorWithFormat( - "'%s' takes exactly one thread index argument:\nUsage: %s\n", + "'%s' takes exactly one thread index argument, or a thread ID " + "option:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); return; - } - - uint32_t index_id; - if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) { - result.AppendErrorWithFormat("Invalid thread index '%s'", - command.GetArgumentAtIndex(0)); + } else if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID && + command.GetArgumentCount() != 0) { + result.AppendErrorWithFormat("'%s' cannot take both a thread ID option " + "and a thread index argument:\nUsage: %s\n", + m_cmd_name.c_str(), m_cmd_syntax.c_str()); return; } - Thread *new_thread = - process->GetThreadList().FindThreadByIndexID(index_id).get(); - if (new_thread == nullptr) { - result.AppendErrorWithFormat("invalid thread #%s.\n", - command.GetArgumentAtIndex(0)); - return; + Thread *new_thread = nullptr; + if (command.GetArgumentCount() == 1) { + uint32_t index_id; + if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) { + result.AppendErrorWithFormat("Invalid thread index '%s'", + command.GetArgumentAtIndex(0)); + return; + } + new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get(); + if (new_thread == nullptr) { + result.AppendErrorWithFormat("Invalid thread index #%s.\n", + command.GetArgumentAtIndex(0)); + return; + } + } else { + new_thread = + process->GetThreadList().FindThreadByID(m_options.m_thread_id).get(); + if (new_thread == nullptr) { + result.AppendErrorWithFormat("Invalid thread ID %" PRIu64 ".\n", + m_options.m_thread_id); + return; + } } process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true); result.SetStatus(eReturnStatusSuccessFinishNoResult); } + + OptionGroupThreadSelect m_options; + OptionGroupOptions m_option_group; }; // CommandObjectThreadList |