VirtualBox

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

Last change on this file since 95841 was 93317, checked in by vboxsync, 3 years ago

RTLdrCheckImports: Open the image with the RTLDR_O_DEBUG flag set so we don't barf on unsupported things when all we need to do is listing imports. This was a problem in ASAN builds where we would get TLS stuff added to all the images. bugref:8489

  • 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 93317 2022-01-18 15:15:17Z vboxsync $ */
2/** @file
3 * IPRT - Module dependency checker.
4 */
5
6/*
7 * Copyright (C) 2010-2022 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, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER,
411 &hLdrMod, &offError, RTErrInfoInitStatic(&ErrInfo));
412 if (RT_FAILURE(rc))
413 {
414 if (RT_FAILURE(rc) && RTErrInfoIsSet(&ErrInfo.Core))
415 return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc - %s", pszImage, rc, ErrInfo.Core.pszMsg);
416 return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc", pszImage, rc);
417 }
418
419 /*
420 * Do the import modules first.
421 */
422 uint32_t cImports = 0;
423 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_IMPORT_COUNT, &cImports, sizeof(cImports));
424 if (RT_SUCCESS(rc))
425 {
426 RTCHECKIMPORTSTATE *pState = (RTCHECKIMPORTSTATE *)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCHECKIMPORTSTATE, aImports[cImports + 1]));
427 if (pState)
428 {
429 pState->pszImage = pszImage;
430 pState->pOpts = pOpts;
431 pState->cImports = cImports;
432 for (uint32_t iImport = 0; iImport < cImports; iImport++)
433 pState->aImports[iImport].hLdrMod = NIL_RTLDRMOD;
434
435 for (uint32_t iImport = 0; iImport < cImports; iImport++)
436 {
437 *(uint32_t *)&pState->aImports[iImport].szModule[0] = iImport;
438 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_IMPORT_MODULE, pState->aImports[iImport].szModule,
439 sizeof(pState->aImports[iImport].szModule));
440 if (RT_FAILURE(rc))
441 {
442 RTMsgError("%s: Error querying import #%u: %Rrc", pszImage, iImport, rc);
443 break;
444 }
445 rc = LoadImportModule(pOpts, &pState->aImports[iImport], &ErrInfo.Core, pszImage);
446 if (RT_FAILURE(rc))
447 break;
448 }
449 if (RT_SUCCESS(rc))
450 {
451 /*
452 * Get the image bits, indirectly resolving imports.
453 */
454 size_t cbImage = RTLdrSize(hLdrMod);
455 void *pvImage = RTMemAllocZ(cbImage);
456 if (pvImage)
457 {
458 pState->iRc = VINF_SUCCESS;
459 rc = RTLdrGetBits(hLdrMod, pvImage, _4M, GetImportCallback, pState);
460 if (RT_SUCCESS(rc))
461 rc = pState->iRc;
462 else
463 RTMsgError("%s: RTLdrGetBits failed: %Rrc", pszImage, rc);
464
465 RTMemFree(pvImage);
466 }
467 else
468 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: out of memory", pszImage);
469 }
470
471 for (uint32_t iImport = 0; iImport < cImports; iImport++)
472 if (pState->aImports[iImport].hLdrMod != NIL_RTLDRMOD)
473 {
474 RTLdrClose(pState->aImports[iImport].hLdrMod);
475
476 size_t i = pState->aImports[iImport].cExports;
477 while (i-- > 0)
478 RTStrFree(pState->aImports[iImport].papszExports[i]);
479 RTMemFree(pState->aImports[iImport].papszExports);
480 }
481 RTMemFree(pState);
482 }
483 else
484 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: out of memory", pszImage);
485 }
486 else
487 RTMsgError("%s: Querying RTLDRPROP_IMPORT_COUNT failed: %Rrc", pszImage, rc);
488 RTLdrClose(hLdrMod);
489 return rc;
490}
491
492
493/**
494 * @callback_method_impl{FNRTLDRENUMSYMS}
495 */
496static DECLCALLBACK(int) PrintSymbolForExportList(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
497 RTLDRADDR Value, void *pvUser)
498{
499 if (pszSymbol)
500 RTPrintf("%s\n", pszSymbol);
501 if (uSymbol != ~(unsigned)0 && (!pszSymbol || ((PCRTCHECKIMPORTSOPTS)pvUser)->fListOrdinals))
502 RTPrintf("#%u\n", uSymbol);
503 RT_NOREF(hLdrMod, Value, pvUser);
504 return VINF_SUCCESS;
505}
506
507
508/**
509 * Produces the export list for the given image.
510 *
511 * @returns IPRT status code.
512 * @param pOpts The check program options.
513 * @param pszImage Path to the image.
514 */
515static int ProduceExportList(PCRTCHECKIMPORTSOPTS pOpts, const char *pszImage)
516{
517 /*
518 * Open the image.
519 */
520 uint32_t offError;
521 RTERRINFOSTATIC ErrInfo;
522 RTLDRMOD hLdrMod;
523 int rc = RTLdrOpenVfsChain(pszImage, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, &hLdrMod, &offError, RTErrInfoInitStatic(&ErrInfo));
524 if (RT_SUCCESS(rc))
525 {
526 /*
527 * Some info about the file.
528 */
529 RTPrintf(";\n"
530 "; Generated from: %s\n", pszImage);
531
532 RTFSOBJINFO ObjInfo;
533 rc = RTVfsChainQueryInfo(pszImage, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK, NULL, NULL);
534 if (RT_SUCCESS(rc))
535 RTPrintf("; Size file: %#RX64 (%RU64)\n", ObjInfo.cbObject, ObjInfo.cbObject);
536
537 switch (RTLdrGetFormat(hLdrMod))
538 {
539 case RTLDRFMT_AOUT: RTPrintf("; Format: a.out\n"); break;
540 case RTLDRFMT_ELF: RTPrintf("; Format: ELF\n"); break;
541 case RTLDRFMT_LX: RTPrintf("; Format: LX\n"); break;
542 case RTLDRFMT_MACHO: RTPrintf("; Format: Mach-O\n"); break;
543 case RTLDRFMT_PE: RTPrintf("; Format: PE\n"); break;
544 default: RTPrintf("; Format: %u\n", RTLdrGetFormat(hLdrMod)); break;
545
546 }
547
548 RTPrintf("; Size of image: %#x (%u)\n", RTLdrSize(hLdrMod), RTLdrSize(hLdrMod));
549
550 switch (RTLdrGetArch(hLdrMod))
551 {
552 case RTLDRARCH_AMD64: RTPrintf("; Architecture: AMD64\n"); break;
553 case RTLDRARCH_X86_32: RTPrintf("; Architecture: X86\n"); break;
554 default: RTPrintf("; Architecture: %u\n", RTLdrGetArch(hLdrMod)); break;
555 }
556
557 uint64_t uTimestamp;
558 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp, sizeof(uTimestamp));
559 if (RT_SUCCESS(rc))
560 {
561 RTTIMESPEC Timestamp;
562 char szTime[128];
563 RTTimeSpecToString(RTTimeSpecSetSeconds(&Timestamp, uTimestamp), szTime, sizeof(szTime));
564 char *pszEnd = strchr(szTime, '\0');
565 while (pszEnd[0] != '.')
566 pszEnd--;
567 *pszEnd = '\0';
568 RTPrintf("; Timestamp: %#RX64 - %s\n", uTimestamp, szTime);
569 }
570
571 RTUUID ImageUuid;
572 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_UUID, &ImageUuid, sizeof(ImageUuid));
573 if (RT_SUCCESS(rc))
574 RTPrintf("; UUID: %RTuuid\n", &ImageUuid);
575
576 RTPrintf(";\n");
577
578 /*
579 * The list of exports.
580 */
581 rc = RTLdrEnumSymbols(hLdrMod, 0 /*fFlags*/, NULL, _4M, PrintSymbolForExportList, (void *)pOpts);
582 if (RT_FAILURE(rc))
583 RTMsgError("%s: RTLdrEnumSymbols failed: %Rrc", pszImage, rc);
584
585 /* done */
586 RTLdrClose(hLdrMod);
587 }
588 else if (RTErrInfoIsSet(&ErrInfo.Core))
589 RTMsgError("Failed opening image '%s': %Rrc - %s", pszImage, rc, ErrInfo.Core.pszMsg);
590 else
591 RTMsgError("Failed opening image '%s': %Rrc", pszImage, rc);
592 return rc;
593}
594
595
596int main(int argc, char **argv)
597{
598 int rc = RTR3InitExe(argc, &argv, 0);
599 if (RT_FAILURE(rc))
600 return RTMsgInitFailure(rc);
601
602 RTCHECKIMPORTSOPTS Opts;
603 Opts.cPaths = 0;
604 Opts.papszPaths = NULL;
605 Opts.enmLdrArch = RTLDRARCH_WHATEVER;
606 Opts.cVerbosity = 1;
607 Opts.fListOrdinals = false;
608
609 static const RTGETOPTDEF s_aOptions[] =
610 {
611 { "--path", 'p', RTGETOPT_REQ_STRING },
612 { "--export", 'e', RTGETOPT_REQ_STRING },
613 { "--list-ordinals", 'O', RTGETOPT_REQ_NOTHING },
614 { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
615 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
616 };
617 RTGETOPTSTATE State;
618 rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
619 AssertRCReturn(rc, RTEXITCODE_FAILURE);
620
621 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
622 RTGETOPTUNION ValueUnion;
623 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
624 {
625 switch (rc)
626 {
627 case 'p':
628 if ((Opts.cPaths % 16) == 0)
629 {
630 void *pvNew = RTMemRealloc(Opts.papszPaths, sizeof(Opts.papszPaths[0]) * (Opts.cPaths + 16));
631 AssertRCReturn(rc, RTEXITCODE_FAILURE);
632 Opts.papszPaths = (char **)pvNew;
633 }
634 Opts.papszPaths[Opts.cPaths] = RTStrDup(ValueUnion.psz);
635 AssertReturn(Opts.papszPaths[Opts.cPaths], RTEXITCODE_FAILURE);
636 Opts.cPaths++;
637 break;
638
639 case 'e':
640 rc = ProduceExportList(&Opts, ValueUnion.psz);
641 if (RT_FAILURE(rc))
642 rcExit = RTEXITCODE_FAILURE;
643 break;
644
645 case 'O':
646 Opts.fListOrdinals = true;
647 break;
648
649 case 'q':
650 Opts.cVerbosity = 0;
651 break;
652
653 case 'v':
654 Opts.cVerbosity = 0;
655 break;
656
657 case VINF_GETOPT_NOT_OPTION:
658 rc = rtCheckImportsForImage(&Opts, ValueUnion.psz);
659 if (RT_FAILURE(rc))
660 rcExit = RTEXITCODE_FAILURE;
661 break;
662
663 case 'h':
664 RTPrintf("Usage: RTCheckImports [-p|--path <dir>] [-v|--verbose] [-q|--quiet] <image [..]>\n"
665 " or: RTCheckImports -e <image>\n"
666 " or: RTCheckImports <-h|--help>\n"
667 " or: RTCheckImports <-V|--version>\n"
668 "Checks library imports. VFS chain syntax supported.\n"
669 "\n"
670 "Options:\n"
671 " -p, --path <dir>\n"
672 " Search the specified directory for imported modules or their export lists.\n"
673 " -e, --export <image>\n"
674 " Write export list for the file to stdout. (Redirect to a .export file.)\n"
675 " -O, --list-ordinals\n"
676 " Whether to list ordinals as well as names in the export list.\n"
677 " -q, --quiet\n"
678 " Quiet execution.\n"
679 " -v, --verbose\n"
680 " Increases verbosity.\n"
681 ""
682 );
683 return RTEXITCODE_SUCCESS;
684
685#ifndef IPRT_IN_BUILD_TOOL
686 case 'V':
687 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
688 return RTEXITCODE_SUCCESS;
689#endif
690
691 default:
692 return RTGetOptPrintError(rc, &ValueUnion);
693 }
694 }
695
696 return rcExit;
697}
698
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