Changeset 45350 in vbox for trunk/src/VBox
- Timestamp:
- Apr 4, 2013 8:22:25 PM (12 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 1 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/Makefile.kmk
r45238 r45350 2502 2502 # Windows build tool. 2503 2503 # 2504 ##BLDPROGS.win = ntBldSymDb 2505 ##ntBldSymDb_TEMPLATE = VBoxAdvBldProg 2506 ##ntBldSymDb_SOURCES = r0drv/nt/ntBldSymDb.cpp 2504 BLDPROGS.win = ntBldSymDb 2505 ntBldSymDb_TEMPLATE = VBoxAdvBldProg 2506 ntBldSymDb_INCS = . 2507 ntBldSymDb_SOURCES = r0drv/nt/ntBldSymDb.cpp 2507 2508 2508 2509 # -
trunk/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp
r45211 r45350 32 32 #include <Dbghelp.h> 33 33 34 #include <iprt/alloca.h> 35 #include <iprt/dir.h> 34 36 #include <iprt/initterm.h> 37 #include <iprt/list.h> 38 #include <iprt/mem.h> 35 39 #include <iprt/message.h> 36 40 #include <iprt/path.h> 37 41 #include <iprt/stream.h> 42 #include <iprt/string.h> 38 43 #include <iprt/err.h> 39 44 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. */ 52 typedef 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. */ 68 typedef MYMEMBER *PMYMEMBER; 69 70 /** Members we're interested in. */ 71 typedef 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. */ 84 typedef 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. */ 96 typedef MYSET *PMYSET; 97 98 99 /******************************************************************************* 100 * Global Variables * 101 *******************************************************************************/ 102 /** Set if verbose operation.*/ 103 static bool g_fVerbose = false; 104 105 /** The members of the KPRCB structure that we're interested in. */ 106 static 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. */ 114 static 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. */ 120 static 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 */ 132 static 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 */ 150 static 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 */ 164 static 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 */ 176 static 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 */ 323 static 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 */ 378 static 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 */ 406 static 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 */ 451 static 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 */ 481 static 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 */ 630 static 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 654 static 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 */ 677 static 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 */ 54 710 static RTEXITCODE processOnePdb(const char *pszPdb) 55 711 { … … 59 715 */ 60 716 RTFSOBJINFO ObjInfo; 61 int rc = RTPathQueryInfo (pszPdb, &ObjInfo, RTFSOBJATTRADD_NOTHING);717 int rc = RTPathQueryInfoEx(pszPdb, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK); 62 718 if (RT_FAILURE(rc)) 63 719 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); 64 728 65 729 /* … … 71 735 return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymInitialied failed: %u\n", GetLastError()); 72 736 73 RTEXITCODE rcExit;74 737 uint64_t uModAddr = UINT64_C(0x1000000); 75 738 uModAddr = SymLoadModuleEx(hFake, NULL /*hFile*/, pszPdb, NULL /*pszModuleName*/, … … 77 740 if (uModAddr != 0) 78 741 { 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)); 80 746 81 747 /* 82 * Enumerate types.748 * Find the structures. 83 749 */ 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 91 764 if (!SymCleanup(hFake)) 92 765 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymCleanup failed: %u\n", GetLastError()); … … 95 768 96 769 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 */ 782 static 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 */ 880 static 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 97 896 int main(int argc, char **argv) 98 897 { … … 101 900 return RTMsgInitFailure(rc); 102 901 902 RTListInit(&g_SetList); 903 103 904 /* 104 905 * Parse options. … … 111 912 RTEXITCODE rcExit = processOnePdb(argv[argc - 1]); 112 913 914 if (rcExit == RTEXITCODE_SUCCESS) 915 { 916 generateHeader(g_pStdOut); 917 } 918 113 919 return rcExit; 114 920 } -
trunk/src/VBox/Runtime/r3/init.cpp
r44528 r45350 276 276 return VERR_NO_MEMORY; 277 277 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 ) 279 288 { 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++) 282 291 { 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 } 287 317 } 288 318 } 319 289 320 papszArgs[cArgs] = NULL; 290 321
Note:
See TracChangeset
for help on using the changeset viewer.