1212
1313#include " llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
1414#include " llvm/ADT/StringSwitch.h"
15+ #include " llvm/Object/Archive.h"
1516#include " llvm/Object/COFF.h"
1617#include " llvm/Object/COFFImportFile.h"
1718#include " llvm/Object/COFFModuleDefinition.h"
@@ -158,6 +159,143 @@ bool parseModuleDefinition(StringRef DefFileName, MachineTypes Machine,
158159 return true ;
159160}
160161
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+
161299} // namespace
162300
163301int llvm::dlltoolDriverMain (llvm::ArrayRef<const char *> ArgsArr) {
@@ -173,7 +311,8 @@ int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
173311
174312 // Handle when no input or output is specified
175313 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))) {
177316 Table.printHelp (outs (), " llvm-dlltool [options] file..." , " llvm-dlltool" ,
178317 false );
179318 llvm::outs ()
@@ -185,6 +324,11 @@ int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
185324 llvm::errs () << " ignoring unknown argument: " << Arg->getAsString (Args)
186325 << " \n " ;
187326
327+ if (Args.hasArg (OPT_I)) {
328+ return doIdentify (Args.getLastArg (OPT_I)->getValue (),
329+ Args.hasArg (OPT_identify_strict));
330+ }
331+
188332 if (!Args.hasArg (OPT_d)) {
189333 llvm::errs () << " no definition file specified\n " ;
190334 return 1 ;
0 commit comments