Skip to content

Commit 0a0c9a6

Browse files
authored
[lldb] Accept address in task backtrace and select commands (#10191)
Update the `language swift task {backtrace,select}` commands to take a task address. This is useful in conjunction with #10176 which prints a tasks address. An example use case is printing a `TaskGroup`, and then using the address of one of the group's child tasks with either the `backtrace` or `select` command.
1 parent 6956cf6 commit 0a0c9a6

File tree

3 files changed

+97
-37
lines changed

3 files changed

+97
-37
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2164,58 +2164,72 @@ class CommandObjectSwift_RefCount : public CommandObjectRaw {
21642164
/// Construct a `ThreadTask` instance for a Task variable contained in the first
21652165
/// argument.
21662166
static llvm::Expected<ThreadSP>
2167-
ThreadForTaskVariable(Args &command, ExecutionContext &exe_ctx) {
2167+
ThreadForTaskArgument(Args &command, ExecutionContext &exe_ctx) {
21682168
if (!exe_ctx.GetFramePtr())
21692169
return llvm::createStringError("no active frame selected");
21702170

21712171
if (command.empty() || command[0].ref().empty())
21722172
return llvm::createStringError("missing task variable argument");
21732173

2174+
StringRef arg = command[0].ref();
2175+
21742176
StackFrame &frame = exe_ctx.GetFrameRef();
21752177
uint32_t path_options =
21762178
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
21772179
VariableSP var_sp;
21782180
Status status;
21792181
ValueObjectSP valobj_sp = frame.GetValueForVariableExpressionPath(
2180-
command[0].c_str(), eDynamicDontRunTarget, path_options, var_sp, status);
2181-
if (!valobj_sp)
2182-
return status.takeError();
2182+
arg, eDynamicDontRunTarget, path_options, var_sp, status);
21832183

21842184
addr_t task_ptr = LLDB_INVALID_ADDRESS;
2185-
ThreadSafeReflectionContext reflection_ctx;
2186-
if (ValueObjectSP task_obj_sp = valobj_sp->GetChildMemberWithName("_task")) {
2187-
task_ptr = task_obj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
2188-
if (task_ptr != LLDB_INVALID_ADDRESS)
2189-
if (auto *runtime = SwiftLanguageRuntime::Get(exe_ctx.GetProcessSP()))
2190-
reflection_ctx = runtime->GetReflectionContext();
2185+
if (status.Success() && valobj_sp) {
2186+
if (auto task_obj_sp = valobj_sp->GetChildMemberWithName("_task"))
2187+
task_ptr = task_obj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
2188+
if (task_ptr == LLDB_INVALID_ADDRESS)
2189+
return llvm::createStringError("failed to access Task pointer");
2190+
} else {
2191+
// The argument is not a valid variable expression, try parsing it as a
2192+
// (task) address.
2193+
if (arg.getAsInteger(0, task_ptr))
2194+
return status.takeError();
21912195
}
2192-
if (task_ptr == LLDB_INVALID_ADDRESS || !reflection_ctx)
2193-
return llvm::createStringError("failed to access Task data from runtime");
21942196

2195-
llvm::Expected<ReflectionContextInterface::AsyncTaskInfo> task_info =
2196-
reflection_ctx->asyncTaskInfo(task_ptr);
2197-
if (auto error = task_info.takeError())
2198-
return error;
2197+
if (auto *runtime = SwiftLanguageRuntime::Get(exe_ctx.GetProcessSP()))
2198+
if (auto reflection_ctx = runtime->GetReflectionContext()) {
2199+
if (auto task_info = reflection_ctx->asyncTaskInfo(task_ptr))
2200+
return ThreadTask::Create(task_info->id, task_info->resumeAsyncContext,
2201+
exe_ctx);
2202+
else
2203+
return task_info.takeError();
2204+
}
21992205

2200-
return ThreadTask::Create(task_info->id, task_info->resumeAsyncContext,
2201-
exe_ctx);
2206+
return llvm::createStringError("failed to access Task data from runtime");
22022207
}
22032208

22042209
class CommandObjectLanguageSwiftTaskBacktrace final
22052210
: public CommandObjectParsed {
22062211
public:
22072212
CommandObjectLanguageSwiftTaskBacktrace(CommandInterpreter &interpreter)
2208-
: CommandObjectParsed(interpreter, "backtrace",
2209-
"Show the backtrace of Swift tasks. See `thread "
2210-
"backtrace` for customizing backtrace output.",
2211-
"language swift task backtrace <variable-name>") {
2212-
AddSimpleArgumentList(eArgTypeVarName);
2213+
: CommandObjectParsed(
2214+
interpreter, "backtrace",
2215+
"Show the backtrace of Swift tasks. See `thread "
2216+
"backtrace` for customizing backtrace output.",
2217+
"language swift task backtrace <variable-name | address>") {
2218+
CommandArgumentEntry arg_entry;
2219+
arg_entry.emplace_back(eArgTypeVarName, eArgRepeatPlain, LLDB_OPT_SET_1);
2220+
arg_entry.emplace_back(eArgTypeAddress, eArgRepeatPlain, LLDB_OPT_SET_2);
2221+
m_arguments.push_back(arg_entry);
22132222
}
22142223

22152224
private:
22162225
void DoExecute(Args &command, CommandReturnObject &result) override {
2226+
if (command.GetArgumentCount() != 1) {
2227+
result.AppendError("missing <variable-name> or <address> argument");
2228+
return;
2229+
}
2230+
22172231
llvm::Expected<ThreadSP> thread_task =
2218-
ThreadForTaskVariable(command, m_exe_ctx);
2232+
ThreadForTaskArgument(command, m_exe_ctx);
22192233
if (auto error = thread_task.takeError()) {
22202234
result.AppendError(toString(std::move(error)));
22212235
return;
@@ -2235,14 +2249,22 @@ class CommandObjectLanguageSwiftTaskSelect final : public CommandObjectParsed {
22352249
interpreter, "select",
22362250
"Change the currently selected thread to thread representation of "
22372251
"the given Swift Task. See `thread select`.",
2238-
"language swift task select <variable-name>") {
2239-
AddSimpleArgumentList(eArgTypeVarName);
2252+
"language swift task select <variable-name | address>") {
2253+
CommandArgumentEntry arg_entry;
2254+
arg_entry.emplace_back(eArgTypeVarName, eArgRepeatPlain, LLDB_OPT_SET_1);
2255+
arg_entry.emplace_back(eArgTypeAddress, eArgRepeatPlain, LLDB_OPT_SET_2);
2256+
m_arguments.push_back(arg_entry);
22402257
}
22412258

22422259
private:
22432260
void DoExecute(Args &command, CommandReturnObject &result) override {
2261+
if (command.GetArgumentCount() != 1) {
2262+
result.AppendError("missing <variable-name> or <address> argument");
2263+
return;
2264+
}
2265+
22442266
llvm::Expected<ThreadSP> thread_task =
2245-
ThreadForTaskVariable(command, m_exe_ctx);
2267+
ThreadForTaskArgument(command, m_exe_ctx);
22462268
if (auto error = thread_task.takeError()) {
22472269
result.AppendError(toString(std::move(error)));
22482270
return;

lldb/test/API/lang/swift/async/tasks/TestSwiftTaskBacktrace.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,27 @@
55

66

77
class TestCase(TestBase):
8-
def test(self):
8+
9+
def test_backtrace_task_variable(self):
910
self.build()
1011
lldbutil.run_to_source_breakpoint(
1112
self, "break here", lldb.SBFileSpec("main.swift")
1213
)
14+
self.do_backtrace("task")
15+
16+
def test_backtrace_task_address(self):
17+
self.build()
18+
_, _, thread, _ = lldbutil.run_to_source_breakpoint(
19+
self, "break here", lldb.SBFileSpec("main.swift")
20+
)
21+
frame = thread.frames[0]
22+
task = frame.FindVariable("task")
23+
task_addr = task.GetChildMemberWithName("address").unsigned
24+
self.do_backtrace(task_addr)
25+
26+
def do_backtrace(self, arg):
1327
self.expect(
14-
"language swift task backtrace task",
28+
f"language swift task backtrace {arg}",
1529
substrs=[
1630
".sleep(",
1731
"`second() at main.swift:6",

lldb/test/API/lang/swift/async/tasks/TestSwiftTaskSelect.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,25 @@
66

77
class TestCase(TestBase):
88

9-
def test_backtrace_selected_task(self):
9+
def test_backtrace_selected_task_variable(self):
1010
self.build()
1111
lldbutil.run_to_source_breakpoint(
1212
self, "break here", lldb.SBFileSpec("main.swift")
1313
)
14-
self.runCmd("language swift task select task")
14+
self.do_backtrace_selected_task("task")
15+
16+
def test_backtrace_selected_task_address(self):
17+
self.build()
18+
_, _, thread, _ = lldbutil.run_to_source_breakpoint(
19+
self, "break here", lldb.SBFileSpec("main.swift")
20+
)
21+
frame = thread.frames[0]
22+
task = frame.FindVariable("task")
23+
task_addr = task.GetChildMemberWithName("address").unsigned
24+
self.do_backtrace_selected_task(task_addr)
25+
26+
def do_backtrace_selected_task(self, arg):
27+
self.runCmd(f"language swift task select {arg}")
1528
self.expect(
1629
"thread backtrace",
1730
substrs=[
@@ -22,16 +35,27 @@ def test_backtrace_selected_task(self):
2235
],
2336
)
2437

25-
def test_navigate_selected_task_stack(self):
38+
def test_navigate_stack_of_selected_task_variable(self):
2639
self.build()
27-
_, process, _, _ = lldbutil.run_to_source_breakpoint(
40+
_, process, thread, _ = lldbutil.run_to_source_breakpoint(
2841
self, "break here", lldb.SBFileSpec("main.swift")
2942
)
30-
self.runCmd("language swift task select task")
43+
self.do_test_navigate_selected_task_stack(process, "task")
44+
45+
def test_navigate_stack_of_selected_task_address(self):
46+
self.build()
47+
_, process, thread, _ = lldbutil.run_to_source_breakpoint(
48+
self, "break here", lldb.SBFileSpec("main.swift")
49+
)
50+
frame = thread.frames[0]
51+
task = frame.FindVariable("task")
52+
task_addr = task.GetChildMemberWithName("address").unsigned
53+
self.do_test_navigate_selected_task_stack(process, task_addr)
54+
55+
def do_test_navigate_selected_task_stack(self, process, arg):
56+
self.runCmd(f"language swift task select {arg}")
57+
thread = process.GetSelectedThread()
3158

32-
thread = process.selected_thread
33-
self.assertEqual(thread.id, 2)
34-
self.assertEqual(thread.idx, 0xFFFFFFFF)
3559
self.assertIn(
3660
"libswift_Concurrency.", thread.GetSelectedFrame().module.file.basename
3761
)

0 commit comments

Comments
 (0)