Quite a while ago (see below) we discussed popping up a dialog when an application gets a "signal". My suggestion was to do this, Pedro disagreed.
To avoid misunderstandings, I'll summarize my view on what has happened since : - I've found the cause of the problem in my app - I've tried creating a configurable event handler for cegcc, see below - I've tried to do a similar thing for mingw32ce but failed The goal of this message is to address the second bullet. I've attached a patch to src/newlib/newlib/libc/sys/wince/startup.c which allows you to configure your PDA to either use printf or use dialogs when the application gets an exception. Right now the code does just that, on my wish list is also an option to specify in which file to write. But before I do anything with this, I'd like to ask opinions from the list whether this addition is a good idea. I believe Pedro's remark would be adressed by this new implementation, but maybe I've not understood his remark completely. If you want to play with this, use regeditce or a similar tool to add HKEY_CURRENT_USER -> cegcc -> debug If you create this as a string, with value "dialog", then that's what will happen. In all other cases, the original functionality (simple printf) is currently preserved. As I said I welcome comments. Danny On Thu, 2007-04-19 at 23:13 +0100, Pedro Alves wrote: > Danny Backx wrote: > > I've simplified the _eh_handler_ in > > src/newlib/newlib/libc/sys/wince/startup.c a bit, see attachment. > > > > This kicks out all the complicated handling in that function, and > > replaces it with a simple message box. > > > > > You're removing functionality. That function does a few things (there > are some log dumps that could 'go away'/'be ifdefs out'): > > - converts unaligned accesses to memcpy's. Questionable if this adds any > real value. Unaligned accesses should be fixed on the code that produces > them. Having a handler fix them hides a "bug", and makes programs run > slow. > > - implements very rudimentary support for SIGSEGV. > > > The downside is that the original (complicated) stuff is gone. I have no > > idea whether this actually worked. > > > > It does. At least it did many months ago. > > > Is replacing this a good idea ? > > > > My test programs now show a dialog titled "WinCE Exception" and > > containing text such as > > ILLEGAL_INSTRUCTION > > Code C000001D > > Flags 0 > > (that's the test program that performs a floating point instruction for > > floating point hardware which isn't on my system), or > > ACCESS_VIOLATION > > Code C0000005 > > Flags 0 > > when trying to access a NULL pointer. > > > > Should cegcc apps really display dialogs like that? Maybe > they should do an fprintf (stderr, ...) instead. I'm thinking > of cegcc console apps over a telnet/ssh for instance. > > > Strangely, dividing by 0 doesn't cause such an exception. > > > > Are you sure the compiler didn't optimize the division into nan > or something else? > Try looking at the asm, building without optimization or > do something like: > > int main (int argc, char** argv) > { > return 5/(argc - 1); > } > > > I haven't tried this in mingw32ce yet, only in cegcc. > > > > The user should do it himself if he wants it in mingw32ce? > > (Any brave soul to implement proper ARM WinCE SEH > support on gcc ?) > > Cheers, > Pedro Alves > -- Danny Backx ; danny.backx - at - scarlet.be ; http://danny.backx.info
Index: startup.c =================================================================== --- startup.c (revision 915) +++ startup.c (working copy) @@ -13,6 +13,10 @@ #include "sys/io.h" #include "sys/fixpath.h" +/* Forward declaration */ +static wchar_t *_get_registry_debugflag(void); +static int _get_registry_debug(void); + void _start_process(wchar_t *exe, wchar_t *cmd) { @@ -36,24 +40,25 @@ DWORD exception; int signal; const char* str; + const wchar_t *wstr; }; /* from pocket console */ struct exception_map_t __exception_map[] = { - { STATUS_ACCESS_VIOLATION, SIGSEGV, "Access Violation" }, - { STATUS_ILLEGAL_INSTRUCTION, SIGILL, "Illegal Instruction"}, - { STATUS_PRIVILEGED_INSTRUCTION, SIGILL, "Privileged Instruction" }, + { STATUS_ACCESS_VIOLATION, SIGSEGV, "Access Violation", L"Access Violation"}, + { STATUS_ILLEGAL_INSTRUCTION, SIGILL, "Illegal Instruction", L"Illegal Instruction"}, + { STATUS_PRIVILEGED_INSTRUCTION, SIGILL, "Privileged Instruction", L"Privileged Instruction"}, /* { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, NOSIG, SIG_DIE }, */ /* { (unsigned long)STATUS_INVALID_DISPOSITION, NOSIG, SIG_DIE }, */ - { STATUS_INTEGER_DIVIDE_BY_ZERO, SIGFPE, "Integer divide by zero" }, - { STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE, "Float denormal operand" }, - { STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE, "Float divide by zero" }, - { STATUS_FLOAT_INEXACT_RESULT, SIGFPE, "Float inexact result" }, - { STATUS_FLOAT_INVALID_OPERATION, SIGFPE, "Float invalid operation" }, - { STATUS_FLOAT_OVERFLOW, SIGFPE, "Float overflow" }, - { STATUS_FLOAT_STACK_CHECK, SIGFPE, "Float stack check" }, - { STATUS_FLOAT_UNDERFLOW, SIGFPE, "Float underflow" }, + { STATUS_INTEGER_DIVIDE_BY_ZERO, SIGFPE, "Integer divide by zero", L"Integer divide by zero"}, + { STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE, "Float denormal operand", L"Float denormal operand"}, + { STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE, "Float divide by zero", L"Float divide by zero"}, + { STATUS_FLOAT_INEXACT_RESULT, SIGFPE, "Float inexact result", L"Float inexact result"}, + { STATUS_FLOAT_INVALID_OPERATION, SIGFPE, "Float invalid operation", L"Float invalid operation"}, + { STATUS_FLOAT_OVERFLOW, SIGFPE, "Float overflow", L"Float overflow"}, + { STATUS_FLOAT_STACK_CHECK, SIGFPE, "Float stack check", L"Float stack check"}, + { STATUS_FLOAT_UNDERFLOW, SIGFPE, "Float underflow", L"Float underflow"}, /* { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO, NOSIG }, */ /* { (unsigned long)STATUS_STACK_OVERFLOW, NOSIG } */ }; @@ -103,6 +108,9 @@ { // ### What is this needed for? static int NestedException=0; + wchar_t msg[256]; + int unhandled = 0; + if(NestedException) { printf("nested exception\n"); @@ -117,22 +125,40 @@ DWORD DataAddr; #if 0 - printf("Trying to handle EXCEPTION_DATATYPE_MISALIGNMENT Flags:%x Addr:%x " - "SP:%x LR:%x R0:%x R1:%x R2:%x R3:%x R4:%x R5:%x R12:%x FP:%x\n", - ExceptionRecord->ExceptionFlags, - ExceptionRecord->ExceptionAddress, - ContextRecord->Sp, - ContextRecord->Lr, - ContextRecord->R0, - ContextRecord->R1, - ContextRecord->R2, - ContextRecord->R3, - ContextRecord->R4, - ContextRecord->R5, - ContextRecord->R12, - EstablisherFrame - ); + if (_get_registry_debug()) { + wsprintf(msg, L"Flags:%x Addr:%x\r\nSP:%x LR:%x R0:%x R1:%x R2:%x R3:%x\r\n" + "R4:%x R5:%x R12:%x FP:%x\n", + ExceptionRecord->ExceptionFlags, + ExceptionRecord->ExceptionAddress, + ContextRecord->Sp, + ContextRecord->Lr, + ContextRecord->R0, + ContextRecord->R1, + ContextRecord->R2, + ContextRecord->R3, + ContextRecord->R4, + ContextRecord->R5, + ContextRecord->R12, + EstablisherFrame); + MessageBoxW(0, msg, L"Datatype Misalignment Exception", 0); + } else #endif + { + printf("Trying to handle EXCEPTION_DATATYPE_MISALIGNMENT Flags:%x Addr:%x " + "SP:%x LR:%x R0:%x R1:%x R2:%x R3:%x R4:%x R5:%x R12:%x FP:%x\n", + ExceptionRecord->ExceptionFlags, + ExceptionRecord->ExceptionAddress, + ContextRecord->Sp, + ContextRecord->Lr, + ContextRecord->R0, + ContextRecord->R1, + ContextRecord->R2, + ContextRecord->R3, + ContextRecord->R4, + ContextRecord->R5, + ContextRecord->R12, + EstablisherFrame); + } Cmd=*(DWORD*)(ExceptionRecord->ExceptionAddress); // this may cause other exception @@ -144,7 +170,8 @@ Dst=(Cmd>>12)&0xf; Off=Cmd&0xfff; DataAddr=Regs[Dst]+Off; - fprintf(stderr, "Warning: Emulating unaligned LDR R%d,[R%d+%d] (DataAddr:%d) (Cmd:%x)\n", + if (_get_registry_debug() == 0) + fprintf(stderr, "Warning: Emulating unaligned LDR R%d,[R%d+%d] (DataAddr:%d) (Cmd:%x)\n", Src, Dst, Off, DataAddr, Cmd); memcpy(Regs+Dst, (char*)DataAddr, 4); } @@ -156,12 +183,14 @@ Src=(Cmd>>12)&0xf; Off=Cmd&0xfff; DataAddr=Regs[Dst]+Off; - fprintf(stderr, "Warning: Emulating unaligned STR R%d,[R%d+%d] (DataAddr:%d) (Cmd:%x)\n", + if (_get_registry_debug() == 0) + fprintf(stderr, "Warning: Emulating unaligned STR R%d,[R%d+%d] (DataAddr:%d) (Cmd:%x)\n", Src, Dst, Off, DataAddr, Cmd); memcpy((char*)DataAddr, Regs+Src, 4); } else { - printf("Unhandled command:%x\n", Cmd); + if (_get_registry_debug() == 0) + printf("Unhandled command:%x\n", Cmd); goto Cont; } @@ -170,11 +199,17 @@ NestedException=0; return ExceptionContinueExecution; Cont: - printf("Unhandled "); + if (_get_registry_debug() == 0) + printf("Unhandled "); + unhandled++; } Nest: - printf("Exception: Code:%x Flags:%x Addr:%x " - "SP:%x LR:%x R0:%x R1:%x R2:%x R3:%x R4:%x R5:%x R12:%x FP:%x\n", +#if 0 + /* + * Disabled this; there's a call with textual explanation for the end user below. + */ + wsprintf(msg, L"%sCode:%x Flags:%x Addr:%x\r\nSP:%x LR:%x R0:%x R1:%x R2:%x R3:%x\r\nR4:%x R5:%x R12:%x FP:%x\n", + (unhandled ? L"Unhandled\r\n" : L""), ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionFlags, ExceptionRecord->ExceptionAddress, @@ -189,6 +224,24 @@ ContextRecord->R12, EstablisherFrame ); + MessageBoxW(0, msg, L"WinCE Exception a", 0); +#endif + if (_get_registry_debug() == 0) + printf("Exception: Code:%x Flags:%x Addr:%x " + "SP:%x LR:%x R0:%x R1:%x R2:%x R3:%x R4:%x R5:%x R12:%x FP:%x\n", + ExceptionRecord->ExceptionCode, + ExceptionRecord->ExceptionFlags, + ExceptionRecord->ExceptionAddress, + ContextRecord->Sp, + ContextRecord->Lr, + ContextRecord->R0, + ContextRecord->R1, + ContextRecord->R2, + ContextRecord->R3, + ContextRecord->R4, + ContextRecord->R5, + ContextRecord->R12, + EstablisherFrame); DWORD* sp = (DWORD*)ContextRecord->Sp; *--sp = ContextRecord->Pc; @@ -217,10 +270,29 @@ struct exception_map_t* expt = get_exception_map_for(ExceptionRecord->ExceptionCode); if (!expt) { - printf("Unhandled kernel exception %x\n", ExceptionRecord->ExceptionCode); + if (_get_registry_debug() == 0) { + printf("Unhandled kernel exception %x\n", ExceptionRecord->ExceptionCode); + } else { + wsprintf(msg, L"%x", ExceptionRecord->ExceptionCode); + MessageBoxW(0, msg, L"Unhandled kernel exception", 0); + } exit(-1); } - printf("%s\n", expt->str); + + /* + * Show readable text explaining what went wrong, with a limited amount of detail. + */ + if (_get_registry_debug() == 0) { + printf("%s\n", expt->str); + } else { + wsprintf(msg, L"%s\r\nCode:%x Flags:%x Addr:%x SP:%x", + expt->wstr, + ExceptionRecord->ExceptionCode, + ExceptionRecord->ExceptionFlags, + ExceptionRecord->ExceptionAddress, + ContextRecord->Sp); + MessageBoxW(0, msg, L"WinCE Exception", 0); + } ContextRecord->R0 = expt->signal; /* raise(SIGSEGV); */ @@ -577,3 +649,66 @@ } __argc = index; } + +/* + * This function will query the registry for the value of an flag. + * Use it to determine whether to use printf to some file, + * or MessageBox in case of trouble. + * + * There's a fixed size buffer in here. + * + * Simplistic version - do this only once. + */ +static wchar_t *_get_registry_debugflag(void) +{ + static int onlyonce = 0; + + LONG r; + const static wchar_t *env = L"cegcc"; + const static wchar_t *wname = L"debug"; + size_t l; + DWORD tp; + HKEY k; + +#define BUF_SIZE 256 + + static wchar_t *wbuffer = NULL; + static DWORD bufsize; + + if (onlyonce) { + return wbuffer; + } + onlyonce++; + + r = RegOpenKeyEx(HKEY_CURRENT_USER, env, 0, 0, &k); + if (r != ERROR_SUCCESS) + return NULL; + + bufsize = BUF_SIZE; + wbuffer = (wchar_t *)malloc(bufsize); + r = RegQueryValueEx(k, wname, NULL, &tp, (LPBYTE)wbuffer, &bufsize); + RegCloseKey(k); + + if (r != ERROR_SUCCESS) { + free(wbuffer); + wbuffer = NULL; + return NULL; + } + + if (tp == REG_SZ) + return wbuffer; + free(wbuffer); + wbuffer = NULL; + return NULL; +} + +static int _get_registry_debug(void) +{ + wchar_t *r = _get_registry_debugflag(); + + if (r == NULL) + return 0; + if (wcscmp(r, L"dialog") == 0) + return 1; + return 0; +}
signature.asc
Description: This is a digitally signed message part
------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/
_______________________________________________ Cegcc-devel mailing list Cegcc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/cegcc-devel