home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / debug / deb / debdebug.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  73KB  |  1,957 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. // ************************************************************************
  13. // MODULE    : DEBDebug.C
  14. // PURPOSE   : Debug support functions for the Debug Event Browser
  15. // FUNCTIONS :
  16. //   DebugEventThread()         - debug event processing thread
  17. // COMMENTS  :
  18. //
  19. // ************************************************************************
  20. #define   STRICT               // enable strict typing
  21. #include <Windows.H>           // required for all Windows applications
  22. #include <StdDef.H>            // offsetof()
  23.  
  24. #include "LinkList.H"          // include the linked list functions
  25. #include "DEBMisc.H"           // include the misc. support functions
  26. #include "DEBDebug.H"          // include the DEB debugging functions
  27.  
  28. // internal global data
  29. // ------------------------------------------------------------------------
  30. HANDLE hHeap;                  // local heap
  31. PLIST  pProcessList;           // pointer to the process list
  32. BOOL   fFinished = FALSE;      // set to TRUE if the DebugEventThread
  33.                                //  is no longer needed (such as the
  34.                                //  debuggee failed to load or the number
  35.                                //  of debuggee threads goes to zero
  36.                                //  indicating debug session termination
  37.  
  38. static TCHAR szSourceFileName[] = TEXT(__FILE__);
  39.  
  40. // internal function prototypes
  41. // ------------------------------------------------------------------------
  42.  
  43. //-- debug event handling functions
  44. BOOL HandleExceptionEvent( LPDEBUG_EVENT );
  45. BOOL HandleBreakPointException( LPDEBUG_EVENT );
  46. BOOL HandleCreateThreadEvent( LPDEBUG_EVENT );
  47. BOOL HandleCreateProcessEvent( LPDEBUG_EVENT );
  48. BOOL HandleExitThreadEvent( LPDEBUG_EVENT );
  49. BOOL HandleExitProcessEvent( LPDEBUG_EVENT );
  50. BOOL HandleLoadDllEvent( LPDEBUG_EVENT );
  51. BOOL HandleUnloadDllEvent( LPDEBUG_EVENT );
  52. BOOL HandleOutputDebugStringEvent( LPDEBUG_EVENT );
  53. BOOL HandleRipEvent( LPDEBUG_EVENT );
  54. BOOL HandleUnknownEvent( LPDEBUG_EVENT );
  55.  
  56. //-- misc debug event helper functions
  57. BOOL  DebugNewProcess( LPTSTR, LPTSTR );
  58. BOOL  GetDllFileName( LPDEBUG_EVENT, LPTSTR, DWORD );
  59. BOOL  GetDllFileNameFromList( LPDEBUG_EVENT, LPTSTR, DWORD );
  60. BOOL  GetOutputDebugString( LPDEBUG_EVENT, LPTSTR, DWORD );
  61. DWORD GetModuleFileNameFromHeader( HANDLE, HANDLE, DWORD, LPTSTR, DWORD );
  62. #if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
  63.  BOOL  SkipBreakPoint( HANDLE );
  64. #endif
  65.  
  66. //-- linked list wrapper functions
  67.  
  68. //-- process list and node specific linked list wrapper functions
  69. int  ProcessOrderFunction( PNODE, PNODE );
  70. BOOL CreateProcessList( PLIST* );
  71. BOOL DestroyProcessList( PLIST );
  72. BOOL AllocProcessNode( PNODE*, PDEB_PROCESS_NODE_INFO* );
  73. BOOL InitProcessNodeInfo( PDEB_PROCESS_NODE_INFO*, LPDEBUG_EVENT );
  74. BOOL InsertProcessNode( PLIST, PNODE );
  75. BOOL SetCurrentProcessNode( PLIST, PNODE );
  76. BOOL DeleteProcessNode( PLIST, PNODE );
  77. BOOL FreeProcessNodeInfo( PNODE );
  78. BOOL DestroyProcessNode( PNODE );
  79. BOOL DeleteCurrentProcessNode( PLIST );
  80.  
  81. //-- thread list and node specific linked list wrapper functions
  82. int  ThreadOrderFunction( PNODE, PNODE );
  83. BOOL CreateThreadList( PLIST* );
  84. BOOL DestroyThreadList( PLIST );
  85. BOOL AllocThreadNode( PNODE*, PDEB_THREAD_NODE_INFO* );
  86. BOOL InitThreadNodeInfo( PDEB_THREAD_NODE_INFO*, LPDEBUG_EVENT );
  87. BOOL InsertThreadNode( PLIST, PNODE );
  88. BOOL SetCurrentThreadNode( PLIST, PNODE );
  89. BOOL DeleteThreadNode( PLIST, PNODE );
  90. BOOL FreeThreadNodeInfo( PNODE );
  91. BOOL DestroyThreadNode( PNODE );
  92. BOOL DeleteCurrentThreadNode( PLIST );
  93.  
  94. //-- dll list and node specific linked list wrapper functions
  95. int  DllOrderFunction( PNODE, PNODE );
  96. BOOL CreateDllList( PLIST* );
  97. BOOL DestroyDllList( PLIST );
  98. BOOL AllocDllNode( PNODE*, PDEB_DLL_NODE_INFO* );
  99. BOOL InitDllNodeInfo( PDEB_DLL_NODE_INFO*, LPDEBUG_EVENT );
  100. BOOL InsertDllNode( PLIST, PNODE );
  101. BOOL SetCurrentDllNode( PLIST, PNODE );
  102. BOOL DeleteDllNode( PLIST, PNODE );
  103. BOOL FreeDllNodeInfo( PNODE );
  104. BOOL DestroyDllNode( PNODE );
  105. BOOL DeleteCurrentDllNode( PLIST );
  106.  
  107.  
  108. // ************************************************************************
  109. // FUNCTION : DebugEventThread( PDEB_STARTUP_INFO )
  110. // PURPOSE  : Main debug event processing loop
  111. // COMMENTS :
  112. //   A new debug event thread is created for each Debuggee process.
  113. //   Return TRUE (non 0) if success, else FALSE (0)
  114. // ************************************************************************
  115. DWORD WINAPI
  116. DebugEventThread( PDEB_STARTUP_INFO pDebStartupInfo )
  117. {
  118.   #define BUFFER_SIZE 256
  119.  
  120.   static BOOL  fFirstTime = TRUE;
  121.   static TCHAR szDebuggeeTitle[128];
  122.  
  123.   DEBUG_EVENT  DebugEvent;
  124.  
  125.   LPTSTR lpszDebugEventBuffer;
  126.   LPTSTR lpszTempBuffer;
  127.  
  128.   //-- set the minimum error level for debugging events
  129.   SetDebugErrorLevel( Profile.DebugErrorLevel );
  130.  
  131.   if( fFirstTime ) {
  132.     if( !LoadString( Global.hInstance, IDS_OFN_DEBUGGEE_TITLE, szDebuggeeTitle,
  133.            sizeof(szDebuggeeTitle)/sizeof(TCHAR) ) )
  134.       ErrorMessageBox( TEXT("LoadString()"),
  135.         Global.szApiFailed, szSourceFileName, __LINE__ );
  136.   }
  137.  
  138.   //-- determine if 'attach to' or 'open new' debuggee
  139.   if( pDebStartupInfo->fActive ) {
  140.     if( !DebugActiveProcess( pDebStartupInfo->dwProcessId ) )
  141.       ErrorMessageBox( TEXT("DebugActiveProcess()"),
  142.         Global.szApiFailed, szSourceFileName, __LINE__ );
  143.   }
  144.   else {
  145.     if( !DebugNewProcess( pDebStartupInfo->lpstrPathName, szDebuggeeTitle ) )
  146.     ExitThread( FALSE );
  147.   }
  148.  
  149.   //-- increment active process count
  150.   Global.dwActiveDebuggees++;
  151.  
  152.   //-- create a local heap
  153.   {
  154.     SYSTEM_INFO SysInfo;
  155.  
  156.     GetSystemInfo( &SysInfo );  // get the system memory page size
  157.     hHeap = HeapCreate( (DWORD) NULL, SysInfo.dwPageSize, 1000*SysInfo.dwPageSize );
  158.   }
  159.  
  160.   //-- create and initialize the process list
  161.   CreateProcessList( &pProcessList );
  162.  
  163.   //-- alloc temporary (life of thread) string buffers
  164.   lpszDebugEventBuffer = (LPTSTR) HeapAlloc( hHeap, (DWORD) NULL, BUFFER_SIZE );
  165.   lpszTempBuffer = (LPTSTR) HeapAlloc( hHeap, (DWORD) NULL, BUFFER_SIZE );
  166.  
  167.   // ----------------------------------------------------------------------
  168.   // begin debug event processing loop
  169.   // ----------------------------------------------------------------------
  170.   for(;;) {
  171.  
  172.     //-- wait for debug events
  173.     if( !WaitForDebugEvent( &DebugEvent, INFINITE ) ) {
  174.       ListBoxPrintF( pDebStartupInfo->hWndListBox, TEXT( "%s" ), TEXT( "Failed to attach to Debuggee..." ) );
  175.       fFinished = TRUE;
  176.       break;
  177.     }
  178.  
  179.     // --------------------------------------------------------------------
  180.     // display each debug event as it occurs and handle minimal debug
  181.     // event processing
  182.     // --------------------------------------------------------------------
  183.     MakeCommonDebugEventString( lpszDebugEventBuffer, &DebugEvent );
  184.  
  185.     switch( DebugEvent.dwDebugEventCode ) {
  186.  
  187.       // ------------------------------------------------------------------
  188.       // exception occured
  189.       // ------------------------------------------------------------------
  190.       case EXCEPTION_DEBUG_EVENT:
  191.  
  192.         //-- figure out which type of exception
  193.         switch( DebugEvent.u.Exception.ExceptionRecord.ExceptionCode ) {
  194.  
  195.           //--standard exceptions
  196.           case EXCEPTION_ACCESS_VIOLATION:
  197.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  198.               TEXT( "Exception: " ), TEXT( "Access Violation" ) );
  199.             break;
  200.  
  201.           case EXCEPTION_DATATYPE_MISALIGNMENT:
  202.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  203.               TEXT( "Exception: " ), TEXT( "Datatype Misalignment" ) );
  204.             break;
  205.  
  206.           case EXCEPTION_BREAKPOINT:
  207.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  208.               TEXT( "Exception: " ), TEXT( "Breakpoint" ) );
  209.             break;
  210.  
  211.           case EXCEPTION_SINGLE_STEP:
  212.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  213.               TEXT( "Exception: " ), TEXT( "Single Step" ) );
  214.             break;
  215.  
  216.           case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  217.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  218.               TEXT( "Exception: " ), TEXT( "Array Bound Exceeded" ) );
  219.             break;
  220.  
  221.           case EXCEPTION_FLT_DENORMAL_OPERAND:
  222.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  223.               TEXT( "Exception: " ), TEXT( "Floating Point" ),
  224.               TEXT( "Denormal Operand" ) );
  225.             break;
  226.  
  227.           case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  228.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  229.               TEXT( "Exception: " ), TEXT( "Floating Point" ),
  230.               TEXT( "Divide By Zero" ) );
  231.             break;
  232.  
  233.           case EXCEPTION_FLT_INEXACT_RESULT:
  234.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  235.               TEXT( "Exception: " ), TEXT( "Floating Point" ),
  236.               TEXT( "Inexact Result" ) );
  237.             break;
  238.  
  239.           case EXCEPTION_FLT_INVALID_OPERATION:
  240.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  241.               TEXT( "Exception: " ), TEXT( "Floating Point" ),
  242.               TEXT( "Invalid Operation" ) );
  243.             break;
  244.  
  245.           case EXCEPTION_FLT_OVERFLOW:
  246.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  247.               TEXT( "Exception: " ), TEXT( "Floating Point" ),
  248.               TEXT( "Overflow" ) );
  249.             break;
  250.  
  251.           case EXCEPTION_FLT_STACK_CHECK:
  252.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  253.               TEXT( "Exception: " ), TEXT( "Floating Point" ),
  254.               TEXT( "Stack Check" ) );
  255.             break;
  256.  
  257.           case EXCEPTION_FLT_UNDERFLOW:
  258.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  259.               TEXT( "Exception: " ), TEXT( "Floating Point" ),
  260.               TEXT( "Underflow" ) );
  261.             break;
  262.  
  263.           case EXCEPTION_INT_DIVIDE_BY_ZERO:
  264.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  265.               TEXT( "Exception: " ), TEXT( "Integer" ),
  266.               TEXT( "Divide By Zero" ) );
  267.             break;
  268.  
  269.           case EXCEPTION_INT_OVERFLOW:
  270.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s %s" ),
  271.               TEXT( "Exception: " ), TEXT( "Integer" ),
  272.               TEXT( "Overflow" ) );
  273.             break;
  274.  
  275.           case EXCEPTION_PRIV_INSTRUCTION:
  276.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  277.               TEXT( "Exception: " ), TEXT( "Privileged Instruction" ) );
  278.             break;
  279.  
  280.           case EXCEPTION_IN_PAGE_ERROR:
  281.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  282.               TEXT( "Exception: " ), TEXT( "In Page Error" ) );
  283.             break;
  284.  
  285.           //-- Debug exceptions
  286.           case DBG_TERMINATE_THREAD:
  287.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  288.               TEXT( "Debug Exception: " ), TEXT( "Terminate Thread" ) );
  289.             break;
  290.  
  291.           case DBG_TERMINATE_PROCESS:
  292.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  293.               TEXT( "Debug Exception: " ), TEXT( "Terminate Process" ) );
  294.             break;
  295.  
  296.           case DBG_CONTROL_C:
  297.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  298.               TEXT( "Debug Exception: " ), TEXT( "Control+C" ) );
  299.             break;
  300.  
  301.           case DBG_CONTROL_BREAK:
  302.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  303.               TEXT( "Debug Exception: " ), TEXT( "Control+Break" ) );
  304.             break;
  305.  
  306.           //-- RPC exceptions (some)
  307.           case RPC_S_UNKNOWN_IF:
  308.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  309.               TEXT( "RPC Exception: " ), TEXT( "Unknown Interface" ) );
  310.             break;
  311.  
  312.           case RPC_S_SERVER_UNAVAILABLE:
  313.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s" ),
  314.               TEXT( "RPC Exception: " ), TEXT( "Server Unavailable" ) );
  315.             break;
  316.  
  317.           //-- VDM exceptions (minimal information)
  318.           case EXCEPTION_VDM_EVENT:  // see DEBDebug.H for definition
  319.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  320.               TEXT( "VDM Exception: " ) );
  321.  
  322.           default:
  323.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s%s%X%s" ),
  324.               TEXT( "Exception: " ), TEXT( "Unknown [0x" ),
  325.                DebugEvent.u.Exception.ExceptionRecord.ExceptionCode,
  326.                TEXT( "]" ) );
  327.             break;
  328.  
  329.         }
  330.         if( Profile.fVerbose ) {
  331.           StringAppendF( lpszDebugEventBuffer, TEXT( "\n + %s%d" ),
  332.             TEXT( "dwFirstChance: " ), DebugEvent.u.Exception.dwFirstChance );
  333.         }
  334.         else {
  335.           if( DebugEvent.u.Exception.dwFirstChance != 0 )
  336.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  337.               TEXT( " - First Chance" ) );
  338.           else
  339.             StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  340.               TEXT( " - Second Chance" ) );
  341.         }
  342.         HandleExceptionEvent( &DebugEvent );
  343.         break;
  344.  
  345.       // ------------------------------------------------------------------
  346.       // new thread started
  347.       // ------------------------------------------------------------------
  348.       case CREATE_THREAD_DEBUG_EVENT:
  349.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  350.           TEXT( "Create Thread: " ) );
  351.         if( Profile.fVerbose ) {
  352.           StringAppendF( lpszDebugEventBuffer, TEXT( "\n + %s%d\n + %s%X\n + %s%d" ),
  353.             TEXT( "hThread:0x" ), DebugEvent.u.CreateThread.hThread,
  354.             TEXT( "lpThreadLocalBase:0x" ), DebugEvent.u.CreateThread.lpThreadLocalBase,
  355.             TEXT( "lpStartAddress:0x" ), DebugEvent.u.CreateThread.lpStartAddress );
  356.         }
  357.         HandleCreateThreadEvent( &DebugEvent );
  358.         break;
  359.  
  360.       // ------------------------------------------------------------------
  361.       // new process started
  362.       // ------------------------------------------------------------------
  363.       case CREATE_PROCESS_DEBUG_EVENT:
  364.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  365.           TEXT( "Create Process: " ) );
  366.         if( Profile.fVerbose ) {
  367.           StringAppendF( lpszDebugEventBuffer,
  368.             TEXT( "\n + %s%X\n + %s%X\n + %s%X\n + %s%X\n + %s%d" )
  369.             TEXT( "\n + %s%d\n + %s%X\n + %s%X\n + %s%X\n + %s%d" ),
  370.             TEXT( "hFile:0x" ), DebugEvent.u.CreateProcessInfo.hFile,
  371.             TEXT( "hProcess:0x" ), DebugEvent.u.CreateProcessInfo.hProcess,
  372.             TEXT( "hThread:0x" ), DebugEvent.u.CreateProcessInfo.hThread,
  373.             TEXT( "lpBaseOfImage:0x" ), DebugEvent.u.CreateProcessInfo.lpBaseOfImage,
  374.             TEXT( "dwDebugInfoFileOffset: " ), DebugEvent.u.CreateProcessInfo.dwDebugInfoFileOffset,
  375.             TEXT( "nDebugInfoSize: " ), DebugEvent.u.CreateProcessInfo.nDebugInfoSize,
  376.             TEXT( "lpThreadLocalBase:0x" ), DebugEvent.u.CreateProcessInfo.lpThreadLocalBase,
  377.             TEXT( "lpStartAddress:0x" ), DebugEvent.u.CreateProcessInfo.lpStartAddress,
  378.             TEXT( "lpImageName:0x" ), DebugEvent.u.CreateProcessInfo.lpImageName,
  379.             TEXT( "fUnicode: " ), DebugEvent.u.CreateProcessInfo.fUnicode );
  380.         }
  381.         HandleCreateProcessEvent( &DebugEvent );
  382.         break;
  383.  
  384.       // ------------------------------------------------------------------
  385.       // existing thread terminated
  386.       // ------------------------------------------------------------------
  387.       case EXIT_THREAD_DEBUG_EVENT:
  388.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  389.           TEXT( "Exit Thread: " ) );
  390.         if( Profile.fVerbose ) {
  391.           StringAppendF( lpszDebugEventBuffer, TEXT( "\n + %s%d" ),
  392.             TEXT( "dwExitCode: " ), DebugEvent.u.ExitThread.dwExitCode );
  393.         }
  394.         else {
  395.           StringAppendF( lpszDebugEventBuffer, TEXT( "%s%d" ),
  396.             TEXT( "Returned " ), DebugEvent.u.ExitThread.dwExitCode );
  397.         }
  398.         HandleExitThreadEvent( &DebugEvent );
  399.         break;
  400.  
  401.       // ------------------------------------------------------------------
  402.       // existing process terminated
  403.       // ------------------------------------------------------------------
  404.       case EXIT_PROCESS_DEBUG_EVENT:
  405.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  406.           TEXT( "Exit Process: " ) );
  407.         if( Profile.fVerbose ) {
  408.           StringAppendF( lpszDebugEventBuffer, TEXT( "\n + %s%d" ),
  409.             TEXT( "dwExitCode: " ), DebugEvent.u.ExitProcess.dwExitCode );
  410.         }
  411.         else {
  412.           StringAppendF( lpszDebugEventBuffer, TEXT( "%s%d" ),
  413.             TEXT( "Returned " ), DebugEvent.u.ExitProcess.dwExitCode );
  414.         }
  415.         HandleExitProcessEvent( &DebugEvent );
  416.         break;
  417.  
  418.       // ------------------------------------------------------------------
  419.       // new DLL loaded
  420.       // ------------------------------------------------------------------
  421.       case LOAD_DLL_DEBUG_EVENT:
  422.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  423.           TEXT( "Load DLL: " ) );
  424.         lstrcpy( lpszTempBuffer, TEXT("Empty!") );
  425.         GetDllFileName( &DebugEvent, lpszTempBuffer, BUFFER_SIZE );
  426.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ), lpszTempBuffer );
  427.         if( Profile.fVerbose ) {
  428.           StringAppendF( lpszDebugEventBuffer,
  429.             TEXT( "\n + %s%X\n + %s%X\n + %s%d\n + %s%d\n + %s%X\n + %s%d" ),
  430.             TEXT( "hFile:0x" ), DebugEvent.u.LoadDll.hFile,
  431.             TEXT( "lpBaseOfDll:0x" ), DebugEvent.u.LoadDll.lpBaseOfDll,
  432.             TEXT( "dwDebugInfoFileOffset: " ), DebugEvent.u.LoadDll.dwDebugInfoFileOffset,
  433.             TEXT( "nDebugInfoSize: " ), DebugEvent.u.LoadDll.nDebugInfoSize,
  434.             TEXT( "lpImageName:0x" ), DebugEvent.u.LoadDll.lpImageName,
  435.             TEXT( "fUnicode: " ), DebugEvent.u.LoadDll.fUnicode );
  436.         }
  437.         HandleLoadDllEvent( &DebugEvent );
  438.         break;
  439.  
  440.       // ------------------------------------------------------------------
  441.       // existing DLL explicitly unloaded
  442.       // ------------------------------------------------------------------
  443.       case UNLOAD_DLL_DEBUG_EVENT:
  444.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ), TEXT( "Unload DLL: " ) );
  445.         GetDllFileNameFromList( &DebugEvent, lpszTempBuffer, BUFFER_SIZE );
  446.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ), lpszTempBuffer );
  447.         if( Profile.fVerbose ) {
  448.           StringAppendF( lpszDebugEventBuffer, TEXT( "\n + %s%X" ),
  449.             TEXT( "lpBaseOfDLL:0x" ), DebugEvent.u.UnloadDll.lpBaseOfDll );
  450.         }
  451.         HandleUnloadDllEvent( &DebugEvent );
  452.         break;
  453.  
  454.       // ------------------------------------------------------------------
  455.       // OutputDebugString() occured
  456.       // ------------------------------------------------------------------
  457.       case OUTPUT_DEBUG_STRING_EVENT:
  458.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  459.           TEXT( "Output Debug String: " ) );
  460.         GetOutputDebugString( &DebugEvent, lpszTempBuffer, BUFFER_SIZE );
  461.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ), lpszTempBuffer );
  462.         if( Profile.fVerbose ) {
  463.           StringAppendF( lpszDebugEventBuffer, TEXT( "\n + %s%X\n + %s%d\n + %s%d" ),
  464.             TEXT( "lpDebugStringData:0x" ), DebugEvent.u.DebugString.lpDebugStringData,
  465.             TEXT( "fUnicode: " ), DebugEvent.u.DebugString.fUnicode,
  466.             TEXT( "nDebugStringLength: " ), DebugEvent.u.DebugString.nDebugStringLength );
  467.         }
  468.         HandleOutputDebugStringEvent( &DebugEvent );
  469.         break;
  470.  
  471.       // ------------------------------------------------------------------
  472.       // RIP occured
  473.       // ------------------------------------------------------------------
  474.       case RIP_EVENT:
  475.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s" ),
  476.           TEXT( "RIP" ) );
  477.         if( Profile.fVerbose ) {
  478.           StringAppendF( lpszDebugEventBuffer, TEXT( "\n + %s%d\n + %s%d" ),
  479.             TEXT( "dwError: " ), DebugEvent.u.RipInfo.dwError,
  480.             TEXT( "dwType: " ), DebugEvent.u.RipInfo.dwType );
  481.         }
  482.         HandleRipEvent( &DebugEvent );
  483.         break;
  484.  
  485.       // ------------------------------------------------------------------
  486.       // unknown debug event occured
  487.       // ------------------------------------------------------------------
  488.       default:
  489.         StringAppendF( lpszDebugEventBuffer, TEXT( "%s%X%s" ),
  490.           TEXT( "Debug Event:Unknown [0x" ),
  491.           DebugEvent.dwDebugEventCode, lpszTempBuffer,
  492.           TEXT( "]" ) );
  493.         HandleUnknownEvent( &DebugEvent );
  494.         break;
  495.     }
  496.  
  497.     //-- insert the debug event string into the listbox
  498.     ListBoxPrintF( pDebStartupInfo->hWndListBox, TEXT( "%s" ), lpszDebugEventBuffer );
  499.  
  500.     //-- default action, just continue
  501.     if( fFinished ) {
  502.       fFinished = FALSE;   // reset the value
  503.       break;
  504.     }
  505.     else
  506.       ContinueDebugEvent( DebugEvent.dwProcessId, DebugEvent.dwThreadId,
  507.         DBG_CONTINUE );
  508.   }
  509.  
  510.   //-- free temporary (life of thread) string buffers
  511.   HeapFree( hHeap, (DWORD) NULL, (PVOID) lpszDebugEventBuffer );
  512.   HeapFree( hHeap, (DWORD) NULL, (PVOID) lpszTempBuffer );
  513.  
  514.   //-- free list
  515.   DestroyProcessList( pProcessList );
  516.  
  517.   //-- free the heap
  518.   HeapDestroy( hHeap );
  519.  
  520.   //-- decrement active process count
  521.   Global.dwActiveDebuggees--;
  522.   ExitThread( TRUE );
  523.  
  524.   return( TRUE );  // avoid the "no return value" warning
  525. }
  526.  
  527.  
  528. // ========================================================================
  529. // debug event handling functions
  530. // ========================================================================
  531.  
  532.  
  533. // ************************************************************************
  534. // FUNCTION : HandleExceptionEvent( LPDEBUG_EVENT lpDebugEvent )
  535. // PURPOSE  : handle EXCEPTION_DEBUG_EVENT
  536. // COMMENTS : except for the BreakPoint event, continue and let the
  537. //            application or system exception handlers to the work
  538. // ************************************************************************
  539. BOOL
  540. HandleExceptionEvent( LPDEBUG_EVENT lpDebugEvent )
  541. {
  542.   switch( lpDebugEvent->u.Exception.ExceptionRecord.ExceptionCode ) {
  543.  
  544.     case EXCEPTION_BREAKPOINT:
  545.       HandleBreakPointException( lpDebugEvent );
  546.       break;
  547.  
  548.     default:
  549.       ContinueDebugEvent( lpDebugEvent->dwProcessId, lpDebugEvent->dwThreadId,
  550.         DBG_EXCEPTION_NOT_HANDLED );
  551.  
  552.   }
  553.  
  554.   return( TRUE );
  555. }
  556.  
  557.  
  558. // ************************************************************************
  559. // FUNCTION : HandleBreakPointException( LPDEBUG_EVENT lpDebugEvent )
  560. // PURPOSE  : handle the BREAKPOINT exception
  561. // COMMENTS : search process list, search thread list, skip over breakpoint
  562. // ************************************************************************
  563. BOOL
  564. HandleBreakPointException( LPDEBUG_EVENT lpDebugEvent )
  565. {
  566. #if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
  567.   PNODE                  pProcessNode, pSearchProcessNode;
  568.   PNODE                  pThreadNode, pSearchThreadNode;
  569.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo, pSearchProcessNodeInfo;
  570.   PDEB_THREAD_NODE_INFO  pThreadNodeInfo, pSearchThreadNodeInfo;
  571.   PDEB_THREAD_LIST_INFO  pThreadListInfo;
  572.  
  573.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  574.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  575.   SetCurrentProcessNode( pProcessList, pSearchProcessNode );
  576.   GetCurrentNode( pProcessList, &pProcessNode );
  577.   pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  578.   pThreadListInfo = (PDEB_THREAD_LIST_INFO) pProcessNodeInfo->pThreadList->pListData;
  579.   //-- if no thread nodes then hThread is stored in the process node
  580.   if( !pThreadListInfo->dwActiveThreads ) {
  581.     SkipBreakPoint( (pProcessNodeInfo->ProcessDebugInfo).hThread );
  582.   }
  583.   else {
  584.     AllocThreadNode( &pSearchThreadNode, &pSearchThreadNodeInfo );
  585.     pSearchThreadNodeInfo->dwThreadId = lpDebugEvent->dwThreadId;
  586.     SetCurrentThreadNode( pProcessNodeInfo->pThreadList, pSearchThreadNode );
  587.     GetCurrentNode( pProcessNodeInfo->pThreadList, &pThreadNode );
  588.     pThreadNodeInfo = (PDEB_THREAD_NODE_INFO) pThreadNode->pNodeData;
  589.     SkipBreakPoint( (pThreadNodeInfo->ThreadDebugInfo).hThread );
  590.     DestroyThreadNode( pSearchThreadNode );
  591.   }
  592.   DestroyProcessNode( pSearchProcessNode );
  593.  #else
  594.   ContinueDebugEvent( lpDebugEvent->dwProcessId, lpDebugEvent->dwThreadId,
  595.     DBG_CONTINUE );
  596.  #endif
  597.  
  598.   return( TRUE );
  599. }
  600.  
  601.  
  602. // ************************************************************************
  603. // FUNCTION : HandleCreateThreadEvent( LPDEBUG_EVENT )
  604. // PURPOSE  : handle CREATE_THREAD_DEBUG_EVENT
  605. // COMMENTS : search process list, insert new thread node
  606. // ************************************************************************
  607. BOOL
  608. HandleCreateThreadEvent( LPDEBUG_EVENT lpDebugEvent )
  609. {
  610.   PNODE                  pProcessNode, pSearchProcessNode;
  611.   PNODE                  pThreadNode;
  612.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo, pSearchProcessNodeInfo;
  613.   PDEB_THREAD_NODE_INFO  pThreadNodeInfo;
  614.  
  615.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  616.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  617.   SetCurrentProcessNode( pProcessList, pSearchProcessNode );
  618.   GetCurrentNode( pProcessList, &pProcessNode );
  619.   pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  620.   AllocThreadNode( &pThreadNode, &pThreadNodeInfo );
  621.   InitThreadNodeInfo( &pThreadNodeInfo, lpDebugEvent );
  622.   InsertThreadNode( pProcessNodeInfo->pThreadList, pThreadNode );
  623.   DestroyProcessNode( pSearchProcessNode );
  624.  
  625.   return( TRUE );
  626. }
  627.  
  628.  
  629. // ************************************************************************
  630. // FUNCTION : HandleCreateProcessEvent( LPDEBUG_EVENT )
  631. // PURPOSE  : handle CREATE_PROCESS_DEBUG_EVENT
  632. // COMMENTS : insert new process node
  633. // ************************************************************************
  634. BOOL
  635. HandleCreateProcessEvent( LPDEBUG_EVENT lpDebugEvent )
  636. {
  637.   PNODE                  pProcessNode;
  638.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo;
  639.  
  640.   AllocProcessNode( &pProcessNode, &pProcessNodeInfo );
  641.   InitProcessNodeInfo( &pProcessNodeInfo, lpDebugEvent );
  642.   InsertProcessNode( pProcessList, pProcessNode );
  643.  
  644.   return( TRUE );
  645. }
  646.  
  647.  
  648. // ************************************************************************
  649. // FUNCTION : HandleExitThreadEvent( LPDEBUG_EVENT )
  650. // PURPOSE  : handle EXIT_THREAD_DEBUG_EVENT
  651. // COMMENTS : search process list, search thread list, delete existing
  652. //            thread node
  653. // ************************************************************************
  654. BOOL
  655. HandleExitThreadEvent( LPDEBUG_EVENT lpDebugEvent )
  656. {
  657.   PNODE                  pProcessNode, pSearchProcessNode;
  658.   PNODE                  pSearchThreadNode;
  659.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo, pSearchProcessNodeInfo;
  660.   PDEB_THREAD_NODE_INFO  pSearchThreadNodeInfo;
  661.  
  662.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  663.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  664.   SetCurrentProcessNode( pProcessList, pSearchProcessNode );
  665.   GetCurrentNode( pProcessList, &pProcessNode );
  666.   pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  667.   AllocThreadNode( &pSearchThreadNode, &pSearchThreadNodeInfo );
  668.   pSearchThreadNodeInfo->dwThreadId = lpDebugEvent->dwThreadId;
  669.   DeleteThreadNode( pProcessNodeInfo->pThreadList, pSearchThreadNode );
  670.   DestroyThreadNode( pSearchThreadNode );
  671.   DestroyProcessNode( pSearchProcessNode );
  672.  
  673.   return( TRUE );
  674. }
  675.  
  676.  
  677. // ************************************************************************
  678. // FUNCTION : HandleExitProcessEvent( LPDEBUG_EVENT )
  679. // PURPOSE  : handle EXIT_PROCESS_DEBUG_EVENT
  680. // COMMENTS : search process list, delete existing process node,
  681. // ************************************************************************
  682. BOOL
  683. HandleExitProcessEvent( LPDEBUG_EVENT lpDebugEvent )
  684. {
  685.   PNODE                  pSearchProcessNode;
  686.   PDEB_PROCESS_NODE_INFO pSearchProcessNodeInfo;
  687.   PDEB_PROCESS_LIST_INFO pProcessListInfo;
  688.  
  689.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  690.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  691.   DeleteProcessNode( pProcessList, pSearchProcessNode );
  692.   //-- if last process? free all temporary memory, exit thread
  693.   pProcessListInfo = (PDEB_PROCESS_LIST_INFO) pProcessList->pListData;
  694.   if( !pProcessListInfo->dwActiveProcesses )
  695.     fFinished = TRUE;
  696.   DestroyProcessNode( pSearchProcessNode );
  697.  
  698.   return( TRUE );
  699. }
  700.  
  701.  
  702. // ************************************************************************
  703. // FUNCTION : HandleLoadDllEvent( LPDEBUG_EVENT )
  704. // PURPOSE  : handle LOAD_DLL_DEBUG_EVENT
  705. // COMMENTS : search process list, insert new DLL node
  706. // ************************************************************************
  707. BOOL
  708. HandleLoadDllEvent( LPDEBUG_EVENT lpDebugEvent )
  709. {
  710.   PNODE                  pProcessNode, pSearchProcessNode;
  711.   PNODE                  pDllNode;
  712.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo, pSearchProcessNodeInfo;
  713.   PDEB_DLL_NODE_INFO     pDllNodeInfo;
  714.  
  715.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  716.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  717.   SetCurrentProcessNode( pProcessList, pSearchProcessNode );
  718.   GetCurrentNode( pProcessList, &pProcessNode );
  719.   pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  720.   AllocDllNode( &pDllNode, &pDllNodeInfo );
  721.   InitDllNodeInfo( &pDllNodeInfo, lpDebugEvent );
  722.   InsertDllNode( pProcessNodeInfo->pDllList, pDllNode );
  723.   DestroyProcessNode( pSearchProcessNode );
  724.  
  725.   return( TRUE );
  726. }
  727.  
  728.  
  729. // ************************************************************************
  730. // FUNCTION : HandleUnloadDllEvent( LPDEBUG_EVENT )
  731. // PURPOSE  : handle UNLOAD_DLL_DEBUG_EVENT
  732. // COMMENTS : search process list, search DLL list, delete existing DLL
  733. //            node
  734. // ************************************************************************
  735. BOOL
  736. HandleUnloadDllEvent( LPDEBUG_EVENT lpDebugEvent )
  737. {
  738.   PNODE                  pProcessNode, pSearchProcessNode;
  739.   PNODE                  pSearchDllNode;
  740.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo, pSearchProcessNodeInfo;
  741.   PDEB_DLL_NODE_INFO     pSearchDllNodeInfo;
  742.  
  743.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  744.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  745.   SetCurrentProcessNode( pProcessList, pSearchProcessNode );
  746.   GetCurrentNode( pProcessList, &pProcessNode );
  747.   pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  748.   AllocDllNode( &pSearchDllNode, &pSearchDllNodeInfo );
  749.   pSearchDllNodeInfo->DllDebugInfo.lpBaseOfDll = lpDebugEvent->u.UnloadDll.lpBaseOfDll;
  750.   DeleteDllNode( pProcessNodeInfo->pDllList, pSearchDllNode );
  751.   DestroyDllNode( pSearchDllNode );
  752.   DestroyProcessNode( pSearchProcessNode );
  753.  
  754.   return( TRUE );
  755. }
  756.  
  757.  
  758. // ************************************************************************
  759. // FUNCTION : HandleOutputDebugStringEvent( LPDEBUG_EVENT )
  760. // PURPOSE  : handle OUTPUT_DEBUG_STRING_EVENT
  761. // COMMENTS : do nothing
  762. // ************************************************************************
  763. BOOL
  764. HandleOutputDebugStringEvent( LPDEBUG_EVENT lpDebugEvent )
  765. {
  766.   return( TRUE );
  767. }
  768.  
  769.  
  770. // ************************************************************************
  771. // FUNCTION : HandleRipEvent( LPDEBUG_EVENT )
  772. // PURPOSE  : handle RIP_EVENT
  773. // COMMENTS : do nothing
  774. // ************************************************************************
  775. BOOL
  776. HandleRipEvent( LPDEBUG_EVENT lpDebugEvent )
  777. {
  778.   return( TRUE );
  779. }
  780.  
  781.  
  782. // ************************************************************************
  783. // FUNCTION : HandleUnknownEvent( LPDEBUG_EVENT )
  784. // PURPOSE  : handle all unknown debug events
  785. // COMMENTS : do nothing
  786. // ************************************************************************
  787. BOOL
  788. HandleUnknownEvent( LPDEBUG_EVENT lpDebugEvent )
  789. {
  790.   return( TRUE );
  791. }
  792.  
  793.  
  794. // ========================================================================
  795. // misc debug event helper functions
  796. // ========================================================================
  797.  
  798.  
  799. // ************************************************************************
  800. // FUNCTION : DebugNewProcess( LPTSTR, LPTSTR )
  801. // PURPOSE  : starts a new process as a debuggee
  802. // COMMENTS :
  803. // ************************************************************************
  804. BOOL
  805. DebugNewProcess( LPTSTR lpszFileName, LPTSTR lpszTitle )
  806. {
  807.   static STARTUPINFO           StartupInfo;
  808.   static LPSTARTUPINFO         lpStartupInfo = &StartupInfo;
  809.   static PROCESS_INFORMATION   ProcessInfo;
  810.   static LPPROCESS_INFORMATION lpProcessInfo = &ProcessInfo;
  811.  
  812.   lpStartupInfo->cb          = sizeof( STARTUPINFO );
  813.   lpStartupInfo->lpDesktop   = NULL;
  814.   lpStartupInfo->lpTitle     = lpszTitle;
  815.   lpStartupInfo->dwX         = 0;
  816.   lpStartupInfo->dwY         = 0;
  817.   lpStartupInfo->dwXSize     = 0;
  818.   lpStartupInfo->dwYSize     = 0;
  819.   lpStartupInfo->dwFlags     = (DWORD) NULL;
  820.   lpStartupInfo->wShowWindow = SW_SHOWDEFAULT;
  821.  
  822.   lpProcessInfo->hProcess = NULL;
  823.  
  824.   //-- create the Debuggee process instead
  825.   if( !CreateProcess(
  826.          NULL,
  827.          lpszFileName,
  828.          (LPSECURITY_ATTRIBUTES) NULL,
  829.          (LPSECURITY_ATTRIBUTES) NULL,
  830.          TRUE,
  831.          Profile.DebugMode | Profile.DebuggeePriority | CREATE_NEW_CONSOLE,
  832.          (LPVOID) NULL,
  833.          (LPTSTR) NULL,
  834.          lpStartupInfo, lpProcessInfo ) ) {
  835.  
  836.     switch( GetLastError() ) {
  837.  
  838.       case ERROR_FILE_NOT_FOUND:
  839.         MessageBox( GetDesktopWindow(), TEXT( "This file does not exist." ),
  840.           TEXT( "Open File Error" ), MB_OK | MB_APPLMODAL | MB_SETFOREGROUND );
  841.         break;
  842.       case ERROR_ACCESS_DENIED:
  843.         MessageBox( GetDesktopWindow(), TEXT( "Access denied." ),
  844.           TEXT( "Open File Error" ), MB_OK | MB_APPLMODAL | MB_SETFOREGROUND );
  845.         break;
  846.       case ERROR_FILE_INVALID:
  847.         MessageBox( GetDesktopWindow(), TEXT( "Invalid file." ),
  848.           TEXT( "Open File Error" ), MB_OK | MB_APPLMODAL | MB_SETFOREGROUND );
  849.         break;
  850.       case ERROR_FILE_CORRUPT:
  851.         MessageBox( GetDesktopWindow(), TEXT( "The file is corrupt." ),
  852.           TEXT( "Open File Error" ), MB_OK | MB_APPLMODAL | MB_SETFOREGROUND );
  853.         break;
  854.       case ERROR_BAD_EXE_FORMAT:
  855.         MessageBox( GetDesktopWindow(), TEXT( "The file has a bad format." ),
  856.           TEXT( "Open File Error" ), MB_OK | MB_APPLMODAL | MB_SETFOREGROUND );
  857.         break;
  858.       default:
  859.         ErrorMessageBox( TEXT( "CreateProcess()" ),
  860.           Global.szApiFailed, szSourceFileName, __LINE__ );
  861.         break;
  862.  
  863.     }
  864.     return( FALSE );
  865.  
  866.   }
  867.   else {
  868.     CloseHandle( ProcessInfo.hProcess );
  869.     CloseHandle( ProcessInfo.hThread );
  870.   }
  871.  
  872.   return( TRUE
  873.  );
  874. }
  875.  
  876.  
  877. // ************************************************************************
  878. // FUNCTION : GetDllFileName( LPDEBUG_EVENT, LPTSTR, DWORD )
  879. // PURPOSE  : get DLL filename when LOAD_DLL_DEBUG_EVENT occurs
  880. // COMMENTS : search process list, get DLL name from header
  881. // ************************************************************************
  882. BOOL
  883. GetDllFileName( LPDEBUG_EVENT lpDebugEvent, LPTSTR lpszBuffer,
  884.   DWORD cchBuffer )
  885. {
  886.   PNODE                  pProcessNode, pSearchProcessNode;
  887.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo, pSearchProcessNodeInfo;
  888.  
  889.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  890.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  891.   SetCurrentProcessNode( pProcessList, pSearchProcessNode );
  892.   GetCurrentNode( pProcessList, &pProcessNode );
  893.   pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  894.   GetModuleFileNameFromHeader(
  895.     pProcessNodeInfo->ProcessDebugInfo.hProcess,
  896.     lpDebugEvent->u.LoadDll.hFile,
  897.     (DWORD) lpDebugEvent->u.LoadDll.lpBaseOfDll,
  898.     lpszBuffer, cchBuffer);
  899.   DestroyProcessNode( pSearchProcessNode );
  900.  
  901.   return( TRUE );
  902. }
  903.  
  904.  
  905. // ************************************************************************
  906. // FUNCTION : GetDllFileNameFromList( LPDEBUG_EVENT, LPTSTR, DWORD )
  907. // PURPOSE  : get DLL filename when UNLOAD_DLL_DEBUG_EVENT occurs
  908. // COMMENTS : search process list, search DLL list, get DLL name
  909. // ************************************************************************
  910. BOOL
  911. GetDllFileNameFromList( LPDEBUG_EVENT lpDebugEvent, LPTSTR lpszBuffer,
  912.   DWORD cchBuffer )
  913. {
  914.   PNODE                  pProcessNode, pSearchProcessNode;
  915.   PNODE                  pDllNode, pSearchDllNode;
  916.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo, pSearchProcessNodeInfo;
  917.   PDEB_DLL_NODE_INFO     pDllNodeInfo, pSearchDllNodeInfo;
  918.  
  919.   UNREFERENCED_PARAMETER( cchBuffer );
  920.  
  921.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  922.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  923.   SetCurrentProcessNode( pProcessList, pSearchProcessNode );
  924.   GetCurrentNode( pProcessList, &pProcessNode );
  925.   pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  926.   AllocDllNode( &pSearchDllNode, &pSearchDllNodeInfo );
  927.   pSearchDllNodeInfo->DllDebugInfo.lpBaseOfDll = lpDebugEvent->u.UnloadDll.lpBaseOfDll;
  928.   SetCurrentDllNode( pProcessNodeInfo->pDllList, pSearchDllNode );
  929.   GetCurrentNode( pProcessNodeInfo->pDllList, &pDllNode );
  930.   pDllNodeInfo = (PDEB_DLL_NODE_INFO) pDllNode->pNodeData;
  931.   lstrcpy( lpszBuffer, pDllNodeInfo->lpstrFileName );
  932.  
  933.   return( TRUE );
  934. }
  935.  
  936.  
  937. // ************************************************************************
  938. // FUNCTION : GetOutputDebugString( LPDEBUG_EVENT, LPTSTR, DWORD )
  939. // PURPOSE  : get the output debug string from the debuggee when
  940. //            OUTPUT_DEBUG_STRING_EVENT occurs
  941. // COMMENTS : search process list, read the string from the debuggee
  942. // ************************************************************************
  943. BOOL
  944. GetOutputDebugString( LPDEBUG_EVENT lpDebugEvent, LPTSTR lpszBuffer,
  945.   DWORD cchBuffer )
  946. {
  947.   PNODE                  pProcessNode, pSearchProcessNode;
  948.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo, pSearchProcessNodeInfo;
  949.   DWORD dwNumberOfBytesRead;
  950.  
  951.   UNREFERENCED_PARAMETER( cchBuffer );
  952.  
  953.   AllocProcessNode( &pSearchProcessNode, &pSearchProcessNodeInfo );
  954.   pSearchProcessNodeInfo->dwProcessId = lpDebugEvent->dwProcessId;
  955.   SetCurrentProcessNode( pProcessList, pSearchProcessNode );
  956.   GetCurrentNode( pProcessList, &pProcessNode );
  957.   pProcessNode = (PNODE) pProcessList->pCurrentNode;
  958.   pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  959.   ReadProcessMemory(
  960.     pProcessNodeInfo->ProcessDebugInfo.hProcess,
  961.     lpDebugEvent->u.DebugString.lpDebugStringData,
  962.     lpszBuffer, lpDebugEvent->u.DebugString.nDebugStringLength,
  963.     &dwNumberOfBytesRead );
  964.   DestroyProcessNode( pSearchProcessNode );
  965.  
  966.   return( TRUE );
  967. }
  968.  
  969.  
  970. // ************************************************************************
  971. // FUNCTION : GetModuleFileNameFromHeader( HANDLE, HANDLE, DWORD, LPTSTR, DWORD )
  972. // PURPOSE  : Retrieves the DLL module name for a given file handle of a
  973. //            the module.  Reads the module name from the EXE header.
  974. // COMMENTS :
  975. //   Retrieves only the module name and not the pathname.  Returns the
  976. //   number of characters copies to the buffer, else returns 0.
  977. // ************************************************************************
  978. DWORD
  979. GetModuleFileNameFromHeader( HANDLE hProcess, HANDLE hFile, DWORD BaseOfDll,
  980.   LPTSTR lpszPath, DWORD cchPath )
  981. {
  982.   #define IMAGE_SECOND_HEADER_OFFSET    (15 * sizeof(ULONG)) // relative to file beginning
  983.   #define IMAGE_BASE_OFFSET             (13 * sizeof(DWORD)) // relative to PE header base
  984.   #define IMAGE_EXPORT_TABLE_RVA_OFFSET (30 * sizeof(DWORD)) // relative to PE header base
  985.   #define IMAGE_NAME_RVA_OFFSET         offsetof(IMAGE_EXPORT_DIRECTORY, Name)
  986.  
  987.   WORD   DosSignature;
  988.   DWORD  NtSignature;
  989.   DWORD  dwNumberOfBytesRead = 0;
  990.   DWORD  PeHeader, ImageBase, ExportTableRVA, NameRVA;
  991.  
  992.   //-- verify that the handle is not NULL
  993.   if( !hFile ) {
  994.     lstrcpy( lpszPath, TEXT("Invalid File Handle") );
  995.     return( 0 );
  996.   }
  997.  
  998.   //-- verify that the handle is for a disk file
  999.   if( GetFileType(hFile) != FILE_TYPE_DISK ) {
  1000.     lstrcpy( lpszPath, TEXT("Invalid File Type") );
  1001.     return( 0 );
  1002.   }
  1003.  
  1004.   //-- Extract the filename from the EXE header
  1005.   SetFilePointer( hFile, 0L, NULL, FILE_BEGIN );
  1006.   ReadFile( hFile, &DosSignature, sizeof(DosSignature), &dwNumberOfBytesRead,
  1007.     (LPOVERLAPPED) NULL);
  1008.  
  1009.   //-- verify DOS signature found
  1010.   if( DosSignature != IMAGE_DOS_SIGNATURE ) {
  1011.     wsprintf( lpszPath, TEXT( "Bad MZ Signature: 0x%x" ), DosSignature );
  1012.     return( 0 );
  1013.   }
  1014.  
  1015.   SetFilePointer( hFile, IMAGE_SECOND_HEADER_OFFSET, (LPLONG) NULL,
  1016.     FILE_BEGIN );
  1017.   ReadFile( hFile, &PeHeader, sizeof(PeHeader), &dwNumberOfBytesRead,
  1018.     (LPOVERLAPPED) NULL );
  1019.   SetFilePointer( hFile, PeHeader, (LPLONG) NULL, FILE_BEGIN );
  1020.   ReadFile( hFile, &NtSignature, sizeof(NtSignature), &dwNumberOfBytesRead,
  1021.     (LPOVERLAPPED) NULL);
  1022.  
  1023.   //-- verify Windows NT (PE) signature found
  1024.   if( NtSignature != IMAGE_NT_SIGNATURE ) {
  1025.     wsprintf( lpszPath, TEXT( "Bad PE Signature: 0x%x" ), DosSignature );
  1026.     return( 0 );
  1027.   }
  1028.  
  1029.   SetFilePointer( hFile, PeHeader + IMAGE_BASE_OFFSET, (LPLONG) NULL,
  1030.     FILE_BEGIN );
  1031.   ReadFile( hFile, &ImageBase, sizeof(ImageBase), &dwNumberOfBytesRead,
  1032.     (LPOVERLAPPED) NULL);
  1033.   SetFilePointer( hFile, PeHeader + IMAGE_EXPORT_TABLE_RVA_OFFSET,
  1034.     (LPLONG) NULL, FILE_BEGIN );
  1035.   ReadFile( hFile, &ExportTableRVA, sizeof(ExportTableRVA),
  1036.     &dwNumberOfBytesRead, (LPOVERLAPPED) NULL);
  1037.  
  1038.   //-- now read from the virtual address space in the process
  1039.   ReadProcessMemory( hProcess,
  1040.      (LPVOID) (BaseOfDll + ExportTableRVA + IMAGE_NAME_RVA_OFFSET),
  1041.      &NameRVA, sizeof(NameRVA), &dwNumberOfBytesRead );
  1042.   lstrcpy( lpszPath, TEXT("Empty!") );
  1043.   if( !ReadProcessMemory( hProcess,
  1044.          (LPVOID) (BaseOfDll + NameRVA),
  1045.          lpszPath, cchPath, &dwNumberOfBytesRead ) )
  1046.      lstrcpy( lpszPath, TEXT("Access Denied!") );
  1047.  
  1048.   return( dwNumberOfBytesRead );
  1049. }
  1050.  
  1051.  
  1052. #if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
  1053. // ************************************************************************
  1054. // FUNCTION : SkipThreadBreakPoint( HANDLE );
  1055. // PURPOSE  : Skip over the break point instruction belonging to
  1056. //            hThread.
  1057. // COMMENTS :
  1058. //   Only the MIPS R4x00 and DEC Alpha AXP require this.
  1059. // ************************************************************************
  1060. BOOL
  1061. SkipBreakPoint( HANDLE hThread )
  1062. {
  1063.   static CONTEXT Context;
  1064.  
  1065.   Context.ContextFlags = CONTEXT_CONTROL;
  1066.   if( !GetThreadContext( hThread, &Context ) )
  1067.     return( FALSE );
  1068. #if defined(_PPC_)
  1069.   Context.Iar += 4L;  // Iar is the PC (program counter)
  1070. #else
  1071.   Context.Fir += 4L;  // Fir is the PC (program counter)
  1072.                       // BREAK (breakpoint instruction) occupies 4 bytes
  1073. #endif
  1074.  
  1075.   // -----------------------------------------------------------------------
  1076.   //  Below would be equivalent for the Intel 80x86 (if it were necessary)
  1077.   //  however the Intel x86 automatically increments ip past the 'int 3':
  1078.   //  Context.Eip += 1L;  // Eip is the PC (program counter)
  1079.   //              // int 3 (breakpoint instruction) occupies 1 byte
  1080.   // -----------------------------------------------------------------------
  1081.  
  1082.   if( !SetThreadContext( hThread, &Context ) )
  1083.     return( FALSE );
  1084.  
  1085.   return( TRUE );
  1086. }
  1087. #endif
  1088.  
  1089.  
  1090.  
  1091. // ========================================================================
  1092. // wrapper functions to the linked list services
  1093. // ========================================================================
  1094.  
  1095. // ========================================================================
  1096. // Debug Event Browser Data Structure Overview
  1097. // -------------------------------------------
  1098. //
  1099. // The Debug Event Browser (DEB) maintains a rather involved data structure
  1100. // to store various debug event and debuggee process information.  It
  1101. // attempts to encapsulate the intricacies of what makes a process based on
  1102. // the occuring events.  Much of this stored information is never utilized
  1103. // by the Debug Event Browser but it is included to demonstrate what types
  1104. // of debug event may be useful to a full blown debugger application.
  1105. //
  1106. // This data structure uses the generalized, sorted, double-linked list
  1107. // package provided with the sample.  Each list can store list-specific
  1108. // instance data, list-specific node data, and maintain various pointers
  1109. // to these nodes.  The list is sorted via the insertion sort method where
  1110. // the programmer defines the list-specific sort function whose purpose is
  1111. // to compare two given nodes and return their relative sort location.  The
  1112. // list package in generalized in the sense that the list and node-specific
  1113. // data type is not known to this package at compile time or at runtime.
  1114. // The application programmer is merely responsible for defining the list
  1115. // and node-specific data structures and the sorting and optional searching
  1116. // functions and the list package keeps track of these nodes and provides
  1117. // easy access to them.
  1118. //
  1119. // DEB uses this list package to create three unique list types: process,
  1120. // thread and DLL lists.
  1121. //
  1122. // The backbone of the data structure is the process list.  The nodes of
  1123. // the process list are the individual debuggee processes.  DEB allows
  1124. // debugging (or should I say debug event browsing) of other processes that
  1125. // are spawned by the initial debuggee.  Thus each debug session may have
  1126. // multiple debuggees and thus the process becomes the logical node unit.
  1127. //
  1128. // A visual diagram of the process list is as follows:
  1129. //
  1130. //                 (ProcessList)
  1131. //                      |
  1132. //                      |
  1133. //                      v
  1134. //                 +-----------------+           +----------------------+
  1135. //                 | -ProcessList-   |           | -ListData-           |
  1136. //                 |                 |           |                      |
  1137. //                 | ListData--------+---------->| ActiveProcessCount=N |
  1138. //           +-----+-FirstNode       |           +----------------------+
  1139. //           |   +-+ CurrentNode     |
  1140. //           |   | | LastNode--------+-----------------------+
  1141. //           |   | | OrderFunction=& |                       |
  1142. //           |   | | ListError=0     |                       |
  1143. //           |   | +-----------------+                       |
  1144. //           |   |                                           |
  1145. //           |   +-------------------+                       |
  1146. //           |                       |                       |
  1147. //           v                       v                       v
  1148. //         +------------+     +------------+             +------------+
  1149. // NULL <- |ProcessNode1| <=> |ProcessNode2| <=> ... <=> |ProcessNodeN| -> NULL
  1150. //         +------------+     +------------+             +------------+
  1151. //
  1152. // Each process node also contains two lists: the thread list and the DLL list.
  1153. // This node also stores some of the relevent debug event information
  1154. // particular to the create process event.  Visually it is as follows:
  1155. //
  1156. //    +------------------+         +--------------+
  1157. //    | -ProcessNode-    | +------>| -ThreadList- |
  1158. //    |                  | |       +--------------+
  1159. //    | ProcessID=0      | |
  1160. //    | ThreadID=0       | |       +-----------+
  1161. //    | FileName=""      | |   +-->| -DllList- |
  1162. //    | PathName=""      | |   |   +-----------+
  1163. //    | ThreadList-------+-+   |
  1164. //    | DllList----------+-----+   +-------------------+
  1165. //    | ProcessDebugInfo-+-------->|-ProcessDebugInfo- |
  1166. //    +------------------+         +-------------------+
  1167. //
  1168. // Much like the process list, the visual diagram of the thread list is as
  1169. // follows:
  1170. //
  1171. //                 +-----------------+           +---------------------+
  1172. //                 | -ThreadList-    |           | -ListData-          |
  1173. //                 |                 |           |                     |
  1174. //                 | ListData--------+---------->| ActiveThreadCount=N |
  1175. //           +-----+-FirstNode       |           +---------------------+
  1176. //           |   +-+ CurrentNode     |
  1177. //           |   | | LastNode--------+-----------------------+
  1178. //           |   | | OrderFunction=& |                       |
  1179. //           |   | | ListError=0     |                       |
  1180. //           |   | +-----------------+                       |
  1181. //           |   |                                           |
  1182. //           |   +-------------------+                       |
  1183. //           |                       |                       |
  1184. //           v                       v                       v
  1185. //          +-----------+     +-----------+             +-----------+
  1186. //  NULL <- |ThreadNode1| <=> |ThreadNode2| <=> ... <=> |ThreadNodeN| -> NULL
  1187. //          +-----------+     +-----------+             +-----------+
  1188. //
  1189. // The thread nodes store some of the relevent debug event information
  1190. // particular to the create thread event.  Visually it is as follows:
  1191. //
  1192. //    +--------------------+
  1193. //    | -ThreadNode-       |
  1194. //    |                    |
  1195. //    | ProcessID=0        |
  1196. //    | ThreadID=0         |
  1197. //    | ThreadDebugInfo={} |
  1198. //    +--------------------+
  1199. //
  1200. // Much like the process and thread lists, the visual diagram of the Dll list
  1201. // is as follows:
  1202. //
  1203. //                 +-----------------+           +------------------+
  1204. //                 | -DllList-       |           | -ListData-       |
  1205. //                 |                 |           |                  |
  1206. //                 | ListData--------+---------->| ActiveDllCount=N |
  1207. //           +-----+-FirstNode       |           +------------------+
  1208. //           |   +-+ CurrentNode     |
  1209. //           |   | | LastNode--------+-----------------+
  1210. //           |   | | OrderFunction=& |                 |
  1211. //           |   | | ListError=0     |                 |
  1212. //           |   | +-----------------+                 |
  1213. //           |   |                                     |
  1214. //           |   +-------------+                       |
  1215. //           |                 |                       |
  1216. //           v                 v                       v
  1217. //          +--------+     +--------+             +--------+
  1218. //  NULL <- |DllNode1| <=> |DllNode2| <=> ... <=> |DllNodeN| -> NULL
  1219. //          +--------+     +--------+             +--------+
  1220. //
  1221. // The Dll nodes store some of the relevent debug event information particular
  1222. // to the Dll load event.  Visually it is as follows:
  1223. //
  1224. //    +----------------+
  1225. //    | -DllNode-      |
  1226. //    |                |
  1227. //    | FileName=""    |
  1228. //    | PathName=""    |
  1229. //    | DllDebugInfo={}|
  1230. //    +----------------+
  1231. //
  1232. // ========================================================================
  1233.  
  1234. // ------------------------------------------------------------------------
  1235. // Process list and node specific linked list wrapper functions
  1236. // ------------------------------------------------------------------------
  1237.  
  1238.  
  1239. // ************************************************************************
  1240. // FUNCTION : ProcessOrderFunction( PNODE, PNODE );
  1241. // PURPOSE  : Provides the sorting/search logic for the double linked
  1242. //            list package.
  1243. // COMMENTS :
  1244. //   Sorted by process ID value
  1245. // ************************************************************************
  1246. int
  1247. ProcessOrderFunction( PNODE pNode1, PNODE pNode2 )
  1248. {
  1249.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo1 = pNode1->pNodeData;
  1250.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo2 = pNode2->pNodeData;
  1251.  
  1252.   if( pProcessNodeInfo1->dwProcessId < pProcessNodeInfo2->dwProcessId )
  1253.     return( LIST_LEFT_OF );
  1254.  
  1255.   if( pProcessNodeInfo1->dwProcessId > pProcessNodeInfo2->dwProcessId )
  1256.     return( LIST_RIGHT_OF );
  1257.  
  1258.   return( LIST_MATCH );
  1259. }
  1260.  
  1261.  
  1262. // ************************************************************************
  1263. // FUNCTION : CreateProcessList( PLIST* )
  1264. // PURPOSE  :
  1265. // COMMENTS :
  1266. //
  1267. // ************************************************************************
  1268. BOOL
  1269. CreateProcessList( PLIST* ppProcessList )
  1270. {
  1271.   PDEB_PROCESS_LIST_INFO pProcessListInfo;
  1272.  
  1273.   //-- create list
  1274.   CreateList( ppProcessList, ProcessOrderFunction );
  1275.  
  1276.   //-- alloc info data
  1277.   pProcessListInfo = (PDEB_PROCESS_LIST_INFO) HeapAlloc( hHeap, (DWORD) NULL,
  1278.                                                 sizeof( DEB_PROCESS_LIST_INFO ) );
  1279.   (*ppProcessList)->pListData = pProcessListInfo;
  1280.  
  1281.   //-- init info data
  1282.   pProcessListInfo->dwActiveProcesses = 0;
  1283.  
  1284.   return( TRUE );
  1285. }
  1286.  
  1287.  
  1288. // ************************************************************************
  1289. // FUNCTION : DestroyProcessList( PLIST )
  1290. // PURPOSE  :
  1291. // COMMENTS :
  1292. //
  1293. // ************************************************************************
  1294. BOOL
  1295. DestroyProcessList( PLIST pProcessList )
  1296. {
  1297.   PDEB_PROCESS_LIST_INFO pProcessListInfo = pProcessList->pListData;
  1298.   PNODE                  pDeleteNode;
  1299.  
  1300.   //-- make sure all nodes are removed first
  1301.   while( pProcessListInfo->dwActiveProcesses ) {
  1302.     GetCurrentNode( pProcessList, &pDeleteNode );
  1303.     DeleteCurrentProcessNode( pProcessList );
  1304.   }
  1305.  
  1306.   //-- free info data
  1307.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pProcessListInfo );
  1308.  
  1309.   //-- destroy list
  1310.   DestroyList( pProcessList );
  1311.  
  1312.   return( TRUE );
  1313. }
  1314.  
  1315.  
  1316. // ************************************************************************
  1317. // FUNCTION : AllocProcessNode( PNODE*, PDEB_PROCESS_NODE_INFO* )
  1318. // PURPOSE  :
  1319. // COMMENTS :
  1320. //
  1321. // ************************************************************************
  1322. BOOL
  1323. AllocProcessNode( PNODE* ppProcessNode, PDEB_PROCESS_NODE_INFO* ppProcessNodeInfo )
  1324. {
  1325.   //-- create node
  1326.   CreateNode( ppProcessNode );
  1327.  
  1328.   //-- alloc info data
  1329.   *ppProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) HeapAlloc( hHeap, (DWORD) NULL,
  1330.                                               sizeof( DEB_PROCESS_NODE_INFO ) );
  1331.   (*ppProcessNode)->pNodeData = *(ppProcessNodeInfo);
  1332.  
  1333.   (*ppProcessNodeInfo)->lpstrFileName = (LPTSTR) HeapAlloc( hHeap, (DWORD) NULL,
  1334.                                                (DWORD) MAX_PATH );
  1335.   (*ppProcessNodeInfo)->lpstrPathName = (LPTSTR) HeapAlloc( hHeap, (DWORD) NULL,
  1336.                                                (DWORD) MAX_PATH );
  1337.   CreateThreadList( &((*ppProcessNodeInfo)->pThreadList) );
  1338.   CreateDllList( &((*ppProcessNodeInfo)->pDllList) );
  1339.  
  1340.   return( TRUE );
  1341. }
  1342.  
  1343.  
  1344. // ************************************************************************
  1345. // FUNCTION : InitProcessNodeInfo( PDEB_PROCESS_NODE_INFO*, LPDEBUG_EVENT )
  1346. // PURPOSE  :
  1347. // COMMENTS :
  1348. //
  1349. // ************************************************************************
  1350. BOOL
  1351. InitProcessNodeInfo( PDEB_PROCESS_NODE_INFO* ppProcessNodeInfo, LPDEBUG_EVENT lpDebugEvent )
  1352. {
  1353.   //-- init info data
  1354.   (*ppProcessNodeInfo)->dwProcessId = lpDebugEvent->dwProcessId;
  1355.   (*ppProcessNodeInfo)->dwThreadId  = lpDebugEvent->dwThreadId;
  1356.   // Note:pThreadList initialized via previous CreateThreadList() call
  1357.   // Note:pDllList initialized via previous CreateDllList() call
  1358.   (*ppProcessNodeInfo)->ProcessDebugInfo = lpDebugEvent->u.CreateProcessInfo;
  1359.  
  1360.   return( TRUE );
  1361. }
  1362.  
  1363.  
  1364. // ************************************************************************
  1365. // FUNCTION : InsertProcessNode( PLIST, PNODE )
  1366. // PURPOSE  :
  1367. // COMMENTS :
  1368. //
  1369. // ************************************************************************
  1370. BOOL
  1371. InsertProcessNode( PLIST pProcessList, PNODE pProcessNode )
  1372. {
  1373.   PDEB_PROCESS_LIST_INFO pProcessListInfo = pProcessList->pListData;
  1374.  
  1375.   //-- insert the node
  1376.   InsertNode( pProcessList, pProcessNode );
  1377.  
  1378.   //-- increment dwActiveProcesss
  1379.   pProcessListInfo->dwActiveProcesses++;
  1380.  
  1381.   return( TRUE );
  1382. }
  1383.  
  1384.  
  1385. // ************************************************************************
  1386. // FUNCTION : SetCurrentProcessNode( PLIST, PNODE )
  1387. // PURPOSE  :
  1388. // COMMENTS :
  1389. //
  1390. // ************************************************************************
  1391. BOOL
  1392. SetCurrentProcessNode( PLIST pProcessList, PNODE pProcessNode )
  1393. {
  1394.   SetCurrentNode( pProcessList, pProcessNode, pProcessList->OrderFunction );
  1395.  
  1396.   return( TRUE );
  1397. }
  1398.  
  1399.  
  1400. // ************************************************************************
  1401. // FUNCTION : DeleteProcessNode( PLIST, PNODE )
  1402. // PURPOSE  :
  1403. // COMMENTS :
  1404. //
  1405. // ************************************************************************
  1406. BOOL
  1407. DeleteProcessNode( PLIST pProcessList, PNODE pProcessNode )
  1408. {
  1409.   PNODE pDeleteNode;
  1410.  
  1411.   SetCurrentNode( pProcessList, pProcessNode, pProcessList->OrderFunction );
  1412.   GetCurrentNode( pProcessList, &pDeleteNode );
  1413.   DeleteCurrentProcessNode( pProcessList );
  1414.  
  1415.   return( TRUE );
  1416. }
  1417.  
  1418.  
  1419. // ************************************************************************
  1420. // FUNCTION : FreeProcessNodeInfo( PNODE )
  1421. // PURPOSE  :
  1422. // COMMENTS :
  1423. //
  1424. // ************************************************************************
  1425. BOOL
  1426. FreeProcessNodeInfo( PNODE pProcessNode )
  1427. {
  1428.   PDEB_PROCESS_NODE_INFO pProcessNodeInfo = (PDEB_PROCESS_NODE_INFO) pProcessNode->pNodeData;
  1429.  
  1430.   //-- free info data
  1431.   DestroyDllList( pProcessNodeInfo->pDllList );
  1432.   DestroyThreadList( pProcessNodeInfo->pThreadList );
  1433.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pProcessNodeInfo->lpstrPathName );
  1434.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pProcessNodeInfo->lpstrFileName );
  1435.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pProcessNodeInfo );
  1436.  
  1437.   return( TRUE );
  1438. }
  1439.  
  1440.  
  1441. // ************************************************************************
  1442. // FUNCTION : DestroyProcessNode( PNODE )
  1443. // PURPOSE  :
  1444. // COMMENTS : Frees all memory associated with the node.
  1445. // ************************************************************************
  1446. BOOL
  1447. DestroyProcessNode( PNODE pProcessNode )
  1448. {
  1449.   //-- free info data
  1450.   FreeProcessNodeInfo( pProcessNode );
  1451.  
  1452.   //-- destroy node
  1453.   DestroyNode( pProcessNode );
  1454.  
  1455.   return( TRUE );
  1456. }
  1457.  
  1458.  
  1459. // ************************************************************************
  1460. // FUNCTION : DeleteCurrentProcessNode( PLIST )
  1461. // PURPOSE  :
  1462. // COMMENTS :
  1463. //
  1464. // ************************************************************************
  1465. BOOL
  1466. DeleteCurrentProcessNode( PLIST pProcessList )
  1467. {
  1468.   PDEB_PROCESS_LIST_INFO pProcessListInfo = pProcessList->pListData;
  1469.   PNODE                  pProcessNode = (PNODE) pProcessList->pCurrentNode;
  1470.  
  1471.   //-- free info data
  1472.   FreeProcessNodeInfo( pProcessNode );
  1473.  
  1474.   //-- delete and destroy node
  1475.   DeleteCurrentNode( pProcessList );
  1476.  
  1477.   //-- decrement dwActiveProcesss
  1478.   pProcessListInfo->dwActiveProcesses--;
  1479.  
  1480.   return( TRUE );
  1481. }
  1482.  
  1483.  
  1484. // ------------------------------------------------------------------------
  1485. // Thread list and node specific linked list wrapper functions
  1486. // ------------------------------------------------------------------------
  1487.  
  1488.  
  1489. // ************************************************************************
  1490. // FUNCTION : ThreadOrderFunction( PNODE, PNODE );
  1491. // PURPOSE  : Provides the sorting/search logic for the double linked
  1492. //            list package.
  1493. // COMMENTS :
  1494. //   Sorted by thread ID value
  1495. // ************************************************************************
  1496. int
  1497. ThreadOrderFunction( PNODE pNode1, PNODE pNode2 )
  1498. {
  1499.   PDEB_THREAD_NODE_INFO pThreadNodeInfo1 = pNode1->pNodeData;
  1500.   PDEB_THREAD_NODE_INFO pThreadNodeInfo2 = pNode2->pNodeData;
  1501.  
  1502.   if( pThreadNodeInfo1->dwThreadId < pThreadNodeInfo2->dwThreadId )
  1503.     return( LIST_LEFT_OF );
  1504.  
  1505.   if( pThreadNodeInfo1->dwThreadId > pThreadNodeInfo2->dwThreadId )
  1506.     return( LIST_RIGHT_OF );
  1507.  
  1508.   return( LIST_MATCH );
  1509. }
  1510.  
  1511.  
  1512. // ************************************************************************
  1513. // FUNCTION : CreateThreadList( PLIST* )
  1514. // PURPOSE  :
  1515. // COMMENTS :
  1516. //
  1517. // ************************************************************************
  1518. BOOL
  1519. CreateThreadList( PLIST* ppThreadList )
  1520. {
  1521.   PDEB_THREAD_LIST_INFO pThreadListInfo;
  1522.  
  1523.   //-- create list
  1524.   CreateList( ppThreadList, ThreadOrderFunction );
  1525.  
  1526.   //-- alloc info data
  1527.   pThreadListInfo = (PDEB_THREAD_LIST_INFO) HeapAlloc( hHeap, (DWORD) NULL,
  1528.                                                 sizeof( DEB_THREAD_LIST_INFO ) );
  1529.   (*ppThreadList)->pListData = pThreadListInfo;
  1530.  
  1531.   //-- init info data
  1532.   pThreadListInfo->dwActiveThreads = 0;
  1533.  
  1534.   return( TRUE );
  1535. }
  1536.  
  1537.  
  1538. // ************************************************************************
  1539. // FUNCTION : DestroyThreadList( PLIST )
  1540. // PURPOSE  :
  1541. // COMMENTS :
  1542. //
  1543. // ************************************************************************
  1544. BOOL
  1545. DestroyThreadList( PLIST pThreadList )
  1546. {
  1547.   PDEB_THREAD_LIST_INFO pThreadListInfo = pThreadList->pListData;
  1548.   PNODE                 pDeleteNode;
  1549.  
  1550.   //-- make sure all nodes are removed first
  1551.   while( pThreadListInfo->dwActiveThreads ) {
  1552.     GetCurrentNode( pThreadList, &pDeleteNode );
  1553.     DeleteCurrentThreadNode( pThreadList );
  1554.   }
  1555.  
  1556.   //-- free info data
  1557.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pThreadListInfo );
  1558.  
  1559.   //-- destroy list
  1560.   DestroyList( pThreadList );
  1561.  
  1562.   return( TRUE );
  1563. }
  1564.  
  1565.  
  1566. // ************************************************************************
  1567. // FUNCTION : AllocThreadNode( PNODE*, PDEB_THREAD_NODE_INFO* )
  1568. // PURPOSE  :
  1569. // COMMENTS :
  1570. //
  1571. // ************************************************************************
  1572. BOOL
  1573. AllocThreadNode( PNODE* ppThreadNode, PDEB_THREAD_NODE_INFO* ppThreadNodeInfo )
  1574. {
  1575.   //-- create node
  1576.   CreateNode( ppThreadNode );
  1577.  
  1578.   //-- alloc info data
  1579.   *ppThreadNodeInfo = (PDEB_THREAD_NODE_INFO) HeapAlloc( hHeap, (DWORD) NULL,
  1580.                                             (DWORD) sizeof( DEB_THREAD_NODE_INFO ) );
  1581.   (*ppThreadNode)->pNodeData = *(ppThreadNodeInfo);
  1582.  
  1583.   return( TRUE );
  1584. }
  1585.  
  1586.  
  1587. // ************************************************************************
  1588. // FUNCTION : InitThreadNodeInfo( PDEB_THREAD_NODE_INFO*, LPDEBUG_EVENT )
  1589. // PURPOSE  :
  1590. // COMMENTS :
  1591. //
  1592. // ************************************************************************
  1593. BOOL
  1594. InitThreadNodeInfo( PDEB_THREAD_NODE_INFO* ppThreadNodeInfo,
  1595.   LPDEBUG_EVENT lpDebugEvent )
  1596. {
  1597.   //-- init info data
  1598.   (*ppThreadNodeInfo)->dwProcessId     = lpDebugEvent->dwProcessId;
  1599.   (*ppThreadNodeInfo)->dwThreadId      = lpDebugEvent->dwThreadId;
  1600.   (*ppThreadNodeInfo)->ThreadDebugInfo = lpDebugEvent->u.CreateThread;
  1601.  
  1602.   return( TRUE );
  1603. }
  1604.  
  1605.  
  1606. // ************************************************************************
  1607. // FUNCTION : InsertThreadNode( PLIST, PNODE )
  1608. // PURPOSE  :
  1609. // COMMENTS :
  1610. //
  1611. // ************************************************************************
  1612. BOOL
  1613. InsertThreadNode( PLIST pThreadList, PNODE pThreadNode )
  1614. {
  1615.   PDEB_THREAD_LIST_INFO pThreadListInfo = (PDEB_THREAD_LIST_INFO) pThreadList->pListData;
  1616.  
  1617.   //-- insert the thread node
  1618.   InsertNode( pThreadList, pThreadNode );
  1619.  
  1620.   //-- increment dwActiveThreads
  1621.   pThreadListInfo->dwActiveThreads++;
  1622.  
  1623.   return( TRUE );
  1624. }
  1625.  
  1626.  
  1627. // ************************************************************************
  1628. // FUNCTION : SetCurrentThreadNode( PLIST, PNODE )
  1629. // PURPOSE  :
  1630. // COMMENTS :
  1631. //
  1632. // ************************************************************************
  1633. BOOL
  1634. SetCurrentThreadNode( PLIST pThreadList, PNODE pThreadNode )
  1635. {
  1636.   SetCurrentNode( pThreadList, pThreadNode, pThreadList->OrderFunction );
  1637.  
  1638.   return( TRUE );
  1639. }
  1640.  
  1641.  
  1642. // ************************************************************************
  1643. // FUNCTION : DeleteThreadNode( PLIST, PNODE )
  1644. // PURPOSE  :
  1645. // COMMENTS :
  1646. //
  1647. // ************************************************************************
  1648. BOOL
  1649. DeleteThreadNode( PLIST pThreadList, PNODE pThreadNode )
  1650. {
  1651.   PNODE pDeleteNode;
  1652.  
  1653.   SetCurrentNode( pThreadList, pThreadNode, pThreadList->OrderFunction );
  1654.   GetCurrentNode( pThreadList, &pDeleteNode );
  1655.   DeleteCurrentThreadNode( pThreadList );
  1656.  
  1657.   return( TRUE );
  1658. }
  1659.  
  1660.  
  1661. // ************************************************************************
  1662. // FUNCTION : FreeThreadNodeInfo( PNODE )
  1663. // PURPOSE  :
  1664. // COMMENTS :
  1665. //
  1666. // ************************************************************************
  1667. BOOL
  1668. FreeThreadNodeInfo( PNODE pThreadNode )
  1669. {
  1670.   PDEB_THREAD_NODE_INFO pThreadNodeInfo = (PDEB_THREAD_NODE_INFO) pThreadNode->pNodeData;
  1671.  
  1672.   //-- free info data
  1673.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pThreadNodeInfo );
  1674.  
  1675.   return( TRUE );
  1676. }
  1677.  
  1678.  
  1679. // ************************************************************************
  1680. // FUNCTION : DestroyThreadNode( PNODE )
  1681. // PURPOSE  :
  1682. // COMMENTS : Frees all memory associated with the node.
  1683. // ************************************************************************
  1684. BOOL
  1685. DestroyThreadNode( PNODE pThreadNode )
  1686. {
  1687.   //-- free info data
  1688.   FreeThreadNodeInfo( pThreadNode );
  1689.  
  1690.   //-- destroy node
  1691.   DestroyNode( pThreadNode );
  1692.  
  1693.   return( TRUE );
  1694. }
  1695.  
  1696.  
  1697. // ************************************************************************
  1698. // FUNCTION : DeleteCurrentThreadNode( PLIST )
  1699. // PURPOSE  :
  1700. // COMMENTS :
  1701. //
  1702. // ************************************************************************
  1703. BOOL
  1704. DeleteCurrentThreadNode( PLIST pThreadList )
  1705. {
  1706.   PDEB_THREAD_LIST_INFO pThreadListInfo = pThreadList->pListData;
  1707.   PNODE                 pThreadNode = (PNODE) pThreadList->pCurrentNode;
  1708.  
  1709.   //-- free info data
  1710.   FreeThreadNodeInfo( pThreadNode );
  1711.  
  1712.   //-- delete and destroy node
  1713.   DeleteCurrentNode( pThreadList );
  1714.  
  1715.   //-- decrement dwActiveThreads
  1716.   pThreadListInfo->dwActiveThreads--;
  1717.  
  1718.   return( TRUE );
  1719. }
  1720.  
  1721.  
  1722. // ------------------------------------------------------------------------
  1723. // DLL list and node specific linked list wrapper functions
  1724. // ------------------------------------------------------------------------
  1725.  
  1726.  
  1727. // ************************************************************************
  1728. // FUNCTION : DllOrderFunction( PNODE, PNODE );
  1729. // PURPOSE  : Provides the sorting/search logic for the double linked
  1730. //            list package.
  1731. // COMMENTS :
  1732. //   Sorted by base address of the DLL
  1733. // ************************************************************************
  1734. int
  1735. DllOrderFunction( PNODE pNode1, PNODE pNode2 )
  1736. {
  1737.   PDEB_DLL_NODE_INFO pDllNodeInfo1 = pNode1->pNodeData;
  1738.   PDEB_DLL_NODE_INFO pDllNodeInfo2 = pNode2->pNodeData;
  1739.  
  1740.   if( pDllNodeInfo1->DllDebugInfo.lpBaseOfDll < pDllNodeInfo2->DllDebugInfo.lpBaseOfDll )
  1741.     return( LIST_LEFT_OF );
  1742.  
  1743.   if( pDllNodeInfo1->DllDebugInfo.lpBaseOfDll > pDllNodeInfo2->DllDebugInfo.lpBaseOfDll )
  1744.     return( LIST_RIGHT_OF );
  1745.  
  1746.   return( LIST_MATCH );
  1747. }
  1748.  
  1749.  
  1750. // ************************************************************************
  1751. // FUNCTION : CreateDllList( PLIST* )
  1752. // PURPOSE  :
  1753. // COMMENTS :
  1754. //
  1755. // ************************************************************************
  1756. BOOL
  1757. CreateDllList( PLIST* ppDllList )
  1758. {
  1759.   PDEB_DLL_LIST_INFO pDllListInfo;
  1760.  
  1761.   //-- create list
  1762.   CreateList( ppDllList, DllOrderFunction );
  1763.  
  1764.   //-- alloc info data
  1765.   pDllListInfo = (PDEB_DLL_LIST_INFO) HeapAlloc( hHeap, (DWORD) NULL,
  1766.                                                 sizeof( DEB_DLL_LIST_INFO ) );
  1767.   (*ppDllList)->pListData = pDllListInfo;
  1768.  
  1769.   //-- init info data
  1770.   pDllListInfo->dwActiveDlls = 0;
  1771.  
  1772.   return( TRUE );
  1773. }
  1774.  
  1775.  
  1776. // ************************************************************************
  1777. // FUNCTION : DestroyDllList( PLIST )
  1778. // PURPOSE  :
  1779. // COMMENTS :
  1780. //
  1781. // ************************************************************************
  1782. BOOL
  1783. DestroyDllList( PLIST pDllList )
  1784. {
  1785.   PDEB_DLL_LIST_INFO pDllListInfo = pDllList->pListData;
  1786.   PNODE              pDeleteNode;
  1787.  
  1788.   //-- make sure all nodes are removed first
  1789.   while( pDllListInfo->dwActiveDlls ) {
  1790.     GetCurrentNode( pDllList, &pDeleteNode );
  1791.     DeleteCurrentDllNode( pDllList );
  1792.   }
  1793.  
  1794.   //-- free list data and destroy the list
  1795.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pDllListInfo );
  1796.   DestroyList( pDllList );
  1797.  
  1798.   return( TRUE );
  1799. }
  1800.  
  1801.  
  1802. // ************************************************************************
  1803. // FUNCTION : AllocDllNode( PNODE*, PDEB_DLL_NODE_INFO* )
  1804. // PURPOSE  :
  1805. // COMMENTS :
  1806. //
  1807. // ************************************************************************
  1808. BOOL
  1809. AllocDllNode( PNODE* ppDllNode, PDEB_DLL_NODE_INFO* ppDllNodeInfo )
  1810. {
  1811.   //-- create node
  1812.   CreateNode( ppDllNode );
  1813.  
  1814.   //-- alloc info data
  1815.   *ppDllNodeInfo = (PDEB_DLL_NODE_INFO) HeapAlloc( hHeap, (DWORD) NULL,
  1816.                                       sizeof( DEB_DLL_NODE_INFO ) );
  1817.   (*ppDllNode)->pNodeData = *(ppDllNodeInfo);
  1818.   (*ppDllNodeInfo)->lpstrFileName = (LPTSTR) HeapAlloc( hHeap, (DWORD) NULL, (DWORD) MAX_PATH );
  1819.  
  1820.   return( TRUE );
  1821. }
  1822.  
  1823.  
  1824. // ************************************************************************
  1825. // FUNCTION : InitDllNodeInfo( PDEB_DLL_NODE_INFO*, LPDEBUG_EVENT )
  1826. // PURPOSE  :
  1827. // COMMENTS :
  1828. //
  1829. // ************************************************************************
  1830. BOOL
  1831. InitDllNodeInfo( PDEB_DLL_NODE_INFO* ppDllNodeInfo,
  1832.   LPDEBUG_EVENT lpDebugEvent )
  1833. {
  1834.   //-- init info data
  1835.   GetDllFileName( lpDebugEvent, (*ppDllNodeInfo)->lpstrFileName, MAX_PATH );
  1836.   (*ppDllNodeInfo)->DllDebugInfo = lpDebugEvent->u.LoadDll;
  1837.  
  1838.   return( TRUE );
  1839. }
  1840.  
  1841.  
  1842. // ************************************************************************
  1843. // FUNCTION : InsertDllNode( PLIST, PNODE )
  1844. // PURPOSE  :
  1845. // COMMENTS :
  1846. //
  1847. // ************************************************************************
  1848. BOOL
  1849. InsertDllNode( PLIST pDllList, PNODE pDllNode )
  1850. {
  1851.   PDEB_DLL_LIST_INFO pDllListInfo = pDllList->pListData;
  1852.  
  1853.   // insert the node
  1854.   InsertNode( pDllList, pDllNode );
  1855.  
  1856.   //-- increment dwActiveDlls
  1857.   pDllListInfo->dwActiveDlls++;
  1858.  
  1859.   return( TRUE );
  1860. }
  1861.  
  1862.  
  1863. // ************************************************************************
  1864. // FUNCTION : SetCurrentDllNode( PLIST, PNODE )
  1865. // PURPOSE  :
  1866. // COMMENTS :
  1867. //
  1868. // ************************************************************************
  1869. BOOL
  1870. SetCurrentDllNode( PLIST pDllList, PNODE pDllNode )
  1871. {
  1872.   SetCurrentNode( pDllList, pDllNode, pDllList->OrderFunction );
  1873.  
  1874.   return( TRUE );
  1875. }
  1876.  
  1877.  
  1878. // ************************************************************************
  1879. // FUNCTION : DeleteDllNode( PLIST, PNODE )
  1880. // PURPOSE  :
  1881. // COMMENTS :
  1882. //
  1883. // ************************************************************************
  1884. BOOL
  1885. DeleteDllNode( PLIST pDllList, PNODE pDllNode )
  1886. {
  1887.   PNODE pDeleteNode;
  1888.  
  1889.   SetCurrentNode( pDllList, pDllNode, pDllList->OrderFunction );
  1890.   GetCurrentNode( pDllList, &pDeleteNode );
  1891.   DeleteCurrentDllNode( pDllList );
  1892.  
  1893.   return( TRUE );
  1894. }
  1895.  
  1896.  
  1897. // ************************************************************************
  1898. // FUNCTION : FreeDllNodeInfo( PNODE )
  1899. // PURPOSE  :
  1900. // COMMENTS :
  1901. //
  1902. // ************************************************************************
  1903. BOOL
  1904. FreeDllNodeInfo( PNODE pDllNode )
  1905. {
  1906.   PDEB_DLL_NODE_INFO pDllNodeInfo = (PDEB_DLL_NODE_INFO) pDllNode->pNodeData;
  1907.  
  1908.   //-- free info data
  1909.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pDllNodeInfo->lpstrFileName );
  1910.   HeapFree( hHeap, (DWORD) NULL, (PVOID) pDllNodeInfo );
  1911.  
  1912.   return( TRUE );
  1913. }
  1914.  
  1915.  
  1916. // ************************************************************************
  1917. // FUNCTION : DestroyDllNode( PNODE )
  1918. // PURPOSE  :
  1919. // COMMENTS : Frees all memory associated with the node.
  1920. // ************************************************************************
  1921. BOOL
  1922. DestroyDllNode( PNODE pDllNode )
  1923. {
  1924.   //-- free info data
  1925.   FreeDllNodeInfo( pDllNode );
  1926.  
  1927.   //-- destroy node
  1928.   DestroyNode( pDllNode );
  1929.  
  1930.   return( TRUE );
  1931. }
  1932.  
  1933.  
  1934. // ************************************************************************
  1935. // FUNCTION : DeleteCurrentDllNode( PLIST )
  1936. // PURPOSE  :
  1937. // COMMENTS : Deletes the current DLL node from the list and frees all
  1938. //            memory associated with it.
  1939. // ************************************************************************
  1940. BOOL
  1941. DeleteCurrentDllNode( PLIST pDllList )
  1942. {
  1943.   PDEB_DLL_LIST_INFO pDllListInfo = pDllList->pListData;
  1944.   PNODE              pDllNode = (PNODE) pDllList->pCurrentNode;
  1945.  
  1946.   //-- free info data
  1947.   FreeDllNodeInfo( pDllNode );
  1948.  
  1949.   //-- delete and destroy node
  1950.   DeleteCurrentNode( pDllList );
  1951.  
  1952.   //-- decrement dwActiveDlls
  1953.   pDllListInfo->dwActiveDlls--;
  1954.  
  1955.   return( TRUE );
  1956. }
  1957.