@@ -101,6 +101,12 @@ class ReflectionContext
101
101
std::vector<MemoryReader::ReadBytesResult> savedBuffers;
102
102
std::vector<std::tuple<RemoteAddress, RemoteAddress>> imageRanges;
103
103
104
+ bool setupTargetPointers = false ;
105
+ typename super::StoredPointer target_non_future_adapter = 0 ;
106
+ typename super::StoredPointer target_future_adapter = 0 ;
107
+ typename super::StoredPointer target_task_wait_throwing_resume_adapter = 0 ;
108
+ typename super::StoredPointer target_task_future_wait_resume_adapter = 0 ;
109
+
104
110
public:
105
111
using super::getBuilder;
106
112
using super::readDemanglingForContextDescriptor;
@@ -137,6 +143,21 @@ class ReflectionContext
137
143
std::vector<AsyncTaskAllocationChunk> Chunks;
138
144
};
139
145
146
+ struct AsyncTaskInfo {
147
+ uint32_t JobFlags;
148
+ uint64_t TaskStatusFlags;
149
+ uint64_t Id;
150
+ StoredPointer RunJob;
151
+ StoredPointer AllocatorSlabPtr;
152
+ std::vector<StoredPointer> ChildTasks;
153
+ std::vector<StoredPointer> AsyncBacktraceFrames;
154
+ };
155
+
156
+ struct ActorInfo {
157
+ StoredSize Flags;
158
+ StoredPointer FirstJob;
159
+ };
160
+
140
161
explicit ReflectionContext (std::shared_ptr<MemoryReader> reader)
141
162
: super(std::move(reader), *this)
142
163
{}
@@ -1083,6 +1104,31 @@ class ReflectionContext
1083
1104
return dyn_cast_or_null<const RecordTypeInfo>(TypeInfo);
1084
1105
}
1085
1106
1107
+ bool metadataIsActor (StoredPointer MetadataAddress) {
1108
+ auto Metadata = readMetadata (MetadataAddress);
1109
+ if (!Metadata)
1110
+ return false ;
1111
+
1112
+ // Only classes can be actors.
1113
+ if (Metadata->getKind () != MetadataKind::Class)
1114
+ return false ;
1115
+
1116
+ auto DescriptorAddress =
1117
+ super::readAddressOfNominalTypeDescriptor (Metadata);
1118
+ if (!DescriptorAddress)
1119
+ return false ;
1120
+
1121
+ auto DescriptorBytes =
1122
+ getReader ().readBytes (RemoteAddress (DescriptorAddress),
1123
+ sizeof (TargetTypeContextDescriptor<Runtime>));
1124
+ if (!DescriptorBytes)
1125
+ return false ;
1126
+ auto Descriptor =
1127
+ reinterpret_cast <const TargetTypeContextDescriptor<Runtime> *>(
1128
+ DescriptorBytes.get ());
1129
+ return Descriptor->getTypeContextDescriptorFlags ().class_isActor ();
1130
+ }
1131
+
1086
1132
// / Iterate the protocol conformance cache tree rooted at NodePtr, calling
1087
1133
// / Call with the type and protocol in each node.
1088
1134
void iterateConformanceTree (StoredPointer NodePtr,
@@ -1394,22 +1440,179 @@ class ReflectionContext
1394
1440
return {llvm::None, {Slab->Next , SlabSize, {Chunk}}};
1395
1441
}
1396
1442
1397
- std::pair<llvm::Optional<std::string>, StoredPointer>
1398
- asyncTaskSlabPtr (StoredPointer AsyncTaskPtr) {
1399
- using AsyncTask = AsyncTask<Runtime>;
1400
-
1401
- auto AsyncTaskBytes =
1402
- getReader ().readBytes (RemoteAddress (AsyncTaskPtr), sizeof (AsyncTask));
1403
- auto *AsyncTaskObj =
1404
- reinterpret_cast <const AsyncTask *>(AsyncTaskBytes.get ());
1443
+ std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1444
+ asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1445
+ auto AsyncTaskObj = readObj<AsyncTask<Runtime>>(AsyncTaskPtr);
1405
1446
if (!AsyncTaskObj)
1406
- return {std::string (" failure reading async task" ), 0 };
1447
+ return {std::string (" failure reading async task" ), {}};
1448
+
1449
+ AsyncTaskInfo Info{};
1450
+ Info.JobFlags = AsyncTaskObj->Flags ;
1451
+ Info.TaskStatusFlags = AsyncTaskObj->PrivateStorage .Status .Flags ;
1452
+ Info.Id =
1453
+ AsyncTaskObj->Id | ((uint64_t )AsyncTaskObj->PrivateStorage .Id << 32 );
1454
+ Info.AllocatorSlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
1455
+ Info.RunJob = getRunJob (AsyncTaskObj.get ());
1456
+
1457
+ // Find all child tasks.
1458
+ auto RecordPtr = AsyncTaskObj->PrivateStorage .Status .Record ;
1459
+ while (RecordPtr) {
1460
+ auto RecordObj = readObj<TaskStatusRecord<Runtime>>(RecordPtr);
1461
+ if (!RecordObj)
1462
+ break ;
1463
+
1464
+ // This cuts off high bits if our size_t doesn't match the target's. We
1465
+ // only read the Kind bits which are at the bottom, so that's OK here.
1466
+ // Beware of this when reading anything else.
1467
+ TaskStatusRecordFlags Flags{RecordObj->Flags };
1468
+ auto Kind = Flags.getKind ();
1469
+
1470
+ StoredPointer ChildTask = 0 ;
1471
+ if (Kind == TaskStatusRecordKind::ChildTask) {
1472
+ auto RecordObj = readObj<ChildTaskStatusRecord<Runtime>>(RecordPtr);
1473
+ if (RecordObj)
1474
+ ChildTask = RecordObj->FirstChild ;
1475
+ } else if (Kind == TaskStatusRecordKind::TaskGroup) {
1476
+ auto RecordObj = readObj<TaskGroupTaskStatusRecord<Runtime>>(RecordPtr);
1477
+ if (RecordObj)
1478
+ ChildTask = RecordObj->FirstChild ;
1479
+ }
1480
+
1481
+ while (ChildTask) {
1482
+ Info.ChildTasks .push_back (ChildTask);
1483
+
1484
+ StoredPointer ChildFragmentAddr =
1485
+ ChildTask + sizeof (AsyncTask<Runtime>);
1486
+ auto ChildFragmentObj =
1487
+ readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1488
+ if (ChildFragmentObj)
1489
+ ChildTask = ChildFragmentObj->NextChild ;
1490
+ else
1491
+ ChildTask = 0 ;
1492
+ }
1493
+
1494
+ RecordPtr = RecordObj->Parent ;
1495
+ }
1496
+
1497
+ // Walk the async backtrace if the task isn't running or cancelled.
1498
+ // TODO: Use isEnqueued from https://github.com/apple/swift/pull/41088/ once
1499
+ // that's available.
1500
+ int IsCancelledFlag = 0x100 ;
1501
+ int IsRunningFlag = 0x800 ;
1502
+ if (!(AsyncTaskObj->PrivateStorage .Status .Flags & IsCancelledFlag) &&
1503
+ !(AsyncTaskObj->PrivateStorage .Status .Flags & IsRunningFlag)) {
1504
+ auto ResumeContext = AsyncTaskObj->ResumeContextAndReserved [0 ];
1505
+ while (ResumeContext) {
1506
+ auto ResumeContextObj = readObj<AsyncContext<Runtime>>(ResumeContext);
1507
+ if (!ResumeContextObj)
1508
+ break ;
1509
+ Info.AsyncBacktraceFrames .push_back (
1510
+ stripSignedPointer (ResumeContextObj->ResumeParent ));
1511
+ ResumeContext = stripSignedPointer (ResumeContextObj->Parent );
1512
+ }
1513
+ }
1514
+
1515
+ return {llvm::None, Info};
1516
+ }
1517
+
1518
+ std::pair<llvm::Optional<std::string>, ActorInfo>
1519
+ actorInfo (StoredPointer ActorPtr) {
1520
+ using DefaultActorImpl = DefaultActorImpl<Runtime>;
1521
+
1522
+ auto ActorObj = readObj<DefaultActorImpl>(ActorPtr);
1523
+ if (!ActorObj)
1524
+ return {std::string (" failure reading actor" ), {}};
1525
+
1526
+ ActorInfo Info{};
1527
+ Info.Flags = ActorObj->Flags ;
1528
+
1529
+ // Status is the low 3 bits of Flags. Status of 0 is Idle. Don't read
1530
+ // FirstJob when idle.
1531
+ auto Status = Info.Flags & 0x7 ;
1532
+ if (Status != 0 ) {
1533
+ // This is a JobRef which stores flags in the low bits.
1534
+ Info.FirstJob = ActorObj->FirstJob & ~StoredPointer (0x3 );
1535
+ }
1536
+ return {llvm::None, Info};
1537
+ }
1407
1538
1408
- StoredPointer SlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
1409
- return {llvm::None, SlabPtr};
1539
+ StoredPointer nextJob (StoredPointer JobPtr) {
1540
+ using Job = Job<Runtime>;
1541
+
1542
+ auto JobBytes = getReader ().readBytes (RemoteAddress (JobPtr), sizeof (Job));
1543
+ auto *JobObj = reinterpret_cast <const Job *>(JobBytes.get ());
1544
+ if (!JobObj)
1545
+ return 0 ;
1546
+
1547
+ // This is a JobRef which stores flags in the low bits.
1548
+ return JobObj->SchedulerPrivate [0 ] & ~StoredPointer (0x3 );
1410
1549
}
1411
1550
1412
1551
private:
1552
+ // Get the most human meaningful "run job" function pointer from the task,
1553
+ // like AsyncTask::getResumeFunctionForLogging does.
1554
+ StoredPointer getRunJob (const AsyncTask<Runtime> *AsyncTaskObj) {
1555
+ auto Fptr = stripSignedPointer (AsyncTaskObj->RunJob );
1556
+
1557
+ loadTargetPointers ();
1558
+ auto ResumeContextPtr = AsyncTaskObj->ResumeContextAndReserved [0 ];
1559
+ if (target_non_future_adapter && Fptr == target_non_future_adapter) {
1560
+ using Prefix = AsyncContextPrefix<Runtime>;
1561
+ auto PrefixAddr = ResumeContextPtr - sizeof (Prefix);
1562
+ auto PrefixBytes =
1563
+ getReader ().readBytes (RemoteAddress (PrefixAddr), sizeof (Prefix));
1564
+ if (PrefixBytes) {
1565
+ auto PrefixPtr = reinterpret_cast <const Prefix *>(PrefixBytes.get ());
1566
+ return stripSignedPointer (PrefixPtr->AsyncEntryPoint );
1567
+ }
1568
+ } else if (target_future_adapter && Fptr == target_future_adapter) {
1569
+ using Prefix = FutureAsyncContextPrefix<Runtime>;
1570
+ auto PrefixAddr = ResumeContextPtr - sizeof (Prefix);
1571
+ auto PrefixBytes =
1572
+ getReader ().readBytes (RemoteAddress (PrefixAddr), sizeof (Prefix));
1573
+ if (PrefixBytes) {
1574
+ auto PrefixPtr = reinterpret_cast <const Prefix *>(PrefixBytes.get ());
1575
+ return stripSignedPointer (PrefixPtr->AsyncEntryPoint );
1576
+ }
1577
+ } else if ((target_task_wait_throwing_resume_adapter &&
1578
+ Fptr == target_task_wait_throwing_resume_adapter) ||
1579
+ (target_task_future_wait_resume_adapter &&
1580
+ Fptr == target_task_future_wait_resume_adapter)) {
1581
+ auto ContextBytes = getReader ().readBytes (RemoteAddress (ResumeContextPtr),
1582
+ sizeof (AsyncContext<Runtime>));
1583
+ if (ContextBytes) {
1584
+ auto ContextPtr =
1585
+ reinterpret_cast <const AsyncContext<Runtime> *>(ContextBytes.get ());
1586
+ return stripSignedPointer (ContextPtr->ResumeParent );
1587
+ }
1588
+ }
1589
+
1590
+ return Fptr;
1591
+ }
1592
+
1593
+ void loadTargetPointers () {
1594
+ if (setupTargetPointers)
1595
+ return ;
1596
+
1597
+ auto getFunc = [&](const std::string &name) -> StoredPointer {
1598
+ auto Symbol = getReader ().getSymbolAddress (name);
1599
+ if (!Symbol)
1600
+ return 0 ;
1601
+ auto Pointer = getReader ().readPointer (Symbol, sizeof (StoredPointer));
1602
+ if (!Pointer)
1603
+ return 0 ;
1604
+ return Pointer->getResolvedAddress ().getAddressData ();
1605
+ };
1606
+ target_non_future_adapter =
1607
+ getFunc (" _swift_concurrency_debug_non_future_adapter" );
1608
+ target_future_adapter = getFunc (" _swift_concurrency_debug_future_adapter" );
1609
+ target_task_wait_throwing_resume_adapter =
1610
+ getFunc (" _swift_concurrency_debug_task_wait_throwing_resume_adapter" );
1611
+ target_task_future_wait_resume_adapter =
1612
+ getFunc (" _swift_concurrency_debug_task_future_wait_resume_adapter" );
1613
+ setupTargetPointers = true ;
1614
+ }
1615
+
1413
1616
const TypeInfo *
1414
1617
getClosureContextInfo (StoredPointer Context, const ClosureContextInfo &Info,
1415
1618
remote::TypeInfoProvider *ExternalTypeInfo) {
@@ -1631,6 +1834,11 @@ class ReflectionContext
1631
1834
1632
1835
return llvm::None;
1633
1836
}
1837
+
1838
+ template <typename T>
1839
+ MemoryReader::ReadObjResult<T> readObj (StoredPointer Ptr) {
1840
+ return getReader ().template readObj <T>(RemoteAddress (Ptr));
1841
+ }
1634
1842
};
1635
1843
1636
1844
} // end namespace reflection
0 commit comments