VirtualBox

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

Last change on this file since 70275 was 70275, checked in by vboxsync, 7 years ago

RTLdrCheckImports.cpp: Build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: RTLdrCheckImports.cpp 70275 2017-12-21 13:44:55Z vboxsync $ */
2/** @file
3 * IPRT - Module dependency checker.
4 */
5
6/*
7 * Copyright (C) 2010-2017 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/err.h>
32#include <iprt/getopt.h>
33#include <iprt/buildconfig.h>
34#include <iprt/file.h>
35#include <iprt/initterm.h>
36#include <iprt/ldr.h>
37#include <iprt/mem.h>
38#include <iprt/message.h>
39#include <iprt/path.h>
40#include <iprt/string.h>
41#include <iprt/stream.h>
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47/**
48 * Import checker options.
49 */
50typedef struct RTCHECKIMPORTSOPTS
51{
52 /** Number of paths to search. */
53 size_t cPaths;
54 /** Search directories. */
55 char **papszPaths;
56 /** The loader architecture. */
57 RTLDRARCH enmLdrArch;
58} RTCHECKIMPORTSOPTS;
59/** Pointer to the checker options. */
60typedef RTCHECKIMPORTSOPTS *PRTCHECKIMPORTSOPTS;
61/** Pointer to the const checker options. */
62typedef RTCHECKIMPORTSOPTS const *PCRTCHECKIMPORTSOPTS;
63
64
65/**
66 * Import module.
67 */
68typedef struct RTCHECKIMPORTMODULE
69{
70 /** The module. If NIL, then we've got a export list (papszExports). */
71 RTLDRMOD hLdrMod;
72 /** Number of export in the export list. (Zero if hLdrMod is valid.) */
73 size_t cExports;
74 /** Export list. (NULL if hLdrMod is valid.) */
75 char *papszExports;
76 /** The module name. */
77 char szModule[256];
78} RTCHECKIMPORTMODULE;
79/** Pointer to an import module. */
80typedef RTCHECKIMPORTMODULE *PRTCHECKIMPORTMODULE;
81
82
83/**
84 * Import checker state (for each image being checked).
85 */
86typedef struct RTCHECKIMPORTSTATE
87{
88 /** The image we're processing. */
89 const char *pszImage;
90 /** The image we're processing. */
91 PCRTCHECKIMPORTSOPTS pOpts;
92 /** Status code. */
93 int iRc;
94 /** Import hint. */
95 uint32_t iHint;
96 /** Number modules. */
97 uint32_t cImports;
98 /** Import modules. */
99 RTCHECKIMPORTMODULE aImports[RT_FLEXIBLE_ARRAY];
100} RTCHECKIMPORTSTATE;
101/** Pointer to the import checker state. */
102typedef RTCHECKIMPORTSTATE *PRTCHECKIMPORTSTATE;
103
104
105
106/**
107 * @callback_method_impl{FNRTLDRIMPORT}
108 */
109static DECLCALLBACK(int) GetImportCallback(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
110 unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
111{
112 PRTCHECKIMPORTSTATE pState = (PRTCHECKIMPORTSTATE)pvUser;
113 int rc;
114 NOREF(hLdrMod);
115
116 /*
117 * If a module is given, lookup the symbol/ordinal there.
118 */
119 if (pszModule)
120 {
121 uint32_t iModule = pState->iHint;
122 if ( iModule > pState->cImports
123 || strcmp(pState->aImports[iModule].szModule, pszModule) != 0)
124 {
125 for (iModule = 0; iModule < pState->cImports; iModule++)
126 if (strcmp(pState->aImports[iModule].szModule, pszModule) == 0)
127 break;
128 if (iModule >= pState->cImports)
129 return RTMsgErrorRc(VERR_MODULE_NOT_FOUND, "%s: Failed to locate import module '%s'", pState->pszImage, pszModule);
130 pState->iHint = iModule;
131 }
132
133 rc = RTLdrGetSymbolEx(pState->aImports[iModule].hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);
134 if (RT_SUCCESS(rc))
135 { /* likely */ }
136 else if (rc == VERR_LDR_FORWARDER)
137 rc= VINF_SUCCESS;
138 else
139 {
140 if (pszSymbol)
141 RTMsgError("%s: Missing import '%s' from '%s'!", pState->pszImage, pszSymbol, pszModule);
142 else
143 RTMsgError("%s: Missing import #%u from '%s'!", pState->pszImage, uSymbol, pszModule);
144 pState->iRc = rc;
145 rc = VINF_SUCCESS;
146 *pValue = _128M + _4K;
147 }
148 }
149 /*
150 * Otherwise we need to scan all modules.
151 */
152 else
153 {
154 Assert(pszSymbol);
155 uint32_t iModule = pState->iHint;
156 if (iModule < pState->cImports)
157 rc = RTLdrGetSymbolEx(pState->aImports[iModule].hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);
158 else
159 rc = VERR_SYMBOL_NOT_FOUND;
160 if (rc == VERR_SYMBOL_NOT_FOUND)
161 {
162 for (iModule = 0; iModule < pState->cImports; iModule++)
163 {
164 rc = RTLdrGetSymbolEx(pState->aImports[iModule].hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);
165 if (rc != VERR_SYMBOL_NOT_FOUND)
166 break;
167 }
168 }
169 if (RT_FAILURE(rc))
170 {
171 RTMsgError("%s: Missing import '%s'!", pState->pszImage, pszSymbol);
172 pState->iRc = rc;
173 rc = VINF_SUCCESS;
174 *pValue = _128M + _4K;
175 }
176 }
177 return rc;
178}
179
180
181/**
182 * Loads an imported module.
183 *
184 * @returns IPRT status code.
185 * @param pOpts The check program options.
186 * @param pModule The import module.
187 * @param pErrInfo Error buffer (to avoid wasting stack).
188 * @param pszImage The image we're processing (for error messages).
189 */
190static int LoadImportModule(PCRTCHECKIMPORTSOPTS pOpts, PRTCHECKIMPORTMODULE pModule, PRTERRINFO pErrInfo, const char *pszImage)
191
192{
193 for (uint32_t iPath = 0; iPath < pOpts->cPaths; iPath++)
194 {
195 char szPath[RTPATH_MAX];
196 int rc = RTPathJoin(szPath, sizeof(szPath), pOpts->papszPaths[iPath], pModule->szModule);
197 if ( RT_SUCCESS(rc)
198 && RTFileExists(szPath))
199 {
200 RTLDRMOD hLdrMod;
201 rc = RTLdrOpenEx(szPath, RTLDR_O_FOR_DEBUG, pOpts->enmLdrArch, &hLdrMod, pErrInfo);
202 if (RT_SUCCESS(rc))
203 {
204 pModule->hLdrMod = hLdrMod;
205 RTMsgInfo("Import '%s' -> '%s'\n", pModule->szModule, szPath);
206 }
207 else if (RTErrInfoIsSet(pErrInfo))
208 RTMsgError("%s: Failed opening import image '%s': %Rrc - %s", pszImage, szPath, rc, pErrInfo->pszMsg);
209 else
210 RTMsgError("%s: Failed opening import image '%s': %Rrc", pszImage, szPath, rc);
211 return rc;
212 }
213 }
214
215 /** @todo export list. */
216
217 return RTMsgErrorRc(VERR_MODULE_NOT_FOUND, "%s: Import module '%s' was not found!", pszImage, pModule->szModule);
218}
219
220
221/**
222 * Checks the imports for the given image.
223 *
224 * @returns IPRT status code.
225 * @param pOpts The check program options.
226 * @param pszImage The image to check.
227 */
228static int rtCheckImportsForImage(PCRTCHECKIMPORTSOPTS pOpts, const char *pszImage)
229{
230 /*
231 * Open the image.
232 */
233 RTERRINFOSTATIC ErrInfo;
234 RTLDRMOD hLdrMod;
235 int rc = RTLdrOpenEx(pszImage, 0 /*fFlags*/, RTLDRARCH_WHATEVER, &hLdrMod, RTErrInfoInitStatic(&ErrInfo));
236 if (RT_FAILURE(rc) && RTErrInfoIsSet(&ErrInfo.Core))
237 return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc - %s", pszImage, rc, ErrInfo.Core.pszMsg);
238 if (RT_FAILURE(rc))
239 return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc", pszImage, rc);
240
241 /*
242 * Do the import modules first.
243 */
244 uint32_t cImports = 0;
245 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_IMPORT_COUNT, &cImports, sizeof(cImports));
246 if (RT_SUCCESS(rc))
247 {
248 RTCHECKIMPORTSTATE *pState = (RTCHECKIMPORTSTATE *)RTMemAllocZ(RT_UOFFSETOF(RTCHECKIMPORTSTATE, aImports[cImports + 1]));
249 if (pState)
250 {
251 pState->pszImage = pszImage;
252 pState->pOpts = pOpts;
253 pState->cImports = cImports;
254
255 for (uint32_t iImport = 0; iImport < cImports; iImport++)
256 {
257 *(uint32_t *)&pState->aImports[iImport].szModule[0] = iImport;
258 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_IMPORT_MODULE, pState->aImports[iImport].szModule,
259 sizeof(pState->aImports[iImport].szModule));
260 if (RT_FAILURE(rc))
261 {
262 RTMsgError("%s: Error querying import #%u: %Rrc", pszImage, iImport, rc);
263 break;
264 }
265 rc = LoadImportModule(pOpts, &pState->aImports[iImport], &ErrInfo.Core, pszImage);
266 if (RT_FAILURE(rc))
267 break;
268 }
269 if (RT_SUCCESS(rc))
270 {
271 /*
272 * Get the image bits, indirectly resolving imports.
273 */
274 size_t cbImage = RTLdrSize(hLdrMod);
275 void *pvImage = RTMemAllocZ(cbImage);
276 if (pvImage)
277 {
278 pState->iRc = VINF_SUCCESS;
279 rc = RTLdrGetBits(hLdrMod, pvImage, _4M, GetImportCallback, pState);
280 if (RT_SUCCESS(rc))
281 rc = pState->iRc;
282 else
283 RTMsgError("%s: RTLdrGetBits failed: %Rrc", pszImage, rc);
284
285 RTMemFree(pvImage);
286 }
287 else
288 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: out of memory", pszImage);
289 }
290
291 AssertCompile(NIL_RTLDRMOD == NULL);
292 for (uint32_t iImport = 0; iImport < cImports; iImport++)
293 if (pState->aImports[iImport].hLdrMod != NIL_RTLDRMOD)
294 RTLdrClose(pState->aImports[iImport].hLdrMod);
295 RTMemFree(pState);
296 }
297 else
298 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: out of memory", pszImage);
299 }
300 else
301 RTMsgError("%s: Querying RTLDRPROP_IMPORT_COUNT failed: %Rrc", pszImage, rc);
302 RTLdrClose(hLdrMod);
303 return rc;
304}
305
306
307int main(int argc, char **argv)
308{
309 int rc = RTR3InitExe(argc, &argv, 0);
310 if (RT_FAILURE(rc))
311 return RTMsgInitFailure(rc);
312
313 RTCHECKIMPORTSOPTS Opts;
314 Opts.cPaths = 0;
315 Opts.papszPaths = NULL;
316 Opts.enmLdrArch = RTLDRARCH_WHATEVER;
317
318 static const RTGETOPTDEF s_aOptions[] =
319 {
320 { "--path", 'p', RTGETOPT_REQ_STRING },
321 };
322 RTGETOPTSTATE State;
323 rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
324 AssertRCReturn(rc, RTEXITCODE_FAILURE);
325
326 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
327 RTGETOPTUNION ValueUnion;
328 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
329 {
330 switch (rc)
331 {
332 case 'p':
333 if ((Opts.cPaths % 16) == 0)
334 {
335 void *pvNew = RTMemRealloc(Opts.papszPaths, sizeof(Opts.papszPaths[0]) * (Opts.cPaths + 16));
336 AssertRCReturn(rc, RTEXITCODE_FAILURE);
337 Opts.papszPaths = (char **)pvNew;
338 }
339 Opts.papszPaths[Opts.cPaths] = RTStrDup(ValueUnion.psz);
340 AssertReturn(Opts.papszPaths[Opts.cPaths], RTEXITCODE_FAILURE);
341 Opts.cPaths++;
342 break;
343
344 case VINF_GETOPT_NOT_OPTION:
345 rc = rtCheckImportsForImage(&Opts, ValueUnion.psz);
346 if (RT_FAILURE(rc))
347 rcExit = RTEXITCODE_FAILURE;
348 break;
349
350 case 'h':
351 RTPrintf("Usage: RTCheckImports [-p|--path <dir>] [-h|--help] [-V|--version] <image [..]>\n"
352 "Checks library imports.\n");
353 return RTEXITCODE_SUCCESS;
354
355 case 'V':
356 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
357 return RTEXITCODE_SUCCESS;
358
359 default:
360 return RTGetOptPrintError(rc, &ValueUnion);
361 }
362 }
363
364 return rcExit;
365}
366
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