12
12
13
13
#include " llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
14
14
#include " llvm/ADT/StringSwitch.h"
15
+ #include " llvm/Object/Archive.h"
15
16
#include " llvm/Object/COFF.h"
16
17
#include " llvm/Object/COFFImportFile.h"
17
18
#include " llvm/Object/COFFModuleDefinition.h"
@@ -158,6 +159,143 @@ bool parseModuleDefinition(StringRef DefFileName, MachineTypes Machine,
158
159
return true ;
159
160
}
160
161
162
+ int printError (llvm::Error E, Twine File) {
163
+ if (!E)
164
+ return 0 ;
165
+ handleAllErrors (std::move (E), [&](const llvm::ErrorInfoBase &EIB) {
166
+ llvm::errs () << " error opening " << File << " : " << EIB.message () << " \n " ;
167
+ });
168
+ return 1 ;
169
+ }
170
+
171
+ template <typename Callable>
172
+ int forEachCoff (object::Archive &Archive, StringRef Name, Callable Callback) {
173
+ Error Err = Error::success ();
174
+ for (auto &C : Archive.children (Err)) {
175
+ Expected<StringRef> NameOrErr = C.getName ();
176
+ if (!NameOrErr)
177
+ return printError (NameOrErr.takeError (), Name);
178
+ StringRef Name = *NameOrErr;
179
+
180
+ Expected<MemoryBufferRef> ChildMB = C.getMemoryBufferRef ();
181
+ if (!ChildMB)
182
+ return printError (ChildMB.takeError (), Name);
183
+
184
+ if (identify_magic (ChildMB->getBuffer ()) == file_magic::coff_object) {
185
+ auto Obj = object::COFFObjectFile::create (*ChildMB);
186
+ if (!Obj)
187
+ return printError (Obj.takeError (), Name);
188
+ if (!Callback (*Obj->get (), Name))
189
+ return 1 ;
190
+ }
191
+ }
192
+ if (Err)
193
+ return printError (std::move (Err), Name);
194
+ return 0 ;
195
+ }
196
+
197
+ // To find the named of the imported DLL from an import library, we can either
198
+ // inspect the object files that form the import table entries, or we could
199
+ // just look at the archive member names, for MSVC style import libraries.
200
+ // Looking at the archive member names doesn't work for GNU style import
201
+ // libraries though, while inspecting the import table entries works for
202
+ // both. (MSVC style import libraries contain a couple regular object files
203
+ // for the header/trailers.)
204
+ //
205
+ // This implementation does the same as GNU dlltool does; look at the
206
+ // content of ".idata$7" sections, or for MSVC style libraries, look
207
+ // at ".idata$6" sections.
208
+ //
209
+ // For GNU style import libraries, there are also other data chunks in sections
210
+ // named ".idata$7" (entries to the IAT or ILT); these are distinguished
211
+ // by seeing that they contain relocations. (They also look like an empty
212
+ // string when looking for null termination.)
213
+ //
214
+ // Alternatively, we could do things differently - look for any .idata$2
215
+ // section; this would be import directory entries. At offset 0xc in them
216
+ // there is the RVA of the import DLL name; look for a relocation at this
217
+ // spot and locate the symbol that it points at. That symbol may either
218
+ // be within the same object file (in the case of MSVC style import libraries)
219
+ // or another object file (in the case of GNU import libraries).
220
+ bool identifyImportName (const COFFObjectFile &Obj, StringRef ObjName,
221
+ std::vector<StringRef> &Names, bool IsMsStyleImplib) {
222
+ StringRef TargetName = IsMsStyleImplib ? " .idata$6" : " .idata$7" ;
223
+ for (const auto &S : Obj.sections ()) {
224
+ Expected<StringRef> NameOrErr = S.getName ();
225
+ if (!NameOrErr) {
226
+ printError (NameOrErr.takeError (), ObjName);
227
+ return false ;
228
+ }
229
+ StringRef Name = *NameOrErr;
230
+ if (Name != TargetName)
231
+ continue ;
232
+
233
+ // GNU import libraries contain .idata$7 section in the per function
234
+ // objects too, but they contain relocations.
235
+ if (!IsMsStyleImplib && !S.relocations ().empty ())
236
+ continue ;
237
+
238
+ Expected<StringRef> ContentsOrErr = S.getContents ();
239
+ if (!ContentsOrErr) {
240
+ printError (ContentsOrErr.takeError (), ObjName);
241
+ return false ;
242
+ }
243
+ StringRef Contents = *ContentsOrErr;
244
+ Contents = Contents.substr (0 , Contents.find (' \0 ' ));
245
+ if (Contents.empty ())
246
+ continue ;
247
+ Names.push_back (Contents);
248
+ return true ;
249
+ }
250
+ return true ;
251
+ }
252
+
253
+ int doIdentify (StringRef File, bool IdentifyStrict) {
254
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MaybeBuf = MemoryBuffer::getFile (
255
+ File, /* IsText=*/ false , /* RequiredNullTerminator=*/ false );
256
+ if (!MaybeBuf)
257
+ return printError (errorCodeToError (MaybeBuf.getError ()), File);
258
+ if (identify_magic (MaybeBuf.get ()->getBuffer ()) != file_magic::archive) {
259
+ llvm::errs () << File << " is not a library\n " ;
260
+ return 1 ;
261
+ }
262
+
263
+ std::unique_ptr<MemoryBuffer> B = std::move (MaybeBuf.get ());
264
+ Error Err = Error::success ();
265
+ object::Archive Archive (B->getMemBufferRef (), Err);
266
+ if (Err)
267
+ return printError (std::move (Err), B->getBufferIdentifier ());
268
+
269
+ bool IsMsStyleImplib = false ;
270
+ for (const auto &S : Archive.symbols ()) {
271
+ if (S.getName () == " __NULL_IMPORT_DESCRIPTOR" ) {
272
+ IsMsStyleImplib = true ;
273
+ break ;
274
+ }
275
+ }
276
+ std::vector<StringRef> Names;
277
+ if (forEachCoff (Archive, B->getBufferIdentifier (),
278
+ [&](const COFFObjectFile &Obj, StringRef ObjName) -> bool {
279
+ return identifyImportName (Obj, ObjName, Names,
280
+ IsMsStyleImplib);
281
+ }))
282
+ return 1 ;
283
+
284
+ if (Names.empty ()) {
285
+ llvm::errs () << " No DLL import name found in " << File << " \n " ;
286
+ return 1 ;
287
+ }
288
+ if (Names.size () > 1 && IdentifyStrict) {
289
+ llvm::errs () << File << " contains imports for two or more DLLs\n " ;
290
+ return 1 ;
291
+ }
292
+
293
+ for (StringRef S : Names)
294
+ llvm::outs () << S << " \n " ;
295
+
296
+ return 0 ;
297
+ }
298
+
161
299
} // namespace
162
300
163
301
int llvm::dlltoolDriverMain (llvm::ArrayRef<const char *> ArgsArr) {
@@ -173,7 +311,8 @@ int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
173
311
174
312
// Handle when no input or output is specified
175
313
if (Args.hasArgNoClaim (OPT_INPUT) ||
176
- (!Args.hasArgNoClaim (OPT_d) && !Args.hasArgNoClaim (OPT_l))) {
314
+ (!Args.hasArgNoClaim (OPT_d) && !Args.hasArgNoClaim (OPT_l) &&
315
+ !Args.hasArgNoClaim (OPT_I))) {
177
316
Table.printHelp (outs (), " llvm-dlltool [options] file..." , " llvm-dlltool" ,
178
317
false );
179
318
llvm::outs ()
@@ -185,6 +324,11 @@ int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
185
324
llvm::errs () << " ignoring unknown argument: " << Arg->getAsString (Args)
186
325
<< " \n " ;
187
326
327
+ if (Args.hasArg (OPT_I)) {
328
+ return doIdentify (Args.getLastArg (OPT_I)->getValue (),
329
+ Args.hasArg (OPT_identify_strict));
330
+ }
331
+
188
332
if (!Args.hasArg (OPT_d)) {
189
333
llvm::errs () << " no definition file specified\n " ;
190
334
return 1 ;
0 commit comments