19
19
#if defined(__ELF__) || defined(__ANDROID__)
20
20
21
21
#include " ImageInspection.h"
22
+ #include " ../SwiftShims/Visibility.h"
23
+ #include < atomic>
22
24
#include < elf.h>
23
25
#include < link.h>
24
26
#include < dlfcn.h>
@@ -35,67 +37,124 @@ static const char ProtocolConformancesSymbol[] =
35
37
static const char TypeMetadataRecordsSymbol[] =
36
38
" .swift2_type_metadata_start" ;
37
39
40
+ static std::atomic<bool > didInitializeProtocolConformanceLookup;
41
+ static std::atomic<bool > didInitializeTypeMetadataLookup;
42
+
38
43
// / Context arguments passed down from dl_iterate_phdr to its callback.
39
44
struct InspectArgs {
40
45
// / Symbol name to look up.
41
46
const char *symbolName;
42
47
// / Callback function to invoke with the metadata block.
43
48
void (*addBlock)(const void *start, uintptr_t size);
49
+ // / Set to true when initialize*Lookup() is called.
50
+ std::atomic<bool > *didInitializeLookup;
44
51
};
45
52
46
- static int iteratePHDRCallback (struct dl_phdr_info *info,
47
- size_t size, void *data) {
48
- const InspectArgs *inspectArgs = reinterpret_cast <const InspectArgs *>(data);
49
- void *handle;
50
- if (!info->dlpi_name || info->dlpi_name [0 ] == ' \0 ' ) {
51
- handle = dlopen (nullptr , RTLD_LAZY);
52
- } else {
53
- handle = dlopen (info->dlpi_name , RTLD_LAZY | RTLD_NOLOAD);
54
- }
53
+ static InspectArgs ProtocolConformanceArgs = {
54
+ ProtocolConformancesSymbol,
55
+ addImageProtocolConformanceBlockCallback,
56
+ &didInitializeProtocolConformanceLookup
57
+ };
55
58
56
- if (!handle) {
57
- // Not a shared library.
58
- return 0 ;
59
- }
59
+ static InspectArgs TypeMetadataRecordArgs = {
60
+ TypeMetadataRecordsSymbol,
61
+ addImageTypeMetadataRecordBlockCallback,
62
+ &didInitializeTypeMetadataLookup
63
+ };
60
64
61
- const char *conformances =
62
- reinterpret_cast <const char *>(dlsym (handle, inspectArgs->symbolName ));
63
65
64
- if (!conformances) {
65
- // if there are no conformances, don't hold this handle open.
66
+ // Extract the section information for a named section in an image. imageName
67
+ // can be nullptr to specify the main executable.
68
+ static SectionInfo getSectionInfo (const char *imageName,
69
+ const char *sectionName) {
70
+ SectionInfo sectionInfo = { 0 , nullptr };
71
+ void *handle = dlopen (imageName, RTLD_LAZY);
72
+ if (handle) {
73
+ void *symbol = dlsym (handle, sectionName);
74
+ if (symbol) {
75
+ // Extract the size of the section data from the head of the section.
76
+ const char *section = reinterpret_cast <const char *>(symbol);
77
+ memcpy (§ionInfo.size , section, sizeof (uint64_t ));
78
+ sectionInfo.data = section + sizeof (uint64_t );
79
+ }
66
80
dlclose (handle);
81
+ }
82
+ return sectionInfo;
83
+ }
84
+
85
+ static int iteratePHDRCallback (struct dl_phdr_info *info,
86
+ size_t size, void *data) {
87
+ const InspectArgs *inspectArgs = reinterpret_cast <const InspectArgs *>(data);
88
+ const char *fname = info->dlpi_name ;
89
+
90
+ // While dl_iterate_phdr() is in progress it holds a lock to prevent other
91
+ // images being loaded. The initialize flag is set here inside the callback so
92
+ // that addNewDSOImage() sees a consistent state. If it was set outside the
93
+ // dl_interate_phdr() call then it could result in images being missed or
94
+ // added twice.
95
+ inspectArgs->didInitializeLookup ->store (true , std::memory_order_release);
96
+
97
+ if (fname == nullptr || fname[0 ] == ' \0 ' ) {
98
+ // The filename may be null for both the dynamic loader and main executable.
99
+ // So ignore null image name here and explictly add the main executable
100
+ // in initialize*Lookup() to avoid adding the data twice.
67
101
return 0 ;
68
102
}
69
103
70
- // Extract the size of the conformances block from the head of the section.
71
- uint64_t conformancesSize;
72
- memcpy (&conformancesSize, conformances, sizeof (conformancesSize));
73
- conformances += sizeof (conformancesSize);
104
+ SectionInfo block = getSectionInfo (fname, inspectArgs->symbolName );
105
+ if (block.size > 0 ) {
106
+ inspectArgs->addBlock (block.data , block.size );
107
+ }
108
+ return 0 ;
109
+ }
74
110
75
- inspectArgs->addBlock (conformances, conformancesSize);
111
+ // Add the section information in an image specified by an address in that
112
+ // image.
113
+ static void addBlockInImage (const InspectArgs *inspectArgs, const void *addr) {
114
+ const char *fname = nullptr ;
115
+ if (addr) {
116
+ Dl_info info;
117
+ if (dladdr (addr, &info) == 0 || info.dli_fname == nullptr ) {
118
+ return ;
119
+ }
120
+ fname = info.dli_fname ;
121
+ }
122
+ SectionInfo block = getSectionInfo (fname, inspectArgs->symbolName );
123
+ if (block.size > 0 ) {
124
+ inspectArgs->addBlock (block.data , block.size );
125
+ }
126
+ }
76
127
77
- dlclose (handle);
78
- return 0 ;
128
+ static void initializeSectionLookup (InspectArgs *inspectArgs) {
129
+ // Add section data in the main executable.
130
+ addBlockInImage (inspectArgs, nullptr );
131
+ // Search the loaded dls. This only searches the already
132
+ // loaded ones. Any images loaded after this are processed by
133
+ // addNewDSOImage() below.
134
+ dl_iterate_phdr (iteratePHDRCallback, reinterpret_cast <void *>(inspectArgs));
79
135
}
80
136
81
137
void swift::initializeProtocolConformanceLookup () {
82
- // Search the loaded dls. This only searches the already
83
- // loaded ones.
84
- // FIXME: Find a way to have this continue to happen for dlopen-ed images.
85
- // rdar://problem/19045112
86
- InspectArgs ProtocolConformanceArgs = {
87
- ProtocolConformancesSymbol,
88
- addImageProtocolConformanceBlockCallback
89
- };
90
- dl_iterate_phdr (iteratePHDRCallback, &ProtocolConformanceArgs);
138
+ initializeSectionLookup (&ProtocolConformanceArgs);
91
139
}
92
140
93
141
void swift::initializeTypeMetadataRecordLookup () {
94
- InspectArgs TypeMetadataRecordArgs = {
95
- TypeMetadataRecordsSymbol,
96
- addImageTypeMetadataRecordBlockCallback
97
- };
98
- dl_iterate_phdr (iteratePHDRCallback, &TypeMetadataRecordArgs);
142
+ initializeSectionLookup (&TypeMetadataRecordArgs);
143
+ }
144
+
145
+ // As ELF images are loaded, ImageInspectionInit:sectionDataInit() will call
146
+ // addNewDSOImage() with an address in the image that can later be used via
147
+ // dladdr() to dlopen() the image after the appropiate initialize*Lookup()
148
+ // function has been called.
149
+ SWIFT_RUNTIME_EXPORT
150
+ void swift::addNewDSOImage (const void *addr) {
151
+ if (didInitializeProtocolConformanceLookup.load (std::memory_order_acquire)) {
152
+ addBlockInImage (&ProtocolConformanceArgs, addr);
153
+ }
154
+
155
+ if (didInitializeTypeMetadataLookup.load (std::memory_order_acquire)) {
156
+ addBlockInImage (&TypeMetadataRecordArgs, addr);
157
+ }
99
158
}
100
159
101
160
int swift::lookupSymbol (const void *address, SymbolInfo *info) {
0 commit comments