@@ -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
{}
@@ -1067,6 +1088,31 @@ class ReflectionContext
1067
1088
return dyn_cast_or_null<const RecordTypeInfo>(TypeInfo);
1068
1089
}
1069
1090
1091
+ bool metadataIsActor (StoredPointer MetadataAddress) {
1092
+ auto Metadata = readMetadata (MetadataAddress);
1093
+ if (!Metadata)
1094
+ return false ;
1095
+
1096
+ // Only classes can be actors.
1097
+ if (Metadata->getKind () != MetadataKind::Class)
1098
+ return false ;
1099
+
1100
+ auto DescriptorAddress =
1101
+ super::readAddressOfNominalTypeDescriptor (Metadata);
1102
+ if (!DescriptorAddress)
1103
+ return false ;
1104
+
1105
+ auto DescriptorBytes =
1106
+ getReader ().readBytes (RemoteAddress (DescriptorAddress),
1107
+ sizeof (TargetTypeContextDescriptor<Runtime>));
1108
+ if (!DescriptorBytes)
1109
+ return false ;
1110
+ auto Descriptor =
1111
+ reinterpret_cast <const TargetTypeContextDescriptor<Runtime> *>(
1112
+ DescriptorBytes.get ());
1113
+ return Descriptor->getTypeContextDescriptorFlags ().class_isActor ();
1114
+ }
1115
+
1070
1116
// / Iterate the protocol conformance cache tree rooted at NodePtr, calling
1071
1117
// / Call with the type and protocol in each node.
1072
1118
void iterateConformanceTree (StoredPointer NodePtr,
@@ -1378,22 +1424,179 @@ class ReflectionContext
1378
1424
return {llvm::None, {Slab->Next , SlabSize, {Chunk}}};
1379
1425
}
1380
1426
1381
- std::pair<llvm::Optional<std::string>, StoredPointer>
1382
- asyncTaskSlabPtr (StoredPointer AsyncTaskPtr) {
1383
- using AsyncTask = AsyncTask<Runtime>;
1384
-
1385
- auto AsyncTaskBytes =
1386
- getReader ().readBytes (RemoteAddress (AsyncTaskPtr), sizeof (AsyncTask));
1387
- auto *AsyncTaskObj =
1388
- reinterpret_cast <const AsyncTask *>(AsyncTaskBytes.get ());
1427
+ std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1428
+ asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1429
+ auto AsyncTaskObj = readObj<AsyncTask<Runtime>>(AsyncTaskPtr);
1389
1430
if (!AsyncTaskObj)
1390
- return {std::string (" failure reading async task" ), 0 };
1431
+ return {std::string (" failure reading async task" ), {}};
1432
+
1433
+ AsyncTaskInfo Info{};
1434
+ Info.JobFlags = AsyncTaskObj->Flags ;
1435
+ Info.TaskStatusFlags = AsyncTaskObj->PrivateStorage .Status .Flags ;
1436
+ Info.Id =
1437
+ AsyncTaskObj->Id | ((uint64_t )AsyncTaskObj->PrivateStorage .Id << 32 );
1438
+ Info.AllocatorSlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
1439
+ Info.RunJob = getRunJob (AsyncTaskObj.get ());
1440
+
1441
+ // Find all child tasks.
1442
+ auto RecordPtr = AsyncTaskObj->PrivateStorage .Status .Record ;
1443
+ while (RecordPtr) {
1444
+ auto RecordObj = readObj<TaskStatusRecord<Runtime>>(RecordPtr);
1445
+ if (!RecordObj)
1446
+ break ;
1447
+
1448
+ // This cuts off high bits if our size_t doesn't match the target's. We
1449
+ // only read the Kind bits which are at the bottom, so that's OK here.
1450
+ // Beware of this when reading anything else.
1451
+ TaskStatusRecordFlags Flags{RecordObj->Flags };
1452
+ auto Kind = Flags.getKind ();
1453
+
1454
+ StoredPointer ChildTask = 0 ;
1455
+ if (Kind == TaskStatusRecordKind::ChildTask) {
1456
+ auto RecordObj = readObj<ChildTaskStatusRecord<Runtime>>(RecordPtr);
1457
+ if (RecordObj)
1458
+ ChildTask = RecordObj->FirstChild ;
1459
+ } else if (Kind == TaskStatusRecordKind::TaskGroup) {
1460
+ auto RecordObj = readObj<TaskGroupTaskStatusRecord<Runtime>>(RecordPtr);
1461
+ if (RecordObj)
1462
+ ChildTask = RecordObj->FirstChild ;
1463
+ }
1464
+
1465
+ while (ChildTask) {
1466
+ Info.ChildTasks .push_back (ChildTask);
1467
+
1468
+ StoredPointer ChildFragmentAddr =
1469
+ ChildTask + sizeof (AsyncTask<Runtime>);
1470
+ auto ChildFragmentObj =
1471
+ readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1472
+ if (ChildFragmentObj)
1473
+ ChildTask = ChildFragmentObj->NextChild ;
1474
+ else
1475
+ ChildTask = 0 ;
1476
+ }
1477
+
1478
+ RecordPtr = RecordObj->Parent ;
1479
+ }
1480
+
1481
+ // Walk the async backtrace if the task isn't running or cancelled.
1482
+ // TODO: Use isEnqueued from https://github.com/apple/swift/pull/41088/ once
1483
+ // that's available.
1484
+ int IsCancelledFlag = 0x100 ;
1485
+ int IsRunningFlag = 0x800 ;
1486
+ if (!(AsyncTaskObj->PrivateStorage .Status .Flags & IsCancelledFlag) &&
1487
+ !(AsyncTaskObj->PrivateStorage .Status .Flags & IsRunningFlag)) {
1488
+ auto ResumeContext = AsyncTaskObj->ResumeContextAndReserved [0 ];
1489
+ while (ResumeContext) {
1490
+ auto ResumeContextObj = readObj<AsyncContext<Runtime>>(ResumeContext);
1491
+ if (!ResumeContextObj)
1492
+ break ;
1493
+ Info.AsyncBacktraceFrames .push_back (
1494
+ stripSignedPointer (ResumeContextObj->ResumeParent ));
1495
+ ResumeContext = stripSignedPointer (ResumeContextObj->Parent );
1496
+ }
1497
+ }
1498
+
1499
+ return {llvm::None, Info};
1500
+ }
1501
+
1502
+ std::pair<llvm::Optional<std::string>, ActorInfo>
1503
+ actorInfo (StoredPointer ActorPtr) {
1504
+ using DefaultActorImpl = DefaultActorImpl<Runtime>;
1505
+
1506
+ auto ActorObj = readObj<DefaultActorImpl>(ActorPtr);
1507
+ if (!ActorObj)
1508
+ return {std::string (" failure reading actor" ), {}};
1509
+
1510
+ ActorInfo Info{};
1511
+ Info.Flags = ActorObj->Flags ;
1512
+
1513
+ // Status is the low 3 bits of Flags. Status of 0 is Idle. Don't read
1514
+ // FirstJob when idle.
1515
+ auto Status = Info.Flags & 0x7 ;
1516
+ if (Status != 0 ) {
1517
+ // This is a JobRef which stores flags in the low bits.
1518
+ Info.FirstJob = ActorObj->FirstJob & ~StoredPointer (0x3 );
1519
+ }
1520
+ return {llvm::None, Info};
1521
+ }
1391
1522
1392
- StoredPointer SlabPtr = AsyncTaskObj->PrivateStorage .Allocator .FirstSlab ;
1393
- return {llvm::None, SlabPtr};
1523
+ StoredPointer nextJob (StoredPointer JobPtr) {
1524
+ using Job = Job<Runtime>;
1525
+
1526
+ auto JobBytes = getReader ().readBytes (RemoteAddress (JobPtr), sizeof (Job));
1527
+ auto *JobObj = reinterpret_cast <const Job *>(JobBytes.get ());
1528
+ if (!JobObj)
1529
+ return 0 ;
1530
+
1531
+ // This is a JobRef which stores flags in the low bits.
1532
+ return JobObj->SchedulerPrivate [0 ] & ~StoredPointer (0x3 );
1394
1533
}
1395
1534
1396
1535
private:
1536
+ // Get the most human meaningful "run job" function pointer from the task,
1537
+ // like AsyncTask::getResumeFunctionForLogging does.
1538
+ StoredPointer getRunJob (const AsyncTask<Runtime> *AsyncTaskObj) {
1539
+ auto Fptr = stripSignedPointer (AsyncTaskObj->RunJob );
1540
+
1541
+ loadTargetPointers ();
1542
+ auto ResumeContextPtr = AsyncTaskObj->ResumeContextAndReserved [0 ];
1543
+ if (target_non_future_adapter && Fptr == target_non_future_adapter) {
1544
+ using Prefix = AsyncContextPrefix<Runtime>;
1545
+ auto PrefixAddr = ResumeContextPtr - sizeof (Prefix);
1546
+ auto PrefixBytes =
1547
+ getReader ().readBytes (RemoteAddress (PrefixAddr), sizeof (Prefix));
1548
+ if (PrefixBytes) {
1549
+ auto PrefixPtr = reinterpret_cast <const Prefix *>(PrefixBytes.get ());
1550
+ return stripSignedPointer (PrefixPtr->AsyncEntryPoint );
1551
+ }
1552
+ } else if (target_future_adapter && Fptr == target_future_adapter) {
1553
+ using Prefix = FutureAsyncContextPrefix<Runtime>;
1554
+ auto PrefixAddr = ResumeContextPtr - sizeof (Prefix);
1555
+ auto PrefixBytes =
1556
+ getReader ().readBytes (RemoteAddress (PrefixAddr), sizeof (Prefix));
1557
+ if (PrefixBytes) {
1558
+ auto PrefixPtr = reinterpret_cast <const Prefix *>(PrefixBytes.get ());
1559
+ return stripSignedPointer (PrefixPtr->AsyncEntryPoint );
1560
+ }
1561
+ } else if ((target_task_wait_throwing_resume_adapter &&
1562
+ Fptr == target_task_wait_throwing_resume_adapter) ||
1563
+ (target_task_future_wait_resume_adapter &&
1564
+ Fptr == target_task_future_wait_resume_adapter)) {
1565
+ auto ContextBytes = getReader ().readBytes (RemoteAddress (ResumeContextPtr),
1566
+ sizeof (AsyncContext<Runtime>));
1567
+ if (ContextBytes) {
1568
+ auto ContextPtr =
1569
+ reinterpret_cast <const AsyncContext<Runtime> *>(ContextBytes.get ());
1570
+ return stripSignedPointer (ContextPtr->ResumeParent );
1571
+ }
1572
+ }
1573
+
1574
+ return Fptr;
1575
+ }
1576
+
1577
+ void loadTargetPointers () {
1578
+ if (setupTargetPointers)
1579
+ return ;
1580
+
1581
+ auto getFunc = [&](const std::string &name) -> StoredPointer {
1582
+ auto Symbol = getReader ().getSymbolAddress (name);
1583
+ if (!Symbol)
1584
+ return 0 ;
1585
+ auto Pointer = getReader ().readPointer (Symbol, sizeof (StoredPointer));
1586
+ if (!Pointer)
1587
+ return 0 ;
1588
+ return Pointer->getResolvedAddress ().getAddressData ();
1589
+ };
1590
+ target_non_future_adapter =
1591
+ getFunc (" _swift_concurrency_debug_non_future_adapter" );
1592
+ target_future_adapter = getFunc (" _swift_concurrency_debug_future_adapter" );
1593
+ target_task_wait_throwing_resume_adapter =
1594
+ getFunc (" _swift_concurrency_debug_task_wait_throwing_resume_adapter" );
1595
+ target_task_future_wait_resume_adapter =
1596
+ getFunc (" _swift_concurrency_debug_task_future_wait_resume_adapter" );
1597
+ setupTargetPointers = true ;
1598
+ }
1599
+
1397
1600
const TypeInfo *
1398
1601
getClosureContextInfo (StoredPointer Context, const ClosureContextInfo &Info,
1399
1602
remote::TypeInfoProvider *ExternalTypeInfo) {
@@ -1615,6 +1818,11 @@ class ReflectionContext
1615
1818
1616
1819
return llvm::None;
1617
1820
}
1821
+
1822
+ template <typename T>
1823
+ MemoryReader::ReadObjResult<T> readObj (StoredPointer Ptr) {
1824
+ return getReader ().template readObj <T>(RemoteAddress (Ptr));
1825
+ }
1618
1826
};
1619
1827
1620
1828
} // end namespace reflection
0 commit comments