Merge branch 'mob' of git://repo.or.cz/tinycc into mypatch
[tinycc.git] / tccrun.c
blob494dd59f27bd6b35b357e98ec7c454597439b1e6
1 /*
2 * TCC - Tiny C Compiler - Support for -run switch
4 * Copyright (c) 2001-2004 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "tcc.h"
23 /* only native compiler supports -run */
24 #ifdef TCC_IS_NATIVE
26 #ifndef _WIN32
27 # include <sys/mman.h>
28 #endif
30 #ifdef CONFIG_TCC_BACKTRACE
31 static void set_exception_handler(void);
32 #ifdef _WIN32
33 static DWORD s1_for_run_idx;
34 void set_s1_for_run(TCCState *s)
36 if (!s1_for_run_idx)
37 s1_for_run_idx = TlsAlloc();
38 TlsSetValue(s1_for_run_idx, s);
40 #define get_s1_for_run() ((TCCState*)TlsGetValue(s1_for_run_idx))
41 #else
42 /* XXX: add tls support for linux */
43 static TCCState *s1_for_run;
44 #define set_s1_for_run(s) (s1_for_run = s)
45 #define get_s1_for_run() s1_for_run
46 #endif
47 #endif
49 static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length);
50 static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
52 #ifdef _WIN64
53 static void *win64_add_function_table(TCCState *s1);
54 static void win64_del_function_table(void *);
55 #endif
57 /* ------------------------------------------------------------- */
58 /* Do all relocations (needed before using tcc_get_symbol())
59 Returns -1 on error. */
61 LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
63 int size;
64 addr_t ptr_diff = 0;
66 if (TCC_RELOCATE_AUTO != ptr)
67 return tcc_relocate_ex(s1, ptr, 0);
69 size = tcc_relocate_ex(s1, NULL, 0);
70 if (size < 0)
71 return -1;
73 #ifdef HAVE_SELINUX
75 /* Using mmap instead of malloc */
76 void *prx;
77 char tmpfname[] = "/tmp/.tccrunXXXXXX";
78 int fd = mkstemp(tmpfname);
79 unlink(tmpfname);
80 ftruncate(fd, size);
82 ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
83 prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
84 if (ptr == MAP_FAILED || prx == MAP_FAILED)
85 tcc_error("tccrun: could not map memory");
86 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
87 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx);
88 ptr_diff = (char*)prx - (char*)ptr;
89 close(fd);
91 #else
92 ptr = tcc_malloc(size);
93 #endif
94 tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */
95 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
96 return 0;
99 ST_FUNC void tcc_run_free(TCCState *s1)
101 int i;
103 for (i = 0; i < s1->nb_runtime_mem; ++i) {
104 #ifdef HAVE_SELINUX
105 unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
106 munmap(s1->runtime_mem[i++], size);
107 munmap(s1->runtime_mem[i], size);
108 #else
109 #ifdef _WIN64
110 win64_del_function_table(*(void**)s1->runtime_mem[i]);
111 #endif
112 tcc_free(s1->runtime_mem[i]);
113 #endif
115 tcc_free(s1->runtime_mem);
116 if (get_s1_for_run() == s1)
117 set_s1_for_run(NULL);
120 /* launch the compiled program with the given arguments */
121 LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
123 /* PE target overwrites runtime_main */
124 #ifndef TCC_TARGET_PE
125 typedef void (*init_array_func)(int, char **, char **);
126 typedef void (*fini_array_func)(void);
127 init_array_func *__init_array_start;
128 init_array_func *__init_array_end;
129 fini_array_func *__fini_array_start;
130 fini_array_func *__fini_array_end;
131 #endif
132 int i;
133 int ret;
134 int (*prog_main)(int, char **);
136 s1->runtime_main = s1->nostdlib ? "_start" : "main";
137 if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
138 return 0;
139 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
140 return -1;
141 prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
143 #ifdef CONFIG_TCC_BACKTRACE
144 if (s1->do_debug) {
145 set_exception_handler();
146 s1->rt_prog_main = prog_main;
147 /* set global state pointer for exception handlers*/
148 set_s1_for_run(s1);
150 #endif
152 errno = 0; /* clean errno value */
154 #ifdef CONFIG_TCC_BCHECK
155 if (s1->do_bounds_check)
156 /* set error function */
157 s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
158 #endif
160 #ifndef TCC_TARGET_PE
161 __init_array_start = tcc_get_symbol_err(s1, "__init_array_start");
162 __init_array_end = tcc_get_symbol_err(s1, "__init_array_end");
163 __fini_array_start = tcc_get_symbol_err(s1, "__fini_array_start");
164 __fini_array_end = tcc_get_symbol_err(s1, "__fini_array_end");
166 if (__init_array_start && __init_array_end) {
167 i = 0;
168 while (&__init_array_start[i] != __init_array_end)
169 (*__init_array_start[i++])(argc, argv, environ);
171 #endif
173 ret = (*prog_main)(argc, argv);
175 #ifndef TCC_TARGET_PE
176 if (__fini_array_start && __fini_array_end) {
177 i = 0;
178 while (&__fini_array_end[i] != __fini_array_start)
179 (*__fini_array_end[--i])();
181 #endif
182 return ret;
185 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
186 /* To avoid that x86 processors would reload cached instructions
187 each time when data is written in the near, we need to make
188 sure that code and data do not share the same 64 byte unit */
189 #define RUN_SECTION_ALIGNMENT 63
190 #else
191 #define RUN_SECTION_ALIGNMENT 0
192 #endif
194 /* relocate code. Return -1 on error, required size if ptr is NULL,
195 otherwise copy code into buffer passed by the caller */
196 static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
198 Section *s;
199 unsigned offset, length, align, max_align, i, k, f;
200 addr_t mem, addr;
202 if (NULL == ptr) {
203 s1->nb_errors = 0;
204 #ifdef TCC_TARGET_PE
205 pe_output_file(s1, NULL);
206 #else
207 tcc_add_runtime(s1);
208 resolve_common_syms(s1);
209 build_got_entries(s1);
210 #endif
211 if (s1->nb_errors)
212 return -1;
215 offset = max_align = 0, mem = (addr_t)ptr;
216 #ifdef _WIN64
217 offset += sizeof (void*); /* space for function_table pointer */
218 #endif
219 for (k = 0; k < 2; ++k) {
220 f = 0, addr = k ? mem : mem + ptr_diff;
221 for(i = 1; i < s1->nb_sections; i++) {
222 s = s1->sections[i];
223 if (0 == (s->sh_flags & SHF_ALLOC))
224 continue;
225 if (k != !(s->sh_flags & SHF_EXECINSTR))
226 continue;
227 align = s->sh_addralign - 1;
228 if (++f == 1 && align < RUN_SECTION_ALIGNMENT)
229 align = RUN_SECTION_ALIGNMENT;
230 if (max_align < align)
231 max_align = align;
232 offset += -(addr + offset) & align;
233 s->sh_addr = mem ? addr + offset : 0;
234 offset += s->data_offset;
235 #if 0
236 if (mem)
237 printf("%-16s %p len %04x align %2d\n",
238 s->name, (void*)s->sh_addr, (unsigned)s->data_offset, align + 1);
239 #endif
243 /* relocate symbols */
244 relocate_syms(s1, s1->symtab, 1);
245 if (s1->nb_errors)
246 return -1;
248 if (0 == mem)
249 return offset + max_align;
251 #ifdef TCC_TARGET_PE
252 s1->pe_imagebase = mem;
253 #endif
255 /* relocate each section */
256 for(i = 1; i < s1->nb_sections; i++) {
257 s = s1->sections[i];
258 if (s->reloc)
259 relocate_section(s1, s);
261 #ifndef TCC_TARGET_PE
262 relocate_plt(s1);
263 #endif
265 for(i = 1; i < s1->nb_sections; i++) {
266 s = s1->sections[i];
267 if (0 == (s->sh_flags & SHF_ALLOC))
268 continue;
269 length = s->data_offset;
270 ptr = (void*)s->sh_addr;
271 if (s->sh_flags & SHF_EXECINSTR)
272 ptr = (char*)((addr_t)ptr - ptr_diff);
273 if (NULL == s->data || s->sh_type == SHT_NOBITS)
274 memset(ptr, 0, length);
275 else
276 memcpy(ptr, s->data, length);
277 /* mark executable sections as executable in memory */
278 if (s->sh_flags & SHF_EXECINSTR)
279 set_pages_executable(s1, (char*)((addr_t)ptr + ptr_diff), length);
282 #ifdef _WIN64
283 *(void**)mem = win64_add_function_table(s1);
284 #endif
286 return 0;
289 /* ------------------------------------------------------------- */
290 /* allow to run code in memory */
292 static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length)
294 #ifdef _WIN32
295 unsigned long old_protect;
296 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
297 #else
298 void __clear_cache(void *beginning, void *end);
299 # ifndef HAVE_SELINUX
300 addr_t start, end;
301 # ifndef PAGESIZE
302 # define PAGESIZE 4096
303 # endif
304 start = (addr_t)ptr & ~(PAGESIZE - 1);
305 end = (addr_t)ptr + length;
306 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
307 if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
308 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
309 # endif
310 # if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
311 __clear_cache(ptr, (char *)ptr + length);
312 # endif
313 #endif
316 #ifdef _WIN64
317 static void *win64_add_function_table(TCCState *s1)
319 void *p = NULL;
320 if (s1->uw_pdata) {
321 p = (void*)s1->uw_pdata->sh_addr;
322 RtlAddFunctionTable(
323 (RUNTIME_FUNCTION*)p,
324 s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
325 s1->pe_imagebase
327 s1->uw_pdata = NULL;
329 return p;
332 static void win64_del_function_table(void *p)
334 if (p) {
335 RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p);
338 #endif
340 /* ------------------------------------------------------------- */
341 #ifdef CONFIG_TCC_BACKTRACE
343 #define INCLUDE_STACK_SIZE 32
344 static int rt_vprintf(const char *fmt, va_list ap)
346 int ret = vfprintf(stderr, fmt, ap);
347 fflush(stderr);
348 return ret;
351 static int rt_printf(const char *fmt, ...)
353 va_list ap;
354 int r;
355 va_start(ap, fmt);
356 r = rt_vprintf(fmt, ap);
357 va_end(ap);
358 return r;
361 /* print the position in the source file of PC value 'pc' by reading
362 the stabs debug information */
363 static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
365 char func_name[128];
366 addr_t func_addr, last_pc, pc;
367 const char *incl_files[INCLUDE_STACK_SIZE];
368 int incl_index, last_incl_index, len, last_line_num, i;
369 const char *str, *p;
371 ElfW(Sym) *esym_start = NULL, *esym_end = NULL, *esym;
372 Stab_Sym *stab_sym = NULL, *stab_sym_end = NULL, *sym;
373 char *stab_str = NULL;
374 char *elf_str = NULL;
376 func_name[0] = '\0';
377 func_addr = 0;
378 incl_index = 0;
379 last_pc = (addr_t)-1;
380 last_line_num = 1;
381 last_incl_index = 0;
383 if (stab_section) {
384 stab_sym = (Stab_Sym *)stab_section->data;
385 stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
386 stab_str = (char *) stab_section->link->data;
388 if (symtab_section) {
389 esym_start = (ElfW(Sym) *)(symtab_section->data);
390 esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
391 elf_str = (char *) symtab_section->link->data;
394 for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
395 str = stab_str + sym->n_strx;
396 pc = sym->n_value;
398 switch(sym->n_type) {
399 case N_SLINE:
400 if (func_addr)
401 goto rel_pc;
402 case N_SO:
403 case N_SOL:
404 goto abs_pc;
405 case N_FUN:
406 if (sym->n_strx == 0) /* end of function */
407 goto rel_pc;
408 abs_pc:
409 if (sizeof pc == 8)
410 /* Stab_Sym.n_value is only 32bits */
411 pc |= wanted_pc & 0xffffffff00000000ULL;
412 break;
413 rel_pc:
414 pc += func_addr;
415 break;
418 if (pc > wanted_pc && wanted_pc > last_pc)
419 goto found;
421 switch(sym->n_type) {
422 /* function start or end */
423 case N_FUN:
424 if (sym->n_strx == 0)
425 goto reset_func;
426 p = strchr(str, ':');
427 if (0 == p || (len = p - str + 1, len > sizeof func_name))
428 len = sizeof func_name;
429 pstrcpy(func_name, len, str);
430 func_addr = pc;
431 break;
432 /* line number info */
433 case N_SLINE:
434 last_pc = pc;
435 last_line_num = sym->n_desc;
436 last_incl_index = incl_index;
437 if (pc == wanted_pc)
438 goto found;
439 break;
440 /* include files */
441 case N_BINCL:
442 if (incl_index < INCLUDE_STACK_SIZE)
443 incl_files[incl_index++] = str;
444 break;
445 case N_EINCL:
446 if (incl_index > 1)
447 incl_index--;
448 break;
449 /* start/end of translation unit */
450 case N_SO:
451 incl_index = 0;
452 if (sym->n_strx) {
453 /* do not add path */
454 len = strlen(str);
455 if (len > 0 && str[len - 1] != '/')
456 incl_files[incl_index++] = str;
458 reset_func:
459 func_name[0] = '\0';
460 func_addr = 0;
461 last_pc = (addr_t)-1;
462 break;
463 /* alternative file name (from #line or #include directives) */
464 case N_SOL:
465 if (incl_index)
466 incl_files[incl_index-1] = str;
467 break;
471 /* we try symtab symbols (no line number info) */
472 for (esym = esym_start + 1; esym < esym_end; ++esym) {
473 int type = ELFW(ST_TYPE)(esym->st_info);
474 if (type == STT_FUNC || type == STT_GNU_IFUNC) {
475 if (wanted_pc >= esym->st_value &&
476 wanted_pc < esym->st_value + esym->st_size) {
477 pstrcpy(func_name, sizeof(func_name),
478 elf_str + esym->st_name);
479 func_addr = esym->st_value;
480 last_incl_index = 0;
481 goto found;
485 /* did not find any info: */
486 rt_printf("%s %p ???", msg, (void*)wanted_pc);
487 return 0;
489 found:
490 i = last_incl_index;
491 if (i > 0)
492 rt_printf("%s:%d: ", incl_files[--i], last_line_num);
493 rt_printf("%s %p", msg, (void*)wanted_pc);
494 if (func_name[0] != '\0')
495 rt_printf(" %s()", func_name);
496 if (--i >= 0) {
497 rt_printf(" (included from ");
498 for (;;) {
499 rt_printf("%s", incl_files[i]);
500 if (--i < 0)
501 break;
502 rt_printf(", ");
504 rt_printf(")");
506 return func_addr;
509 typedef struct rt_context {
510 addr_t ip, fp, sp, pc;
511 } rt_context;
513 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
515 /* emit a run time error at position 'pc' */
516 static void rt_error(rt_context *rc, const char *fmt, ...)
518 va_list ap;
519 addr_t pc;
520 int i;
521 TCCState *s1;
523 s1 = get_s1_for_run();
524 if (*fmt == ' ') {
525 if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
526 fmt = *s1->rt_bound_error_msg;
527 else
528 ++fmt;
531 rt_printf("Runtime error: ");
532 va_start(ap, fmt);
533 rt_vprintf(fmt, ap);
534 va_end(ap);
535 rt_printf("\n");
537 if (!s1)
538 return;
540 for(i=0; i<s1->rt_num_callers; i++) {
541 if (rt_get_caller_pc(&pc, rc, i) < 0)
542 break;
543 pc = rt_printline(s1, pc, i ? "by" : "at");
544 rt_printf("\n");
545 if (pc == (addr_t)s1->rt_prog_main && pc)
546 break;
550 /* ------------------------------------------------------------- */
552 #ifndef _WIN32
553 # include <signal.h>
554 # ifndef __OpenBSD__
555 # include <sys/ucontext.h>
556 # endif
557 #else
558 # define ucontext_t CONTEXT
559 #endif
561 /* translate from ucontext_t* to internal rt_context * */
562 static void rt_getcontext(ucontext_t *uc, rt_context *rc)
564 #if defined _WIN64
565 rc->ip = uc->Rip;
566 rc->fp = uc->Rbp;
567 rc->sp = uc->Rsp;
568 #elif defined _WIN32
569 rc->ip = uc->Eip;
570 rc->fp = uc->Ebp;
571 rc->sp = uc->Esp;
572 #elif defined __i386__
573 # if defined(__APPLE__)
574 rc->ip = uc->uc_mcontext->__ss.__eip;
575 rc->fp = uc->uc_mcontext->__ss.__ebp;
576 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
577 rc->ip = uc->uc_mcontext.mc_eip;
578 rc->fp = uc->uc_mcontext.mc_ebp;
579 # elif defined(__dietlibc__)
580 rc->ip = uc->uc_mcontext.eip;
581 rc->fp = uc->uc_mcontext.ebp;
582 # elif defined(__NetBSD__)
583 rc->ip = uc->uc_mcontext.__gregs[_REG_EIP];
584 rc->fp = uc->uc_mcontext.__gregs[_REG_EBP];
585 # elif defined(__OpenBSD__)
586 rc->ip = uc->sc_eip;
587 rc->fp = uc->sc_ebp;
588 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
589 rc->ip = uc->uc_mcontext.gregs[EIP];
590 rc->fp = uc->uc_mcontext.gregs[EBP];
591 # else
592 rc->ip = uc->uc_mcontext.gregs[REG_EIP];
593 rc->fp = uc->uc_mcontext.gregs[REG_EBP];
594 # endif
595 #elif defined(__x86_64__)
596 # if defined(__APPLE__)
597 rc->ip = uc->uc_mcontext->__ss.__rip;
598 rc->fp = uc->uc_mcontext->__ss.__rbp;
599 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
600 rc->ip = uc->uc_mcontext.mc_rip;
601 rc->fp = uc->uc_mcontext.mc_rbp;
602 # elif defined(__NetBSD__)
603 rc->ip = uc->uc_mcontext.__gregs[_REG_RIP];
604 rc->fp = uc->uc_mcontext.__gregs[_REG_RBP];
605 # else
606 rc->ip = uc->uc_mcontext.gregs[REG_RIP];
607 rc->fp = uc->uc_mcontext.gregs[REG_RBP];
608 # endif
609 #elif defined(__arm__)
610 rc->ip = uc->uc_mcontext.arm_pc;
611 rc->fp = uc->uc_mcontext.arm_fp;
612 rc->sp = uc->uc_mcontext.arm_sp;
613 #elif defined(__aarch64__)
614 rc->ip = uc->uc_mcontext.pc;
615 rc->fp = uc->uc_mcontext.regs[29];
616 #endif
619 /* ------------------------------------------------------------- */
620 #ifndef _WIN32
621 /* signal handler for fatal errors */
622 static void sig_error(int signum, siginfo_t *siginf, void *puc)
624 rt_context rc;
626 rt_getcontext(puc, &rc);
627 switch(signum) {
628 case SIGFPE:
629 switch(siginf->si_code) {
630 case FPE_INTDIV:
631 case FPE_FLTDIV:
632 rt_error(&rc, "division by zero");
633 break;
634 default:
635 rt_error(&rc, "floating point exception");
636 break;
638 break;
639 case SIGBUS:
640 case SIGSEGV:
641 rt_error(&rc, " dereferencing invalid pointer");
642 break;
643 case SIGILL:
644 rt_error(&rc, "illegal instruction");
645 break;
646 case SIGABRT:
647 rt_error(&rc, "abort() called");
648 break;
649 default:
650 rt_error(&rc, "caught signal %d", signum);
651 break;
653 exit(255);
656 #ifndef SA_SIGINFO
657 # define SA_SIGINFO 0x00000004u
658 #endif
660 /* Generate a stack backtrace when a CPU exception occurs. */
661 static void set_exception_handler(void)
663 struct sigaction sigact;
664 /* install TCC signal handlers to print debug info on fatal
665 runtime errors */
666 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
667 #ifdef SIGSTKSZ
668 sigact.sa_flags |= SA_ONSTACK;
669 #endif
670 sigact.sa_sigaction = sig_error;
671 sigemptyset(&sigact.sa_mask);
672 sigaction(SIGFPE, &sigact, NULL);
673 sigaction(SIGILL, &sigact, NULL);
674 sigaction(SIGSEGV, &sigact, NULL);
675 sigaction(SIGBUS, &sigact, NULL);
676 sigaction(SIGABRT, &sigact, NULL);
677 #ifdef SIGSTKSZ
678 /* This allows stack overflow to be reported instead of a SEGV */
680 stack_t ss;
681 static unsigned char stack[SIGSTKSZ] __attribute__((aligned(16)));
683 ss.ss_sp = stack;
684 ss.ss_size = SIGSTKSZ;
685 ss.ss_flags = 0;
686 sigaltstack(&ss, NULL);
688 #endif
691 #else /* WIN32 */
692 /* signal handler for fatal errors */
693 static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
695 rt_context rc;
696 unsigned code;
698 rt_getcontext(ex_info->ContextRecord, &rc);
699 switch (code = ex_info->ExceptionRecord->ExceptionCode) {
700 case EXCEPTION_ACCESS_VIOLATION:
701 rt_error(&rc, " access violation");
702 break;
703 case EXCEPTION_STACK_OVERFLOW:
704 rt_error(&rc, "stack overflow");
705 break;
706 case EXCEPTION_INT_DIVIDE_BY_ZERO:
707 rt_error(&rc, "division by zero");
708 break;
709 case EXCEPTION_BREAKPOINT:
710 case EXCEPTION_SINGLE_STEP:
711 rc.ip = *(addr_t*)rc.sp;
712 rt_error(&rc, "^breakpoint/single-step exception:");
713 return EXCEPTION_CONTINUE_SEARCH;
714 default:
715 rt_error(&rc, "caught exception %08x", code);
716 break;
718 return EXCEPTION_EXECUTE_HANDLER;
721 /* Generate a stack backtrace when a CPU exception occurs. */
722 static void set_exception_handler(void)
724 SetUnhandledExceptionFilter(cpu_exception_handler);
727 #endif
729 /* ------------------------------------------------------------- */
730 /* return the PC at frame level 'level'. Return negative if not found */
731 #if defined(__i386__) || defined(__x86_64__)
732 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
734 addr_t ip, fp;
735 if (level == 0) {
736 ip = rc->ip;
737 } else {
738 ip = 0;
739 fp = rc->fp;
740 while (--level) {
741 /* XXX: check address validity with program info */
742 if (fp <= 0x1000)
743 break;
744 fp = ((addr_t *)fp)[0];
746 if (fp > 0x1000)
747 ip = ((addr_t *)fp)[1];
749 if (ip <= 0x1000)
750 return -1;
751 *paddr = ip;
752 return 0;
755 #elif defined(__arm__)
756 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
758 /* XXX: only supports linux */
759 #if !defined(__linux__)
760 return -1;
761 #else
762 if (level == 0) {
763 *paddr = rc->ip;
764 } else {
765 addr_t fp = rc->fp;
766 addr_t sp = rc->sp;
767 if (sp < 0x1000)
768 sp = 0x1000;
769 /* XXX: specific to tinycc stack frames */
770 if (fp < sp + 12 || fp & 3)
771 return -1;
772 while (--level) {
773 sp = ((addr_t *)fp)[-2];
774 if (sp < fp || sp - fp > 16 || sp & 3)
775 return -1;
776 fp = ((addr_t *)fp)[-3];
777 if (fp <= sp || fp - sp < 12 || fp & 3)
778 return -1;
780 /* XXX: check address validity with program info */
781 *paddr = ((addr_t *)fp)[-1];
783 return 0;
784 #endif
787 #elif defined(__aarch64__)
788 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
790 if (level == 0) {
791 *paddr = rc->ip;
792 } else {
793 addr_t *fp = (addr_t*)rc->fp;
794 while (--level)
795 fp = (addr_t *)fp[0];
796 *paddr = fp[1];
798 return 0;
801 #else
802 #warning add arch specific rt_get_caller_pc()
803 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
805 return -1;
808 #endif
809 #endif /* CONFIG_TCC_BACKTRACE */
811 /* ------------------------------------------------------------- */
812 #ifdef CONFIG_TCC_STATIC
814 /* dummy function for profiling */
815 ST_FUNC void *dlopen(const char *filename, int flag)
817 return NULL;
820 ST_FUNC void dlclose(void *p)
824 ST_FUNC const char *dlerror(void)
826 return "error";
829 typedef struct TCCSyms {
830 char *str;
831 void *ptr;
832 } TCCSyms;
835 /* add the symbol you want here if no dynamic linking is done */
836 static TCCSyms tcc_syms[] = {
837 #if !defined(CONFIG_TCCBOOT)
838 #define TCCSYM(a) { #a, &a, },
839 TCCSYM(printf)
840 TCCSYM(fprintf)
841 TCCSYM(fopen)
842 TCCSYM(fclose)
843 #undef TCCSYM
844 #endif
845 { NULL, NULL },
848 ST_FUNC void *dlsym(void *handle, const char *symbol)
850 TCCSyms *p;
851 p = tcc_syms;
852 while (p->str != NULL) {
853 if (!strcmp(p->str, symbol))
854 return p->ptr;
855 p++;
857 return NULL;
860 #endif /* CONFIG_TCC_STATIC */
861 #endif /* TCC_IS_NATIVE */
862 /* ------------------------------------------------------------- */