Changeset 70311 in vbox for trunk/src/VBox/Runtime/tools/RTLdrCheckImports.cpp
- Timestamp:
- Dec 22, 2017 11:47:24 AM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/tools/RTLdrCheckImports.cpp
r70293 r70311 29 29 * Header Files * 30 30 *********************************************************************************************************************************/ 31 #define RTMEM_WRAP_TO_EF_APIS 32 #include <iprt/ctype.h> 31 33 #include <iprt/err.h> 32 34 #include <iprt/getopt.h> … … 40 42 #include <iprt/string.h> 41 43 #include <iprt/stream.h> 44 #include <iprt/vfs.h> 42 45 43 46 … … 73 76 size_t cExports; 74 77 /** Export list. (NULL if hLdrMod is valid.) */ 75 char 78 char **papszExports; 76 79 /** The module name. */ 77 80 char szModule[256]; … … 105 108 106 109 /** 110 * Looks up a symbol/ordinal in the given import module. 111 * 112 * @returns IPRT status code. 113 * @param pModule The import module. 114 * @param pszSymbol The symbol name (NULL if not used). 115 * @param uSymbol The ordinal (~0 if unused). 116 * @param pValue Where to return a fake address. 117 */ 118 static int QuerySymbolFromImportModule(PRTCHECKIMPORTMODULE pModule, const char *pszSymbol, unsigned uSymbol, PRTLDRADDR pValue) 119 { 120 if (pModule->hLdrMod != NIL_RTLDRMOD) 121 return RTLdrGetSymbolEx(pModule->hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue); 122 123 /* 124 * Search the export list. Ordinal imports are stringified: #<ordinal> 125 */ 126 char szOrdinal[32]; 127 if (!pszSymbol) 128 { 129 RTStrPrintf(szOrdinal, sizeof(szOrdinal), "#%u", uSymbol); 130 pszSymbol = szOrdinal; 131 } 132 133 size_t i = pModule->cExports; 134 while (i-- > 0) 135 if (strcmp(pModule->papszExports[i], pszSymbol) == 0) 136 { 137 *pValue = _128M + i*4; 138 return VINF_SUCCESS; 139 } 140 return VERR_SYMBOL_NOT_FOUND; 141 } 142 143 144 /** 107 145 * @callback_method_impl{FNRTLDRIMPORT} 108 146 */ … … 131 169 } 132 170 133 rc = RTLdrGetSymbolEx(pState->aImports[iModule].hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);171 rc = QuerySymbolFromImportModule(&pState->aImports[iModule], pszSymbol, uSymbol, pValue); 134 172 if (RT_SUCCESS(rc)) 135 173 { /* likely */ } … … 155 193 uint32_t iModule = pState->iHint; 156 194 if (iModule < pState->cImports) 157 rc = RTLdrGetSymbolEx(pState->aImports[iModule].hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);195 rc = QuerySymbolFromImportModule(&pState->aImports[iModule], pszSymbol, uSymbol, pValue); 158 196 else 159 197 rc = VERR_SYMBOL_NOT_FOUND; … … 162 200 for (iModule = 0; iModule < pState->cImports; iModule++) 163 201 { 164 rc = RTLdrGetSymbolEx(pState->aImports[iModule].hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);202 rc = QuerySymbolFromImportModule(&pState->aImports[iModule], pszSymbol, uSymbol, pValue); 165 203 if (rc != VERR_SYMBOL_NOT_FOUND) 166 204 break; … … 191 229 192 230 { 231 /* 232 * Look for real DLLs. 233 */ 193 234 for (uint32_t iPath = 0; iPath < pOpts->cPaths; iPath++) 194 235 { 195 char szPath[RTPATH_MAX];236 char szPath[RTPATH_MAX]; 196 237 int rc = RTPathJoin(szPath, sizeof(szPath), pOpts->papszPaths[iPath], pModule->szModule); 197 if ( RT_SUCCESS(rc)198 && RTFileExists(szPath))199 {200 RT LDRMOD hLdrMod;201 rc = RT LdrOpenEx(szPath, RTLDR_O_FOR_DEBUG, pOpts->enmLdrArch, &hLdrMod, pErrInfo);238 if (RT_SUCCESS(rc)) 239 { 240 uint32_t offError; 241 RTFSOBJINFO ObjInfo; 242 rc = RTVfsChainQueryInfo(szPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK, &offError, pErrInfo); 202 243 if (RT_SUCCESS(rc)) 203 244 { 204 pModule->hLdrMod = hLdrMod; 205 RTMsgInfo("Import '%s' -> '%s'\n", pModule->szModule, szPath); 245 if (RTFS_IS_FILE(ObjInfo.Attr.fMode)) 246 { 247 RTLDRMOD hLdrMod; 248 rc = RTLdrOpenVfsChain(szPath, RTLDR_O_FOR_DEBUG, pOpts->enmLdrArch, &hLdrMod, &offError, pErrInfo); 249 if (RT_SUCCESS(rc)) 250 { 251 pModule->hLdrMod = hLdrMod; 252 RTMsgInfo("Import '%s' -> '%s'\n", pModule->szModule, szPath); 253 } 254 else if (RTErrInfoIsSet(pErrInfo)) 255 RTMsgError("%s: Failed opening import image '%s': %Rrc - %s", pszImage, szPath, rc, pErrInfo->pszMsg); 256 else 257 RTMsgError("%s: Failed opening import image '%s': %Rrc", pszImage, szPath, rc); 258 return rc; 259 } 206 260 } 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. */ 261 else if ( rc != VERR_PATH_NOT_FOUND 262 && rc != VERR_FILE_NOT_FOUND) 263 RTVfsChainMsgError("RTVfsChainQueryInfo", szPath, rc, offError, pErrInfo); 264 265 /* 266 * Check for export file. 267 */ 268 RTStrCat(szPath, sizeof(szPath), ".exports"); 269 RTVFSFILE hVfsFile; 270 rc = RTVfsChainOpenFile(szPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hVfsFile, &offError, pErrInfo); 271 if (RT_SUCCESS(rc)) 272 { 273 /* Read it into a memory buffer. */ 274 uint64_t cbFile; 275 rc = RTVfsFileGetSize(hVfsFile, &cbFile); 276 if (RT_SUCCESS(rc)) 277 { 278 if (cbFile < _4M) 279 { 280 char *pszFile = (char *)RTMemAlloc((size_t)cbFile + 1); 281 if (pszFile) 282 { 283 rc = RTVfsFileRead(hVfsFile, pszFile, (size_t)cbFile, NULL); 284 if (RT_SUCCESS(rc)) 285 { 286 pszFile[(size_t)cbFile] = '\0'; 287 rc = RTStrValidateEncoding(pszFile); 288 if (RT_SUCCESS(rc)) 289 { 290 /* 291 * Parse it. 292 */ 293 size_t iLine = 1; 294 size_t off = 0; 295 while (off < cbFile) 296 { 297 size_t const offStartLine = off; 298 299 /* skip leading blanks */ 300 while (RT_C_IS_BLANK(pszFile[off])) 301 off++; 302 303 char ch = pszFile[off]; 304 if ( ch != ';' /* comment */ 305 && !RT_C_IS_CNTRL(ch)) 306 { 307 /* find length of symbol */ 308 size_t const offSymbol = off; 309 while ( (ch = pszFile[off]) != '\0' 310 && !RT_C_IS_SPACE(ch)) 311 off++; 312 size_t const cchSymbol = off - offSymbol; 313 314 /* add it. */ 315 if ((pModule->cExports & 127) == 0) 316 { 317 void *pvNew = RTMemRealloc(pModule->papszExports, 318 (pModule->cExports + 128) * sizeof(char *)); 319 if (!pvNew) 320 { 321 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: %s:%u: out of memory!", pszImage, szPath, iLine); 322 break; 323 } 324 pModule->papszExports = (char **)pvNew; 325 } 326 pModule->papszExports[pModule->cExports] = RTStrDupN(&pszFile[offSymbol], cchSymbol); 327 if (pModule->papszExports[pModule->cExports]) 328 pModule->cExports++; 329 else 330 { 331 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: %s:%u: out of memory!", pszImage, szPath, iLine); 332 break; 333 } 334 335 /* check what comes next is a comment or end of line/file */ 336 while (RT_C_IS_BLANK(pszFile[off])) 337 off++; 338 ch = pszFile[off]; 339 if ( ch != '\0' 340 && ch != '\n' 341 && ch != '\r' 342 && ch != ';') 343 rc = RTMsgErrorRc(VERR_PARSE_ERROR, "%s: %s:%u: Unexpected text at position %u!", 344 pszImage, szPath, iLine, off - offStartLine); 345 } 346 347 /* advance to the end of the the line */ 348 while ( (ch = pszFile[off]) != '\0' 349 && ch != '\n') 350 off++; 351 off++; 352 iLine++; 353 } 354 355 RTMsgInfo("Import '%s' -> '%s' (%u exports)\n", pModule->szModule, szPath, pModule->cExports); 356 } 357 else 358 RTMsgError("%s: %s: Invalid UTF-8 encoding in export file: %Rrc", pszImage, szPath, rc); 359 } 360 RTMemFree(pszFile); 361 } 362 else 363 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: %s: Out of memory reading export file (%#RX64 bytes)", 364 pszImage, szPath, cbFile + 1); 365 } 366 else 367 rc = RTMsgErrorRc(VERR_NO_MEMORY, "%s: %s: Export file is too big: %#RX64 bytes, max 4MiB", 368 pszImage, szPath, cbFile); 369 } 370 else 371 RTMsgError("%s: %s: RTVfsFileGetSize failed on export file: %Rrc", pszImage, szPath, rc); 372 RTVfsFileRelease(hVfsFile); 373 return rc; 374 } 375 else if ( rc != VERR_PATH_NOT_FOUND 376 && rc != VERR_FILE_NOT_FOUND) 377 RTVfsChainMsgError("RTVfsChainOpenFile", szPath, rc, offError, pErrInfo); 378 } 379 } 216 380 217 381 return RTMsgErrorRc(VERR_MODULE_NOT_FOUND, "%s: Import module '%s' was not found!", pszImage, pModule->szModule); … … 231 395 * Open the image. 232 396 */ 397 uint32_t offError; 233 398 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); 399 RTLDRMOD hLdrMod; 400 int rc = RTLdrOpenVfsChain(pszImage, 0 /*fFlags*/, RTLDRARCH_WHATEVER, &hLdrMod, &offError, RTErrInfoInitStatic(&ErrInfo)); 238 401 if (RT_FAILURE(rc)) 402 { 403 if (RT_FAILURE(rc) && RTErrInfoIsSet(&ErrInfo.Core)) 404 return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc - %s", pszImage, rc, ErrInfo.Core.pszMsg); 239 405 return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc", pszImage, rc); 406 } 240 407 241 408 /* … … 252 419 pState->pOpts = pOpts; 253 420 pState->cImports = cImports; 421 for (uint32_t iImport = 0; iImport < cImports; iImport++) 422 pState->aImports[iImport].hLdrMod = NIL_RTLDRMOD; 254 423 255 424 for (uint32_t iImport = 0; iImport < cImports; iImport++) … … 289 458 } 290 459 291 AssertCompile(NIL_RTLDRMOD == (RTLDRMOD)NULL);292 460 for (uint32_t iImport = 0; iImport < cImports; iImport++) 293 461 if (pState->aImports[iImport].hLdrMod != NIL_RTLDRMOD) 462 { 294 463 RTLdrClose(pState->aImports[iImport].hLdrMod); 464 465 size_t i = pState->aImports[iImport].cExports; 466 while (i-- > 0) 467 RTStrFree(pState->aImports[iImport].papszExports[i]); 468 RTMemFree(pState->aImports[iImport].papszExports); 469 } 295 470 RTMemFree(pState); 296 471 } … … 305 480 306 481 482 /** 483 * @callback_method_impl{FNRTLDRENUMSYMS} 484 */ 485 static DECLCALLBACK(int) PrintSymbolForExportList(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, 486 RTLDRADDR Value, void *pvUser) 487 { 488 if (pszSymbol) 489 RTPrintf("%s\n", pszSymbol); 490 else 491 RTPrintf("#%u\n", uSymbol); 492 RT_NOREF(hLdrMod, Value, pvUser); 493 return VINF_SUCCESS; 494 } 495 496 497 /** 498 * Produces the export list for the given image. 499 * 500 * @returns IPRT status code. 501 * @param pszImage Path to the image. 502 */ 503 static int ProduceExportList(const char *pszImage) 504 { 505 /* 506 * Open the image. 507 */ 508 uint32_t offError; 509 RTERRINFOSTATIC ErrInfo; 510 RTLDRMOD hLdrMod; 511 int rc = RTLdrOpenVfsChain(pszImage, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, &hLdrMod, &offError, RTErrInfoInitStatic(&ErrInfo)); 512 if (RT_SUCCESS(rc)) 513 { 514 /* 515 * Some info about the file. 516 */ 517 RTPrintf(";\n" 518 "; Generated from: %s\n", pszImage); 519 520 RTFSOBJINFO ObjInfo; 521 rc = RTVfsChainQueryInfo(pszImage, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK, NULL, NULL); 522 if (RT_SUCCESS(rc)) 523 RTPrintf("; Size file: %#RX64 (%RU64)\n", ObjInfo.cbObject, ObjInfo.cbObject); 524 525 switch (RTLdrGetFormat(hLdrMod)) 526 { 527 case RTLDRFMT_AOUT: RTPrintf("; Format: a.out\n"); break; 528 case RTLDRFMT_ELF: RTPrintf("; Format: ELF\n"); break; 529 case RTLDRFMT_LX: RTPrintf("; Format: LX\n"); break; 530 case RTLDRFMT_MACHO: RTPrintf("; Format: Mach-O\n"); break; 531 case RTLDRFMT_PE: RTPrintf("; Format: PE\n"); break; 532 default: RTPrintf("; Format: %u\n", RTLdrGetFormat(hLdrMod)); break; 533 534 } 535 536 RTPrintf("; Size of image: %#x (%u)\n", RTLdrSize(hLdrMod), RTLdrSize(hLdrMod)); 537 538 switch (RTLdrGetArch(hLdrMod)) 539 { 540 case RTLDRARCH_AMD64: RTPrintf("; Architecture: AMD64\n"); break; 541 case RTLDRARCH_X86_32: RTPrintf("; Architecture: X86\n"); break; 542 default: RTPrintf("; Architecture: %u\n", RTLdrGetArch(hLdrMod)); break; 543 } 544 545 uint64_t uTimestamp; 546 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp, sizeof(uTimestamp)); 547 if (RT_SUCCESS(rc)) 548 { 549 RTTIMESPEC Timestamp; 550 char szTime[128]; 551 RTTimeSpecToString(RTTimeSpecSetSeconds(&Timestamp, uTimestamp), szTime, sizeof(szTime)); 552 char *pszEnd = strchr(szTime, '\0'); 553 while (pszEnd[0] != '.') 554 pszEnd--; 555 *pszEnd = '\0'; 556 RTPrintf("; Timestamp: %#RX64 - %s\n", uTimestamp, szTime); 557 } 558 559 RTUUID ImageUuid; 560 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_UUID, &ImageUuid, sizeof(ImageUuid)); 561 if (RT_SUCCESS(rc)) 562 RTPrintf("; UUID: %RTuuid\n", &ImageUuid); 563 564 RTPrintf(";\n"); 565 566 /* 567 * The list of exports. 568 */ 569 rc = RTLdrEnumSymbols(hLdrMod, 0 /*fFlags*/, NULL, _4M, PrintSymbolForExportList, NULL); 570 if (RT_FAILURE(rc)) 571 RTMsgError("%s: RTLdrEnumSymbols failed: %Rrc", pszImage, rc); 572 573 /* done */ 574 RTLdrClose(hLdrMod); 575 } 576 else if (RTErrInfoIsSet(&ErrInfo.Core)) 577 RTMsgError("Failed opening image '%s': %Rrc - %s", pszImage, rc, ErrInfo.Core.pszMsg); 578 else 579 RTMsgError("Failed opening image '%s': %Rrc", pszImage, rc); 580 return rc; 581 } 582 583 307 584 int main(int argc, char **argv) 308 585 { … … 319 596 { 320 597 { "--path", 'p', RTGETOPT_REQ_STRING }, 598 { "--export", 'e', RTGETOPT_REQ_STRING }, 321 599 }; 322 600 RTGETOPTSTATE State; … … 342 620 break; 343 621 622 case 'e': 623 rc = ProduceExportList(ValueUnion.psz); 624 if (RT_FAILURE(rc)) 625 rcExit = RTEXITCODE_FAILURE; 626 break; 627 344 628 case VINF_GETOPT_NOT_OPTION: 345 629 rc = rtCheckImportsForImage(&Opts, ValueUnion.psz); … … 350 634 case 'h': 351 635 RTPrintf("Usage: RTCheckImports [-p|--path <dir>] [-h|--help] [-V|--version] <image [..]>\n" 352 "Checks library imports.\n"); 636 " or: RTCheckImports -e <image>\n" 637 "Checks library imports. VFS chain syntax supported.\n" 638 "\n" 639 "Options:\n" 640 " -p, --path <dir>\n" 641 " Search the specified directory for imported modules or their export lists.\n" 642 " -e, --export <image>\n" 643 " Write export list for the file to stdout. (Redirect to a .export file.)\n" 644 "" 645 ); 353 646 return RTEXITCODE_SUCCESS; 354 647 648 #ifndef IPRT_IN_BUILD_TOOL 355 649 case 'V': 356 650 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr()); 357 651 return RTEXITCODE_SUCCESS; 652 #endif 358 653 359 654 default:
Note:
See TracChangeset
for help on using the changeset viewer.