1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: win_dbg.c 1257 2016-09-20 17:14:21Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2016 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: win_dbg.c,v $
20 // Revision 1.8 2001/01/25 22:15:45 bpereira
21 // added heretic support
22 //
23 // Revision 1.7 2000/09/28 20:57:22 bpereira
24 // Revision 1.6 2000/09/01 19:34:38 bpereira
25 // Revision 1.5 2000/08/03 17:57:42 bpereira
26 // Revision 1.4 2000/04/24 20:24:39 bpereira
27 // Revision 1.3 2000/04/16 18:38:07 bpereira
28 // Revision 1.2 2000/02/27 00:42:12 hurdler
29 // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
30 // Initial import into CVS (v1.29 pr3)
31 //
32 //
33 // DESCRIPTION:
34 // this source file contains the exception handler for recording error
35 // information after crashes.
36 // Sources from GameDeveloper magazine article, January 1998, by Bruce Dawson.
37 //
38 //-----------------------------------------------------------------------------
39
40 // Because of WINVER redefine, doomtype.h (via doomincl.h) is before any
41 // other include that might define WINVER
42 #include "doomincl.h"
43 // VERSION
44
45 #include "win_dbg.h"
46 #include "win_main.h"
47
48 #include "m_argv.h" //print the parameter in the log
49
50 #define NumCodeBytes 16 // Number of code bytes to record.
51 #define MaxStackDump 2048 // Maximum number of DWORDS in stack dumps.
52 #define StackColumns 8 // Number of columns in stack dump.
53
54 #define ONEK 1024
55 #define SIXTYFOURK (64*ONEK)
56 #define ONEM (ONEK*ONEK)
57 #define ONEG (ONEK*ONEK*ONEK)
58
59
60 // --------------------------------------------------------------------------
61 // return a description for an ExceptionCode
62 // --------------------------------------------------------------------------
GetExceptionDescription(DWORD ExceptionCode)63 static char* GetExceptionDescription (DWORD ExceptionCode)
64 {
65 int i;
66
67 struct ExceptionNames
68 {
69 DWORD ExceptionCode;
70 char* ExceptionName;
71 };
72
73 struct ExceptionNames ExceptionMap[] =
74 {
75 {EXCEPTION_ACCESS_VIOLATION, "an Access Violation"},
76 {EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "a Array Bounds Exceeded"},
77 {EXCEPTION_BREAKPOINT, "a Breakpoint"},
78 {EXCEPTION_DATATYPE_MISALIGNMENT, "a Datatype Misalignment"},
79 {EXCEPTION_FLT_DENORMAL_OPERAND, "a Float Denormal Operand"},
80 {EXCEPTION_FLT_DIVIDE_BY_ZERO, "a Float Divide By Zero"},
81 {EXCEPTION_FLT_INEXACT_RESULT, "a Float Inexact Result"},
82 {EXCEPTION_FLT_INVALID_OPERATION, "a Float Invalid Operation"},
83 {EXCEPTION_FLT_OVERFLOW, "a Float Overflow"},
84 {EXCEPTION_FLT_STACK_CHECK, "a Float Stack Check"},
85 {EXCEPTION_FLT_UNDERFLOW, "a Float Underflow"},
86 {EXCEPTION_ILLEGAL_INSTRUCTION, "an Illegal Instruction"},
87 {EXCEPTION_IN_PAGE_ERROR, "an In Page Error"},
88 {EXCEPTION_INT_DIVIDE_BY_ZERO, "an Integer Divide By Zero"},
89 {EXCEPTION_INT_OVERFLOW, "an Integer Overflow"},
90 {EXCEPTION_INVALID_DISPOSITION, "an Invalid Disposition"},
91 {EXCEPTION_NONCONTINUABLE_EXCEPTION, "Noncontinuable Exception"},
92 {EXCEPTION_PRIV_INSTRUCTION, "a Privileged Instruction"},
93 {EXCEPTION_SINGLE_STEP, "a Single Step"},
94 {EXCEPTION_STACK_OVERFLOW, "a Stack Overflow"},
95 {0x40010005, "a Control-C"},
96 {0x40010008, "a Control-Break"},
97 {0xc0000006, "an In Page Error"},
98 {0xc0000017, "a No Memory"},
99 {0xc000001d, "an Illegal Instruction"},
100 {0xc0000025, "a Noncontinuable Exception"},
101 {0xc0000142, "a DLL Initialization Failed"},
102 {0xe06d7363, "a Microsoft C++ Exception"},
103 };
104
105 for (i = 0; i < sizeof(ExceptionMap) / sizeof(ExceptionMap[0]); i++)
106 if (ExceptionCode == ExceptionMap[i].ExceptionCode)
107 return ExceptionMap[i].ExceptionName;
108
109 return "Unknown exception type";
110 }
111
112
113 // --------------------------------------------------------------------------
114 // Directly output a formatted string to the errorlog file, using win32 funcs
115 // --------------------------------------------------------------------------
FPrintf(HANDLE fileHandle,LPCTSTR lpFmt,...)116 void FPrintf (HANDLE fileHandle, LPCTSTR lpFmt, ...)
117 {
118 char str[1999];
119 va_list arglist;
120 DWORD bytesWritten;
121
122 va_start (arglist, lpFmt);
123 vsprintf (str, lpFmt, arglist);
124 va_end (arglist);
125
126 WriteFile (fileHandle, str, strlen(str), &bytesWritten, NULL);
127 }
128
129
130 // --------------------------------------------------------------------------
131 // Print the specified FILETIME to output in a human readable format,
132 // without using the C run time.
133 // --------------------------------------------------------------------------
PrintTime(char * output,FILETIME TimeToPrint)134 static void PrintTime (char *output, FILETIME TimeToPrint)
135 {
136 WORD Date, Time;
137 if (FileTimeToLocalFileTime (&TimeToPrint, &TimeToPrint) &&
138 FileTimeToDosDateTime (&TimeToPrint, &Date, &Time))
139 {
140 // What a silly way to print out the file date/time.
141 wsprintf( output, "%d/%d/%d %02d:%02d:%02d",
142 (Date / 32) & 15, Date & 31, (Date / 512) + 1980,
143 (Time / 2048), (Time / 32) & 63, (Time & 31) * 2);
144 }
145 else
146 output[0] = 0;
147 }
148
149
GetFilePart(char * source)150 static char* GetFilePart(char *source)
151 {
152 char *result = strrchr(source, '\\');
153 if (result)
154 result++;
155 else
156 result = source;
157 return result;
158 }
159
160
161 // --------------------------------------------------------------------------
162 // Print information about a code module (DLL or EXE) such as its size,
163 // location, time stamp, etc.
164 // --------------------------------------------------------------------------
ShowModuleInfo(HANDLE LogFile,HINSTANCE ModuleHandle)165 static void ShowModuleInfo(HANDLE LogFile, HINSTANCE ModuleHandle)
166 {
167 char ModName[MAX_PATH];
168 IMAGE_DOS_HEADER *DosHeader;
169 IMAGE_NT_HEADERS *NTHeader;
170 HANDLE ModuleFile;
171 char TimeBuffer[100] = "";
172 DWORD FileSize = 0;
173 __try
174 {
175 if (GetModuleFileName(ModuleHandle, ModName, sizeof(ModName)) > 0)
176 {
177 // If GetModuleFileName returns greater than zero then this must
178 // be a valid code module address. Therefore we can try to walk
179 // our way through its structures to find the link time stamp.
180 DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
181 if (IMAGE_DOS_SIGNATURE != DosHeader->e_magic)
182 return;
183 NTHeader = (IMAGE_NT_HEADERS*)((char *)DosHeader
184 + DosHeader->e_lfanew);
185 if (IMAGE_NT_SIGNATURE != NTHeader->Signature)
186 return;
187 // Open the code module file so that we can get its file date
188 // and size.
189 ModuleFile = CreateFile(ModName, GENERIC_READ,
190 FILE_SHARE_READ, 0, OPEN_EXISTING,
191 FILE_ATTRIBUTE_NORMAL, 0);
192 if (ModuleFile != INVALID_HANDLE_VALUE)
193 {
194 FILETIME LastWriteTime;
195 FileSize = GetFileSize(ModuleFile, 0);
196 if (GetFileTime(ModuleFile, 0, 0, &LastWriteTime))
197 {
198 wsprintf(TimeBuffer, " - file date is ");
199 PrintTime(TimeBuffer + lstrlen(TimeBuffer), LastWriteTime);
200 }
201 CloseHandle(ModuleFile);
202 }
203 FPrintf (LogFile, "%s, loaded at 0x%08x - %d bytes - %08x%s\r\n",
204 ModName, ModuleHandle, FileSize,
205 NTHeader->FileHeader.TimeDateStamp, TimeBuffer);
206 }
207 }
208 // Handle any exceptions by continuing from this point.
209 __except(EXCEPTION_EXECUTE_HANDLER)
210 {
211 }
212 }
213
214 // --------------------------------------------------------------------------
215 // Scan memory looking for code modules (DLLs or EXEs). VirtualQuery is used
216 // to find all the blocks of address space that were reserved or committed,
217 // and ShowModuleInfo will display module information if they are code
218 // modules.
219 // --------------------------------------------------------------------------
RecordModuleList(HANDLE LogFile)220 static void RecordModuleList(HANDLE LogFile)
221 {
222 SYSTEM_INFO SystemInfo;
223 size_t PageSize;
224 size_t NumPages;
225 size_t pageNum = 0;
226 void *LastAllocationBase = 0;
227
228 FPrintf (LogFile, "\r\n"
229 "\tModule list: names, addresses, sizes, time stamps "
230 "and file times:\r\n");
231
232 // Set NumPages to the number of pages in the 4GByte address space,
233 // while being careful to avoid overflowing ints.
234 GetSystemInfo(&SystemInfo);
235 PageSize = SystemInfo.dwPageSize;
236 NumPages = 4 * (unsigned int)(ONEG / PageSize);
237 while (pageNum < NumPages)
238 {
239 MEMORY_BASIC_INFORMATION MemInfo;
240 if (VirtualQuery((void *)(pageNum * PageSize), &MemInfo,
241 sizeof(MemInfo)))
242 {
243 if (MemInfo.RegionSize > 0)
244 {
245 // Adjust the page number to skip over this block of memory.
246 pageNum += MemInfo.RegionSize / PageSize;
247 if (MemInfo.State == MEM_COMMIT && MemInfo.AllocationBase >
248 LastAllocationBase)
249 {
250 // Look for new blocks of committed memory, and try
251 // recording their module names - this will fail
252 // gracefully if they aren't code modules.
253 LastAllocationBase = MemInfo.AllocationBase;
254 ShowModuleInfo(LogFile, (HINSTANCE)LastAllocationBase);
255 }
256 }
257 else
258 pageNum += SIXTYFOURK / PageSize;
259 }
260 else
261 pageNum += SIXTYFOURK / PageSize;
262 // If VirtualQuery fails we advance by 64K because that is the
263 // granularity of address space doled out by VirtualAlloc().
264 }
265 }
266
267
268 // --------------------------------------------------------------------------
269 // Record information about the user's system, such as processor type, amount
270 // of memory, etc.
271 // --------------------------------------------------------------------------
RecordSystemInformation(HANDLE fileHandle)272 static void RecordSystemInformation(HANDLE fileHandle)
273 {
274 FILETIME CurrentTime;
275 char TimeBuffer[100];
276 char ModuleName[MAX_PATH];
277 char UserName[200];
278 DWORD UserNameSize;
279 SYSTEM_INFO SystemInfo;
280 MEMORYSTATUS MemInfo;
281
282 GetSystemTimeAsFileTime (&CurrentTime);
283 PrintTime (TimeBuffer, CurrentTime);
284 FPrintf(fileHandle, "Error occurred at %s.\r\n", TimeBuffer);
285
286 if (GetModuleFileName (NULL, ModuleName, sizeof(ModuleName)) <= 0)
287 lstrcpy (ModuleName, "Unknown");
288 UserNameSize = sizeof(UserName);
289 if (!GetUserName (UserName, &UserNameSize))
290 lstrcpy (UserName, "Unknown");
291 FPrintf(fileHandle, "%s, run by %s.\r\n", ModuleName, UserName);
292
293 GetSystemInfo (&SystemInfo);
294 FPrintf (fileHandle, "%d processor(s), type %d %d.%d.\r\n"
295 "Program Memory from 0x%p to 0x%p\r\n",
296 SystemInfo.dwNumberOfProcessors,
297 SystemInfo.dwProcessorType,
298 SystemInfo.wProcessorLevel,
299 SystemInfo.wProcessorRevision,
300 SystemInfo.lpMinimumApplicationAddress,
301 SystemInfo.lpMaximumApplicationAddress);
302
303 MemInfo.dwLength = sizeof(MemInfo);
304 GlobalMemoryStatus(&MemInfo);
305 // Print out the amount of physical memory, rounded up.
306 FPrintf(fileHandle, "%d MBytes physical memory.\r\n", (MemInfo.dwTotalPhys +
307 ONEM - 1) / ONEM);
308 }
309
310
311 // --------------------------------------------------------------------------
312 // What we do here is trivial : open a file, write out the register information
313 // from the PEXCEPTION_POINTERS structure, then return EXCEPTION_CONTINUE_SEARCH
314 // whose magic value tells Win32 to proceed with its normal error handling
315 // mechanism. This is important : an error dialog will popup if possible and
316 // the debugger will hopefully coexist peacefully with the structured exception
317 // handler.
318 // --------------------------------------------------------------------------
RecordExceptionInfo(PEXCEPTION_POINTERS data,const char * Message,LPSTR lpCmdLine)319 int __cdecl RecordExceptionInfo (PEXCEPTION_POINTERS data, const char *Message, LPSTR lpCmdLine)
320 {
321 PEXCEPTION_RECORD Exception = data->ExceptionRecord;
322 PCONTEXT Context = data->ContextRecord;
323 char ModuleName[MAX_PATH];
324 char FileName[MAX_PATH] = "Unknown";
325 char* FilePart, *lastperiod;
326 char CrashModulePathName[MAX_PATH];
327 char* CrashModuleFileName = "Unknown";
328 MEMORY_BASIC_INFORMATION MemInfo;
329 static int BeenHere=false;
330 HANDLE fileHandle;
331 unsigned char * code;
332 int codebyte,i;
333
334 if (BeenHere) // Going recursive! That must mean this routine crashed!
335 return EXCEPTION_CONTINUE_SEARCH;
336 BeenHere = true;
337
338 // Create a filename to record the error information to.
339 // Store it in the executable directory.
340 if (GetModuleFileName(NULL, ModuleName, sizeof(ModuleName)) <= 0)
341 ModuleName[0] = 0;
342 FilePart = GetFilePart(ModuleName);
343
344 // Extract the file name portion and remove it's file extension. We'll
345 // use that name shortly.
346 lstrcpy (FileName, FilePart);
347 lastperiod = strrchr (FileName, '.');
348 if (lastperiod)
349 lastperiod[0] = 0;
350 // Replace the executable filename with our error log file name.
351 lstrcpy (FilePart, "errorlog.txt");
352 fileHandle = CreateFile (ModuleName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
353 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
354 if (fileHandle == INVALID_HANDLE_VALUE)
355 {
356 OutputDebugString ("Error creating exception report");
357 return EXCEPTION_CONTINUE_SEARCH;
358 }
359
360 // Append to the error log.
361 SetFilePointer (fileHandle, 0, 0, FILE_END);
362
363 // Print out some blank lines to separate this error log from any previous ones.
364 FPrintf (fileHandle, "\r\n\r\n\r\n\r\n");
365 FPrintf (fileHandle, "%s -ERROR LOG-\r\n\r\n", VERSION_BANNER);
366 FPrintf (fileHandle, "Command Line parameters: ");
367 for (i = 1;i<myargc;i++)
368 FPrintf (fileHandle, "%s ", myargv[i] );
369
370 FPrintf (fileHandle, "\r\n");
371 // VirtualQuery can be used to get the allocation base associated with a
372 // code address, which is the same as the ModuleHandle. This can be used
373 // to get the filename of the module that the crash happened in.
374 if ( VirtualQuery ((void*)Context->Eip, &MemInfo, sizeof(MemInfo)) &&
375 GetModuleFileName ((HINSTANCE)MemInfo.AllocationBase,
376 CrashModulePathName,
377 sizeof(CrashModulePathName)) > 0)
378 CrashModuleFileName = GetFilePart(CrashModulePathName);
379
380 // Print out the beginning of the error log in a Win95 error window
381 // compatible format.
382 FPrintf (fileHandle, "%s caused an %s in module %s at %04x:%08x.\r\n",
383 FileName, GetExceptionDescription(Exception->ExceptionCode),
384 CrashModuleFileName, Context->SegCs, Context->Eip);
385 FPrintf (fileHandle, "Exception handler called in %s.\r\n", Message);
386
387 RecordSystemInformation (fileHandle);
388
389 // If the exception was an access violation, print out some additional
390 // information, to the error log and the debugger.
391 if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION &&
392 Exception->NumberParameters >= 2)
393 {
394 char DebugMessage[1000];
395 const char* readwrite = "Read from";
396 if (Exception->ExceptionInformation[0])
397 readwrite = "Write to";
398 wsprintf(DebugMessage, "%s location %08x caused an access violation.\r\n",
399 readwrite, Exception->ExceptionInformation[1]);
400 #ifdef _DEBUG
401 // The VisualC++ debugger doesn't actually tell you whether a read
402 // or a write caused the access violation, nor does it tell what
403 // address was being read or written. So I fixed that.
404 OutputDebugString("Exception handler: ");
405 OutputDebugString(DebugMessage);
406 #endif
407 FPrintf(fileHandle, "%s", DebugMessage);
408 }
409
410 FPrintf(fileHandle, "\r\n");
411
412 // Print out the register values in a Win95 error window compatible format.
413 if ((Context->ContextFlags & CONTEXT_FULL) == CONTEXT_FULL)
414 {
415 FPrintf (fileHandle, "Registers:\r\n");
416 FPrintf (fileHandle, "EAX=%.8lx CS=%.4x EIP=%.8lx EFLGS=%.8lx\r\n",
417 Context->Eax,Context->SegCs,Context->Eip,Context->EFlags);
418 FPrintf (fileHandle, "EBX=%.8lx SS=%.4x ESP=%.8lx EBP=%.8lx\r\n",
419 Context->Ebx,Context->SegSs,Context->Esp,Context->Ebp);
420 FPrintf (fileHandle, "ECX=%.8lx DS=%.4x ESI=%.8lx FS=%.4x\r\n",
421 Context->Ecx,Context->SegDs,Context->Esi,Context->SegFs);
422 FPrintf (fileHandle, "EDX=%.8lx ES=%.4x EDI=%.8lx GS=%.4x\r\n",
423 Context->Edx,Context->SegEs,Context->Edi,Context->SegGs);
424 }
425
426 FPrintf (fileHandle, "Bytes at CS:EIP:\r\n");
427
428 // Print out the bytes of code at the instruction pointer. Since the
429 // crash may have been caused by an instruction pointer that was bad,
430 // this code needs to be wrapped in an exception handler, in case there
431 // is no memory to read. If the dereferencing of code[] fails, the
432 // exception handler will print '??'.
433 code = (unsigned char*)Context->Eip;
434 for (codebyte = 0; codebyte < NumCodeBytes; codebyte++)
435 {
436 __try
437 {
438 FPrintf (fileHandle, "%02x ", code[codebyte]);
439 }
440 __except(EXCEPTION_EXECUTE_HANDLER)
441 {
442 FPrintf (fileHandle, "?? ");
443 }
444 }
445
446 // Time to print part or all of the stack to the error log. This allows
447 // us to figure out the call stack, parameters, local variables, etc.
448 FPrintf (fileHandle, "\r\n"
449 "Stack dump:\r\n");
450 __try
451 {
452 // Esp contains the bottom of the stack, or at least the bottom of
453 // the currently used area.
454 DWORD* pStack = (DWORD *)Context->Esp;
455 DWORD* pStackTop;
456 int Count = 0;
457 char buffer[1000] = "";
458 const int safetyzone = 50;
459 char* nearend = buffer + sizeof(buffer) - safetyzone;
460 char* output = buffer;
461 char *Suffix;
462 __asm
463 {
464 // Load the top (highest address) of the stack from the
465 // thread information block. It will be found there in
466 // Win9x and Windows NT.
467 mov eax, fs:[4]
468 mov pStackTop, eax
469 }
470 if (pStackTop > pStack + MaxStackDump)
471 pStackTop = pStack + MaxStackDump;
472 // Too many calls to WriteFile can take a long time, causing
473 // confusing delays when programs crash. Therefore I implemented
474 // simple buffering for the stack dumping code instead of calling
475 // FPrintf directly.
476 while (pStack + 1 <= pStackTop)
477 {
478 if ((Count % StackColumns) == 0)
479 output += wsprintf(output, "%08x: ", pStack);
480 if ((++Count % StackColumns) == 0 || pStack + 2 > pStackTop)
481 Suffix = "\r\n";
482 else
483 Suffix = " ";
484 output += wsprintf(output, "%08x%s", *pStack, Suffix);
485 pStack++;
486 // Check for when the buffer is almost full, and flush it to disk.
487 if (output > nearend)
488 {
489 FPrintf (fileHandle, "%s", buffer);
490 buffer[0] = 0;
491 output = buffer;
492 }
493 }
494 // Print out any final characters from the cache.
495 FPrintf (fileHandle, "%s", buffer);
496 }
497 __except(EXCEPTION_EXECUTE_HANDLER)
498 {
499 FPrintf(fileHandle, "Exception encountered during stack dump.\r\n");
500 }
501
502 RecordModuleList (fileHandle);
503
504 CloseHandle (fileHandle);
505
506 // Return the magic value which tells Win32 that this handler didn't
507 // actually handle the exception - so that things will proceed as per
508 // normal.
509 //BP: should put message for end user to send this file to fix any bug
510 return EXCEPTION_CONTINUE_SEARCH;
511 }
512
513
514 /*
515 //
516 //FPrintf ("e-mail this file to legacy@newdoom.com , so that we can fix the problem.\r\n\r\n");
517
518 FPrintf ("Exception handler called in %s.\r\n", Message);
519
520 GetSystemTime (&systemTime);
521 FPrintf ("Error occured at %02d/%02d/%04d %02d:%02d:%02d.\r\n",
522 systemTime.wMonth, systemTime.wDay, systemTime.wYear,
523 systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
524
525
526 FPrintf ("%s\r\n", filename);
527 FPrintf ("Cmd-line: %s\r\n", lpCmdLine);
528
529 // Nested exceptions can occur, get info for each one
530
531 nER = 1;
532 while (ER)
533 {
534 if (nER++>1)
535 FPrintf ("Exception Record %d.\r\n", nER);
536
537 FPrintf ("application caused an %s", GetExceptionCodeStr(Exception->ExceptionCode));
538
539 if (Context->ContextFlags & CONTEXT_CONTROL)
540 FPrintf (" at %.4x:%.8x.\r\n", Context->SegCs, Context->Eip);
541
542 // in case of..
543 if (Context->Eip != (unsigned long)Exception->ExceptionAddress)
544 FPrintf ("Exception Address = %.8x\r\n", Exception->ExceptionAddress);
545
546 if (Exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
547 {
548 FPrintf ("\r\n%s location 0x%x caused an access violation.\r\n",
549 (Exception->ExceptionInformation[0] ? "Write to" : "Read from"),
550 Exception->ExceptionInformation[1]);
551 }
552
553 ER = Exception->ExceptionRecord;
554 }
555
556
557 if (Context->ContextFlags & CONTEXT_DEBUG_REGISTERS)
558 {
559 FPrintf ("\r\nDebug Registers:\r\n");
560 FPrintf ("Dr0=%.8x Dr1=%.8x Dr2=%.8x\r\n"
561 "Dr3=%.8x Dr6=%.8x Dr7=%.8x\r\n",
562 Context->Dr0, Context->Dr1, Context->Dr2,
563 Context->Dr3, Context->Dr6, Context->Dr7);
564 }
565
566 if (Context->ContextFlags & CONTEXT_FLOATING_POINT)
567 {
568 FPrintf ("\r\nFloating Save Area:\r\n");
569 FPrintf ("ControlWord =%.8x TagWord =%.8x ErrorSelector=%.8x DataSelector =%.8x\r\n"
570 "StatusWord =%.8x ErrorOffset =%.8x DataOffset =%.8x Cr0NpxState =%.8x\r\n",
571 Context->FloatSave.ControlWord, Context->FloatSave.TagWord, Context->FloatSave.ErrorSelector, Context->FloatSave.DataSelector,
572 Context->FloatSave.StatusWord, Context->FloatSave.ErrorOffset, Context->FloatSave.DataOffset, Context->FloatSave.Cr0NpxState
573 );
574
575 //BYTE RegisterArea[SIZE_OF_80387_REGISTERS];
576 }
577
578
579 // in case of...
580 if ((Context->ContextFlags & CONTEXT_FULL) != CONTEXT_FULL)
581 {
582 if (!(Context->ContextFlags & CONTEXT_SEGMENTS))
583 FPrintf ("Note! GS,FS,ES,DS are unspecified\r\n");
584 if (!(Context->ContextFlags & CONTEXT_INTEGER))
585 FPrintf ("Note! EDI,ESI,EBX,EDX,ECX,EAX are unspecified\r\n");
586 if (!(Context->ContextFlags & CONTEXT_CONTROL))
587 FPrintf ("Note! EBP,CS:EIP,EFlags,SS:ESP are unspecified\r\n");
588 }
589
590 if (hwdInstance!=NULL)
591 {
592 FPrintf ("\r\nHWDDriver loaded at %.8x\r\n", hwdInstance);
593 FPrintf ("DLL function pointers:\r\n");
594 for (loadfunc = hwdFuncTable, i=0; loadfunc->fnName!=NULL; loadfunc++,i++)
595 {
596 FPrintf ("hwdFuncTable[%d]: %s loaded at %.8x\r\n", i, loadfunc->fnName,
597 (unsigned long) *((void**)loadfunc->fnPointer) );
598 }
599
600 }
601
602 FPrintf ("\r\nBytes at CS:EIP:\r\n");
603 ucptr = (unsigned char*)Context->Eip;
604 for (i=0; i<16; i++)
605 FPrintf ("%.2x ", *ucptr++);
606
607 FPrintf ("\r\n\r\nStack dump:\r\n");
608 ulptr = (unsigned long*)Context->Esp;
609 for (i=0; i<16; i++)
610 FPrintf ("%.8x ", *ulptr++);
611
612 //FPrintf ("Bytes at CS:EIP:\r\n");
613 //FPrintf ("%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x ");
614
615 for (i=0; i<16; i++)
616 {
617 FPrintf ("%x
618 }
619 */
620