[Lldb-commits] [lldb] Add option to pass thread ID to thread select command (PR #73596)
Michael Christensen via lldb-commits
lldb-commits at lists.llvm.org
Mon Nov 27 17:03:22 PST 2023
https://github.com/mdko created https://github.com/llvm/llvm-project/pull/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 at 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)
```
>From 97a6e23c85457a14c91c5800fa03bb872e6f1fa6 Mon Sep 17 00:00:00 2001
From: Michael Christensen <mchristensen at meta.com>
Date: Mon, 27 Nov 2023 12:49:24 -0800
Subject: [PATCH] Add option to pass thread ID to thread select command
---
lldb/source/Commands/CommandObjectThread.cpp | 59 +++++++++++++++++--
lldb/source/Commands/Options.td | 5 ++
.../thread/select/TestThreadSelect.py | 23 +++++++-
3 files changed, 78 insertions(+), 9 deletions(-)
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index a9f5a4f8a4fbd71c..9384df319cc221dd 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -1129,8 +1129,44 @@ class CommandObjectThreadUntil : public CommandObjectParsed {
// CommandObjectThreadSelect
+#define LLDB_OPTIONS_thread_select
+#include "CommandOptions.inc"
+
class CommandObjectThreadSelect : public CommandObjectParsed {
public:
+ class CommandOptions : public Options {
+ public:
+ CommandOptions() { OptionParsingStarting(nullptr); }
+
+ ~CommandOptions() override = default;
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_thread_id = false;
+ }
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ const int short_option = m_getopt_table[option_idx].val;
+ switch (short_option) {
+ case 't': {
+ m_thread_id = true;
+ break;
+ }
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return {};
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_thread_select_options);
+ }
+
+ bool m_thread_id;
+ };
+
CommandObjectThreadSelect(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "thread select",
"Change the currently selected thread.", nullptr,
@@ -1165,6 +1201,8 @@ class CommandObjectThreadSelect : public CommandObjectParsed {
nullptr);
}
+ Options *GetOptions() override { return &m_options; }
+
protected:
void DoExecute(Args &command, CommandReturnObject &result) override {
Process *process = m_exe_ctx.GetProcessPtr();
@@ -1173,22 +1211,29 @@ class CommandObjectThreadSelect : public CommandObjectParsed {
return;
} else if (command.GetArgumentCount() != 1) {
result.AppendErrorWithFormat(
- "'%s' takes exactly one thread index argument:\nUsage: %s\n",
- m_cmd_name.c_str(), m_cmd_syntax.c_str());
+ "'%s' takes exactly one thread %s argument:\nUsage: %s\n",
+ m_cmd_name.c_str(), m_options.m_thread_id ? "ID" : "index",
+ 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'",
+ result.AppendErrorWithFormat("Invalid thread %s '%s'",
+ m_options.m_thread_id ? "ID" : "index",
command.GetArgumentAtIndex(0));
return;
}
- Thread *new_thread =
- process->GetThreadList().FindThreadByIndexID(index_id).get();
+ Thread *new_thread = nullptr;
+ if (m_options.m_thread_id) {
+ new_thread = process->GetThreadList().FindThreadByID(index_id).get();
+ } else {
+ new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
+ }
if (new_thread == nullptr) {
- result.AppendErrorWithFormat("invalid thread #%s.\n",
+ result.AppendErrorWithFormat("invalid thread %s%s.\n",
+ m_options.m_thread_id ? "ID " : "#",
command.GetArgumentAtIndex(0));
return;
}
@@ -1196,6 +1241,8 @@ class CommandObjectThreadSelect : public CommandObjectParsed {
process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);
result.SetStatus(eReturnStatusSuccessFinishNoResult);
}
+
+ CommandOptions m_options;
};
// CommandObjectThreadList
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 542c78be5a12dada..23886046df8f673e 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1117,6 +1117,11 @@ let Command = "thread plan list" in {
Desc<"Display thread plans for unreported threads">;
}
+let Command = "thread select" in {
+ def thread_thread_id : Option<"thread_id", "t">,
+ Desc<"Provide a thread ID instead of a thread index.">;
+}
+
let Command = "thread trace dump function calls" in {
def thread_trace_dump_function_calls_file : Option<"file", "F">, Group<1>,
Arg<"Filename">,
diff --git a/lldb/test/API/commands/thread/select/TestThreadSelect.py b/lldb/test/API/commands/thread/select/TestThreadSelect.py
index 91f8909471bf2bbe..4d01b82d9d947e5b 100644
--- a/lldb/test/API/commands/thread/select/TestThreadSelect.py
+++ b/lldb/test/API/commands/thread/select/TestThreadSelect.py
@@ -12,17 +12,34 @@ def test_invalid_arg(self):
self, "// break here", lldb.SBFileSpec("main.cpp")
)
- self.expect(
- "thread select -1", error=True, startstr="error: Invalid thread index '-1'"
- )
self.expect(
"thread select 0x1ffffffff",
error=True,
startstr="error: Invalid thread index '0x1ffffffff'",
)
+ self.expect(
+ "thread select -t 0x1ffffffff",
+ error=True,
+ startstr="error: Invalid thread ID '0x1ffffffff'",
+ )
# Parses but not a valid thread id.
self.expect(
"thread select 0xffffffff",
error=True,
startstr="error: invalid thread #0xffffffff.",
)
+ self.expect(
+ "thread select -t 0xffffffff",
+ error=True,
+ startstr="error: invalid thread ID 0xffffffff.",
+ )
+
+ def test_thread_select_tid(self):
+ self.build()
+
+ lldbutil.run_to_source_breakpoint(
+ self, "// break here", lldb.SBFileSpec("main.cpp")
+ )
+ self.runCmd(
+ "thread select -t %d" % self.thread().GetThreadID(),
+ )
More information about the lldb-commits
mailing list