Changeset 73416 in vbox for trunk/src/VBox/Debugger
- Timestamp:
- Aug 1, 2018 9:36:37 AM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 124038
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGPlugInWinNt.cpp
r73413 r73416 292 292 293 293 294 /** @callback_method_impl{PFNRTLDRRDRMEMREAD} */295 static DECLCALLBACK(int) dbgDiggerWinNtRdr_Read(void *pvBuf, size_t cb, size_t off, void *pvUser)296 {297 PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser;298 uint32_t offFile = (uint32_t)off;299 AssertReturn(offFile == off, VERR_INVALID_PARAMETER);300 301 uint32_t i = pThis->iHint;302 if (pThis->aMappings[i].offFile > offFile)303 {304 i = pThis->cMappings;305 while (i-- > 0)306 if (offFile >= pThis->aMappings[i].offFile)307 break;308 pThis->iHint = i;309 }310 311 while (cb > 0)312 {313 uint32_t offNextMap = i + 1 < pThis->cMappings ? pThis->aMappings[i + 1].offFile : pThis->cbImage;314 uint32_t offMap = offFile - pThis->aMappings[i].offFile;315 316 /* Read file bits backed by memory. */317 if (offMap < pThis->aMappings[i].cbMem)318 {319 uint32_t cbToRead = pThis->aMappings[i].cbMem - offMap;320 if (cbToRead > cb)321 cbToRead = (uint32_t)cb;322 323 DBGFADDRESS Addr = pThis->ImageAddr;324 DBGFR3AddrAdd(&Addr, pThis->aMappings[i].offMem + offMap);325 326 int rc = DBGFR3MemRead(pThis->pUVM, 0 /*idCpu*/, &Addr, pvBuf, cbToRead);327 if (RT_FAILURE(rc))328 return rc;329 330 /* Apply SizeOfImage patch? */331 if ( pThis->offSizeOfImage != UINT32_MAX332 && offFile < pThis->offSizeOfImage + 4333 && offFile + cbToRead > pThis->offSizeOfImage)334 {335 uint32_t SizeOfImage = pThis->cbCorrectImageSize;336 uint32_t cbPatch = sizeof(SizeOfImage);337 int32_t offPatch = pThis->offSizeOfImage - offFile;338 uint8_t *pbPatch = (uint8_t *)pvBuf + offPatch;339 if (offFile + cbToRead < pThis->offSizeOfImage + cbPatch)340 cbPatch = offFile + cbToRead - pThis->offSizeOfImage;341 while (cbPatch-- > 0)342 {343 if (offPatch >= 0)344 *pbPatch = (uint8_t)SizeOfImage;345 offPatch++;346 pbPatch++;347 SizeOfImage >>= 8;348 }349 }350 351 /* Done? */352 if (cbToRead == cb)353 break;354 355 offFile += cbToRead;356 cb -= cbToRead;357 pvBuf = (char *)pvBuf + cbToRead;358 }359 360 /* Mind the gap. */361 if (offNextMap > offFile)362 {363 uint32_t cbZero = offNextMap - offFile;364 if (cbZero > cb)365 {366 RT_BZERO(pvBuf, cb);367 break;368 }369 370 RT_BZERO(pvBuf, cbZero);371 offFile += cbZero;372 cb -= cbZero;373 pvBuf = (char *)pvBuf + cbZero;374 }375 376 pThis->iHint = ++i;377 }378 379 return VINF_SUCCESS;380 }381 382 383 /** @callback_method_impl{PFNRTLDRRDRMEMDTOR} */384 static DECLCALLBACK(void) dbgDiggerWinNtRdr_Dtor(void *pvUser)385 {386 PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser;387 388 VMR3ReleaseUVM(pThis->pUVM);389 pThis->pUVM = NULL;390 RTMemFree(pvUser);391 }392 393 394 /**395 * Checks if the section headers look okay.396 *397 * @returns true / false.398 * @param paShs Pointer to the section headers.399 * @param cShs Number of headers.400 * @param cbImage The image size reported by NT.401 * @param cbImageFromHdr The image size by the linker in the header.402 * @param uRvaRsrc The RVA of the resource directory. UINT32_MAX if403 * no resource directory.404 * @param cbSectAlign The section alignment specified in the header.405 * @param fNt31 Set if NT 3.1. Needed for chopped off HAL.406 * @param pcbImageCorrect The corrected image size. This is derived from407 * cbImage and virtual range of the section tables.408 *409 * The problem is that NT may choose to drop the410 * last pages in images it loads early, starting at411 * the resource directory. These images will have412 * a page aligned cbImage.413 */414 static bool dbgDiggerWinNtCheckSectHdrsAndImgSize(PCIMAGE_SECTION_HEADER paShs, uint32_t cShs, uint32_t cbImage,415 uint32_t cbImageFromHdr, uint32_t uRvaRsrc, uint32_t cbSectAlign,416 bool fNt31, uint32_t *pcbImageCorrect)417 {418 *pcbImageCorrect = cbImage;419 420 for (uint32_t i = 0; i < cShs; i++)421 {422 if (!paShs[i].Name[0])423 {424 Log(("DigWinNt: Section header #%u has no name\n", i));425 return false;426 }427 428 if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)429 continue;430 431 /* Tweak to determine the virtual size if the linker didn't set it (NT 3.1). */432 /** @todo this isn't really perfect. cbImage is kind of wrong... */433 uint32_t cbVirtual = paShs[i].Misc.VirtualSize;434 if (cbVirtual == 0)435 {436 for (uint32_t j = i + 1; j < cShs; j++)437 if (!(paShs[j].Characteristics & IMAGE_SCN_TYPE_NOLOAD)438 && paShs[j].VirtualAddress > paShs[i].VirtualAddress)439 {440 cbVirtual = paShs[j].VirtualAddress - paShs[i].VirtualAddress;441 break;442 }443 if (!cbVirtual)444 {445 if (paShs[i].VirtualAddress < cbImageFromHdr)446 cbVirtual = cbImageFromHdr - paShs[i].VirtualAddress;447 else if (paShs[i].SizeOfRawData > 0)448 cbVirtual = RT_ALIGN(paShs[i].SizeOfRawData, _4K);449 }450 }451 452 /* Check that sizes are within the same range and that both sizes and453 addresses are within reasonable limits. */454 if ( RT_ALIGN(cbVirtual, _64K) < RT_ALIGN(paShs[i].SizeOfRawData, _64K)455 || cbVirtual >= _1G456 || paShs[i].SizeOfRawData >= _1G)457 {458 Log(("DigWinNt: Section header #%u (%.8s) has a VirtualSize=%#x (%#x) and SizeOfRawData=%#x, that's too much data!\n",459 i, paShs[i].Name, cbVirtual, paShs[i].Misc.VirtualSize, paShs[i].SizeOfRawData));460 return false;461 }462 uint32_t uRvaEnd = paShs[i].VirtualAddress + cbVirtual;463 if (uRvaEnd >= _1G || uRvaEnd < paShs[i].VirtualAddress)464 {465 Log(("DigWinNt: Section header #%u (%.8s) has a VirtualSize=%#x (%#x) and VirtualAddr=%#x, %#x in total, that's too much!\n",466 i, paShs[i].Name, cbVirtual, paShs[i].Misc.VirtualSize, paShs[i].VirtualAddress, uRvaEnd));467 return false;468 }469 470 /* Check for images chopped off around '.rsrc'. */471 if ( cbImage < uRvaEnd472 && uRvaEnd >= uRvaRsrc)473 cbImage = RT_ALIGN(uRvaEnd, cbSectAlign);474 475 /* Check that the section is within the image. */476 if (uRvaEnd > cbImage && fNt31)477 {478 Log(("DigWinNt: Section header #%u has a virtual address range beyond the image: %#x TO %#x cbImage=%#x\n",479 i, paShs[i].VirtualAddress, uRvaEnd, cbImage));480 return false;481 }482 }483 484 Assert(*pcbImageCorrect == cbImage || !(*pcbImageCorrect & 0xfff));485 *pcbImageCorrect = cbImage;486 return true;487 }488 489 490 /**491 * Create a loader module for the in-guest-memory PE module.492 */493 static int dbgDiggerWinNtCreateLdrMod(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName, PCDBGFADDRESS pImageAddr,494 uint32_t cbImage, uint8_t *pbBuf, size_t cbBuf,495 uint32_t offHdrs, PCNTHDRS pHdrs, PRTLDRMOD phLdrMod)496 {497 /*498 * Allocate and create a reader instance.499 */500 uint32_t const cShs = WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections);501 PDBGDIGGERWINNTRDR pRdr = (PDBGDIGGERWINNTRDR)RTMemAlloc(RT_UOFFSETOF_DYN(DBGDIGGERWINNTRDR, aMappings[cShs + 2]));502 if (!pRdr)503 return VERR_NO_MEMORY;504 505 VMR3RetainUVM(pUVM);506 pRdr->pUVM = pUVM;507 pRdr->ImageAddr = *pImageAddr;508 pRdr->cbImage = cbImage;509 pRdr->cbCorrectImageSize = cbImage;510 pRdr->offSizeOfImage = UINT32_MAX;511 pRdr->iHint = 0;512 513 /*514 * Use the section table to construct a more accurate view of the file/515 * image if it's in the buffer (it should be).516 */517 uint32_t uRvaRsrc = UINT32_MAX;518 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).Size > 0)519 uRvaRsrc = WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).VirtualAddress;520 uint32_t offShs = offHdrs521 + ( pThis->f32Bit522 ? pHdrs->vX_32.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader)523 : pHdrs->vX_64.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader));524 uint32_t cbShs = cShs * sizeof(IMAGE_SECTION_HEADER);525 PCIMAGE_SECTION_HEADER paShs = (PCIMAGE_SECTION_HEADER)(pbBuf + offShs);526 if ( offShs + cbShs <= RT_MIN(cbImage, cbBuf)527 && dbgDiggerWinNtCheckSectHdrsAndImgSize(paShs, cShs, cbImage, WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage),528 uRvaRsrc, WINNT_UNION(pThis, pHdrs, OptionalHeader.SectionAlignment),529 pThis->fNt31, &pRdr->cbCorrectImageSize))530 {531 pRdr->cMappings = 0;532 533 for (uint32_t i = 0; i < cShs; i++)534 if ( paShs[i].SizeOfRawData > 0535 && paShs[i].PointerToRawData > 0)536 {537 uint32_t j = 1;538 if (!pRdr->cMappings)539 pRdr->cMappings++;540 else541 {542 while (j < pRdr->cMappings && pRdr->aMappings[j].offFile < paShs[i].PointerToRawData)543 j++;544 if (j < pRdr->cMappings)545 memmove(&pRdr->aMappings[j + 1], &pRdr->aMappings[j], (pRdr->cMappings - j) * sizeof(pRdr->aMappings));546 }547 pRdr->aMappings[j].offFile = paShs[i].PointerToRawData;548 pRdr->aMappings[j].offMem = paShs[i].VirtualAddress;549 pRdr->aMappings[j].cbMem = i + 1 < cShs550 ? paShs[i + 1].VirtualAddress - paShs[i].VirtualAddress551 : paShs[i].Misc.VirtualSize;552 if (j == pRdr->cMappings)553 pRdr->cbImage = paShs[i].PointerToRawData + paShs[i].SizeOfRawData;554 pRdr->cMappings++;555 }556 557 /* Insert the mapping of the headers that isn't covered by the section table. */558 pRdr->aMappings[0].offFile = 0;559 pRdr->aMappings[0].offMem = 0;560 pRdr->aMappings[0].cbMem = pRdr->cMappings ? pRdr->aMappings[1].offFile : pRdr->cbImage;561 562 int j = pRdr->cMappings - 1;563 while (j-- > 0)564 {565 uint32_t cbFile = pRdr->aMappings[j + 1].offFile - pRdr->aMappings[j].offFile;566 if (pRdr->aMappings[j].cbMem > cbFile)567 pRdr->aMappings[j].cbMem = cbFile;568 }569 }570 else571 {572 /*573 * Fallback, fake identity mapped file data.574 */575 pRdr->cMappings = 1;576 pRdr->aMappings[0].offFile = 0;577 pRdr->aMappings[0].offMem = 0;578 pRdr->aMappings[0].cbMem = pRdr->cbImage;579 }580 581 /* Enable the SizeOfImage patching if necessary. */582 if (pRdr->cbCorrectImageSize != cbImage)583 {584 Log(("DigWinNT: The image is really %#x bytes long, not %#x as mapped by NT!\n", pRdr->cbCorrectImageSize, cbImage));585 pRdr->offSizeOfImage = pThis->f32Bit586 ? offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)587 : offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage);588 }589 590 /*591 * Call the loader to open the PE image for debugging.592 * Note! It always calls pfnDtor.593 */594 RTLDRMOD hLdrMod;595 int rc = RTLdrOpenInMemory(pszName, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, pRdr->cbImage,596 dbgDiggerWinNtRdr_Read, dbgDiggerWinNtRdr_Dtor, pRdr,597 &hLdrMod, NULL);598 if (RT_SUCCESS(rc))599 *phLdrMod = hLdrMod;600 else601 *phLdrMod = NIL_RTLDRMOD;602 return rc;603 }604 605 606 294 /** 607 295 * Process a PE image found in guest memory. … … 617 305 */ 618 306 static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName, 619 PCDBGFADDRESS pImageAddr, uint32_t cbImage, 620 uint8_t *pbBuf, size_t cbBuf) 307 PCDBGFADDRESS pImageAddr, uint32_t cbImage) 621 308 { 622 309 LogFlow(("DigWinNt: %RGp %#x %s\n", pImageAddr->FlatPtr, cbImage, pszName)); 623 624 /*625 * NT 3.1 doesn't set the image size in the MTEs, so a little626 * bit of tweaking is necessary here.627 */628 uint32_t const cbImageValidate = !pThis->fNt31 ? cbImage : _64M;629 310 630 311 /* 631 312 * Do some basic validation first. 632 * This is the usual exteremely verbose and messy code...633 313 */ 634 Assert(cbBuf >= sizeof(IMAGE_NT_HEADERS64));635 314 if ( (cbImage < sizeof(IMAGE_NT_HEADERS64) && !pThis->fNt31) 636 315 || cbImage >= _1M * 256) … … 640 319 } 641 320 642 /* Dig out the NT/PE headers. */ 643 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbBuf; 644 PCNTHDRS pHdrs; 645 uint32_t offHdrs; 646 if (pMzHdr->e_magic != IMAGE_DOS_SIGNATURE) 647 { 648 offHdrs = 0; 649 pHdrs = (PCNTHDRS)pbBuf; 321 /* 322 * Use the common in-memory module reader to create a debug module. 323 */ 324 RTERRINFOSTATIC ErrInfo; 325 RTDBGMOD hDbgMod = NIL_RTDBGMOD; 326 int rc = DBGFR3ModInMem(pUVM, pImageAddr, pThis->fNt31 ? DBGFMODINMEM_F_PE_NT31 : 0, pszName, 327 pThis->f32Bit ? RTLDRARCH_X86_32 : RTLDRARCH_AMD64, cbImage, 328 &hDbgMod, RTErrInfoInitStatic(&ErrInfo)); 329 if (RT_SUCCESS(rc)) 330 { 331 /* 332 * Tag the module. 333 */ 334 rc = RTDbgModSetTag(hDbgMod, DIG_WINNT_MOD_TAG); 335 AssertRC(rc); 336 337 /* 338 * Link the module. 339 */ 340 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL); 341 if (hAs != NIL_RTDBGAS) 342 rc = RTDbgAsModuleLink(hAs, hDbgMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/); 343 else 344 rc = VERR_INTERNAL_ERROR; 345 RTDbgModRelease(hDbgMod); 346 RTDbgAsRelease(hAs); 650 347 } 651 else if ( pMzHdr->e_lfanew >= cbImageValidate 652 || pMzHdr->e_lfanew < sizeof(*pMzHdr) 653 || pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > cbImageValidate) 654 { 655 Log(("DigWinNt: %s: PE header to far into image: %#x cbImage=%#x\n", pszName, pMzHdr->e_lfanew, cbImage)); 656 return; 657 } 658 else if ( pMzHdr->e_lfanew < cbBuf 659 && pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) <= cbBuf) 660 { 661 offHdrs = pMzHdr->e_lfanew; 662 pHdrs = (NTHDRS const *)(pbBuf + offHdrs); 663 } 348 else if (RTErrInfoIsSet(&ErrInfo.Core)) 349 Log(("DigWinNt: %s: DBGFR3ModInMem failed: %Rrc - %s\n", pszName, rc, ErrInfo.Core.pszMsg)); 664 350 else 665 { 666 Log(("DigWinNt: %s: PE header to far into image (lazy bird): %#x\n", pszName, pMzHdr->e_lfanew)); 667 return; 668 } 669 if (pHdrs->vX_32.Signature != IMAGE_NT_SIGNATURE) 670 { 671 Log(("DigWinNt: %s: Bad PE signature: %#x\n", pszName, pHdrs->vX_32.Signature)); 672 return; 673 } 674 675 /* The file header is the same on both archs */ 676 if (pHdrs->vX_32.FileHeader.Machine != (pThis->f32Bit ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64)) 677 { 678 Log(("DigWinNt: %s: Invalid FH.Machine: %#x\n", pszName, pHdrs->vX_32.FileHeader.Machine)); 679 return; 680 } 681 if (pHdrs->vX_32.FileHeader.SizeOfOptionalHeader != (pThis->f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64))) 682 { 683 Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader)); 684 return; 685 } 686 if (WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections) > 64) 687 { 688 Log(("DigWinNt: %s: Too many sections: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections))); 689 return; 690 } 691 692 const uint32_t TimeDateStamp = pHdrs->vX_32.FileHeader.TimeDateStamp; 693 694 /* The optional header is not... */ 695 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic) != (pThis->f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC)) 696 { 697 Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic))); 698 return; 699 } 700 uint32_t cbImageFromHdr = WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage); 701 if (pThis->fNt31) 702 cbImage = RT_ALIGN(cbImageFromHdr, _4K); 703 else if (RT_ALIGN(cbImageFromHdr, _4K) != RT_ALIGN(cbImage, _4K)) 704 { 705 Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, cbImageFromHdr, cbImage)); 706 return; 707 } 708 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes) != IMAGE_NUMBEROF_DIRECTORY_ENTRIES) 709 { 710 Log(("DigWinNt: %s: Invalid OH.NumberOfRvaAndSizes: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes))); 711 return; 712 } 713 714 /* 715 * Create the module using the in memory image first, falling back 716 * on cached image. 717 */ 718 RTLDRMOD hLdrMod; 719 int rc = dbgDiggerWinNtCreateLdrMod(pThis, pUVM, pszName, pImageAddr, cbImage, pbBuf, cbBuf, offHdrs, pHdrs, 720 &hLdrMod); 721 if (RT_FAILURE(rc)) 722 hLdrMod = NIL_RTLDRMOD; 723 724 RTDBGMOD hMod; 725 rc = RTDbgModCreateFromPeImage(&hMod, pszName, NULL, &hLdrMod, 726 cbImageFromHdr, TimeDateStamp, DBGFR3AsGetConfig(pUVM)); 727 if (RT_FAILURE(rc)) 728 { 729 /* 730 * Final fallback is a container module. 731 */ 732 rc = RTDbgModCreate(&hMod, pszName, cbImage, 0); 733 if (RT_FAILURE(rc)) 734 return; 735 736 rc = RTDbgModSymbolAdd(hMod, "Headers", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL); 737 AssertRC(rc); 738 } 739 740 /* Tag the module. */ 741 rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG); 742 AssertRC(rc); 743 744 /* 745 * Link the module. 746 */ 747 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL); 748 if (hAs != NIL_RTDBGAS) 749 rc = RTDbgAsModuleLink(hAs, hMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/); 750 else 751 rc = VERR_INTERNAL_ERROR; 752 RTDbgModRelease(hMod); 753 RTDbgAsRelease(hAs); 754 if (hLdrMod != NIL_RTLDRMOD) 755 RTLdrClose(hLdrMod); 351 Log(("DigWinNt: %s: DBGFR3ModInMem failed: %Rrc\n", pszName, rc)); 756 352 } 757 353 … … 953 549 if (RT_SUCCESS(rc)) 954 550 { 955 u.wsz[cbName/2] = '\0'; 551 u.wsz[cbName / 2] = '\0'; 552 956 553 char *pszName; 957 554 rc = RTUtf16ToUtf8(u.wsz, &pszName); … … 961 558 DBGFADDRESS ImageAddr; 962 559 DBGFR3AddrFromFlat(pUVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase)); 963 uint32_t cbImageBuf = RT_MIN(sizeof(u), RT_MAX(cbImageMte, _4K)); 964 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf); 965 if (RT_SUCCESS(rc)) 966 dbgDiggerWinNtProcessImage(pThis, 967 pUVM, 968 pszName, 969 &ImageAddr, 970 cbImageMte, 971 &u.au8[0], 972 sizeof(u)); 560 dbgDiggerWinNtProcessImage(pThis, pUVM, pszName, &ImageAddr, cbImageMte); 973 561 RTStrFree(pszName); 974 562 }
Note:
See TracChangeset
for help on using the changeset viewer.