- Changed the archive format for crash reports from tar.gz to zip.

- Went back to a single process model for crash reporting. It appears there
  are some machines that don't like having another process collect the
  information and report it. I still feel that having another process do
  it _should_ be more reliable, because that process can execute in a known
  good state. Ah well. I haven't yet seen anything that left the main process
  in a totally unrecoverable state, so it's probably okay. Unlike before, this
  single-process version is still GCC-compatible.


SVN r217 (trunk)
This commit is contained in:
Randy Heit 2006-06-24 03:47:17 +00:00
parent 1faa6d57a4
commit 27ff97f16e
4 changed files with 407 additions and 399 deletions

View file

@ -1,3 +1,13 @@
June 23, 2006
- Changed the archive format for crash reports from tar.gz to zip.
- Went back to a single process model for crash reporting. It appears there
are some machines that don't like having another process collect the
information and report it. I still feel that having another process do
it _should_ be more reliable, because that process can execute in a known
good state. Ah well. I haven't yet seen anything that left the main process
in a totally unrecoverable state, so it's probably okay. Unlike before, this
single-process version is still GCC-compatible.
June 22, 2006 (Changes by Graf Zahl)
- Fixed: The resurrect cheat didn't reset the player's damage type so
if he died by being frozen the blue blend didn't disappear.

View file

