home *** CD-ROM | disk | FTP | other *** search
- //=================================
- // Coroner, by Matt Pietrek, 1992
- // File: XCPTREPT.C
- //=================================
-
- #include <windows.h>
- #include <stdarg.h>
- #include <string.h>
- #include <stdio.h>
- #include <alloc.h>
- #include <time.h>
- #include <dos.h>
-
- #include "toolhelp.h"
- #include "coroner.h"
-
- unsigned int Output(char *format, ... );
- void DoReportLineFeed(void);
- void GetDateTimeString(char *s);
-
- extern HANDLE HCoronerWnd;
- extern char LogFileName[];
- extern char ExceptionTaskName[];
-
- int HReportFile=-1;
- char pszNull[] = "NULL";
-
- WORD Exception_AX, Exception_BX, Exception_CX, Exception_DX;
- WORD Exception_SI, Exception_DI;
- WORD Exception_SP, Exception_BP, Exception_IP, Exception_FLAGS;
- WORD Exception_CS, Exception_DS, Exception_ES, Exception_SS;
-
- char *DescriptorTypes[] =
- {
- "read-only", "read/write",
- "read-only, expand-down", "read/write, expand-down",
- "execute-only", "execute/read",
- "execute-only, conforming", "execute/read-only, conforming"
- };
-
-
- int GetLogicalSegmentFromSelector(WORD selector, char *name, WORD *lseg)
- {
- GLOBALENTRY ge;
- MODULEENTRY me;
-
- name[0] = 0;
- *lseg = 0;
-
- ge.dwSize = sizeof(ge);
-
- if ( GlobalEntryHandle(&ge, (HANDLE)selector) == 0 )
- return 0;
-
- if ( ge.wType != GT_CODE ) // Logical segments are only valid for
- return 0; // code segments
-
- me.dwSize = sizeof(me);
-
- if ( ModuleFindHandle(&me, ge.hOwner) == 0 )
- return 0;
-
- strcpy(name, me.szModule);
- *lseg = ge.wData;
-
- return 1;
- }
-
- void DoWhatHappenedReport(int wNumber)
- {
- char moduleName[13];
- WORD lseg;
- TASKENTRY te;
-
- if ( GetLogicalSegmentFromSelector(Exception_CS, moduleName, &lseg) == 0 )
- {
- Output("Exception %u at unknown address\r\n", wNumber);
- }
- else
- {
- Output
- (
- "Exception %u at %s %04X:%04X (%04X:%04X)",
- wNumber, moduleName, Exception_CS, Exception_IP,
- lseg, Exception_IP
- );
- }
-
- te.dwSize = sizeof(te);
-
- if ( TaskFindHandle(&te, GetCurrentTask()) )
- {
- Output(" (TASK=%s)", te.szModule);
- strcpy(ExceptionTaskName, te.szModule);
- }
-
- DoReportLineFeed();
- DoReportLineFeed();
- }
-
- void DoStackTraceReport(void)
- {
- char moduleName[13];
- WORD lseg;
- STACKTRACEENTRY ste;
- BOOL ok;
- WORD stackframe_id = 0; // Keeps track of the current frame in the trace
-
- Output("Stack Trace:\r\n");
-
- ste.dwSize = sizeof(ste);
-
- ok = StackTraceCSIPFirst
- (
- &ste,
- Exception_SS, Exception_CS,
- Exception_IP, Exception_BP
- );
-
- while ( ok )
- {
- GetLogicalSegmentFromSelector(ste.wCS, moduleName, &lseg);
-
- Output
- (
- "%-2u %-8s CS:IP %04X:%04X (%04X:%04X) SS:BP %04X:%04X\r\n",
- stackframe_id++, moduleName, ste.wCS, ste.wIP, lseg, ste.wIP,
- ste.wSS, ste.wBP
- );
-
- ok = StackTraceNext(&ste);
- }
-
- DoReportLineFeed();
- }
-
- void DoRegisterReport(void)
- {
- WORD CSlimit, DSlimit, ESlimit, SSlimit;
- WORD CSrights, DSrights, ESrights, SSrights;
- Output("Registers:\r\n");
-
- Output("AX %04X\r\n", Exception_AX);
- Output("BX %04X\r\n", Exception_BX);
- Output("CX %04X\r\n", Exception_CX);
- Output("DX %04X\r\n", Exception_DX);
- Output("SI %04X\r\n", Exception_SI);
- Output("DI %04X\r\n", Exception_DI);
- Output("SP %04X\r\n", Exception_SP);
- Output("BP %04X\r\n", Exception_BP);
- Output("IP %04X\r\n", Exception_IP);
- Output("FL %04X\r\n", Exception_FLAGS);
-
-
- asm {
- xor ax, ax
- lsl ax, word ptr (Exception_CS)
- mov CSlimit, ax
- lar ax, word ptr (Exception_CS);
- shr ax, 9 // Put the type field, minus the "accessed" bit
- and al, 07h // in the low bits of AX, and mask them off.
- mov CSrights, ax
-
- xor ax, ax
- lsl ax, word ptr (Exception_DS)
- mov DSlimit, ax
- lar ax, word ptr (Exception_DS);
- shr ax, 9
- and al, 07h
- mov DSrights, ax
-
- xor ax, ax
- lsl ax, word ptr (Exception_ES)
- mov ESlimit, ax
- lar ax, word ptr (Exception_ES);
- shr ax, 9
- and al, 07h
- mov ESrights, ax
-
- xor ax, ax
- lsl ax, word ptr (Exception_SS)
- mov SSlimit, ax
- lar ax, word ptr (Exception_SS);
- shr ax, 9
- and al, 07h
- mov SSrights, ax
- }
-
- Output("CS %04X Limit: %04X %s\r\n",
- Exception_CS, CSlimit, DescriptorTypes[CSrights] );
-
- Output("DS %04X Limit: %04X %s\r\n",
- Exception_DS, DSlimit,
- Exception_DS ? DescriptorTypes[DSrights] : pszNull );
-
- Output("ES %04X Limit: %04X %s\r\n",
- Exception_ES, ESlimit,
- Exception_ES ? DescriptorTypes[ESrights] : pszNull );
-
- Output("SS %04X Limit: %04X %s\r\n",
- Exception_SS, SSlimit, DescriptorTypes[SSrights] );
-
- DoReportLineFeed();
- }
-
- void DoTaskReport(void)
- {
- char fileName[MAX_PATH_LENGTH];
- TASKENTRY te;
- BOOL ok;
-
- Output("Tasks:\r\n");
-
- te.dwSize = sizeof(te);
-
- ok = TaskFirst(&te);
-
- while ( ok )
- {
- GetModuleFileName(te.hModule, fileName, sizeof(fileName));
- Output("%s\r\n", fileName);
-
- Output(
- " Module: %-8s hModule: %04X hTask: %04X hInstance: %04X\r\n",
- te.szModule, te.hModule, te.hTask, te.hInst );
-
- ok = TaskNext(&te);
- }
-
- DoReportLineFeed();
- }
-
- void DoModuleReport(void)
- {
- MODULEENTRY me;
- BOOL ok;
-
- Output("Modules:\r\n");
-
- me.dwSize = sizeof(me);
-
- ok = ModuleFirst(&me);
-
- while ( ok )
- {
- Output("%s\r\n", me.szExePath );
-
- Output
- (
- " Module: %-8s hModule: %04X reference count: %u\r\n",
- me.szModule, me.hModule, me.wcUsage
- );
-
- ok = ModuleNext(&me);
- }
-
- DoReportLineFeed();
- }
-
- void DoHeapsInfoReport(void)
- {
- SYSHEAPINFO sysHeapInfo;
- BOOL ok;
-
- Output("Heaps:\r\n");
-
- sysHeapInfo.dwSize = sizeof(sysHeapInfo);
-
- ok = SystemHeapInfo(&sysHeapInfo);
-
- if ( !ok )
- return;
-
- Output("USER Free %3u%%\r\n", sysHeapInfo.wUserFreePercent );
- Output("GDI Free %3u%%\r\n", sysHeapInfo.wGDIFreePercent );
-
- DoReportLineFeed();
- }
-
- void DoWindowsInfoReport(void)
- {
- DWORD winFlags;
- WORD version;
- MEMMANINFO mmi;
- BOOL ok;
- char *cpuName;
-
- winFlags = GetWinFlags();
- version = GetVersion();
-
- Output("System info:\r\n");
-
- Output("Running in %s mode under Windows %d.%d %s version\r\n",
- (winFlags & WF_STANDARD) ? "standard" : "enhanced",
- LOBYTE(version), HIBYTE(version),
- GetSystemMetrics(SM_DEBUG) ? "debug" : "retail" );
-
-
- if ( winFlags & WF_CPU486 )
- cpuName = "80486";
- else if ( winFlags & WF_CPU386 )
- cpuName = "80386";
- else if ( winFlags & WF_CPU286 )
- cpuName = "80286";
- else
- cpuName = "Unknown";
-
- Output("CPU: %s\r\n", cpuName);
-
- if ( winFlags & WF_STANDARD ) // MemManInfo is useless for standard mode
- return;
-
- mmi.dwSize = sizeof(mmi);
-
- ok = MemManInfo(&mmi);
-
- if ( !ok )
- return;
-
- // Output select fields from the MEMMANINFO structure
-
- Output("Largest Free memory block: %lu bytes\r\n",
- mmi.dwLargestFreeBlock);
-
- Output("Total linear memory space: %-5lu K\r\n",
- mmi.dwTotalLinearSpace * (mmi.wPageSize/1024) );
-
- Output("Free linear memory space : %-5lu K\r\n",
- mmi.dwFreeLinearSpace * (mmi.wPageSize/1024) );
-
- Output("Swap file Pages: %lx (%lu K)\r\n",
- mmi.dwSwapFilePages, mmi.dwSwapFilePages * (mmi.wPageSize/1024) );
- }
-
- void GetDateTimeString(char *s)
- {
- struct date mydate;
- struct time mytime;
-
- getdate(&mydate);
- gettime(&mytime);
-
- sprintf(s, "%u/%02u/%u %02u:%02u:%02u",
- mydate.da_mon, mydate.da_day, mydate.da_year,
- mytime.ti_hour, mytime.ti_min, mytime.ti_sec
- );
- }
-
- unsigned int Output(char *format, ... )
- {
- static char mybuff[512];
- va_list argptr;
- unsigned len;
-
- if ( HReportFile == -1 )
- return 0;
-
- va_start( argptr, format ); /* Open the output list format */
- len = vsprintf(mybuff, format, argptr);
- va_end( argptr ); /* Close the output list */
-
- if ( len == 0)
- return 0;
-
- len = _lwrite(HReportFile, mybuff, len);
-
- return len;
- }
-
- int OpenReportFile(void)
- {
- HReportFile = _lopen(LogFileName, OF_WRITE);
-
- if ( HReportFile != -1 )
- {
- _llseek(HReportFile, 0, 2);
- return HReportFile;
- }
-
- // We couldn't open the file. It may not exist. Try creating it.
- HReportFile = _lcreat(LogFileName, 0);
-
- if ( HReportFile == -1 )
- return 0;
-
- return 1;
- }
-
- void CloseReportFile(void)
- {
- if ( HReportFile != -1 )
- {
- _lclose(HReportFile);
- HReportFile = -1;
- }
- }
-
- void DoReportLineFeed(void)
- {
- Output("\r\n");
- }
-
- void DoReportHeader(void)
- {
- char buffer[80];
-
- Output("\r\n~~~~~~~~~~\r\n");
-
- GetDateTimeString(buffer);
- Output("Coroner exception report - %s\r\n", buffer );
- }
-
- int PrepareForReport(void)
- {
- int ok;
-
- ExceptionTaskName[0] = 0; // Null out the task name string
-
- ok = OpenReportFile();
-
- if ( ok )
- return 1;
-
- // If we get here, we couldn't open the report file. Maybe there wasn't
- // an available file handle in the task that blew up. Remember, we're
- // not running as the CORONER. So, let's try closing STDPRN to try to
- // free up file handles, and then try again.
-
- _lclose(4);
-
- ok = OpenReportFile();
-
- return ok;
- }
-
- void DoExceptionReport(int wNumber)
- {
- if ( !PrepareForReport() )
- {
- PostMessage(HCoronerWnd, WM_CORONER_FILEOPEN_ERROR, 0, 0);
- return;
- }
-
- DoReportHeader();
-
- DoWhatHappenedReport( wNumber);
-
- DoStackTraceReport();
-
- DoRegisterReport();
-
- DoTaskReport();
-
- DoModuleReport();
-
- DoHeapsInfoReport();
-
- DoWindowsInfoReport();
-
- CloseReportFile();
-
- // Post a message to the CORONER window, so it can display the
- // exception message.
-
- PostMessage(HCoronerWnd, WM_CORONER_EXCEPTION, wNumber, 0);
- }
-
- char *tempstack; // Pointer to temporary working stack
- WORD tempstack_end; // offset of the end of the temporary stack
-
- WORD old_ss; // A place to save the SS:SP that we came in on.
- WORD old_sp;
-
- WORD exception_number;
-
- void C_ExceptionHandler(
- WORD wES,
- WORD wDS,
- WORD wDI,
- WORD wSI,
- WORD wBP,
- WORD wSP,
- WORD wBX,
- WORD wDX,
- WORD wCX,
- WORD wAX,
- WORD wOldBP,
- WORD wRetIP,
- WORD wRetCS,
- WORD wRealAX,
- WORD wNumber,
- WORD wHandle,
- WORD wIP,
- WORD wCS,
- WORD wFlags)
- {
- // Flag that tells us if we're already processing an interrupt/exception
- static WORD inHandler = 0;
-
- // Pass on the debugger interrupts. We don't care about them.
-
- if ( (wNumber == 1) || (wNumber == 3) )
- return;
-
- /* See if we're already here. If so, chain on */
-
- if (inHandler)
- return;
- else
- inHandler = 1;
-
- // Save off all of the parameters that we care about. We're going to
- // be switching stacks, so they won't be available.
-
- exception_number = wNumber;
-
- Exception_AX = wRealAX;
- Exception_BX = wBX;
- Exception_CX = wCX;
- Exception_DX = wDX;
- Exception_SI = wSI;
- Exception_DI = wDI;
- Exception_BP = wOldBP;
- Exception_IP = wIP;
- Exception_FLAGS = wFlags;
- Exception_CS = wCS;
- Exception_DS = wDS;
- Exception_ES = wES;
-
- asm mov [Exception_SS],ss
- asm lea ax, [wES + 26h] // calculate SP at time of exception
- asm mov [Exception_SP],ax
-
- // We're now going to switch the stack over to the temporary 4K stack
- // we allocated before we called InterruptRegister
-
- asm {
- mov [old_ss], ss
- mov [old_sp], sp
-
- mov ax, ds
- mov ss, ax
- mov sp, [tempstack_end]
- }
-
- DoExceptionReport(exception_number);
-
- // Switch the stack back to the original stack
-
- asm {
- mov ss, [old_ss]
- mov sp, [old_sp]
- }
-
- inHandler = 0;
-
- // Return to .ASM handler, which will chain on to the other installed
- // handlers. If none of them handle it, Windows will kill the task for us.
-
- return;
- }
-
- #define TEMPSTACK_SIZE 4096
-
- BOOL SetupInterruptHandler(void)
- {
- tempstack = malloc(TEMPSTACK_SIZE);
-
- if ( !tempstack )
- return 0;
-
- tempstack_end = (WORD)((tempstack + TEMPSTACK_SIZE) - 2);
-
- return InterruptRegister(NULL, (LPFNINTCALLBACK)EXCEPTIONHANDLER);
- }
-
- void ShutdownInterruptHandler(void)
- {
- InterruptUnRegister(NULL);
-
- if ( tempstack )
- free(tempstack);
- }
-
-