VirtualBox

Ignore:
Timestamp:
Dec 22, 2017 11:47:24 AM (7 years ago)
Author:
vboxsync
Message:

RTLdrCheckImports: Implemented export lists and made it a build tool.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/tools/RTLdrCheckImports.cpp

    r70293 r70311  
    2929*   Header Files                                                                                                                 *
    3030*********************************************************************************************************************************/
     31#define RTMEM_WRAP_TO_EF_APIS
     32#include <iprt/ctype.h>
    3133#include <iprt/err.h>
    3234#include <iprt/getopt.h>
     
    4042#include <iprt/string.h>
    4143#include <iprt/stream.h>
     44#include <iprt/vfs.h>
    4245
    4346
     
    7376    size_t      cExports;
    7477    /** Export list. (NULL if hLdrMod is valid.)   */
    75     char       *papszExports;
     78    char      **papszExports;
    7679    /** The module name. */
    7780    char        szModule[256];
     
    105108
    106109/**
     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 */
     118static 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/**
    107145 * @callback_method_impl{FNRTLDRIMPORT}
    108146 */
     
    131169        }
    132170
    133         rc = RTLdrGetSymbolEx(pState->aImports[iModule].hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);
     171        rc = QuerySymbolFromImportModule(&pState->aImports[iModule], pszSymbol, uSymbol, pValue);
    134172        if (RT_SUCCESS(rc))
    135173        { /* likely */ }
     
    155193        uint32_t iModule = pState->iHint;
    156194        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);
    158196        else
    159197            rc = VERR_SYMBOL_NOT_FOUND;
     
    162200            for (iModule = 0; iModule < pState->cImports; iModule++)
    163201            {
    164                 rc = RTLdrGetSymbolEx(pState->aImports[iModule].hLdrMod, NULL, _128M, uSymbol, pszSymbol, pValue);
     202                rc = QuerySymbolFromImportModule(&pState->aImports[iModule], pszSymbol, uSymbol, pValue);
    165203                if (rc != VERR_SYMBOL_NOT_FOUND)
    166204                    break;
     
    191229
    192230{
     231    /*
     232     * Look for real DLLs.
     233     */
    193234    for (uint32_t iPath = 0; iPath < pOpts->cPaths; iPath++)
    194235    {
    195         char szPath[RTPATH_MAX];
     236        char        szPath[RTPATH_MAX];
    196237        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);
     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);
    202243            if (RT_SUCCESS(rc))
    203244            {
    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                }
    206260            }
    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    }
    216380
    217381    return RTMsgErrorRc(VERR_MODULE_NOT_FOUND, "%s: Import module '%s' was not found!", pszImage, pModule->szModule);
     
    231395     * Open the image.
    232396     */
     397    uint32_t        offError;
    233398    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));
    238401    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);
    239405        return RTMsgErrorRc(rc, "Failed opening image '%s': %Rrc", pszImage, rc);
     406    }
    240407
    241408    /*
     
    252419            pState->pOpts    = pOpts;
    253420            pState->cImports = cImports;
     421            for (uint32_t iImport = 0; iImport < cImports; iImport++)
     422                pState->aImports[iImport].hLdrMod = NIL_RTLDRMOD;
    254423
    255424            for (uint32_t iImport = 0; iImport < cImports; iImport++)
     
    289458            }
    290459
    291             AssertCompile(NIL_RTLDRMOD == (RTLDRMOD)NULL);
    292460            for (uint32_t iImport = 0; iImport < cImports; iImport++)
    293461                if (pState->aImports[iImport].hLdrMod != NIL_RTLDRMOD)
     462                {
    294463                    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                }
    295470            RTMemFree(pState);
    296471        }
     
    305480
    306481
     482/**
     483 * @callback_method_impl{FNRTLDRENUMSYMS}
     484 */
     485static 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 */
     503static 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
    307584int main(int argc, char **argv)
    308585{
     
    319596    {
    320597        { "--path", 'p', RTGETOPT_REQ_STRING },
     598        { "--export", 'e', RTGETOPT_REQ_STRING },
    321599    };
    322600    RTGETOPTSTATE State;
     
    342620                break;
    343621
     622            case 'e':
     623                rc = ProduceExportList(ValueUnion.psz);
     624                if (RT_FAILURE(rc))
     625                    rcExit = RTEXITCODE_FAILURE;
     626                break;
     627
    344628            case VINF_GETOPT_NOT_OPTION:
    345629                rc = rtCheckImportsForImage(&Opts, ValueUnion.psz);
     
    350634            case 'h':
    351635                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                         );
    353646                return RTEXITCODE_SUCCESS;
    354647
     648#ifndef IPRT_IN_BUILD_TOOL
    355649            case 'V':
    356650                RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
    357651                return RTEXITCODE_SUCCESS;
     652#endif
    358653
    359654            default:
Note: See TracChangeset for help on using the changeset viewer.

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