1010
1111#include " Discovery.h"
1212
13+ #include < algorithm>
14+ #include < array>
1315#include < atomic>
1416#include < cstring>
1517#include < iterator>
18+ #include < tuple>
1619#include < type_traits>
1720#include < vector>
21+ #include < optional>
1822
19- #if defined(SWT_NO_DYNAMIC_LINKING)
20- #include < algorithm>
21- #elif defined(__APPLE__)
23+ #if defined(__APPLE__) && !defined(SWT_NO_DYNAMIC_LINKING)
2224#include < dispatch/dispatch.h>
2325#include < mach-o/dyld.h>
2426#include < mach-o/getsect.h>
2527#include < objc/runtime.h>
2628#include < os/lock.h>
2729#endif
2830
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+
2956// / Enumerate over all Swift type metadata sections in the current process.
3057// /
3158// / - Parameters:
@@ -199,39 +226,19 @@ extern "C" const char sectionEnd __asm("section$end$__TEXT$__swift5_types");
199226template <typename SectionEnumerator>
200227static void enumerateTypeMetadataSections (const SectionEnumerator& body) {
201228 auto size = std::distance (§ionBegin, §ionEnd);
202- body (§ionBegin, size);
229+ bool stop = false ;
230+ body (nullptr , §ionBegin, size, &stop);
203231}
204232
205233#elif defined(__APPLE__)
206234#pragma mark - Apple implementation
207235
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-
229236// / A type that acts as a C++ [Container](https://en.cppreference.com/w/cpp/named_req/Container)
230237// / and which contains a sequence of Mach headers.
231238#if __LP64__
232- using SWTMachHeaderList = std::vector <const mach_header_64 *, SWTHeapAllocator< const mach_header_64 *> >;
239+ using SWTMachHeaderList = SWTVector <const mach_header_64 *>;
233240#else
234- using SWTMachHeaderList = std::vector <const mach_header *, SWTHeapAllocator< const mach_header *> >;
241+ using SWTMachHeaderList = SWTVector <const mach_header *>;
235242#endif
236243
237244// / Get a copy of the currently-loaded Mach headers list.
@@ -301,13 +308,118 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {
301308 unsigned long size = 0 ;
302309 const void *section = getsectiondata (mh, SEG_TEXT, " __swift5_types" , &size);
303310 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 ;
305416 }
306417 }
307418}
308419
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
311423
312424// / Specifies the address range corresponding to a section.
313425struct MetadataSectionRange {
@@ -352,7 +464,11 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {
352464 const auto & body = *reinterpret_cast <const SectionEnumerator *>(context);
353465 MetadataSectionRange section = sections->swift5_type_metadata ;
354466 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+ }
356472 }
357473 return true ;
358474 }, const_cast <SectionEnumerator *>(&body));
@@ -366,12 +482,11 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) {}
366482#pragma mark -
367483
368484void 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 ) {
370486 auto records = reinterpret_cast <const SWTTypeMetadataRecord *>(section);
371487 size_t recordCount = size / sizeof (SWTTypeMetadataRecord);
372488
373- bool stop = false ;
374- for (size_t i = 0 ; i < recordCount && !stop; i++) {
489+ for (size_t i = 0 ; i < recordCount && !*stop; i++) {
375490 const auto & record = records[i];
376491
377492 auto contextDescriptor = record.getContextDescriptor ();
@@ -394,7 +509,7 @@ void swt_enumerateTypesWithNamesContaining(const char *nameSubstring, void *cont
394509 }
395510
396511 if (void *typeMetadata = contextDescriptor->getMetadata ()) {
397- body (typeMetadata, & stop, context);
512+ body (imageAddress, typeMetadata, stop, context);
398513 }
399514 }
400515 });
0 commit comments