Skip to content

Commit 739191e

Browse files
Merge pull request #10936 from swiftlang/dl/lldb-Add-parent-address-to-Task-synthetic-provider
[lldb] Add parent address to Task synthetic provider
2 parents 46256c8 + 5ef6378 commit 739191e

File tree

9 files changed

+118
-19
lines changed

9 files changed

+118
-19
lines changed

lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,11 @@ namespace lldb_private {
734734
namespace formatters {
735735
namespace swift {
736736

737+
/// The size of Swift Tasks. Fragments are tail allocated.
738+
static constexpr size_t AsyncTaskSize = sizeof(::swift::AsyncTask);
739+
/// The offset of ChildFragment, which is the first fragment of an AsyncTask.
740+
static constexpr offset_t ChildFragmentOffset = AsyncTaskSize;
741+
737742
class EnumSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
738743
public:
739744
EnumSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@@ -806,6 +811,7 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
806811
"address",
807812
"id",
808813
"enqueuePriority",
814+
"parent",
809815
"children",
810816

811817
// Children below this point are hidden.
@@ -823,8 +829,9 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
823829
};
824830

825831
llvm::Expected<uint32_t> CalculateNumChildren() override {
826-
// Show only the first four children address/id/enqueuePriority/children.
827-
return 4;
832+
// Show only the first five children
833+
// address/id/enqueuePriority/parent/children.
834+
return 5;
828835
}
829836

830837
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
@@ -873,6 +880,36 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
873880
RETURN_CHILD(m_enqueue_priority_sp, enqueuePriority, priority_type);
874881
}
875882
case 3: {
883+
if (!m_parent_task_sp) {
884+
auto process_sp = m_backend.GetProcessSP();
885+
if (!process_sp)
886+
return {};
887+
888+
// TypeMangling for "Swift.Optional<Swift.UnsafeRawPointer>"
889+
CompilerType raw_pointer_type =
890+
m_ts->GetTypeFromMangledTypename(ConstString("$sSVSgD"));
891+
892+
addr_t parent_addr = 0;
893+
if (m_task_info.isChildTask) {
894+
// Read ChildFragment::Parent, the first field of the ChildFragment.
895+
Status status;
896+
parent_addr = process_sp->ReadPointerFromMemory(
897+
m_task_ptr + ChildFragmentOffset, status);
898+
if (status.Fail() || parent_addr == LLDB_INVALID_ADDRESS)
899+
parent_addr = 0;
900+
}
901+
902+
addr_t value = parent_addr;
903+
DataExtractor data{reinterpret_cast<const void *>(&value),
904+
sizeof(value), endian::InlHostByteOrder(),
905+
sizeof(void *)};
906+
m_parent_task_sp = ValueObject::CreateValueObjectFromData(
907+
"parent", data, m_backend.GetExecutionContextRef(),
908+
raw_pointer_type);
909+
}
910+
return m_parent_task_sp;
911+
}
912+
case 4: {
876913
if (!m_child_tasks_sp) {
877914
using task_type = decltype(m_task_info.childTasks)::value_type;
878915
std::vector<task_type> tasks = m_task_info.childTasks;
@@ -901,26 +938,26 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
901938
}
902939
return m_child_tasks_sp;
903940
}
904-
case 4:
905-
RETURN_CHILD(m_is_child_task_sp, isChildTask, bool_type);
906941
case 5:
907-
RETURN_CHILD(m_is_future_sp, isFuture, bool_type);
942+
RETURN_CHILD(m_is_child_task_sp, isChildTask, bool_type);
908943
case 6:
909-
RETURN_CHILD(m_is_group_child_task_sp, isGroupChildTask, bool_type);
944+
RETURN_CHILD(m_is_future_sp, isFuture, bool_type);
910945
case 7:
911-
RETURN_CHILD(m_is_async_let_task_sp, isAsyncLetTask, bool_type);
946+
RETURN_CHILD(m_is_group_child_task_sp, isGroupChildTask, bool_type);
912947
case 8:
913-
RETURN_CHILD(m_is_cancelled_sp, isCancelled, bool_type);
948+
RETURN_CHILD(m_is_async_let_task_sp, isAsyncLetTask, bool_type);
914949
case 9:
950+
RETURN_CHILD(m_is_cancelled_sp, isCancelled, bool_type);
951+
case 10:
915952
RETURN_CHILD(m_is_status_record_locked_sp, isStatusRecordLocked,
916953
bool_type);
917-
case 10:
918-
RETURN_CHILD(m_is_escalated_sp, isEscalated, bool_type);
919954
case 11:
920-
RETURN_CHILD(m_is_enqueued_sp, isEnqueued, bool_type);
955+
RETURN_CHILD(m_is_escalated_sp, isEscalated, bool_type);
921956
case 12:
957+
RETURN_CHILD(m_is_enqueued_sp, isEnqueued, bool_type);
958+
case 13:
922959
RETURN_CHILD(m_is_complete_sp, isComplete, bool_type);
923-
case 13: {
960+
case 14: {
924961
if (m_task_info.hasIsRunning)
925962
RETURN_CHILD(m_is_running_sp, isRunning, bool_type);
926963
return {};
@@ -953,8 +990,8 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
953990
m_is_child_task_sp, m_is_future_sp, m_is_group_child_task_sp,
954991
m_is_async_let_task_sp, m_is_cancelled_sp,
955992
m_is_status_record_locked_sp, m_is_escalated_sp,
956-
m_is_enqueued_sp, m_is_complete_sp, m_child_tasks_sp,
957-
m_is_running_sp})
993+
m_is_enqueued_sp, m_is_complete_sp, m_parent_task_sp,
994+
m_child_tasks_sp, m_is_running_sp})
958995
child.reset();
959996
}
960997
}
@@ -990,6 +1027,7 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
9901027
ValueObjectSP m_is_escalated_sp;
9911028
ValueObjectSP m_is_enqueued_sp;
9921029
ValueObjectSP m_is_complete_sp;
1030+
ValueObjectSP m_parent_task_sp;
9931031
ValueObjectSP m_child_tasks_sp;
9941032
ValueObjectSP m_is_running_sp;
9951033
};
@@ -1280,8 +1318,6 @@ class TaskGroupSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
12801318
bool operator==(const Task &other) const { return addr == other.addr; }
12811319
bool operator!=(const Task &other) const { return !(*this == other); }
12821320

