VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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