10
10
11
11
#include " Discovery.h"
12
12
13
+ #include < algorithm>
14
+ #include < array>
13
15
#include < atomic>
14
16
#include < cstring>
15
17
#include < iterator>
18
+ #include < tuple>
16
19
#include < type_traits>
17
20
#include < vector>
21
+ #include < optional>
18
22
19
- #if defined(SWT_NO_DYNAMIC_LINKING)
20
- #include < algorithm>
21
- #elif defined(__APPLE__)
23
+ #if defined(__APPLE__) && !defined(SWT_NO_DYNAMIC_LINKING)
22
24
#include < dispatch/dispatch.h>
23
25
#include < mach-o/dyld.h>
24
26
#include < mach-o/getsect.h>
25
27
#include < objc/runtime.h>
26
28
#include < os/lock.h>
27
29
#endif
28
30
31
+ // / A type that acts as a C++ [Allocator](https://en.cppreference.com/w/cpp/named_req/Allocator)
32
+ // / without using global `operator new` or `operator delete`.
33
+ // /
34
+ // / This type is necessary because global `operator new` and `operator delete`
35
+ // / can be overridden in developer-supplied code and cause deadlocks or crashes
36
+ // / when subsequently used while holding a dyld- or libobjc-owned lock. Using
37
+ // / `std::malloc()` and `std::free()` allows the use of C++ container types
38
+ // / without this risk.
39
+ template <typename T>
40
+ struct SWTHeapAllocator {
41
+ using value_type = T;
42
+
43
+ T *allocate (size_t count) {
44
+ return reinterpret_cast <T *>(std::calloc (count, sizeof (T)));
45
+ }
46
+
47
+ void deallocate (T *ptr, size_t count) {
48
+ std::free (ptr);
49
+ }
50
+ };
51
+
52
+ // / A `std::vector` that uses `SWTHeapAllocator`.
53
+ template <typename T>
54
+ using SWTVector = std::vector<T, SWTHeapAllocator<T>>;
55
+
29
56
// / Enumerate over all Swift type metadata sections in the current process.
30
57
// /
31
58
// / - Parameters:
@@ -199,39 +226,19 @@ extern "C" const char sectionEnd __asm("section$end$__TEXT$__swift5_types");
199
226
template <typename SectionEnumerator>
200
227
static void enumerateTypeMetadataSections (const SectionEnumerator& body) {
201
228
auto size = std::distance (§ionBegin, §ionEnd);
202
- body (§ionBegin, size);
229
+ bool stop = false ;
230
+ body (nullptr , §ionBegin, size, &stop);
203
231
}
204
232
205
233
#elif defined(__APPLE__)
206
234
#pragma mark - Apple implementation
207
235
208
- // / A type that acts as a C++ [Allocator](https://en.cppreference.com/w/cpp/named_req/Allocator)
209
- // / without using global `operator new` or `operator delete`.
210
- // /
211
- // / This type is necessary because global `operator new` and `operator delete`
212
- // / can be overridden in developer-supplied code and cause deadlocks or crashes
213
- // / when subsequently used while holding a dyld- or libobjc-owned lock. Using
214
- // / `std::malloc()` and `std::free()` allows the use of C++ container types
215
- // / without this risk.
216
- template <typename T>
217
- struct SWTHeapAllocator {
218
- using value_type = T;
219
-
220
- T *allocate (size_t count) {
221
- return reinterpret_cast <T *>(std::calloc (count, sizeof (T)));
222
- }
223
-
224
- void deallocate (T *ptr, size_t count) {
225
- std::free (ptr);
226
- }
227
- };
228
-
229
236
// / A type that acts as a C++ [Container](https://en.cppreference.com/w/cpp/named_req/Container)
230
237
// / and which contains a sequence of Mach headers.
231
238
#if __LP64__
232
- using SWTMachHeaderList = std::vector <const mach_header_64 *, SWTHeapAllocator< const mach_header_64 *> >;
239
+ using SWTMachHeaderList = SWTVector <const mach_header_64 *>;
233
240
#else
234
- using SWTMachHeaderList = std::vector <const mach_header *, SWTHeapAllocator< const mach_header *> >;
241
+ using SWTMachHeaderList = SWTVector <const mach_header *>;
235
242
#endif
236
243
237
244
// / Get a copy of the currently-loaded Mach headers list.
@@ -301,13 +308,118 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {
301
308
unsigned long size = 0 ;
302
309
const void *section = getsectiondata (mh, SEG_TEXT, " __swift5_types" , &size);
303
310
if (section && size > 0 ) {
304
- body (section, size);
311
+ bool stop = false ;
312
+ body (mh, section, size, &stop);
313
+ if (stop) {
314
+ break ;
315
+ }
316
+ }
317
+ }
318
+ }
319
+
320
+ #elif defined(_WIN32)
321
+ #pragma mark - Windows implementation
322
+
323
+ // / Find the section with the given name in the given module.
324
+ // /
325
+ // / - Parameters:
326
+ // / - module: The module to inspect.
327
+ // / - sectionName: The name of the section to look for. Long section names are
328
+ // / not supported.
329
+ // /
330
+ // / - Returns: A pointer to the start of the given section along with its size
331
+ // / in bytes, or `std::nullopt` if the section could not be found. If the
332
+ // / section was emitted by the Swift toolchain, be aware it will have leading
333
+ // / and trailing bytes (`sizeof(uintptr_t)` each.)
334
+ static std::optional<std::pair<const void *, size_t >> findSection (HMODULE module, const char *sectionName) {
335
+ if (!module) {
336
+ return std::nullopt;
337
+ }
338
+
339
+ // Get the DOS header (to which the HMODULE directly points, conveniently!)
340
+ // and check it's sufficiently valid for us to walk.
341
+ auto dosHeader = reinterpret_cast <const PIMAGE_DOS_HEADER>(module);
342
+ if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE || dosHeader->e_lfanew <= 0 ) {
343
+ return std::nullopt;
344
+ }
345
+
346
+ // Check the NT header as well as the optional header.
347
+ auto ntHeader = reinterpret_cast <const PIMAGE_NT_HEADERS>(reinterpret_cast <uintptr_t >(dosHeader) + dosHeader->e_lfanew );
348
+ if (!ntHeader || ntHeader->Signature != IMAGE_NT_SIGNATURE) {
349
+ return std::nullopt;
350
+ }
351
+ if (ntHeader->FileHeader .SizeOfOptionalHeader < offsetof (decltype (ntHeader->OptionalHeader ), Magic) + sizeof (decltype (ntHeader->OptionalHeader )::Magic)) {
352
+ return std::nullopt;
353
+ }
354
+ if (ntHeader->OptionalHeader .Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) {
355
+ return std::nullopt;
356
+ }
357
+
358
+ auto sectionCount = ntHeader->FileHeader .NumberOfSections ;
359
+ auto section = IMAGE_FIRST_SECTION (ntHeader);
360
+ for (size_t i = 0 ; i < sectionCount; i++, section += 1 ) {
361
+ if (section->VirtualAddress == 0 ) {
362
+ continue ;
363
+ }
364
+
365
+ auto start = reinterpret_cast <const void *>(reinterpret_cast <uintptr_t >(dosHeader) + section->VirtualAddress );
366
+ size_t size = std::min (section->Misc .VirtualSize , section->SizeOfRawData );
367
+ if (start && size > 0 ) {
368
+ // FIXME: Handle longer names ("/%u") from string table
369
+ auto thisSectionName = reinterpret_cast <const char *>(section->Name );
370
+ if (0 == std::strncmp (sectionName, thisSectionName, IMAGE_SIZEOF_SHORT_NAME)) {
371
+ return std::make_pair (start, size);
372
+ }
373
+ }
374
+ }
375
+
376
+ return std::nullopt;
377
+ }
378
+
379
+ template <typename SectionEnumerator>
380
+ static void enumerateTypeMetadataSections (const SectionEnumerator& body) {
381
+ // Find all the modules loaded in the current process. We assume there aren't
382
+ // more than 1024 loaded modules (as does Microsoft sample code.)
383
+ std::array<HMODULE, 1024 > hModules;
384
+ DWORD byteCountNeeded = 0 ;
385
+ if (!EnumProcessModules (GetCurrentProcess (), &hModules[0 ], hModules.size () * sizeof (HMODULE), &byteCountNeeded)) {
386
+ return ;
387
+ }
388
+ DWORD hModuleCount = std::min (hModules.size (), byteCountNeeded / sizeof (HMODULE));
389
+
390
+ // Look in all the loaded modules for Swift type metadata sections and store
391
+ // them in a side table.
392
+ //
393
+ // This two-step process is less algorithmically efficient than a single loop,
394
+ // but it is safer: the callback will eventually invoke developer code that
395
+ // could theoretically unload a module from the list we're enumerating. (Swift
396
+ // modules do not support unloading, so we'll just not worry about them.)
397
+ using SWTSectionList = SWTVector<std::tuple<HMODULE, const void *, size_t >>;
398
+ SWTSectionList sectionList;
399
+ for (DWORD i = 0 ; i < hModuleCount; i++) {
400
+ if (auto section = findSection (hModules[i], " .sw5tymd" )) {
401
+ sectionList.emplace_back (hModules[i], section->first , section->second );
402
+ }
403
+ }
404
+
405
+ // Pass the loaded module and section info back to the body callback.
406
+ // Note we ignore the leading and trailing uintptr_t values: they're both
407
+ // always set to zero so we'll skip them in the callback, and in the future
408
+ // the toolchain might not emit them at all in which case we don't want to
409
+ // skip over real section data.
410
+ bool stop = false ;
411
+ for (const auto & section : sectionList) {
412
+ // TODO: Use C++17 unstructured binding here.
413
+ body (get<0 >(section), get<1 >(section), get<2 >(section), &stop);
414
+ if (stop) {
415
+ break ;
305
416
}
306
417
}
307
418
}
308
419
309
- #elif defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32) || defined(__wasi__) || defined(__ANDROID__)
310
- #pragma mark - Linux/Windows implementation
420
+
421
+ #elif defined(__linux__) || defined(__FreeBSD__) || defined(__wasi__) || defined(__ANDROID__)
422
+ #pragma mark - ELF implementation
311
423
312
424
// / Specifies the address range corresponding to a section.
313
425
struct MetadataSectionRange {
@@ -352,7 +464,11 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {
352
464
const auto & body = *reinterpret_cast <const SectionEnumerator *>(context);
353
465
MetadataSectionRange section = sections->swift5_type_metadata ;
354
466
if (section.start && section.length > 0 ) {
355
- body (reinterpret_cast <const void *>(section.start ), section.length );
467
+ bool stop = false ;
468
+ body (sections->baseAddress .load (), reinterpret_cast <const void *>(section.start ), section.length , &stop);
469
+ if (stop) {
470
+ return false ;
471
+ }
356
472
}
357
473
return true ;
358
474
}, const_cast <SectionEnumerator *>(&body));
@@ -366,12 +482,11 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {}
366
482
#pragma mark -
367
483
368
484
void swt_enumerateTypesWithNamesContaining (const char *nameSubstring, void *context, SWTTypeEnumerator body) {
369
- enumerateTypeMetadataSections ([=] (const void *section, size_t size) {
485
+ enumerateTypeMetadataSections ([=] (const void *imageAddress, const void * section, size_t size, bool *stop ) {
370
486
auto records = reinterpret_cast <const SWTTypeMetadataRecord *>(section);
371
487
size_t recordCount = size / sizeof (SWTTypeMetadataRecord);
372
488
373
- bool stop = false ;
374
- for (size_t i = 0 ; i < recordCount && !stop; i++) {
489
+ for (size_t i = 0 ; i < recordCount && !*stop; i++) {
375
490
const auto & record = records[i];
376
491
377
492
auto contextDescriptor = record.getContextDescriptor ();
@@ -394,7 +509,7 @@ void swt_enumerateTypesWithNamesContaining(const char *nameSubstring, void *cont
394
509
}
395
510
396
511
if (void *typeMetadata = contextDescriptor->getMetadata ()) {
397
- body (typeMetadata, & stop, context);
512
+ body (imageAddress, typeMetadata, stop, context);
398
513
}
399
514
}
400
515
});
0 commit comments