home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l430 / 1.ddi / CHAP10.ZIP / XCPTREPT.C < prev   
Encoding:
C/C++ Source or Header  |  1992-01-05  |  13.5 KB  |  585 lines

  1. //=================================
  2. // Coroner, by Matt Pietrek, 1992
  3. // File: XCPTREPT.C
  4. //=================================
  5.  
  6. #include <windows.h>
  7. #include <stdarg.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <alloc.h>
  11. #include <time.h>
  12. #include <dos.h>
  13.  
  14. #include "toolhelp.h"
  15. #include "coroner.h"
  16.  
  17. unsigned int Output(char *format, ... );
  18. void DoReportLineFeed(void);
  19. void GetDateTimeString(char *s);
  20.  
  21. extern HANDLE HCoronerWnd;
  22. extern char LogFileName[];
  23. extern char ExceptionTaskName[];
  24.  
  25. int  HReportFile=-1;
  26. char pszNull[] = "NULL";
  27.  
  28. WORD    Exception_AX, Exception_BX, Exception_CX, Exception_DX;
  29. WORD    Exception_SI, Exception_DI;
  30. WORD    Exception_SP, Exception_BP, Exception_IP, Exception_FLAGS;
  31. WORD    Exception_CS, Exception_DS, Exception_ES, Exception_SS;
  32.  
  33. char *DescriptorTypes[] =
  34. {
  35.     "read-only",                "read/write",
  36.     "read-only, expand-down",   "read/write, expand-down",
  37.     "execute-only",             "execute/read",
  38.     "execute-only, conforming", "execute/read-only, conforming"
  39. };
  40.  
  41.  
  42. int GetLogicalSegmentFromSelector(WORD selector, char *name, WORD *lseg)
  43. {
  44.     GLOBALENTRY ge;
  45.     MODULEENTRY me;
  46.  
  47.     name[0] = 0;
  48.     *lseg = 0;
  49.  
  50.     ge.dwSize = sizeof(ge);
  51.  
  52.     if ( GlobalEntryHandle(&ge, (HANDLE)selector) == 0 )
  53.         return 0;
  54.  
  55.     if ( ge.wType != GT_CODE )    // Logical segments are only valid for
  56.         return 0;                // code segments
  57.         
  58.     me.dwSize = sizeof(me);
  59.  
  60.     if ( ModuleFindHandle(&me, ge.hOwner) == 0 )
  61.         return 0;
  62.  
  63.     strcpy(name, me.szModule);
  64.     *lseg = ge.wData;
  65.  
  66.     return 1;
  67. }
  68.  
  69. void DoWhatHappenedReport(int wNumber)
  70. {
  71.     char moduleName[13];
  72.     WORD lseg;
  73.     TASKENTRY te;
  74.  
  75.     if ( GetLogicalSegmentFromSelector(Exception_CS, moduleName, &lseg) == 0 )
  76.     {
  77.         Output("Exception %u at unknown address\r\n", wNumber);
  78.     }
  79.     else
  80.     {
  81.         Output
  82.         (
  83.             "Exception %u at %s %04X:%04X (%04X:%04X)",
  84.             wNumber, moduleName, Exception_CS, Exception_IP,
  85.             lseg, Exception_IP
  86.         );
  87.     }
  88.  
  89.     te.dwSize = sizeof(te);
  90.  
  91.     if ( TaskFindHandle(&te, GetCurrentTask()) )
  92.     {
  93.         Output("  (TASK=%s)", te.szModule);
  94.         strcpy(ExceptionTaskName, te.szModule);
  95.     }
  96.  
  97.     DoReportLineFeed();
  98.     DoReportLineFeed();
  99. }
  100.  
  101. void DoStackTraceReport(void)
  102. {
  103.     char moduleName[13];
  104.     WORD lseg;
  105.     STACKTRACEENTRY ste;
  106.     BOOL ok;
  107.     WORD stackframe_id = 0; // Keeps track of the current frame in the trace
  108.  
  109.     Output("Stack Trace:\r\n");
  110.  
  111.     ste.dwSize = sizeof(ste);
  112.  
  113.     ok = StackTraceCSIPFirst
  114.         (
  115.             &ste,
  116.             Exception_SS, Exception_CS,
  117.             Exception_IP, Exception_BP
  118.         );
  119.  
  120.     while ( ok )
  121.     {
  122.         GetLogicalSegmentFromSelector(ste.wCS, moduleName, &lseg);
  123.  
  124.         Output
  125.         (
  126.             "%-2u %-8s  CS:IP %04X:%04X (%04X:%04X)  SS:BP %04X:%04X\r\n",
  127.             stackframe_id++, moduleName, ste.wCS, ste.wIP, lseg, ste.wIP,
  128.             ste.wSS, ste.wBP
  129.         );
  130.  
  131.         ok = StackTraceNext(&ste);
  132.     }
  133.  
  134.     DoReportLineFeed();
  135. }
  136.  
  137. void DoRegisterReport(void)
  138. {
  139.     WORD CSlimit, DSlimit, ESlimit, SSlimit;
  140.     WORD CSrights, DSrights, ESrights, SSrights;
  141.     Output("Registers:\r\n");
  142.  
  143.     Output("AX  %04X\r\n", Exception_AX);
  144.     Output("BX  %04X\r\n", Exception_BX);
  145.     Output("CX  %04X\r\n", Exception_CX);
  146.     Output("DX  %04X\r\n", Exception_DX);
  147.     Output("SI  %04X\r\n", Exception_SI);
  148.     Output("DI  %04X\r\n", Exception_DI);
  149.     Output("SP  %04X\r\n", Exception_SP);
  150.     Output("BP  %04X\r\n", Exception_BP);
  151.     Output("IP  %04X\r\n", Exception_IP);
  152.     Output("FL  %04X\r\n", Exception_FLAGS);
  153.  
  154.  
  155.     asm {
  156.             xor     ax, ax
  157.             lsl     ax, word ptr (Exception_CS)
  158.             mov     CSlimit, ax
  159.             lar     ax, word ptr (Exception_CS);
  160.             shr     ax, 9       // Put the type field, minus the "accessed" bit
  161.             and     al, 07h     // in the low bits of AX, and mask them off.
  162.             mov     CSrights, ax
  163.  
  164.             xor     ax, ax
  165.             lsl     ax, word ptr (Exception_DS)
  166.             mov     DSlimit, ax
  167.             lar     ax, word ptr (Exception_DS);
  168.             shr     ax, 9
  169.             and     al, 07h
  170.             mov     DSrights, ax
  171.  
  172.             xor     ax, ax
  173.             lsl     ax, word ptr (Exception_ES)
  174.             mov     ESlimit, ax
  175.             lar     ax, word ptr (Exception_ES);
  176.             shr     ax, 9
  177.             and     al, 07h
  178.             mov     ESrights, ax
  179.  
  180.             xor     ax, ax
  181.             lsl     ax, word ptr (Exception_SS)
  182.             mov     SSlimit, ax
  183.             lar     ax, word ptr (Exception_SS);
  184.             shr     ax, 9
  185.             and     al, 07h
  186.             mov     SSrights, ax
  187.         }
  188.  
  189.     Output("CS  %04X  Limit: %04X  %s\r\n",
  190.             Exception_CS, CSlimit, DescriptorTypes[CSrights] );
  191.  
  192.     Output("DS  %04X  Limit: %04X  %s\r\n",
  193.             Exception_DS, DSlimit,
  194.             Exception_DS ? DescriptorTypes[DSrights] : pszNull );
  195.  
  196.     Output("ES  %04X  Limit: %04X  %s\r\n",
  197.             Exception_ES, ESlimit,
  198.             Exception_ES ? DescriptorTypes[ESrights] : pszNull );
  199.  
  200.     Output("SS  %04X  Limit: %04X  %s\r\n",
  201.             Exception_SS, SSlimit, DescriptorTypes[SSrights] );
  202.  
  203.     DoReportLineFeed();
  204. }
  205.  
  206. void DoTaskReport(void)
  207. {
  208.     char fileName[MAX_PATH_LENGTH];
  209.     TASKENTRY te;
  210.     BOOL ok;
  211.  
  212.     Output("Tasks:\r\n");
  213.  
  214.     te.dwSize = sizeof(te);
  215.  
  216.     ok = TaskFirst(&te);
  217.  
  218.     while ( ok )
  219.     {
  220.         GetModuleFileName(te.hModule, fileName, sizeof(fileName));
  221.         Output("%s\r\n", fileName);
  222.  
  223.         Output(
  224.             "    Module: %-8s  hModule: %04X  hTask: %04X  hInstance: %04X\r\n",
  225.             te.szModule, te.hModule, te.hTask, te.hInst );
  226.  
  227.         ok = TaskNext(&te);
  228.     }
  229.  
  230.     DoReportLineFeed();
  231. }
  232.  
  233. void DoModuleReport(void)
  234. {
  235.     MODULEENTRY me;
  236.     BOOL ok;
  237.  
  238.     Output("Modules:\r\n");
  239.  
  240.     me.dwSize = sizeof(me);
  241.  
  242.     ok = ModuleFirst(&me);
  243.  
  244.     while ( ok )
  245.     {
  246.         Output("%s\r\n", me.szExePath );
  247.  
  248.         Output
  249.         (
  250.             "    Module: %-8s  hModule: %04X  reference count: %u\r\n",
  251.             me.szModule, me.hModule, me.wcUsage
  252.         );
  253.  
  254.         ok = ModuleNext(&me);
  255.     }
  256.  
  257.     DoReportLineFeed();
  258. }
  259.  
  260. void DoHeapsInfoReport(void)
  261. {
  262.     SYSHEAPINFO sysHeapInfo;
  263.     BOOL ok;
  264.  
  265.     Output("Heaps:\r\n");
  266.     
  267.     sysHeapInfo.dwSize = sizeof(sysHeapInfo);
  268.  
  269.     ok = SystemHeapInfo(&sysHeapInfo);
  270.  
  271.     if ( !ok )
  272.         return;
  273.  
  274.     Output("USER  Free %3u%%\r\n", sysHeapInfo.wUserFreePercent );
  275.     Output("GDI   Free %3u%%\r\n", sysHeapInfo.wGDIFreePercent );
  276.  
  277.     DoReportLineFeed();
  278. }
  279.  
  280. void DoWindowsInfoReport(void)
  281. {
  282.     DWORD winFlags;
  283.     WORD  version;
  284.     MEMMANINFO mmi;
  285.     BOOL ok;
  286.     char *cpuName;
  287.  
  288.     winFlags = GetWinFlags();
  289.     version = GetVersion();
  290.  
  291.     Output("System info:\r\n");
  292.  
  293.     Output("Running in %s mode under Windows %d.%d %s version\r\n",
  294.         (winFlags & WF_STANDARD) ? "standard" : "enhanced",
  295.         LOBYTE(version), HIBYTE(version),
  296.         GetSystemMetrics(SM_DEBUG) ? "debug" : "retail" );
  297.  
  298.  
  299.     if ( winFlags & WF_CPU486 )
  300.         cpuName = "80486";
  301.     else if ( winFlags & WF_CPU386 )
  302.         cpuName = "80386";
  303.     else if ( winFlags & WF_CPU286 )
  304.         cpuName = "80286";
  305.     else
  306.         cpuName = "Unknown";
  307.  
  308.     Output("CPU: %s\r\n", cpuName);
  309.  
  310.     if ( winFlags & WF_STANDARD )   // MemManInfo is useless for standard mode
  311.         return;
  312.  
  313.     mmi.dwSize = sizeof(mmi);
  314.  
  315.     ok = MemManInfo(&mmi);
  316.  
  317.     if ( !ok )
  318.         return;
  319.  
  320.     // Output select fields from the MEMMANINFO structure
  321.  
  322.     Output("Largest Free memory block: %lu bytes\r\n",
  323.             mmi.dwLargestFreeBlock);
  324.  
  325.     Output("Total linear memory space: %-5lu K\r\n",
  326.             mmi.dwTotalLinearSpace * (mmi.wPageSize/1024) );
  327.  
  328.     Output("Free linear memory space : %-5lu K\r\n",
  329.             mmi.dwFreeLinearSpace * (mmi.wPageSize/1024) );
  330.  
  331.     Output("Swap file Pages: %lx (%lu K)\r\n",
  332.             mmi.dwSwapFilePages, mmi.dwSwapFilePages * (mmi.wPageSize/1024) );
  333. }
  334.  
  335. void GetDateTimeString(char *s)
  336. {
  337.     struct date mydate;
  338.     struct time mytime;
  339.  
  340.     getdate(&mydate);
  341.     gettime(&mytime);
  342.  
  343.     sprintf(s, "%u/%02u/%u  %02u:%02u:%02u",
  344.             mydate.da_mon, mydate.da_day, mydate.da_year,
  345.             mytime.ti_hour, mytime.ti_min, mytime.ti_sec
  346.             );
  347. }
  348.  
  349. unsigned int Output(char *format, ... )
  350. {
  351.     static char mybuff[512];
  352.     va_list argptr;
  353.     unsigned len;
  354.  
  355.     if ( HReportFile == -1 )
  356.         return 0;
  357.  
  358.     va_start( argptr, format );     /* Open the output list format  */
  359.     len = vsprintf(mybuff, format, argptr);
  360.     va_end( argptr );           /* Close the output list    */
  361.  
  362.     if ( len == 0)
  363.         return 0;
  364.  
  365.     len = _lwrite(HReportFile, mybuff, len);
  366.  
  367.     return len;
  368. }
  369.  
  370. int OpenReportFile(void)
  371. {
  372.     HReportFile = _lopen(LogFileName, OF_WRITE);
  373.  
  374.     if ( HReportFile != -1 )
  375.     {
  376.         _llseek(HReportFile, 0, 2);
  377.         return HReportFile;
  378.     }
  379.  
  380.     // We couldn't open the file.  It may not exist.  Try creating it.
  381.     HReportFile = _lcreat(LogFileName, 0);
  382.  
  383.     if ( HReportFile == -1 )
  384.         return 0;
  385.  
  386.     return 1;
  387. }
  388.  
  389. void CloseReportFile(void)
  390. {
  391.     if ( HReportFile != -1 )
  392.     {
  393.         _lclose(HReportFile);
  394.         HReportFile = -1;
  395.     }
  396. }
  397.  
  398. void DoReportLineFeed(void)
  399. {
  400.     Output("\r\n");
  401. }
  402.  
  403. void DoReportHeader(void)
  404. {
  405.     char buffer[80];
  406.  
  407.     Output("\r\n~~~~~~~~~~\r\n");
  408.  
  409.     GetDateTimeString(buffer);
  410.     Output("Coroner exception report - %s\r\n", buffer );
  411. }
  412.  
  413. int PrepareForReport(void)
  414. {
  415.     int ok;
  416.  
  417.     ExceptionTaskName[0] = 0;   // Null out the task name string
  418.  
  419.     ok = OpenReportFile();
  420.  
  421.     if ( ok )
  422.         return 1;
  423.  
  424.     // If we get here, we couldn't open the report file.  Maybe there wasn't
  425.     // an available file handle in the task that blew up.  Remember, we're
  426.     // not running as the CORONER.  So, let's try closing STDPRN to try to
  427.     // free up file handles, and then try again.
  428.  
  429.     _lclose(4);
  430.  
  431.     ok = OpenReportFile();
  432.  
  433.     return ok;
  434. }
  435.  
  436. void DoExceptionReport(int wNumber)
  437. {
  438.     if ( !PrepareForReport() )
  439.     {
  440.         PostMessage(HCoronerWnd, WM_CORONER_FILEOPEN_ERROR, 0, 0);
  441.         return;
  442.     }
  443.  
  444.     DoReportHeader();
  445.  
  446.     DoWhatHappenedReport( wNumber);
  447.  
  448.     DoStackTraceReport();
  449.  
  450.     DoRegisterReport();
  451.  
  452.     DoTaskReport();
  453.  
  454.     DoModuleReport();
  455.  
  456.     DoHeapsInfoReport();
  457.  
  458.     DoWindowsInfoReport();
  459.  
  460.     CloseReportFile();
  461.  
  462.     // Post a message to the CORONER window, so it can display the
  463.     // exception message.
  464.         
  465.     PostMessage(HCoronerWnd, WM_CORONER_EXCEPTION, wNumber, 0);
  466. }
  467.  
  468. char *tempstack;        // Pointer to temporary working stack
  469. WORD tempstack_end;     // offset of the end of the temporary stack
  470.  
  471. WORD old_ss;            // A place to save the SS:SP that we came in on.
  472. WORD old_sp;
  473.  
  474. WORD exception_number;
  475.  
  476. void C_ExceptionHandler(
  477.     WORD wES,
  478.     WORD wDS,
  479.     WORD wDI,
  480.     WORD wSI,
  481.     WORD wBP,
  482.     WORD wSP,
  483.     WORD wBX,
  484.     WORD wDX,
  485.     WORD wCX,
  486.     WORD wAX,
  487.     WORD wOldBP,
  488.     WORD wRetIP,
  489.     WORD wRetCS,
  490.     WORD wRealAX,
  491.     WORD wNumber,
  492.     WORD wHandle,
  493.     WORD wIP,
  494.     WORD wCS,
  495.     WORD wFlags)
  496. {
  497.     // Flag that tells us if we're already processing an interrupt/exception
  498.     static WORD inHandler = 0;
  499.  
  500.     // Pass on the debugger interrupts.  We don't care about them.
  501.         
  502.     if ( (wNumber == 1) || (wNumber == 3) )
  503.         return;
  504.     
  505.     /* See if we're already here.  If so, chain on */
  506.     
  507.     if (inHandler)
  508.         return;
  509.     else
  510.         inHandler = 1;
  511.     
  512.     // Save off all of the parameters that we care about.  We're going to
  513.     // be switching stacks, so they won't be available.
  514.  
  515.     exception_number = wNumber;
  516.         
  517.     Exception_AX = wRealAX;
  518.     Exception_BX = wBX;
  519.     Exception_CX = wCX;
  520.     Exception_DX = wDX;
  521.     Exception_SI = wSI;
  522.     Exception_DI = wDI;
  523.     Exception_BP = wOldBP;
  524.     Exception_IP = wIP;
  525.     Exception_FLAGS = wFlags;
  526.     Exception_CS = wCS;
  527.     Exception_DS = wDS;
  528.     Exception_ES = wES;
  529.  
  530.     asm     mov     [Exception_SS],ss
  531.     asm     lea     ax, [wES + 26h]     // calculate SP at time of exception
  532.     asm     mov     [Exception_SP],ax
  533.  
  534.     // We're now going to switch the stack over to the temporary 4K stack
  535.     // we allocated before we called InterruptRegister
  536.         
  537.     asm {
  538.             mov     [old_ss], ss
  539.             mov     [old_sp], sp
  540.  
  541.             mov     ax, ds
  542.             mov     ss, ax
  543.             mov     sp, [tempstack_end]
  544.         }
  545.  
  546.     DoExceptionReport(exception_number);
  547.  
  548.     // Switch the stack back to the original stack
  549.         
  550.     asm {
  551.             mov     ss, [old_ss]
  552.             mov     sp, [old_sp]
  553.         }
  554.         
  555.     inHandler = 0;
  556.     
  557.     // Return to .ASM handler, which will chain on to the other installed
  558.     // handlers.  If none of them handle it, Windows will kill the task for us.
  559.         
  560.     return;
  561. }
  562.  
  563. #define TEMPSTACK_SIZE  4096
  564.  
  565. BOOL SetupInterruptHandler(void)
  566. {
  567.     tempstack = malloc(TEMPSTACK_SIZE);
  568.     
  569.     if ( !tempstack )
  570.         return 0;
  571.     
  572.     tempstack_end = (WORD)((tempstack + TEMPSTACK_SIZE) - 2);
  573.     
  574.     return InterruptRegister(NULL, (LPFNINTCALLBACK)EXCEPTIONHANDLER);
  575. }
  576.  
  577. void ShutdownInterruptHandler(void)
  578. {
  579.     InterruptUnRegister(NULL);
  580.     
  581.     if ( tempstack )
  582.         free(tempstack);
  583. }
  584.  
  585.