28
28
#include < os/lock.h>
29
29
#endif
30
30
31
+ // / Enumerate over all Swift type metadata sections in the current process.
32
+ // /
33
+ // / - Parameters:
34
+ // / - body: A function to call once for every section in the current process.
35
+ // / A pointer to the first type metadata record and the number of records
36
+ // / are passed to this function.
37
+ template <typename SectionEnumerator>
38
+ static void enumerateTypeMetadataSections (const SectionEnumerator& body);
39
+
31
40
// / A type that acts as a C++ [Allocator](https://en.cppreference.com/w/cpp/named_req/Allocator)
32
41
// / without using global `operator new` or `operator delete`.
33
42
// /
@@ -49,18 +58,35 @@ struct SWTHeapAllocator {
49
58
}
50
59
};
51
60
52
- // / A `std::vector` that uses `SWTHeapAllocator`.
61
+ // / A structure describing the bounds of a Swift metadata section.
62
+ // /
63
+ // / The template argument `T` is the element type of the metadata section.
64
+ // / Instances of this type can be used with a range-based `for`-loop to iterate
65
+ // / the contents of the section.
53
66
template <typename T>
54
- using SWTVector = std::vector<T, SWTHeapAllocator<T>>;
67
+ struct SWTSectionBounds {
68
+ // / The base address of the image containing the section, if known.
69
+ const void *imageAddress;
55
70
56
- // / Enumerate over all Swift type metadata sections in the current process.
57
- // /
58
- // / - Parameters:
59
- // / - body: A function to call once for every section in the current process.
60
- // / A pointer to the first type metadata record and the number of records
61
- // / are passed to this function.
62
- template <typename SectionEnumerator>
63
- static void enumerateTypeMetadataSections (const SectionEnumerator& body);
71
+ // / The base address of the section.
72
+ const void *start;
73
+
74
+ // / The size of the section in bytes.
75
+ size_t size;
76
+
77
+ const struct SWTTypeMetadataRecord *begin (void ) const {
78
+ return reinterpret_cast <const T *>(start);
79
+ }
80
+
81
+ const struct SWTTypeMetadataRecord *end (void ) const {
82
+ return reinterpret_cast <const T *>(reinterpret_cast <uintptr_t >(start) + size);
83
+ }
84
+ };
85
+
86
+ // / A type that acts as a C++ [Container](https://en.cppreference.com/w/cpp/named_req/Container)
87
+ // / and which contains a sequence of instances of `SWTSectionBounds<T>`.
88
+ template <typename T>
89
+ using SWTSectionBoundsList = std::vector<SWTSectionBounds<T>, SWTHeapAllocator<SWTSectionBounds<T>>>;
64
90
65
91
#pragma mark - Swift ABI
66
92
@@ -217,22 +243,14 @@ struct SWTTypeMetadataRecord {
217
243
#if !defined(SWT_NO_DYNAMIC_LINKING)
218
244
#pragma mark - Apple implementation
219
245
220
- // / A type that acts as a C++ [Container](https://en.cppreference.com/w/cpp/named_req/Container)
221
- // / and which contains a sequence of Mach headers.
222
- #if __LP64__
223
- using SWTMachHeaderList = SWTVector<const mach_header_64 *>;
224
- #else
225
- using SWTMachHeaderList = SWTVector<const mach_header *>;
226
- #endif
227
-
228
- // / Get a copy of the currently-loaded Mach headers list.
246
+ // / Get a copy of the currently-loaded type metadata sections list.
229
247
// /
230
- // / - Returns: A list of Mach headers loaded into the current process. The order
231
- // / of the resulting list is unspecified.
248
+ // / - Returns: A list of type metadata sections in images loaded into the
249
+ // / current process. The order of the resulting list is unspecified.
232
250
// /
233
- // / On non-Apple platforms, the `swift_enumerateAllMetadataSections()` function
251
+ // / On ELF-based platforms, the `swift_enumerateAllMetadataSections()` function
234
252
// / exported by the runtime serves the same purpose as this function.
235
- static SWTMachHeaderList getMachHeaders (void ) {
253
+ static SWTSectionBoundsList<SWTTypeMetadataRecord> getSectionBounds (void ) {
236
254
// / This list is necessarily mutated while a global libobjc- or dyld-owned
237
255
// / lock is held. Hence, code using this list must avoid potentially
238
256
// / re-entering either library (otherwise it could potentially deadlock.)
@@ -242,17 +260,21 @@ static SWTMachHeaderList getMachHeaders(void) {
242
260
// / testing library is not tasked with the same performance constraints as
243
261
// / Swift's runtime library, we just use a `std::vector` guarded by an unfair
244
262
// / lock.
245
- static constinit SWTMachHeaderList *machHeaders = nullptr ;
263
+ static constinit SWTSectionBoundsList<SWTTypeMetadataRecord> *sectionBounds = nullptr ;
246
264
static constinit os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
247
265
248
266
static constinit dispatch_once_t once = 0 ;
249
267
dispatch_once_f (&once, nullptr , [] (void *) {
250
- machHeaders = reinterpret_cast <SWTMachHeaderList *>(std::malloc (sizeof (SWTMachHeaderList )));
251
- ::new (machHeaders) SWTMachHeaderList ();
252
- machHeaders ->reserve (_dyld_image_count ());
268
+ sectionBounds = reinterpret_cast <SWTSectionBoundsList<SWTTypeMetadataRecord> *>(std::malloc (sizeof (SWTSectionBoundsList<SWTTypeMetadataRecord> )));
269
+ ::new (sectionBounds) SWTSectionBoundsList<SWTTypeMetadataRecord> ();
270
+ sectionBounds ->reserve (_dyld_image_count ());
253
271
254
272
objc_addLoadImageFunc ([] (const mach_header *mh) {
255
- auto mhn = reinterpret_cast <SWTMachHeaderList::value_type>(mh);
273
+ #if __LP64__
274
+ auto mhn = reinterpret_cast <const mach_header_64 *>(mh);
275
+ #else
276
+ auto mhn = mh;
277
+ #endif
256
278
257
279
// Ignore this Mach header if it is in the shared cache. On platforms that
258
280
// support it (Darwin), most system images are contained in this range.
@@ -262,41 +284,36 @@ static SWTMachHeaderList getMachHeaders(void) {
262
284
return ;
263
285
}
264
286
265
- // Only store the mach header address if the image contains Swift data.
266
- // Swift does not support unloading images, but images that do not contain
267
- // Swift code may be unloaded at runtime and later crash
268
- // the testing library when it calls enumerateTypeMetadataSections().
287
+ // If this image contains the Swift section we need, acquire the lock and
288
+ // store the section's bounds.
269
289
unsigned long size = 0 ;
270
- if (getsectiondata (mhn, SEG_TEXT, " __swift5_types" , &size)) {
290
+ auto start = getsectiondata (mhn, SEG_TEXT, " __swift5_types" , &size);
291
+ if (start && size > 0 ) {
271
292
os_unfair_lock_lock (&lock); {
272
- machHeaders-> push_back (mhn);
293
+ sectionBounds-> emplace_back (mhn, start, size );
273
294
} os_unfair_lock_unlock (&lock);
274
295
}
275
296
});
276
297
});
277
298
278
299
// After the first call sets up the loader hook, all calls take the lock and
279
300
// make a copy of whatever has been loaded so far.
280
- SWTMachHeaderList result;
301
+ SWTSectionBoundsList<SWTTypeMetadataRecord> result;
281
302
result.reserve (_dyld_image_count ());
282
303
os_unfair_lock_lock (&lock); {
283
- result = *machHeaders ;
304
+ result = *sectionBounds ;
284
305
} os_unfair_lock_unlock (&lock);
306
+ result.shrink_to_fit ();
285
307
return result;
286
308
}
287
309
288
310
template <typename SectionEnumerator>
289
311
static void enumerateTypeMetadataSections (const SectionEnumerator& body) {
290
- SWTMachHeaderList machHeaders = getMachHeaders ();
291
- for (auto mh : machHeaders) {
292
- unsigned long size = 0 ;
293
- const void *section = getsectiondata (mh, SEG_TEXT, " __swift5_types" , &size);
294
- if (section && size > 0 ) {
295
- bool stop = false ;
296
- body (mh, section, size, &stop);
297
- if (stop) {
298
- break ;
299
- }
312
+ bool stop = false ;
313
+ for (const auto & sb : getSectionBounds ()) {
314
+ body (sb, &stop);
315
+ if (stop) {
316
+ break ;
300
317
}
301
318
}
302
319
}
@@ -313,9 +330,13 @@ extern "C" const char sectionEnd __asm("section$end$__TEXT$__swift5_types");
313
330
314
331
template <typename SectionEnumerator>
315
332
static void enumerateTypeMetadataSections (const SectionEnumerator& body) {
316
- auto size = std::distance (§ionBegin, §ionEnd);
333
+ SWTSectionBounds<SWTTypeMetadataRecord> sb = {
334
+ nullptr ,
335
+ §ionBegin,
336
+ static_cast <size_t >(std::distance (§ionBegin, §ionEnd))
337
+ };
317
338
bool stop = false ;
318
- body (nullptr , §ionBegin, size , &stop);
339
+ body (sb , &stop);
319
340
}
320
341
#endif
321
342
@@ -325,37 +346,31 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {
325
346
// / Find the section with the given name in the given module.
326
347
// /
327
348
// / - Parameters:
328
- // / - module : The module to inspect.
349
+ // / - hModule : The module to inspect.
329
350
// / - sectionName: The name of the section to look for. Long section names are
330
351
// / not supported.
331
352
// /
332
353
// / - Returns: A pointer to the start of the given section along with its size
333
354
// / in bytes, or `std::nullopt` if the section could not be found. If the
334
355
// / section was emitted by the Swift toolchain, be aware it will have leading
335
356
// / and trailing bytes (`sizeof(uintptr_t)` each.)
336
- static std::optional<std::pair< const void *, size_t >> findSection (HMODULE module , const char *sectionName) {
337
- if (!module ) {
357
+ static std::optional<SWTSectionBounds<SWTTypeMetadataRecord >> findSection (HMODULE hModule , const char *sectionName) {
358
+ if (!hModule ) {
338
359
return std::nullopt;
339
360
}
340
361
341
362
// Get the DOS header (to which the HMODULE directly points, conveniently!)
342
363
// and check it's sufficiently valid for us to walk.
343
- auto dosHeader = reinterpret_cast <const PIMAGE_DOS_HEADER>(module );
364
+ auto dosHeader = reinterpret_cast <const PIMAGE_DOS_HEADER>(hModule );
344
365
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE || dosHeader->e_lfanew <= 0 ) {
345
366
return std::nullopt;
346
367
}
347
368
348
- // Check the NT header as well as the optional header.
369
+ // Check the NT header. Since we don't use the optional header, skip it .
349
370
auto ntHeader = reinterpret_cast <const PIMAGE_NT_HEADERS>(reinterpret_cast <uintptr_t >(dosHeader) + dosHeader->e_lfanew );
350
371
if (!ntHeader || ntHeader->Signature != IMAGE_NT_SIGNATURE) {
351
372
return std::nullopt;
352
373
}
353
- if (ntHeader->FileHeader .SizeOfOptionalHeader < offsetof (decltype (ntHeader->OptionalHeader ), Magic) + sizeof (decltype (ntHeader->OptionalHeader )::Magic)) {
354
- return std::nullopt;
355
- }
356
- if (ntHeader->OptionalHeader .Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) {
357
- return std::nullopt;
358
- }
359
374
360
375
auto sectionCount = ntHeader->FileHeader .NumberOfSections ;
361
376
auto section = IMAGE_FIRST_SECTION (ntHeader);
@@ -370,7 +385,7 @@ static std::optional<std::pair<const void *, size_t>> findSection(HMODULE module
370
385
// FIXME: Handle longer names ("/%u") from string table
371
386
auto thisSectionName = reinterpret_cast <const char *>(section->Name );
372
387
if (0 == std::strncmp (sectionName, thisSectionName, IMAGE_SIZEOF_SHORT_NAME)) {
373
- return std::make_pair ( start, size) ;
388
+ return SWTSectionBounds<SWTTypeMetadataRecord> { hModule, start, size } ;
374
389
}
375
390
}
376
391
}
@@ -392,27 +407,27 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {
392
407
// Look in all the loaded modules for Swift type metadata sections and store
393
408
// them in a side table.
394
409
//
395
- // This two-step process is less algorithmically efficient than a single loop,
396
- // but it is safer: the callback will eventually invoke developer code that
410
+ // This two-step process is more complicated to read than a single loop would
411
+ // be but it is safer: the callback will eventually invoke developer code that
397
412
// could theoretically unload a module from the list we're enumerating. (Swift
398
413
// modules do not support unloading, so we'll just not worry about them.)
399
- using SWTSectionList = SWTVector<std::tuple<HMODULE, const void *, size_t >> ;
400
- SWTSectionList sectionList ;
414
+ SWTSectionBoundsList<SWTTypeMetadataRecord> sectionBounds ;
415
+ sectionBounds. reserve (hModuleCount) ;
401
416
for (size_t i = 0 ; i < hModuleCount; i++) {
402
- if (auto section = findSection (hModules[i], " .sw5tymd" )) {
403
- sectionList. emplace_back (hModules[i], section-> first , section-> second );
417
+ if (auto sb = findSection (hModules[i], " .sw5tymd" )) {
418
+ sectionBounds. push_back (*sb );
404
419
}
405
420
}
406
421
407
- // Pass the loaded module and section info back to the body callback.
408
- // Note we ignore the leading and trailing uintptr_t values: they're both
422
+ // Pass each discovered section back to the body callback.
423
+ //
424
+ // NOTE: we ignore the leading and trailing uintptr_t values: they're both
409
425
// always set to zero so we'll skip them in the callback, and in the future
410
426
// the toolchain might not emit them at all in which case we don't want to
411
427
// skip over real section data.
412
428
bool stop = false ;
413
- for (const auto & section : sectionList) {
414
- // TODO: Use C++17 unstructured binding here.
415
- body (get<0 >(section), get<1 >(section), get<2 >(section), &stop);
429
+ for (const auto & sb : sectionBounds) {
430
+ body (sb, &stop);
416
431
if (stop) {
417
432
break ;
418
433
}
@@ -427,15 +442,19 @@ extern "C" const char __stop_swift5_type_metadata;
427
442
428
443
template <typename SectionEnumerator>
429
444
static void enumerateTypeMetadataSections (const SectionEnumerator& body) {
430
- const auto & sectionBegin = __start_swift5_type_metadata;
431
- const auto & sectionEnd = __stop_swift5_type_metadata;
432
-
433
445
// WASI only has a single image (so far) and it is statically linked, so all
434
446
// Swift metadata ends up in the same section bounded by the named symbols
435
447
// above. So we can just yield the section betwixt them.
436
- auto size = std::distance (§ionBegin, §ionEnd);
448
+ const auto & sectionBegin = __start_swift5_type_metadata;
449
+ const auto & sectionEnd = __stop_swift5_type_metadata;
450
+
451
+ SWTSectionBounds<SWTTypeMetadataRecord> sb = {
452
+ nullptr ,
453
+ §ionBegin,
454
+ static_cast <size_t >(std::distance (§ionBegin, §ionEnd))
455
+ };
437
456
bool stop = false ;
438
- body (nullptr , §ionBegin, size , &stop);
457
+ body (sb , &stop);
439
458
}
440
459
441
460
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__ANDROID__)
@@ -481,16 +500,20 @@ SWT_IMPORT_FROM_STDLIB void swift_enumerateAllMetadataSections(
481
500
template <typename SectionEnumerator>
482
501
static void enumerateTypeMetadataSections (const SectionEnumerator& body) {
483
502
swift_enumerateAllMetadataSections ([] (const MetadataSections *sections, void *context) {
503
+ bool stop = false ;
504
+
484
505
const auto & body = *reinterpret_cast <const SectionEnumerator *>(context);
485
506
MetadataSectionRange section = sections->swift5_type_metadata ;
486
507
if (section.start && section.length > 0 ) {
487
- bool stop = false ;
488
- body (sections->baseAddress .load (), reinterpret_cast <const void *>(section.start ), section.length , &stop);
489
- if (stop) {
490
- return false ;
491
- }
508
+ SWTSectionBounds<SWTTypeMetadataRecord> sb = {
509
+ sections->baseAddress .load (),
510
+ reinterpret_cast <const void *>(section.start ),
511
+ section.length
512
+ };
513
+ body (sb, &stop);
492
514
}
493
- return true ;
515
+
516
+ return !stop;
494
517
}, const_cast <SectionEnumerator *>(&body));
495
518
}
496
519
#else
@@ -502,13 +525,8 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {}
502
525
#pragma mark -
503
526
504
527
void swt_enumerateTypesWithNamesContaining (const char *nameSubstring, void *context, SWTTypeEnumerator body) {
505
- enumerateTypeMetadataSections ([=] (const void *imageAddress, const void *section, size_t size, bool *stop) {
506
- auto records = reinterpret_cast <const SWTTypeMetadataRecord *>(section);
507
- size_t recordCount = size / sizeof (SWTTypeMetadataRecord);
508
-
509
- for (size_t i = 0 ; i < recordCount && !*stop; i++) {
510
- const auto & record = records[i];
511
-
528
+ enumerateTypeMetadataSections ([=] (const SWTSectionBounds<SWTTypeMetadataRecord>& sectionBounds, bool *stop) {
529
+ for (const auto & record : sectionBounds) {
512
530
auto contextDescriptor = record.getContextDescriptor ();
513
531
if (!contextDescriptor) {
514
532
// This type metadata record is invalid (or we don't understand how to
@@ -529,7 +547,7 @@ void swt_enumerateTypesWithNamesContaining(const char *nameSubstring, void *cont
529
547
}
530
548
531
549
if (void *typeMetadata = contextDescriptor->getMetadata ()) {
532
- body (imageAddress, typeMetadata, stop, context);
550
+ body (sectionBounds. imageAddress , typeMetadata, stop, context);
533
551
}
534
552
}
535
553
});
0 commit comments