Wii: Add a custom exception handler that saves the crash information to the log and directs the user to submit it to us. DONT_BUILD.

git-svn-id: https://svn.eduke32.com/eduke32@4821 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
hendricks266 2014-12-17 13:02:21 +00:00
parent 8d115df01e
commit c397841cda
4 changed files with 476 additions and 1 deletions

View file

@ -69,6 +69,7 @@ ifeq ($(PLATFORM),WINDOWS)
endif
ifeq ($(PLATFORM),WII)
ENGINE_OBJS+= wiibits
LINKERFLAGS+= -Wl,-wrap,c_default_exceptionhandler
endif
ifeq ($(RENDERTYPE),SDL)
ENGINE_OBJS+= sdlayer

View file

@ -168,6 +168,9 @@ typedef struct
extern osdmain_t *osd;
extern BFILE *osdlog;
extern const char* osdlogfn;
enum osdflags_t
{
// OSD_INITIALIZED = 0x00000001,

View file

@ -42,7 +42,8 @@ osdmain_t *osd = NULL;
static int32_t osdrowscur=-1;
static int32_t osdscroll=0;
static int32_t osdmaxrows=20; // maximum number of lines which can fit on the screen
static BFILE *osdlog=NULL; // log filehandle
BFILE *osdlog; // log filehandle
const char* osdlogfn;
static int32_t keytime=0;
static int32_t osdscrtime = 0;
@ -812,6 +813,7 @@ void OSD_SetLogFile(const char *fn)
#endif
MAYBE_FCLOSE_AND_NULL(osdlog);
osdlogfn = NULL;
if (!fn)
return;
@ -819,7 +821,10 @@ void OSD_SetLogFile(const char *fn)
osdlog = Bfopen(fn, "w");
if (osdlog)
{
setvbuf(osdlog, (char *)NULL, bufmode, BUFSIZ);
osdlogfn = fn;
}
}

View file

