24
24
#include " ../SwiftShims/Visibility.h"
25
25
#include " ../SwiftShims/MetadataSections.h"
26
26
#include " ImageInspection.h"
27
+ #include " swift/Basic/Lazy.h"
28
+ #include " swift/Runtime/Concurrent.h"
27
29
30
+ #include < algorithm>
31
+ #include < atomic>
32
+ #include < cstdlib>
28
33
29
34
namespace swift {
30
35
31
- #ifndef NDEBUG
32
- static swift::MetadataSections *registered = nullptr ;
36
+ static Lazy<ConcurrentReadableArray<swift::MetadataSections *>> registered;
33
37
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 ;
62
48
63
- #ifndef NDEBUG
64
49
#if defined(__ELF__)
65
50
// If the base address was set but the image is an ELF image, it is going to
66
51
// 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 ;
74
61
}
75
- #endif
76
62
#endif
77
63
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
+ }
79
73
}
80
74
}
81
75
82
76
SWIFT_RUNTIME_EXPORT
83
77
void 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);
86
90
#endif
87
-
88
- auto baseAddress = swift::getMetadataSectionBaseAddress (sections);
91
+ auto baseAddress = sections->baseAddress .load (std::memory_order_relaxed);
89
92
90
93
const auto &protocols_section = sections->swift5_protocols ;
91
94
const void *protocols = reinterpret_cast <void *>(protocols_section.start );
@@ -125,6 +128,29 @@ void swift_addNewDSOImage(swift::MetadataSections *sections) {
125
128
if (accessible_funcs_section.length )
126
129
swift::addImageAccessibleFunctionsBlockCallback (
127
130
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
+ }
128
154
}
129
155
130
156
void swift::initializeProtocolLookup () {
@@ -146,19 +172,19 @@ void swift::initializeAccessibleFunctionsLookup() {
146
172
147
173
SWIFT_RUNTIME_EXPORT
148
174
const 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];
151
180
}
152
181
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);
160
185
}
161
- return selected;
186
+
187
+ return result;
162
188
}
163
189
164
190
SWIFT_RUNTIME_EXPORT
@@ -184,19 +210,16 @@ void swift_getMetadataSectionBaseAddress(const swift::MetadataSections *section,
184
210
*out_actual = nullptr ;
185
211
}
186
212
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);
188
217
}
189
218
190
219
SWIFT_RUNTIME_EXPORT
191
220
size_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 ();
200
223
}
201
224
202
225
#endif // NDEBUG
0 commit comments