riscv64: adjust for cast changes
[tinycc.git] / tccrun.c
blobcca6a2512f8aeb2bb7a669967578a0314b78e400
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;
90 #else
91 ptr = tcc_malloc(size);
92 #endif
93 tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */
94 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
95 return 0;
98 ST_FUNC void tcc_run_free(TCCState *s1)
100 int i;
102 for (i = 0; i < s1->nb_runtime_mem; ++i) {
103 #ifdef HAVE_SELINUX
104 unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
105 munmap(s1->runtime_mem[i++], size);
106 munmap(s1->runtime_mem[i], size);
107 #else
108 #ifdef _WIN64
109 win64_del_function_table(*(void**)s1->runtime_mem[i]);
110 #endif
111 tcc_free(s1->runtime_mem[i]);
112 #endif
114 tcc_free(s1->runtime_mem);
115 if (get_s1_for_run() == s1)
116 set_s1_for_run(NULL);
119 /* launch the compiled program with the given arguments */
120 LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
122 int (*prog_main)(int, char **);
124 s1->runtime_main = s1->nostdlib ? "_start" : "main";
125 if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
126 return 0;
127 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
128 return -1;
129 prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
131 #ifdef CONFIG_TCC_BACKTRACE
132 if (s1->do_debug) {
133 set_exception_handler();
134 s1->rt_prog_main = prog_main;
135 /* set global state pointer for exception handlers*/
136 set_s1_for_run(s1);
138 #endif
140 errno = 0; /* clean errno value */
142 #ifdef CONFIG_TCC_BCHECK
143 if (s1->do_bounds_check) {
144 void (*bound_init)(void);
145 void (*bound_exit)(void);
146 void (*bounds_add_static_var)(size_t *p);
147 size_t *bounds_start;
148 int ret;
150 /* set error function */
151 s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
152 /* XXX: use .init section so that it also work in binary ? */
153 bound_init = tcc_get_symbol_err(s1, "__bound_init");
154 bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
155 bounds_add_static_var = tcc_get_symbol_err(s1, "__bounds_add_static_var");
156 bounds_start = tcc_get_symbol_err(s1, "__bounds_start");
158 bound_init();
159 bounds_add_static_var (bounds_start);
161 ret = (*prog_main)(argc, argv);
163 bound_exit();
164 return ret;
166 #endif
167 return (*prog_main)(argc, argv);
170 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
171 /* To avoid that x86 processors would reload cached instructions
172 each time when data is written in the near, we need to make
173 sure that code and data do not share the same 64 byte unit */
174 #define RUN_SECTION_ALIGNMENT 63
175 #else
176 #define RUN_SECTION_ALIGNMENT 0
177 #endif
179 /* relocate code. Return -1 on error, required size if ptr is NULL,
180 otherwise copy code into buffer passed by the caller */
181 static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
183 Section *s;
184 unsigned offset, length, align, max_align, i, k, f;
185 addr_t mem, addr;
187 if (NULL == ptr) {
188 s1->nb_errors = 0;
189 #ifdef TCC_TARGET_PE
190 pe_output_file(s1, NULL);
191 #else
192 tcc_add_runtime(s1);
193 resolve_common_syms(s1);
194 build_got_entries(s1);
195 #endif
196 if (s1->nb_errors)
197 return -1;
200 offset = max_align = 0, mem = (addr_t)ptr;
201 #ifdef _WIN64
202 offset += sizeof (void*); /* space for function_table pointer */
203 #endif
204 for (k = 0; k < 2; ++k) {
205 f = 0, addr = k ? mem : mem + ptr_diff;
206 for(i = 1; i < s1->nb_sections; i++) {
207 s = s1->sections[i];
208 if (0 == (s->sh_flags & SHF_ALLOC))
209 continue;
210 if (k != !(s->sh_flags & SHF_EXECINSTR))
211 continue;
212 align = s->sh_addralign - 1;
213 if (++f == 1 && align < RUN_SECTION_ALIGNMENT)
214 align = RUN_SECTION_ALIGNMENT;
215 if (max_align < align)
216 max_align = align;
217 offset += -(addr + offset) & align;
218 s->sh_addr = mem ? addr + offset : 0;
219 offset += s->data_offset;
220 #if 0
221 if (mem)
222 printf("%-16s %p len %04x align %2d\n",
223 s->name, (void*)s->sh_addr, (unsigned)s->data_offset, align + 1);
224 #endif
228 /* relocate symbols */
229 relocate_syms(s1, s1->symtab, 1);
230 if (s1->nb_errors)
231 return -1;
233 if (0 == mem)
234 return offset + max_align;
236 #ifdef TCC_TARGET_PE
237 s1->pe_imagebase = mem;
238 #endif
240 /* relocate each section */
241 for(i = 1; i < s1->nb_sections; i++) {
242 s = s1->sections[i];
243 if (s->reloc)
244 relocate_section(s1, s);
246 #ifndef TCC_TARGET_PE
247 relocate_plt(s1);
248 #endif
250 for(i = 1; i < s1->nb_sections; i++) {
251 s = s1->sections[i];
252 if (0 == (s->sh_flags & SHF_ALLOC))
253 continue;
254 length = s->data_offset;
255 ptr = (void*)s->sh_addr;
256 if (s->sh_flags & SHF_EXECINSTR)
257 ptr = (char*)ptr - ptr_diff;
258 if (NULL == s->data || s->sh_type == SHT_NOBITS)
259 memset(ptr, 0, length);
260 else
261 memcpy(ptr, s->data, length);
262 /* mark executable sections as executable in memory */
263 if (s->sh_flags & SHF_EXECINSTR)
264 set_pages_executable(s1, (char*)ptr + ptr_diff, length);
267 #ifdef _WIN64
268 *(void**)mem = win64_add_function_table(s1);
269 #endif
271 return 0;
274 /* ------------------------------------------------------------- */
275 /* allow to run code in memory */
277 static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length)
279 #ifdef _WIN32
280 unsigned long old_protect;
281 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
282 #else
283 void __clear_cache(void *beginning, void *end);
284 # ifndef HAVE_SELINUX
285 addr_t start, end;
286 # ifndef PAGESIZE
287 # define PAGESIZE 4096
288 # endif
289 start = (addr_t)ptr & ~(PAGESIZE - 1);
290 end = (addr_t)ptr + length;
291 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
292 if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
293 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
294 # endif
295 # if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
296 __clear_cache(ptr, (char *)ptr + length);
297 # endif
298 #endif
301 #ifdef _WIN64
302 static void *win64_add_function_table(TCCState *s1)
304 void *p = NULL;
305 if (s1->uw_pdata) {
306 p = (void*)s1->uw_pdata->sh_addr;
307 RtlAddFunctionTable(
308 (RUNTIME_FUNCTION*)p,
309 s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
310 s1->pe_imagebase
312 s1->uw_pdata = NULL;
314 return p;
317 static void win64_del_function_table(void *p)
319 if (p) {
320 RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p);
323 #endif
325 /* ------------------------------------------------------------- */
326 #ifdef CONFIG_TCC_BACKTRACE
328 #define INCLUDE_STACK_SIZE 32
329 static int rt_vprintf(const char *fmt, va_list ap)
331 int ret = vfprintf(stderr, fmt, ap);
332 fflush(stderr);
333 return ret;
336 static int rt_printf(const char *fmt, ...)
338 va_list ap;
339 int r;
340 va_start(ap, fmt);
341 r = rt_vprintf(fmt, ap);
342 va_end(ap);
343 return r;
346 /* print the position in the source file of PC value 'pc' by reading
347 the stabs debug information */
348 static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
350 char func_name[128];
351 addr_t func_addr, last_pc, pc;
352 const char *incl_files[INCLUDE_STACK_SIZE];
353 int incl_index, last_incl_index, len, last_line_num, i;
354 const char *str, *p;
356 ElfW(Sym) *esym_start = NULL, *esym_end = NULL, *esym;
357 Stab_Sym *stab_sym = NULL, *stab_sym_end = NULL, *sym;
358 char *stab_str = NULL;
359 char *elf_str = NULL;
361 func_name[0] = '\0';
362 func_addr = 0;
363 incl_index = 0;
364 last_pc = (addr_t)-1;
365 last_line_num = 1;
366 last_incl_index = 0;
368 if (stab_section) {
369 stab_sym = (Stab_Sym *)stab_section->data;
370 stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
371 stab_str = (char *) stab_section->link->data;
373 if (symtab_section) {
374 esym_start = (ElfW(Sym) *)(symtab_section->data);
375 esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
376 elf_str = (char *) symtab_section->link->data;
379 for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
380 str = stab_str + sym->n_strx;
381 pc = sym->n_value;
383 switch(sym->n_type) {
384 case N_SLINE:
385 if (func_addr)
386 goto rel_pc;
387 case N_SO:
388 case N_SOL:
389 goto abs_pc;
390 case N_FUN:
391 if (sym->n_strx == 0) /* end of function */
392 goto rel_pc;
393 abs_pc:
394 if (sizeof pc == 8)
395 /* Stab_Sym.n_value is only 32bits */
396 pc |= wanted_pc & 0xffffffff00000000ULL;
397 break;
398 rel_pc:
399 pc += func_addr;
400 break;
403 if (pc > wanted_pc && wanted_pc > last_pc)
404 goto found;
406 switch(sym->n_type) {
407 /* function start or end */
408 case N_FUN:
409 if (sym->n_strx == 0)
410 goto reset_func;
411 p = strchr(str, ':');
412 if (0 == p || (len = p - str + 1, len > sizeof func_name))
413 len = sizeof func_name;
414 pstrcpy(func_name, len, str);
415 func_addr = pc;
416 break;
417 /* line number info */
418 case N_SLINE:
419 last_pc = pc;
420 last_line_num = sym->n_desc;
421 last_incl_index = incl_index;
422 if (pc == wanted_pc)
423 goto found;
424 break;
425 /* include files */
426 case N_BINCL:
427 if (incl_index < INCLUDE_STACK_SIZE)
428 incl_files[incl_index++] = str;
429 break;
430 case N_EINCL:
431 if (incl_index > 1)
432 incl_index--;
433 break;
434 /* start/end of translation unit */
435 case N_SO:
436 incl_index = 0;
437 if (sym->n_strx) {
438 /* do not add path */
439 len = strlen(str);
440 if (len > 0 && str[len - 1] != '/')
441 incl_files[incl_index++] = str;
443 reset_func:
444 func_name[0] = '\0';
445 func_addr = 0;
446 last_pc = (addr_t)-1;
447 break;
448 /* alternative file name (from #line or #include directives) */
449 case N_SOL:
450 if (incl_index)
451 incl_files[incl_index-1] = str;
452 break;
456 /* we try symtab symbols (no line number info) */
457 for (esym = esym_start + 1; esym < esym_end; ++esym) {
458 int type = ELFW(ST_TYPE)(esym->st_info);
459 if (type == STT_FUNC || type == STT_GNU_IFUNC) {
460 if (wanted_pc >= esym->st_value &&
461 wanted_pc < esym->st_value + esym->st_size) {
462 pstrcpy(func_name, sizeof(func_name),
463 elf_str + esym->st_name);
464 func_addr = esym->st_value;
465 last_incl_index = 0;
466 goto found;
470 /* did not find any info: */
471 rt_printf("%s %p ???", msg, (void*)wanted_pc);
472 return 0;
474 found:
475 i = last_incl_index;
476 if (i > 0)
477 rt_printf("%s:%d: ", incl_files[--i], last_line_num);
478 rt_printf("%s %p", msg, (void*)wanted_pc);
479 if (func_name[0] != '\0')
480 rt_printf(" %s()", func_name);
481 if (--i >= 0) {
482 rt_printf(" (included from ");
483 for (;;) {
484 rt_printf("%s", incl_files[i]);
485 if (--i < 0)
486 break;
487 rt_printf(", ");
489 rt_printf(")");
491 return func_addr;
494 typedef struct rt_context {
495 addr_t ip, fp, sp, pc;
496 } rt_context;
498 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
500 /* emit a run time error at position 'pc' */
501 static void rt_error(rt_context *rc, const char *fmt, ...)
503 va_list ap;
504 addr_t pc;
505 int i;
506 TCCState *s1;
508 s1 = get_s1_for_run();
509 if (*fmt == ' ') {
510 if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
511 fmt = *s1->rt_bound_error_msg;
512 else
513 ++fmt;
516 rt_printf("Runtime error: ");
517 va_start(ap, fmt);
518 rt_vprintf(fmt, ap);
519 va_end(ap);
520 rt_printf("\n");
522 if (!s1)
523 return;
525 for(i=0; i<s1->rt_num_callers; i++) {
526 if (rt_get_caller_pc(&pc, rc, i) < 0)
527 break;
528 pc = rt_printline(s1, pc, i ? "by" : "at");
529 rt_printf("\n");
530 if (pc == (addr_t)s1->rt_prog_main && pc)
531 break;
535 /* ------------------------------------------------------------- */
537 #ifndef _WIN32
538 # include <signal.h>
539 # ifndef __OpenBSD__
540 # include <sys/ucontext.h>
541 # endif
542 #else
543 # define ucontext_t CONTEXT
544 #endif
546 /* translate from ucontext_t* to internal rt_context * */
547 static void rt_getcontext(ucontext_t *uc, rt_context *rc)
549 #if defined _WIN64
550 rc->ip = uc->Rip;
551 rc->fp = uc->Rbp;
552 rc->sp = uc->Rsp;
553 #elif defined _WIN32
554 rc->ip = uc->Eip;
555 rc->fp = uc->Ebp;
556 rc->sp = uc->Esp;
557 #elif defined __i386__
558 # if defined(__APPLE__)
559 rc->ip = uc->uc_mcontext->__ss.__eip;
560 rc->fp = uc->uc_mcontext->__ss.__ebp;
561 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
562 rc->ip = uc->uc_mcontext.mc_eip;
563 rc->fp = uc->uc_mcontext.mc_ebp;
564 # elif defined(__dietlibc__)
565 rc->ip = uc->uc_mcontext.eip;
566 rc->fp = uc->uc_mcontext.ebp;
567 # elif defined(__NetBSD__)
568 rc->ip = uc->uc_mcontext.__gregs[_REG_EIP];
569 rc->fp = uc->uc_mcontext.__gregs[_REG_EBP];
570 # elif defined(__OpenBSD__)
571 rc->ip = uc->sc_eip;
572 rc->fp = uc->sc_ebp;
573 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
574 rc->ip = uc->uc_mcontext.gregs[EIP];
575 rc->fp = uc->uc_mcontext.gregs[EBP];
576 # else
577 rc->ip = uc->uc_mcontext.gregs[REG_EIP];
578 rc->fp = uc->uc_mcontext.gregs[REG_EBP];
579 # endif
580 #elif defined(__x86_64__)
581 # if defined(__APPLE__)
582 rc->ip = uc->uc_mcontext->__ss.__rip;
583 rc->fp = uc->uc_mcontext->__ss.__rbp;
584 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
585 rc->ip = uc->uc_mcontext.mc_rip;
586 rc->fp = uc->uc_mcontext.mc_rbp;
587 # elif defined(__NetBSD__)
588 rc->ip = uc->uc_mcontext.__gregs[_REG_RIP];
589 rc->fp = uc->uc_mcontext.__gregs[_REG_RBP];
590 # else
591 rc->ip = uc->uc_mcontext.gregs[REG_RIP];
592 rc->fp = uc->uc_mcontext.gregs[REG_RBP];
593 # endif
594 #elif defined(__arm__)
595 rc->ip = uc->uc_mcontext.arm_pc;
596 rc->fp = uc->uc_mcontext.arm_fp;
597 rc->sp = uc->uc_mcontext.arm_sp;
598 #elif defined(__aarch64__)
599 rc->ip = uc->uc_mcontext.pc;
600 rc->fp = uc->uc_mcontext.regs[29];
601 #endif
604 /* ------------------------------------------------------------- */
605 #ifndef _WIN32
606 /* signal handler for fatal errors */
607 static void sig_error(int signum, siginfo_t *siginf, void *puc)
609 rt_context rc;
611 rt_getcontext(puc, &rc);
612 switch(signum) {
613 case SIGFPE:
614 switch(siginf->si_code) {
615 case FPE_INTDIV:
616 case FPE_FLTDIV:
617 rt_error(&rc, "division by zero");
618 break;
619 default:
620 rt_error(&rc, "floating point exception");
621 break;
623 break;
624 case SIGBUS:
625 case SIGSEGV:
626 rt_error(&rc, " dereferencing invalid pointer");
627 break;
628 case SIGILL:
629 rt_error(&rc, "illegal instruction");
630 break;
631 case SIGABRT:
632 rt_error(&rc, "abort() called");
633 break;
634 default:
635 rt_error(&rc, "caught signal %d", signum);
636 break;
638 exit(255);
641 #ifndef SA_SIGINFO
642 # define SA_SIGINFO 0x00000004u
643 #endif
645 /* Generate a stack backtrace when a CPU exception occurs. */
646 static void set_exception_handler(void)
648 struct sigaction sigact;
649 /* install TCC signal handlers to print debug info on fatal
650 runtime errors */
651 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
652 sigact.sa_sigaction = sig_error;
653 sigemptyset(&sigact.sa_mask);
654 sigaction(SIGFPE, &sigact, NULL);
655 sigaction(SIGILL, &sigact, NULL);
656 sigaction(SIGSEGV, &sigact, NULL);
657 sigaction(SIGBUS, &sigact, NULL);
658 sigaction(SIGABRT, &sigact, NULL);
661 #else /* WIN32 */
662 /* signal handler for fatal errors */
663 static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
665 rt_context rc;
666 unsigned code;
668 rt_getcontext(ex_info->ContextRecord, &rc);
669 switch (code = ex_info->ExceptionRecord->ExceptionCode) {
670 case EXCEPTION_ACCESS_VIOLATION:
671 rt_error(&rc, " access violation");
672 break;
673 case EXCEPTION_STACK_OVERFLOW:
674 rt_error(&rc, "stack overflow");
675 break;
676 case EXCEPTION_INT_DIVIDE_BY_ZERO:
677 rt_error(&rc, "division by zero");
678 break;
679 case EXCEPTION_BREAKPOINT:
680 case EXCEPTION_SINGLE_STEP:
681 rc.ip = *(addr_t*)rc.sp;
682 rt_error(&rc, "^breakpoint/single-step exception:");
683 return EXCEPTION_CONTINUE_SEARCH;
684 default:
685 rt_error(&rc, "caught exception %08x", code);
686 break;
688 return EXCEPTION_EXECUTE_HANDLER;
691 /* Generate a stack backtrace when a CPU exception occurs. */
692 static void set_exception_handler(void)
694 SetUnhandledExceptionFilter(cpu_exception_handler);
697 #endif
699 /* ------------------------------------------------------------- */
700 /* return the PC at frame level 'level'. Return negative if not found */
701 #if defined(__i386__) || defined(__x86_64__)
702 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
704 addr_t ip, fp;
705 if (level == 0) {
706 ip = rc->ip;
707 } else {
708 ip = 0;
709 fp = rc->fp;
710 while (--level) {
711 /* XXX: check address validity with program info */
712 if (fp <= 0x1000)
713 break;
714 fp = ((addr_t *)fp)[0];
716 if (fp > 0x1000)
717 ip = ((addr_t *)fp)[1];
719 if (ip <= 0x1000)
720 return -1;
721 *paddr = ip;
722 return 0;
725 #elif defined(__arm__)
726 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
728 /* XXX: only supports linux */
729 #if !defined(__linux__)
730 return -1;
731 #else
732 if (level == 0) {
733 *paddr = rc->ip;
734 } else {
735 addr_t fp = rc->fp;
736 addr_t sp = rc->sp;
737 if (sp < 0x1000)
738 sp = 0x1000;
739 /* XXX: specific to tinycc stack frames */
740 if (fp < sp + 12 || fp & 3)
741 return -1;
742 while (--level) {
743 sp = ((addr_t *)fp)[-2];
744 if (sp < fp || sp - fp > 16 || sp & 3)
745 return -1;
746 fp = ((addr_t *)fp)[-3];
747 if (fp <= sp || fp - sp < 12 || fp & 3)
748 return -1;
750 /* XXX: check address validity with program info */
751 *paddr = ((addr_t *)fp)[-1];
753 return 0;
754 #endif
757 #elif defined(__aarch64__)
758 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
760 if (level == 0) {
761 *paddr = rc->ip;
762 } else {
763 addr_t *fp = (addr_t*)rc->fp;
764 while (--level)
765 fp = (addr_t *)fp[0];
766 *paddr = fp[1];
768 return 0;
771 #else
772 #warning add arch specific rt_get_caller_pc()
773 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
775 return -1;
778 #endif
779 #endif /* CONFIG_TCC_BACKTRACE */
781 /* ------------------------------------------------------------- */
782 #ifdef CONFIG_TCC_STATIC
784 /* dummy function for profiling */
785 ST_FUNC void *dlopen(const char *filename, int flag)
787 return NULL;
790 ST_FUNC void dlclose(void *p)
794 ST_FUNC const char *dlerror(void)
796 return "error";
799 typedef struct TCCSyms {
800 char *str;
801 void *ptr;
802 } TCCSyms;
805 /* add the symbol you want here if no dynamic linking is done */
806 static TCCSyms tcc_syms[] = {
807 #if !defined(CONFIG_TCCBOOT)
808 #define TCCSYM(a) { #a, &a, },
809 TCCSYM(printf)
810 TCCSYM(fprintf)
811 TCCSYM(fopen)
812 TCCSYM(fclose)
813 #undef TCCSYM
814 #endif
815 { NULL, NULL },
818 ST_FUNC void *dlsym(void *handle, const char *symbol)
820 TCCSyms *p;
821 p = tcc_syms;
822 while (p->str != NULL) {
823 if (!strcmp(p->str, symbol))
824 return p->ptr;
825 p++;
827 return NULL;
830 #endif /* CONFIG_TCC_STATIC */
831 #endif /* TCC_IS_NATIVE */
832 /* ------------------------------------------------------------- */