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

  1. /*++
  2.  
  3. Copyright (c) 1993  Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     debug.c
  8.  
  9. Abstract:
  10.  
  11.     This file implements the debug module for drwatson.  This module
  12.     processes all debug events and generates the postmortem dump.
  13.  
  14. Author:
  15.  
  16.     Wesley Witt (wesw) 1-May-1993
  17.  
  18. Environment:
  19.  
  20.     User Mode
  21.  
  22. --*/
  23.  
  24. #include <windows.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <stddef.h>
  29.  
  30. #include "drwatson.h"
  31. #include "cv.h"
  32. #include "cvfmt.h"
  33. #include "proto.h"
  34. #include "messages.h"
  35. #include "resource.h"
  36.  
  37. typedef struct tagSYSINFO {
  38.     char    szUserName[MAX_PATH];
  39.     char    szMachineName[MAX_PATH];
  40. } SYSINFO, *PSYSINFO;
  41.  
  42.  
  43. #define DBG_EXCEPTION_HANDLED           ((DWORD)0x00010001L)
  44. #define STATUS_POSSIBLE_DEADLOCK        ((DWORD)0xC0000194L)
  45. #define STATUS_VDM_EVENT                STATUS_SEGMENT_NOTIFICATION
  46.  
  47. PTHREADCONTEXT
  48. AllocTctx(
  49.     PDEBUGPACKET dp
  50.     );
  51.  
  52. void
  53. PostMortemDump(
  54.     PDEBUGPACKET dp,
  55.     LPEXCEPTION_DEBUG_INFO ed
  56.     );
  57.  
  58. void
  59. AttachToActiveProcess (
  60.     PDEBUGPACKET dp
  61.     );
  62.  
  63. void
  64. ProcessCreateProcess(
  65.     PDEBUGPACKET dp,
  66.     LPDEBUG_EVENT de
  67.     );
  68.  
  69. void
  70. ProcessCreateThread(
  71.     PDEBUGPACKET dp,
  72.     LPDEBUG_EVENT de
  73.     );
  74.  
  75. void
  76. ProcessExitThread(
  77.     PDEBUGPACKET dp,
  78.     LPDEBUG_EVENT de
  79.     );
  80.  
  81. void
  82. ProcessLoadDll(
  83.     PDEBUGPACKET dp,
  84.     LPDEBUG_EVENT de
  85.     );
  86.  
  87. void
  88. LogSystemInformation(
  89.     PDEBUGPACKET dp
  90.     );
  91.  
  92. DWORD
  93. SysInfoThread(
  94.     PSYSINFO si
  95.     );
  96.  
  97. void
  98. LogDisassembly(
  99.     PDEBUGPACKET dp,
  100.     PCRASHES pCrash
  101.     );
  102.  
  103. void
  104. LogStackWalk(
  105.     PDEBUGPACKET dp
  106.     );
  107.  
  108. void
  109. LogStackDump(
  110.     PDEBUGPACKET dp
  111.     );
  112.  
  113. char *
  114. GetExceptionText(
  115.     DWORD dwExceptionCode
  116.     );
  117.  
  118. LPSTR
  119. ExpandPath(
  120.     LPSTR lpPath
  121.     );
  122.  
  123. void
  124. SetFaultingContext(
  125.     PDEBUGPACKET dp,
  126.     LPDEBUG_EVENT de
  127.     );
  128.  
  129. void
  130. SkipOverBreakpoint(
  131.     PDEBUGPACKET dp,
  132.     LPDEBUG_EVENT de
  133.     );
  134.  
  135. DWORD
  136. DispatchDebugEventThread(
  137.     PDEBUGPACKET dp
  138.     )
  139.  
  140. /*++
  141.  
  142. Routine Description:
  143.  
  144.     This is the entry point for DRWTSN32
  145.  
  146. Arguments:
  147.  
  148.     None.
  149.  
  150. Return Value:
  151.  
  152.     None.
  153.  
  154. --*/
  155.  
  156. {
  157.     DEBUG_EVENT   de;
  158.     DWORD         rc = 0;
  159.     char          szLogFileName[1024];
  160.     char          buf[1024];
  161.     LPSTR         p;
  162.     DWORD         ContinueStatus;
  163.  
  164.  
  165.     if (dp->dwPidToDebug == 0) {
  166.         rc = 1;
  167.         goto exit;
  168.     }
  169.  
  170.     SetErrorMode( SEM_FAILCRITICALERRORS |
  171.                   SEM_NOGPFAULTERRORBOX  |
  172.                   SEM_NOOPENFILEERRORBOX   );
  173.  
  174.     AttachToActiveProcess( dp );
  175.  
  176.     p = ExpandPath( dp->options.szLogPath );
  177.     if (p) {
  178.         strcpy( szLogFileName, p );
  179.         free( p );
  180.     } else {
  181.         strcpy( szLogFileName, dp->options.szLogPath );
  182.     }
  183.     MakeLogFileName( szLogFileName );
  184.     OpenLogFile( szLogFileName,
  185.                  dp->options.fAppendToLogFile,
  186.                  dp->options.fVisual
  187.                );
  188.  
  189.     while (TRUE) {
  190.         if (!WaitForDebugEvent( &de, 10000 )) {
  191.             rc = GetLastError();
  192.             goto exit;
  193.         }
  194.         ContinueStatus = DBG_CONTINUE;
  195.  
  196.         switch (de.dwDebugEventCode) {
  197.             case EXCEPTION_DEBUG_EVENT:
  198.                 if (de.u.Exception.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT) {
  199.                     if (de.u.Exception.dwFirstChance) {
  200.                         SkipOverBreakpoint(dp, &de);
  201.                         ContinueStatus = DBG_EXCEPTION_HANDLED;
  202.                         //
  203.                         // The aedebug event will be signalled AFTER this
  204.                         // thread exits, so that it will disappear before
  205.                         // the dump snapshot is taken.
  206.                         //
  207.                         break;
  208.                     }
  209.                 }
  210.                 if (dp->options.fVisual) {
  211.                     //
  212.                     // this notification is necessary because the shell must know when
  213.                     // the debugee has been attached.  if it doesn't know and the user is
  214.                     // allowed to terminate drwatson then the system may intervene with
  215.                     // a popup.
  216.                     //
  217.                     SendMessage( dp->hwnd, WM_ATTACHCOMPLETE, 0, 0 );
  218.                     wsprintf( buf,
  219.                               LoadRcString( IDS_AE_TEXT ),
  220.                               GetExceptionText(de.u.Exception.ExceptionRecord.ExceptionCode),
  221.                               de.u.Exception.ExceptionRecord.ExceptionCode,
  222.                               de.u.Exception.ExceptionRecord.ExceptionAddress );
  223.                     SendMessage( dp->hwnd, WM_EXCEPTIONINFO, 0, (LPARAM) buf );
  224.                 }
  225.                 SetFaultingContext(dp, &de);
  226.                 PostMortemDump( dp, &de.u.Exception );
  227.                 if (dp->options.fCrash) {
  228.                     CreateDumpFile( dp, &de.u.Exception );
  229.                 }
  230.                 ContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
  231.                 break;
  232.  
  233.             case CREATE_THREAD_DEBUG_EVENT:
  234.                 ProcessCreateThread( dp, &de );
  235.                 break;
  236.  
  237.             case CREATE_PROCESS_DEBUG_EVENT:
  238.                 ProcessModuleLoad( dp, &de );
  239.                 de.u.CreateThread.hThread = de.u.CreateProcessInfo.hThread;
  240.                 ProcessCreateThread( dp, &de );
  241.                 break;
  242.  
  243.             case EXIT_THREAD_DEBUG_EVENT:
  244.                 ProcessExitThread( dp, &de );
  245.                 if ( dp->hEventToSignal ) {
  246.                     SetEvent(dp->hEventToSignal);
  247.                     dp->hEventToSignal = 0L;
  248.                 }
  249.                 break;
  250.  
  251.             case EXIT_PROCESS_DEBUG_EVENT:
  252.                 goto exit;
  253.                 break;
  254.  
  255.             case LOAD_DLL_DEBUG_EVENT:
  256.                 ProcessModuleLoad( dp, &de );
  257.                 break;
  258.  
  259.             case UNLOAD_DLL_DEBUG_EVENT:
  260.                 break;
  261.  
  262.             case OUTPUT_DEBUG_STRING_EVENT:
  263.                 break;
  264.  
  265.             case RIP_EVENT:
  266.                 break;
  267.  
  268.             default:
  269.                 lprintf( MSG_INVALID_DEBUG_EVENT, de.dwDebugEventCode );
  270.                 break;
  271.         }
  272.         ContinueDebugEvent( de.dwProcessId, de.dwThreadId, ContinueStatus );
  273.     }
  274.  
  275. exit:
  276.     CloseLogFile();
  277.  
  278.     if (dp->options.fVisual) {
  279.         SendMessage( dp->hwnd, WM_DUMPCOMPLETE, 0, 0 );
  280.     }
  281.  
  282.     return 0;
  283. }
  284.  
  285. PTHREADCONTEXT
  286. AllocTctx(
  287.     PDEBUGPACKET dp
  288.     )
  289. {
  290.     PTHREADCONTEXT ptctx;
  291.  
  292.     ptctx = (PTHREADCONTEXT) malloc( sizeof(THREADCONTEXT) );
  293.     if (ptctx == NULL) {
  294.         if (dp->options.fVisual) {
  295.             FatalError( LoadRcString(IDS_MEMORY) );
  296.         }
  297.         else {
  298.             ExitProcess( 1 );
  299.         }
  300.     }
  301.     memset( ptctx, 0, sizeof(THREADCONTEXT) );
  302.  
  303.     return ptctx;
  304. }
  305.  
  306. void
  307. ProcessCreateThread(
  308.     PDEBUGPACKET dp,
  309.     LPDEBUG_EVENT de
  310.     )
  311. {
  312.     dp->tctx              = AllocTctx( dp );
  313.     dp->tctx->hThread     = de->u.CreateThread.hThread;
  314.     dp->tctx->dwThreadId  = de->dwThreadId;
  315.  
  316.     InsertTailList(&dp->ThreadList, &dp->tctx->ThreadList);
  317.  
  318.     return;
  319. }
  320.  
  321. void
  322. ProcessExitThread(
  323.     PDEBUGPACKET dp,
  324.     LPDEBUG_EVENT de
  325.     )
  326. {
  327.     PTHREADCONTEXT ptctx;
  328.     PLIST_ENTRY List = dp->ThreadList.Flink;
  329.  
  330.     while (List != &dp->ThreadList) {
  331.         ptctx = CONTAINING_RECORD(List, THREADCONTEXT, ThreadList);
  332.         if (ptctx->dwThreadId == de->dwThreadId) {
  333.             RemoveEntryList(List);
  334.             free(ptctx);
  335.             break;
  336.         }
  337.         List = List->Flink;
  338.     }
  339. }
  340.  
  341. void
  342. PostMortemDump(
  343.     PDEBUGPACKET dp,
  344.     LPEXCEPTION_DEBUG_INFO ed
  345.     )
  346. {
  347.     IMAGEHLP_MODULE   mi;
  348.     char              dbuf[1024];
  349.     char              szDate[20];
  350.     char              szTime[20];
  351.     CRASHES           crash;
  352.     DWORD             dwThreadId;
  353.     HANDLE            hThread;
  354.     PLIST_ENTRY        List;
  355.  
  356.  
  357.     GetLocalTime( &crash.time );
  358.     crash.dwExceptionCode = ed->ExceptionRecord.ExceptionCode;
  359.     crash.dwAddress = (DWORD)ed->ExceptionRecord.ExceptionAddress;
  360.     strcpy( crash.szAppName, szApp );
  361.  
  362.     lprintf( MSG_APP_EXCEPTION );
  363.     wsprintf( dbuf, "%d", dp->dwPidToDebug );
  364.     lprintf( MSG_APP_EXEP_NAME, crash.szAppName, dbuf );
  365.     wsprintf( szDate, "%d/%d/%d", crash.time.wMonth,
  366.                                   crash.time.wDay,
  367.                                   crash.time.wYear );
  368.     wsprintf( szTime, "%d:%d:%d.%d", crash.time.wHour,
  369.                                      crash.time.wMinute,
  370.                                      crash.time.wSecond,
  371.                                      crash.time.wMilliseconds );
  372.     lprintf( MSG_APP_EXEP_WHEN, szDate, szTime );
  373.     wsprintf( dbuf, "%08lx", ed->ExceptionRecord.ExceptionCode );
  374.     lprintf( MSG_EXCEPTION_NUMBER, dbuf );
  375.  
  376.  
  377.     lprintfs( "(%s)\r\n\r\n",
  378.               GetExceptionText(ed->ExceptionRecord.ExceptionCode) );
  379.  
  380.     LogSystemInformation( dp );
  381.  
  382.     LogTaskList();
  383.  
  384.     if (SymGetModuleInfo( dp->hProcess, 0, &mi )) {
  385.         do {
  386.             lprintfs( "(%08x - %08x) %s\r\n",
  387.                       (DWORD)mi.BaseOfImage,
  388.                       (DWORD)mi.BaseOfImage + mi.ImageSize,
  389.                       mi.LoadedImageName
  390.                     );
  391.         } while( SymGetModuleInfo( dp->hProcess, (DWORD)-1, &mi ));
  392.         lprintfs( "\r\n" );
  393.     }
  394.  
  395.     List = dp->ThreadList.Flink;
  396.     while (List != &dp->ThreadList) {
  397.  
  398.         dp->tctx = CONTAINING_RECORD(List, THREADCONTEXT, ThreadList);
  399.         List = List->Flink;
  400.  
  401.         GetContextForThread( dp );
  402.  
  403.         if (dp->tctx->fFaultingContext || dp->options.fDumpAllThreads) {
  404.             wsprintf( dbuf, "%x", dp->tctx->dwThreadId );
  405.             lprintf( MSG_STATE_DUMP, dbuf );
  406.             OutputAllRegs( dp, TRUE );
  407.             LogDisassembly( dp, &crash );
  408.             LogStackWalk( dp );
  409.             LogStackDump( dp );
  410.         }
  411.     }
  412.  
  413.     if (dp->options.fDumpSymbols) {
  414.         DumpSymbols( dp );
  415.     }
  416.  
  417.     ElSaveCrash( &crash, dp->options.dwMaxCrashes );
  418.  
  419.     hThread = CreateThread( NULL,
  420.                             16000,
  421.                             (LPTHREAD_START_ROUTINE)TerminationThread,
  422.                             dp,
  423.                             0,
  424.                             (LPDWORD)&dwThreadId
  425.                           );
  426.  
  427.     WaitForSingleObject( hThread, 30000 );
  428.  
  429.     CloseHandle( hThread );
  430.  
  431.     return;
  432. }
  433.  
  434. void
  435. LogStackDump(
  436.     PDEBUGPACKET dp
  437.     )
  438. {
  439.     DWORD   i;
  440.     DWORD   j;
  441.     BYTE    stack[1024];
  442.  
  443.  
  444.  
  445.     memset( stack, 0, sizeof(stack) );
  446.     if (!DoMemoryRead( dp,
  447.                        (LPVOID)dp->tctx->stack,
  448.                        (LPVOID)stack,
  449.                        sizeof(stack),
  450.                        (LPDWORD)&i )) {
  451.         return;
  452.     }
  453.  
  454.     lprintf( MSG_STACK_DUMP_HEADER );
  455.  
  456.     for( i = 0; i < 20; i++ ) {
  457.         j = i * 16;
  458.         lprintfs( "%08x  %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x  %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\r\n",
  459.                   j + dp->tctx->stack,
  460.                   stack[ j +  0 ],
  461.                   stack[ j +  1 ],
  462.                   stack[ j +  2 ],
  463.                   stack[ j +  3 ],
  464.                   stack[ j +  4 ],
  465.                   stack[ j +  5 ],
  466.                   stack[ j +  6 ],
  467.                   stack[ j +  7 ],
  468.                   stack[ j +  8 ],
  469.                   stack[ j +  9 ],
  470.                   stack[ j + 10 ],
  471.                   stack[ j + 11 ],
  472.                   stack[ j + 12 ],
  473.                   stack[ j + 13 ],
  474.                   stack[ j + 14 ],
  475.                   stack[ j + 15 ],
  476.                   isprint( stack[ j +  0 ]) ? stack[ j +  0 ] : '.',
  477.                   isprint( stack[ j +  1 ]) ? stack[ j +  1 ] : '.',
  478.                   isprint( stack[ j +  2 ]) ? stack[ j +  2 ] : '.',
  479.                   isprint( stack[ j +  3 ]) ? stack[ j +  3 ] : '.',
  480.                   isprint( stack[ j +  4 ]) ? stack[ j +  4 ] : '.',
  481.                   isprint( stack[ j +  5 ]) ? stack[ j +  5 ] : '.',
  482.                   isprint( stack[ j +  6 ]) ? stack[ j +  6 ] : '.',
  483.                   isprint( stack[ j +  7 ]) ? stack[ j +  7 ] : '.',
  484.                   isprint( stack[ j +  8 ]) ? stack[ j +  8 ] : '.',
  485.                   isprint( stack[ j +  9 ]) ? stack[ j +  9 ] : '.',
  486.                   isprint( stack[ j + 10 ]) ? stack[ j + 10 ] : '.',
  487.                   isprint( stack[ j + 11 ]) ? stack[ j + 11 ] : '.',
  488.                   isprint( stack[ j + 12 ]) ? stack[ j + 12 ] : '.',
  489.                   isprint( stack[ j + 13 ]) ? stack[ j + 13 ] : '.',
  490.                   isprint( stack[ j + 14 ]) ? stack[ j + 14 ] : '.',
  491.                   isprint( stack[ j + 15 ]) ? stack[ j + 15 ] : '.'
  492.                 );
  493.     }
  494.  
  495.     lprintfs( "\r\n" );
  496.     return;
  497. }
  498.  
  499. void
  500. LogStackWalk(
  501.     PDEBUGPACKET dp
  502.     )
  503. {
  504.     #define SAVE_EBP(f)        f.Reserved[0]
  505.     #define TRAP_TSS(f)        f.Reserved[1]
  506.     #define TRAP_EDITED(f)     f.Reserved[1]
  507.     #define SAVE_TRAP(f)       f.Reserved[2]
  508.  
  509.     DWORD             dwDisplacement = 0;
  510.     DWORD             frames = 0;
  511.     LPSTR             szSymName;
  512.     IMAGEHLP_MODULE   mi;
  513.     DWORD             i;
  514.     DWORD             machType;
  515.     CONTEXT           Context;
  516.     STACKFRAME        stk;
  517.  
  518.  
  519.     Context = dp->tctx->context;
  520.     ZeroMemory( &stk, sizeof(stk) );
  521.  
  522.     stk.AddrPC.Offset       = dp->tctx->pc;
  523.     stk.AddrPC.Mode         = AddrModeFlat;
  524.  
  525. #if defined(_M_IX86)
  526.     machType = IMAGE_FILE_MACHINE_I386;
  527.     stk.AddrStack.Offset    = dp->tctx->stack;
  528.     stk.AddrStack.Mode      = AddrModeFlat;
  529.     stk.AddrFrame.Offset    = dp->tctx->frame;
  530.     stk.AddrFrame.Mode      = AddrModeFlat;
  531. #elif defined(_M_MRX000)
  532.     machType = IMAGE_FILE_MACHINE_R4000;
  533. #elif defined(_M_ALPHA)
  534.     machType = IMAGE_FILE_MACHINE_ALPHA;
  535. #elif defined(_M_PPC)
  536.     machType = IMAGE_FILE_MACHINE_POWERPC;
  537. #else
  538. #error( "unknown target machine" );
  539. #endif
  540.  
  541.     lprintf( MSG_STACKTRACE );
  542.  
  543.     for (i=0; i<100; i++) {
  544.         if (!StackWalk( machType,
  545.                         (HANDLE)dp,
  546.                         NULL,
  547.                         &stk,
  548.                         &Context,
  549.                         SwReadProcessMemory,
  550.                         SwFunctionTableAccess,
  551.                         SwGetModuleBase,
  552.                         SwTranslateAddress )) {
  553.             break;
  554.         }
  555.         if (SymGetSymFromAddr( dp->hProcess, stk.AddrPC.Offset, &dwDisplacement, sym )) {
  556.             szSymName = sym->Name;
  557.         }
  558.         else {
  559.             szSymName = "<nosymbols>";
  560.         }
  561.         lprintfs( "%08x %08x %08x %08x %08x %08x ",
  562.                   stk.AddrFrame.Offset,
  563.                   stk.AddrReturn.Offset,
  564.                   stk.Params[0],
  565.                   stk.Params[1],
  566.                   stk.Params[2],
  567.                   stk.Params[3]
  568.                 );
  569.  
  570.         if (SymGetModuleInfo( dp->hProcess, stk.AddrPC.Offset, &mi )) {
  571.             lprintfs( "%s!", mi.ModuleName );
  572.         }
  573.  
  574.         lprintfs( "%s ", szSymName );
  575.  
  576.         if (sym && (sym->Flags & SYMF_OMAP_GENERATED || sym->Flags & SYMF_OMAP_MODIFIED)) {
  577.             lprintfs( "[omap] " );
  578.         }
  579.  
  580.         if (stk.FuncTableEntry && machType == IMAGE_FILE_MACHINE_I386) {
  581.             PFPO_DATA pFpoData = (PFPO_DATA)stk.FuncTableEntry;
  582.             switch (pFpoData->cbFrame) {
  583.                 case FRAME_FPO:
  584.                     if (pFpoData->fHasSEH) {
  585.                         lprintfs( "(FPO: [SEH])" );
  586.                     } else {
  587.                         lprintfs( " (FPO:" );
  588.                         if (pFpoData->fUseBP) {
  589.                             lprintfs( " [EBP 0x%08x]", SAVE_EBP(stk) );
  590.                         }
  591.                         lprintfs(" [%d,%d,%d])", pFpoData->cdwParams,
  592.                                                  pFpoData->cdwLocals,
  593.                                                  pFpoData->cbRegs);
  594.                     }
  595.                     break;
  596.                 case FRAME_NONFPO:
  597.                     lprintfs( "(FPO: Non-FPO [%d,%d,%d])",
  598.                                  pFpoData->cdwParams,
  599.                                  pFpoData->cdwLocals,
  600.                                  pFpoData->cbRegs);
  601.                     break;
  602.  
  603.                 case FRAME_TRAP:
  604.                 case FRAME_TSS:
  605.                 default:
  606.                     lprintfs( "(UNKNOWN FPO TYPE)" );
  607.                     break;
  608.             }
  609.         }
  610.  
  611.         lprintfs( "\r\n" );
  612.  
  613.     }
  614.  
  615.     lprintfs( "\r\n" );
  616.     return;
  617. }
  618.  
  619.  
  620. void
  621. LogDisassembly(
  622.     PDEBUGPACKET dp,
  623.     PCRASHES pCrash
  624.     )
  625. {
  626.     DWORD             dwFuncAddr;
  627.     DWORD             dwFuncSize;
  628.     DWORD             dwDisplacement = 0;
  629.     char              *szSymName;
  630.     DWORD             offset;
  631.     int               i;
  632.     int               j;
  633.     char              dbuf[1024];
  634.     BOOL              fFaultingInst;
  635.     int               dwStartDis;
  636.     int               dwEndDis;
  637.  
  638.  
  639.     if (SymGetSymFromAddr( dp->hProcess, dp->tctx->pc, &dwDisplacement, sym )) {
  640.         dwFuncAddr = sym->Address;
  641.         dwFuncSize = sym->Size;
  642.         if (dwFuncSize < 1) {
  643.             dwFuncSize = 100;
  644.         }
  645.         szSymName = sym->Name;
  646.     }
  647.     else {
  648.         dwFuncAddr = dp->tctx->pc - 50;
  649.         dwFuncSize = 100;
  650.         szSymName = "<nosymbols>";
  651.     }
  652.  
  653.     if (dp->tctx->fFaultingContext) {
  654.         strcpy( pCrash->szFunction, szSymName );
  655.     }
  656.  
  657.     lprintf( MSG_FUNCTION, szSymName );
  658.  
  659. tryagain:
  660.     //
  661.     // count the number of instructions in the function
  662.     // also, save the instruction number of context's pc
  663.     //
  664.     for (i=0,offset=dwFuncAddr,j=-1; offset<dwFuncAddr+dwFuncSize; i++) {
  665.         if (offset == dp->tctx->pc) {
  666.             j = i;
  667.         }
  668.         if (!disasm( dp, &offset, dbuf, TRUE )) {
  669.             break;
  670.         }
  671.     }
  672.  
  673.     if (j == -1) {
  674.         //
  675.         // we didn't find a match for the current pc
  676.         // this because we don't have symbols for the current pc and
  677.         // therefore had to just backup and start disassembling.  we try
  678.         // to recover by adding 1 to the func addr and do it again.
  679.         // eventually we will hit the pc and we will be a-ok.
  680.         //
  681.         dwFuncAddr++;
  682.         goto tryagain;
  683.     }
  684.  
  685.     //
  686.     // print the disassemled instructions.  only print the number
  687.     // of instructions before and after the current pc that the
  688.     // user specified in the registry options.
  689.     //
  690.     dwStartDis = max(0,j - (int)dp->options.dwInstructions);
  691.     dwEndDis = j+(int)dp->options.dwInstructions;
  692.     fFaultingInst = FALSE;
  693.     for (i=0,offset=dwFuncAddr; offset<dwFuncAddr+dwFuncSize; i++) {
  694.         if (offset == dp->tctx->pc) {
  695.             fFaultingInst = TRUE;
  696.         }
  697.         if (!disasm( dp, &offset, dbuf, TRUE )) {
  698.             break;
  699.         }
  700.         if (i >= dwStartDis) {
  701.             if (fFaultingInst && dp->tctx->fFaultingContext) {
  702.                 fFaultingInst = FALSE;
  703.                 lprintf( MSG_FAULT );
  704.             }
  705.             else {
  706.                 lprintfs( "        " );
  707.             }
  708.             lprintfs( "%s\r\n", dbuf );
  709.         }
  710.         if (i > dwEndDis) {
  711.             break;
  712.         }
  713.     }
  714.  
  715.     lprintfs( "\r\n" );
  716.     return;
  717. }
  718.  
  719. void
  720. AttachToActiveProcess (
  721.     PDEBUGPACKET dp
  722.     )
  723. {
  724.     HANDLE              Token;
  725.     PTOKEN_PRIVILEGES   NewPrivileges;
  726.     BYTE                OldPriv[1024];
  727.     PBYTE               pbOldPriv;
  728.     ULONG               cbNeeded;
  729.     BOOLEAN             fRc;
  730.     LUID                LuidPrivilege;
  731.  
  732.     //
  733.     // Make sure we have access to adjust and to get the old token privileges
  734.     //
  735.     if (!OpenProcessToken( GetCurrentProcess(),
  736.                            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  737.                            &Token)) {
  738.         if (dp->options.fVisual) {
  739.             FatalError( LoadRcString(IDS_DEBUGPRIV) );
  740.         }
  741.         else {
  742.             ExitProcess( 1 );
  743.         }
  744.     }
  745.  
  746.     cbNeeded = 0;
  747.  
  748.     //
  749.     // Initialize the privilege adjustment structure
  750.     //
  751.  
  752.     LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &LuidPrivilege );
  753.  
  754.     NewPrivileges =
  755.         (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_ZEROINIT,
  756.                                       sizeof(TOKEN_PRIVILEGES) +
  757.                                           (1 - ANYSIZE_ARRAY) *
  758.                                           sizeof(LUID_AND_ATTRIBUTES));
  759.     if (NewPrivileges == NULL) {
  760.         if (dp->options.fVisual) {
  761.             FatalError( LoadRcString(IDS_DEBUGPRIV) );
  762.         }
  763.         else {
  764.             ExitProcess( 1 );
  765.         }
  766.     }
  767.  
  768.     NewPrivileges->PrivilegeCount = 1;
  769.     NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  770.     NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  771.  
  772.     //
  773.     // Enable the privilege
  774.     //
  775.  
  776.     pbOldPriv = OldPriv;
  777.     fRc = AdjustTokenPrivileges( Token,
  778.                                  FALSE,
  779.                                  NewPrivileges,
  780.                                  1024,
  781.                                  (PTOKEN_PRIVILEGES)pbOldPriv,
  782.                                  &cbNeeded );
  783.  
  784.     if (!fRc) {
  785.  
  786.         //
  787.         // If the stack was too small to hold the privileges
  788.         // then allocate off the heap
  789.         //
  790.         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  791.  
  792.             pbOldPriv = LocalAlloc(LMEM_FIXED, cbNeeded);
  793.             if (pbOldPriv == NULL) {
  794.                 if (dp->options.fVisual) {
  795.                     FatalError( LoadRcString(IDS_DEBUGPRIV) );
  796.                 }
  797.                 else {
  798.                     ExitProcess( 1 );
  799.                 }
  800.             }
  801.  
  802.             fRc = AdjustTokenPrivileges( Token,
  803.                                          FALSE,
  804.                                          NewPrivileges,
  805.                                          cbNeeded,
  806.                                          (PTOKEN_PRIVILEGES)pbOldPriv,
  807.                                          &cbNeeded );
  808.         }
  809.     }
  810.  
  811.  
  812.     if (!DebugActiveProcess( dp->dwPidToDebug )) {
  813.         FatalError( LoadRcString(IDS_ATTACHFAIL) );
  814.         if (dp->options.fVisual) {
  815.             FatalError( LoadRcString(IDS_ATTACHFAIL) );
  816.         }
  817.         else {
  818.             ExitProcess( 1 );
  819.         }
  820.     }
  821.  
  822.     return;
  823. }
  824.  
  825. void
  826. LogSystemInformation(
  827.     PDEBUGPACKET dp
  828.     )
  829. {
  830.     char          buf[1024];
  831.     SYSTEM_INFO   si;
  832.     DWORD         ver;
  833.     SYSINFO       mySi;
  834.     DWORD         dwThreadId;
  835.     HANDLE        hThread;
  836.  
  837.     lprintf( MSG_SYSINFO_HEADER );
  838.     hThread = CreateThread( NULL,
  839.                             16000,
  840.                             (LPTHREAD_START_ROUTINE)SysInfoThread,
  841.                             &mySi,
  842.                             0,
  843.                             (LPDWORD)&dwThreadId
  844.                           );
  845.     Sleep( 0 );
  846.     if (WaitForSingleObject( hThread, 30000 ) == WAIT_TIMEOUT) {
  847.         Assert(TerminateThread( hThread, 0 ) == TRUE);
  848.     }
  849.     CloseHandle( hThread );
  850.     lprintf( MSG_SYSINFO_COMPUTER, mySi.szMachineName );
  851.     lprintf( MSG_SYSINFO_USER, mySi.szUserName );
  852.     GetSystemInfo( &si );
  853.     wsprintf( buf, "%d", si.dwNumberOfProcessors );
  854.     lprintf( MSG_SYSINFO_NUM_PROC, buf );
  855.     RegLogProcessorType();
  856.     ver = GetVersion();
  857.     wsprintf( buf, "%d.%d", LOBYTE(LOWORD(ver)), HIBYTE(LOWORD(ver)) );
  858.     lprintf( MSG_SYSINFO_WINVER, buf );
  859.     RegLogCurrentVersion();
  860.     lprintfs( "\r\n" );
  861. }
  862.  
  863. DWORD
  864. SysInfoThread(
  865.     PSYSINFO si
  866.     )
  867. {
  868.     DWORD len;
  869.  
  870.     strcpy( si->szMachineName, LoadRcString( IDS_UNKNOWN_MACHINE ) );
  871.     strcpy( si->szUserName,    LoadRcString( IDS_UNKNOWN_USER ) );
  872.     len = sizeof(si->szMachineName);
  873.     GetComputerName( si->szMachineName, &len );
  874.     len = sizeof(si->szUserName);
  875.     GetUserName( si->szUserName, &len );
  876.  
  877.     return 0;
  878. }
  879.  
  880. DWORD
  881. TerminationThread(
  882.     PDEBUGPACKET dp
  883.     )
  884. {
  885.     HANDLE hProcess;
  886.  
  887.     hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, dp->dwPidToDebug );
  888.     if (hProcess != NULL) {
  889.         TerminateProcess( hProcess, 0 );
  890.         CloseHandle( hProcess );
  891.     }
  892.  
  893.     return 0;
  894. }
  895.  
  896. char *
  897. GetExceptionText(
  898.     DWORD dwExceptionCode
  899.     )
  900. {
  901.     static char buf[80];
  902.     DWORD dwFormatId = 0;
  903.  
  904.     memset( buf, 0, sizeof(buf) );
  905.  
  906.     switch (dwExceptionCode) {
  907.         case STATUS_SINGLE_STEP:
  908.             dwFormatId = MSG_SINGLE_STEP_EXCEPTION;
  909.             break;
  910.  
  911.         case DBG_CONTROL_C:
  912.             dwFormatId = MSG_CONTROLC_EXCEPTION;
  913.             break;
  914.  
  915.         case DBG_CONTROL_BREAK:
  916.             dwFormatId = MSG_CONTROL_BRK_EXCEPTION;
  917.             break;
  918.  
  919.         case STATUS_ACCESS_VIOLATION:
  920.             dwFormatId = MSG_ACCESS_VIOLATION_EXCEPTION;
  921.             break;
  922.  
  923.         case STATUS_STACK_OVERFLOW:
  924.             dwFormatId = MSG_STACK_OVERFLOW_EXCEPTION;
  925.             break;
  926.  
  927.         case STATUS_INTEGER_DIVIDE_BY_ZERO:
  928.             dwFormatId = MSG_INTEGER_DIVIDE_BY_ZERO_EXCEPTION;
  929.             break;
  930.  
  931.         case STATUS_PRIVILEGED_INSTRUCTION:
  932.             dwFormatId = MSG_PRIVILEGED_INSTRUCTION_EXCEPTION;
  933.             break;
  934.  
  935.         case STATUS_ILLEGAL_INSTRUCTION:
  936.             dwFormatId = MSG_ILLEGAL_INSTRUCTION_EXCEPTION;
  937.             break;
  938.  
  939.         case STATUS_IN_PAGE_ERROR:
  940.             dwFormatId = MSG_IN_PAGE_IO_EXCEPTION;
  941.             break;
  942.  
  943.         case STATUS_DATATYPE_MISALIGNMENT:
  944.             dwFormatId = MSG_DATATYPE_EXCEPTION;
  945.             break;
  946.  
  947.         case STATUS_POSSIBLE_DEADLOCK:
  948.             dwFormatId = MSG_DEADLOCK_EXCEPTION;
  949.             break;
  950.  
  951.         case STATUS_VDM_EVENT:
  952.             dwFormatId = MSG_VDM_EXCEPTION;
  953.             break;
  954.  
  955.         case STATUS_BREAKPOINT:
  956.             dwFormatId = MSG_BREAKPOINT_EXCEPTION;
  957.             break;
  958.  
  959.         default:
  960.             lprintfs( "\r\n" );
  961.             break;
  962.     }
  963.  
  964.     FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  965.                    NULL,
  966.                    dwFormatId,
  967.                    0, // GetUserDefaultLangID(),
  968.                    buf,
  969.                    sizeof(buf),
  970.                    NULL
  971.                  );
  972.  
  973.     return buf;
  974. }
  975.  
  976. BOOL
  977. DoMemoryRead(
  978.     PDEBUGPACKET  dp,
  979.     LPVOID        addr,
  980.     LPVOID        buf,
  981.     DWORD         size,
  982.     LPDWORD       lpcb
  983.     )
  984. {
  985.     return ReadProcessMemory( dp->hProcess, addr, buf, size, lpcb );
  986. }
  987.  
  988. LPSTR
  989. ExpandPath(
  990.     LPSTR lpPath
  991.     )
  992. {
  993.     DWORD   len;
  994.     LPSTR   p;
  995.  
  996.  
  997.     len = ExpandEnvironmentStrings( lpPath, NULL, 0 );
  998.     if (!len) {
  999.         return NULL;
  1000.     }
  1001.  
  1002.     len += 1;
  1003.     p = malloc( len );
  1004.     if (!p) {
  1005.         return NULL;
  1006.     }
  1007.  
  1008.     len = ExpandEnvironmentStrings( lpPath, p, len );
  1009.     if (!len) {
  1010.         free( p );
  1011.         return NULL;
  1012.     }
  1013.  
  1014.     return p;
  1015. }
  1016.  
  1017. void
  1018. SetFaultingContext(
  1019.     PDEBUGPACKET dp,
  1020.     LPDEBUG_EVENT de
  1021.     )
  1022. {
  1023.     PTHREADCONTEXT ptctx;
  1024.     PLIST_ENTRY List = dp->ThreadList.Flink;
  1025.  
  1026.     dp->DebugEvent = *de;
  1027.  
  1028.     while (List != &dp->ThreadList) {
  1029.         ptctx = CONTAINING_RECORD(List, THREADCONTEXT, ThreadList);
  1030.         List = List->Flink;
  1031.         if (ptctx->dwThreadId == de->dwThreadId) {
  1032.             ptctx->fFaultingContext = TRUE;
  1033.             break;
  1034.         }
  1035.     }
  1036. }
  1037.  
  1038. PTHREADCONTEXT
  1039. DebugEventToThreadContext(
  1040.     PDEBUGPACKET dp,
  1041.     LPDEBUG_EVENT de
  1042.     )
  1043. {
  1044.     PTHREADCONTEXT ptctx;
  1045.     PLIST_ENTRY List = dp->ThreadList.Flink;
  1046.  
  1047.     while (List != &dp->ThreadList) {
  1048.         ptctx = CONTAINING_RECORD(List, THREADCONTEXT, ThreadList);
  1049.         List = List->Flink;
  1050.         if (ptctx->dwThreadId == de->dwThreadId) {
  1051.             return ptctx;
  1052.         }
  1053.     }
  1054.     return NULL;
  1055. }
  1056.  
  1057. void
  1058. SkipOverBreakpoint(
  1059.     PDEBUGPACKET dp,
  1060.     LPDEBUG_EVENT de
  1061.     )
  1062. {
  1063.     PTHREADCONTEXT ptctx;
  1064.     CONTEXT Context;
  1065.  
  1066.     ptctx = DebugEventToThreadContext(dp, de);
  1067.     Context.ContextFlags = CONTEXT_FULL;
  1068.     GetThreadContext(ptctx->hThread, &Context);
  1069.     PC(&Context) = (DWORD) de->u.Exception.ExceptionRecord.ExceptionAddress + BP_SIZE;
  1070.     SetThreadContext(ptctx->hThread, &Context);
  1071. }
  1072.