@ -20,6 +20,8 @@
extern "C" {
#endif
extern BFILE *osdlog;
extern void L2Enhance();
extern void CON_EnableGecko(int channel,int safe);
extern bool fatInit(uint32_t cacheSize, bool setAsDefaultDevice);
@ -90,3 +92,467 @@ void wii_initgamevideo(void)
{
WII_InitVideoSystem();
}
/*
* linux/lib/vsprintf.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
*/
/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
static int skip_atoi(const char **s)
{
int i=0;
while (is_digit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
#define do_div(n,base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res; })
static char * number(char * str, long num, int base, int size, int precision
,int type)
{
char c,sign,tmp[66];
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
if (type & LARGE)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (num < 0) {
sign = '-';
num = -num;
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
if (type & SPECIAL) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num != 0)
tmp[i++] = digits[do_div(num,base)];
if (i > precision)
precision = i;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
*str++ = ' ';
if (sign)
*str++ = sign;
if (type & SPECIAL) {
if (base==8)
*str++ = '0';
else if (base==16) {
*str++ = '0';
*str++ = digits[33];
}
}
if (!(type & LEFT))
while (size-- > 0)
*str++ = c;
while (i < precision--)
*str++ = '0';
while (i-- > 0)
*str++ = tmp[i];
while (size-- > 0)
*str++ = ' ';
return str;
}
static int exception_vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
unsigned long num;
int i, base;
char * str;
const char *s;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
for (str=buf ; *fmt ; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if (is_digit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier = *fmt;
++fmt;
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
*str++ = ' ';
*str++ = (unsigned char) va_arg(args, int);
while (--field_width > 0)
*str++ = ' ';
continue;
case 's':
s = va_arg(args, char *);
if (!s)
s = "<NULL>";
len = strnlen(s, precision);
if (!(flags & LEFT))
while (len < field_width--)
*str++ = ' ';
for (i = 0; i < len; ++i)
*str++ = *s++;
while (len < field_width--)
*str++ = ' ';
continue;
case 'p':
if (field_width == -1) {
field_width = 2*sizeof(void *);
flags |= ZEROPAD;
}
str = number(str,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
continue;
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
} else {
int * ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
case '%':
*str++ = '%';
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default:
*str++ = '%';
if (*fmt)
*str++ = *fmt;
else
--fmt;
continue;
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & SIGN)
num = (short) num;
} else if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
str = number(str, num, base, field_width, precision, flags);
}
*str = '\0';
return str-buf;
}
#define DOUTBUFSIZE 256
static int exception_output;
static void exception_printf(const char *str, ...)
{
char outstr[DOUTBUFSIZE];
int len;
va_list args;
va_start(args, str);
len = exception_vsprintf(outstr, str, args);
va_end(args);
if (exception_output)
Bfputs(outstr, osdlog);
else
Bwrite(2, outstr, len);
}
/*-------------------------------------------------------------
exception.c -- PPC exception handling support
Copyright (C) 2004
Michael Wiedenbauer (shagkur)
Dave Murphy (WinterMute)
Copyright (C) 2014
Modified for EDuke32
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
-------------------------------------------------------------*/
//#define _EXC_DEBUG
#define CPU_STACK_TRACE_DEPTH 10
typedef struct _framerec {
struct _framerec *up;
void *lr;
} frame_rec, *frame_rec_t;
static void *exception_xfb = (void*)0xC1700000; //we use a static address above ArenaHi.
#ifdef __cplusplus
extern "C" {
#endif
extern void udelay(int us);
extern void __reload();
extern void VIDEO_SetFramebuffer(void *);
extern void __console_init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride);
extern void __wrap_c_default_exceptionhandler(frame_context *pCtx);
#ifdef __cplusplus
}
#endif
static const char *exception_name[NUM_EXCEPTIONS] = {
"System Reset", "Machine Check", "DSI", "ISI",
"Interrupt", "Alignment", "Program", "Floating Point",
"Decrementer", "System Call", "Trace", "Performance",
"IABR", "Reserved", "Thermal"};
extern void __wrap_c_default_exceptionhandler(frame_context *pCtx);
static void _cpu_print_stack(void *pc,void *lr,void *r1)
{
register u32 i = 0;
register frame_rec_t l,p = (frame_rec_t)lr;
l = p;
p = (frame_rec_t)r1;
if(!p) __asm__ __volatile__("mr %0,%%r1" : "=r"(p));
exception_printf("\n\tSTACK DUMP:");
for(i=0;i<CPU_STACK_TRACE_DEPTH-1 && p->up;p=p->up,i++) {
if(i%4) exception_printf(" --> ");
else {
if(i>0) exception_printf(" -->\n\t");
else exception_printf("\n\t");
}
switch(i) {
case 0:
if(pc) exception_printf("%p",pc);
break;
case 1:
if(!l) l = (frame_rec_t)mfspr(8);
exception_printf("%p",(void*)l);
break;
default:
exception_printf("%p",(void*)(p->up->lr));
break;
}
}
}
static void waitForReload(void)
{
u32 level;
exception_printf("\tPress the Reset button to return to loader.\n\n");
while ( 1 )
{
if( SYS_ResetButtonDown() )
{
exception_printf("\tReturning to loader...\n");
_CPU_ISR_Disable(level);
__reload ();
}
udelay(20000);
}
}
void __wrap_c_default_exceptionhandler(frame_context *pCtx)
{
GX_AbortFrame();
VIDEO_SetFramebuffer(exception_xfb);
__console_init(exception_xfb,20,20,640,574,1280);
CON_EnableGecko(1, true);
exception_printf("\n\n\n");
if (osdlog && osdlogfn)
{
exception_printf("\tAn unrecoverable error has occurred.\n\tPlease submit \"%s\" to the %s developers.\n\n", osdlogfn, AppProperName);
exception_output = 1;
}
exception_printf("\tException: %s\n\n", exception_name[pCtx->EXCPT_Number]);
exception_printf("\tGPR00 %08X GPR08 %08X GPR16 %08X GPR24 %08X\n",pCtx->GPR[0], pCtx->GPR[8], pCtx->GPR[16], pCtx->GPR[24]);
exception_printf("\tGPR01 %08X GPR09 %08X GPR17 %08X GPR25 %08X\n",pCtx->GPR[1], pCtx->GPR[9], pCtx->GPR[17], pCtx->GPR[25]);
exception_printf("\tGPR02 %08X GPR10 %08X GPR18 %08X GPR26 %08X\n",pCtx->GPR[2], pCtx->GPR[10], pCtx->GPR[18], pCtx->GPR[26]);
exception_printf("\tGPR03 %08X GPR11 %08X GPR19 %08X GPR27 %08X\n",pCtx->GPR[3], pCtx->GPR[11], pCtx->GPR[19], pCtx->GPR[27]);
exception_printf("\tGPR04 %08X GPR12 %08X GPR20 %08X GPR28 %08X\n",pCtx->GPR[4], pCtx->GPR[12], pCtx->GPR[20], pCtx->GPR[28]);
exception_printf("\tGPR05 %08X GPR13 %08X GPR21 %08X GPR29 %08X\n",pCtx->GPR[5], pCtx->GPR[13], pCtx->GPR[21], pCtx->GPR[29]);
exception_printf("\tGPR06 %08X GPR14 %08X GPR22 %08X GPR30 %08X\n",pCtx->GPR[6], pCtx->GPR[14], pCtx->GPR[22], pCtx->GPR[30]);
exception_printf("\tGPR07 %08X GPR15 %08X GPR23 %08X GPR31 %08X\n",pCtx->GPR[7], pCtx->GPR[15], pCtx->GPR[23], pCtx->GPR[31]);
exception_printf("\tLR %08X SRR0 %08x SRR1 %08x MSR %08x\n", pCtx->LR, pCtx->SRR0, pCtx->SRR1,pCtx->MSR);
exception_printf("\tDAR %08X DSISR %08X\n", mfspr(19), mfspr(18));
_cpu_print_stack((void*)pCtx->SRR0,(void*)pCtx->LR,(void*)pCtx->GPR[1]);
if((pCtx->EXCPT_Number==EX_DSI) || (pCtx->EXCPT_Number==EX_FP)) {
u32 i;
u32 *pAdd = (u32*)pCtx->SRR0;
exception_printf("\n\n\tCODE DUMP:\n");
for (i=0; i<12; i+=4)
exception_printf("\t%p: %08X %08X %08X %08X\n",
&(pAdd[i]),pAdd[i], pAdd[i+1], pAdd[i+2], pAdd[i+3]);
}
if (exception_output)
{
exception_output = 0;
MAYBE_FCLOSE_AND_NULL(osdlog);
}
else
{
exception_printf("\n");
}
waitForReload();
return;
}