Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

861 lines
22 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. Debugger.cpp
  5. Abstract:
  6. This module implements the AppVerifier.exe debugger.
  7. Author:
  8. clupu created 01/25/2001
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "appverif.h"
  13. #include "Log.h"
  14. #include <memory.h>
  15. #include <stdlib.h>
  16. #include "wdbgexts.h"
  17. #include "Debugger.h"
  18. #include "Setting.h"
  19. #include "UserDump.h"
  20. #include "DbgHelp.h"
  21. #include "ChooseExe.h"
  22. #ifdef BP_SIZE
  23. ULONG g_BpSize = BP_SIZE;
  24. #endif
  25. #ifdef BP_INSTR
  26. ULONG g_BpInstr = BP_INSTR;
  27. #endif
  28. typedef void (*PFNDBGEXT)(HANDLE hCurrentProcess,
  29. HANDLE hCurrentThread,
  30. DWORD dwUnused,
  31. PWINDBG_EXTENSION_APIS lpExtensionApis,
  32. LPSTR lpArgumentString);
  33. PFNDBGEXT g_pfnPhextsInit;
  34. BOOL g_bInitialBreakpoint = TRUE;
  35. PROCESS_INFORMATION g_ProcessInformation;
  36. WINDBG_EXTENSION_APIS ExtensionAPIs;
  37. typedef struct tagLOADEDDLL
  38. {
  39. struct tagLOADEDDLL* pNext;
  40. LPTSTR pszName;
  41. LPVOID lpBaseOfDll;
  42. } LOADEDDLL, *PLOADEDDLL;
  43. PLOADEDDLL g_pFirstDll;
  44. PPROCESS_INFO g_pProcessHead = NULL;
  45. PPROCESS_INFO g_pFirstProcess = NULL;
  46. //
  47. // BUGBUG: what's this for ?
  48. //
  49. TCHAR g_szDbgString[1024];
  50. //
  51. // Local function prototypes
  52. //
  53. void DebuggerLoop(void);
  54. DWORD WINAPI ExecuteAppThread( LPVOID lParam )
  55. /*++
  56. Return: TRUE if successful, FALSE otherwise.
  57. Desc: Launch the debuggee.
  58. --*/
  59. {
  60. BOOL bRet;
  61. STARTUPINFO StartupInfo;
  62. ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  63. StartupInfo.cb = sizeof(StartupInfo);
  64. //
  65. // Set some pageheap flags
  66. //
  67. AVSetVerifierFlagsForExe(g_szAppShortName, (DWORD)(LPARAM)lParam);
  68. bRet = CreateProcess(NULL,
  69. g_szAppFullPath,
  70. NULL,
  71. NULL,
  72. FALSE,
  73. CREATE_SEPARATE_WOW_VDM | DEBUG_ONLY_THIS_PROCESS,
  74. NULL,
  75. NULL,
  76. &StartupInfo,
  77. &g_ProcessInformation);
  78. if ( !bRet )
  79. {
  80. LogMessage(LOG_ERROR, _T("[ExecuteApp] Couldn't start \"%s\""), g_szAppFullPath);
  81. return 0;
  82. }
  83. LogMessage(LOG_INFO,
  84. _T("[ExecuteApp] CreateProcess hProcess 0x%X. \"%s\""),
  85. g_ProcessInformation.hProcess,
  86. g_szAppFullPath);
  87. if ( g_ProcessInformation.hProcess != NULL )
  88. {
  89. //
  90. // Start the debugger loop.
  91. //
  92. DebuggerLoop();
  93. //
  94. // Free the memory.
  95. //
  96. PPROCESS_INFO pProcess = g_pProcessHead;
  97. PPROCESS_INFO pProcessNext;
  98. while ( pProcess != NULL )
  99. {
  100. pProcessNext = pProcess->pNext;
  101. PTHREAD_INFO pThread = pProcess->pFirstThreadInfo;
  102. PTHREAD_INFO pThreadNext;
  103. while ( pThread != NULL )
  104. {
  105. pThreadNext = pThread->pNext;
  106. HeapFree(GetProcessHeap(), 0, pThread);
  107. pThread = pThreadNext;
  108. }
  109. HeapFree(GetProcessHeap(), 0, pProcess);
  110. pProcess = pProcessNext;
  111. }
  112. g_pProcessHead = NULL;
  113. PLOADEDDLL pDll = g_pFirstDll;
  114. PLOADEDDLL pDllNext;
  115. while ( pDll != NULL )
  116. {
  117. pDllNext = pDll->pNext;
  118. HeapFree(GetProcessHeap(), 0, pDll->pszName);
  119. HeapFree(GetProcessHeap(), 0, pDll);
  120. pDll = pDllNext;
  121. }
  122. g_pFirstDll = NULL;
  123. g_bDebuggeeExited = TRUE;
  124. CloseHandle(g_ProcessInformation.hProcess);
  125. CloseHandle(g_ProcessInformation.hThread);
  126. ZeroMemory(&g_ProcessInformation, sizeof(PROCESS_INFORMATION));
  127. }
  128. //
  129. // Delete the pageheap flags
  130. //
  131. AVSetVerifierFlagsForExe(g_szAppShortName, 0);
  132. return 1;
  133. }
  134. PPROCESS_INFO GetProcessInfo( HANDLE hProcess )
  135. {
  136. PPROCESS_INFO pProcess = g_pProcessHead;
  137. while ( pProcess != NULL )
  138. {
  139. if ( pProcess->hProcess == hProcess )
  140. {
  141. return pProcess;
  142. }
  143. }
  144. return NULL;
  145. }
  146. SIZE_T
  147. ReadMemoryDbg(
  148. HANDLE hProcess,
  149. LPVOID Address,
  150. LPVOID Buffer,
  151. SIZE_T Length
  152. )
  153. {
  154. SIZE_T cbRead;
  155. LPVOID AddressBp;
  156. PPROCESS_INFO pProcess;
  157. if ( !ReadProcessMemory(hProcess,
  158. Address,
  159. Buffer,
  160. Length,
  161. &cbRead) )
  162. {
  163. return 0;
  164. }
  165. pProcess = GetProcessInfo(hProcess);
  166. if ( pProcess == NULL )
  167. {
  168. return 0;
  169. }
  170. #if defined(BP_INSTR) && defined(BP_SIZE)
  171. for ( int i = 0; i < MAX_BREAKPOINTS; i++ )
  172. {
  173. AddressBp = pProcess->bp[i].Address;
  174. if ( (ULONG_PTR)AddressBp >= (ULONG_PTR)Address &&
  175. (ULONG_PTR)AddressBp < (ULONG_PTR)Address + Length )
  176. {
  177. CopyMemory((LPVOID)((ULONG_PTR)Buffer + (ULONG_PTR)AddressBp - (ULONG_PTR)Address),
  178. &pProcess->bp[i].OriginalInstr,
  179. g_BpSize);
  180. }
  181. }
  182. #endif
  183. return cbRead;
  184. }
  185. BOOL
  186. WriteMemoryDbg(
  187. HANDLE hProcess,
  188. PVOID Address,
  189. PVOID Buffer,
  190. SIZE_T Length
  191. )
  192. {
  193. SIZE_T cb = 0;
  194. BOOL bSuccess;
  195. bSuccess = WriteProcessMemory(hProcess, Address, Buffer, Length, &cb);
  196. if ( !bSuccess || cb != Length )
  197. {
  198. return FALSE;
  199. }
  200. return TRUE;
  201. }
  202. BOOL
  203. GetImageName(
  204. HANDLE hProcess,
  205. ULONG_PTR ImageBase,
  206. PVOID ImageNamePtr,
  207. LPTSTR ImageName,
  208. DWORD ImageNameLength
  209. )
  210. /*++
  211. Return: TRUE if successful, FALSE otherwise.
  212. Desc: BUGBUG: give details here
  213. --*/
  214. {
  215. DWORD_PTR i;
  216. BYTE UnicodeBuf[256 * 2];
  217. IMAGE_DOS_HEADER dh;
  218. IMAGE_NT_HEADERS nh;
  219. IMAGE_EXPORT_DIRECTORY expdir;
  220. if ( !ReadMemoryDbg(hProcess,
  221. (ULONG*)ImageNamePtr,
  222. &i,
  223. sizeof(i)) )
  224. {
  225. goto GetFromExports;
  226. }
  227. if ( !ReadMemoryDbg(hProcess,
  228. (ULONG*)i,
  229. (ULONG*)UnicodeBuf,
  230. sizeof(UnicodeBuf)) )
  231. {
  232. goto GetFromExports;
  233. }
  234. ZeroMemory(ImageName, ImageNameLength);
  235. #ifdef UNICODE
  236. lstrcpyW(ImageName, (LPCWSTR)UnicodeBuf);
  237. #else
  238. WideCharToMultiByte(CP_ACP,
  239. 0,
  240. (LPWSTR)UnicodeBuf,
  241. wcslen((LPWSTR)UnicodeBuf),
  242. ImageName,
  243. ImageNameLength,
  244. NULL,
  245. NULL);
  246. #endif // UNICODE
  247. if ( lstrlen(ImageName) == 0 )
  248. {
  249. goto GetFromExports;
  250. }
  251. return TRUE;
  252. GetFromExports:
  253. if ( !ReadMemoryDbg(hProcess,
  254. (ULONG*)ImageBase,
  255. (ULONG*)&dh,
  256. sizeof(IMAGE_DOS_HEADER)) )
  257. {
  258. return FALSE;
  259. }
  260. if ( dh.e_magic != IMAGE_DOS_SIGNATURE )
  261. {
  262. return FALSE;
  263. }
  264. if ( !ReadMemoryDbg(hProcess,
  265. (ULONG*)(ImageBase + dh.e_lfanew),
  266. (ULONG*)&nh,
  267. sizeof(IMAGE_NT_HEADERS)) )
  268. {
  269. return FALSE;
  270. }
  271. if ( nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0 )
  272. {
  273. return FALSE;
  274. }
  275. if ( !ReadMemoryDbg(hProcess,
  276. (ULONG*)(ImageBase +
  277. nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress),
  278. (ULONG*)&expdir,
  279. sizeof(IMAGE_EXPORT_DIRECTORY)) )
  280. {
  281. return FALSE;
  282. }
  283. if ( !ReadMemoryDbg(hProcess,
  284. (ULONG*)(ImageBase + expdir.Name),
  285. #ifdef UNICODE
  286. (ULONG*)UnicodeBuf,
  287. #else
  288. (ULONG*)ImageName,
  289. #endif // UNICODE
  290. ImageNameLength) )
  291. {
  292. return FALSE;
  293. }
  294. #ifdef UNICODE
  295. MultiByteToWideChar(CP_ACP,
  296. 0,
  297. (LPCSTR)UnicodeBuf,
  298. -1,
  299. ImageName,
  300. ImageNameLength);
  301. #endif // UNICODE
  302. return TRUE;
  303. }
  304. void
  305. AddDll(
  306. LPVOID lpBaseOfDll,
  307. LPCTSTR pszDllName
  308. )
  309. /*++
  310. Return: void.
  311. Desc: BUGBUG: give details here
  312. --*/
  313. {
  314. PLOADEDDLL pDll;
  315. pDll = (PLOADEDDLL)HeapAlloc(GetProcessHeap(), 0, sizeof(LOADEDDLL));
  316. if ( pDll == NULL )
  317. {
  318. LogMessage(LOG_ERROR, _T("[AddDll] Failed to allocate %d bytes"), sizeof(LOADEDDLL));
  319. return;
  320. }
  321. pDll->pszName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, (lstrlen(pszDllName) + 1) * sizeof(TCHAR));
  322. if ( pDll->pszName == NULL )
  323. {
  324. HeapFree(GetProcessHeap(), 0, pDll);
  325. LogMessage(LOG_ERROR,
  326. _T("[AddDll] Failed to allocate %d bytes"),
  327. (lstrlen(pszDllName) + 1) * sizeof(TCHAR));
  328. return;
  329. }
  330. lstrcpy(pDll->pszName, pszDllName);
  331. pDll->lpBaseOfDll = lpBaseOfDll;
  332. pDll->pNext = g_pFirstDll;
  333. g_pFirstDll = pDll;
  334. }
  335. LPTSTR GetDll( LPVOID lpBaseOfDll )
  336. /*++
  337. Return: The name of the DLL with the specified base address.
  338. Desc: BUGBUG
  339. --*/
  340. {
  341. PLOADEDDLL pDll = g_pFirstDll;
  342. while ( pDll != NULL )
  343. {
  344. if ( pDll->lpBaseOfDll == lpBaseOfDll )
  345. {
  346. return pDll->pszName;
  347. }
  348. pDll = pDll->pNext;
  349. }
  350. return NULL;
  351. }
  352. void RemoveDll( LPVOID lpBaseOfDll )
  353. /*++
  354. Return: void.
  355. Desc: BUGBUG: give details here
  356. --*/
  357. {
  358. PLOADEDDLL* ppDll = &g_pFirstDll;
  359. PLOADEDDLL pDllFree;
  360. while ( *ppDll != NULL )
  361. {
  362. if ( (*ppDll)->lpBaseOfDll == lpBaseOfDll )
  363. {
  364. HeapFree(GetProcessHeap(), 0, (*ppDll)->pszName);
  365. pDllFree = *ppDll;
  366. *ppDll = (*ppDll)->pNext;
  367. HeapFree(GetProcessHeap(), 0, pDllFree);
  368. break;
  369. }
  370. ppDll = &((*ppDll)->pNext);
  371. }
  372. }
  373. BOOL ProcessModuleLoad( PPROCESS_INFO pProcess, DEBUG_EVENT* pde )
  374. /*++
  375. Return: TRUE on success, FALSE otherwise
  376. Desc: Process all module load debug events, create process & dll load.
  377. The purpose is to allocate a MODULEINFO structure, fill in the
  378. necessary values, and load the symbol table.
  379. --*/
  380. {
  381. HANDLE hFile=NULL;
  382. DWORD_PTR dwBaseOfImage;
  383. if ( pde->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT )
  384. {
  385. hFile = pde->u.CreateProcessInfo.hFile;
  386. dwBaseOfImage = (DWORD_PTR)pde->u.CreateProcessInfo.lpBaseOfImage;
  387. SymInitialize(pProcess->hProcess, NULL, FALSE);
  388. }
  389. else if ( pde->dwDebugEventCode == LOAD_DLL_DEBUG_EVENT )
  390. {
  391. hFile = pde->u.LoadDll.hFile;
  392. dwBaseOfImage = (DWORD_PTR)pde->u.LoadDll.lpBaseOfDll;
  393. }
  394. if ( hFile == NULL || hFile == INVALID_HANDLE_VALUE )
  395. {
  396. return FALSE;
  397. }
  398. if ( dwBaseOfImage==(DWORD_PTR)NULL )
  399. {
  400. return FALSE;
  401. }
  402. if ( !SymLoadModule(pProcess->hProcess, hFile, NULL, NULL, dwBaseOfImage, 0) )
  403. {
  404. return FALSE;
  405. }
  406. return TRUE;
  407. }
  408. void DebuggerLoop( void )
  409. /*++
  410. Return: void.
  411. Desc: BUGBUG: give details here
  412. --*/
  413. {
  414. DEBUG_EVENT DebugEv; // debugging event information
  415. DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation
  416. PPROCESS_INFO pProcess = NULL;
  417. PTHREAD_INFO pThread = NULL;
  418. while ( TRUE )
  419. {
  420. //
  421. // Wait for a debugging event to occur. The second parameter indicates
  422. // that the function does not return until a debugging event occurs.
  423. //
  424. WaitForDebugEvent(&DebugEv, INFINITE);
  425. //
  426. // Update the processes and threads lists.
  427. //
  428. pProcess = g_pProcessHead;
  429. while ( pProcess != NULL )
  430. {
  431. if ( pProcess->dwProcessId == DebugEv.dwProcessId )
  432. {
  433. break;
  434. }
  435. pProcess = pProcess->pNext;
  436. }
  437. if ( pProcess == NULL )
  438. {
  439. //
  440. // New process.
  441. //
  442. pProcess = (PPROCESS_INFO)HeapAlloc(GetProcessHeap(),
  443. HEAP_ZERO_MEMORY,
  444. sizeof(PROCESS_INFO));
  445. if ( pProcess == NULL )
  446. {
  447. LogMessage(LOG_ERROR,
  448. _T("[DebuggerLoop] Failed to allocate memory for the new process. Fatal !"));
  449. break;
  450. }
  451. pProcess->dwProcessId = DebugEv.dwProcessId;
  452. pProcess->pNext = g_pProcessHead;
  453. g_pProcessHead = pProcess;
  454. }
  455. pThread = pProcess->pFirstThreadInfo;
  456. while ( pThread != NULL )
  457. {
  458. if ( pThread->dwThreadId == DebugEv.dwThreadId )
  459. {
  460. break;
  461. }
  462. pThread = pThread->pNext;
  463. }
  464. if ( pThread == NULL )
  465. {
  466. //
  467. // New thread.
  468. //
  469. pThread = (PTHREAD_INFO)HeapAlloc(GetProcessHeap(),
  470. HEAP_ZERO_MEMORY,
  471. sizeof(THREAD_INFO));
  472. if ( pThread == NULL )
  473. {
  474. LogMessage(LOG_ERROR,
  475. _T("[DebuggerLoop] Failed to allocate memory for the new thread. Fatal !"));
  476. break;
  477. }
  478. pThread->dwThreadId = DebugEv.dwThreadId;
  479. pThread->pNext = pProcess->pFirstThreadInfo;
  480. pProcess->pFirstThreadInfo = pThread;
  481. }
  482. dwContinueStatus = DBG_CONTINUE;
  483. if ( DebugEv.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT )
  484. {
  485. goto EndProcess;
  486. }
  487. switch ( DebugEv.dwDebugEventCode )
  488. {
  489. case EXCEPTION_DEBUG_EVENT:
  490. switch ( DebugEv.u.Exception.ExceptionRecord.ExceptionCode )
  491. {
  492. case EXCEPTION_BREAKPOINT:
  493. //
  494. // Hit a breakpoint.
  495. //
  496. if ( !pProcess->bSeenLdrBp )
  497. {
  498. pProcess->bSeenLdrBp = TRUE;
  499. //
  500. // When the initial breakpoint is hit all the
  501. // staticly linked DLLs are already loaded so
  502. // we can go ahead and set breakpoints.
  503. //
  504. LogMessage(LOG_INFO, _T("[DebuggerLoop] Hit initial breakpoint."));
  505. //
  506. // Now it would be a good time to initialize the debugger extensions.
  507. //
  508. break;
  509. }
  510. LogMessage(LOG_INFO, _T("[DebuggerLoop] Hit breakpoint."));
  511. LogAVStatus(AVS_PAGEHEAP_DOUBLEFREE);
  512. if ( MessageBox(NULL,
  513. _T("An Access Violation occured. Do you want to create")
  514. _T(" a crash dump file so you can later debug this problem ?"),
  515. _T("Error"),
  516. MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) == IDYES )
  517. {
  518. pProcess->DebugEvent = DebugEv;
  519. GenerateUserModeDump(g_szCrashDumpFile,
  520. pProcess,
  521. &DebugEv.u.Exception);
  522. }
  523. if ( MessageBox(NULL,
  524. _T("Do you want to continue running the program ?"),
  525. _T("Error"),
  526. MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) != IDYES )
  527. {
  528. goto EndProcess;
  529. }
  530. dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
  531. break;
  532. case STATUS_SINGLE_STEP:
  533. LogMessage(LOG_INFO, _T("[DebuggerLoop] Hit single step breakpoint."));
  534. break;
  535. case EXCEPTION_ACCESS_VIOLATION:
  536. LogMessage(LOG_INFO,
  537. _T("[DebuggerLoop] AV. Addr: 0x%08X, firstChance %d"),
  538. DebugEv.u.Exception.ExceptionRecord.ExceptionAddress,
  539. DebugEv.u.Exception.dwFirstChance);
  540. LogAVStatus(AVS_PAGEHEAP_DOUBLEFREE);
  541. if ( MessageBox(NULL,
  542. _T("An Access Violation occured. Do you want to create")
  543. _T(" a crash dump file so you can later debug this problem ?"),
  544. _T("Error"),
  545. MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) == IDYES )
  546. {
  547. pProcess->DebugEvent = DebugEv;
  548. GenerateUserModeDump(g_szCrashDumpFile,
  549. pProcess,
  550. &DebugEv.u.Exception);
  551. }
  552. if ( MessageBox(NULL,
  553. _T("Do you want to continue running the program ?"),
  554. _T("Error"),
  555. MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) != IDYES )
  556. {
  557. goto EndProcess;
  558. }
  559. dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
  560. break;
  561. default:
  562. LogMessage(LOG_INFO, _T("[DebuggerLoop] Unknown debugger exception."));
  563. dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
  564. break;
  565. }
  566. break;
  567. case CREATE_THREAD_DEBUG_EVENT:
  568. pThread->hProcess = pProcess->hProcess;
  569. pThread->hThread = DebugEv.u.CreateThread.hThread;
  570. LogMessage(LOG_INFO,
  571. _T("[DebuggerLoop] new thread. StartAddress: 0x%x"),
  572. DebugEv.u.CreateThread.lpStartAddress);
  573. break;
  574. case EXIT_THREAD_DEBUG_EVENT:
  575. LogMessage(LOG_INFO,
  576. _T("[DebuggerLoop] exiting thread with code: 0x%x"),
  577. DebugEv.u.ExitThread.dwExitCode);
  578. break;
  579. case CREATE_PROCESS_DEBUG_EVENT:
  580. pProcess->hProcess = DebugEv.u.CreateProcessInfo.hProcess;
  581. pThread->hProcess = pProcess->hProcess;
  582. pThread->hThread = DebugEv.u.CreateProcessInfo.hThread;
  583. if ( g_pFirstProcess == NULL )
  584. {
  585. g_pFirstProcess = pProcess;
  586. }
  587. pProcess->EntryPoint = DebugEv.u.CreateProcessInfo.lpStartAddress;
  588. ProcessModuleLoad(pProcess, &DebugEv);
  589. LogMessage(LOG_INFO,
  590. _T("[DebuggerLoop] new process. BaseImage: 0x%x StartAddress: 0x%x"),
  591. DebugEv.u.CreateProcessInfo.lpBaseOfImage,
  592. DebugEv.u.CreateProcessInfo.lpStartAddress);
  593. break;
  594. case LOAD_DLL_DEBUG_EVENT:
  595. {
  596. TCHAR szAsciiBuf[256];
  597. TCHAR szDllName[128];
  598. TCHAR szExt[16];
  599. BOOL bRet;
  600. bRet = GetImageName(pProcess->hProcess,
  601. (ULONG_PTR)DebugEv.u.LoadDll.lpBaseOfDll,
  602. DebugEv.u.LoadDll.lpImageName,
  603. szAsciiBuf,
  604. sizeof(szAsciiBuf));
  605. if (!bRet) {
  606. LogMessage(LOG_INFO,
  607. _T("[DebuggerLoop] DLL LOADED. BaseDll: 0x%X cannot get the name."),
  608. DebugEv.u.LoadDll.lpBaseOfDll);
  609. AddDll(DebugEv.u.LoadDll.lpBaseOfDll, NULL);
  610. } else {
  611. _tsplitpath(szAsciiBuf, NULL, NULL, szDllName, szExt);
  612. lstrcat(szDllName, szExt);
  613. AddDll(DebugEv.u.LoadDll.lpBaseOfDll, szDllName);
  614. LogMessage(LOG_INFO,
  615. _T("[DebuggerLoop] DLL LOADED. BaseDll: 0x%X \"%s\"."),
  616. DebugEv.u.LoadDll.lpBaseOfDll,
  617. szDllName);
  618. }
  619. ProcessModuleLoad(pProcess, &DebugEv);
  620. CloseHandle(DebugEv.u.LoadDll.hFile);
  621. break;
  622. }
  623. case UNLOAD_DLL_DEBUG_EVENT:
  624. {
  625. LPTSTR pszName = GetDll(DebugEv.u.UnloadDll.lpBaseOfDll);
  626. if ( pszName == NULL )
  627. {
  628. LogMessage(LOG_INFO,
  629. _T("[DebuggerLoop] DLL UNLOADED. BaseDll: 0x%X unknown."),
  630. DebugEv.u.UnloadDll.lpBaseOfDll);
  631. }
  632. else
  633. {
  634. LogMessage(LOG_INFO,
  635. _T("[DebuggerLoop] DLL UNLOADED. BaseDll: 0x%X \"%s\"."),
  636. DebugEv.u.UnloadDll.lpBaseOfDll, pszName);
  637. }
  638. RemoveDll(DebugEv.u.UnloadDll.lpBaseOfDll);
  639. break;
  640. }
  641. case OUTPUT_DEBUG_STRING_EVENT:
  642. ReadMemoryDbg(pThread->hProcess,
  643. DebugEv.u.DebugString.lpDebugStringData,
  644. g_szDbgString,
  645. DebugEv.u.DebugString.nDebugStringLength);
  646. #ifdef UNICODE
  647. LogMessage(LOG_INFO, _T("DPF - %S"), g_szDbgString);
  648. #else
  649. LogMessage(LOG_INFO, _T("DPF - %s"), g_szDbgString);
  650. #endif // UNICODE
  651. break;
  652. default:
  653. LogMessage(LOG_ERROR,
  654. _T("[DebuggerLoop] Unknown event 0x%X"),
  655. DebugEv.dwDebugEventCode);
  656. break;
  657. }
  658. //
  659. // Resume executing the thread that reported the debugging event.
  660. //
  661. ContinueDebugEvent(DebugEv.dwProcessId,
  662. DebugEv.dwThreadId,
  663. dwContinueStatus);
  664. }
  665. EndProcess:
  666. LogMessage(LOG_INFO, _T("[DebuggerLoop] The debugged process has exited."));
  667. LogAVStatus(AVS_APP_TERMINATED);
  668. }