/* * Copyright (C)2005-2016 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #ifdef HL_CONSOLE #include #endif HL_PRIM void *hl_fatal_error( const char *msg, const char *file, int line ) { hl_blocking(true); # ifdef HL_WIN_DESKTOP HWND consoleWnd = GetConsoleWindow(); DWORD pid; GetWindowThreadProcessId(consoleWnd, &pid); if( consoleWnd == NULL || GetActiveWindow() != NULL || GetCurrentProcessId() == pid ) { char buf[256]; sprintf(buf,"%s\n\n%s(%d)",msg,file,line); MessageBoxA(NULL,buf,"Fatal Error", MB_OK | MB_ICONERROR); } # endif printf("%s(%d) : FATAL ERROR : %s\n",file,line,msg); hl_blocking(false); hl_debug_break(); exit(1); return NULL; } typedef uchar *(*resolve_symbol_type)( void *addr, uchar *out, int *outSize ); typedef int (*capture_stack_type)( void **stack, int size ); static resolve_symbol_type resolve_symbol_func = NULL; static capture_stack_type capture_stack_func = NULL; int hl_internal_capture_stack( void **stack, int size ) { return capture_stack_func(stack,size); } HL_PRIM uchar *hl_resolve_symbol( void *addr, uchar *out, int *outSize ) { return resolve_symbol_func(addr, out, outSize); } static void (*throw_jump)( jmp_buf, int ) = NULL; HL_PRIM void hl_setup_longjump( void *j ) { throw_jump = j; } HL_PRIM void hl_setup_exception( void *resolve_symbol, void *capture_stack ) { resolve_symbol_func = resolve_symbol; capture_stack_func = capture_stack; } HL_PRIM void hl_set_error_handler( vclosure *d ) { hl_thread_info *t = hl_get_thread(); t->trap_uncaught = t->trap_current; t->exc_handler = d; } static bool break_on_trap( hl_thread_info *t, hl_trap_ctx *trap, vdynamic *v ) { while( true ) { if( trap == NULL || trap == t->trap_uncaught || t->trap_current == NULL || trap->prev == NULL ) return true; if( !trap->tcheck || !v ) return false; hl_type *ot = ((hl_type**)trap->tcheck)[1]; // it's an obj with first field is a hl_type if( !ot || hl_safe_cast(v->t,ot) ) return false; trap = trap->prev; } return false; } HL_PRIM void hl_throw( vdynamic *v ) { hl_thread_info *t = hl_get_thread(); hl_trap_ctx *trap = t->trap_current; bool call_handler = false; if( !(t->flags & HL_EXC_RETHROW) ) t->exc_stack_count = capture_stack_func(t->exc_stack_trace, HL_EXC_MAX_STACK); t->exc_value = v; t->trap_current = trap->prev; call_handler = trap == t->trap_uncaught || t->trap_current == NULL; if( (t->flags&HL_EXC_CATCH_ALL) || break_on_trap(t,trap,v) ) { if( trap == t->trap_uncaught ) t->trap_uncaught = NULL; t->flags |= HL_EXC_IS_THROW; hl_debug_break(); t->flags &= ~HL_EXC_IS_THROW; } t->flags &= ~HL_EXC_RETHROW; if( t->exc_handler && call_handler ) hl_dyn_call_safe(t->exc_handler,&v,1,&call_handler); if( throw_jump == NULL ) throw_jump = longjmp; throw_jump(trap->buf,1); HL_UNREACHABLE; } HL_PRIM void hl_null_access() { hl_error("Null access"); HL_UNREACHABLE; } HL_PRIM void hl_throw_buffer( hl_buffer *b ) { vdynamic *d = hl_alloc_dynamic(&hlt_bytes); d->v.ptr = hl_buffer_content(b,NULL); hl_throw(d); } HL_PRIM void hl_dump_stack() { void *stack[0x1000]; int count = capture_stack_func(stack, 0x1000); int i; for(i=0;iexc_stack_count); int i, pos = 0; for(i=0;iexc_stack_count;i++) { void *addr = t->exc_stack_trace[i]; uchar sym[512]; int size = 512; uchar *str = resolve_symbol_func(addr, sym, &size); if( str == NULL ) continue; hl_aptr(a,vbyte*)[pos++] = hl_copy_bytes((vbyte*)str,sizeof(uchar)*(size+1)); } a->size = pos; return a; } HL_PRIM int hl_exception_stack_raw( varray *arr ) { hl_thread_info *t = hl_get_thread(); if( arr ) memcpy(hl_aptr(arr,void*), t->exc_stack_trace, t->exc_stack_count*sizeof(void*)); return t->exc_stack_count; } HL_PRIM int hl_call_stack_raw( varray *arr ) { if( !arr ) return capture_stack_func(NULL,0); return capture_stack_func(hl_aptr(arr,void*), arr->size); } HL_PRIM void hl_rethrow( vdynamic *v ) { hl_get_thread()->flags |= HL_EXC_RETHROW; hl_throw(v); } HL_PRIM vdynamic *hl_alloc_strbytes( const uchar *fmt, ... ) { uchar _buf[256]; vdynamic *d; int len; uchar *buf = _buf; int bsize = sizeof(_buf) / sizeof(uchar); va_list args; while( true ) { va_start(args, fmt); len = uvszprintf(buf,bsize,fmt,args); va_end(args); if( (len + 2) << 1 < bsize ) break; if( buf != _buf ) free(buf); bsize <<= 1; buf = (uchar*)malloc(bsize * sizeof(uchar)); } d = hl_alloc_dynamic(&hlt_bytes); d->v.ptr = hl_copy_bytes((vbyte*)buf,(len + 1) << 1); if( buf != _buf ) free(buf); return d; } HL_PRIM void hl_fatal_fmt( const char *file, int line, const char *fmt, ...) { char buf[256]; va_list args; va_start(args, fmt); vsprintf(buf,fmt, args); va_end(args); hl_fatal_error(buf,file,line); } #ifdef HL_VCC # pragma optimize( "", off ) #endif HL_PRIM HL_NO_OPT void hl_breakpoint() { hl_debug_break(); } #ifdef HL_VCC # pragma optimize( "", on ) #endif #ifdef HL_LINUX__ #include static int debugger_present = -1; static void _sigtrap_handler(int signum) { debugger_present = 0; signal(SIGTRAP,SIG_DFL); } #endif #ifdef HL_MAC extern bool kinc_debugger_attached(void); #endif HL_PRIM bool hl_detect_debugger() { # if defined(HL_WIN) return (bool)IsDebuggerPresent(); # elif defined(HL_LINUX__) if( debugger_present == -1 ) { debugger_present = 1; signal(SIGTRAP,_sigtrap_handler); raise(SIGTRAP); } return (bool)debugger_present; # elif defined(HL_MAC) return kinc_debugger_attached(); # else return false; # endif } #ifdef HL_VCC # pragma optimize( "", off ) #endif HL_PRIM HL_NO_OPT void hl_assert() { hl_debug_break(); hl_error("assert"); } #ifdef HL_VCC # pragma optimize( "", on ) #endif #define _SYMBOL _ABSTRACT(hl_symbol) DEFINE_PRIM(_ARR,exception_stack,_NO_ARG); DEFINE_PRIM(_I32,exception_stack_raw,_ARR); DEFINE_PRIM(_I32,call_stack_raw,_ARR); DEFINE_PRIM(_VOID,set_error_handler,_FUN(_VOID,_DYN)); DEFINE_PRIM(_VOID,breakpoint,_NO_ARG); DEFINE_PRIM(_BYTES,resolve_symbol, _SYMBOL _BYTES _REF(_I32));