Changeset 3550 for trunk/kStuff/kDbg/kDbgModWinDbgHelp.cpp
- Timestamp:
- Aug 26, 2007, 3:13:35 AM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kStuff/kDbg/kDbgModWinDbgHelp.cpp
r3541 r3550 32 32 #define _IMAGEHLP64 33 33 #include <DbgHelp.h> 34 #include <malloc.h> /* alloca */35 34 36 35 #include "kDbgInternal.h" 36 #include <k/kHlpAlloc.h> 37 #include <k/kHlpString.h> 37 38 38 39 … … 72 73 HANDLE hSymInst; 73 74 /** The image size. */ 74 uint32_tcbImage;75 KU32 cbImage; 75 76 /** The number of sections. (We've added the implicit header section.) */ 76 int32_tcSections;77 KI32 cSections; 77 78 /** The section headers (variable size). The first section is the 78 79 * implicit header section.*/ … … 107 108 * @param puRVA Where to store the RVA on success. 108 109 */ 109 static int kdbgModDHSegOffToRVA(PKDBGMODDBGHELP pModDH, int32_t iSegment, KDBGADDR off, uint32_t*puRVA)110 static int kdbgModDHSegOffToRVA(PKDBGMODDBGHELP pModDH, KI32 iSegment, KDBGADDR off, KU32 *puRVA) 110 111 { 111 112 if (iSegment >= 0) … … 116 117 ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModDH->aSections[iSegment].Misc.VirtualSize), 117 118 KDBG_ERR_INVALID_ADDRESS); 118 *puRVA = pModDH->aSections[iSegment].VirtualAddress + ( uint32_t)off;119 *puRVA = pModDH->aSections[iSegment].VirtualAddress + (KU32)off; 119 120 return 0; 120 121 } … … 124 125 kDbgAssertMsgReturn(off < pModDH->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModDH->cbImage), 125 126 KDBG_ERR_INVALID_ADDRESS); 126 *puRVA = ( uint32_t)off;127 *puRVA = (KU32)off; 127 128 return 0; 128 129 } … … 141 142 * @param poff Where to store the segment offset. 142 143 */ 143 static int kdbgModDHRVAToSegOff(PKDBGMODDBGHELP pModDH, uint32_t uRVA, int32_t*piSegment, KDBGADDR *poff)144 static int kdbgModDHRVAToSegOff(PKDBGMODDBGHELP pModDH, KU32 uRVA, KI32 *piSegment, KDBGADDR *poff) 144 145 { 145 146 kDbgAssertMsgReturn(uRVA < pModDH->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModDH->cbImage), 146 147 KDBG_ERR_INVALID_ADDRESS); 147 for ( int32_tiSegment = 0; iSegment < pModDH->cSections; iSegment++)148 for (KI32 iSegment = 0; iSegment < pModDH->cSections; iSegment++) 148 149 { 149 150 /** @todo should probably be less strict about address in the alignment gaps. */ 150 uint32_toff = uRVA - pModDH->aSections[iSegment].VirtualAddress;151 KU32 off = uRVA - pModDH->aSections[iSegment].VirtualAddress; 151 152 if (off < pModDH->aSections[iSegment].Misc.VirtualSize) 152 153 { … … 163 164 * @copydoc KDBGMODOPS::pfnQueryLine 164 165 */ 165 static int kdbgModDHQueryLine(PKDBGMOD pMod, int32_tiSegment, KDBGADDR off, PKDBGLINE pLine)166 static int kdbgModDHQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine) 166 167 { 167 168 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; … … 170 171 * Translate the address to an RVA. 171 172 */ 172 uint32_tuRVA;173 KU32 uRVA; 173 174 int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA); 174 175 if (!rc) … … 180 181 { 181 182 pLine->RVA = (KDBGADDR)(Line.Address - pModDH->ImageBase); 182 rc = kdbgModDHRVAToSegOff(pModDH, ( uint32_t)pLine->RVA, &pLine->iSegment, &pLine->offSegment);183 rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pLine->RVA, &pLine->iSegment, &pLine->offSegment); 183 184 pLine->iLine = Line.LineNumber; 184 size_t cchFile = strlen(Line.FileName);185 KSIZE cchFile = kHlpStrLen(Line.FileName); 185 186 pLine->cchFile = cchFile < sizeof(pLine->szFile) 186 ? ( uint16_t)cchFile187 : ( uint16_t)sizeof(pLine->szFile) - 1;188 memcpy(pLine->szFile, Line.FileName, pLine->cchFile);187 ? (KU16)cchFile 188 : (KU16)sizeof(pLine->szFile) - 1; 189 kHlpMemCopy(pLine->szFile, Line.FileName, pLine->cchFile); 189 190 pLine->szFile[pLine->cchFile] = '\0'; 190 191 } … … 202 203 * @copydoc KDBGMODOPS::pfnQuerySymbol 203 204 */ 204 static int kdbgModDHQuerySymbol(PKDBGMOD pMod, int32_tiSegment, KDBGADDR off, PKDBGSYMBOL pSym)205 static int kdbgModDHQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) 205 206 { 206 207 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; … … 209 210 * Translate the address to an RVA. 210 211 */ 211 uint32_tuRVA;212 KU32 uRVA; 212 213 int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA); 213 214 if (!rc) … … 242 243 { 243 244 pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModDH->ImageBase); 244 rc = kdbgModDHRVAToSegOff(pModDH, ( uint32_t)pSym->RVA, &pSym->iSegment, &pSym->offSegment);245 rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pSym->RVA, &pSym->iSegment, &pSym->offSegment); 245 246 } 246 pSym->cchName = ( uint16_t)Buf.Sym.NameLen;247 pSym->cchName = (KU16)Buf.Sym.NameLen; 247 248 if (pSym->cchName >= sizeof(pSym->szName)) 248 249 pSym->cchName = sizeof(pSym->szName) - 1; 249 memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);250 kHlpMemCopy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen); 250 251 pSym->szName[Buf.Sym.NameLen] = '\0'; 251 252 } … … 272 273 DWORD Err = GetLastError(); 273 274 int rc = kdbgModDHConvWinError(Err); 274 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=% Rrc\n", Err, rc));275 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc)); 275 276 return rc; 276 277 } … … 278 279 279 280 /** 280 * Methods for a PE module.281 */282 static const KDBGMODOPS g_kdbgModDHOps =283 {284 "PE (dbghelp)",285 kdbgModDHClose,286 kdbgModDHQuerySymbol,287 kdbgModDHQueryLine288 };289 290 291 /**292 281 * Checks if the specified dbghelp.dll is usable. 293 282 * … … 296 285 * @param pszPath the path to the dbghelp.dll. 297 286 */ 298 static int kdbgModDHTryDbgHelp(const char *pszPath, uint32_t *pu32FileVersionMS, uint32_t*pu32FileVersionLS)287 static int kdbgModDHTryDbgHelp(const char *pszPath, KU32 *pu32FileVersionMS, KU32 *pu32FileVersionLS) 299 288 { 300 289 int rc; … … 337 326 * Find the dbghelp.dll 338 327 */ 339 static int kdbgModDHFindDbgHelp(char *pszPath, size_tcchPath)328 static int kdbgModDHFindDbgHelp(char *pszPath, KSIZE cchPath) 340 329 { 341 330 /* 342 331 * Try the current directory. 343 332 */ 344 uint32_tFileVersionMS = 0;345 uint32_tFileVersionLS = 0;333 KU32 FileVersionMS = 0; 334 KU32 FileVersionLS = 0; 346 335 int rc = KERR_GENERAL_FAILURE; 347 336 static char s_szDbgHelp[] = "\\dbghelp.dll"; … … 361 350 if (GetModuleFileName(NULL, pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) 362 351 { 363 strcat(strrchr(pszPath, '\\'), s_szDbgHelp);352 kHlpStrCat(kHlpStrRChr(pszPath, '\\'), s_szDbgHelp); 364 353 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); 365 354 if (!rc) … … 374 363 if (GetSystemDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) 375 364 { 376 strcat(pszPath, s_szDbgHelp);365 kHlpStrCat(pszPath, s_szDbgHelp); 377 366 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); 378 367 if (!rc2) … … 387 376 if (GetWindowsDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) 388 377 { 389 strcat(pszPath, s_szDbgHelp);378 kHlpStrCat(pszPath, s_szDbgHelp); 390 379 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); 391 380 if (!rc2) … … 407 396 { 408 397 /* find the end of the path. */ 409 char *pszEnd = strchr(psz, ';');398 char *pszEnd = kHlpStrChr(psz, ';'); 410 399 if (!pszEnd) 411 pszEnd = strchr(psz, '\0');400 pszEnd = kHlpStrChr(psz, '\0'); 412 401 if (pszEnd != psz) 413 402 { 414 403 /* construct filename and try it out */ 415 memcpy(pszPath, psz, pszEnd - psz);416 memcpy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp));404 kHlpMemCopy(pszPath, psz, pszEnd - psz); 405 kHlpMemCopy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp)); 417 406 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); 418 407 if (!rc2) … … 453 442 454 443 /* primitive locking - make some useful API for this kind of spinning! */ 455 static volatile uint32_t s_u32Lock = 0;456 while (!InterlockedCompareExchange( (long volatile *)&s_u32Lock, 1, 0))457 while (s_ u32Lock)444 static volatile long s_lLock = 0; 445 while (!InterlockedCompareExchange(&s_lLock, 1, 0)) 446 while (s_lLock) 458 447 Sleep(1); 459 448 if (g_hDbgHelp) 460 449 { 461 InterlockedExchange( (long volatile *)&s_u32Lock, 0);450 InterlockedExchange(&s_lLock, 0); 462 451 return 0; 463 452 } … … 470 459 if (rc) 471 460 { 472 InterlockedExchange( (volatile long *)&s_u32Lock, 0);461 InterlockedExchange(&s_lLock, 0); 473 462 return rc; 474 463 } … … 479 468 DWORD Err = GetLastError(); 480 469 int rc = kdbgModDHConvWinError(Err); 481 kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=% Rrc\n", szPath, Err, rc), rc);470 kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%d\n", szPath, Err, rc), rc); 482 471 } 483 472 … … 515 504 { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 }, 516 505 }; 517 for (unsigned i = 0; i < K DBG_ELEMENTS(s_aFunctions); i++)506 for (unsigned i = 0; i < K_ELEMENTS(s_aFunctions); i++) 518 507 { 519 508 FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName); … … 522 511 DWORD Err = GetLastError(); 523 512 rc = kdbgModDHConvWinError(Err); 524 kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=% Rrc\n",525 s_aFunctions[i].pszName, Err, rc));513 kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%d\n", 514 s_aFunctions[i].pszName, Err, rc)); 526 515 break; 527 516 } … … 533 522 g_hDbgHelp = hmod; 534 523 Sleep(1); 535 InterlockedExchange( (volatile long *)&s_u32Lock, 0);524 InterlockedExchange(&s_lLock, 0); 536 525 return 0; 537 526 } … … 547 536 DWORD Err = GetLastError(); 548 537 rc = kdbgModDHConvWinError(Err); 549 kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=% Rrc\n", Err, rc));538 kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%d\n", Err, rc)); 550 539 } 551 540 FreeLibrary(hmod); 552 InterlockedExchange( (long volatile *)&s_u32Lock, 0);541 InterlockedExchange(&s_lLock, 0); 553 542 return rc; 554 543 } … … 556 545 557 546 /** 558 * Opens the debug info for a PE image using the windows dbghelp library. 559 * 560 * @returns IPRT status code. 561 * 562 * @param pFile The handle to the module. 563 * @param offHdr The offset of the PE header. 564 * @param pszModulePath The path to the module. 565 * @param ppDbgMod Where to store the module handle. 566 * 567 */ 568 int kdbgModWinDbgHelpOpen(PKDBGHLPFILE pFile, PKDBGMOD *ppDbgMod) 569 { 547 * @copydoc KDBGMODOPS::pfnOpen 548 */ 549 static int kdbgModDHOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) 550 { 551 /* 552 * This reader doesn't support partial files. 553 * Also weed out small files early on as they cannot be 554 * PE images and will only cause read errors 555 */ 556 if ( off != 0 557 || cb != KFOFF_MAX) 558 return KDBG_ERR_UNKOWN_FORMAT; 559 if (kRdrSize(pRdr) < sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER)) 560 return KDBG_ERR_UNKOWN_FORMAT; 561 570 562 /* 571 563 * We need to read the section headers and get the image size. 572 564 */ 565 /* Find the PE header magic. */ 566 KU32 offHdr = 0; 567 KU32 u32Magic; 568 int rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), 0); 569 kDbgAssertRCReturn(rc, rc); 570 if ((KU16)u32Magic == IMAGE_DOS_SIGNATURE) 571 { 572 rc = kRdrRead(pRdr, &offHdr, sizeof(offHdr), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew)); 573 kDbgAssertRCReturn(rc, rc); 574 if (!offHdr) 575 return KDBG_ERR_FORMAT_NOT_SUPPORTED; 576 if ( offHdr < sizeof(IMAGE_DOS_SIGNATURE) 577 || offHdr >= kRdrSize(pRdr) - 4) 578 return KDBG_ERR_BAD_EXE_FORMAT; 579 580 rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), offHdr); 581 kDbgAssertRCReturn(rc, rc); 582 } 583 if (u32Magic != IMAGE_NT_SIGNATURE) 584 return KDBG_ERR_FORMAT_NOT_SUPPORTED; 585 586 /* read the file header and the image size in the optional header.. */ 573 587 IMAGE_FILE_HEADER FHdr; 574 int rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr));588 rc = kRdrRead(pRdr, &FHdr, sizeof(FHdr), K_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader)); 575 589 kDbgAssertRCReturn(rc, rc); 576 590 577 uint32_tcbImage;591 KU32 cbImage; 578 592 if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) 579 rc = k DbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage),580 &cbImage, sizeof(cbImage));593 rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage), 594 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)); 581 595 else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) 582 rc = k DbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage),583 &cbImage, sizeof(cbImage));596 rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage), 597 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage)); 584 598 else 585 599 kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT); … … 596 610 * Allocate the module and read/construct the section headers. 597 611 */ 598 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)k DbgHlpAlloc(KDBG_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2]));612 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)kHlpAlloc(K_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2])); 599 613 kDbgAssertReturn(pModDH, KERR_NO_MEMORY); 600 614 pModDH->Core.u32Magic = KDBGMOD_MAGIC; 601 pModDH->Core.pOps = &g_kdbgModDHOps; 602 pModDH->Core.pFile = pFile; 615 pModDH->Core.pOps = &g_kDbgModWinDbgHelpOpen; 616 pModDH->Core.pRdr = pRdr; 617 pModDH->Core.fCloseRdr = fCloseRdr; 618 pModDH->Core.pLdrMod = pLdrMod; 603 619 pModDH->cbImage = cbImage; 604 620 pModDH->cSections = 1 + FHdr.NumberOfSections; 605 rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader, 606 &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections); 621 622 rc = kRdrRead(pRdr, &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections, 623 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader); 607 624 if (!rc) 608 625 { 609 626 PIMAGE_SECTION_HEADER pSH = &pModDH->aSections[0]; 610 memcpy(pSH->Name, "headers", sizeof(pSH->Name));627 kHlpMemCopy(pSH->Name, "headers", sizeof(pSH->Name)); 611 628 pSH->Misc.VirtualSize = pModDH->aSections[1].VirtualAddress; 612 629 pSH->VirtualAddress = 0; … … 619 636 pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; 620 637 621 uint32_tuTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress622 638 KU32 uTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress 639 + pModDH->aSections[FHdr.NumberOfSections].Misc.VirtualSize; 623 640 if (uTheEnd < cbImage) 624 641 { 625 642 pSH = &pModDH->aSections[pModDH->cSections++]; 626 memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));643 kHlpMemCopy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name)); 627 644 pSH->Misc.VirtualSize = cbImage - uTheEnd; 628 645 pSH->VirtualAddress = uTheEnd; … … 642 659 * when we start reusing handles they are no longer in use. :-) 643 660 */ 644 static volatile uint32_ts_u32LastHandle = 1;645 HANDLE hSymInst = (HANDLE)InterlockedIncrement( (long *)&s_u32LastHandle);661 static volatile long s_u32LastHandle = 1; 662 HANDLE hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle); 646 663 while ( hSymInst == INVALID_HANDLE_VALUE 647 664 || hSymInst == (HANDLE)0 648 665 || hSymInst == GetCurrentProcess()) 649 hSymInst = (HANDLE)InterlockedIncrement( (long *)&s_u32LastHandle);666 hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle); 650 667 651 668 /* … … 656 673 g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); 657 674 658 kDbgHlpSeek(pFile, 0); /* don't know if this is required or not... */659 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)kDbgHlpNativeFileHandle(pFile),660 pszModulePath, NULL, 0x00400000, 0);675 KIPTR NativeFH = kRdrNativeFH(pRdr); 676 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, NativeFH == -1 ? NULL : (HANDLE)NativeFH, 677 kRdrName(pRdr), NULL, 0x00400000, 0); 661 678 if (ImageBase) 662 679 { 663 pModDH->hSymInst = hSymInst;664 pModDH->ImageBase = ImageBase;665 *pp DbgMod = &pModDH->Core;680 pModDH->hSymInst = hSymInst; 681 pModDH->ImageBase = ImageBase; 682 *ppMod = &pModDH->Core; 666 683 return rc; 667 684 } … … 669 686 DWORD Err = GetLastError(); 670 687 rc = kdbgModDHConvWinError(Err); 671 kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=% Rrc\n", Err, rc));688 kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%d\n", Err, rc)); 672 689 g_pfnSymCleanup(hSymInst); 673 690 } … … 676 693 DWORD Err = GetLastError(); 677 694 rc = kdbgModDHConvWinError(Err); 678 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=% Rrc\n", Err, rc));695 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc)); 679 696 } 680 697 } … … 682 699 kDbgAssertRC(rc); 683 700 684 k DbgHlpFree(pModDH);701 kHlpFree(pModDH); 685 702 return rc; 686 703 } 687 704 705 706 /** 707 * Methods for a PE module. 708 */ 709 const KDBGMODOPS g_kDbgModWinDbgHelpOpen = 710 { 711 "Windows DbgHelp", 712 NULL, 713 kdbgModDHOpen, 714 kdbgModDHClose, 715 kdbgModDHQuerySymbol, 716 kdbgModDHQueryLine, 717 "Windows DbgHelp" 718 }; 719
Note:
See TracChangeset
for help on using the changeset viewer.