Changeset 46269 in vbox for trunk/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp
- Timestamp:
- May 26, 2013 3:27:31 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp
r46266 r46269 2 2 /** @file 3 3 * IPRT - Debug Module Reader For Microsoft CodeView. 4 * 5 * Based on the following documentation (plus guess work and googling): 6 * 7 * - "Tools Interface Standard (TIS) Formats Specification for Windows", 8 * dated February 1993, version 1.0. 9 * 10 * - "Visual C++ 5.0 Symbolic Debug Information Specification" chapter of 11 * SPECS.CHM from MSDN Library October 2001. 12 * 13 * - "High Level Languages Debug Table Documentation", aka HLLDBG.HTML, aka 14 * IBMHLL.HTML, last changed 1996-07-08. 4 15 */ 5 16 … … 43 54 #include <iprt/path.h> 44 55 #include <iprt/string.h> 56 #include <iprt/strcache.h> 45 57 #include "internal/dbgmod.h" 46 58 #include "internal/ldrPE.h" … … 57 69 typedef struct RTCVHDR 58 70 { 59 /** The magic ('NBxx') . */71 /** The magic ('NBxx'), see RTCVHDR_MAGIC_XXX. */ 60 72 uint32_t u32Magic; 61 73 /** … … 69 81 /** Pointer to a CodeView header. */ 70 82 typedef RTCVHDR *PRTCVHDR; 83 84 /** @name CodeView magic values (RTCVHDR::u32Magic). 85 * @{ */ 86 /** CodeView from Visual C++ 5.0. Specified in the 2001 MSDN specs.chm file. */ 87 #define RTCVHDR_MAGIC_NB11 RT_MAKE_U32_FROM_U8('N', 'B', '1', '1') 88 /** External PDB reference (often referred to as PDB 2.0). */ 89 #define RTCVHDR_MAGIC_NB10 RT_MAKE_U32_FROM_U8('N', 'B', '1', '0') 90 /** CodeView v4.10, packed. Specified in the TIS document. */ 91 #define RTCVHDR_MAGIC_NB09 RT_MAKE_U32_FROM_U8('N', 'B', '0', '9') 92 /** CodeView v4.00 thru v4.05. Specified in the TIS document? */ 93 #define RTCVHDR_MAGIC_NB08 RT_MAKE_U32_FROM_U8('N', 'B', '0', '8') 94 /** Quick C for Windows 1.0 debug info. */ 95 #define RTCVHDR_MAGIC_NB07 RT_MAKE_U32_FROM_U8('N', 'B', '0', '7') 96 /** Emitted by ILINK indicating incremental link. Comparable to NB05? */ 97 #define RTCVHDR_MAGIC_NB06 RT_MAKE_U32_FROM_U8('N', 'B', '0', '6') 98 /** Emitted by LINK version 5.20 and later before packing. */ 99 #define RTCVHDR_MAGIC_NB05 RT_MAKE_U32_FROM_U8('N', 'B', '0', '5') 100 /** Emitted by IBM ILINK for HLL (similar to NB02 in many ways). */ 101 #define RTCVHDR_MAGIC_NB04 RT_MAKE_U32_FROM_U8('N', 'B', '0', '4') 102 /** Emitted by LINK version 5.10 (or similar OMF linkers), as shipped with 103 * Microsoft C v6.0 for example. More or less entirely 16-bit. */ 104 #define RTCVHDR_MAGIC_NB02 RT_MAKE_U32_FROM_U8('N', 'B', '0', '2') 105 /* No idea what NB03 might have been. */ 106 /** AIX debugger format according to "IBM OS/2 16/32-bit Object Module Format 107 * (OMF) and Linear eXecutable Module Format (LX)" revision 10 (LXOMF.PDF). */ 108 #define RTCVHDR_MAGIC_NB01 RT_MAKE_U32_FROM_U8('N', 'B', '0', '1') 109 /** Ancient CodeView format according to LXOMF.PDF. */ 110 #define RTCVHDR_MAGIC_NB00 RT_MAKE_U32_FROM_U8('N', 'B', '0', '0') 111 /** @} */ 71 112 72 113 … … 216 257 217 258 218 /** @name CodeView magic values. 219 * @{ */ 220 /** CodeView from Visual C++ 5.0. Specified in the 2001 MSDN specs.chm file. */ 221 #define RTCVHDR_MAGIC_NB11 RT_MAKE_U32_FROM_U8('N', 'B', '1', '1') 222 /** External PDB reference (often referred to as PDB 2.0). */ 223 #define RTCVHDR_MAGIC_NB10 RT_MAKE_U32_FROM_U8('N', 'B', '1', '0') 224 /** CodeView v4.10, packed. Specified in the TIS document. */ 225 #define RTCVHDR_MAGIC_NB09 RT_MAKE_U32_FROM_U8('N', 'B', '0', '9') 226 /** CodeView v4.00 thru v4.05. Specified in the TIS document? */ 227 #define RTCVHDR_MAGIC_NB08 RT_MAKE_U32_FROM_U8('N', 'B', '0', '8') 228 /** Quick C for Windows 1.0 debug info. */ 229 #define RTCVHDR_MAGIC_NB07 RT_MAKE_U32_FROM_U8('N', 'B', '0', '7') 230 /** Emitted by ILINK indicating incremental link. Comparable to NB05? */ 231 #define RTCVHDR_MAGIC_NB06 RT_MAKE_U32_FROM_U8('N', 'B', '0', '6') 232 /** Emitted by LINK version 5.20 and later before packing. */ 233 #define RTCVHDR_MAGIC_NB05 RT_MAKE_U32_FROM_U8('N', 'B', '0', '5') 234 /** Emitted by IBM ILINK for HLL (similar to NB02 in many ways). */ 235 #define RTCVHDR_MAGIC_NB04 RT_MAKE_U32_FROM_U8('N', 'B', '0', '4') 236 /** Emitted by LINK version 5.10 (or similar OMF linkers), as shipped with 237 * Microsoft C v6.0 for example. More or less entirely 16-bit. */ 238 #define RTCVHDR_MAGIC_NB02 RT_MAKE_U32_FROM_U8('N', 'B', '0', '2') 239 /* No idea what NB03 might have been. */ 240 /** AIX debugger format according to "IBM OS/2 16/32-bit Object Module Format 241 * (OMF) and Linear eXecutable Module Format (LX)" revision 10 (LXOMF.PDF). */ 242 #define RTCVHDR_MAGIC_NB01 RT_MAKE_U32_FROM_U8('N', 'B', '0', '1') 243 /** Ancient CodeView format according to LXOMF.PDF. */ 244 #define RTCVHDR_MAGIC_NB00 RT_MAKE_U32_FROM_U8('N', 'B', '0', '0') 259 /** 260 * CV4 module segment info. 261 */ 262 typedef struct RTCVMODSEGINFO32 263 { 264 /** The segment number. */ 265 uint16_t iSeg; 266 /** Explicit padding. */ 267 uint16_t u16Padding; 268 /** Offset into the segment. */ 269 uint32_t off; 270 /** The size of the contribution. */ 271 uint32_t cb; 272 } RTCVMODSEGINFO32; 273 typedef RTCVMODSEGINFO32 *PRTCVMODSEGINFO32; 274 typedef RTCVMODSEGINFO32 const *PCRTCVMODSEGINFO32; 275 276 277 /** 278 * CV4 segment map header. 279 */ 280 typedef struct RTCVSEGMAPHDR 281 { 282 /** Number of segments descriptors in the table. */ 283 uint16_t cSegs; 284 /** Number of logical segment descriptors. */ 285 uint16_t cLogSegs; 286 } RTCVSEGMAPHDR; 287 /** Pointer to a CV4 segment map header. */ 288 typedef RTCVSEGMAPHDR *PRTCVSEGMAPHDR; 289 /** Pointer to a const CV4 segment map header. */ 290 typedef RTCVSEGMAPHDR const *PCRTCVSEGMAPHDR; 291 292 /** 293 * CV4 Segment map descriptor entry. 294 */ 295 typedef struct RTCVSEGMAPDESC 296 { 297 /** Segment flags. */ 298 uint16_t fFlags; 299 /** The overlay number. */ 300 uint16_t iOverlay; 301 /** Group index into this segment descriptor array. 0 if not relevant. 302 * The group descriptors are found in the second half of the table. */ 303 uint16_t iGroup; 304 /** Complicated. */ 305 uint16_t iFrame; 306 /** Offset (byte) into the kCvSst_SegName table of the segment name, or 307 * 0xffff. */ 308 uint16_t offSegName; 309 /** Offset (byte) into the kCvSst_SegName table of the class name, or 0xffff. */ 310 uint16_t offClassName; 311 /** Offset into the physical segment. */ 312 uint32_t off; 313 /** Size of segment. */ 314 uint32_t cb; 315 } RTCVSEGMAPDESC; 316 /** Pointer to a segment map descriptor entry. */ 317 typedef RTCVSEGMAPDESC *PRTCVSEGMAPDESC; 318 /** Pointer to a const segment map descriptor entry. */ 319 typedef RTCVSEGMAPDESC const *PCRTCVSEGMAPDESC; 320 321 /** @name RTCVSEGMAPDESC_F_XXX - RTCVSEGMAPDESC::fFlags values. 322 * @{ */ 323 #define RTCVSEGMAPDESC_F_READ UINT16_C(0x0001) 324 #define RTCVSEGMAPDESC_F_WRITE UINT16_C(0x0002) 325 #define RTCVSEGMAPDESC_F_EXECUTE UINT16_C(0x0004) 326 #define RTCVSEGMAPDESC_F_32BIT UINT16_C(0x0008) 327 #define RTCVSEGMAPDESC_F_SEL UINT16_C(0x0100) 328 #define RTCVSEGMAPDESC_F_ABS UINT16_C(0x0200) 329 #define RTCVSEGMAPDESC_F_GROUP UINT16_C(0x1000) 330 #define RTCVSEGMAPDESC_F_RESERVED UINT16_C(0xecf0) 245 331 /** @} */ 332 333 /** 334 * CV4 segment map subsection. 335 */ 336 typedef struct RTCVSEGMAP 337 { 338 /** The header. */ 339 RTCVSEGMAPHDR Hdr; 340 /** Descriptor array. */ 341 RTCVSEGMAPDESC aDescs[1]; 342 } RTCVSEGMAP; 343 /** Pointer to a segment map subsection. */ 344 typedef RTCVSEGMAP *PRTCVSEGMAP; 345 /** Pointer to a const segment map subsection. */ 346 typedef RTCVSEGMAP const *PCRTCVSEGMAP; 347 348 349 /** 350 * Global symbol table header, used by kCvSst_GlobalSym and kCvSst_GlobalPub. 351 */ 352 typedef struct RTCVGLOBALSYMTABHDR 353 { 354 /** The symbol hash function. */ 355 uint16_t uSymHash; 356 /** The address hash function. */ 357 uint16_t uAddrHash; 358 /** The amount of symbol information following immediately after the header. */ 359 uint32_t cbSymbols; 360 /** The amount of symbol hash tables following the symbols. */ 361 uint32_t cbSymHash; 362 /** The amount of address hash tables following the symbol hash tables. */ 363 uint32_t cbAddrHash; 364 } RTCVGLOBALSYMTABHDR; 365 /** Pointer to a global symbol table header. */ 366 typedef RTCVGLOBALSYMTABHDR *PRTCVGLOBALSYMTABHDR; 367 /** Pointer to a const global symbol table header. */ 368 typedef RTCVGLOBALSYMTABHDR const *PCRTCVGLOBALSYMTABHDR; 369 370 371 typedef enum RTCVSYMTYPE 372 { 373 /** @name Symbols that doesn't change with compilation model or target machine. 374 * @{ */ 375 kCvSymType_Compile = 0x0001, 376 kCvSymType_Register, 377 kCvSymType_Constant, 378 kCvSymType_UDT, 379 kCvSymType_SSearch, 380 kCvSymType_End, 381 kCvSymType_Skip, 382 kCvSymType_CVReserve, 383 kCvSymType_ObjName, 384 kCvSymType_EndArg, 385 kCvSymType_CobolUDT, 386 kCvSymType_ManyReg, 387 kCvSymType_Return, 388 kCvSymType_EntryThis, 389 /** @} */ 390 391 /** @name Symbols with 16:16 addresses. 392 * @{ */ 393 kCvSymType_BpRel16 = 0x0100, 394 kCvSymType_LData16, 395 kCvSymType_GData16, 396 kCvSymType_Pub16, 397 kCvSymType_LProc16, 398 kCvSymType_GProc16, 399 kCvSymType_Thunk16, 400 kCvSymType_BLock16, 401 kCvSymType_With16, 402 kCvSymType_Label16, 403 kCvSymType_CExModel16, 404 kCvSymType_VftPath16, 405 kCvSymType_RegRel16, 406 /** @} */ 407 408 /** @name Symbols with 16:32 addresses. 409 * @{ */ 410 kCvSymType_BpRel32 = 0x0200, 411 kCvSymType_LData32, 412 kCvSymType_GData32, 413 kCvSymType_Pub32, 414 kCvSymType_LProc32, 415 kCvSymType_GProc32, 416 kCvSymType_Thunk32, 417 kCvSymType_Block32, 418 kCvSymType_With32, 419 kCvSymType_Label32, 420 kCvSymType_CExModel32, 421 kCvSymType_VftPath32, 422 kCvSymType_RegRel32, 423 kCvSymType_LThread32, 424 kCvSymType_GThread32, 425 /** @} */ 426 427 /** @name Symbols for MIPS. 428 * @{ */ 429 kCvSymType_LProcMips = 0x0300, 430 kCvSymType_GProcMips, 431 /** @} */ 432 433 /** @name Symbols for Microsoft CodeView. 434 * @{ */ 435 kCvSymType_ProcRef, 436 kCvSymType_DataRef, 437 kCvSymType_Align, 438 /** @} */ 439 } RTCVSYMTYPE; 440 typedef RTCVSYMTYPE *PRTCVSYMTYPE; 441 typedef RTCVSYMTYPE const *PCRTCVSYMTYPE; 442 443 444 /** The $$SYMBOL table signature for CV4. */ 445 #define RTCVSYMBOLS_SIGNATURE_CV4 UINT32_C(0x00000001) 446 447 246 448 247 449 … … 303 505 /** The directory (converted to 32-bit). */ 304 506 PRTCVDIRENT32 paDirEnts; 507 /** Current debugging style when parsing modules. */ 508 uint16_t uCurStyle; 509 /** Current debugging style version (HLL only). */ 510 uint16_t uCurStyleVer; 511 512 /** The segment map (if present). */ 513 PRTCVSEGMAP pSegMap; 514 /** Segment names. */ 515 char *pszzSegNames; 516 /** The size of the segment names. */ 517 uint32_t cbSegNames; 305 518 306 519 /** @} */ … … 313 526 314 527 528 529 /** 530 * Subsection callback. 531 * 532 * @returns IPRT status code. 533 * @param pThis The CodeView debug info reader instance. 534 * @param pvSubSect Pointer to the subsection data. 535 * @param cbSubSect The size of the subsection data. 536 * @param pDirEnt The directory entry. 537 */ 538 typedef DECLCALLBACK(int) FNDBGMODCVSUBSECTCALLBACK(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, 539 PCRTCVDIRENT32 pDirEnt); 540 /** Pointer to a subsection callback. */ 541 typedef FNDBGMODCVSUBSECTCALLBACK *PFNDBGMODCVSUBSECTCALLBACK; 542 543 544 545 /******************************************************************************* 546 * Defined Constants And Macros * 547 *******************************************************************************/ 548 /** Light weight assert + return w/ fixed status code. */ 549 #define RTDBGMODCV_CHECK_RET_BF(a_Expr, a_LogArgs) \ 550 do { \ 551 if (!(a_Expr)) \ 552 { \ 553 Log(("RTDbgCv: Check failed on line %d: " #a_Expr "\n", __LINE__)); \ 554 Log(a_LogArgs); \ 555 return VERR_CV_BAD_FORMAT; \ 556 } \ 557 } while (0) 558 559 560 /** Light weight assert + return w/ fixed status code. */ 561 #define RTDBGMODCV_CHECK_NOMSG_RET_BF(a_Expr) \ 562 do { \ 563 if (!(a_Expr)) \ 564 { \ 565 Log(("RTDbgCv: Check failed on line %d: " #a_Expr "\n", __LINE__)); \ 566 return VERR_CV_BAD_FORMAT; \ 567 } \ 568 } while (0) 569 570 571 572 573 315 574 static int rtDbgModCvReadAt(PRTDBGMODCV pThis, uint32_t off, void *pvBuf, size_t cb) 316 575 { 317 576 int rc; 318 577 if (pThis->hFile == NIL_RTFILE) 319 rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off , pvBuf, cb);578 rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off + pThis->offBase, pvBuf, cb); 320 579 else 321 rc = RTFileReadAt(pThis->hFile, off , pvBuf, cb, NULL);580 rc = RTFileReadAt(pThis->hFile, off + pThis->offBase, pvBuf, cb, NULL); 322 581 return rc; 323 582 } 324 583 584 585 static int rtDbgModCvReadAtAlloc(PRTDBGMODCV pThis, uint32_t off, void **ppvBuf, size_t cb) 586 { 587 int rc; 588 void *pvBuf = *ppvBuf = RTMemAlloc(cb); 589 if (pvBuf) 590 { 591 if (pThis->hFile == NIL_RTFILE) 592 rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off + pThis->offBase, pvBuf, cb); 593 else 594 rc = RTFileReadAt(pThis->hFile, off + pThis->offBase, pvBuf, cb, NULL); 595 if (RT_SUCCESS(rc)) 596 return VINF_SUCCESS; 597 598 RTMemFree(pvBuf); 599 *ppvBuf = NULL; 600 } 601 else 602 rc = VERR_NO_MEMORY; 603 return rc; 604 } 325 605 326 606 … … 375 655 376 656 /** 657 * Adds a symbol to the container. 658 * 659 * @returns IPRT status code 660 * @param pThis The CodeView debug info reader instance. 661 * @param iSeg Segment number. 662 * @param off Offset into the segment 663 * @param pchName The symbol name (not necessarily terminated). 664 * @param cchName The symbol name length. 665 * @param fFlags Flags reserved for future exploits, MBZ. 666 */ 667 static int rtDbgModCvAddSymbol(PRTDBGMODCV pThis, uint32_t iSeg, uint64_t off, const char *pchName, 668 uint8_t cchName, uint32_t fFlags) 669 { 670 const char *pszName = RTStrCacheEnterN(g_hDbgModStrCache, pchName, cchName); 671 if (!pszName) 672 return VERR_NO_STR_MEMORY; 673 #if 1 674 if (iSeg == 0) 675 iSeg = RTDBGSEGIDX_ABS; 676 else if (pThis->pSegMap) 677 { 678 if ( iSeg > pThis->pSegMap->Hdr.cSegs 679 || iSeg == 0 680 || off > pThis->pSegMap->aDescs[iSeg - 1].cb) 681 { 682 Log(("Invalid segment index/offset %#06x:%08x for symbol %.*s\n", iSeg, off, cchName, pchName)); 683 return VERR_CV_BAD_FORMAT; 684 } 685 off += pThis->pSegMap->aDescs[iSeg - 1].off; 686 if (pThis->pSegMap->aDescs[iSeg - 1].fFlags & RTCVSEGMAPDESC_F_ABS) 687 iSeg = RTDBGSEGIDX_ABS; 688 else 689 iSeg = pThis->pSegMap->aDescs[iSeg - 1].iGroup; 690 } 691 692 int rc = RTDbgModSymbolAdd(pThis->hCnt, pszName, iSeg, off, 0, 0 /*fFlags*/, NULL); 693 Log(("Symbol: %04x:%08x %.*s [%Rrc]\n", iSeg, off, cchName, pchName, rc)); 694 if (rc == VERR_DBG_ADDRESS_CONFLICT || rc == VERR_DBG_DUPLICATE_SYMBOL) 695 rc = VINF_SUCCESS; 696 RTStrCacheRelease(g_hDbgModStrCache, pszName); 697 return rc; 698 #else 699 Log(("Symbol: %04x:%08x %.*s\n", iSeg, off, cchName, pchName)); 700 return VINF_SUCCESS; 701 #endif 702 } 703 704 705 /** 706 * Parses a CV4 symbol table, adding symbols to the container. 707 * 708 * @returns IPRT status code 709 * @param pThis The CodeView debug info reader instance. 710 * @param pbSymTab The symbol table. 711 * @param cbSymTab The size of the symbol table. 712 * @param fFlags Flags reserved for future exploits, MBZ. 713 */ 714 static int rtDbgModCvSsProcessV4SymTab(PRTDBGMODCV pThis, void const *pvSymTab, size_t cbSymTab, uint32_t fFlags) 715 { 716 int rc = VINF_SUCCESS; 717 RTCPTRUNION uCursor; 718 uCursor.pv = pvSymTab; 719 720 while (cbSymTab > 0 && RT_SUCCESS(rc)) 721 { 722 uint8_t const * const pbRecStart = uCursor.pu8; 723 uint16_t cbRec = *uCursor.pu16++; 724 if (cbRec >= 2) 725 { 726 uint16_t uSymType = *uCursor.pu16++; 727 728 Log3((" %p: uSymType=%#06x LB %#x\n", pbRecStart - (uint8_t *)pvSymTab, uSymType, cbRec)); 729 RTDBGMODCV_CHECK_RET_BF(cbRec >= 2 && cbRec <= cbSymTab, ("cbRec=%#x cbSymTab=%#x\n", cbRec, cbSymTab)); 730 731 switch (uSymType) 732 { 733 case kCvSymType_LData16: 734 case kCvSymType_GData16: 735 case kCvSymType_Pub16: 736 { 737 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec > 2 + 2+2+2+1); 738 uint16_t off = *uCursor.pu16++; 739 uint16_t iSeg = *uCursor.pu16++; 740 /*uint16_t iType =*/ *uCursor.pu16++; 741 uint8_t cchName = *uCursor.pu8++; 742 RTDBGMODCV_CHECK_NOMSG_RET_BF(cchName > 0); 743 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec >= 2 + 2+2+2+1 + cchName); 744 745 rc = rtDbgModCvAddSymbol(pThis, iSeg, off, uCursor.pch, cchName, 0); 746 break; 747 } 748 749 case kCvSymType_LData32: 750 case kCvSymType_GData32: 751 case kCvSymType_Pub32: 752 { 753 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec > 2 + 4+2+2+1); 754 uint32_t off = *uCursor.pu32++; 755 uint16_t iSeg = *uCursor.pu16++; 756 /*uint16_t iType =*/ *uCursor.pu16++; 757 uint8_t cchName = *uCursor.pu8++; 758 RTDBGMODCV_CHECK_NOMSG_RET_BF(cchName > 0); 759 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec >= 2 + 4+2+2+1 + cchName); 760 761 rc = rtDbgModCvAddSymbol(pThis, iSeg, off, uCursor.pch, cchName, 0); 762 break; 763 } 764 765 /** @todo add GProc and LProc so we can gather sizes as well as just symbols. */ 766 } 767 } 768 /*else: shorter records can be used for alignment, I guess. */ 769 770 /* next */ 771 uCursor.pu8 = pbRecStart + cbRec + 2; 772 cbSymTab -= cbRec + 2; 773 } 774 return rc; 775 } 776 777 778 /** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK, 779 * Parses kCvSst_GlobalPub, kCvSst_GlobalSym and kCvSst_StaticSym subsections, 780 * adding symbols it finds to the container.} */ 781 static DECLCALLBACK(int) 782 rtDbgModCvSs_GlobalPub_GlobalSym_StaticSym(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt) 783 { 784 PCRTCVGLOBALSYMTABHDR pHdr = (PCRTCVGLOBALSYMTABHDR)pvSubSect; 785 786 /* 787 * Quick data validation. 788 */ 789 Log2(("RTDbgModCv: %s: uSymHash=%#x uAddrHash=%#x cbSymbols=%#x cbSymHash=%#x cbAddrHash=%#x\n", 790 rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pHdr->uSymHash, 791 pHdr->uAddrHash, pHdr->cbSymbols, pHdr->cbSymHash, pHdr->cbAddrHash)); 792 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= sizeof(RTCVGLOBALSYMTABHDR)); 793 RTDBGMODCV_CHECK_NOMSG_RET_BF((uint64_t)pHdr->cbSymbols + pHdr->cbSymHash + pHdr->cbAddrHash <= cbSubSect - sizeof(*pHdr)); 794 RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->uSymHash < 0x20); 795 RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->uAddrHash < 0x20); 796 if (!pHdr->cbSymbols) 797 return VINF_SUCCESS; 798 799 /* 800 * Parse the symbols. 801 */ 802 return rtDbgModCvSsProcessV4SymTab(pThis, pHdr + 1, pHdr->cbSymbols, 0); 803 } 804 805 806 /** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK, 807 * Parses kCvSst_Module subsection, storing the debugging style in pThis.} */ 808 static DECLCALLBACK(int) 809 rtDbgModCvSs_Module(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt) 810 { 811 RTCPTRUNION uCursor; 812 uCursor.pv = pvSubSect; 813 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 2 + 2 + 2 + 2 + 0 + 1); 814 uint16_t iOverlay = *uCursor.pu16++; 815 uint16_t iLib = *uCursor.pu16++; 816 uint16_t cSegs = *uCursor.pu16++; 817 pThis->uCurStyle = *uCursor.pu16++; 818 if (pThis->uCurStyle == 0) 819 pThis->uCurStyle = RT_MAKE_U16('C', 'V'); 820 pThis->uCurStyleVer = 0; 821 uint8_t cchName = uCursor.pu8[cSegs * 12]; 822 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 2 + 2 + 2 + 2 + cSegs * 12U + 1 + cchName); 823 824 const char *pchName = (const char *)&uCursor.pu8[cSegs * 12 + 1]; 825 Log2(("RTDbgModCv: Module: iOverlay=%#x iLib=%#x cSegs=%#x Style=%c%c (%#x) %.*s\n", iOverlay, iLib, cSegs, 826 RT_BYTE1(pThis->uCurStyle), RT_BYTE2(pThis->uCurStyle), pThis->uCurStyle, cchName, pchName)); 827 RTDBGMODCV_CHECK_NOMSG_RET_BF(pThis->uCurStyle == RT_MAKE_U16('C', 'V')); 828 829 PCRTCVMODSEGINFO32 paSegs = (PCRTCVMODSEGINFO32)uCursor.pv; 830 for (uint16_t iSeg = 0; iSeg < cSegs; iSeg++) 831 Log2((" #%02u: %04x:%08x LB %08x\n", iSeg, paSegs[iSeg].iSeg, paSegs[iSeg].off, paSegs[iSeg].cb)); 832 833 return VINF_SUCCESS; 834 } 835 836 837 /** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK, 838 * Parses kCvSst_Symbols, kCvSst_PublicSym and kCvSst_AlignSym subsections, 839 * adding symbols it finds to the container.} */ 840 static DECLCALLBACK(int) 841 rtDbgModCvSs_Symbols_PublicSym_AlignSym(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt) 842 { 843 RTDBGMODCV_CHECK_NOMSG_RET_BF(pThis->uCurStyle == RT_MAKE_U16('C', 'V')); 844 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 8); 845 846 uint32_t u32Signature = *(uint32_t const *)pvSubSect; 847 RTDBGMODCV_CHECK_RET_BF(u32Signature == RTCVSYMBOLS_SIGNATURE_CV4, 848 ("%#x, expected %#x\n", u32Signature, RTCVSYMBOLS_SIGNATURE_CV4)); 849 850 return rtDbgModCvSsProcessV4SymTab(pThis, (uint8_t const *)pvSubSect + 4, cbSubSect - 4, 0); 851 } 852 853 854 static int rtDbgModCvLoadSegmentMap(PRTDBGMODCV pThis) 855 { 856 /* 857 * Search for the segment map and segment names. They will be at the end of the directory. 858 */ 859 uint32_t iSegMap = UINT32_MAX; 860 uint32_t iSegNames = UINT32_MAX; 861 uint32_t i = pThis->cDirEnts; 862 while (i-- > 0) 863 { 864 if ( pThis->paDirEnts[i].iMod != 0xffff 865 && pThis->paDirEnts[i].iMod != 0x0000) 866 break; 867 if (pThis->paDirEnts[i].uSubSectType == kCvSst_SegMap) 868 iSegMap = i; 869 else if (pThis->paDirEnts[i].uSubSectType == kCvSst_SegName) 870 iSegNames = i; 871 } 872 if (iSegMap == UINT32_MAX) 873 { 874 Log(("RTDbgModCv: No segment map present, using segment indexes as is then...\n")); 875 return VINF_SUCCESS; 876 } 877 RTDBGMODCV_CHECK_RET_BF(pThis->paDirEnts[iSegMap].cb >= sizeof(RTCVSEGMAPHDR), 878 ("Bad sstSegMap entry: cb=%#x\n", pThis->paDirEnts[iSegMap].cb)); 879 RTDBGMODCV_CHECK_NOMSG_RET_BF(iSegNames == UINT32_MAX || pThis->paDirEnts[iSegNames].cb > 0); 880 881 /* 882 * Read them into memory. 883 */ 884 int rc = rtDbgModCvReadAtAlloc(pThis, pThis->paDirEnts[iSegMap].off, (void **)&pThis->pSegMap, 885 pThis->paDirEnts[iSegMap].cb); 886 if (iSegNames != UINT32_MAX && RT_SUCCESS(rc)) 887 { 888 pThis->cbSegNames = pThis->paDirEnts[iSegNames].cb; 889 rc = rtDbgModCvReadAtAlloc(pThis, pThis->paDirEnts[iSegNames].off, (void **)&pThis->pszzSegNames, 890 pThis->paDirEnts[iSegNames].cb); 891 } 892 if (RT_FAILURE(rc)) 893 return rc; 894 RTDBGMODCV_CHECK_NOMSG_RET_BF(!pThis->pszzSegNames || !pThis->pszzSegNames[pThis->cbSegNames - 1]); /* must be terminated */ 895 896 /* Use local pointers to avoid lots of indirection and typing. */ 897 PCRTCVSEGMAPHDR pHdr = &pThis->pSegMap->Hdr; 898 PRTCVSEGMAPDESC paDescs = &pThis->pSegMap->aDescs[0]; 899 900 /* 901 * If there are only logical segments, assume a direct mapping. 902 * PE images, like the NT4 kernel, does it like this. 903 */ 904 bool const fNoGroups = pHdr->cSegs == pHdr->cLogSegs; 905 906 /* 907 * Validate and display it all. 908 */ 909 Log2(("RTDbgModCv: SegMap: cSegs=%#x cLogSegs=%#x (cbSegNames=%#x)\n", pHdr->cSegs, pHdr->cLogSegs, pThis->cbSegNames)); 910 RTDBGMODCV_CHECK_RET_BF(pThis->paDirEnts[iSegMap].cb >= sizeof(*pHdr) + pHdr->cSegs * sizeof(paDescs[0]), 911 ("SegMap is out of bounds: cbSubSect=%#x cSegs=%#x\n", pThis->paDirEnts[iSegMap].cb, pHdr->cSegs)); 912 RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->cSegs >= pHdr->cLogSegs); 913 914 Log2(("Logical segment descriptors: %u\n", pHdr->cLogSegs)); 915 for (uint16_t i = 0; i < pHdr->cSegs; i++) 916 { 917 if (i == pHdr->cLogSegs) 918 Log2(("Group/Physical descriptors: %u\n", pHdr->cSegs - pHdr->cLogSegs)); 919 uint16_t idx = i < pHdr->cLogSegs ? i : i - pHdr->cLogSegs; 920 char szFlags[16]; 921 memset(szFlags, '-', sizeof(szFlags)); 922 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_READ) 923 szFlags[0] = 'R'; 924 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_WRITE) 925 szFlags[1] = 'W'; 926 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_EXECUTE) 927 szFlags[2] = 'X'; 928 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_32BIT) 929 szFlags[3] = '3', szFlags[4] = '2'; 930 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_SEL) 931 szFlags[5] = 'S'; 932 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS) 933 szFlags[6] = 'A'; 934 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) 935 szFlags[7] = 'G'; 936 szFlags[8] = '\0'; 937 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_RESERVED) 938 szFlags[8] = '!', szFlags[9] = '\0'; 939 Log2((" #%02u: %#010x LB %#010x flags=%#06x ovl=%#06x group=%#06x frame=%#06x iSegName=%#06x iClassName=%#06x %s\n", 940 idx, paDescs[i].off, paDescs[i].cb, paDescs[i].fFlags, paDescs[i].iOverlay, paDescs[i].iGroup, 941 paDescs[i].iFrame, paDescs[i].offSegName, paDescs[i].offClassName, szFlags)); 942 943 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].offSegName == UINT16_MAX || paDescs[i].offSegName < pThis->cbSegNames); 944 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].offClassName == UINT16_MAX || paDescs[i].offClassName < pThis->cbSegNames); 945 const char *pszName = paDescs[i].offSegName != UINT16_MAX 946 ? pThis->pszzSegNames + paDescs[i].offSegName 947 : NULL; 948 const char *pszClass = paDescs[i].offClassName != UINT16_MAX 949 ? pThis->pszzSegNames + paDescs[i].offClassName 950 : NULL; 951 if (pszName || pszClass) 952 Log2((" pszName=%s pszClass=%s\n", pszName, pszClass)); 953 954 /* Validate the group link. */ 955 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iGroup == 0 || !(paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP)); 956 RTDBGMODCV_CHECK_NOMSG_RET_BF( paDescs[i].iGroup == 0 957 || ( paDescs[i].iGroup >= pHdr->cLogSegs 958 && paDescs[i].iGroup < pHdr->cSegs)); 959 RTDBGMODCV_CHECK_NOMSG_RET_BF( paDescs[i].iGroup == 0 960 || (paDescs[paDescs[i].iGroup].fFlags & RTCVSEGMAPDESC_F_GROUP)); 961 RTDBGMODCV_CHECK_NOMSG_RET_BF(!(paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || paDescs[i].off == 0); /* assumed below */ 962 963 if (fNoGroups) 964 { 965 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iGroup == 0); 966 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].off == 0); 967 } 968 } 969 970 /* 971 * Modify the groups index to be the loader segment index instead, also 972 * add the segments to the container if we haven't done that already. 973 */ 974 975 /* Guess work: Group can be implicit if used. Observed Visual C++ v1.5, 976 omitting the CODE group. */ 977 const char *pszGroup0 = NULL; 978 uint64_t cbGroup0 = 0; 979 if (!fNoGroups) 980 { 981 for (uint16_t i = 0; i < pHdr->cSegs; i++) 982 if ( !(paDescs[i].fFlags & (RTCVSEGMAPDESC_F_GROUP | RTCVSEGMAPDESC_F_ABS)) 983 && paDescs[i].iGroup == 0) 984 { 985 if (pszGroup0 == NULL && paDescs[i].offClassName != UINT16_MAX) 986 pszGroup0 = pThis->pszzSegNames + paDescs[i].offClassName; 987 uint64_t offEnd = (uint64_t)paDescs[i].off + paDescs[i].cb; 988 if (offEnd > cbGroup0) 989 cbGroup0 = offEnd; 990 } 991 } 992 993 /* Add the segments. 994 Note! The RVAs derived from this exercise are all wrong. :-/ 995 Note! We don't have an image loader, so we cannot add any fake sections. */ 996 /** @todo Try see if we can figure something out from the frame value later. */ 997 if (!pThis->fHaveLoadedSegments) 998 { 999 Assert(!pThis->pMod->pImgVt); Assert(pThis->enmType != RTCVFILETYPE_DBG); 1000 uint16_t iSeg = 0; 1001 uint64_t uRva = 0; 1002 if (cbGroup0 && !fNoGroups) 1003 { 1004 rc = RTDbgModSegmentAdd(pThis->hCnt, 0, cbGroup0, pszGroup0 ? pszGroup0 : "Seg00", 0 /*fFlags*/, NULL); 1005 uRva += cbGroup0; 1006 iSeg++; 1007 } 1008 1009 for (uint32_t i = 0; RT_SUCCESS(rc) && i < pHdr->cSegs; i++) 1010 if ((paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || fNoGroups) 1011 { 1012 char szName[16]; 1013 char *pszName = szName; 1014 if (paDescs[i].offSegName != UINT16_MAX) 1015 pszName = pThis->pszzSegNames + paDescs[i].offSegName; 1016 else 1017 RTStrPrintf(szName, sizeof(szName), "Seg%02u", iSeg); 1018 rc = RTDbgModSegmentAdd(pThis->hCnt, uRva, paDescs[i].cb, pszName, 0 /*fFlags*/, NULL); 1019 uRva += paDescs[i].cb; 1020 iSeg++; 1021 } 1022 1023 if (RT_FAILURE(rc)) 1024 { 1025 Log(("RTDbgModCv: %Rrc while adding segments from SegMap\n", rc)); 1026 return rc; 1027 } 1028 1029 pThis->fHaveLoadedSegments = true; 1030 } 1031 1032 /* The PE image has an extra section/segment for the headers, the others doesn't. */ 1033 RTLDRFMT enmImgFmt = RTLDRFMT_INVALID; 1034 if (pThis->pMod->pImgVt) 1035 enmImgFmt = pThis->pMod->pImgVt->pfnGetFormat(pThis->pMod); 1036 1037 /* Pass one: Fixate the group segment indexes. */ 1038 uint16_t iSeg0 = enmImgFmt == RTLDRFMT_PE || pThis->enmType == RTCVFILETYPE_DBG ? 1 : 0; 1039 uint16_t iSeg = iSeg0 + cbGroup0 > 0; 1040 for (uint16_t i = 0; i < pHdr->cSegs; i++) 1041 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS) 1042 paDescs[i].iGroup = (uint16_t)RTDBGSEGIDX_ABS; 1043 else if ((paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || fNoGroups) 1044 paDescs[i].iGroup = iSeg++; 1045 1046 /* Pass two: Resolve group references in to segment indexes. */ 1047 Log2(("Mapped segments (both kinds):\n")); 1048 for (uint16_t i = 0; i < pHdr->cSegs; i++) 1049 { 1050 if (!fNoGroups && !(paDescs[i].fFlags & (RTCVSEGMAPDESC_F_GROUP | RTCVSEGMAPDESC_F_ABS))) 1051 paDescs[i].iGroup = paDescs[i].iGroup == 0 ? iSeg0 : paDescs[paDescs[i].iGroup].iGroup; 1052 1053 Log2((" #%02u: %#010x LB %#010x -> %#06x (flags=%#06x ovl=%#06x frame=%#06x)\n", 1054 i, paDescs[i].off, paDescs[i].cb, paDescs[i].iGroup, 1055 paDescs[i].fFlags, paDescs[i].iOverlay, paDescs[i].iFrame)); 1056 } 1057 1058 return VINF_SUCCESS; 1059 } 1060 1061 1062 /** 377 1063 * Loads the directory into memory (RTDBGMODCV::paDirEnts and 378 1064 * RTDBGMODCV::cDirEnts). … … 398 1084 */ 399 1085 RTCVDIRHDR16 DirHdr; 400 rc = rtDbgModCvReadAt(pThis, pThis->off Base + pThis->offDir, &DirHdr, sizeof(DirHdr));1086 rc = rtDbgModCvReadAt(pThis, pThis->offDir, &DirHdr, sizeof(DirHdr)); 401 1087 if (RT_SUCCESS(rc)) 402 1088 { … … 407 1093 if (pThis->paDirEnts) 408 1094 { 409 rc = rtDbgModCvReadAt(pThis, pThis->off Base + pThis->offDir + sizeof(DirHdr),1095 rc = rtDbgModCvReadAt(pThis, pThis->offDir + sizeof(DirHdr), 410 1096 pThis->paDirEnts, DirHdr.cEntries * sizeof(RTCVDIRENT16)); 411 1097 if (RT_SUCCESS(rc)) … … 443 1129 */ 444 1130 RTCVDIRHDR32EX DirHdr; 445 rc = rtDbgModCvReadAt(pThis, pThis->off Base + pThis->offDir, &DirHdr, sizeof(DirHdr));1131 rc = rtDbgModCvReadAt(pThis, pThis->offDir, &DirHdr, sizeof(DirHdr)); 446 1132 if (RT_SUCCESS(rc)) 447 1133 { … … 475 1161 pThis->paDirEnts = (PRTCVDIRENT32)RTMemAlloc(DirHdr.Core.cEntries * sizeof(pThis->paDirEnts[0])); 476 1162 if (pThis->paDirEnts) 477 rc = rtDbgModCvReadAt(pThis, pThis->off Base + pThis->offDir + DirHdr.Core.cbHdr,1163 rc = rtDbgModCvReadAt(pThis, pThis->offDir + DirHdr.Core.cbHdr, 478 1164 pThis->paDirEnts, DirHdr.Core.cEntries * sizeof(RTCVDIRENT32)); 479 1165 else … … 488 1174 if (RT_SUCCESS(rc)) 489 1175 { 1176 uint16_t iMod = 0; 490 1177 uint32_t const cbDbgInfo = pThis->cbDbgInfo; 491 1178 uint32_t const cDirEnts = pThis->cDirEnts; … … 513 1200 rc = VERR_CV_BAD_FORMAT; 514 1201 } 1202 if ( pDirEnt->iMod < iMod 1203 && ( pDirEnt->iMod != 0 1204 || ( pThis->u32CvMagic != RTCVHDR_MAGIC_NB00 /* May be first, maybe last. */ 1205 && pThis->u32CvMagic != RTCVHDR_MAGIC_NB02 1206 && pThis->u32CvMagic != RTCVHDR_MAGIC_NB04) ) ) 1207 { 1208 Log(("CV directory entry #%u is out of module order, this mod %u, prev mod %#u\n", i, pDirEnt->iMod, iMod)); 1209 rc = VERR_CV_BAD_FORMAT; 1210 } 1211 if (pDirEnt->iMod != iMod) 1212 { 1213 iMod = pDirEnt->iMod; 1214 if ( iMod != 0 1215 && iMod != 0xffff 1216 && pDirEnt->uSubSectType != kCvSst_Module 1217 && pDirEnt->uSubSectType != kCvSst_OldModule) 1218 { 1219 Log(("CV directory entry #%u: expected module subsection first, found %s (%#x)\n", 1220 i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pDirEnt->uSubSectType)); 1221 rc = VERR_CV_BAD_FORMAT; 1222 } 1223 } 515 1224 } 516 1225 } … … 520 1229 521 1230 522 523 1231 static int rtDbgModCvLoadInfo(PRTDBGMODCV pThis) 524 1232 { 525 1233 /* 526 * Load the directory and segments. 1234 * Load the directory, the segment map (if any) and then scan for segments 1235 * if necessary. 527 1236 */ 528 1237 int rc = rtDbgModCvLoadDirectory(pThis); 1238 if (RT_SUCCESS(rc)) 1239 rc = rtDbgModCvLoadSegmentMap(pThis); 529 1240 if (RT_SUCCESS(rc) && !pThis->fHaveLoadedSegments) 1241 { 530 1242 rc = VERR_CV_TODO; /** @todo Scan anything containing address, in particular sstSegMap and sstModule, 531 1243 * and reconstruct the segments from that information. */ 532 533 /* 534 * Load segment map, if present. 535 */ 536 //if (RT_SUCCESS(rc)) 537 // rc = rtDbgModCvLoadGlobals(pThis); 1244 pThis->cbImage = 0x1000; 1245 rc = VINF_SUCCESS; 1246 } 538 1247 539 1248 /* 540 1249 * Process the directory. 541 1250 */ 542 uint32_t i = pThis->cDirEnts; 543 while (i-- > 0) 544 { 545 #if 0 546 if ( pThis->paDirEnts[i].uSubSectType == kCvSst_OldPublic 547 || pThis->paDirEnts[i].uSubSectType == kCvSst_Public 548 ) 1251 for (uint32_t i = 0; RT_SUCCESS(rc) && i < pThis->cDirEnts; i++) 1252 { 1253 PCRTCVDIRENT32 pDirEnt = &pThis->paDirEnts[i]; 1254 Log3(("Processing subsection %#u %s\n", i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType))); 1255 PFNDBGMODCVSUBSECTCALLBACK pfnCallback = NULL; 1256 switch (pDirEnt->uSubSectType) 549 1257 { 1258 case kCvSst_GlobalPub: 1259 case kCvSst_GlobalSym: 1260 case kCvSst_StaticSym: 1261 pfnCallback = rtDbgModCvSs_GlobalPub_GlobalSym_StaticSym; 1262 break; 1263 case kCvSst_Module: 1264 pfnCallback = rtDbgModCvSs_Module; 1265 break; 1266 case kCvSst_PublicSym: 1267 case kCvSst_Symbols: 1268 case kCvSst_AlignSym: 1269 pfnCallback = rtDbgModCvSs_Symbols_PublicSym_AlignSym; 1270 break; 1271 1272 case kCvSst_OldModule: 1273 case kCvSst_OldPublic: 1274 case kCvSst_OldTypes: 1275 case kCvSst_OldSymbols: 1276 case kCvSst_OldSrcLines: 1277 case kCvSst_OldLibraries: 1278 case kCvSst_OldImports: 1279 case kCvSst_OldCompacted: 1280 case kCvSst_OldSrcLnSeg: 1281 case kCvSst_OldSrcLines3: 1282 1283 case kCvSst_Types: 1284 case kCvSst_Public: 1285 case kCvSst_SrcLnSeg: 1286 case kCvSst_SrcModule: 1287 case kCvSst_Libraries: 1288 case kCvSst_GlobalTypes: 1289 case kCvSst_MPC: 1290 case kCvSst_PreComp: 1291 case kCvSst_PreCompMap: 1292 case kCvSst_OffsetMap16: 1293 case kCvSst_OffsetMap32: 1294 case kCvSst_FileIndex: 1295 1296 default: 1297 /** @todo implement more. */ 1298 break; 1299 1300 /* Skip because we've already processed them: */ 1301 case kCvSst_SegMap: 1302 case kCvSst_SegName: 1303 pfnCallback = NULL; 1304 break; 550 1305 } 551 #endif 1306 1307 if (pfnCallback) 1308 { 1309 void *pvSubSect; 1310 rc = rtDbgModCvReadAtAlloc(pThis, pDirEnt->off, &pvSubSect, pDirEnt->cb); 1311 if (RT_SUCCESS(rc)) 1312 { 1313 rc = pfnCallback(pThis, pvSubSect, pDirEnt->cb, pDirEnt); 1314 RTMemFree(pvSubSect); 1315 } 1316 } 552 1317 } 553 1318 … … 905 1670 pThis->offDir = pCvHdr->off; 906 1671 pThis->hFile = hFile; 1672 pThis->pMod = pDbgMod; 907 1673 return VINF_CALLBACK_RETURN; 908 1674 }
Note:
See TracChangeset
for help on using the changeset viewer.