1283-
static constexpr offset_t AsyncTaskSize = sizeof(::swift::AsyncTask);
1284-
static constexpr offset_t ChildFragmentOffset = AsyncTaskSize;
12851321
static constexpr offset_t NextChildOffset = ChildFragmentOffset + 0x8;
12861322

12871323
Task getNextChild(Status &status) {

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2859,6 +2859,13 @@ TypeSystemSwiftTypeRef::RemangleAsType(swift::Demangle::Demangler &dem,
28592859
if (!node)
28602860
return {};
28612861

2862+
// Guard against an empty opaque type. This can happen when demangling an
2863+
// OpaqueTypeRef (ex `$sBpD`). An empty opaque will assert when mangled.
2864+
if (auto *opaque_type =
2865+
swift_demangle::ChildAtPath(node, {Node::Kind::OpaqueType}))
2866+
if (!opaque_type->hasChildren())
2867+
return {};
2868+
28622869
using namespace swift::Demangle;
28632870
if (node->getKind() != Node::Kind::Global) {
28642871
auto global = dem.createNode(Node::Kind::Global);

lldb/test/API/lang/swift/async/continuations/TestSwiftContinuationSynthetic.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def test_unsafe_continuation_printing(self):
2424
address = 0x[0-9a-f]+
2525
id = \1
2626
enqueuePriority = 0
27+
parent = nil
2728
children = \{\}
2829
\}
2930
\}
@@ -49,6 +50,7 @@ def test_checked_continuation_printing(self):
4950
address = 0x[0-9a-f]+
5051
id = \1
5152
enqueuePriority = 0
53+
parent = nil
5254
children = \{\}
5355
\}
5456
\}

