VirtualBox

Changeset 45350 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Apr 4, 2013 8:22:25 PM (12 years ago)
Author:
vboxsync
Message:

More ntBldSymDb.cpp work.

Location:
trunk/src/VBox/Runtime
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile.kmk

    r45238 r45350  
    25022502# Windows build tool.
    25032503#
    2504 ##BLDPROGS.win = ntBldSymDb
    2505 ##ntBldSymDb_TEMPLATE = VBoxAdvBldProg
    2506 ##ntBldSymDb_SOURCES = r0drv/nt/ntBldSymDb.cpp
     2504BLDPROGS.win = ntBldSymDb
     2505ntBldSymDb_TEMPLATE = VBoxAdvBldProg
     2506ntBldSymDb_INCS = .
     2507ntBldSymDb_SOURCES = r0drv/nt/ntBldSymDb.cpp
    25072508
    25082509#
  • trunk/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp

    r45211 r45350  
    3232#include <Dbghelp.h>
    3333
     34#include <iprt/alloca.h>
     35#include <iprt/dir.h>
    3436#include <iprt/initterm.h>
     37#include <iprt/list.h>
     38#include <iprt/mem.h>
    3539#include <iprt/message.h>
    3640#include <iprt/path.h>
    3741#include <iprt/stream.h>
     42#include <iprt/string.h>
    3843#include <iprt/err.h>
    3944
    40 
    41 static BOOL CALLBACK enumTypesCallback(PSYMBOL_INFO pSymInfo, ULONG cbSymbol, PVOID pvUser)
    42 {
    43     RTPrintf("pSymInfo=%p cbSymbol=%#x SizeOfStruct=%#x\n", pSymInfo, cbSymbol, pSymInfo->SizeOfStruct);
    44     RTPrintf("  TypeIndex=%#x Reserved[0]=%#llx Reserved[1]=%#llx info=%#x\n",
    45              pSymInfo->TypeIndex, pSymInfo->Reserved[0], pSymInfo->Reserved[1], pSymInfo->Index);
    46     RTPrintf("  Size=%#x ModBase=%#llx Flags=%#x Value=%#llx Address=%#llx\n",
    47              pSymInfo->Size, pSymInfo->ModBase, pSymInfo->Flags, pSymInfo->Value, pSymInfo->Address);
    48     RTPrintf("  Register=%#x Scope=%#x Tag=%#x NameLen=%#x MaxNameLen=%#x Name=%s\n",
    49              pSymInfo->Register, pSymInfo->Scope, pSymInfo->Tag, pSymInfo->NameLen, pSymInfo->MaxNameLen, pSymInfo->Name);
    50     return TRUE;
    51 }
    52 
    53 
     45#include "r0drv/nt/symdb.h"
     46
     47
     48/*******************************************************************************
     49*   Structures and Typedefs                                                    *
     50*******************************************************************************/
     51/** A structure member we're interested in. */
     52typedef struct MYMEMBER
     53{
     54    /** The member name. */
     55    const char * const          pszName;
     56    /** Reserved.  */
     57    uint32_t    const           fFlags;
     58    /** The offset of the member. UINT32_MAX if not found. */
     59    uint32_t                    off;
     60    /** The size of the member. */
     61    uint32_t                    cb;
     62    /** Alternative names, optional.
     63     * This is a string of zero terminated strings, ending with an zero length
     64     * string (or double '\\0' if you like). */
     65    const char * const          pszzAltNames;
     66} MYMEMBER;
     67/** Pointer to a member we're interested. */
     68typedef MYMEMBER *PMYMEMBER;
     69
     70/** Members we're interested in. */
     71typedef struct MYSTRUCT
     72{
     73    /** The structure name. */
     74    const char * const          pszName;
     75    /** Array of members we're interested in. */
     76    MYMEMBER                   *paMembers;
     77    /** The number of members we're interested in. */
     78    uint32_t const              cMembers;
     79    /** Reserved.  */
     80    uint32_t const              fFlags;
     81} MYSTRUCT;
     82
     83/** Set of structures for one kernel. */
     84typedef struct MYSET
     85{
     86    /** The list entry. */
     87    RTLISTNODE      ListEntry;
     88    /** The source PDB. */
     89    char           *pszPdb;
     90    /** The OS version we've harvested structs for */
     91    RTNTSDBOSVER    OsVerInfo;
     92    /** The structures and their member. */
     93    MYSTRUCT        aStructs[1];
     94} MYSET;
     95/** Pointer a set of structures for one kernel. */
     96typedef MYSET *PMYSET;
     97
     98
     99/*******************************************************************************
     100*   Global Variables                                                           *
     101*******************************************************************************/
     102/** Set if verbose operation.*/
     103static bool     g_fVerbose = false;
     104
     105/** The members of the KPRCB structure that we're interested in. */
     106static MYMEMBER g_aKprcbMembers[] =
     107{
     108    { "QuantumEnd",         0,  UINT32_MAX, UINT32_MAX, NULL },
     109    { "DpcQueueDepth",      0,  UINT32_MAX, UINT32_MAX, "DpcData[0].DpcQueueDepth\0" },
     110    { "VendorString",       0,  UINT32_MAX, UINT32_MAX, NULL },
     111};
     112
     113/** The structures we're interested in. */
     114static MYSTRUCT g_aStructs[] =
     115{
     116    { "_KPRCB", &g_aKprcbMembers[0], RT_ELEMENTS(g_aKprcbMembers), 0 },
     117};
     118
     119/** List of data we've found. This is sorted by version info. */
     120static RTLISTANCHOR g_SetList;
     121
     122
     123
     124
     125
     126/**
     127 * For debug/verbose output.
     128 *
     129 * @param   pszFormat           The format string.
     130 * @param   ...                 The arguments referenced in the format string.
     131 */
     132static void MyDbgPrintf(const char *pszFormat, ...)
     133{
     134    if (g_fVerbose)
     135    {
     136        va_list va;
     137        va_start(va, pszFormat);
     138        RTPrintf("debug: ");
     139        RTPrintfV(pszFormat, va);
     140        va_end(va);
     141    }
     142}
     143
     144
     145/**
     146 * Returns the name we wish to use in the C code.
     147 * @returns Structure name.
     148 * @param   pStruct             The structure descriptor.
     149 */
     150static const char *figureCStructName(MYSTRUCT const *pStruct)
     151{
     152    const char *psz = pStruct->pszName;
     153    while (*psz == '_')
     154        psz++;
     155    return psz;
     156}
     157
     158
     159/**
     160 * Returns the name we wish to use in the C code.
     161 * @returns Member name.
     162 * @param   pStruct             The member descriptor.
     163 */
     164static const char *figureCMemberName(MYMEMBER const *pMember)
     165{
     166    return pMember->pszName;
     167}
     168
     169
     170/**
     171 * Creates a MYSET with copies of all the data and inserts it into the
     172 * g_SetList in a orderly fashion.
     173 *
     174 * @param   pOut        The output stream.
     175 */
     176static void generateHeader(PRTSTREAM pOut)
     177{
     178    RTStrmPrintf(pOut,
     179                 "/* $" "I" "d" ": $ */\n" /* avoid it being expanded */
     180                 "/** @file\n"
     181                 " * IPRT - NT kernel type helpers - Autogenerated, do NOT edit.\n"
     182                 " */\n"
     183                 "\n"
     184                 "/*\n"
     185                 " * Copyright (C) 2013 Oracle Corporation\n"
     186                 " *\n"
     187                 " * This file is part of VirtualBox Open Source Edition (OSE), as\n"
     188                 " * available from http://www.virtualbox.org. This file is free software;\n"
     189                 " * you can redistribute it and/or modify it under the terms of the GNU\n"
     190                 " * General Public License (GPL) as published by the Free Software\n"
     191                 " * Foundation, in version 2 as it comes in the \"COPYING\" file of the\n"
     192                 " * VirtualBox OSE distribution. VirtualBox OSE is distributed in the\n"
     193                 " * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.\n"
     194                 " *\n"
     195                 " * The contents of this file may alternatively be used under the terms\n"
     196                 " * of the Common Development and Distribution License Version 1.0\n"
     197                 " * (CDDL) only, as it comes in the \"COPYING.CDDL\" file of the\n"
     198                 " * VirtualBox OSE distribution, in which case the provisions of the\n"
     199                 " * CDDL are applicable instead of those of the GPL.\n"
     200                 " *\n"
     201                 " * You may elect to license modified versions of this file under the\n"
     202                 " * terms and conditions of either the GPL or the CDDL or both.\n"
     203                 " */\n"
     204                 "\n"
     205                 "\n"
     206                 "#ifndef ___r0drv_nt_symdbdata_h\n"
     207                 "#define ___r0drv_nt_symdbdata_h\n"
     208                 "\n"
     209                 "#include \"r0drv/nt/symdb.h\"\n"
     210                 "\n"
     211                 );
     212
     213    /*
     214     * Generate types.
     215     */
     216    for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
     217    {
     218        const char *pszStructName = figureCStructName(&g_aStructs[i]);
     219
     220        RTStrmPrintf(pOut,
     221                     "typedef struct RTNTSDBTYPE_%s\n"
     222                     "{\n",
     223                     pszStructName);
     224        PMYMEMBER paMembers = g_aStructs[i].paMembers;
     225        for (uint32_t j = 0; j < g_aStructs->cMembers; j++)
     226        {
     227            const char *pszMemName = figureCMemberName(&paMembers[j]);
     228            RTStrmPrintf(pOut,
     229                         "    uint32_t off%s;\n"
     230                         "    uint32_t cb%s;\n",
     231                         pszMemName, pszMemName);
     232        }
     233
     234        RTStrmPrintf(pOut,
     235                     "} RTNTSDBTYPE_%s;\n"
     236                     "\n",
     237                     pszStructName);
     238    }
     239
     240    RTStrmPrintf(pOut,
     241                 "\n"
     242                 "typedef struct RTNTSDBSET\n"
     243                 "{\n"
     244                 "    RTNTSDBOSVER%-20s OsVerInfo;\n", "");
     245    for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
     246    {
     247        const char *pszStructName = figureCStructName(&g_aStructs[i]);
     248        RTStrmPrintf(pOut, "    RTNTSDBTYPE_%-20s %s\n", pszStructName, pszStructName);
     249    }
     250    RTStrmPrintf(pOut,
     251                 "} RTNTSDBSET;\n"
     252                 "typedef RTNTSDBSET const *PCRTNTSDBSET;\n"
     253                 "\n");
     254
     255    /*
     256     * Output the data.
     257     */
     258    RTStrmPrintf(pOut,
     259                 "\n"
     260                 "#ifndef RTNTSDB_NO_DATA\n"
     261                 "const RTNTSDBSET g_rtNtSdbSets[] = \n"
     262                 "{\n");
     263    PMYSET pSet;
     264    RTListForEach(&g_SetList, pSet, MYSET, ListEntry)
     265    {
     266        RTStrmPrintf(pOut,
     267                     "    {   /* Source: %s */\n"
     268                     "        /*.OsVerInfo = */\n"
     269                     "        {\n"
     270                     "            /* .uMajorVer = */ %u,\n"
     271                     "            /* .uMinorVer = */ %u,\n"
     272                     "            /* .fChecked  = */ %s,\n"
     273                     "            /* .fSmp      = */ %s,\n"
     274                     "            /* .uCsdNo    = */ %u,\n"
     275                     "            /* .uBuildNo  = */ %u,\n"
     276                     "        },\n",
     277                     pSet->pszPdb,
     278                     pSet->OsVerInfo.uMajorVer,
     279                     pSet->OsVerInfo.uMinorVer,
     280                     pSet->OsVerInfo.fChecked ? "true" : "false",
     281                     pSet->OsVerInfo.fSmp     ? "true" : "false",
     282                     pSet->OsVerInfo.uCsdNo,
     283                     pSet->OsVerInfo.uBuildNo);
     284        for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
     285        {
     286            const char *pszStructName = figureCStructName(&g_aStructs[i]);
     287            RTStrmPrintf(pOut,
     288                         "        /* .%s = */\n"
     289                         "        {\n", pszStructName);
     290            PMYMEMBER paMembers = g_aStructs[i].paMembers;
     291            for (uint32_t j = 0; j < g_aStructs->cMembers; j++)
     292            {
     293                const char *pszMemName = figureCMemberName(&paMembers[j]);
     294                RTStrmPrintf(pOut,
     295                             "            /* .off%-25s = */ %#06x,\n"
     296                             "            /* .cb%-26s = */ %#06x,\n",
     297                             pszMemName, paMembers[j].off,
     298                             pszMemName, paMembers[j].cb);
     299            }
     300            RTStrmPrintf(pOut,
     301                         "        },\n");
     302        }
     303        RTStrmPrintf(pOut,
     304                     "    },\n");
     305    }
     306
     307    RTStrmPrintf(pOut,
     308                 "};\n"
     309                 "#endif /* !RTNTSDB_NO_DATA */\n"
     310                 "\n");
     311
     312    RTStrmPrintf(pOut, "\n#endif\n");
     313}
     314
     315
     316/**
     317 * Creates a MYSET with copies of all the data and inserts it into the
     318 * g_SetList in a orderly fashion.
     319 *
     320 * @returns Fully complained exit code.
     321 * @param   pOsVerInfo      The OS version info.
     322 */
     323static RTEXITCODE saveStructures(PRTNTSDBOSVER pOsVerInfo, const char *pszPdb)
     324{
     325    /*
     326     * Allocate one big chunk, figure it's size once.
     327     */
     328    static size_t s_cbNeeded = 0;
     329    if (s_cbNeeded == 0)
     330    {
     331        s_cbNeeded = RT_OFFSETOF(MYSET, aStructs[RT_ELEMENTS(g_aStructs)]);
     332        for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
     333            s_cbNeeded += sizeof(MYMEMBER) * g_aStructs[i].cMembers;
     334    }
     335
     336    size_t cbPdb = strlen(pszPdb) + 1;
     337    PMYSET pSet = (PMYSET)RTMemAlloc(s_cbNeeded + cbPdb);
     338    if (!pSet)
     339        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory!\n");
     340
     341    /*
     342     * Copy over the data.
     343     */
     344    memcpy(&pSet->OsVerInfo, pOsVerInfo, sizeof(pSet->OsVerInfo));
     345    memcpy(&pSet->aStructs[0], g_aStructs, sizeof(g_aStructs));
     346
     347    PMYMEMBER pDst = (PMYMEMBER)&pSet->aStructs[RT_ELEMENTS(g_aStructs)];
     348    for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
     349    {
     350        pSet->aStructs[i].paMembers = pDst;
     351        memcpy(pDst, g_aStructs[i].paMembers, g_aStructs[i].cMembers * sizeof(*pDst));
     352        pDst += g_aStructs[i].cMembers;
     353    }
     354
     355    pSet->pszPdb = (char *)pDst;
     356    memcpy(pDst, pszPdb, cbPdb);
     357
     358    /*
     359     * Link it.
     360     */
     361    PMYSET pInsertBefore;
     362    RTListForEach(&g_SetList, pInsertBefore, MYSET, ListEntry)
     363    {
     364        if (rtNtOsVerInfoCompare(&pSet->OsVerInfo, &pInsertBefore->OsVerInfo) >= 0)
     365            break;
     366    }
     367    RTListPrepend(&pInsertBefore->ListEntry, &pSet->ListEntry);
     368
     369    return RTEXITCODE_SUCCESS;
     370}
     371
     372
     373/**
     374 * Checks that we found everything.
     375 *
     376 * @returns Fully complained exit code.
     377 */
     378static RTEXITCODE checkThatWeFoundEverything(void)
     379{
     380    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     381    for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
     382    {
     383        PMYMEMBER paMembers = g_aStructs[i].paMembers;
     384        uint32_t  j         = g_aStructs[i].cMembers;
     385        while (j-- > 0)
     386        {
     387            if (paMembers[j].off == UINT32_MAX)
     388                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, " Missing %s::%s\n", g_aStructs[i].pszName, paMembers[j].pszName);
     389        }
     390    }
     391    return rcExit;
     392}
     393
     394
     395/**
     396 * Matches the member against what we're looking for.
     397 *
     398 * @returns Number of hits.
     399 * @param   cWantedMembers  The number members in paWantedMembers.
     400 * @param   paWantedMembers The members we're looking for.
     401 * @param   pszPrefix       The member name prefix.
     402 * @param   pszMember       The member name.
     403 * @param   offMember       The member offset.
     404 * @param   cbMember        The member size.
     405 */
     406static uint32_t matchUpStructMembers(unsigned cWantedMembers, PMYMEMBER paWantedMembers,
     407                                     const char *pszPrefix, const char *pszMember,
     408                                     uint32_t offMember, uint32_t cbMember)
     409{
     410    size_t   cchPrefix = strlen(pszPrefix);
     411    uint32_t cHits     = 0;
     412    uint32_t iMember   = cWantedMembers;
     413    while (iMember-- > 0)
     414    {
     415        if (   !strncmp(pszPrefix, paWantedMembers[iMember].pszName, cchPrefix)
     416            && !strcmp(pszMember, paWantedMembers[iMember].pszName + cchPrefix))
     417        {
     418            paWantedMembers[iMember].off = offMember;
     419            paWantedMembers[iMember].cb  = cbMember;
     420            cHits++;
     421        }
     422        else if (paWantedMembers[iMember].pszzAltNames)
     423        {
     424            char const *pszCur = paWantedMembers[iMember].pszzAltNames;
     425            while (*pszCur)
     426            {
     427                size_t cchCur = strlen(pszCur);
     428                if (   !strncmp(pszPrefix, pszCur, cchPrefix)
     429                    && !strcmp(pszMember, pszCur + cchPrefix))
     430                {
     431                    paWantedMembers[iMember].off = offMember;
     432                    paWantedMembers[iMember].cb  = cbMember;
     433                    cHits++;
     434                    break;
     435                }
     436                pszCur += cchCur + 1;
     437            }
     438        }
     439    }
     440    return cHits;
     441}
     442
     443
     444/**
     445 * Resets the writable structure members prior to processing a PDB.
     446 *
     447 * While processing the PDB, will fill in the sizes and offsets of what we find.
     448 * Afterwards we'll use look for reset values to see that every structure and
     449 * member was located successfully.
     450 */
     451static void resetMyStructs(void)
     452{
     453    for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
     454    {
     455        PMYMEMBER paMembers = g_aStructs[i].paMembers;
     456        uint32_t  j         = g_aStructs[i].cMembers;
     457        while (j-- > 0)
     458        {
     459            paMembers[j].off = UINT32_MAX;
     460            paMembers[j].cb  = UINT32_MAX;
     461        }
     462    }
     463}
     464
     465
     466/**
     467 * Find members in the specified structure type (@a idxType).
     468 *
     469 * @returns Fully bitched exit code.
     470 * @param   hFake           Fake process handle.
     471 * @param   uModAddr        The module address.
     472 * @param   idxType         The type index of the structure which members we're
     473 *                          going to process.
     474 * @param   cWantedMembers  The number of wanted members.
     475 * @param   paWantedMembers The wanted members.  This will be modified.
     476 * @param   offDisp         Displacement when calculating member offsets.
     477 * @param   pszStructNm     The top level structure name.
     478 * @param   pszPrefix       The member name prefix.
     479 * @param   pszLogTag       The log tag.
     480 */
     481static RTEXITCODE findMembers(HANDLE hFake, uint64_t uModAddr, uint32_t idxType,
     482                              uint32_t cWantedMembers, PMYMEMBER paWantedMembers,
     483                              uint32_t offDisp, const char *pszStructNm, const char *pszPrefix, const char *pszLogTag)
     484{
     485    RTEXITCODE  rcExit   = RTEXITCODE_SUCCESS;
     486
     487    DWORD cChildren = 0;
     488    if (!SymGetTypeInfo(hFake, uModAddr, idxType, TI_GET_CHILDRENCOUNT, &cChildren))
     489        return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: TI_GET_CHILDRENCOUNT failed on _KPRCB: %u\n", pszLogTag, GetLastError());
     490
     491    MyDbgPrintf(" %s: cChildren=%u (%#x)\n", pszStructNm, cChildren);
     492    TI_FINDCHILDREN_PARAMS *pChildren;
     493    pChildren = (TI_FINDCHILDREN_PARAMS *)alloca(RT_OFFSETOF(TI_FINDCHILDREN_PARAMS, ChildId[cChildren]));
     494    pChildren->Start = 0;
     495    pChildren->Count = cChildren;
     496    if (!SymGetTypeInfo(hFake, uModAddr, idxType, TI_FINDCHILDREN, pChildren))
     497        return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: TI_FINDCHILDREN failed on _KPRCB: %u\n", pszLogTag, GetLastError());
     498
     499    for (uint32_t i = 0; i < cChildren; i++)
     500    {
     501        //MyDbgPrintf(" %s: child#%u: TypeIndex=%u\n", pszStructNm, i, pChildren->ChildId[i]);
     502        IMAGEHLP_SYMBOL_TYPE_INFO enmErr;
     503        PWCHAR      pwszMember = NULL;
     504        uint32_t    idxRefType = 0;
     505        uint32_t    offMember = 0;
     506        uint64_t    cbMember = 0;
     507        uint32_t    cMemberChildren = 0;
     508        if (   SymGetTypeInfo(hFake, uModAddr, pChildren->ChildId[i], enmErr = TI_GET_SYMNAME, &pwszMember)
     509            && SymGetTypeInfo(hFake, uModAddr, pChildren->ChildId[i], enmErr = TI_GET_OFFSET, &offMember)
     510            && SymGetTypeInfo(hFake, uModAddr, pChildren->ChildId[i], enmErr = TI_GET_TYPE, &idxRefType)
     511            && SymGetTypeInfo(hFake, uModAddr, idxRefType, enmErr = TI_GET_LENGTH, &cbMember)
     512            && SymGetTypeInfo(hFake, uModAddr, idxRefType, enmErr = TI_GET_CHILDRENCOUNT, &cMemberChildren)
     513            )
     514        {
     515            offMember += offDisp;
     516
     517            char *pszMember;
     518            int rc = RTUtf16ToUtf8(pwszMember, &pszMember);
     519            if (RT_SUCCESS(rc))
     520            {
     521                matchUpStructMembers(cWantedMembers, paWantedMembers, pszPrefix, pszMember, offMember, cbMember);
     522
     523                /*
     524                 * Gather more info and do some debug printing. We'll use some
     525                 * of this info below when recursing into sub-structures
     526                 * and arrays.
     527                 */
     528                uint32_t fNested      = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_NESTED, &fNested);
     529                uint32_t uDataKind    = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_DATAKIND, &uDataKind);
     530                uint32_t uBaseType    = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_BASETYPE, &uBaseType);
     531                uint32_t uMembTag     = 0; SymGetTypeInfo(hFake, uModAddr, pChildren->ChildId[i], TI_GET_SYMTAG, &uMembTag);
     532                uint32_t uBaseTag     = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_SYMTAG, &uBaseTag);
     533                uint32_t cElements    = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_COUNT, &cElements);
     534                uint32_t idxArrayType = 0; SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_ARRAYINDEXTYPEID, &idxArrayType);
     535                MyDbgPrintf(" %#06x LB %#06llx %c%c %2d %2d %2d %2d %2d %4d %s::%s%s\n",
     536                            offMember, cbMember,
     537                            cMemberChildren > 0 ? 'c' : '-',
     538                            fNested        != 0 ? 'n' : '-',
     539                            uDataKind,
     540                            uBaseType,
     541                            uMembTag,
     542                            uBaseTag,
     543                            cElements,
     544                            idxArrayType,
     545                            pszStructNm,
     546                            pszPrefix,
     547                            pszMember);
     548
     549                /*
     550                 * Recurse into children.
     551                 */
     552                if (cMemberChildren > 0)
     553                {
     554                    size_t cbNeeded = strlen(pszMember) + strlen(pszPrefix) + sizeof(".");
     555                    char *pszSubPrefix = (char *)RTMemTmpAlloc(cbNeeded);
     556                    if (pszSubPrefix)
     557                    {
     558                        strcat(strcat(strcpy(pszSubPrefix, pszPrefix), pszMember), ".");
     559                        RTEXITCODE rcExit2 = findMembers(hFake, uModAddr, idxRefType, cWantedMembers,
     560                                                         paWantedMembers, offMember,
     561                                                         pszStructNm,
     562                                                         pszSubPrefix,
     563                                                         pszLogTag);
     564                        if (rcExit2 != RTEXITCODE_SUCCESS)
     565                            rcExit = rcExit2;
     566                        RTMemTmpFree(pszSubPrefix);
     567                    }
     568                    else
     569                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory\n");
     570                }
     571                /*
     572                 * Recurse into arrays too.
     573                 */
     574                else if (cElements > 0 && idxArrayType > 0)
     575                {
     576                    BOOL fRc;
     577                    uint32_t idxElementRefType = 0;
     578                    fRc = SymGetTypeInfo(hFake, uModAddr, idxRefType, TI_GET_TYPE, &idxElementRefType); Assert(fRc);
     579                    uint64_t cbElement = cbMember / cElements;
     580                    fRc = SymGetTypeInfo(hFake, uModAddr, idxElementRefType, TI_GET_LENGTH, &cbElement); Assert(fRc);
     581                    MyDbgPrintf("idxArrayType=%u idxElementRefType=%u cbElement=%u\n", idxArrayType, idxElementRefType, cbElement);
     582
     583                    size_t cbNeeded = strlen(pszMember) + strlen(pszPrefix) + sizeof("[xxxxxxxxxxxxxxxx].");
     584                    char *pszSubPrefix = (char *)RTMemTmpAlloc(cbNeeded);
     585                    if (pszSubPrefix)
     586                    {
     587                        for (uint32_t iElement = 0; iElement < cElements; iElement++)
     588                        {
     589                            RTStrPrintf(pszSubPrefix, cbNeeded, "%s%s[%u].", pszPrefix, pszMember, iElement);
     590                            RTEXITCODE rcExit2 = findMembers(hFake, uModAddr, idxElementRefType, cWantedMembers,
     591                                                             paWantedMembers,
     592                                                             offMember + iElement * cbElement,
     593                                                             pszStructNm,
     594                                                             pszSubPrefix,
     595                                                             pszLogTag);
     596                            if (rcExit2 != RTEXITCODE_SUCCESS)
     597                                rcExit = rcExit2;
     598                        }
     599                        RTMemTmpFree(pszSubPrefix);
     600                    }
     601                    else
     602                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory\n");
     603                }
     604
     605                RTStrFree(pszMember);
     606            }
     607            else
     608                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: RTUtf16ToUtf8 failed on %s child#%u: %Rrc\n",
     609                                        pszLogTag, pszStructNm, i, rc);
     610        }
     611        /* TI_GET_OFFSET fails on bitfields, so just ignore+skip those. */
     612        else if (enmErr != TI_GET_OFFSET || GetLastError() != ERROR_INVALID_FUNCTION)
     613            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: SymGetTypeInfo(,,,%d,) failed on %s child#%u: %u\n",
     614                                    pszLogTag, enmErr, pszStructNm, i, GetLastError());
     615        LocalFree(pwszMember);
     616    } /* For each child. */
     617
     618    return rcExit;
     619}
     620
     621
     622/**
     623 * Lookup up structures and members in the given module.
     624 *
     625 * @returns Fully bitched exit code.
     626 * @param   hFake           Fake process handle.
     627 * @param   uModAddr        The module address.
     628 * @param   pszLogTag       The log tag.
     629 */
     630static RTEXITCODE findStructures(HANDLE hFake, uint64_t uModAddr, const char *pszLogTag)
     631{
     632    RTEXITCODE   rcExit   = RTEXITCODE_SUCCESS;
     633    PSYMBOL_INFO pSymInfo = (PSYMBOL_INFO)alloca(sizeof(*pSymInfo));
     634    for (uint32_t iStruct = 0; iStruct < RT_ELEMENTS(g_aStructs); iStruct++)
     635    {
     636        pSymInfo->SizeOfStruct = sizeof(*pSymInfo);
     637        pSymInfo->MaxNameLen   = 0;
     638        if (!SymGetTypeFromName(hFake, uModAddr, g_aStructs[iStruct].pszName, pSymInfo))
     639            return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to find _KPRCB: %u\n", pszLogTag, GetLastError());
     640
     641        MyDbgPrintf(" %s: TypeIndex=%u\n", g_aStructs[iStruct].pszName, pSymInfo->TypeIndex);
     642        MyDbgPrintf(" %s: Size=%u (%#x)\n", g_aStructs[iStruct].pszName, pSymInfo->Size, pSymInfo->Size);
     643
     644        rcExit = findMembers(hFake, uModAddr, pSymInfo->TypeIndex,
     645                             g_aStructs[iStruct].cMembers, g_aStructs[iStruct].paMembers, 0 /* offDisp */,
     646                             g_aStructs[iStruct].pszName, "", pszLogTag);
     647        if (rcExit != RTEXITCODE_SUCCESS)
     648            return rcExit;
     649    } /* for each struct we want */
     650    return rcExit;
     651}
     652
     653
     654static bool strIEndsWith(const char *pszString, const char *pszSuffix)
     655{
     656    size_t cchString = strlen(pszString);
     657    size_t cchSuffix = strlen(pszSuffix);
     658    if (cchString < cchSuffix)
     659        return false;
     660    return RTStrICmp(pszString + cchString - cchSuffix, pszSuffix) == 0;
     661}
     662
     663
     664/**
     665 * Use various hysterics to figure out the OS version details from the PDB path.
     666 *
     667 * This ASSUMES quite a bunch of things:
     668 *      -# Working on unpacked symbol packages. This does not work for
     669 *         windbg symbol stores/caches.
     670 *      -# The symbol package has been unpacked into a directory with the same
     671 *       name as the symbol package (sans suffixes).
     672 *
     673 * @returns Fully complained exit code.
     674 * @param   pszPdb              The path to the PDB.
     675 * @param   pVerInfo            Where to return the version info.
     676 */
     677static RTEXITCODE FigurePdbVersionInfo(const char *pszPdb, PRTNTSDBOSVER pVerInfo)
     678{
     679    const char *pszFilename = RTPathFilename(pszPdb);
     680
     681    if (!RTStrICmp(pszFilename, "ntkrnlmp.pdb"))
     682        pVerInfo->fSmp = true;
     683    else if (!RTStrICmp(pszFilename, "ntoskrnl.pdb"))
     684        pVerInfo->fSmp = false;
     685    else
     686        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Doesn't recognize the filename '%s'...", pszFilename);
     687
     688    /* testing only */
     689    if (strIEndsWith(pszPdb, "ntkrnlmp.pdb\\B2DA40502FA744C18B9022FD187ADB592\\ntkrnlmp.pdb"))
     690    {
     691        pVerInfo->uMajorVer = 6;
     692        pVerInfo->uMinorVer = 1;
     693        pVerInfo->fChecked  = false;
     694        pVerInfo->uCsdNo    = 1;
     695        pVerInfo->uBuildNo  = 7601;
     696    }
     697    else
     698        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Giving up on '%s'...\n", pszPdb);
     699
     700    return RTEXITCODE_SUCCESS;
     701}
     702
     703
     704/**
     705 * Process one PDB.
     706 *
     707 * @returns Fully bitched exit code.
     708 * @param   pszPdb              The path to the PDB.
     709 */
    54710static RTEXITCODE processOnePdb(const char *pszPdb)
    55711{
     
    59715     */
    60716    RTFSOBJINFO ObjInfo;
    61     int rc = RTPathQueryInfo(pszPdb, &ObjInfo, RTFSOBJATTRADD_NOTHING);
     717    int rc = RTPathQueryInfoEx(pszPdb, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
    62718    if (RT_FAILURE(rc))
    63719        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathQueryInfo fail on '%s': %Rrc\n", pszPdb, rc);
     720
     721    /*
     722     * Figure the windows version details for the given PDB.
     723     */
     724    RTNTSDBOSVER OsVerInfo;
     725    RTEXITCODE rcExit = FigurePdbVersionInfo(pszPdb, &OsVerInfo);
     726    if (rcExit != RTEXITCODE_SUCCESS)
     727        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to figure the OS version info for '%s'.\n'", pszPdb);
    64728
    65729    /*
     
    71735        return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymInitialied failed: %u\n", GetLastError());
    72736
    73     RTEXITCODE rcExit;
    74737    uint64_t uModAddr = UINT64_C(0x1000000);
    75738    uModAddr = SymLoadModuleEx(hFake, NULL /*hFile*/, pszPdb, NULL /*pszModuleName*/,
     
    77740    if (uModAddr != 0)
    78741    {
    79         RTPrintf("debug: uModAddr=%#llx\n", uModAddr);
     742        MyDbgPrintf("*** uModAddr=%#llx \"%s\" ***\n", uModAddr, pszPdb);
     743
     744        char szLogTag[32];
     745        RTStrCopy(szLogTag, sizeof(szLogTag), RTPathFilename(pszPdb));
    80746
    81747        /*
    82          * Enumerate types.
     748         * Find the structures.
    83749         */
    84         if (SymEnumTypes(hFake, uModAddr, enumTypesCallback, NULL))
    85         {
    86             rcExit = RTEXITCODE_SUCCESS;
    87         }
    88         else
    89             rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymEnumTypes failed: %u\n", GetLastError());
    90     }
     750        rcExit = findStructures(hFake, uModAddr, szLogTag);
     751        if (rcExit == RTEXITCODE_SUCCESS)
     752            rcExit = checkThatWeFoundEverything();
     753        if (rcExit == RTEXITCODE_SUCCESS)
     754        {
     755            /*
     756             * Save the details for later when we produce the header.
     757             */
     758            rcExit = saveStructures(&OsVerInfo, pszPdb);
     759        }
     760    }
     761    else
     762        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymLoadModuleEx failed: %u\n", GetLastError());
     763
    91764    if (!SymCleanup(hFake))
    92765        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymCleanup failed: %u\n", GetLastError());
     
    95768
    96769
     770/** The size of the directory entry buffer we're using.  */
     771#define MY_DIRENTRY_BUF_SIZE (sizeof(RTDIRENTRYEX) + RTPATH_MAX)
     772
     773
     774/**
     775 * Recursively processes relevant files in the specified directory.
     776 *
     777 * @returns Fully complained exit code.
     778 * @param   pszDir              Pointer to the directory buffer.
     779 * @param   cchDir              The length of pszDir in pszDir.
     780 * @param   pDirEntry           Pointer to the directory buffer.
     781 */
     782static RTEXITCODE processDirSub(char *pszDir, size_t cchDir, PRTDIRENTRYEX pDirEntry)
     783{
     784    Assert(cchDir > 0); Assert(pszDir[cchDir] == '\0');
     785
     786    /* Make sure we've got some room in the path, to save us extra work further down. */
     787    if (cchDir + 3 >= RTPATH_MAX)
     788        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Path too long: '%s'\n", pszDir);
     789
     790    /* Open directory. */
     791    PRTDIR pDir;
     792    int rc = RTDirOpen(&pDir, pszDir);
     793    if (RT_FAILURE(rc))
     794        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirOpen failed on '%s': %Rrc\n", pszDir, rc);
     795
     796    /* Ensure we've got a trailing slash (there is space for it see above). */
     797    if (!RTPATH_IS_SEP(pszDir[cchDir - 1]))
     798    {
     799        pszDir[cchDir++] = RTPATH_SLASH;
     800        pszDir[cchDir]   = '\0';
     801    }
     802
     803    /*
     804     * Process the files and subdirs.
     805     */
     806    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     807    for (;;)
     808    {
     809        /* Get the next directory. */
     810        size_t cbDirEntry = MY_DIRENTRY_BUF_SIZE;
     811        rc = RTDirReadEx(pDir, pDirEntry, &cbDirEntry, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
     812        if (RT_FAILURE(rc))
     813            break;
     814
     815        /* Skip the dot and dot-dot links. */
     816        if (   (pDirEntry->cbName == 1 && pDirEntry->szName[0] == '.')
     817            || (pDirEntry->cbName == 2 && pDirEntry->szName[0] == '.' && pDirEntry->szName[1] == '.'))
     818            continue;
     819
     820        /* Check length. */
     821        if (pDirEntry->cbName + cchDir + 3 >= RTPATH_MAX)
     822        {
     823            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Path too long: '%s' in '%.*s'\n", pDirEntry->szName, cchDir, pszDir);
     824            break;
     825        }
     826
     827        if (RTFS_IS_FILE(pDirEntry->Info.Attr.fMode))
     828        {
     829            /* Is this a file which might interest us? */
     830            static struct { const char *psz; size_t cch; } const s_aNames[] =
     831            {
     832                RT_STR_TUPLE("ntoskrnl.dbg"),
     833                RT_STR_TUPLE("ntoskrnl.pdb"),
     834                RT_STR_TUPLE("ntkrnlmp.dbg"),
     835                RT_STR_TUPLE("ntkrnlmp.pdb"),
     836            };
     837            int i = RT_ELEMENTS(s_aNames);
     838            while (i-- > 0)
     839                if (   s_aNames[i].cch == pDirEntry->cbName
     840                    && !RTStrICmp(s_aNames[i].psz, pDirEntry->szName))
     841                {
     842                    /*
     843                     * Found debug info file of interest, process it.
     844                     */
     845                    memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);
     846                    RTEXITCODE rcExit2 = processOnePdb(pszDir);
     847                    if (rcExit2 != RTEXITCODE_SUCCESS)
     848                        rcExit = rcExit2;
     849                    break;
     850                }
     851        }
     852        else if (RTFS_IS_DIRECTORY(pDirEntry->Info.Attr.fMode))
     853        {
     854            /*
     855             * Recurse into the subdirectory.
     856             * Note! When we get back pDirEntry will be invalid.
     857             */
     858            memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);
     859            RTEXITCODE rcExit2 = processDirSub(pszDir, cchDir + pDirEntry->cbName, pDirEntry);
     860            if (rcExit2 != RTEXITCODE_SUCCESS)
     861                rcExit = rcExit2;
     862        }
     863    }
     864    if (rc != VERR_NO_MORE_FILES)
     865        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirReadEx failed: %Rrc\npszDir=%.*s", rc, cchDir, pszDir);
     866
     867    rc = RTDirClose(pDir);
     868    if (RT_FAILURE(rc))
     869        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDirClose failed: %Rrc\npszDir=%.*s", rc, cchDir, pszDir);
     870    return rcExit;
     871}
     872
     873
     874/**
     875 * Recursively processes relevant files in the specified directory.
     876 *
     877 * @returns Fully complained exit code.
     878 * @param   pszDir              The directory to search.
     879 */
     880static RTEXITCODE processDir(const char *pszDir)
     881{
     882    char szPath[RTPATH_MAX];
     883    int rc = RTPathAbs(pszDir, szPath, sizeof(szPath));
     884    if (RT_FAILURE(rc))
     885        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on '%s': %Rrc\n", pszDir, rc);
     886
     887    union
     888    {
     889        uint8_t         abPadding[MY_DIRENTRY_BUF_SIZE];
     890        RTDIRENTRYEX    DirEntry;
     891    } uBuf;
     892    return processDirSub(szPath, strlen(szPath), &uBuf.DirEntry);
     893}
     894
     895
    97896int main(int argc, char **argv)
    98897{
     
    101900        return RTMsgInitFailure(rc);
    102901
     902    RTListInit(&g_SetList);
     903
    103904    /*
    104905     * Parse options.
     
    111912    RTEXITCODE rcExit = processOnePdb(argv[argc - 1]);
    112913
     914    if (rcExit == RTEXITCODE_SUCCESS)
     915    {
     916        generateHeader(g_pStdOut);
     917    }
     918
    113919    return rcExit;
    114920}
  • trunk/src/VBox/Runtime/r3/init.cpp

    r44528 r45350  
    276276            return VERR_NO_MEMORY;
    277277
    278         for (int i = 0; i < cArgs; i++)
     278#ifdef RT_OS_WINDOWS
     279        /* HACK ALERT! Try convert from unicode versions if possible.
     280           Unfortunately for us, __wargv is only initialized if we have a
     281           unicode main function.  So, we have to use CommandLineToArgvW to get
     282           something similar. It should do the same conversion... :-) */
     283        int    cArgsW     = -1;
     284        PWSTR *papwszArgs = NULL;
     285        if (   papszOrgArgs == __argv
     286            && cArgs        == __argc
     287            && (papwszArgs = CommandLineToArgvW(GetCommandLineW(), &cArgsW)) != NULL )
    279288        {
    280             int rc = RTStrCurrentCPToUtf8(&papszArgs[i], papszOrgArgs[i]);
    281             if (RT_FAILURE(rc))
     289            AssertMsg(cArgsW == cArgs, ("%d vs %d\n", cArgsW, cArgs));
     290            for (int i = 0; i < cArgs; i++)
    282291            {
    283                 while (i--)
    284                     RTStrFree(papszArgs[i]);
    285                 RTMemFree(papszArgs);
    286                 return rc;
     292                int rc = RTUtf16ToUtf8(papwszArgs[i], &papszArgs[i]);
     293                if (RT_FAILURE(rc))
     294                {
     295                    while (i--)
     296                        RTStrFree(papszArgs[i]);
     297                    RTMemFree(papszArgs);
     298                    LocalFree(papwszArgs);
     299                    return rc;
     300                }
     301            }
     302            LocalFree(papwszArgs);
     303        }
     304        else
     305#endif
     306        {
     307            for (int i = 0; i < cArgs; i++)
     308            {
     309                int rc = RTStrCurrentCPToUtf8(&papszArgs[i], papszOrgArgs[i]);
     310                if (RT_FAILURE(rc))
     311                {
     312                    while (i--)
     313                        RTStrFree(papszArgs[i]);
     314                    RTMemFree(papszArgs);
     315                    return rc;
     316                }
    287317            }
    288318        }
     319
    289320        papszArgs[cArgs] = NULL;
    290321
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