@ -1,31 +0,0 @@
// GCC does not support Windows' Structured Exception Handling. :-(
// So I have to fake it using inline assembly
#ifdef __GNUC__
#define __try try
#define __except(a) catch(...)
#define EH_NONCONTINUABLE 0x01
#define EH_UNWINDING 0x02
#define EH_EXIT_UNWIND 0x04
#define EH_STACK_INVALID 0x08
#define EH_NESTED_CALL 0x10
typedef enum {
ExceptionContinueExecution,
ExceptionContinueSearch,
ExceptionNestedException,
ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;
typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)
(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
typedef struct _EXCEPTION_REGISTRATION
{
struct _EXCEPTION_REGISTRATION* Prev;
PEXCEPTION_HANDLER Handler;
} EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION;
#endif

View file

@ -32,6 +32,8 @@
**
*/
// HEADER FILES ------------------------------------------------------------
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#include <windows.h>
@ -51,6 +53,7 @@
#include <stddef.h>
#include "resource.h"
#include "version.h"
#include "m_swap.h"
#include <stdlib.h>
#include <stdio.h>
@ -58,16 +61,7 @@
#include <time.h>
#include <zlib.h>
// Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of
// giving them proper prototypes under Win32, they are just macros for
// Get/SetWindowLong, meaning they take LONGs and not LONG_PTRs.
#ifdef _WIN64
typedef LONG_PTR WLONG_PTR;
#else
typedef LONG WLONG_PTR;
#endif
HRESULT (__stdcall *pEnableThemeDialogTexture) (HWND hwnd, DWORD dwFlags);
// MACROS ------------------------------------------------------------------
#define BUGS_FORUM_URL "http://forum.zdoom.org/index.php?c=3"
@ -80,11 +74,143 @@ HRESULT (__stdcall *pEnableThemeDialogTexture) (HWND hwnd, DWORD dwFlags);
// If you are working on your own modified version of ZDoom, change
// the last part of the UPLOAD_AGENT (between parentheses) to your
// own program's name. e.g. (Skulltag) or (ZDaemon) or (ZDoomFu)
#define UPLOAD_AGENT "ZDoom/" DOTVERSIONSTR " (ZDoom the Original)"
#define UPLOAD_AGENT "ZDoom/" DOTVERSIONSTR " (" GAMESIG ")"
// Time, in milliseconds, to wait for a send() or recv() to complete.
#define TIMEOUT 60000
// Maximum number of files that might appear in a crash report.
#define MAX_FILES 5
#ifndef WORDS_BIGENDIAN
#define MAKE_ID(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24))
#else
#define MAKE_ID(a,b,c,d) ((d)|((c)<<8)|((b)<<16)|((a)<<24))
#endif
#define ZIP_LOCALFILE MAKE_ID('P','K',3,4)
#define ZIP_CENTRALFILE MAKE_ID('P','K',1,2)
#define ZIP_ENDOFDIR MAKE_ID('P','K',5,6)
// TYPES -------------------------------------------------------------------
// Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of
// giving them proper prototypes under Win32, they are just macros for
// Get/SetWindowLong, meaning they take LONGs and not LONG_PTRs.
#ifdef _WIN64
typedef LONG_PTR WLONG_PTR;
#else
typedef LONG WLONG_PTR;
#endif
namespace zip
{
#pragma pack(push,1)
struct LocalFileHeader
{
DWORD Magic; // 0
BYTE VersionToExtract[2]; // 4
WORD Flags; // 6
WORD Method; // 8
WORD ModTime; // 10
WORD ModDate; // 12
DWORD CRC32; // 14
DWORD CompressedSize; // 18
DWORD UncompressedSize; // 22
WORD NameLength; // 26
WORD ExtraLength; // 28
};
struct CentralDirectoryEntry
{
DWORD Magic;
BYTE VersionMadeBy[2];
BYTE VersionToExtract[2];
WORD Flags;
WORD Method;
WORD ModTime;
WORD ModDate;
DWORD CRC32;
DWORD CompressedSize;
DWORD UncompressedSize;
WORD NameLength;
WORD ExtraLength;
WORD CommentLength;
WORD StartingDiskNumber;
WORD InternalAttributes;
DWORD ExternalAttributes;
DWORD LocalHeaderOffset;
};
struct EndOfCentralDirectory
{
DWORD Magic;
WORD DiskNumber;
WORD FirstDisk;
WORD NumEntries;
WORD NumEntriesOnAllDisks;
DWORD DirectorySize;
DWORD DirectoryOffset;
WORD ZipCommentLength;
};
#pragma pack(pop)
}
struct TarFile
{
HANDLE File;
const char *Filename;
int ZipOffset;
DWORD UncompressedSize;
DWORD CompressedSize;
DWORD CRC32;
bool Deflated;
};
typedef BOOL (WINAPI *THREADWALK) (HANDLE, LPTHREADENTRY32);
typedef BOOL (WINAPI *MODULEWALK) (HANDLE, LPMODULEENTRY32);
typedef HANDLE (WINAPI *CREATESNAPSHOT) (DWORD, DWORD);
typedef BOOL (WINAPI *WRITEDUMP) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
PMINIDUMP_EXCEPTION_INFORMATION,
PMINIDUMP_USER_STREAM_INFORMATION,
PMINIDUMP_CALLBACK_INFORMATION);
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void AddFile (HANDLE file, const char *filename);
static void CloseTarFiles ();
static HANDLE MakeZip ();
static void AddZipFile (HANDLE ziphandle, TarFile *whichfile, short dosdate, short dostime);
static HANDLE CreateTempFile ();
static void DumpBytes (HANDLE file, BYTE *address);
static void AddStackInfo (HANDLE file, void *dumpaddress);
static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack);
static void AddToolHelp (HANDLE file);
static HANDLE WriteTextReport ();
static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
static void SetEditControl (HWND control, HWND sizedisplay, int filenum);
static BOOL UploadReport (HANDLE report, bool gziped);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern HINSTANCE g_hInst;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
EXCEPTION_POINTERS CrashPointers;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static HRESULT (__stdcall *pEnableThemeDialogTexture) (HWND hwnd, DWORD dwFlags);
static const char PostHeader[] =
"POST " UPLOAD_URI " HTTP/1.1\r\n"
"Host: " REMOTE_HOST "\r\n"
@ -132,70 +258,10 @@ static const char DbgHelpRequest[] =
"User-Agent: " UPLOAD_AGENT "\r\n"
"\r\n";
namespace tar
{
/*
* Standard Archive Format - Standard TAR - USTAR
*/
enum
{
RECORDSIZE = 512,
NAMSIZE = 100,
TUNMLEN = 32,
TGNMLEN = 32
};
union record {
unsigned char charptr[RECORDSIZE];
struct {
char name[NAMSIZE];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char linkflag;
char linkname[NAMSIZE];
char magic[8];
char uname[TUNMLEN];
char gname[TGNMLEN];
char devmajor[8];
char devminor[8];
} header;
};
}
#define MAX_FILES 5
struct TarFile
{
HANDLE File;
const char *Filename;
};
static TarFile TarFiles[MAX_FILES];
static int NumFiles;
static void AddFile (HANDLE file, const char *filename);
static void CloseTarFiles ();
static HANDLE MakeTar (bool &gzip);
static HANDLE CreateTempFile ();
typedef BOOL (WINAPI *THREADWALK) (HANDLE, LPTHREADENTRY32);
typedef BOOL (WINAPI *MODULEWALK) (HANDLE, LPMODULEENTRY32);
typedef HANDLE (WINAPI *CREATESNAPSHOT) (DWORD, DWORD);
typedef BOOL (WINAPI *WRITEDUMP) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
PMINIDUMP_EXCEPTION_INFORMATION,
PMINIDUMP_USER_STREAM_INFORMATION,
PMINIDUMP_CALLBACK_INFORMATION);
extern HINSTANCE g_hInst;
EXCEPTION_POINTERS CrashPointers;
EXCEPTION_RECORD MyExceptionRecord;
CONTEXT MyContextRecord;
static HANDLE DbgProcess;
static DWORD DbgProcessID;
static DWORD DbgThreadID;
@ -204,17 +270,48 @@ static PVOID CrashAddress;
static bool NeedDbgHelp;
static char CrashSummary[256];
static void DumpBytes (HANDLE file, BYTE *address);
static void AddStackInfo (HANDLE file, void *dumpaddress);
static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack);
static void AddToolHelp (HANDLE file);
static WNDPROC StdStaticProc;
static HANDLE WriteTextReport ();
// CODE --------------------------------------------------------------------
static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
static void SetEditControl (HWND control, HWND sizedisplay, int filenum);
//==========================================================================
//
// SafeReadMemory
//
// Returns true if the memory was succussfully read and false if not.
//
//==========================================================================
static BOOL UploadReport (HANDLE report, bool gziped);
static bool SafeReadMemory (const void *base, void *buffer, size_t len)
{
// Non-GCC version: Use SEH to catch any bad reads immediately when
// they happen instead of trying to catch them beforehand.
//
// GCC version: Test the memory beforehand and hope it doesn't become
// unreadable while we read it. GCC is the only Windows compiler (that
// I know of) that can't do SEH.
#ifdef __GNUC__
if (IsBadReadPtr (base, len) != 0)
{
return false;
}
#endif
bool success = false;
#ifndef __GNUC__
__try
{
#endif
memcpy (buffer, base, len);
success = true;
#ifndef __GNUC__
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
#endif
return success;
}
//==========================================================================
//
@ -321,7 +418,7 @@ void __cdecl Writef (HANDLE file, const char *format, ...)
//
//==========================================================================
void CreateCrashLog (HANDLE process, DWORD processID, DWORD threadID, LPEXCEPTION_POINTERS exceptionRecord, char *custominfo, DWORD customsize)
void CreateCrashLog (char *custominfo, DWORD customsize)
{
// Do not collect information more than once.
if (NumFiles != 0)
@ -329,59 +426,46 @@ void CreateCrashLog (HANDLE process, DWORD processID, DWORD threadID, LPEXCEPTIO
return;
}
DbgThreadID = threadID;
DbgProcessID = processID;
DbgProcess = process;
if (!ReadProcessMemory (DbgProcess, exceptionRecord, &CrashPointers, sizeof(CrashPointers), NULL) ||
!ReadProcessMemory (DbgProcess, CrashPointers.ExceptionRecord, &MyExceptionRecord, sizeof(EXCEPTION_RECORD), NULL) ||
!ReadProcessMemory (DbgProcess, CrashPointers.ContextRecord, &MyContextRecord, sizeof(CONTEXT), NULL))
DbgThreadID = GetCurrentThreadId();
DbgProcessID = GetCurrentProcessId();
DbgProcess = GetCurrentProcess();
CrashCode = CrashPointers.ExceptionRecord->ExceptionCode;
CrashAddress = CrashPointers.ExceptionRecord->ExceptionAddress;
AddFile (WriteTextReport(), "report.txt");
AddFile (WriteMyMiniDump(), "minidump.mdmp");
// Copy app-specific information out of the crashing process's memory
// and into a new temporary file.
if (customsize != 0)
{
HANDLE file = CreateTempFile();
DWORD wrote;
Writef (file, "Could not read process memory\n");
AddFile (file, "failed.txt");
}
else
{
CrashPointers.ExceptionRecord = &MyExceptionRecord;
CrashPointers.ContextRecord = &MyContextRecord;
CrashCode = CrashPointers.ExceptionRecord->ExceptionCode;
CrashAddress = CrashPointers.ExceptionRecord->ExceptionAddress;
AddFile (WriteTextReport(), "report.txt");
AddFile (WriteMyMiniDump(), "minidump.mdmp");
// Copy app-specific information out of the crashing process's memory
// and into a new temporary file.
if (customsize != 0)
if (file != INVALID_HANDLE_VALUE)
{
HANDLE file = CreateTempFile();
DWORD wrote;
BYTE buffer[512];
DWORD left;
if (file != INVALID_HANDLE_VALUE)
for (;; customsize -= left, custominfo += left)
{
BYTE buffer[512];
DWORD left;
for (;; customsize -= left, custominfo += left)
left = customsize > 512 ? 512 : customsize;
if (left == 0)
{
left = customsize > 512 ? 512 : customsize;
if (left == 0)
{
break;
}
if (ReadProcessMemory (DbgProcess, custominfo, buffer, left, NULL))
{
WriteFile (file, buffer, left, &wrote, NULL);
}
else
{
Writef (file, "Failed reading remaining %lu bytes\r\n", customsize);
break;
}
break;
}
if (SafeReadMemory (custominfo, buffer, left))
{
WriteFile (file, buffer, left, &wrote, NULL);
}
else
{
Writef (file, "Failed reading remaining %lu bytes\r\n", customsize);
break;
}
AddFile (file, "local.txt");
}
AddFile (file, "local.txt");
}
}
CloseHandle (DbgProcess);
@ -675,7 +759,7 @@ static void AddStackInfo (HANDLE file, void *dumpaddress)
Writef (file, "%p:", scan);
for (i = 0; i < max; ++i)
{
if (!ReadProcessMemory (DbgProcess, &scan[i], &peekd, 4, NULL))
if (!SafeReadMemory (&scan[i], &peekd, 4))
{
break;
}
@ -688,7 +772,7 @@ static void AddStackInfo (HANDLE file, void *dumpaddress)
Writef (file, " ");
for (i = 0; i < max*4; ++i)
{
if (!ReadProcessMemory (DbgProcess, (BYTE *)scan + i, &peekb, 1, NULL))
if (!SafeReadMemory ((BYTE *)scan + i, &peekb, 1))
{
break;
}
@ -725,7 +809,7 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
{
DWORD_PTR code;
if (ReadProcessMemory (DbgProcess, scan, &code, sizeof(code), NULL) &&
if (SafeReadMemory (scan, &code, sizeof(code)) &&
code >= codeStart && code < codeEnd)
{
static const char regNames[][4] =
@ -737,18 +821,18 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
const BYTE *bytep = (BYTE *)code;
BYTE peekb;
#define chkbyte(x,m,v) ReadProcessMemory(DbgProcess, x, &peekb, 1, NULL) && ((peekb & m) == v)
#define chkbyte(x,m,v) SafeReadMemory(x, &peekb, 1) && ((peekb & m) == v)
if (chkbyte(bytep - 5, 0xFF, 0xE8) || chkbyte(bytep - 5, 0xFF, 0xE9))
{
DWORD peekd;
if (ReadProcessMemory (DbgProcess, bytep - 4, &peekd, 4, NULL))
if (SafeReadMemory (bytep - 4, &peekd, 4))
{
DWORD_PTR jumpaddr = peekd + code;
Writef (file, "\r\n %p %s %p", code - 5,
peekb == 0xE9 ? "jmp " : "call", jumpaddr);
if (chkbyte((LPCVOID)jumpaddr, 0xFF, 0xE9) &&
ReadProcessMemory (DbgProcess, (LPCVOID)(jumpaddr + 1), &peekd, 4, NULL))
SafeReadMemory ((LPCVOID)(jumpaddr + 1), &peekd, 4))
{
Writef (file," => jmp %p", peekd + jumpaddr + 5);
}
@ -785,7 +869,7 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
Writef (file, "\r\n %08x", bytep - i);
bytep -= i - 1;
ReadProcessMemory (DbgProcess, bytep, &peekb, 1, NULL);
SafeReadMemory (bytep, &peekb, 1);
mod = peekb >> 6;
rm = peekb & 7;
bytep++;
@ -798,7 +882,7 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
{
int index, base;
ReadProcessMemory (DbgProcess, bytep, &peekb, 1, NULL);
SafeReadMemory (bytep, &peekb, 1);
scale = 1 << (peekb >> 6);
index = (peekb >> 3) & 7;
base = peekb & 7;
@ -832,12 +916,12 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
if (mod == 1)
{
signed char miniofs;
ReadProcessMemory (DbgProcess, bytep++, &miniofs, 1, NULL);
SafeReadMemory (bytep++, &miniofs, 1);
offset = miniofs;
}
else
{
ReadProcessMemory (DbgProcess, bytep, &offset, 4, NULL);
SafeReadMemory (bytep, &offset, 4);
bytep += 4;
}
if ((DWORD_PTR)bytep == code)
@ -905,7 +989,7 @@ static void DumpBytes (HANDLE file, BYTE *address)
{
line_p += sprintf (line_p, "\r\n%p:", address);
}
if (ReadProcessMemory (DbgProcess, address, &peek, 1, NULL))
if (SafeReadMemory (address, &peek, 1))
{
line_p += sprintf (line_p, " %02x", *address);
}
@ -989,40 +1073,44 @@ static void CloseTarFiles ()
// WriteBlock
//
// This is a wrapper around WriteFile. If stream is non-NULL, then the data
// is compressed before writing it to the file. outbuf must be 512 bytes.
// is compressed before writing it to the file. outbuf must be 1024 bytes.
//
//==========================================================================
static void WriteBlock (HANDLE file, LPCVOID buffer, DWORD bytes, z_stream *stream, Bytef *outbuf, DWORD *crc)
static DWORD WriteBlock (HANDLE file, LPCVOID buffer, DWORD bytes, z_stream *stream, Bytef *outbuf)
{
if (stream == NULL)
{
WriteFile (file, buffer, bytes, &bytes, NULL);
return bytes;
}
else
{
DWORD wrote = 0;
stream->next_in = (Bytef *)buffer;
stream->avail_in = bytes;
*crc = crc32 (*crc, (const Bytef *)buffer, bytes);
while (stream->avail_in != 0)
{
if (stream->avail_out == 0)
{
stream->next_out = outbuf;
stream->avail_out = sizeof(tar::record);
WriteFile (file, outbuf, sizeof(tar::record), &bytes, NULL);
stream->avail_out = 1024;
wrote += 1024;
WriteFile (file, outbuf, 1024, &bytes, NULL);
}
deflate (stream, Z_NO_FLUSH);
}
return wrote;
}
}
//==========================================================================
//
// WriteTar
// WriteZip
//
// Writes a .tar.gz file. If deflateInit fails, then ".gz" the gzip
// Writes a .zip/pk3 file. If deflateInit fails, then ".gz" the gzip
// argument will be false, otherwise it will be set true. A HANDLE to the
// file is returned. This file is delete-on-close.
//
@ -1031,27 +1119,120 @@ static void WriteBlock (HANDLE file, LPCVOID buffer, DWORD bytes, z_stream *stre
//
//==========================================================================
static HANDLE MakeTar (bool &gzip)
static HANDLE MakeZip ()
{
DWORD len;
unsigned char gzipheader[10];
tar::record record;
Bytef outbuf[sizeof(record)];
zip::CentralDirectoryEntry central = { ZIP_CENTRALFILE, { 20, 0 }, { 20, 0 }, };
zip::EndOfCentralDirectory dirend = { ZIP_ENDOFDIR, };
short dosdate, dostime;
time_t now;
int i, j, sum;
struct tm *nowtm;
int i, numfiles;
HANDLE file;
DWORD filesize, k;
DWORD totalsize;
z_stream stream;
int err;
DWORD crc;
DWORD len, dirsize;
if (NumFiles == 0)
{
return INVALID_HANDLE_VALUE;
}
// Open the zip file.
file = CreateTempFile ();
if (file == INVALID_HANDLE_VALUE)
{
return file;
}
time (&now);
nowtm = localtime (&now);
if (nowtm == NULL || nowtm->tm_year < 80)
{
dosdate = dostime = 0;
}
else
{
dosdate = (nowtm->tm_year - 80) * 512 + (nowtm->tm_mon + 1) * 32 + nowtm->tm_mday;
dostime = nowtm->tm_hour * 2048 + nowtm->tm_min * 32 + nowtm->tm_sec / 2;
dosdate = LittleShort(dosdate);
dostime = LittleShort(dostime);
}
// Write out the zip archive, one file at a time
for (i = 0; i < NumFiles; ++i)
{
AddZipFile (file, &TarFiles[i], dosdate, dostime);
}
// Write the central directory
central.ModTime = dostime;
central.ModDate = dosdate;
central.InternalAttributes = LittleShort(1);
dirend.DirectoryOffset = LittleLong(SetFilePointer (file, 0, NULL, FILE_CURRENT));
for (i = 0, numfiles = 0, dirsize = 0; i < NumFiles; ++i)
{
// Skip empty files
if (TarFiles[i].UncompressedSize == 0)
{
continue;
}
numfiles++;
if (TarFiles[i].Deflated)
{
central.Flags = LittleShort(2);
central.Method = LittleShort(8);
}
else
{
central.Flags = 0;
central.Method = 0;
}
central.CRC32 = LittleLong(TarFiles[i].CRC32);
central.CompressedSize = LittleLong(TarFiles[i].CompressedSize);
central.UncompressedSize = LittleLong(TarFiles[i].UncompressedSize);
central.NameLength = LittleShort((WORD)strlen(TarFiles[i].Filename));
central.LocalHeaderOffset = LittleLong(TarFiles[i].ZipOffset);
WriteFile (file, &central, sizeof(central), &len, NULL);
WriteFile (file, TarFiles[i].Filename, (DWORD)strlen(TarFiles[i].Filename), &len, NULL);
dirsize += sizeof(central) + len;
}
// Write the directory terminator
dirend.NumEntriesOnAllDisks = dirend.NumEntries = LittleShort(numfiles);
dirend.DirectorySize = LittleLong(dirsize);
WriteFile (file, &dirend, sizeof(dirend), &len, NULL);
return file;
}
//==========================================================================
//
// AddZipFile
//
// Adds a file to the opened zip.
//
//==========================================================================
static void AddZipFile (HANDLE ziphandle, TarFile *whichfile, short dosdate, short dostime)
{
zip::LocalFileHeader local = { ZIP_LOCALFILE, };
Bytef outbuf[1024], inbuf[1024];
z_stream stream;
DWORD wrote, len, k;
int err;
bool gzip;
whichfile->UncompressedSize = GetFileSize (whichfile->File, NULL);
whichfile->CompressedSize = 0;
whichfile->ZipOffset = 0;
whichfile->Deflated = false;
// Skip empty files.
if (whichfile->UncompressedSize == 0)
{
return;
}
stream.next_in = Z_NULL;
stream.avail_in = 0;
@ -1061,89 +1242,42 @@ static HANDLE MakeTar (bool &gzip)
8, Z_DEFAULT_STRATEGY);
gzip = err == Z_OK;
// Open the tar file.
file = CreateTempFile ();
if (file == INVALID_HANDLE_VALUE)
if (gzip)
{
if (gzip)
{
deflateEnd (&stream);
}
return file;
}
if (gzip = (err == Z_OK))
{
// Write GZIP header
memcpy (gzipheader, "\x1F\x8B\x08\x00 \x02\x0B", 10);
memcpy (gzipheader+4, &now, 4);
WriteFile (file, gzipheader, 10, &len, NULL);
crc = crc32 (0, NULL, 0);
local.Method = LittleShort(8);
whichfile->Deflated = true;
stream.next_out = outbuf;
stream.avail_out = sizeof(outbuf);
}
// Write out the tar archive, one file at a time
for (i = 0, totalsize = 0; i < NumFiles; ++i)
// Write out the header and filename.
local.VersionToExtract[0] = 20;
local.Flags = gzip ? LittleShort(2) : 0;
local.ModTime = dostime;
local.ModDate = dosdate;
local.UncompressedSize = LittleLong(whichfile->UncompressedSize);
local.NameLength = LittleShort((WORD)strlen(whichfile->Filename));
whichfile->ZipOffset = SetFilePointer (ziphandle, 0, NULL, FILE_CURRENT);
WriteFile (ziphandle, &local, sizeof(local), &wrote, NULL);
WriteFile (ziphandle, whichfile->Filename, (DWORD)strlen(whichfile->Filename), &wrote, NULL);
// Write the file itself and calculate its CRC.
SetFilePointer (whichfile->File, 0, NULL, FILE_BEGIN);
for (k = 0; k < whichfile->UncompressedSize; )
{
// Fill in header information
filesize = GetFileSize (TarFiles[i].File, NULL);
// Skip empty files
if (filesize == 0)
len = whichfile->UncompressedSize - k;
if (len > 1024)
{
continue;
}
memset (&record, 0, sizeof(record));
strcpy (record.header.name, TarFiles[i].Filename);
strcpy (record.header.mode, "000666 ");
strcpy (record.header.uid, " 0 ");
strcpy (record.header.gid, " 0 ");
strcpy (record.header.magic, "ustar ");
strcpy (record.header.uname, "zdoom");
strcpy (record.header.gname, "games");
sprintf(record.header.size, "%11lo ", filesize);
sprintf(record.header.mtime, "%11lo ", now);
record.header.linkflag = '0';
// Calculate checksum
memcpy (record.header.chksum, " ", 8);
for (j = 0, sum = 0; j < (int)sizeof(record); ++j)
{
sum += record.charptr[j];
}
sprintf (record.header.chksum, "%6o", sum);
// Write out the header and then the file (padded to 512 bytes)
WriteBlock (file, &record, sizeof(record), gzip ? &stream : NULL, outbuf, &crc);
totalsize += sizeof(record);
SetFilePointer (TarFiles[i].File, 0, NULL, FILE_BEGIN);
for (k = 0; k < filesize; k += 512)
{
len = filesize - k;
if (len > sizeof(record))
{
len = sizeof(record);
}
else
{
memset (&record.charptr[len], 0, sizeof(record)-len);
}
ReadFile (TarFiles[i].File, &record, len, &len, NULL);
WriteBlock (file, &record, sizeof(record), gzip ? &stream : NULL, outbuf, &crc);
totalsize += sizeof(record);
len = 1024;
}
k += len;
ReadFile (whichfile->File, &inbuf, len, &len, NULL);
whichfile->CRC32 = crc32 (whichfile->CRC32, inbuf, len);
whichfile->CompressedSize += WriteBlock (ziphandle, inbuf, len, gzip ? &stream : NULL, outbuf);
}
// EOT is two zeroed blocks, according to GNU tar.
memset (&record, 0, sizeof(record));
WriteBlock (file, &record, sizeof(record), gzip ? &stream : NULL, outbuf, &crc);
WriteBlock (file, &record, sizeof(record), gzip ? &stream : NULL, outbuf, &crc);
totalsize += 2*sizeof(record);
// Flush the zlib stream buffer and write the gzip epilogue
// Flush the zlib stream buffer.
if (gzip)
{
for (bool done = false;;)
@ -1151,7 +1285,8 @@ static HANDLE MakeTar (bool &gzip)
len = sizeof(outbuf) - stream.avail_out;
if (len != 0)
{
WriteFile (file, outbuf, len, &len, NULL);
whichfile->CompressedSize += len;
WriteFile (ziphandle, outbuf, len, &wrote, NULL);
stream.next_out = outbuf;
stream.avail_out = sizeof(outbuf);
}
@ -1167,14 +1302,17 @@ static HANDLE MakeTar (bool &gzip)
}
}
deflateEnd (&stream);
memcpy (gzipheader, &crc, 4);
memcpy (gzipheader+4, &totalsize, 4);
WriteFile (file, gzipheader, 8, &len, NULL);
}
return file;
}
static WNDPROC StdStaticProc;
// Fill in fields we didn't know when we wrote the local header.
SetFilePointer (ziphandle, whichfile->ZipOffset + 14, NULL, FILE_BEGIN);
k = LittleLong(whichfile->CRC32);
WriteFile (ziphandle, &k, 4, &wrote, NULL);
k = LittleLong(whichfile->CompressedSize);
WriteFile (ziphandle, &k, 4, &wrote, NULL);
SetFilePointer (ziphandle, 0, NULL, FILE_END);
}
//==========================================================================
//
@ -2301,7 +2439,6 @@ struct UploadParmStruct
HWND hDlg;
HANDLE hThread;
HANDLE hFile;
bool gzipped;
const char *UserSummary;
};
@ -2394,10 +2531,6 @@ static DWORD WINAPI UploadProc (LPVOID lpParam)
sizeof(MultipartBinaryHeader)-1 +
sizeof(MultipartHeaderGZip)-1 + fileLen +
sizeof(MultipartFooter)-1;
if (!parm->gzipped)
{
contentLength -= sizeof(MultipartHeaderGZip) - sizeof(MultipartHeaderNoGZip);
}
headerLen = sprintf (xferbuf, PostHeader, contentLength);
bytesSent = send (sock, xferbuf, headerLen, 0);
if (bytesSent != headerLen)
@ -2463,8 +2596,7 @@ static DWORD WINAPI UploadProc (LPVOID lpParam)
}
// Send the report file.
headerLen = sprintf (xferbuf, "%s%s", MultipartBinaryHeader,
parm->gzipped ? MultipartHeaderGZip : MultipartHeaderNoGZip);
headerLen = sprintf (xferbuf, "%s%s", MultipartBinaryHeader, MultipartHeaderZip);
bytesSent = send (sock, xferbuf, headerLen, 0);
if (bytesSent == SOCKET_ERROR)
@ -2684,9 +2816,9 @@ static BOOL CALLBACK BoingDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARA
//
//==========================================================================
static BOOL UploadReport (HANDLE file, bool gzipped)
static BOOL UploadReport (HANDLE file)
{
UploadParmStruct uploadParm = { 0, 0, file, gzipped, UserSummary };
UploadParmStruct uploadParm = { 0, 0, file, UserSummary };
BOOL res = (BOOL)DialogBoxParam (g_hInst, MAKEINTRESOURCE(IDD_BOING), NULL, (DLGPROC)BoingDlgProc, (LPARAM)&uploadParm);
if (UserSummary != NULL)
{
@ -2706,7 +2838,7 @@ static BOOL UploadReport (HANDLE file, bool gzipped)
//
//==========================================================================
static void SaveReport (HANDLE file, bool gzipped)
static void SaveReport (HANDLE file)
{
OPENFILENAME ofn = {
#ifdef OPENFILENAME_SIZE_VERSION_400
@ -2717,16 +2849,8 @@ static void SaveReport (HANDLE file, bool gzipped)
, };
char filename[256];
if (gzipped)
{
ofn.lpstrFilter = "GZipped Tarball (*.tar.gz)\0*.tar.gz\0";
strcpy (filename, "CrashReport.tar.gz");
}
else
{
ofn.lpstrFilter = "Tarball (*.tar)\0*.tar\0";
strcpy (filename, "CrashReport.tar");
}
ofn.lpstrFilter = "Zip file (*.pk3)\0*.pk3\0";
strcpy (filename, "CrashReport.pk3");
ofn.lpstrFile = filename;
ofn.nMaxFile = sizeof(filename);
@ -2780,7 +2904,6 @@ void DisplayCrashLog ()
{
HINSTANCE riched;
HANDLE file;
bool gzipped = false;
if (NumFiles == 0 || (riched = LoadLibrary ("riched20.dll")) == NULL)
{
@ -2805,16 +2928,16 @@ void DisplayCrashLog ()
INT_PTR result = DialogBox (g_hInst, MAKEINTRESOURCE(IDD_CRASHDIALOG), NULL, (DLGPROC)CrashDlgProc);
if (result == IDYES)
{
#if 0 // Server-side support is not done yet
file = MakeTar (gzipped);
UploadReport (file, gzipped);
#if 0 // Server-side support is not done yet because I am too lazy.
file = MakeZip ();
UploadReport (file);
CloseHandle (file);
#endif
}
else if (result == IDC_SAVEREPORT)
{
file = MakeTar (gzipped);
SaveReport (file, gzipped);
file = MakeZip ();
SaveReport (file);
CloseHandle (file);
}
FreeLibrary (riched);

View file

@ -67,11 +67,9 @@
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
void CreateCrashLog (HANDLE process, DWORD processID, DWORD threadID, LPEXCEPTION_POINTERS exceptionRecord, char *custominfo, DWORD customsize);
void CreateCrashLog (char *custominfo, DWORD customsize);
extern void DisplayCrashLog ();
extern EXCEPTION_POINTERS CrashPointers;
extern EXCEPTION_RECORD MyExceptionRecord;
extern CONTEXT MyContextRecord;
// Will this work with something besides VC++?
// Answer: yes it will.
@ -479,15 +477,7 @@ LONG WINAPI ExitMessedUp (LPEXCEPTION_POINTERS foo)
ExitProcess (1000);
}
void CALLBACK TimeToDie (ULONG_PTR dummy)
{
SetUnhandledExceptionFilter (ExitMessedUp);
I_ShutdownHardware ();
SetWindowPos (Window, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW);
exit (-1);
}
void CALLBACK SpawnFailed (ULONG_PTR dummy)
void CALLBACK ExitFatally (ULONG_PTR dummy)
{
SetUnhandledExceptionFilter (ExitMessedUp);
I_ShutdownHardware ();
@ -496,30 +486,8 @@ void CALLBACK SpawnFailed (ULONG_PTR dummy)
exit (-1);
}
void GetInfo (PEXCEPTION_POINTERS dst, PEXCEPTION_POINTERS src)
{
dst->ExceptionRecord = &MyExceptionRecord;
dst->ContextRecord = &MyContextRecord;
MyExceptionRecord = *src->ExceptionRecord;
MyContextRecord = *src->ContextRecord;
}
LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info)
{
static bool caughtsomething = false;
if (caughtsomething) return EXCEPTION_EXECUTE_HANDLER;
caughtsomething = true;
char *custominfo = (char *)HeapAlloc (GetProcessHeap(), 0, 16384);
PAPCFUNC apcfunc;
char cmdline[128];
char modname[_MAX_PATH];
STARTUPINFO startup = { sizeof(startup) };
PROCESS_INFORMATION newproc;
GetInfo (&CrashPointers, info);
#ifdef _DEBUG
if (info->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
{
@ -527,41 +495,27 @@ LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info)
}
#endif
static bool caughtsomething = false;
if (caughtsomething) return EXCEPTION_EXECUTE_HANDLER;
caughtsomething = true;
char *custominfo = (char *)HeapAlloc (GetProcessHeap(), 0, 16384);
CrashPointers = *info;
DoomSpecificInfo (custominfo);
// Spawn off a new copy of ourself to handle the information gathering and reporting.
wsprintf (cmdline, "IDidCrash:OuchieBooboo %x %x %p %p %lx", GetCurrentProcessId(),
GetCurrentThreadId(), &CrashPointers, custominfo, strlen(custominfo));
GetModuleFileName (NULL, modname, _MAX_PATH);
modname[_MAX_PATH-1] = 0;
if (!CreateProcess (modname, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &newproc))
{
// CreateProcess failed. We'll have to do everything ourself!
CreateCrashLog (GetCurrentProcess(), GetCurrentProcessId(), GetCurrentThreadId(), &CrashPointers, custominfo, (DWORD)strlen(custominfo));
apcfunc = SpawnFailed;
QueueUserAPC (SpawnFailed, MainThread, 0);
}
else
{
// Give our new debugger process a chance to get up and running and attach
// itself to us. Calling SuspendThread (so that we wait only as long as actually
// needed) does not work, because it interferes with the receipt of the
// exception information. I'm not sure why.
Sleep (1000);
apcfunc = TimeToDie;
}
CreateCrashLog (custominfo, (DWORD)strlen(custominfo));
// If the main thread crashed, then make it clean up after itself.
// Otherwise, put the crashing thread to sleep and signal the main thread to clean up.
if (GetCurrentThreadId() == MainThreadID)
{
info->ContextRecord->Eip = (DWORD_PTR)apcfunc;
info->ContextRecord->Eip = (DWORD_PTR)ExitFatally;
}
else
{
info->ContextRecord->Eip = (DWORD_PTR)SleepForever;
QueueUserAPC (apcfunc, MainThread, 0);
QueueUserAPC (ExitFatally, MainThread, 0);
}
return EXCEPTION_CONTINUE_EXECUTION;
}
@ -572,63 +526,15 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n
InitCommonControls (); // Be pretty under XP
if (strncmp (GetCommandLine(), "IDidCrash:OuchieBooboo ", 23) == 0 && __argc == 6)
{ // We are being run to handle a crash in another instance of ourself.
// argv[1] is the process ID of the instance that crashed.
// argv[2] is the thread ID of the crasher.
// argv[3] is a pointer to the exception information in that process's address space.
// argv[4] is a pointer to a text buffer for ZDoom-specific info.
// argv[5] is the length of argv[4]'s buffer
DWORD pid, tid;
LPEXCEPTION_POINTERS info;
char *info2;
DWORD info2len;
BOOL debugging;
HANDLE debuggee;
DEBUG_EVENT debugev;
pid = strtoul (__argv[1], NULL, 16);
tid = strtoul (__argv[2], NULL, 16);
sscanf (__argv[3], "%p", &info);
sscanf (__argv[4], "%p", &info2);
info2len = strtoul (__argv[5], NULL, 16);
// DebugActiveProcess will suspend all threads in the other process,
// so that's why we call it. When it resumes, it will shut down
// as cleanly as it can.
debugging = DebugActiveProcess (pid);
// if (MessageBox (NULL, GetCommandLine(), "foo", MB_OKCANCEL) == IDCANCEL) exit (0);
debuggee = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
CreateCrashLog (debuggee, pid, tid, info, info2, info2len);
if (debugging)
{ // Now let the crashing process resume. Process debug events until the process
// has exited. We don't care about the events, we just wanted the debugger status
// so that the process would be suspended while we gathered info on it.
while (WaitForDebugEvent (&debugev, INFINITE))
{
ContinueDebugEvent(debugev.dwProcessId, debugev.dwThreadId, DBG_CONTINUE);
if (debugev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
{
// In this case, ContinueDebugEvent closes the process handle for us,
// so we don't need to (and we must be sure not to reference it again).
break;
}
}
}
DisplayCrashLog ();
exit (0);
}
#if !defined(__GNUC__) && defined(_DEBUG)
if (__argc == 2 && strcmp (__argv[1], "TestCrash") == 0)
{
EXCEPTION_POINTERS info;
__try
{
*(int *)0 = 0;
}
__except(GetInfo (&info, GetExceptionInformation()),
CreateCrashLog (GetCurrentProcess(), GetCurrentProcessId(), GetCurrentThreadId(), &info, __argv[1], 9),
EXCEPTION_EXECUTE_HANDLER)
__except(CrashPointers = *GetExceptionInformation(),
CreateCrashLog (__argv[1], 9), EXCEPTION_EXECUTE_HANDLER)
{
}
DisplayCrashLog ();