called function should pop the arguments when using fastcall
[tinycc.git] / tccrun.c
blob85957b882b6f76ff8cb3d547623c461c01f4c4d5
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 # ifndef _WIN32
32 # include <signal.h>
33 # ifndef __OpenBSD__
34 # include <sys/ucontext.h>
35 # endif
36 # else
37 # define ucontext_t CONTEXT
38 # endif
39 ST_DATA int rt_num_callers = 6;
40 ST_DATA const char **rt_bound_error_msg;
41 ST_DATA void *rt_prog_main;
42 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
43 static void rt_error(ucontext_t *uc, const char *fmt, ...);
44 static void set_exception_handler(void);
45 #endif
47 static void set_pages_executable(void *ptr, unsigned long length);
48 static int tcc_relocate_ex(TCCState *s1, void *ptr);
50 #ifdef _WIN64
51 static void *win64_add_function_table(TCCState *s1);
52 static void win64_del_function_table(void *);
53 #endif
55 // #define HAVE_SELINUX
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;
65 if (TCC_RELOCATE_AUTO != ptr)
66 return tcc_relocate_ex(s1, ptr);
68 size = tcc_relocate_ex(s1, NULL);
69 if (size < 0)
70 return -1;
72 #ifdef HAVE_SELINUX
73 /* Use mmap instead of malloc for Selinux. */
74 ptr = mmap (NULL, size, PROT_READ|PROT_WRITE,
75 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
76 if (ptr == MAP_FAILED)
77 tcc_error("tccrun: could not map memory");
78 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
79 #else
80 ptr = tcc_malloc(size);
81 #endif
82 tcc_relocate_ex(s1, ptr); /* no more errors expected */
83 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
84 return 0;
87 ST_FUNC void tcc_run_free(TCCState *s1)
89 int i;
91 for (i = 0; i < s1->nb_runtime_mem; ++i) {
92 #ifdef HAVE_SELINUX
93 unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
94 munmap(s1->runtime_mem[i], size);
95 #else
96 #ifdef _WIN64
97 win64_del_function_table(*(void**)s1->runtime_mem[i]);
98 #endif
99 tcc_free(s1->runtime_mem[i]);
100 #endif
102 tcc_free(s1->runtime_mem);
105 /* launch the compiled program with the given arguments */
106 LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
108 int (*prog_main)(int, char **);
110 s1->runtime_main = "main";
111 if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
112 return 0;
113 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
114 return -1;
115 prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
117 #ifdef CONFIG_TCC_BACKTRACE
118 if (s1->do_debug) {
119 set_exception_handler();
120 rt_prog_main = prog_main;
122 #endif
124 errno = 0; /* clean errno value */
126 #ifdef CONFIG_TCC_BCHECK
127 if (s1->do_bounds_check) {
128 void (*bound_init)(void);
129 void (*bound_exit)(void);
130 void (*bound_new_region)(void *p, addr_t size);
131 int (*bound_delete_region)(void *p);
132 int i, ret;
134 /* set error function */
135 rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
136 /* XXX: use .init section so that it also work in binary ? */
137 bound_init = tcc_get_symbol_err(s1, "__bound_init");
138 bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
139 bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
140 bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
142 bound_init();
143 /* mark argv area as valid */
144 bound_new_region(argv, argc*sizeof(argv[0]));
145 for (i=0; i<argc; ++i)
146 bound_new_region(argv[i], strlen(argv[i]) + 1);
148 ret = (*prog_main)(argc, argv);
150 /* unmark argv area */
151 for (i=0; i<argc; ++i)
152 bound_delete_region(argv[i]);
153 bound_delete_region(argv);
154 bound_exit();
155 return ret;
157 #endif
158 return (*prog_main)(argc, argv);
161 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
162 #define RUN_SECTION_ALIGNMENT 63
163 #else
164 #define RUN_SECTION_ALIGNMENT 15
165 #endif
167 /* relocate code. Return -1 on error, required size if ptr is NULL,
168 otherwise copy code into buffer passed by the caller */
169 static int tcc_relocate_ex(TCCState *s1, void *ptr)
171 Section *s;
172 unsigned offset, length, fill, i, k;
173 addr_t mem;
175 if (NULL == ptr) {
176 s1->nb_errors = 0;
177 #ifdef TCC_TARGET_PE
178 pe_output_file(s1, NULL);
179 #else
180 tcc_add_runtime(s1);
181 relocate_common_syms();
182 tcc_add_linker_symbols(s1);
183 build_got_entries(s1);
184 #endif
185 if (s1->nb_errors)
186 return -1;
189 offset = 0, mem = (addr_t)ptr;
190 fill = -mem & RUN_SECTION_ALIGNMENT;
191 #ifdef _WIN64
192 offset += sizeof (void*);
193 #endif
194 for (k = 0; k < 2; ++k) {
195 for(i = 1; i < s1->nb_sections; i++) {
196 s = s1->sections[i];
197 if (0 == (s->sh_flags & SHF_ALLOC))
198 continue;
199 if (k != !(s->sh_flags & SHF_EXECINSTR))
200 continue;
201 offset += fill;
202 s->sh_addr = mem ? mem + offset : 0;
203 #if 0
204 if (mem)
205 printf("%-16s +%02lx %p %04x\n",
206 s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset);
207 #endif
208 offset += s->data_offset;
209 fill = -(mem + offset) & 15;
211 #if RUN_SECTION_ALIGNMENT > 15
212 /* To avoid that x86 processors would reload cached instructions each time
213 when data is written in the near, we need to make sure that code and data
214 do not share the same 64 byte unit */
215 fill = -(mem + offset) & RUN_SECTION_ALIGNMENT;
216 #endif
219 /* relocate symbols */
220 relocate_syms(s1, s1->symtab, 1);
221 if (s1->nb_errors)
222 return -1;
224 if (0 == mem)
225 return offset + RUN_SECTION_ALIGNMENT;
227 /* relocate each section */
228 for(i = 1; i < s1->nb_sections; i++) {
229 s = s1->sections[i];
230 if (s->reloc)
231 relocate_section(s1, s);
233 relocate_plt(s1);
235 #ifdef _WIN64
236 *(void**)ptr = win64_add_function_table(s1);
237 #endif
239 for(i = 1; i < s1->nb_sections; i++) {
240 s = s1->sections[i];
241 if (0 == (s->sh_flags & SHF_ALLOC))
242 continue;
243 length = s->data_offset;
244 ptr = (void*)s->sh_addr;
245 if (NULL == s->data || s->sh_type == SHT_NOBITS)
246 memset(ptr, 0, length);
247 else
248 memcpy(ptr, s->data, length);
249 /* mark executable sections as executable in memory */
250 if (s->sh_flags & SHF_EXECINSTR)
251 set_pages_executable(ptr, length);
253 return 0;
256 /* ------------------------------------------------------------- */
257 /* allow to run code in memory */
259 static void set_pages_executable(void *ptr, unsigned long length)
261 #ifdef _WIN32
262 unsigned long old_protect;
263 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
264 #else
265 void __clear_cache(void *beginning, void *end);
266 addr_t start, end;
267 #ifndef PAGESIZE
268 # define PAGESIZE 4096
269 #endif
270 start = (addr_t)ptr & ~(PAGESIZE - 1);
271 end = (addr_t)ptr + length;
272 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
273 if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
274 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
275 # if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
276 __clear_cache(ptr, (char *)ptr + length);
277 # endif
278 #endif
281 #ifdef _WIN64
282 static void *win64_add_function_table(TCCState *s1)
284 void *p = NULL;
285 if (s1->uw_pdata) {
286 p = (void*)s1->uw_pdata->sh_addr;
287 RtlAddFunctionTable(
288 (RUNTIME_FUNCTION*)p,
289 s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
290 text_section->sh_addr
292 s1->uw_pdata = NULL;
294 return p;;
297 static void win64_del_function_table(void *p)
299 if (p) {
300 RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p);
303 #endif
305 /* ------------------------------------------------------------- */
306 #ifdef CONFIG_TCC_BACKTRACE
308 ST_FUNC void tcc_set_num_callers(int n)
310 rt_num_callers = n;
313 /* print the position in the source file of PC value 'pc' by reading
314 the stabs debug information */
315 static addr_t rt_printline(addr_t wanted_pc, const char *msg)
317 char func_name[128], last_func_name[128];
318 addr_t func_addr, last_pc, pc;
319 const char *incl_files[INCLUDE_STACK_SIZE];
320 int incl_index, len, last_line_num, i;
321 const char *str, *p;
323 Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym;
324 int stab_len = 0;
325 char *stab_str = NULL;
327 if (stab_section) {
328 stab_len = stab_section->data_offset;
329 stab_sym = (Stab_Sym *)stab_section->data;
330 stab_str = (char *) stabstr_section->data;
333 func_name[0] = '\0';
334 func_addr = 0;
335 incl_index = 0;
336 last_func_name[0] = '\0';
337 last_pc = (addr_t)-1;
338 last_line_num = 1;
340 if (!stab_sym)
341 goto no_stabs;
343 stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len);
344 for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
345 switch(sym->n_type) {
346 /* function start or end */
347 case N_FUN:
348 if (sym->n_strx == 0) {
349 /* we test if between last line and end of function */
350 pc = sym->n_value + func_addr;
351 if (wanted_pc >= last_pc && wanted_pc < pc)
352 goto found;
353 func_name[0] = '\0';
354 func_addr = 0;
355 } else {
356 str = stab_str + sym->n_strx;
357 p = strchr(str, ':');
358 if (!p) {
359 pstrcpy(func_name, sizeof(func_name), str);
360 } else {
361 len = p - str;
362 if (len > sizeof(func_name) - 1)
363 len = sizeof(func_name) - 1;
364 memcpy(func_name, str, len);
365 func_name[len] = '\0';
367 func_addr = sym->n_value;
369 break;
370 /* line number info */
371 case N_SLINE:
372 pc = sym->n_value + func_addr;
373 if (wanted_pc >= last_pc && wanted_pc < pc)
374 goto found;
375 last_pc = pc;
376 last_line_num = sym->n_desc;
377 /* XXX: slow! */
378 strcpy(last_func_name, func_name);
379 break;
380 /* include files */
381 case N_BINCL:
382 str = stab_str + sym->n_strx;
383 add_incl:
384 if (incl_index < INCLUDE_STACK_SIZE) {
385 incl_files[incl_index++] = str;
387 break;
388 case N_EINCL:
389 if (incl_index > 1)
390 incl_index--;
391 break;
392 case N_SO:
393 if (sym->n_strx == 0) {
394 incl_index = 0; /* end of translation unit */
395 } else {
396 str = stab_str + sym->n_strx;
397 /* do not add path */
398 len = strlen(str);
399 if (len > 0 && str[len - 1] != '/')
400 goto add_incl;
402 break;
406 no_stabs:
407 /* second pass: we try symtab symbols (no line number info) */
408 incl_index = 0;
409 if (symtab_section)
411 ElfW(Sym) *sym, *sym_end;
412 int type;
414 sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
415 for(sym = (ElfW(Sym) *)symtab_section->data + 1;
416 sym < sym_end;
417 sym++) {
418 type = ELFW(ST_TYPE)(sym->st_info);
419 if (type == STT_FUNC || type == STT_GNU_IFUNC) {
420 if (wanted_pc >= sym->st_value &&
421 wanted_pc < sym->st_value + sym->st_size) {
422 pstrcpy(last_func_name, sizeof(last_func_name),
423 (char *) strtab_section->data + sym->st_name);
424 func_addr = sym->st_value;
425 goto found;
430 /* did not find any info: */
431 fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc);
432 fflush(stderr);
433 return 0;
434 found:
435 i = incl_index;
436 if (i > 0)
437 fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num);
438 fprintf(stderr, "%s %p", msg, (void*)wanted_pc);
439 if (last_func_name[0] != '\0')
440 fprintf(stderr, " %s()", last_func_name);
441 if (--i >= 0) {
442 fprintf(stderr, " (included from ");
443 for (;;) {
444 fprintf(stderr, "%s", incl_files[i]);
445 if (--i < 0)
446 break;
447 fprintf(stderr, ", ");
449 fprintf(stderr, ")");
451 fprintf(stderr, "\n");
452 fflush(stderr);
453 return func_addr;
456 /* emit a run time error at position 'pc' */
457 static void rt_error(ucontext_t *uc, const char *fmt, ...)
459 va_list ap;
460 addr_t pc;
461 int i;
463 fprintf(stderr, "Runtime error: ");
464 va_start(ap, fmt);
465 vfprintf(stderr, fmt, ap);
466 va_end(ap);
467 fprintf(stderr, "\n");
469 for(i=0;i<rt_num_callers;i++) {
470 if (rt_get_caller_pc(&pc, uc, i) < 0)
471 break;
472 pc = rt_printline(pc, i ? "by" : "at");
473 if (pc == (addr_t)rt_prog_main && pc)
474 break;
478 /* ------------------------------------------------------------- */
479 #ifndef _WIN32
481 /* signal handler for fatal errors */
482 static void sig_error(int signum, siginfo_t *siginf, void *puc)
484 ucontext_t *uc = puc;
486 switch(signum) {
487 case SIGFPE:
488 switch(siginf->si_code) {
489 case FPE_INTDIV:
490 case FPE_FLTDIV:
491 rt_error(uc, "division by zero");
492 break;
493 default:
494 rt_error(uc, "floating point exception");
495 break;
497 break;
498 case SIGBUS:
499 case SIGSEGV:
500 if (rt_bound_error_msg && *rt_bound_error_msg)
501 rt_error(uc, *rt_bound_error_msg);
502 else
503 rt_error(uc, "dereferencing invalid pointer");
504 break;
505 case SIGILL:
506 rt_error(uc, "illegal instruction");
507 break;
508 case SIGABRT:
509 rt_error(uc, "abort() called");
510 break;
511 default:
512 rt_error(uc, "caught signal %d", signum);
513 break;
515 exit(255);
518 #ifndef SA_SIGINFO
519 # define SA_SIGINFO 0x00000004u
520 #endif
522 /* Generate a stack backtrace when a CPU exception occurs. */
523 static void set_exception_handler(void)
525 struct sigaction sigact;
526 /* install TCC signal handlers to print debug info on fatal
527 runtime errors */
528 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
529 sigact.sa_sigaction = sig_error;
530 sigemptyset(&sigact.sa_mask);
531 sigaction(SIGFPE, &sigact, NULL);
532 sigaction(SIGILL, &sigact, NULL);
533 sigaction(SIGSEGV, &sigact, NULL);
534 sigaction(SIGBUS, &sigact, NULL);
535 sigaction(SIGABRT, &sigact, NULL);
538 /* ------------------------------------------------------------- */
539 #ifdef __i386__
541 /* fix for glibc 2.1 */
542 #ifndef REG_EIP
543 #define REG_EIP EIP
544 #define REG_EBP EBP
545 #endif
547 /* return the PC at frame level 'level'. Return negative if not found */
548 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
550 addr_t fp;
551 int i;
553 if (level == 0) {
554 #if defined(__APPLE__)
555 *paddr = uc->uc_mcontext->__ss.__eip;
556 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
557 *paddr = uc->uc_mcontext.mc_eip;
558 #elif defined(__dietlibc__)
559 *paddr = uc->uc_mcontext.eip;
560 #elif defined(__NetBSD__)
561 *paddr = uc->uc_mcontext.__gregs[_REG_EIP];
562 #elif defined(__OpenBSD__)
563 *paddr = uc->sc_eip;
564 #else
565 *paddr = uc->uc_mcontext.gregs[REG_EIP];
566 #endif
567 return 0;
568 } else {
569 #if defined(__APPLE__)
570 fp = uc->uc_mcontext->__ss.__ebp;
571 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
572 fp = uc->uc_mcontext.mc_ebp;
573 #elif defined(__dietlibc__)
574 fp = uc->uc_mcontext.ebp;
575 #elif defined(__NetBSD__)
576 fp = uc->uc_mcontext.__gregs[_REG_EBP];
577 #elif defined(__OpenBSD__)
578 *paddr = uc->sc_ebp;
579 #else
580 fp = uc->uc_mcontext.gregs[REG_EBP];
581 #endif
582 for(i=1;i<level;i++) {
583 /* XXX: check address validity with program info */
584 if (fp <= 0x1000 || fp >= 0xc0000000)
585 return -1;
586 fp = ((addr_t *)fp)[0];
588 *paddr = ((addr_t *)fp)[1];
589 return 0;
593 /* ------------------------------------------------------------- */
594 #elif defined(__x86_64__)
596 /* return the PC at frame level 'level'. Return negative if not found */
597 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
599 addr_t fp;
600 int i;
602 if (level == 0) {
603 /* XXX: only support linux */
604 #if defined(__APPLE__)
605 *paddr = uc->uc_mcontext->__ss.__rip;
606 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
607 *paddr = uc->uc_mcontext.mc_rip;
608 #elif defined(__NetBSD__)
609 *paddr = uc->uc_mcontext.__gregs[_REG_RIP];
610 #else
611 *paddr = uc->uc_mcontext.gregs[REG_RIP];
612 #endif
613 return 0;
614 } else {
615 #if defined(__APPLE__)
616 fp = uc->uc_mcontext->__ss.__rbp;
617 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
618 fp = uc->uc_mcontext.mc_rbp;
619 #elif defined(__NetBSD__)
620 fp = uc->uc_mcontext.__gregs[_REG_RBP];
621 #else
622 fp = uc->uc_mcontext.gregs[REG_RBP];
623 #endif
624 for(i=1;i<level;i++) {
625 /* XXX: check address validity with program info */
626 if (fp <= 0x1000)
627 return -1;
628 fp = ((addr_t *)fp)[0];
630 *paddr = ((addr_t *)fp)[1];
631 return 0;
635 /* ------------------------------------------------------------- */
636 #elif defined(__arm__)
638 /* return the PC at frame level 'level'. Return negative if not found */
639 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
641 addr_t fp, sp;
642 int i;
644 if (level == 0) {
645 /* XXX: only supports linux */
646 #if defined(__linux__)
647 *paddr = uc->uc_mcontext.arm_pc;
648 #else
649 return -1;
650 #endif
651 return 0;
652 } else {
653 #if defined(__linux__)
654 fp = uc->uc_mcontext.arm_fp;
655 sp = uc->uc_mcontext.arm_sp;
656 if (sp < 0x1000)
657 sp = 0x1000;
658 #else
659 return -1;
660 #endif
661 /* XXX: specific to tinycc stack frames */
662 if (fp < sp + 12 || fp & 3)
663 return -1;
664 for(i = 1; i < level; i++) {
665 sp = ((addr_t *)fp)[-2];
666 if (sp < fp || sp - fp > 16 || sp & 3)
667 return -1;
668 fp = ((addr_t *)fp)[-3];
669 if (fp <= sp || fp - sp < 12 || fp & 3)
670 return -1;
672 /* XXX: check address validity with program info */
673 *paddr = ((addr_t *)fp)[-1];
674 return 0;
678 /* ------------------------------------------------------------- */
679 #elif defined(__aarch64__)
681 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
683 if (level < 0)
684 return -1;
685 else if (level == 0) {
686 *paddr = uc->uc_mcontext.pc;
687 return 0;
689 else {
690 addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
691 int i;
692 for (i = 1; i < level; i++)
693 fp = (addr_t *)fp[0];
694 *paddr = fp[1];
695 return 0;
699 /* ------------------------------------------------------------- */
700 #else
702 #warning add arch specific rt_get_caller_pc()
703 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
705 return -1;
708 #endif /* !__i386__ */
710 /* ------------------------------------------------------------- */
711 #else /* WIN32 */
713 static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
715 EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
716 CONTEXT *uc = ex_info->ContextRecord;
717 switch (er->ExceptionCode) {
718 case EXCEPTION_ACCESS_VIOLATION:
719 if (rt_bound_error_msg && *rt_bound_error_msg)
720 rt_error(uc, *rt_bound_error_msg);
721 else
722 rt_error(uc, "access violation");
723 break;
724 case EXCEPTION_STACK_OVERFLOW:
725 rt_error(uc, "stack overflow");
726 break;
727 case EXCEPTION_INT_DIVIDE_BY_ZERO:
728 rt_error(uc, "division by zero");
729 break;
730 default:
731 rt_error(uc, "exception caught");
732 break;
734 return EXCEPTION_EXECUTE_HANDLER;
737 /* Generate a stack backtrace when a CPU exception occurs. */
738 static void set_exception_handler(void)
740 SetUnhandledExceptionFilter(cpu_exception_handler);
743 /* return the PC at frame level 'level'. Return non zero if not found */
744 static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
746 addr_t fp, pc;
747 int i;
748 #ifdef _WIN64
749 pc = uc->Rip;
750 fp = uc->Rbp;
751 #else
752 pc = uc->Eip;
753 fp = uc->Ebp;
754 #endif
755 if (level > 0) {
756 for(i=1;i<level;i++) {
757 /* XXX: check address validity with program info */
758 if (fp <= 0x1000 || fp >= 0xc0000000)
759 return -1;
760 fp = ((addr_t*)fp)[0];
762 pc = ((addr_t*)fp)[1];
764 *paddr = pc;
765 return 0;
768 #endif /* _WIN32 */
769 #endif /* CONFIG_TCC_BACKTRACE */
770 /* ------------------------------------------------------------- */
771 #ifdef CONFIG_TCC_STATIC
773 /* dummy function for profiling */
774 ST_FUNC void *dlopen(const char *filename, int flag)
776 return NULL;
779 ST_FUNC void dlclose(void *p)
783 ST_FUNC const char *dlerror(void)
785 return "error";
788 typedef struct TCCSyms {
789 char *str;
790 void *ptr;
791 } TCCSyms;
794 /* add the symbol you want here if no dynamic linking is done */
795 static TCCSyms tcc_syms[] = {
796 #if !defined(CONFIG_TCCBOOT)
797 #define TCCSYM(a) { #a, &a, },
798 TCCSYM(printf)
799 TCCSYM(fprintf)
800 TCCSYM(fopen)
801 TCCSYM(fclose)
802 #undef TCCSYM
803 #endif
804 { NULL, NULL },
807 ST_FUNC void *dlsym(void *handle, const char *symbol)
809 TCCSyms *p;
810 p = tcc_syms;
811 while (p->str != NULL) {
812 if (!strcmp(p->str, symbol))
813 return p->ptr;
814 p++;
816 return NULL;
819 #endif /* CONFIG_TCC_STATIC */
820 #endif /* TCC_IS_NATIVE */
821 /* ------------------------------------------------------------- */