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
23 /* only native compiler supports -run */
26 #ifdef CONFIG_TCC_BACKTRACE
27 typedef struct rt_context
29 /* --> tccelf.c:tcc_add_btstub wants those below in that order: */
30 Stab_Sym
*stab_sym
, *stab_sym_end
;
32 ElfW(Sym
) *esym_start
, *esym_end
;
36 struct rt_context
*next
;
45 static rt_context g_rtctxt
;
46 static void set_exception_handler(void);
47 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
);
48 static void rt_exit(int code
);
49 #endif /* CONFIG_TCC_BACKTRACE */
51 /* defined when included from lib/bt-exe.c */
52 #ifndef CONFIG_TCC_BACKTRACE_ONLY
55 # include <sys/mman.h>
58 static void set_pages_executable(TCCState
*s1
, int mode
, void *ptr
, unsigned long length
);
59 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
);
62 static void *win64_add_function_table(TCCState
*s1
);
63 static void win64_del_function_table(void *);
66 /* ------------------------------------------------------------- */
67 /* Do all relocations (needed before using tcc_get_symbol())
68 Returns -1 on error. */
70 LIBTCCAPI
int tcc_relocate(TCCState
*s1
, void *ptr
)
75 if (TCC_RELOCATE_AUTO
!= ptr
)
76 return tcc_relocate_ex(s1
, ptr
, 0);
78 size
= tcc_relocate_ex(s1
, NULL
, 0);
84 /* Using mmap instead of malloc */
86 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
87 int fd
= mkstemp(tmpfname
);
91 size
= (size
+ (PAGESIZE
-1)) & ~(PAGESIZE
-1);
92 ptr
= mmap(NULL
, size
* 2, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
93 /* mmap RX memory at a fixed distance */
94 prx
= mmap((char*)ptr
+ size
, size
, PROT_READ
|PROT_EXEC
, MAP_SHARED
|MAP_FIXED
, fd
, 0);
95 if (ptr
== MAP_FAILED
|| prx
== MAP_FAILED
)
96 tcc_error("tccrun: could not map memory");
97 ptr_diff
= (char*)prx
- (char*)ptr
;
99 //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
102 ptr
= tcc_malloc(size
);
104 tcc_relocate_ex(s1
, ptr
, ptr_diff
); /* no more errors expected */
105 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, (void*)(addr_t
)size
);
106 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, ptr
);
110 ST_FUNC
void tcc_run_free(TCCState
*s1
)
114 for (i
= 0; i
< s1
->nb_runtime_mem
; i
+= 2) {
115 unsigned size
= (unsigned)(addr_t
)s1
->runtime_mem
[i
];
116 void *ptr
= s1
->runtime_mem
[i
+1];
118 munmap(ptr
, size
* 2);
120 /* unprotect memory to make it usable for malloc again */
121 set_pages_executable(s1
, 2, ptr
, size
);
123 win64_del_function_table(*(void**)ptr
);
128 tcc_free(s1
->runtime_mem
);
131 static void run_cdtors(TCCState
*s1
, const char *start
, const char *end
,
132 int argc
, char **argv
, char **envp
)
134 void **a
= (void **)get_sym_addr(s1
, start
, 0, 0);
135 void **b
= (void **)get_sym_addr(s1
, end
, 0, 0);
137 ((void(*)(int, char **, char **))*a
++)(argc
, argv
, envp
);
140 /* launch the compiled program with the given arguments */
141 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
143 int (*prog_main
)(int, char **, char **), ret
;
144 #ifdef CONFIG_TCC_BACKTRACE
145 rt_context
*rc
= &g_rtctxt
;
148 #if defined(__APPLE__) || defined(__FreeBSD__)
150 #elif defined(__OpenBSD__) || defined(__NetBSD__)
151 extern char **environ
;
152 char **envp
= environ
;
154 char **envp
= environ
;
157 s1
->runtime_main
= s1
->nostdlib
? "_start" : "main";
158 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, s1
->runtime_main
, 0, 1))
160 #ifdef CONFIG_TCC_BACKTRACE
162 tcc_add_symbol(s1
, "exit", rt_exit
);
164 if (tcc_relocate(s1
, TCC_RELOCATE_AUTO
) < 0)
166 prog_main
= (void*)get_sym_addr(s1
, s1
->runtime_main
, 1, 1);
168 #ifdef CONFIG_TCC_BACKTRACE
169 memset(rc
, 0, sizeof *rc
);
172 rc
->stab_sym
= (Stab_Sym
*)stab_section
->data
;
173 rc
->stab_sym_end
= (Stab_Sym
*)(stab_section
->data
+ stab_section
->data_offset
);
174 rc
->stab_str
= (char *)stab_section
->link
->data
;
175 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
176 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
177 rc
->elf_str
= (char *)symtab_section
->link
->data
;
179 rc
->prog_base
= text_section
->sh_addr
& 0xffffffff00000000ULL
;
181 rc
->top_func
= tcc_get_symbol(s1
, "main");
182 rc
->num_callers
= s1
->rt_num_callers
;
184 if ((p
= tcc_get_symbol(s1
, "__rt_error")))
185 *(void**)p
= _rt_error
;
186 #ifdef CONFIG_TCC_BCHECK
187 if (s1
->do_bounds_check
) {
188 rc
->bounds_start
= (void*)bounds_section
->sh_addr
;
189 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
190 ((void(*)(void*,int))p
)(rc
->bounds_start
, 1);
193 set_exception_handler();
197 errno
= 0; /* clean errno value */
200 /* These aren't C symbols, so don't need leading underscore handling. */
201 run_cdtors(s1
, "__init_array_start", "__init_array_end", argc
, argv
, envp
);
202 #ifdef CONFIG_TCC_BACKTRACE
203 if (!rc
->do_jmp
|| !(ret
= setjmp(rc
->jmp_buf)))
206 ret
= prog_main(argc
, argv
, envp
);
208 run_cdtors(s1
, "__fini_array_start", "__fini_array_end", 0, NULL
, NULL
);
209 if ((s1
->dflag
& 16) && ret
)
210 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
214 #define DEBUG_RUNMEN 0
216 /* enable rx/ro/rw permissions */
217 #define CONFIG_RUNMEM_RO 1
220 # define PAGE_ALIGN PAGESIZE
221 #elif defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
222 /* To avoid that x86 processors would reload cached instructions
223 each time when data is written in the near, we need to make
224 sure that code and data do not share the same 64 byte unit */
225 # define PAGE_ALIGN 64
227 # define PAGE_ALIGN 1
230 /* relocate code. Return -1 on error, required size if ptr is NULL,
231 otherwise copy code into buffer passed by the caller */
232 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
)
235 unsigned offset
, length
, align
, max_align
, i
, k
, f
;
242 pe_output_file(s1
, NULL
);
245 resolve_common_syms(s1
);
246 build_got_entries(s1
);
252 offset
= max_align
= 0, mem
= (addr_t
)ptr
;
254 offset
+= sizeof (void*); /* space for function_table pointer */
258 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
260 for(i
= 1; i
< s1
->nb_sections
; i
++) {
261 static const char shf
[] = {
262 SHF_ALLOC
|SHF_EXECINSTR
, SHF_ALLOC
, SHF_ALLOC
|SHF_WRITE
265 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
267 length
= s
->data_offset
;
271 n
= (s
->sh_addr
- addr
) + length
;
272 ptr
= (void*)s
->sh_addr
;
274 ptr
= (void*)(s
->sh_addr
- ptr_diff
);
275 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
276 memset(ptr
, 0, length
);
278 memcpy(ptr
, s
->data
, length
);
280 if (s
== s1
->uw_pdata
)
281 *(void**)mem
= win64_add_function_table(s1
);
286 s
->data_allocated
= 0;
291 align
= s
->sh_addralign
- 1;
292 if (++n
== 1 && align
< (PAGE_ALIGN
- 1))
293 align
= (PAGE_ALIGN
- 1);
294 if (max_align
< align
)
296 addr
= k
? mem
: mem
+ ptr_diff
;
297 offset
+= -(addr
+ offset
) & align
;
298 s
->sh_addr
= mem
? addr
+ offset
: 0;
302 printf("%d: %-16s %p len %04x align %04x\n",
303 k
, s
->name
, (void*)s
->sh_addr
, length
, align
+ 1);
306 if (copy
) { /* set permissions */
307 if (k
== 0 && ptr_diff
)
308 continue; /* not with HAVE_SELINUX */
310 #if !CONFIG_RUNMEM_RO
313 f
= 3; /* change only SHF_EXECINSTR to rwx */
316 printf("protect %d %p %04x\n", f
, (void*)addr
, n
);
319 set_pages_executable(s1
, f
, (void*)addr
, n
);
326 /* relocate symbols */
327 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
331 return offset
+ max_align
;
334 s1
->pe_imagebase
= mem
;
337 /* relocate sections */
338 #ifndef TCC_TARGET_PE
341 relocate_sections(s1
);
346 /* ------------------------------------------------------------- */
347 /* allow to run code in memory */
349 static void set_pages_executable(TCCState
*s1
, int mode
, void *ptr
, unsigned long length
)
352 static const unsigned char protect
[] = {
356 PAGE_EXECUTE_READWRITE
359 VirtualProtect(ptr
, length
, protect
[mode
], &old
);
361 static const unsigned char protect
[] = {
362 PROT_READ
| PROT_EXEC
,
364 PROT_READ
| PROT_WRITE
,
365 PROT_READ
| PROT_WRITE
| PROT_EXEC
368 start
= (addr_t
)ptr
& ~(PAGESIZE
- 1);
369 end
= (addr_t
)ptr
+ length
;
370 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
371 if (mprotect((void *)start
, end
- start
, protect
[mode
]))
372 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
374 /* XXX: BSD sometimes dump core with bad system call */
375 # if (TCC_TARGET_ARM && !TARGETOS_BSD) || TCC_TARGET_ARM64
376 if (mode
== 0 || mode
== 3) {
377 void __clear_cache(void *beginning
, void *end
);
378 __clear_cache(ptr
, (char *)ptr
+ length
);
386 static void *win64_add_function_table(TCCState
*s1
)
390 p
= (void*)s1
->uw_pdata
->sh_addr
;
392 (RUNTIME_FUNCTION
*)p
,
393 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
401 static void win64_del_function_table(void *p
)
404 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
408 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
409 /* ------------------------------------------------------------- */
410 #ifdef CONFIG_TCC_BACKTRACE
412 static int rt_vprintf(const char *fmt
, va_list ap
)
414 int ret
= vfprintf(stderr
, fmt
, ap
);
419 static int rt_printf(const char *fmt
, ...)
424 r
= rt_vprintf(fmt
, ap
);
429 #define INCLUDE_STACK_SIZE 32
431 /* print the position in the source file of PC value 'pc' by reading
432 the stabs debug information */
433 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
,
434 const char *msg
, const char *skip
)
437 addr_t func_addr
, last_pc
, pc
;
438 const char *incl_files
[INCLUDE_STACK_SIZE
];
439 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
448 last_pc
= (addr_t
)-1;
452 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
453 str
= rc
->stab_str
+ sym
->n_strx
;
456 switch(sym
->n_type
) {
464 if (sym
->n_strx
== 0) /* end of function */
468 /* Stab_Sym.n_value is only 32bits */
475 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
480 switch(sym
->n_type
) {
481 /* function start or end */
483 if (sym
->n_strx
== 0)
485 p
= strchr(str
, ':');
486 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
487 len
= sizeof func_name
;
488 pstrcpy(func_name
, len
, str
);
491 /* line number info */
494 last_line_num
= sym
->n_desc
;
495 last_incl_index
= incl_index
;
499 if (incl_index
< INCLUDE_STACK_SIZE
)
500 incl_files
[incl_index
++] = str
;
506 /* start/end of translation unit */
510 /* do not add path */
512 if (len
> 0 && str
[len
- 1] != '/')
513 incl_files
[incl_index
++] = str
;
518 last_pc
= (addr_t
)-1;
520 /* alternative file name (from #line or #include directives) */
523 incl_files
[incl_index
-1] = str
;
532 /* we try symtab symbols (no line number info) */
533 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
534 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
535 if (type
== STT_FUNC
|| type
== STT_GNU_IFUNC
) {
536 if (wanted_pc
>= esym
->st_value
&&
537 wanted_pc
< esym
->st_value
+ esym
->st_size
) {
538 pstrcpy(func_name
, sizeof(func_name
),
539 rc
->elf_str
+ esym
->st_name
);
540 func_addr
= esym
->st_value
;
552 str
= incl_files
[--i
];
553 if (skip
[0] && strstr(str
, skip
))
555 rt_printf("%s:%d: ", str
, last_line_num
);
557 rt_printf("%08llx : ", (long long)wanted_pc
);
558 rt_printf("%s %s", msg
, func_name
[0] ? func_name
: "???");
561 rt_printf(" (included from ");
563 rt_printf("%s", incl_files
[i
]);
574 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
);
576 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
)
578 rt_context
*rc
= &g_rtctxt
;
581 int i
, level
, ret
, n
;
582 const char *a
, *b
, *msg
;
585 /* we're called from tcc_backtrace. */
590 /* we're called from signal/exception handler */
591 msg
= "RUNTIME ERROR: ";
595 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
596 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
597 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
601 n
= rc
->num_callers
? rc
->num_callers
: 6;
602 for (i
= level
= 0; level
< n
; i
++) {
603 ret
= rt_get_caller_pc(&pc
, rc
, i
);
606 pc
= rt_printline(rc
, pc
, level
? "by" : "at", skip
);
607 if (pc
== (addr_t
)-1)
614 } else if (ret
== -1)
617 if (ret
== -1 || (pc
== (addr_t
)rc
->top_func
&& pc
))
626 /* emit a run time error at position 'pc' */
627 static int rt_error(const char *fmt
, ...)
632 ret
= _rt_error(0, 0, fmt
, ap
);
637 static void rt_exit(int code
)
639 rt_context
*rc
= &g_rtctxt
;
641 longjmp(rc
->jmp_buf, code
? code
: 256);
645 /* ------------------------------------------------------------- */
650 # include <sys/ucontext.h>
653 # define ucontext_t CONTEXT
656 /* translate from ucontext_t* to internal rt_context * */
657 static void rt_getcontext(ucontext_t
*uc
, rt_context
*rc
)
667 #elif defined __i386__
668 # if defined(__APPLE__)
669 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
670 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
671 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
672 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
673 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
674 # elif defined(__dietlibc__)
675 rc
->ip
= uc
->uc_mcontext
.eip
;
676 rc
->fp
= uc
->uc_mcontext
.ebp
;
677 # elif defined(__NetBSD__)
678 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
679 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
680 # elif defined(__OpenBSD__)
683 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
684 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
685 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
687 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
688 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
690 #elif defined(__x86_64__)
691 # if defined(__APPLE__)
692 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
693 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
694 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
695 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
696 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
697 # elif defined(__NetBSD__)
698 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
699 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
700 # elif defined(__OpenBSD__)
704 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
705 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
707 #elif defined(__arm__) && defined(__NetBSD__)
708 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
709 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
710 #elif defined(__arm__) && defined(__OpenBSD__)
713 #elif defined(__arm__) && defined(__FreeBSD__)
714 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
715 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
716 #elif defined(__arm__)
717 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
718 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
719 #elif defined(__aarch64__) && defined(__APPLE__)
721 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
722 rc
->ip
= uc
->uc_mcontext
->__ss
.__pc
;
723 rc
->fp
= uc
->uc_mcontext
->__ss
.__fp
;
724 #elif defined(__aarch64__) && defined(__FreeBSD__)
725 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
726 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
727 #elif defined(__aarch64__) && defined(__NetBSD__)
728 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
729 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
730 #elif defined(__aarch64__) && defined(__OpenBSD__)
732 rc
->fp
= uc
->sc_x
[29];
733 #elif defined(__aarch64__)
734 rc
->ip
= uc
->uc_mcontext
.pc
;
735 rc
->fp
= uc
->uc_mcontext
.regs
[29];
736 #elif defined(__riscv) && defined(__OpenBSD__)
737 rc
->ip
= uc
->sc_sepc
;
738 rc
->fp
= uc
->sc_s
[0];
739 #elif defined(__riscv)
740 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
741 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
745 /* ------------------------------------------------------------- */
747 /* signal handler for fatal errors */
748 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
750 rt_context
*rc
= &g_rtctxt
;
751 rt_getcontext(puc
, rc
);
755 switch(siginf
->si_code
) {
758 rt_error("division by zero");
761 rt_error("floating point exception");
767 rt_error("invalid memory access");
770 rt_error("illegal instruction");
773 rt_error("abort() called");
776 rt_error("caught signal %d", signum
);
783 # define SA_SIGINFO 0x00000004u
786 /* Generate a stack backtrace when a CPU exception occurs. */
787 static void set_exception_handler(void)
789 struct sigaction sigact
;
790 /* install TCC signal handlers to print debug info on fatal
792 sigemptyset (&sigact
.sa_mask
);
793 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
794 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
795 sigact
.sa_flags
|= SA_ONSTACK
;
797 sigact
.sa_sigaction
= sig_error
;
798 sigemptyset(&sigact
.sa_mask
);
799 sigaction(SIGFPE
, &sigact
, NULL
);
800 sigaction(SIGILL
, &sigact
, NULL
);
801 sigaction(SIGSEGV
, &sigact
, NULL
);
802 sigaction(SIGBUS
, &sigact
, NULL
);
803 sigaction(SIGABRT
, &sigact
, NULL
);
805 /* This allows stack overflow to be reported instead of a SEGV */
808 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
811 ss
.ss_size
= SIGSTKSZ
;
813 sigaltstack(&ss
, NULL
);
820 /* signal handler for fatal errors */
821 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
823 rt_context
*rc
= &g_rtctxt
;
825 rt_getcontext(ex_info
->ContextRecord
, rc
);
827 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
828 case EXCEPTION_ACCESS_VIOLATION
:
829 rt_error("invalid memory access");
831 case EXCEPTION_STACK_OVERFLOW
:
832 rt_error("stack overflow");
834 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
835 rt_error("division by zero");
837 case EXCEPTION_BREAKPOINT
:
838 case EXCEPTION_SINGLE_STEP
:
839 rc
->ip
= *(addr_t
*)rc
->sp
;
840 rt_error("breakpoint/single-step exception:");
841 return EXCEPTION_CONTINUE_SEARCH
;
843 rt_error("caught exception %08x", code
);
848 return EXCEPTION_EXECUTE_HANDLER
;
851 /* Generate a stack backtrace when a CPU exception occurs. */
852 static void set_exception_handler(void)
854 SetUnhandledExceptionFilter(cpu_exception_handler
);
859 /* ------------------------------------------------------------- */
860 /* return the PC at frame level 'level'. Return negative if not found */
861 #if defined(__i386__) || defined(__x86_64__)
862 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
871 /* XXX: check address validity with program info */
874 fp
= ((addr_t
*)fp
)[0];
877 ip
= ((addr_t
*)fp
)[1];
885 #elif defined(__arm__)
886 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
888 /* XXX: only supports linux/bsd */
889 #if !defined(__linux__) && \
890 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
898 fp
= ((addr_t
*)fp
)[0];
899 *paddr
= ((addr_t
*)fp
)[2];
905 #elif defined(__aarch64__)
906 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
911 addr_t
*fp
= (addr_t
*)rc
->fp
;
913 fp
= (addr_t
*)fp
[0];
919 #elif defined(__riscv)
920 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
925 addr_t
*fp
= (addr_t
*)rc
->fp
;
926 while (--level
&& fp
>= (addr_t
*)0x1000)
927 fp
= (addr_t
*)fp
[-2];
928 if (fp
< (addr_t
*)0x1000)
936 #warning add arch specific rt_get_caller_pc()
937 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
943 #endif /* CONFIG_TCC_BACKTRACE */
944 /* ------------------------------------------------------------- */
945 #ifdef CONFIG_TCC_STATIC
947 /* dummy function for profiling */
948 ST_FUNC
void *dlopen(const char *filename
, int flag
)
953 ST_FUNC
void dlclose(void *p
)
957 ST_FUNC
const char *dlerror(void)
962 typedef struct TCCSyms
{
968 /* add the symbol you want here if no dynamic linking is done */
969 static TCCSyms tcc_syms
[] = {
970 #if !defined(CONFIG_TCCBOOT)
971 #define TCCSYM(a) { #a, &a, },
981 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
985 while (p
->str
!= NULL
) {
986 if (!strcmp(p
->str
, symbol
))
993 #endif /* CONFIG_TCC_STATIC */
994 #endif /* TCC_IS_NATIVE */
995 /* ------------------------------------------------------------- */