error.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * Copyright (C)2005-2016 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. #include <hl.h>
  23. #include "hlsystem.h"
  24. #include <stdarg.h>
  25. #include <string.h>
  26. #ifdef HL_CONSOLE
  27. #include <posix/posix.h>
  28. #endif
  29. HL_PRIM void *hl_fatal_error( const char *msg, const char *file, int line ) {
  30. hl_blocking(true);
  31. # ifdef HL_WIN_DESKTOP
  32. HWND consoleWnd = GetConsoleWindow();
  33. DWORD pid;
  34. GetWindowThreadProcessId(consoleWnd, &pid);
  35. if( consoleWnd == NULL || GetActiveWindow() != NULL || GetCurrentProcessId() == pid ) {
  36. char buf[256];
  37. sprintf(buf,"%s\n\n%s(%d)",msg,file,line);
  38. MessageBoxA(NULL,buf,"Fatal Error", MB_OK | MB_ICONERROR);
  39. }
  40. # endif
  41. printf("%s(%d) : FATAL ERROR : %s\n",file,line,msg);
  42. hl_blocking(false);
  43. hl_debug_break();
  44. exit(1);
  45. return NULL;
  46. }
  47. typedef uchar *(*resolve_symbol_type)( void *addr, uchar *out, int *outSize );
  48. typedef int (*capture_stack_type)( void **stack, int size );
  49. static resolve_symbol_type resolve_symbol_func = NULL;
  50. static capture_stack_type capture_stack_func = NULL;
  51. int hl_internal_capture_stack( void **stack, int size ) {
  52. return capture_stack_func(stack,size);
  53. }
  54. HL_PRIM uchar *hl_resolve_symbol( void *addr, uchar *out, int *outSize ) {
  55. return resolve_symbol_func(addr, out, outSize);
  56. }
  57. static void (*throw_jump)( jmp_buf, int ) = NULL;
  58. HL_PRIM void hl_setup_longjump( void *j ) {
  59. throw_jump = j;
  60. }
  61. HL_PRIM void hl_setup_exception( void *resolve_symbol, void *capture_stack ) {
  62. resolve_symbol_func = resolve_symbol;
  63. capture_stack_func = capture_stack;
  64. }
  65. HL_PRIM void hl_set_error_handler( vclosure *d ) {
  66. hl_thread_info *t = hl_get_thread();
  67. t->trap_uncaught = t->trap_current;
  68. t->exc_handler = d;
  69. }
  70. static bool break_on_trap( hl_thread_info *t, hl_trap_ctx *trap, vdynamic *v ) {
  71. while( true ) {
  72. if( trap == NULL || trap == t->trap_uncaught || t->trap_current == NULL || trap->prev == NULL ) return true;
  73. if( !trap->tcheck || !v ) return false;
  74. hl_type *ot = ((hl_type**)trap->tcheck)[1]; // it's an obj with first field is a hl_type
  75. if( !ot || hl_safe_cast(v->t,ot) ) return false;
  76. trap = trap->prev;
  77. }
  78. return false;
  79. }
  80. HL_PRIM void hl_throw( vdynamic *v ) {
  81. hl_thread_info *t = hl_get_thread();
  82. hl_trap_ctx *trap = t->trap_current;
  83. bool call_handler = false;
  84. if( t->flags & HL_EXC_KILL )
  85. hl_fatal("Exception Occured");
  86. if( !(t->flags & HL_EXC_RETHROW) )
  87. t->exc_stack_count = capture_stack_func(t->exc_stack_trace, HL_EXC_MAX_STACK);
  88. t->exc_value = v;
  89. t->trap_current = trap->prev;
  90. call_handler = trap == t->trap_uncaught || t->trap_current == NULL;
  91. if( (t->flags&HL_EXC_CATCH_ALL) || break_on_trap(t,trap,v) ) {
  92. if( trap == t->trap_uncaught ) t->trap_uncaught = NULL;
  93. t->flags |= HL_EXC_IS_THROW;
  94. hl_debug_break();
  95. t->flags &= ~HL_EXC_IS_THROW;
  96. }
  97. t->flags &= ~HL_EXC_RETHROW;
  98. if( t->exc_handler && call_handler ) hl_dyn_call_safe(t->exc_handler,&v,1,&call_handler);
  99. if( throw_jump == NULL ) throw_jump = longjmp;
  100. throw_jump(trap->buf,1);
  101. HL_UNREACHABLE;
  102. }
  103. HL_PRIM void hl_null_access() {
  104. hl_error("Null access");
  105. HL_UNREACHABLE;
  106. }
  107. HL_PRIM void hl_throw_buffer( hl_buffer *b ) {
  108. vdynamic *d = hl_alloc_dynamic(&hlt_bytes);
  109. d->v.ptr = hl_buffer_content(b,NULL);
  110. hl_throw(d);
  111. }
  112. HL_PRIM void hl_dump_stack() {
  113. void *stack[0x1000];
  114. int count = capture_stack_func(stack, 0x1000);
  115. int i;
  116. for(i=0;i<count;i++) {
  117. void *addr = stack[i];
  118. uchar sym[512];
  119. int size = 512;
  120. uchar *str = resolve_symbol_func(addr, sym, &size);
  121. if( str == NULL ) {
  122. int iaddr = (int)(int_val)addr;
  123. usprintf(sym,512,USTR("@0x%X"),iaddr);
  124. str = sym;
  125. }
  126. uprintf(USTR("%s\n"),str);
  127. }
  128. fflush(stdout);
  129. }
  130. HL_PRIM bool hl_maybe_print_custom_stack( vdynamic *exc ) {
  131. hl_type *ot = exc->t;
  132. while( ot->kind == HOBJ ) {
  133. if( ot->obj->super == NULL ) {
  134. if( ucmp(ot->obj->name, USTR("haxe.Exception")) == 0 ) {
  135. hl_field_lookup *f = hl_lookup_find(ot->obj->rt->lookup, ot->obj->rt->nlookup, hl_hash_gen(USTR("__customStack"), true));
  136. if( f == NULL || f->field_index < 0 ) break;
  137. vdynamic *customStack = *(vdynamic**)((char*)(exc) + f->field_index);
  138. if( customStack != NULL ) {
  139. uprintf(USTR("%s\n"), hl_to_string(customStack));
  140. return true;
  141. }
  142. }
  143. break;
  144. }
  145. ot = ot->obj->super;
  146. }
  147. return false;
  148. }
  149. HL_PRIM void hl_print_uncaught_exception(vdynamic *exc) {
  150. uprintf(USTR("Uncaught exception: %s\n"), hl_to_string(exc));
  151. if (!hl_maybe_print_custom_stack(exc)) {
  152. varray *a = hl_exception_stack();
  153. for (int i = 0; i < a->size; i++)
  154. uprintf(USTR("Called from %s\n"), hl_aptr(a, uchar *)[i]);
  155. }
  156. fflush(stdout);
  157. }
  158. HL_PRIM varray *hl_exception_stack() {
  159. hl_thread_info *t = hl_get_thread();
  160. varray *a = hl_alloc_array(&hlt_bytes, t->exc_stack_count);
  161. int i, pos = 0;
  162. for(i=0;i<t->exc_stack_count;i++) {
  163. void *addr = t->exc_stack_trace[i];
  164. uchar sym[512];
  165. int size = 512;
  166. uchar *str = resolve_symbol_func(addr, sym, &size);
  167. if( str == NULL ) continue;
  168. hl_aptr(a,vbyte*)[pos++] = hl_copy_bytes((vbyte*)str,sizeof(uchar)*(size+1));
  169. }
  170. a->size = pos;
  171. return a;
  172. }
  173. HL_PRIM int hl_exception_stack_raw( varray *arr ) {
  174. hl_thread_info *t = hl_get_thread();
  175. if( arr ) memcpy(hl_aptr(arr,void*), t->exc_stack_trace, t->exc_stack_count*sizeof(void*));
  176. return t->exc_stack_count;
  177. }
  178. HL_PRIM int hl_call_stack_raw( varray *arr ) {
  179. if( !arr )
  180. return capture_stack_func(NULL,0);
  181. return capture_stack_func(hl_aptr(arr,void*), arr->size);
  182. }
  183. HL_PRIM void hl_rethrow( vdynamic *v ) {
  184. hl_get_thread()->flags |= HL_EXC_RETHROW;
  185. hl_throw(v);
  186. }
  187. HL_PRIM vdynamic *hl_alloc_strbytes( const uchar *fmt, ... ) {
  188. uchar _buf[256];
  189. vdynamic *d;
  190. int len;
  191. uchar *buf = _buf;
  192. int bsize = sizeof(_buf) / sizeof(uchar);
  193. va_list args;
  194. while( true ) {
  195. va_start(args, fmt);
  196. len = uvszprintf(buf,bsize,fmt,args);
  197. va_end(args);
  198. if( (len + 2) << 1 < bsize ) break;
  199. if( buf != _buf ) free(buf);
  200. bsize <<= 1;
  201. buf = (uchar*)malloc(bsize * sizeof(uchar));
  202. }
  203. d = hl_alloc_dynamic(&hlt_bytes);
  204. d->v.ptr = hl_copy_bytes((vbyte*)buf,(len + 1) << 1);
  205. if( buf != _buf ) free(buf);
  206. return d;
  207. }
  208. HL_PRIM void hl_fatal_fmt( const char *file, int line, const char *fmt, ...) {
  209. char buf[256];
  210. va_list args;
  211. va_start(args, fmt);
  212. vsprintf(buf,fmt, args);
  213. va_end(args);
  214. hl_fatal_error(buf,file,line);
  215. }
  216. #ifdef HL_VCC
  217. # pragma optimize( "", off )
  218. #endif
  219. HL_PRIM HL_NO_OPT void hl_breakpoint() {
  220. hl_debug_break();
  221. }
  222. #ifdef HL_VCC
  223. # pragma optimize( "", on )
  224. #endif
  225. #ifdef HL_LINUX
  226. #include <unistd.h>
  227. #include <fcntl.h>
  228. #endif
  229. #if defined(HL_MAC) && defined(__x86_64__)
  230. extern bool is_debugger_attached(void);
  231. # define MAC_DEBUG
  232. #endif
  233. HL_PRIM bool hl_detect_debugger() {
  234. # if defined(HL_WIN)
  235. return (bool)IsDebuggerPresent();
  236. # elif defined(HL_LINUX)
  237. static int debugger_present = -1;
  238. if(debugger_present < 0) {
  239. char buf[2048];
  240. char *tracer_pid;
  241. ssize_t num_read;
  242. debugger_present = 0;
  243. int status_fd = open("/proc/self/status", O_RDONLY);
  244. if (status_fd == -1)
  245. return 0;
  246. num_read = read(status_fd, buf, sizeof(buf));
  247. close(status_fd);
  248. if (num_read > 0) {
  249. buf[num_read] = 0;
  250. tracer_pid = strstr(buf, "TracerPid:");
  251. if (tracer_pid && atoi(tracer_pid + sizeof("TracerPid:") - 1) > 0)
  252. debugger_present = 1;
  253. }
  254. }
  255. return debugger_present == 1;
  256. # elif defined(MAC_DEBUG)
  257. return is_debugger_attached();
  258. # else
  259. return false;
  260. # endif
  261. }
  262. #ifdef HL_VCC
  263. # pragma optimize( "", off )
  264. #endif
  265. HL_PRIM HL_NO_OPT void hl_assert() {
  266. hl_debug_break();
  267. hl_error("assert");
  268. }
  269. #ifdef HL_VCC
  270. # pragma optimize( "", on )
  271. #endif
  272. #define _SYMBOL _ABSTRACT(hl_symbol)
  273. DEFINE_PRIM(_ARR,exception_stack,_NO_ARG);
  274. DEFINE_PRIM(_I32,exception_stack_raw,_ARR);
  275. DEFINE_PRIM(_I32,call_stack_raw,_ARR);
  276. DEFINE_PRIM(_VOID,set_error_handler,_FUN(_VOID,_DYN));
  277. DEFINE_PRIM(_VOID,breakpoint,_NO_ARG);
  278. DEFINE_PRIM(_BYTES,resolve_symbol, _SYMBOL _BYTES _REF(_I32));