| @@ -24,6 +24,7 @@ · 23 unmodified lines |
| 24 | 24 | #ifdef TCC_IS_NATIVE |
| 25 | 25 | |
| 26 | 26 | #ifdef CONFIG_TCC_BACKTRACE |
| 27 | +/* runtime debug info block */ |
| 27 | 28 | typedef struct rt_context |
| 28 | 29 | { |
| 29 | 30 | /* tccelf.c:tcc_add_btstub() wants these in that order: */ |
| @@ -42,32 +43,33 @@ typedef struct rt_context · 12 unmodified lines |
| 42 | 43 | ElfW(Sym) *esym_start; |
| 43 | 44 | ElfW(Sym) *esym_end; |
| 44 | 45 | char *elf_str; |
| 45 | | − // 6 |
| 46 | + // 6 * PTR_SIZE |
| 46 | 47 | addr_t prog_base; |
| 47 | 48 | void *bounds_start; |
| 48 | 49 | void *top_func; |
| 49 | | − TCCState *s1; |
| 50 | 50 | struct rt_context *next; |
| 51 | | − // 11 |
| 51 | + // 10 * PTR_SIZE |
| 52 | 52 | int num_callers; |
| 53 | 53 | int dwarf; |
| 54 | | −} rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */ |
| 54 | +} rt_context; |
| 55 | + |
| 56 | +/* linked list of rt_contexts */ |
| 57 | +static rt_context *g_rc; |
| 58 | +static int signal_set; |
| 59 | +static void set_exception_handler(void); |
| 60 | +#endif /* def CONFIG_TCC_BACKTRACE */ |
| 55 | 61 | |
| 56 | 62 | typedef struct rt_frame { |
| 57 | 63 | addr_t ip, fp, sp; |
| 58 | 64 | } rt_frame; |
| 59 | 65 | |
| 60 | | −/* linked list of rt_contexts */ |
| 61 | | −static rt_context *g_rc; |
| 62 | 66 | static TCCState *g_s1; |
| 63 | 67 | /* semaphore to protect it */ |
| 64 | 68 | TCC_SEM(static rt_sem); |
| 65 | | −static int signal_set; |
| 66 | | −static void set_exception_handler(void); |
| 67 | 69 | static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); } |
| 68 | 70 | static void rt_post_sem(void) { POST_SEM(&rt_sem); } |
| 69 | 71 | static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level); |
| 70 | | −#endif /* def CONFIG_TCC_BACKTRACE */ |
| 72 | +static void rt_exit(rt_frame *f, int code); |
| 71 | 73 | |
| 72 | 74 | /* ------------------------------------------------------------- */ |
| 73 | 75 | /* defined when included from lib/bt-exe.c */ |
| @@ -79,73 +81,26 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level); · 5 unmodified lines |
| 79 | 81 | |
| 80 | 82 | static int protect_pages(void *ptr, unsigned long length, int mode); |
| 81 | 83 | static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff); |
| 82 | | −static int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap); |
| 83 | | −static void rt_longjmp(rt_frame *f, int code); |
| 84 | +static void st_link(TCCState *s1); |
| 85 | +static void st_unlink(TCCState *s1); |
| 86 | +#ifdef CONFIG_TCC_BACKTRACE |
| 87 | +static int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap); |
| 88 | +#endif |
| 84 | 89 | #ifdef _WIN64 |
| 85 | 90 | static void *win64_add_function_table(TCCState *s1); |
| 86 | 91 | static void win64_del_function_table(void *); |
| 87 | 92 | #endif |
| 88 | 93 | |
| 89 | | −static void bt_link(TCCState *s1) |
| 90 | | −{ |
| 91 | | −#ifdef CONFIG_TCC_BACKTRACE |
| 92 | | − rt_context *rc; |
| 93 | | − void *p; |
| 94 | | − |
| 95 | | − if (!s1->do_backtrace) |
| 96 | | − return; |
| 97 | | − rc = tcc_get_symbol(s1, "__rt_info"); |
| 98 | | − if (!rc) |
| 99 | | − return; |
| 100 | | − rc->esym_start = (ElfW(Sym) *)(symtab_section->data); |
| 101 | | − rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); |
| 102 | | − rc->elf_str = (char *)symtab_section->link->data; |
| 103 | | − if (PTR_SIZE == 8 && !s1->dwarf) |
| 104 | | − rc->prog_base &= 0xffffffff00000000ULL; |
| 105 | | −#ifdef CONFIG_TCC_BCHECK |
| 106 | | − if (s1->do_bounds_check) { |
| 107 | | − if ((p = tcc_get_symbol(s1, "__bound_init"))) |
| 108 | | − ((void(*)(void*,int))p)(rc->bounds_start, 1); |
| 109 | | − } |
| 110 | | −#endif |
| 111 | | − rc->next = g_rc, g_rc = rc, rc->s1 = s1, s1->rc = rc; |
| 112 | | − if (0 == signal_set) |
| 113 | | − set_exception_handler(), signal_set = 1; |
| 114 | | −#endif |
| 115 | | −} |
| 116 | | − |
| 117 | | −static void bt_unlink(TCCState *s1) |
| 118 | | −{ |
| 119 | | −#ifdef CONFIG_TCC_BACKTRACE |
| 120 | | − rt_context *rc, **pp; |
| 121 | | − for (pp = &g_rc; rc = *pp, rc; pp = &rc->next) |
| 122 | | − if (rc->s1 == s1) { |
| 123 | | − *pp = rc->next; |
| 124 | | − break; |
| 125 | | − } |
| 94 | +#ifdef __APPLE__ |
| 95 | +# define CONFIG_RUNMEM_ALIGNED 0 |
| 96 | +#else |
| 97 | +# ifndef CONFIG_RUNMEM_ALIGNED |
| 98 | +# define CONFIG_RUNMEM_ALIGNED 1 |
| 99 | +# endif |
| 100 | +# if CONFIG_RUNMEM_ALIGNED |
| 101 | +# include <malloc.h> /* memalign() */ |
| 102 | +# endif |
| 126 | 103 | #endif |
| 127 | | −} |
| 128 | | − |
| 129 | | −static void st_link(TCCState *s1) |
| 130 | | −{ |
| 131 | | − rt_wait_sem(); |
| 132 | | − s1->next = g_s1, g_s1 = s1; |
| 133 | | − bt_link(s1); |
| 134 | | − rt_post_sem(); |
| 135 | | −} |
| 136 | | − |
| 137 | | −static void st_unlink(TCCState *s1) |
| 138 | | −{ |
| 139 | | − TCCState *s2, **pp; |
| 140 | | − rt_wait_sem(); |
| 141 | | − bt_unlink(s1); |
| 142 | | − for (pp = &g_s1; s2 = *pp, s2; pp = &s2->next) |
| 143 | | − if (s2 == s1) { |
| 144 | | − *pp = s2->next; |
| 145 | | − break; |
| 146 | | − } |
| 147 | | − rt_post_sem(); |
| 148 | | −} |
| 149 | 104 | |
| 150 | 105 | #if !_WIN32 && !__APPLE__ |
| 151 | 106 | //#define HAVE_SELINUX 1 |
| @@ -172,7 +127,15 @@ static int rt_mem(TCCState *s1, int size) · 20 unmodified lines |
| 172 | 127 | ptr_diff = (char*)prw - (char*)ptr; /* = size; */ |
| 173 | 128 | //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff); |
| 174 | 129 | #else |
| 175 | | − ptr = tcc_malloc(size); |
| 130 | +# if !CONFIG_RUNMEM_ALIGNED |
| 131 | + ptr = tcc_malloc(size += PAGESIZE); |
| 132 | +# elif _WIN32 |
| 133 | + ptr = _aligned_malloc(size, PAGESIZE); |
| 134 | +# else |
| 135 | + ptr = memalign(PAGESIZE, size); |
| 136 | +# endif |
| 137 | + if (NULL == ptr) |
| 138 | + return tcc_error_noabort("tccrun: could not allocate memory"); |
| 176 | 139 | #endif |
| 177 | 140 | s1->run_ptr = ptr; |
| 178 | 141 | s1->run_size = size; |
| @@ -189,12 +152,10 @@ LIBTCCAPI int tcc_relocate(TCCState *s1) · 10 unmodified lines |
| 189 | 152 | |
| 190 | 153 | if (s1->run_ptr) |
| 191 | 154 | exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported")); |
| 192 | | − |
| 193 | 155 | #ifdef CONFIG_TCC_BACKTRACE |
| 194 | 156 | if (s1->do_backtrace) |
| 195 | | − tcc_add_symbol(s1, "__rt_dump", __rt_dump); /* for bt-log.c */ |
| 157 | + tcc_add_symbol(s1, "_tcc_backtrace", _tcc_backtrace); /* for bt-log.c */ |
| 196 | 158 | #endif |
| 197 | | − |
| 198 | 159 | size = tcc_relocate_ex(s1, NULL, 0); |
| 199 | 160 | if (size < 0) |
| 200 | 161 | return -1; |
| @@ -236,31 +197,24 @@ ST_FUNC void tcc_run_free(TCCState *s1) · 35 unmodified lines |
| 236 | 197 | #else |
| 237 | 198 | /* unprotect memory to make it usable for malloc again */ |
| 238 | 199 | protect_pages(ptr, size, 2 /*rw*/); |
| 239 | | −#ifdef _WIN64 |
| 200 | +# ifdef _WIN64 |
| 240 | 201 | win64_del_function_table(s1->run_function_table); |
| 241 | | −#endif |
| 202 | +# endif |
| 203 | +# if !CONFIG_RUNMEM_ALIGNED |
| 242 | 204 | tcc_free(ptr); |
| 205 | +# elif _WIN32 |
| 206 | + _aligned_free(ptr); |
| 207 | +# else |
| 208 | + libc_free(ptr); |
| 209 | +# endif |
| 243 | 210 | #endif |
| 244 | 211 | } |
| 245 | 212 | |
| 246 | | −LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_longjmp, void *p_jmp_buf, void *func) |
| 247 | | −{ |
| 248 | | − s1->run_lj = p_longjmp; |
| 249 | | − s1->run_jb = p_jmp_buf; |
| 250 | | − if (func && s1->rc) |
| 251 | | − s1->rc->top_func = func; |
| 252 | | − return p_jmp_buf; |
| 253 | | −} |
| 254 | | − |
| 255 | | −LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc *func) |
| 256 | | −{ |
| 257 | | − s1->bt_func = func; |
| 258 | | −} |
| 259 | | − |
| 260 | 213 | /* launch the compiled program with the given arguments */ |
| 261 | 214 | LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) |
| 262 | 215 | { |
| 263 | 216 | int (*prog_main)(int, char **, char **), ret; |
| 217 | + const char *top_sym; |
| 264 | 218 | jmp_buf main_jb; |
| 265 | 219 | |
| 266 | 220 | #if defined(__APPLE__) || defined(__FreeBSD__) |
| @@ -276,20 +230,25 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 9 unmodified lines |
| 276 | 230 | if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, "main", 0, 1)) |
| 277 | 231 | return 0; |
| 278 | 232 | |
| 279 | | − tcc_add_support(s1, "runmain.o"); |
| 280 | | − tcc_add_symbol(s1, "__rt_longjmp", rt_longjmp); |
| 281 | | − s1->run_main = (s1->nostdlib ? "_start" : "_runmain"); |
| 233 | + tcc_add_symbol(s1, "__rt_exit", rt_exit); |
| 234 | + if (s1->nostdlib) { |
| 235 | + s1->run_main = top_sym = "_start"; |
| 236 | + } else { |
| 237 | + tcc_add_support(s1, "runmain.o"); |
| 238 | + s1->run_main = "_runmain"; |
| 239 | + top_sym = "main"; |
| 240 | + } |
| 282 | 241 | if (tcc_relocate(s1) < 0) |
| 283 | | − return -1; |
| 242 | + return 1; |
| 284 | 243 | |
| 285 | 244 | prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1); |
| 286 | 245 | if ((addr_t)-1 == (addr_t)prog_main) |
| 287 | | − return -1; |
| 246 | + return 1; |
| 288 | 247 | errno = 0; /* clean errno value */ |
| 289 | 248 | fflush(stdout); |
| 290 | 249 | fflush(stderr); |
| 291 | 250 | |
| 292 | | − ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, "main")); |
| 251 | + ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, top_sym)); |
| 293 | 252 | if (0 == ret) |
| 294 | 253 | ret = prog_main(argc, argv, envp); |
| 295 | 254 | else if (256 == ret) |
| @@ -344,8 +303,6 @@ static void cleanup_sections(TCCState *s1) · 48 unmodified lines |
| 344 | 303 | # define CONFIG_RUNMEM_RO 1 |
| 345 | 304 | #endif |
| 346 | 305 | |
| 347 | | −#define DEBUG_RUNMEN 0 |
| 348 | | − |
| 349 | 306 | /* relocate code. Return -1 on error, required size if ptr is NULL, |
| 350 | 307 | otherwise copy code into buffer passed by the caller */ |
| 351 | 308 | static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff) |
| @@ -367,16 +324,17 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff) · 15 unmodified lines |
| 367 | 324 | |
| 368 | 325 | offset = copy = 0; |
| 369 | 326 | mem = (addr_t)ptr; |
| 370 | | − |
| 371 | | −#if DEBUG_RUNMEN |
| 372 | | − if (mem) |
| 373 | | − fprintf(stderr, "X: <base> %p len %5x\n", |
| 374 | | − ptr, s1->run_size); |
| 375 | | −#endif |
| 376 | | − |
| 377 | 327 | redo: |
| 328 | + if (s1->verbose == 2 && copy) { |
| 329 | + printf(&"-----------------------------------------------------\n"[PTR_SIZE*2 - 8]); |
| 330 | + if (1 == copy) |
| 331 | + printf("memory %p len %05x\n", ptr, s1->run_size); |
| 332 | + } |
| 378 | 333 | if (s1->nb_errors) |
| 379 | 334 | return -1; |
| 335 | + if (copy == 2) |
| 336 | + return 0; |
| 337 | + |
| 380 | 338 | for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */ |
| 381 | 339 | n = 0; addr = 0; |
| 382 | 340 | for(i = 1; i < s1->nb_sections; i++) { |
| @@ -389,7 +347,9 @@ redo: · 6 unmodified lines |
| 389 | 347 | length = s->data_offset; |
| 390 | 348 | |
| 391 | 349 | if (copy) { /* final step: copy section data to memory */ |
| 392 | | − void *ptr; |
| 350 | + if (s1->verbose == 2) |
| 351 | + printf("%d: %-16s %p len %05x align %04x\n", |
| 352 | + k, s->name, (void*)s->sh_addr, length, s->sh_addralign); |
| 393 | 353 | if (addr == 0) |
| 394 | 354 | addr = s->sh_addr; |
| 395 | 355 | n = (s->sh_addr - addr) + length; |
| @@ -407,28 +367,25 @@ redo: · 11 unmodified lines |
| 407 | 367 | continue; |
| 408 | 368 | } |
| 409 | 369 | |
| 410 | | − align = s->sh_addralign - 1; |
| 370 | + align = s->sh_addralign; |
| 411 | 371 | if (++n == 1) { |
| 412 | 372 | #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 |
| 413 | 373 | /* To avoid that x86 processors would reload cached instructions |
| 414 | 374 | each time when data is written in the near, we need to make |
| 415 | 375 | sure that code and data do not share the same 64 byte unit */ |
| 416 | | − if (align < 63) |
| 417 | | − align = 63; |
| 376 | + if (align < 64) |
| 377 | + align = 64; |
| 418 | 378 | #endif |
| 419 | 379 | /* start new page for different permissions */ |
| 420 | 380 | if (CONFIG_RUNMEM_RO || k < 2) |
| 421 | | − align = PAGESIZE - 1; |
| 381 | + align = PAGESIZE; |
| 422 | 382 | } |
| 383 | + s->sh_addralign = align; |
| 384 | + |
| 423 | 385 | addr = k ? mem + ptr_diff : mem; |
| 424 | | − offset += -(addr + offset) & align; |
| 386 | + offset += -(addr + offset) & (align - 1); |
| 425 | 387 | s->sh_addr = mem ? addr + offset : 0; |
| 426 | 388 | offset += length; |
| 427 | | −#if DEBUG_RUNMEN |
| 428 | | − if (mem) |
| 429 | | − fprintf(stderr, "%d: %-16s %p len %5x align %04x\n", |
| 430 | | − k, s->name, (void*)s->sh_addr, length, align + 1); |
| 431 | | −#endif |
| 432 | 389 | } |
| 433 | 390 | if (copy) { /* set permissions */ |
| 434 | 391 | if (n == 0) /* no data */ |
| @@ -443,30 +400,25 @@ redo: · 8 unmodified lines |
| 443 | 400 | continue; |
| 444 | 401 | f = 3; /* change only SHF_EXECINSTR to rwx */ |
| 445 | 402 | } |
| 446 | | −#if DEBUG_RUNMEN |
| 447 | | − fprintf(stderr, "protect %3s %p len %5x\n", |
| 448 | | − &"rx\0r \0rw\0rwx"[f*3], |
| 449 | | − (void*)addr, (unsigned)((n + PAGESIZE-1) & ~(PAGESIZE-1))); |
| 450 | | −#endif |
| 403 | + n = (n + PAGESIZE-1) & ~(PAGESIZE-1); |
| 404 | + if (s1->verbose == 2) { |
| 405 | + printf("protect %3s %p len %05x\n", |
| 406 | + &"rx\0r \0rw\0rwx"[f*3], (void*)addr, (unsigned)n); |
| 407 | + } |
| 451 | 408 | if (protect_pages((void*)addr, n, f) < 0) |
| 452 | 409 | return tcc_error_noabort( |
| 453 | 410 | "mprotect failed (did you mean to configure --with-selinux?)"); |
| 454 | 411 | } |
| 455 | 412 | } |
| 456 | 413 | |
| 457 | | − if (0 == mem) { |
| 458 | | − offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1); |
| 459 | | −#ifndef HAVE_SELINUX |
| 460 | | − offset += PAGESIZE; /* extra space to align malloc memory start */ |
| 461 | | −#endif |
| 462 | | − return offset; |
| 463 | | − } |
| 414 | + if (0 == mem) |
| 415 | + return (offset + (PAGESIZE-1)) & ~(PAGESIZE-1); |
| 464 | 416 | |
| 465 | | − if (copy) { |
| 417 | + if (++copy == 2) { |
| 466 | 418 | /* remove local symbols and free sections except symtab */ |
| 467 | 419 | cleanup_symbols(s1); |
| 468 | 420 | cleanup_sections(s1); |
| 469 | | − return 0; |
| 421 | + goto redo; |
| 470 | 422 | } |
| 471 | 423 | |
| 472 | 424 | /* relocate symbols */ |
| @@ -478,7 +430,6 @@ redo: · 5 unmodified lines |
| 478 | 430 | relocate_plt(s1); |
| 479 | 431 | #endif |
| 480 | 432 | relocate_sections(s1); |
| 481 | | − copy = 1; |
| 482 | 433 | goto redo; |
| 483 | 434 | } |
| 484 | 435 | |
| @@ -546,6 +497,152 @@ static void win64_del_function_table(void *p) · 61 unmodified lines |
| 546 | 497 | } |
| 547 | 498 | #endif |
| 548 | 499 | |
| 500 | +static void bt_link(TCCState *s1) |
| 501 | +{ |
| 502 | +#ifdef CONFIG_TCC_BACKTRACE |
| 503 | + rt_context *rc; |
| 504 | + void *p; |
| 505 | + |
| 506 | + if (!s1->do_backtrace) |
| 507 | + return; |
| 508 | + rc = tcc_get_symbol(s1, "__rt_info"); |
| 509 | + if (!rc) |
| 510 | + return; |
| 511 | + rc->esym_start = (ElfW(Sym) *)(symtab_section->data); |
| 512 | + rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); |
| 513 | + rc->elf_str = (char *)symtab_section->link->data; |
| 514 | + if (PTR_SIZE == 8 && !s1->dwarf) |
| 515 | + rc->prog_base &= 0xffffffff00000000ULL; |
| 516 | +#ifdef CONFIG_TCC_BCHECK |
| 517 | + if (s1->do_bounds_check) { |
| 518 | + if ((p = tcc_get_symbol(s1, "__bound_init"))) |
| 519 | + ((void(*)(void*,int))p)(rc->bounds_start, 1); |
| 520 | + } |
| 521 | +#endif |
| 522 | + rc->next = g_rc, g_rc = rc, s1->rc = rc; |
| 523 | + if (0 == signal_set) |
| 524 | + set_exception_handler(), signal_set = 1; |
| 525 | +#endif |
| 526 | +} |
| 527 | + |
| 528 | +static void st_link(TCCState *s1) |
| 529 | +{ |
| 530 | + rt_wait_sem(); |
| 531 | + s1->next = g_s1, g_s1 = s1; |
| 532 | + bt_link(s1); |
| 533 | + rt_post_sem(); |
| 534 | +} |
| 535 | + |
| 536 | +/* remove 'el' from 'list' */ |
| 537 | +static void ptr_unlink(void *list, void *e, unsigned next) |
| 538 | +{ |
| 539 | + void **pp, **nn, *p; |
| 540 | + for (pp = list; !!(p = *pp); pp = nn) { |
| 541 | + nn = (void*)((char*)p + next); /* nn = &p->next; */ |
| 542 | + if (p == e) { |
| 543 | + *pp = *nn; |
| 544 | + break; |
| 545 | + } |
| 546 | + } |
| 547 | +} |
| 548 | + |
| 549 | +static void st_unlink(TCCState *s1) |
| 550 | +{ |
| 551 | + rt_wait_sem(); |
| 552 | +#ifdef CONFIG_TCC_BACKTRACE |
| 553 | + ptr_unlink(&g_rc, s1->rc, offsetof(rt_context, next)); |
| 554 | +#endif |
| 555 | + ptr_unlink(&g_s1, s1, offsetof(TCCState, next)); |
| 556 | + rt_post_sem(); |
| 557 | +} |
| 558 | + |
| 559 | +#ifdef _WIN32 |
| 560 | +# define GETTID() GetCurrentThreadId() |
| 561 | +#elif defined __linux__ |
| 562 | +# define GETTID() gettid() |
| 563 | +#elif 0 |
| 564 | +# define GETTID() 1234 // threads not supported |
| 565 | +#endif |
| 566 | + |
| 567 | +LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_jmp_buf, void *func, void *p_longjmp) |
| 568 | +{ |
| 569 | +#ifdef GETTID |
| 570 | + int tid = GETTID(); |
| 571 | + TCCState *s; |
| 572 | + rt_wait_sem(); |
| 573 | + for (s = g_s1; s; s = s->next) |
| 574 | + if (s->run_tid == tid) |
| 575 | + s->run_tid = -1; |
| 576 | + s1->run_tid = (int)tid; |
| 577 | + rt_post_sem(); |
| 578 | +#endif |
| 579 | + s1->run_lj = p_longjmp; |
| 580 | + s1->run_jb = p_jmp_buf; |
| 581 | +#ifdef CONFIG_TCC_BACKTRACE |
| 582 | + if (s1->rc) |
| 583 | + s1->rc->top_func = func; |
| 584 | +#endif |
| 585 | + return p_jmp_buf; |
| 586 | +} |
| 587 | + |
| 588 | +LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void *data, TCCBtFunc *func) |
| 589 | +{ |
| 590 | + s1->bt_func = func; |
| 591 | + s1->bt_data = data; |
| 592 | +} |
| 593 | + |
| 594 | +static TCCState *rt_find_state(rt_frame *f) |
| 595 | +{ |
| 596 | +#ifdef GETTID |
| 597 | + int tid = GETTID(); |
| 598 | + TCCState *s; |
| 599 | + for (s = g_s1; s; s = s->next) |
| 600 | + if (s->run_tid == tid) |
| 601 | + break; |
| 602 | + return s; |
| 603 | +#else |
| 604 | + TCCState *s; |
| 605 | + int level; |
| 606 | + addr_t pc; |
| 607 | + |
| 608 | + s = g_s1; |
| 609 | + if (NULL == s || NULL == s->next) { |
| 610 | + /* play it safe in the simple case when there is only one state */ |
| 611 | + return s; |
| 612 | + } |
| 613 | + for (level = 0; level < 8; ++level) { |
| 614 | + if (rt_get_caller_pc(&pc, f, level) < 0) |
| 615 | + break; |
| 616 | + for (s = g_s1; s; s = s->next) { |
| 617 | + if (pc >= (addr_t)s->run_ptr |
| 618 | + && pc < (addr_t)s->run_ptr + s->run_size) |
| 619 | + return s; |
| 620 | + } |
| 621 | + } |
| 622 | + return NULL; |
| 623 | +#endif |
| 624 | +} |
| 625 | + |
| 626 | +static void rt_exit(rt_frame *f, int code) |
| 627 | +{ |
| 628 | + TCCState *s; |
| 629 | + rt_wait_sem(); |
| 630 | + s = rt_find_state(f); |
| 631 | + rt_post_sem(); |
| 632 | + if (s && s->run_lj) { |
| 633 | + if (code == 0) |
| 634 | + code = 256; |
| 635 | + ((void(*)(void*,int))s->run_lj)(s->run_jb, code); |
| 636 | + } |
| 637 | + exit(code); |
| 638 | +} |
| 639 | + |
| 640 | +/* ------------------------------------------------------------- */ |
| 641 | +#else // if defined CONFIG_TCC_BACKTRACE_ONLY |
| 642 | +static void rt_exit(rt_frame *f, int code) |
| 643 | +{ |
| 644 | + exit(code); |
| 645 | +} |
| 549 | 646 | #endif //ndef CONFIG_TCC_BACKTRACE_ONLY |
| 550 | 647 | /* ------------------------------------------------------------- */ |
| 551 | 648 | #ifdef CONFIG_TCC_BACKTRACE |
| @@ -582,11 +679,17 @@ static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr) · 30 unmodified lines |
| 582 | 679 | return NULL; |
| 583 | 680 | } |
| 584 | 681 | |
| 682 | +typedef struct bt_info |
| 683 | +{ |
| 684 | + char file[100]; |
| 685 | + int line; |
| 686 | + char func[100]; |
| 687 | + addr_t func_pc; |
| 688 | +} bt_info; |
| 585 | 689 | |
| 586 | 690 | /* print the position in the source file of PC value 'pc' by reading |
| 587 | 691 | the stabs debug information */ |
| 588 | | −static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, |
| 589 | | − rt_context** prc, const char *msg, const char *skip) |
| 692 | +static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, bt_info *bi) |
| 590 | 693 | { |
| 591 | 694 | char func_name[128]; |
| 592 | 695 | addr_t func_addr, last_pc, pc; |
| @@ -595,15 +698,12 @@ static addr_t rt_printline (rt_context *rc, addr_t wanted_pc, · 2 unmodified lines |
| 595 | 698 | const char *str, *p; |
| 596 | 699 | Stab_Sym *sym; |
| 597 | 700 | |
| 598 | | −next: |
| 599 | 701 | func_name[0] = '\0'; |
| 600 | 702 | func_addr = 0; |
| 601 | 703 | incl_index = 0; |
| 602 | 704 | last_pc = (addr_t)-1; |
| 603 | 705 | last_line_num = 1; |
| 604 | 706 | last_incl_index = 0; |
| 605 | | − if (NULL == rc) |
| 606 | | − goto found; |
| 607 | 707 | |
| 608 | 708 | for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) { |
| 609 | 709 | str = rc->stab_str + sym->n_strx; |
| @@ -680,50 +780,15 @@ next: · 70 unmodified lines |
| 680 | 780 | break; |
| 681 | 781 | } |
| 682 | 782 | } |
| 683 | | − |
| 684 | | − func_name[0] = '\0'; |
| 685 | | − func_addr = 0; |
| 686 | | − last_incl_index = 0; |
| 687 | | − |
| 688 | | − /* we try symtab symbols (no line number info) */ |
| 689 | | − p = rt_elfsym(rc, wanted_pc, &func_addr); |
| 690 | | − if (p) { |
| 691 | | − pstrcpy(func_name, sizeof func_name, p); |
| 692 | | − goto found; |
| 693 | | − } |
| 694 | | − rc = rc->next; |
| 695 | | − goto next; |
| 696 | | − |
| 783 | + last_incl_index = 0, func_name[0] = 0, func_addr = 0; |
| 697 | 784 | found: |
| 698 | 785 | i = last_incl_index; |
| 699 | | − str = NULL; |
| 700 | 786 | if (i > 0) { |
| 701 | | − str = incl_files[--i]; |
| 702 | | − if (skip[0] && strstr(str, skip)) |
| 703 | | − return (addr_t)-1; |
| 704 | | − } |
| 705 | | − if (rc && rc->s1 && rc->s1->bt_func) { |
| 706 | | − rc->s1->bt_func((void*)wanted_pc, str, last_line_num, func_name[0] ? func_name : NULL); |
| 707 | | − } else { |
| 708 | | − if (str) |
| 709 | | − rt_printf("%s:%d: ", str, last_line_num); |
| 710 | | − else |
| 711 | | − rt_printf("%08llx : ", (long long)wanted_pc); |
| 712 | | − rt_printf("%s %s", msg, func_name[0] ? func_name : "???"); |
| 713 | | − } |
| 714 | | −#if 0 |
| 715 | | − if (--i >= 0) { |
| 716 | | − rt_printf(" (included from "); |
| 717 | | − for (;;) { |
| 718 | | − rt_printf("%s", incl_files[i]); |
| 719 | | − if (--i < 0) |
| 720 | | − break; |
| 721 | | − rt_printf(", "); |
| 722 | | − } |
| 723 | | − rt_printf(")"); |
| 787 | + pstrcpy(bi->file, sizeof bi->file, incl_files[--i]); |
| 788 | + bi->line = last_line_num; |
| 724 | 789 | } |
| 725 | | −#endif |
| 726 | | − *prc = rc; |
| 790 | + pstrcpy(bi->func, sizeof bi->func, func_name); |
| 791 | + bi->func_pc = func_addr; |
| 727 | 792 | return func_addr; |
| 728 | 793 | } |
| 729 | 794 | |
| @@ -793,8 +858,7 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end) · 63 unmodified lines |
| 793 | 858 | return retval; |
| 794 | 859 | } |
| 795 | 860 | |
| 796 | | −static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, |
| 797 | | − rt_context** prc, const char *msg, const char *skip) |
| 861 | +static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, bt_info *bi) |
| 798 | 862 | { |
| 799 | 863 | unsigned char *ln; |
| 800 | 864 | unsigned char *cp; |
| @@ -834,12 +898,10 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, · 33 unmodified lines |
| 834 | 898 | char *filename; |
| 835 | 899 | char *function; |
| 836 | 900 | |
| 837 | | −next: |
| 838 | 901 | filename = NULL; |
| 902 | + function = NULL; |
| 839 | 903 | func_addr = 0; |
| 840 | 904 | line = 0; |
| 841 | | − if (NULL == rc) |
| 842 | | − goto found; |
| 843 | 905 | |
| 844 | 906 | ln = rc->dwarf_line; |
| 845 | 907 | while (ln < rc->dwarf_line_end) { |
| @@ -1070,44 +1132,28 @@ check_pc: · 224 unmodified lines |
| 1070 | 1132 | next_line: |
| 1071 | 1133 | ln = end; |
| 1072 | 1134 | } |
| 1073 | | − |
| 1074 | | − filename = NULL; |
| 1075 | | − func_addr = 0; |
| 1076 | | − /* we try symtab symbols (no line number info) */ |
| 1077 | | − function = rt_elfsym(rc, wanted_pc, &func_addr); |
| 1078 | | − if (function) |
| 1079 | | − goto found; |
| 1080 | | − rc = rc->next; |
| 1081 | | − goto next; |
| 1082 | | − |
| 1135 | + filename = function = NULL, func_addr = 0; |
| 1083 | 1136 | found: |
| 1084 | | − if (rc && rc->s1 && rc->s1->bt_func) { |
| 1085 | | − rc->s1->bt_func((void*)wanted_pc, filename, line, function); |
| 1086 | | − } else { |
| 1087 | | − if (filename) { |
| 1088 | | − if (skip[0] && strstr(filename, skip)) |
| 1089 | | − return (addr_t)-1; |
| 1090 | | − rt_printf("%s:%d: ", filename, line); |
| 1091 | | − } |
| 1092 | | − else |
| 1093 | | − rt_printf("0x%08llx : ", (long long)wanted_pc); |
| 1094 | | − rt_printf("%s %s", msg, function ? function : "???"); |
| 1095 | | − } |
| 1096 | | − *prc = rc; |
| 1137 | + if (filename) |
| 1138 | + pstrcpy(bi->file, sizeof bi->file, filename), bi->line = line; |
| 1139 | + if (function) |
| 1140 | + pstrcpy(bi->func, sizeof bi->func, function); |
| 1141 | + bi->func_pc = func_addr; |
| 1097 | 1142 | return (addr_t)func_addr; |
| 1098 | 1143 | } |
| 1099 | 1144 | /* ------------------------------------------------------------- */ |
| 1100 | 1145 | #ifndef CONFIG_TCC_BACKTRACE_ONLY |
| 1101 | 1146 | static |
| 1102 | 1147 | #endif |
| 1103 | | −int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap) |
| 1148 | +int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap) |
| 1104 | 1149 | { |
| 1105 | | − rt_context *rc, *rd; |
| 1106 | | − addr_t pc = 0; |
| 1107 | | − char skip[100]; |
| 1150 | + rt_context *rc, *rc2; |
| 1151 | + addr_t pc; |
| 1152 | + char skip[40], msg[200]; |
| 1108 | 1153 | int i, level, ret, n, one; |
| 1109 | 1154 | const char *a, *b; |
| 1110 | | − addr_t (*printline)(rt_context*, addr_t, rt_context**, const char*, const char*); |
| 1155 | + bt_info bi; |
| 1156 | + addr_t (*getinfo)(rt_context*, addr_t, bt_info*); |
| 1111 | 1157 | |
| 1112 | 1158 | skip[0] = 0; |
| 1113 | 1159 | /* If fmt is like "^file.c^..." then skip calls from 'file.c' */ |
| @@ -1119,41 +1165,73 @@ int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap) · 5 unmodified lines |
| 1119 | 1165 | /* hack for bcheck.c:dprintf(): one level, no newline */ |
| 1120 | 1166 | if (fmt[0] == '\001') |
| 1121 | 1167 | ++fmt, one = 1; |
| 1168 | + vsnprintf(msg, sizeof msg, fmt, ap); |
| 1122 | 1169 | |
| 1123 | 1170 | rt_wait_sem(); |
| 1124 | 1171 | rc = g_rc; |
| 1125 | | − printline = rt_printline, n = 6; |
| 1172 | + getinfo = rt_printline, n = 6; |
| 1126 | 1173 | if (rc) { |
| 1127 | 1174 | if (rc->dwarf) |
| 1128 | | − printline = rt_printline_dwarf; |
| 1175 | + getinfo = rt_printline_dwarf; |
| 1129 | 1176 | if (rc->num_callers) |
| 1130 | 1177 | n = rc->num_callers; |
| 1131 | 1178 | } |
| 1179 | + |
| 1132 | 1180 | for (i = level = 0; level < n; i++) { |
| 1133 | 1181 | ret = rt_get_caller_pc(&pc, f, i); |
| 1134 | | − if (ret != -1) { |
| 1135 | | − pc = printline(rc, pc, &rd, level ? "by" : "at", skip); |
| 1136 | | − if (pc == (addr_t)-1) |
| 1137 | | − continue; |
| 1182 | + if (ret == -1) |
| 1183 | + break; |
| 1184 | + memset(&bi, 0, sizeof bi); |
| 1185 | + for (rc2 = rc; rc2; rc2 = rc2->next) { |
| 1186 | + if (getinfo(rc2, pc, &bi)) |
| 1187 | + break; |
| 1188 | + /* we try symtab symbols (no line number info) */ |
| 1189 | + if (!!(a = rt_elfsym(rc2, pc, &bi.func_pc))) { |
| 1190 | + pstrcpy(bi.func, sizeof bi.func, a); |
| 1191 | + break; |
| 1192 | + } |
| 1193 | + } |
| 1194 | + //fprintf(stderr, "%d rc %p %p\n", i, (void*)pcfunc, (void*)pc); |
| 1195 | + if (skip[0] && strstr(bi.file, skip)) |
| 1196 | + continue; |
| 1197 | +#ifndef CONFIG_TCC_BACKTRACE_ONLY |
| 1198 | + { |
| 1199 | + TCCState *s = rt_find_state(f); |
| 1200 | + if (s && s->bt_func) { |
| 1201 | + ret = s->bt_func( |
| 1202 | + s->bt_data, |
| 1203 | + (void*)pc, |
| 1204 | + bi.file[0] ? bi.file : NULL, |
| 1205 | + bi.line, |
| 1206 | + bi.func[0] ? bi.func : NULL, |
| 1207 | + level == 0 ? msg : NULL |
| 1208 | + ); |
| 1209 | + if (ret == 0) |
| 1210 | + break; |
| 1211 | + goto check_break; |
| 1212 | + } |
| 1213 | + } |
| 1214 | +#endif |
| 1215 | + if (bi.file[0]) { |
| 1216 | + rt_printf("%s:%d", bi.file, bi.line); |
| 1217 | + } else { |
| 1218 | + rt_printf("0x%08llx", (long long)pc); |
| 1138 | 1219 | } |
| 1220 | + rt_printf(": %s %s", level ? "by" : "at", bi.func[0] ? bi.func : "???"); |
| 1139 | 1221 | if (level == 0) { |
| 1140 | | − if (rd && rd->s1 && rd->s1->bt_func) |
| 1222 | + rt_printf(": %s", msg); |
| 1223 | + if (one) |
| 1141 | 1224 | break; |
| 1142 | | − if (ret != -1) |
| 1143 | | − rt_printf(": "); |
| 1144 | | − if (msg) |
| 1145 | | − rt_printf("%s: ", msg); |
| 1146 | | − rt_vprintf(fmt, ap); |
| 1147 | | − } else if (ret == -1) |
| 1148 | | − break; |
| 1149 | | − if (one) |
| 1150 | | − break; |
| 1225 | + } |
| 1151 | 1226 | rt_printf("\n"); |
| 1152 | | − if (ret == -1 || (rd && pc == (addr_t)rd->top_func && pc)) |
| 1227 | + |
| 1228 | + check_break: |
| 1229 | + if (rc2 |
| 1230 | + && bi.func_pc |
| 1231 | + && bi.func_pc == (addr_t)rc2->top_func) |
| 1153 | 1232 | break; |
| 1154 | 1233 | ++level; |
| 1155 | 1234 | } |
| 1156 | | − |
| 1157 | 1235 | rt_post_sem(); |
| 1158 | 1236 | return 0; |
| 1159 | 1237 | } |
| @@ -1161,49 +1239,14 @@ int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap) · 1 unmodified line |
| 1161 | 1239 | /* emit a run time error at position 'pc' */ |
| 1162 | 1240 | static int rt_error(rt_frame *f, const char *fmt, ...) |
| 1163 | 1241 | { |
| 1164 | | − va_list ap; |
| 1165 | | − int ret; |
| 1242 | + va_list ap; char msg[200]; int ret; |
| 1166 | 1243 | va_start(ap, fmt); |
| 1167 | | − ret = __rt_dump(f, "RUNTIME ERROR", fmt, ap); |
| 1244 | + snprintf(msg, sizeof msg, "RUNTIME ERROR: %s", fmt); |
| 1245 | + ret = _tcc_backtrace(f, msg, ap); |
| 1168 | 1246 | va_end(ap); |
| 1169 | 1247 | return ret; |
| 1170 | 1248 | } |
| 1171 | 1249 | |
| 1172 | | −static TCCState *rt_find_state(rt_frame *f) |
| 1173 | | −{ |
| 1174 | | − TCCState *s; |
| 1175 | | − int level; |
| 1176 | | − addr_t pc; |
| 1177 | | − |
| 1178 | | − rt_wait_sem(); |
| 1179 | | − for (s = g_s1; s; s = s->next) { |
| 1180 | | − if (0 == s->run_lj) |
| 1181 | | − continue; |
| 1182 | | − for (level = 0; level < 8; ++level) { |
| 1183 | | − if (rt_get_caller_pc(&pc, f, level) < 0) |
| 1184 | | − break; |
| 1185 | | − if (pc >= (addr_t)s->run_ptr |
| 1186 | | − && pc < (addr_t)s->run_ptr + s->run_size) |
| 1187 | | − goto found; |
| 1188 | | − } |
| 1189 | | − } |
| 1190 | | −found: |
| 1191 | | − rt_post_sem(); |
| 1192 | | − //fprintf(stderr, "\nrt_state found %s %p %p\n", s ? "YES" : "NO", s, s->rc->top_func), fflush(stderr); |
| 1193 | | − return s; |
| 1194 | | −} |
| 1195 | | − |
| 1196 | | −static void rt_longjmp(rt_frame *f, int code) |
| 1197 | | −{ |
| 1198 | | − TCCState *s = rt_find_state(f); |
| 1199 | | − if (s && s->run_lj) { |
| 1200 | | − if (code == 0) |
| 1201 | | − code = 256; |
| 1202 | | − ((void(*)(void*,int))s->run_lj)(s->run_jb, code); |
| 1203 | | − } |
| 1204 | | − exit(code); |
| 1205 | | −} |
| 1206 | | − |
| 1207 | 1250 | /* ------------------------------------------------------------- */ |
| 1208 | 1251 | |
| 1209 | 1252 | #ifndef _WIN32 |
| @@ -1338,8 +1381,13 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc) · 128 unmodified lines |
| 1338 | 1381 | rt_error(&f, "caught signal %d", signum); |
| 1339 | 1382 | break; |
| 1340 | 1383 | } |
| 1341 | | − set_exception_handler(); |
| 1342 | | − rt_longjmp(&f, 255); |
| 1384 | + { |
| 1385 | + sigset_t s; |
| 1386 | + sigemptyset(&s); |
| 1387 | + sigaddset(&s, signum); |
| 1388 | + sigprocmask(SIG_UNBLOCK, &s, NULL); |
| 1389 | + } |
| 1390 | + rt_exit(&f, 255); |
| 1343 | 1391 | } |
| 1344 | 1392 | |
| 1345 | 1393 | #ifndef SA_SIGINFO |
| @@ -1353,12 +1401,11 @@ static void set_exception_handler(void) · 7 unmodified lines |
| 1353 | 1401 | /* install TCC signal handlers to print debug info on fatal |
| 1354 | 1402 | runtime errors */ |
| 1355 | 1403 | sigemptyset (&sigact.sa_mask); |
| 1356 | | − sigact.sa_flags = SA_SIGINFO | SA_RESETHAND | SA_NODEFER; |
| 1404 | + sigact.sa_flags = SA_SIGINFO; //| SA_RESETHAND; |
| 1357 | 1405 | #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes |
| 1358 | 1406 | sigact.sa_flags |= SA_ONSTACK; |
| 1359 | 1407 | #endif |
| 1360 | 1408 | sigact.sa_sigaction = sig_error; |
| 1361 | | − sigemptyset(&sigact.sa_mask); |
| 1362 | 1409 | sigaction(SIGFPE, &sigact, NULL); |
| 1363 | 1410 | sigaction(SIGILL, &sigact, NULL); |
| 1364 | 1411 | sigaction(SIGSEGV, &sigact, NULL); |
| @@ -1406,7 +1453,7 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) · 41 unmodified lines |
| 1406 | 1453 | rt_error(&f, "caught exception %08x", code); |
| 1407 | 1454 | break; |
| 1408 | 1455 | } |
| 1409 | | − rt_longjmp(&f, 255); |
| 1456 | + rt_exit(&f, 255); |
| 1410 | 1457 | return EXCEPTION_EXECUTE_HANDLER; |
| 1411 | 1458 | } |
| 1412 | 1459 | |
| @@ -1506,6 +1553,14 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level) · 93 unmodified lines |
| 1506 | 1553 | } |
| 1507 | 1554 | |
| 1508 | 1555 | #endif |
| 1556 | +#else // for runmain.c:exit(); when CONFIG_TCC_BACKTRACE == 0 */ |
| 1557 | +static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level) |
| 1558 | +{ |
| 1559 | + if (level) |
| 1560 | + return -1; |
| 1561 | + *paddr = f->ip; |
| 1562 | + return 0; |
| 1563 | +} |
| 1509 | 1564 | #endif /* CONFIG_TCC_BACKTRACE */ |
| 1510 | 1565 | /* ------------------------------------------------------------- */ |
| 1511 | 1566 | #ifdef CONFIG_TCC_STATIC |