VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTLdrCheckImports.cpp@ 86556

Last change on this file since 86556 was 84509, checked in by vboxsync, 5 years ago

iprt/cdefs.h,*: Introducing RT_FLEXIBLE_ARRAY_EXTENSION as a g++ hack that allows us to use RT_FLEXIBLE_ARRAY without the compiler going all pendantic on us. Only tested with 10.1.0. bugref:9746

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.2 KB
Line 
1/* $Id: RTLdrCheckImports.cpp 84509 2020-05-25 15:09:24Z vboxsync $ */
2/** @file
3 * IPRT - Module dependency checker.
4 */
5
6/*
7 * Copyright (C) 2010-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/ctype.h>
32#include <iprt/err.h>
33#include <iprt/getopt.h>
34#include <iprt/buildconfig.h>
35#include <iprt/file.h>
36#include <iprt/initterm.h>
37#include <iprt/ldr.h>
38#include <iprt/mem.h>
39#include <iprt/message.h>
40#include <iprt/path.h>
41#include <iprt/string.h>
42#include <iprt/stream.h>
43#include <iprt/vfs.h>
44
45
46/*********************************************************************************************************************************
47* Structures and Typedefs *
48*********************************************************************************************************************************/
49/**
50 * Import checker options.
51 */
52typedef struct RTCHECKIMPORTSOPTS
53{
54 /** Number of paths to search. */
55 size_t cPaths;
56 /** Search directories. */
57 char **papszPaths;
58 /** The loader architecture. */
59 RTLDRARCH enmLdrArch;
60 /** Verbosity level. */
61 unsigned cVerbosity;
62 /** Whether to also list orinals in the export listing. */
63 bool fListOrdinals;
64} RTCHECKIMPORTSOPTS;
65/** Pointer to the checker options. */
66typedef RTCHECKIMPORTSOPTS *PRTCHECKIMPORTSOPTS;
67/** Pointer to the const checker options. */
68typedef RTCHECKIMPORTSOPTS const *PCRTCHECKIMPORTSOPTS;
69
70
71/**
72 * Import module.
73 */
74typedef struct RTCHECKIMPORTMODULE
75{
76 /** The module. If NIL, then we've got a export list (papszExports). */
77 RTLDRMOD hLdrMod;
78 /** Number of export in the export list. (Zero if hLdrMod is valid.) */
79 size_t cExports;
80 /** Export list. (NULL if hLdrMod is valid.) */
81 char **papszExports;
82 /** The module name. */
83 char szModule[256];
84} RTCHECKIMPORTMODULE;
85/** Pointer to an import module. */
86typedef RTCHECKIMPORTMODULE *PRTCHECKIMPORTMODULE;
87
88
89/**
90 * Import checker state (for each image being checked).
91 */
92typedef struct RTCHECKIMPORTSTATE
93{
94 /** The image we're processing. */
95 const char *pszImage;
96 /** The image we're processing. */
97 PCRTCHECKIMPORTSOPTS pOpts;
98 /** Status code. */
99 int iRc;
100 /** Import hint. */
101 uint32_t iHint;
102 /** Number modules. */
103 uint32_t cImports;
104 /** Import modules. */
105 RT_FLEXIBLE_ARRAY_EXTENSION
106 RTCHECKIMPORTMODULE aImports[RT_FLEXIBLE_ARRAY];
107} RTCHECKIMPORTSTATE;
108/** Pointer to the import checker state. */
109typedef RTCHECKIMPORTSTATE *PRTCHECKIMPORTSTATE;
110
111
112
113/**
114 * Looks up a symbol/ordinal in the given import module.
115 *
116 * @returns IPRT status code.
117 * @param pModule The import module.
118 * @param pszSymbol The symbol name (NULL if not used).
119 * @param uSymbol The ordinal (~0 if unused).
120 * @param pValue Where to return a fake address.
121 */
122static int QuerySymbolFromImportModule(PRTCHECKIMPORTMODULE pModule, const char *pszSymbol, unsigned uSymbol, PRTLDRADDR pValue)
123{
124 if (pModule->hLdrMod != NIL_RTLDRMOD)
125 return RTLdrGetSymbolEx(pModule->hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);
126
127 /*
128 * Search the export list. Ordinal imports are stringified: #<ordinal>
129 */
130 char szOrdinal[32];
131 if (!pszSymbol)
132 {
133 RTStrPrintf(szOrdinal, sizeof(szOrdinal), "#%u", uSymbol);
134 pszSymbol = szOrdinal;
135 }
136
137 size_t i = pModule->cExports;
138 while (i-- > 0)
139 if (strcmp(pModule->papszExports[i], pszSymbol) == 0)
140 {
141 *pValue = _128M + i*4;
142 return VINF_SUCCESS;
143 }
144 return VERR_SYMBOL_NOT_FOUND;
145}
146
147
148/**
149 * @callback_method_impl{FNRTLDRIMPORT}
150 */
151static DECLCALLBACK(int) GetImportCallback(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
152 unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
153{
154 PRTCHECKIMPORTSTATE pState = (PRTCHECKIMPORTSTATE)pvUser;
155 int rc;
156 NOREF(hLdrMod);
157
158 /*
159 * If a module is given, lookup the symbol/ordinal there.
160 */
161 if (pszModule)
162 {
163 uint32_t iModule = pState->iHint;
164 if ( iModule > pState->cImports
165 || strcmp(pState->aImports[iModule].szModule, pszModule) != 0)
166 {
167 for (iModule = 0; iModule < pState->cImports; iModule++)
168 if (strcmp(pState->aImports[iModule].szModule, pszModule) == 0)
169 break;
170 if (iModule >= pState->cImports)
171 return RTMsgErrorRc(VERR_MODULE_NOT_FOUND, "%s: Failed to locate import module '%s'", pState->pszImage, pszModule);
172 pState->iHint = iModule;
173 }
174
175 rc = QuerySymbolFromImportModule(&pState->aImports[iModule], pszSymbol, uSymbol, pValue);
176 if (RT_SUCCESS(rc))
177 { /* likely */ }
178 else if (rc == VERR_LDR_FORWARDER)
179 rc= VINF_SUCCESS;
180 else
181 {
182 if (pszSymbol)
183 RTMsgError("%s: Missing import '%s' from '%s'!", pState->pszImage, pszSymbol, pszModule);
184 else
185 RTMsgError("%s: Missing import #%u from '%s'!", pState->pszImage, uSymbol, pszModule);
186 pState->iRc = rc;
187 rc = VINF_SUCCESS;
188 *pValue = _128M + _4K;
189 }
190 }
191 /*
192 * Otherwise we need to scan all modules.
193 */
194 else
195 {
196 Assert(pszSymbol);
197 uint32_t iModule = pState->iHint;
198 if (iModule < pState->cImports)
199 rc = QuerySymbolFromImportModule(&pState->aImports[iModule], pszSymbol, uSymbol, pValue);
200 else
201 rc = VERR_SYMBOL_NOT_FOUND;
202 if (rc == VERR_SYMBOL_NOT_FOUND)
203 {
204 for (iModule = 0; iModule < pState->cImports; iModule++)
205 {
206 rc = QuerySymbolFromImportModule(&pState->aImports[iModule], pszSymbol, uSymbol, pValue);
207 if (rc != VERR_SYMBOL_NOT_FOUND)
208 break;
209 }
210 }
211 if (RT_FAILURE(rc))
212 {
213 RTMsgError("%s: Missing import '%s'!", pState->pszImage, pszSymbol);
214 pState->iRc = rc;
215 rc = VINF_SUCCESS;
216 *pValue = _128M + _4K;
217 }
218 }
219 return rc;
220}
221
222
223/**
224 * Loads an imported module.
225 *
226 * @returns IPRT status code.
227 * @param pOpts The check program options.
228 * @param pModule The import module.
229 * @param pErrInfo Error buffer (to avoid wasting stack).
230 * @param pszImage The image we're processing (for error messages).
231 */
232static int LoadImportModule(PCRTCHECKIMPORTSOPTS pOpts, PRTCHECKIMPORTMODULE pModule, PRTERRINFO pErrInfo, const char *pszImage)
233
234{
235 /*
236 * Look for real DLLs.
237 */
238 for (uint32_t iPath = 0; iPath < pOpts->cPaths; iPath++)
239 {
240 char szPath[RTPATH_MAX];
241 int rc = RTPathJoin(szPath, sizeof(szPath), pOpts->papszPaths[iPath], pModule->szModule);
242 if (RT_SUCCESS(rc))
243 {
244 uint32_t offError;
245 RTFSOBJINFO ObjInfo;
246 rc = RTVfsChainQueryInfo(szPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK, &offError, pErrInfo);
247 if (RT_SUCCESS(rc))
248 {
249 if (RTFS_IS_FILE(ObjInfo.Attr.fMode))
250 {
251 RTLDRMOD hLdrMod;
252 rc = RTLdrOpenVfsChain(szPath, RTLDR_O_FOR_DEBUG, pOpts->enmLdrArch, &hLdrMod, &offError, pErrInfo);
253 if (RT_SUCCESS(rc))
254 {
255 pModule->hLdrMod = hLdrMod;
256 if (pOpts->cVerbosity > 0)
257 RTMsgInfo("Import '%s' -> '%s'\n", pModule->szModule, szPath);
258 }
259 else if (RTErrInfoIsSet(pErrInfo))
260 RTMsgError("%s: Failed opening import image '%s': %Rrc - %s", pszImage, szPath, rc, pErrInfo->pszMsg);
261 else
262 RTMsgError("%s: Failed opening import image '%s': %Rrc", pszImage, szPath, rc);
263 return rc;
264 }
265 }
266 else if ( rc != VERR_PATH_NOT_FOUND
267 && rc != VERR_FILE_NOT_FOUND)
268 RTVfsChainMsgError("RTVfsChainQueryInfo", szPath, rc, offError, pErrInfo);
269
270 /*
271 * Check for export file.
272 */
273 RTStrCat(szPath, sizeof(szPath), ".exports");
274 RTVFSFILE hVfsFile;
275 rc = RTVfsChainOpenFile(szPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hVfsFile, &offError, pErrInfo);
276 if (RT_SUCCESS(rc))
277 {
278 /* Read it into a memory buffer. */
279 uint64_t cbFile;
280 rc = RTVfsFileQuerySize(hVfsFile, &cbFile);
281 if (RT_SUCCESS(rc))
282 {
283 if (cbFile < _4M)
284 {
285 char *pszFile = (char *)RTMemAlloc((size_t)cbFile + 1);
286 if (pszFile)
287 {
288 rc = RTVfsFileRead(hVfsFile, pszFile, (size_t)cbFile, NULL);
289 if (RT_SUCCESS(rc))
290 {
291 pszFile[(size_t)cbFile] = '\0';
292 rc = RTStrValidateEncoding(pszFile);
293 if (RT_SUCCESS(rc))
294 {
295 /*
296 * Parse it.
297 */
298 size_t iLine = 1;
299 size_t off = 0;
300 while (off < cbFile)
301 {
302 size_t const offStartLine = off;
303
304 /* skip leading blanks */
305 while (RT_C_IS_BLANK(pszFile[off]))
306 off++;
307
308 char ch = pszFile[off];
309 if ( ch != ';' /* comment */
310 && !RT_C_IS_CNTRL(ch))
311 {
312 /* find length of symbol */
313 size_t const offSymbol = off;
314 while ( (ch = pszFile[off]) != '\0'
315 && !RT_C_IS_SPACE(ch))
316 off++;
317 size_t const cchSymbol = off - offSymbol;
318
319 /* add it. */
320 if ((pModule->cExports & 127) == 0)
321 {
322 void *pvNew = RTMemRealloc(pModule->papszExports,
323 (pModule->cExports + 128) * sizeof(char *));
324 if (!pvNew)
325 {
326 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: %s:%u: out of memory!", pszImage, szPath, iLine);
327 break;
328 }
329 pModule->papszExports = (char **)pvNew;
330 }
331 pModule->papszExports[pModule->cExports] = RTStrDupN(&pszFile[offSymbol], cchSymbol);
332 if (pModule->papszExports[pModule->cExports])
333 pModule->cExports++;
334 else
335 {
336 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: %s:%u: out of memory!", pszImage, szPath, iLine);
337 break;
338 }
339
340 /* check what comes next is a comment or end of line/file */
341 while (RT_C_IS_BLANK(pszFile[off]))
342 off++;
343 ch = pszFile[off];
344 if ( ch != '\0'
345 && ch != '\n'
346 && ch != '\r'
347 && ch != ';')
348 rc = RTMsgErrorRc(VERR_PARSE_ERROR, "%s: %s:%u: Unexpected text at position %u!",
349 pszImage, szPath, iLine, off - offStartLine);
350 }
351
352 /* advance to the end of the the line */
353 while ( (ch = pszFile[off]) != '\0'
354 && ch != '\n')
355 off++;
356 off++;
357 iLine++;
358 }
359
360 if (pOpts->cVerbosity > 0)
361 RTMsgInfo("Import '%s' -> '%s' (%u exports)\n",
362 pModule->szModule, szPath, pModule->cExports);
363 }
364 else
365 RTMsgError("%s: %s: Invalid UTF-8 encoding in export file: %Rrc", pszImage, szPath, rc);
366 }
367 RTMemFree(pszFile);
368 }
369 else
370 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: %s: Out of memory reading export file (%#RX64 bytes)",
371 pszImage, szPath, cbFile + 1);
372 }
373 else
374 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: %s: Export file is too big: %#RX64 bytes, max 4MiB",
375 pszImage, szPath, cbFile);
376 }
377 else
378 RTMsgError("%s: %s: RTVfsFileQuerySize failed on export file: %Rrc", pszImage, szPath, rc);
379 RTVfsFileRelease(hVfsFile);
380 return rc;
381 }
382 else if ( rc != VERR_PATH_NOT_FOUND
383 && rc != VERR_FILE_NOT_FOUND)
384 RTVfsChainMsgError("RTVfsChainOpenFile", szPath, rc, offError, pErrInfo);
385 }
386 }
387
388 return RTMsgErrorRc(VERR_MODULE_NOT_FOUND, "%s: Import module '%s' was not found!", pszImage, pModule->szModule);
389}
390
391
392/**
393 * Checks the imports for the given image.
394 *
395 * @returns IPRT status code.
396 * @param pOpts The check program options.
397 * @param pszImage The image to check.
398 */
399static int rtCheckImportsForImage(PCRTCHECKIMPORTSOPTS pOpts, const char *pszImage)
400{
401 if (pOpts->cVerbosity > 0)
402 RTMsgInfo("Checking '%s'...\n", pszImage);
403
404 /*
405 * Open the image.
406 */
407 uint32_t offError;
408 RTERRINFOSTATIC ErrInfo;
409 RTLDRMOD hLdrMod;
410 int rc = RTLdrOpenVfsChain(pszImage, 0 /*fFlags*/, RTLDRARCH_WHATEVER, &hLdrMod, &offError, RTErrInfoInitStatic(&ErrInfo));
411 if (RT_FAILURE(rc))
412 {
413 if (RT_FAILURE(rc) && RTErrInfoIsSet(&ErrInfo.Core))
414 return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc - %s", pszImage, rc, ErrInfo.Core.pszMsg);
415 return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc", pszImage, rc);
416 }
417
418 /*
419 * Do the import modules first.
420 */
421 uint32_t cImports = 0;
422 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_IMPORT_COUNT, &cImports, sizeof(cImports));
423 if (RT_SUCCESS(rc))
424 {
425 RTCHECKIMPORTSTATE *pState = (RTCHECKIMPORTSTATE *)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCHECKIMPORTSTATE, aImports[cImports + 1]));
426 if (pState)
427 {
428 pState->pszImage = pszImage;
429 pState->pOpts = pOpts;
430 pState->cImports = cImports;
431 for (uint32_t iImport = 0; iImport < cImports; iImport++)
432 pState->aImports[iImport].hLdrMod = NIL_RTLDRMOD;
433
434 for (uint32_t iImport = 0; iImport < cImports; iImport++)
435 {
436 *(uint32_t *)&pState->aImports[iImport].szModule[0] = iImport;
437 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_IMPORT_MODULE, pState->aImports[iImport].szModule,
438 sizeof(pState->aImports[iImport].szModule));
439 if (RT_FAILURE(rc))
440 {
441 RTMsgError("%s: Error querying import #%u: %Rrc", pszImage, iImport, rc);
442 break;
443 }
444 rc = LoadImportModule(pOpts, &pState->aImports[iImport], &ErrInfo.Core, pszImage);
445 if (RT_FAILURE(rc))
446 break;
447 }
448 if (RT_SUCCESS(rc))
449 {
450 /*
451 * Get the image bits, indirectly resolving imports.
452 */
453 size_t cbImage = RTLdrSize(hLdrMod);
454 void *pvImage = RTMemAllocZ(cbImage);
455 if (pvImage)
456 {
457 pState->iRc = VINF_SUCCESS;
458 rc = RTLdrGetBits(hLdrMod, pvImage, _4M, GetImportCallback, pState);
459 if (RT_SUCCESS(rc))
460 rc = pState->iRc;
461 else
462 RTMsgError("%s: RTLdrGetBits failed: %Rrc", pszImage, rc);
463
464 RTMemFree(pvImage);
465 }
466 else
467 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: out of memory", pszImage);
468 }
469
470 for (uint32_t iImport = 0; iImport < cImports; iImport++)
471 if (pState->aImports[iImport].hLdrMod != NIL_RTLDRMOD)
472 {
473 RTLdrClose(pState->aImports[iImport].hLdrMod);
474
475 size_t i = pState->aImports[iImport].cExports;
476 while (i-- > 0)
477 RTStrFree(pState->aImports[iImport].papszExports[i]);
478 RTMemFree(pState->aImports[iImport].papszExports);
479 }
480 RTMemFree(pState);
481 }
482 else
483 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: out of memory", pszImage);
484 }
485 else
486 RTMsgError("%s: Querying RTLDRPROP_IMPORT_COUNT failed: %Rrc", pszImage, rc);
487 RTLdrClose(hLdrMod);
488 return rc;
489}
490
491
492/**
493 * @callback_method_impl{FNRTLDRENUMSYMS}
494 */
495static DECLCALLBACK(int) PrintSymbolForExportList(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
496 RTLDRADDR Value, void *pvUser)
497{
498 if (pszSymbol)
499 RTPrintf("%s\n", pszSymbol);
500 if (uSymbol != ~(unsigned)0 && (!pszSymbol || ((PCRTCHECKIMPORTSOPTS)pvUser)->fListOrdinals))
501 RTPrintf("#%u\n", uSymbol);
502 RT_NOREF(hLdrMod, Value, pvUser);
503 return VINF_SUCCESS;
504}
505
506
507/**
508 * Produces the export list for the given image.
509 *
510 * @returns IPRT status code.
511 * @param pOpts The check program options.
512 * @param pszImage Path to the image.
513 */
514static int ProduceExportList(PCRTCHECKIMPORTSOPTS pOpts, const char *pszImage)
515{
516 /*
517 * Open the image.
518 */
519 uint32_t offError;
520 RTERRINFOSTATIC ErrInfo;
521 RTLDRMOD hLdrMod;
522 int rc = RTLdrOpenVfsChain(pszImage, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, &hLdrMod, &offError, RTErrInfoInitStatic(&ErrInfo));
523 if (RT_SUCCESS(rc))
524 {
525 /*
526 * Some info about the file.
527 */
528 RTPrintf(";\n"
529 "; Generated from: %s\n", pszImage);
530
531 RTFSOBJINFO ObjInfo;
532 rc = RTVfsChainQueryInfo(pszImage, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK, NULL, NULL);
533 if (RT_SUCCESS(rc))
534 RTPrintf("; Size file: %#RX64 (%RU64)\n", ObjInfo.cbObject, ObjInfo.cbObject);
535
536 switch (RTLdrGetFormat(hLdrMod))
537 {
538 case RTLDRFMT_AOUT: RTPrintf("; Format: a.out\n"); break;
539 case RTLDRFMT_ELF: RTPrintf("; Format: ELF\n"); break;
540 case RTLDRFMT_LX: RTPrintf("; Format: LX\n"); break;
541 case RTLDRFMT_MACHO: RTPrintf("; Format: Mach-O\n"); break;
542 case RTLDRFMT_PE: RTPrintf("; Format: PE\n"); break;
543 default: RTPrintf("; Format: %u\n", RTLdrGetFormat(hLdrMod)); break;
544
545 }
546
547 RTPrintf("; Size of image: %#x (%u)\n", RTLdrSize(hLdrMod), RTLdrSize(hLdrMod));
548
549 switch (RTLdrGetArch(hLdrMod))
550 {
551 case RTLDRARCH_AMD64: RTPrintf("; Architecture: AMD64\n"); break;
552 case RTLDRARCH_X86_32: RTPrintf("; Architecture: X86\n"); break;
553 default: RTPrintf("; Architecture: %u\n", RTLdrGetArch(hLdrMod)); break;
554 }
555
556 uint64_t uTimestamp;
557 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp, sizeof(uTimestamp));
558 if (RT_SUCCESS(rc))
559 {
560 RTTIMESPEC Timestamp;
561 char szTime[128];
562 RTTimeSpecToString(RTTimeSpecSetSeconds(&Timestamp, uTimestamp), szTime, sizeof(szTime));
563 char *pszEnd = strchr(szTime, '\0');
564 while (pszEnd[0] != '.')
565 pszEnd--;
566 *pszEnd = '\0';
567 RTPrintf("; Timestamp: %#RX64 - %s\n", uTimestamp, szTime);
568 }
569
570 RTUUID ImageUuid;
571 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_UUID, &ImageUuid, sizeof(ImageUuid));
572 if (RT_SUCCESS(rc))
573 RTPrintf("; UUID: %RTuuid\n", &ImageUuid);
574
575 RTPrintf(";\n");
576
577 /*
578 * The list of exports.
579 */
580 rc = RTLdrEnumSymbols(hLdrMod, 0 /*fFlags*/, NULL, _4M, PrintSymbolForExportList, (void *)pOpts);
581 if (RT_FAILURE(rc))
582 RTMsgError("%s: RTLdrEnumSymbols failed: %Rrc", pszImage, rc);
583
584 /* done */
585 RTLdrClose(hLdrMod);
586 }
587 else if (RTErrInfoIsSet(&ErrInfo.Core))
588 RTMsgError("Failed opening image '%s': %Rrc - %s", pszImage, rc, ErrInfo.Core.pszMsg);
589 else
590 RTMsgError("Failed opening image '%s': %Rrc", pszImage, rc);
591 return rc;
592}
593
594
595int main(int argc, char **argv)
596{
597 int rc = RTR3InitExe(argc, &argv, 0);
598 if (RT_FAILURE(rc))
599 return RTMsgInitFailure(rc);
600
601 RTCHECKIMPORTSOPTS Opts;
602 Opts.cPaths = 0;
603 Opts.papszPaths = NULL;
604 Opts.enmLdrArch = RTLDRARCH_WHATEVER;
605 Opts.cVerbosity = 1;
606 Opts.fListOrdinals = false;
607
608 static const RTGETOPTDEF s_aOptions[] =
609 {
610 { "--path", 'p', RTGETOPT_REQ_STRING },
611 { "--export", 'e', RTGETOPT_REQ_STRING },
612 { "--list-ordinals", 'O', RTGETOPT_REQ_NOTHING },
613 { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
614 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
615 };
616 RTGETOPTSTATE State;
617 rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
618 AssertRCReturn(rc, RTEXITCODE_FAILURE);
619
620 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
621 RTGETOPTUNION ValueUnion;
622 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
623 {
624 switch (rc)
625 {
626 case 'p':
627 if ((Opts.cPaths % 16) == 0)
628 {
629 void *pvNew = RTMemRealloc(Opts.papszPaths, sizeof(Opts.papszPaths[0]) * (Opts.cPaths + 16));
630 AssertRCReturn(rc, RTEXITCODE_FAILURE);
631 Opts.papszPaths = (char **)pvNew;
632 }
633 Opts.papszPaths[Opts.cPaths] = RTStrDup(ValueUnion.psz);
634 AssertReturn(Opts.papszPaths[Opts.cPaths], RTEXITCODE_FAILURE);
635 Opts.cPaths++;
636 break;
637
638 case 'e':
639 rc = ProduceExportList(&Opts, ValueUnion.psz);
640 if (RT_FAILURE(rc))
641 rcExit = RTEXITCODE_FAILURE;
642 break;
643
644 case 'O':
645 Opts.fListOrdinals = true;
646 break;
647
648 case 'q':
649 Opts.cVerbosity = 0;
650 break;
651
652 case 'v':
653 Opts.cVerbosity = 0;
654 break;
655
656 case VINF_GETOPT_NOT_OPTION:
657 rc = rtCheckImportsForImage(&Opts, ValueUnion.psz);
658 if (RT_FAILURE(rc))
659 rcExit = RTEXITCODE_FAILURE;
660 break;
661
662 case 'h':
663 RTPrintf("Usage: RTCheckImports [-p|--path <dir>] [-v|--verbose] [-q|--quiet] <image [..]>\n"
664 " or: RTCheckImports -e <image>\n"
665 " or: RTCheckImports <-h|--help>\n"
666 " or: RTCheckImports <-V|--version>\n"
667 "Checks library imports. VFS chain syntax supported.\n"
668 "\n"
669 "Options:\n"
670 " -p, --path <dir>\n"
671 " Search the specified directory for imported modules or their export lists.\n"
672 " -e, --export <image>\n"
673 " Write export list for the file to stdout. (Redirect to a .export file.)\n"
674 " -O, --list-ordinals\n"
675 " Whether to list ordinals as well as names in the export list.\n"
676 " -q, --quiet\n"
677 " Quiet execution.\n"
678 " -v, --verbose\n"
679 " Increases verbosity.\n"
680 ""
681 );
682 return RTEXITCODE_SUCCESS;
683
684#ifndef IPRT_IN_BUILD_TOOL
685 case 'V':
686 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
687 return RTEXITCODE_SUCCESS;
688#endif
689
690 default:
691 return RTGetOptPrintError(rc, &ValueUnion);
692 }
693 }
694
695 return rcExit;
696}
697
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette