Skip to content

Commit d32d287

Browse files
committed
[lldb] Introduce command to select task "threads"
1 parent 2c3335d commit d32d287

File tree

2 files changed

+146
-44
lines changed

2 files changed

+146
-44
lines changed

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

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,6 +2086,46 @@ class CommandObjectSwift_RefCount : public CommandObjectRaw {
20862086
}
20872087
};
20882088

2089+
/// Construct a `ThreadTask` instance for a Task variable contained in the first
2090+
/// argument.
2091+
static llvm::Expected<ThreadSP>
2092+
ThreadForTaskVariable(Args &command, ExecutionContext &exe_ctx) {
2093+
if (!exe_ctx.GetFramePtr())
2094+
return llvm::createStringError("no active frame selected");
2095+
2096+
if (command.empty() || command[0].ref().empty())
2097+
return llvm::createStringError("missing task variable argument");
2098+
2099+
StackFrame &frame = exe_ctx.GetFrameRef();
2100+
uint32_t path_options =
2101+
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
2102+
VariableSP var_sp;
2103+
Status status;
2104+
ValueObjectSP valobj_sp = frame.GetValueForVariableExpressionPath(
2105+
command[0].c_str(), eDynamicDontRunTarget, path_options, var_sp, status);
2106+
if (!valobj_sp)
2107+
return status.takeError();
2108+
2109+
addr_t task_ptr = LLDB_INVALID_ADDRESS;
2110+
ThreadSafeReflectionContext reflection_ctx;
2111+
if (ValueObjectSP task_obj_sp = valobj_sp->GetChildMemberWithName("_task")) {
2112+
task_ptr = task_obj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
2113+
if (task_ptr != LLDB_INVALID_ADDRESS)
2114+
if (auto *runtime = SwiftLanguageRuntime::Get(exe_ctx.GetProcessSP()))
2115+
reflection_ctx = runtime->GetReflectionContext();
2116+
}
2117+
if (task_ptr == LLDB_INVALID_ADDRESS || !reflection_ctx)
2118+
return llvm::createStringError("failed to access Task data from runtime");
2119+
2120+
llvm::Expected<ReflectionContextInterface::AsyncTaskInfo> task_info =
2121+
reflection_ctx->asyncTaskInfo(task_ptr);
2122+
if (auto error = task_info.takeError())
2123+
return error;
2124+
2125+
return ThreadTask::Create(task_info->id, task_info->resumeAsyncContext,
2126+
exe_ctx);
2127+
}
2128+
20892129
class CommandObjectLanguageSwiftTaskBacktrace final
20902130
: public CommandObjectParsed {
20912131
public:
@@ -2099,60 +2139,44 @@ class CommandObjectLanguageSwiftTaskBacktrace final
20992139

21002140
private:
21012141
void DoExecute(Args &command, CommandReturnObject &result) override {
2102-
if (!m_exe_ctx.GetFramePtr()) {
2103-
result.AppendError("no active frame selected");
2104-
return;
2105-
}
2106-
2107-
if (command.empty() || command[0].ref().empty()) {
2108-
result.AppendError("no task variable");
2109-
return;
2110-
}
2111-
2112-
StackFrame &frame = m_exe_ctx.GetFrameRef();
2113-
uint32_t path_options =
2114-
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
2115-
VariableSP var_sp;
2116-
Status status;
2117-
ValueObjectSP valobj_sp = frame.GetValueForVariableExpressionPath(
2118-
command[0].c_str(), eDynamicDontRunTarget, path_options, var_sp,
2119-
status);
2120-
if (!valobj_sp) {
2121-
result.AppendError(status.AsCString());
2142+
llvm::Expected<ThreadSP> thread_task =
2143+
ThreadForTaskVariable(command, m_exe_ctx);
2144+
if (auto error = thread_task.takeError()) {
2145+
result.AppendError(toString(std::move(error)));
21222146
return;
21232147
}
21242148

2125-
addr_t task_ptr = LLDB_INVALID_ADDRESS;
2126-
ThreadSafeReflectionContext reflection_ctx;
2127-
if (ValueObjectSP task_obj_sp =
2128-
valobj_sp->GetChildMemberWithName("_task")) {
2129-
task_ptr = task_obj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
2130-
if (task_ptr != LLDB_INVALID_ADDRESS)
2131-
if (auto *runtime = SwiftLanguageRuntime::Get(m_exe_ctx.GetProcessSP()))
2132-
reflection_ctx = runtime->GetReflectionContext();
2133-
}
2134-
if (task_ptr == LLDB_INVALID_ADDRESS || !reflection_ctx) {
2135-
result.AppendError("failed to access Task data from runtime");
2136-
return;
2137-
}
2149+
// GetStatus prints the backtrace.
2150+
thread_task.get()->GetStatus(result.GetOutputStream(), 0, UINT32_MAX, 0,
2151+
false, true);
2152+
result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
2153+
}
2154+
};
21382155

2139-
llvm::Expected<ReflectionContextInterface::AsyncTaskInfo> task_info =
2140-
reflection_ctx->asyncTaskInfo(task_ptr);
2141-
if (auto error = task_info.takeError()) {
2142-
result.AppendError(toString(std::move(error)));
2143-
return;
2144-
}
2156+
class CommandObjectLanguageSwiftTaskSelect final : public CommandObjectParsed {
2157+
public:
2158+
CommandObjectLanguageSwiftTaskSelect(CommandInterpreter &interpreter)
2159+
: CommandObjectParsed(
2160+
interpreter, "select",
2161+
"Change the currently selected thread to thread representation of "
2162+
"the given Swift Task. See `thread select`.",
2163+
"language swift task select <variable-name>") {
2164+
AddSimpleArgumentList(eArgTypeVarName);
2165+
}
21452166

2146-
auto thread_task = ThreadTask::Create(
2147-
task_info->id, task_info->resumeAsyncContext, m_exe_ctx);
2167+
private:
2168+
void DoExecute(Args &command, CommandReturnObject &result) override {
2169+
llvm::Expected<ThreadSP> thread_task =
2170+
ThreadForTaskVariable(command, m_exe_ctx);
21482171
if (auto error = thread_task.takeError()) {
21492172
result.AppendError(toString(std::move(error)));
21502173
return;
21512174
}
21522175

2153-
// GetStatus prints the backtrace.
2154-
thread_task.get()->GetStatus(result.GetOutputStream(), 0, UINT32_MAX, 0,
2155-
false, true);
2176+
auto &thread_list = m_exe_ctx.GetProcessRef().GetThreadList();
2177+
thread_list.AddThread(thread_task.get());
2178+
thread_list.SetSelectedThreadByID(thread_task.get()->GetID());
2179+
21562180
result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
21572181
}
21582182
};
@@ -2166,6 +2190,9 @@ class CommandObjectLanguageSwiftTask final : public CommandObjectMultiword {
21662190
LoadSubCommand("backtrace",
21672191
CommandObjectSP(new CommandObjectLanguageSwiftTaskBacktrace(
21682192
interpreter)));
2193+
LoadSubCommand(
2194+
"select",
2195+
CommandObjectSP(new CommandObjectLanguageSwiftTaskSelect(interpreter)));
21692196
}
21702197
};
21712198

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import TestBase
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
7+
class TestCase(TestBase):
8+
9+
def test_backtrace_selected_task(self):
10+
self.build()
11+
lldbutil.run_to_source_breakpoint(
12+
self, "break here", lldb.SBFileSpec("main.swift")
13+
)
14+
self.runCmd("language swift task select task")
15+
self.expect(
16+
"thread backtrace",
17+
substrs=[
18+
".sleep(",
19+
"`second() at main.swift:6:",
20+
"`first() at main.swift:2:",
21+
"`closure #1 in static Main.main() at main.swift:12:",
22+
],
23+
)
24+
25+
def test_navigate_selected_task_stack(self):
26+
self.build()
27+
# target, process, thread, bkpt
28+
_, process, _, _ = lldbutil.run_to_source_breakpoint(
29+
self, "break here", lldb.SBFileSpec("main.swift")
30+
)
31+
self.runCmd("language swift task select task")
32+
33+
self.expect(
34+
"thread list",
35+
substrs=[
36+
"* thread #4294967295: tid = 0x0002,",
37+
"libswift_Concurrency.dylib",
38+
"._sleep(",
39+
],
40+
)
41+
42+
frame_index = 0
43+
for frame in process.selected_thread:
44+
if "`second()" in str(frame):
45+
frame_index = frame.idx
46+
self.assertNotEqual(frame_index, -1)
47+
48+
self.expect(
49+
f"frame select {frame_index}",
50+
substrs=[
51+
f"frame #{frame_index}:",
52+
"`second() at main.swift:6:",
53+
" 5 \tfunc second() async {",
54+
"-> 6 \t try? await Task.sleep(for: .seconds(10))",
55+
],
56+
)
57+
58+
self.expect(
59+
"up",
60+
substrs=[
61+
f"frame #{frame_index + 1}:",
62+
"`first() at main.swift:2:",
63+
" 1 \tfunc first() async {",
64+
"-> 2 \t await second()",
65+
],
66+
)
67+
68+
self.expect(
69+
"up",
70+
substrs=[
71+
f"frame #{frame_index + 2}:",
72+
"`closure #1 in static Main.main() at main.swift:12:",
73+
"-> 12 \t await first()",
74+
],
75+
)

0 commit comments

Comments
 (0)