2424#include " ../SwiftShims/Visibility.h"
2525#include " ../SwiftShims/MetadataSections.h"
2626#include " ImageInspection.h"
27+ #include " swift/Basic/Lazy.h"
28+ #include " swift/Runtime/Concurrent.h"
2729
30+ #include < algorithm>
31+ #include < atomic>
32+ #include < cstdlib>
2833
2934namespace swift {
3035
31- #ifndef NDEBUG
32- static swift::MetadataSections *registered = nullptr ;
36+ static Lazy<ConcurrentReadableArray<swift::MetadataSections *>> registered;
3337
34- static void record (swift::MetadataSections *sections) {
35- if (registered == nullptr ) {
36- registered = sections;
37- sections->next = sections->prev = sections;
38- } else {
39- registered->prev ->next = sections;
40- sections->next = registered;
41- sections->prev = registered->prev ;
42- registered->prev = sections;
43- }
44- }
45- #endif
46-
47- static const void *
48- getMetadataSectionBaseAddress (swift::MetadataSections *sections) {
49- // If the base address was not set by the caller of swift_addNewDSOImage()
50- // then we can assume that the caller was built against an older version of
51- // the runtime that did not capture a value for this field. Currently nothing
52- // is actively using the image's base address outside of tests that are built
53- // with the runtime/stdlib, so there's no need to try to fix up the value. If
54- // something in the runtime starts using it, we will want to either:
55- // 1. Resolve the address from a known-good address like swift5_protocols when
56- // the image is first loaded (in this function);
57- // 1. Resolve the address from a known-good address like swift5_protocols when
58- // the address is first used (and atomically swap the address back so we
59- // don't incur the cost of lookupSymbol() each time we need it; or
60- // 3. Introduce an ABI-breaking change so that all binaries are rebuilt and
61- // start supplying a value for this field.
38+ // / Adjust the \c baseAddress field of a metadata sections structure.
39+ // /
40+ // / \param sections A pointer to a valid \c swift::MetadataSections structure.
41+ // /
42+ // / This function should be called at least once before the structure or its
43+ // / address is passed to code outside this file to ensure that the structure's
44+ // / \c baseAddress field correctly points to the base address of the image it
45+ // / is describing.
46+ static void fixupMetadataSectionBaseAddress (swift::MetadataSections *sections) {
47+ bool fixupNeeded = false ;
6248
63- #ifndef NDEBUG
6449#if defined(__ELF__)
6550 // If the base address was set but the image is an ELF image, it is going to
6651 // be __dso_handle which is not the value we expect (Dl_info::dli_fbase), so
67- // we need to fix it up. Since the base address is currently unused by the
68- // runtime outside tests, we don't normally do this work.
69- if (auto baseAddress = sections->baseAddress ) {
70- swift::SymbolInfo symbolInfo;
71- if (lookupSymbol (baseAddress, &symbolInfo) && symbolInfo.baseAddress ) {
72- sections->baseAddress = symbolInfo.baseAddress ;
73- }
52+ // we need to fix it up.
53+ fixupNeeded = true ;
54+ #elif !defined(__MACH__)
55+ // For non-ELF, non-Apple platforms, if the base address is nullptr, it
56+ // implies that this image was built against an older version of the runtime
57+ // that did not capture any value for the base address.
58+ auto oldBaseAddress = sections->baseAddress .load (std::memory_order_relaxed);
59+ if (!oldBaseAddress) {
60+ fixupNeeded = true ;
7461 }
75- #endif
7662#endif
7763
78- return sections->baseAddress ;
64+ if (fixupNeeded) {
65+ // We need to fix up the base address. We'll need a known-good address in
66+ // the same image: `sections` itself will work nicely.
67+ swift::SymbolInfo symbolInfo;
68+ if (lookupSymbol (sections, &symbolInfo) && symbolInfo.baseAddress ) {
69+ sections->baseAddress .store (symbolInfo.baseAddress ,
70+ std::memory_order_relaxed);
71+ }
72+ }
7973}
8074}
8175
8276SWIFT_RUNTIME_EXPORT
8377void swift_addNewDSOImage (swift::MetadataSections *sections) {
84- #ifndef NDEBUG
85- record (sections);
78+ #if 0
79+ // Ensure the base address of the sections structure is correct.
80+ //
81+ // Currently disabled because none of the registration functions below
82+ // actually do anything with the baseAddress field. Instead,
83+ // swift_enumerateAllMetadataSections() is called by other individual
84+ // functions, lower in this file, that yield metadata section pointers.
85+ //
86+ // If one of these registration functions starts needing the baseAddress
87+ // field, this call should be enabled and the calls elsewhere in the file can
88+ // be removed.
89+ swift::fixupMetadataSectionBaseAddress(sections);
8690#endif
87-
88- auto baseAddress = swift::getMetadataSectionBaseAddress (sections);
91+ auto baseAddress = sections->baseAddress .load (std::memory_order_relaxed);
8992
9093 const auto &protocols_section = sections->swift5_protocols ;
9194 const void *protocols = reinterpret_cast <void *>(protocols_section.start );
@@ -125,6 +128,29 @@ void swift_addNewDSOImage(swift::MetadataSections *sections) {
125128 if (accessible_funcs_section.length )
126129 swift::addImageAccessibleFunctionsBlockCallback (
127130 baseAddress, functions, accessible_funcs_section.length );
131+
132+ // Register this section for future enumeration by clients. This should occur
133+ // after this function has done all other relevant work to avoid a race
134+ // condition when someone calls swift_enumerateAllMetadataSections() on
135+ // another thread.
136+ swift::registered->push_back (sections);
137+ }
138+
139+ SWIFT_RUNTIME_EXPORT
140+ void swift_enumerateAllMetadataSections (
141+ bool (* body)(const swift::MetadataSections *sections, void *context),
142+ void *context
143+ ) {
144+ auto snapshot = swift::registered->snapshot ();
145+ for (swift::MetadataSections *sections : snapshot) {
146+ // Ensure the base address is fixed up before yielding the pointer.
147+ swift::fixupMetadataSectionBaseAddress (sections);
148+
149+ // Yield the pointer and (if the callback returns false) break the loop.
150+ if (!(* body)(sections, context)) {
151+ return ;
152+ }
153+ }
128154}
129155
130156void swift::initializeProtocolLookup () {
@@ -146,19 +172,19 @@ void swift::initializeAccessibleFunctionsLookup() {
146172
147173SWIFT_RUNTIME_EXPORT
148174const swift::MetadataSections *swift_getMetadataSection (size_t index) {
149- if (swift::registered == nullptr ) {
150- return nullptr ;
175+ swift::MetadataSections *result = nullptr ;
176+
177+ auto snapshot = swift::registered->snapshot ();
178+ if (index < snapshot.count ()) {
179+ result = snapshot[index];
151180 }
152181
153- auto selected = swift::registered;
154- while (index > 0 ) {
155- selected = selected->next ;
156- if (selected == swift::registered) {
157- return nullptr ;
158- }
159- --index;
182+ if (result) {
183+ // Ensure the base address is fixed up before returning it.
184+ swift::fixupMetadataSectionBaseAddress (result);
160185 }
161- return selected;
186+
187+ return result;
162188}
163189
164190SWIFT_RUNTIME_EXPORT
@@ -184,19 +210,16 @@ void swift_getMetadataSectionBaseAddress(const swift::MetadataSections *section,
184210 *out_actual = nullptr ;
185211 }
186212
187- *out_expected = section->baseAddress ;
213+ // fixupMetadataSectionBaseAddress() was already called by
214+ // swift_getMetadataSection(), presumably on the same thread, so we don't need
215+ // to call it again here.
216+ *out_expected = section->baseAddress .load (std::memory_order_relaxed);
188217}
189218
190219SWIFT_RUNTIME_EXPORT
191220size_t swift_getMetadataSectionCount () {
192- if (swift::registered == nullptr )
193- return 0 ;
194-
195- size_t count = 1 ;
196- for (const auto *current = swift::registered->next ;
197- current != swift::registered; current = current->next , ++count);
198-
199- return count;
221+ auto snapshot = swift::registered->snapshot ();
222+ return snapshot.count ();
200223}
201224
202225#endif // NDEBUG
0 commit comments