lldb/test/API/lang/swift/async/formatters/task/TestSwiftTaskSyntheticProvider.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def test_top_level_task(self):
2525
address = 0x[0-9a-f]+
2626
id = \1
2727
enqueuePriority = \.medium
28+
parent = nil
2829
children = \{\}
2930
}
3031
"""
@@ -49,6 +50,7 @@ def test_current_task(self):
4950
address = 0x[0-9a-f]+
5051
id = \1
5152
enqueuePriority = \.medium
53+
parent = 0x[0-9a-f]+ \{\}
5254
children = \{\}
5355
\}
5456
"""

lldb/test/API/lang/swift/async/formatters/task/children/TestSwiftSyntheticTaskChildren.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ def test(self):
2121
textwrap.dedent(
2222
r"""
2323
\(UnsafeCurrentTask\) current_task = id:1 flags:(?:running|enqueued) \{
24-
address = 0x[0-9a-f]+
24+
address = (0x[0-9a-f]+)
2525
id = 1
2626
enqueuePriority = 0
27+
parent = nil
2728
children = \{
2829
0 = id:2 flags:(?:running\|)?(?:enqueued\|)?asyncLetTask \{
2930
address = 0x[0-9a-f]+
3031
id = 2
3132
enqueuePriority = \.medium
33+
parent = \1 \{\}
3234
children = \{\}
3335
\}
3436
\}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFTFLAGS_EXTRAS := -parse-as-library
3+
include Makefile.rules
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import re
2+
import lldb
3+
from lldbsuite.test.decorators import *
4+
from lldbsuite.test.lldbtest import *
5+
from lldbsuite.test import lldbutil
6+
7+
8+
ADDR_PATTERN = "(0x[0-9a-f]{6,})"
9+
10+
class TestCase(TestBase):
11+
12+
@skipUnlessDarwin
13+
@swiftTest
14+
def test(self):
15+
self.build()
16+
_, process, _, _ = lldbutil.run_to_name_breakpoint(self, "breakHere")
17+
18+
# First breakpoint hit occurrs in a root task, with no parent.
19+
self.expect("task info", substrs=["parent = nil"])
20+
root_task = self._extract("task info", f"address = {ADDR_PATTERN}")
21+
22+
# Continue to the next hit of the same breakpoint, which is called from
23+
# an async let child task.
24+
process.Continue()
25+
parent_of_child_task = self._extract("task info", f"parent = {ADDR_PATTERN}")
26+
27+
# Ensure the parent of the child is the same as the root task.
28+
self.assertEqual(root_task, parent_of_child_task)
29+
30+
def _extract(self, command: str, pattern: str) -> str:
31+
ret = lldb.SBCommandReturnObject()
32+
self.ci.HandleCommand(command, ret)
33+
match = re.search(pattern, ret.GetOutput(), flags=re.I)
34+
self.assertTrue(match)
35+
return match.group(1) if match else ""
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
func breakHere() {}
2+
3+
@main struct Main {
4+
static func main() async {
5+
await breakHere()
6+
async let x = breakHere()
7+
await x
8+
}
9+
}

lldb/test/API/lang/swift/async/taskgroups/TestSwiftTaskGroupSynthetic.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,21 @@ def do_test_print(self):
3636
address = 0x[0-9a-f]+
3737
id = \1
3838
enqueuePriority = \.medium
39+
parent = (.+)
3940
children = \{\}
4041
\}
4142
\[1\] = id:([1-9]\d*) flags:(?:running\|)?(?:enqueued\|)?groupChildTask \{
4243
address = 0x[0-9a-f]+
43-
id = \2
44+
id = \3
4445
enqueuePriority = \.medium
46+
parent = \2
4547
children = \{\}
4648
\}
4749
\[2\] = id:([1-9]\d*) flags:(?:running\|)?(?:enqueued\|)?groupChildTask \{
4850
address = 0x[0-9a-f]+
49-
id = \3
51+
id = \4
5052
enqueuePriority = \.medium
53+
parent = \2
5154
children = \{\}
5255
\}
5356
\}

0 commit comments

Comments
 (0)