Add entry to run tests2 tests
[tinycc.git] / tccrun.c
blob18aed6112efc120546580c69f569e232ef6aa24b
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 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
111 return -1;
112 prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
114 #ifdef CONFIG_TCC_BACKTRACE
115 if (s1->do_debug) {
116 set_exception_handler();
117 rt_prog_main = prog_main;
119 #endif
121 errno = 0; /* clean errno value */
123 #ifdef CONFIG_TCC_BCHECK
124 if (s1->do_bounds_check) {
125 void (*bound_init)(void);
126 void (*bound_exit)(void);
127 void (*bound_new_region)(void *p, addr_t size);
128 int (*bound_delete_region)(void *p);
129 int i, ret;
131 /* set error function */
132 rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
133 /* XXX: use .init section so that it also work in binary ? */
134 bound_init = tcc_get_symbol_err(s1, "__bound_init");
135 bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
136 bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
137 bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
139 bound_init();
140 /* mark argv area as valid */
141 bound_new_region(argv, argc*sizeof(argv[0]));
142 for (i=0; i<argc; ++i)
143 bound_new_region(argv[i], strlen(argv[i]) + 1);
145 ret = (*prog_main)(argc, argv);
147 /* unmark argv area */
148 for (i=0; i<argc; ++i)
149 bound_delete_region(argv[i]);
150 bound_delete_region(argv);
151 bound_exit();
152 return ret;
154 #endif
155 return (*prog_main)(argc, argv);
158 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
159 #define RUN_SECTION_ALIGNMENT 63
160 #else
161 #define RUN_SECTION_ALIGNMENT 15
162 #endif
164 /* relocate code. Return -1 on error, required size if ptr is NULL,
165 otherwise copy code into buffer passed by the caller */
166 static int tcc_relocate_ex(TCCState *s1, void *ptr)
168 Section *s;
169 unsigned offset, length, fill, i, k;
170 addr_t mem;
172 if (NULL == ptr) {
173 s1->nb_errors = 0;
174 #ifdef TCC_TARGET_PE
175 pe_output_file(s1, NULL);
176 #else
177 tcc_add_runtime(s1);
178 relocate_common_syms();
179 tcc_add_linker_symbols(s1);
180 build_got_entries(s1);
181 #endif
182 if (s1->nb_errors)
183 return -1;
186 offset = 0, mem = (addr_t)ptr;
187 fill = -mem & RUN_SECTION_ALIGNMENT;
188 #ifdef _WIN64
189 offset += sizeof (void*);
190 #endif
191 for (k = 0; k < 2; ++k) {
192 for(i = 1; i < s1->nb_sections; i++) {
193 s = s1->sections[i];
194 if (0 == (s->sh_flags & SHF_ALLOC))
195 continue;
196 if (k != !(s->sh_flags & SHF_EXECINSTR))
197 continue;
198 offset += fill;
199 s->sh_addr = mem ? mem + offset : 0;
200 #if 0
201 if (mem)
202 printf("%-16s +%02lx %p %04x\n",
203 s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset);
204 #endif
205 offset += s->data_offset;
206 fill = -(mem + offset) & 15;
208 #if RUN_SECTION_ALIGNMENT > 15
209 /* To avoid that x86 processors would reload cached instructions each time
210 when data is written in the near, we need to make sure that code and data
211 do not share the same 64 byte unit */
212 fill = -(mem + offset) & RUN_SECTION_ALIGNMENT;
213 #endif
216 /* relocate symbols */
217 relocate_syms(s1, s1->symtab, 1);
218 if (s1->nb_errors)
219 return -1;
221 if (0 == mem)
222 return offset + RUN_SECTION_ALIGNMENT;
224 /* relocate each section */
225 for(i = 1; i < s1->nb_sections; i++) {
226 s = s1->sections[i];
227 if (s->reloc)
228 relocate_section(s1, s);
230 relocate_plt(s1);
232 #ifdef _WIN64
233 *(void**)ptr = win64_add_function_table(s1);
234 #endif
236 for(i = 1; i < s1->nb_sections; i++) {
237 s = s1->sections[i];
238 if (0 == (s->sh_flags & SHF_ALLOC))
239 continue;
240 length = s->data_offset;
241 ptr = (void*)s->sh_addr;
242 if (NULL == s->data || s->sh_type == SHT_NOBITS)
243 memset(ptr, 0, length);
244 else
245 memcpy(ptr, s->data, length);
246 /* mark executable sections as executable in memory */
247 if (s->sh_flags & SHF_EXECINSTR)
248 set_pages_executable(ptr, length);
250 return 0;
253 /* ------------------------------------------------------------- */
254 /* allow to run code in memory */
256 static void set_pages_executable(void *ptr, unsigned long length)
258 #ifdef _WIN32
259 unsigned long old_protect;
260 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
261 #else
262 void __clear_cache(void *beginning, void *end);
263 addr_t start, end;
264 #ifndef PAGESIZE
265 # define PAGESIZE 4096
266 #endif
267 start = (addr_t)ptr & ~(PAGESIZE - 1);
268 end = (addr_t)ptr + length;
269 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
270 if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
271 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
272 # if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
273 __clear_cache(ptr, (char *)ptr + length);
274 # endif
275 #endif
278 #ifdef _WIN64
279 static void *win64_add_function_table(TCCState *s1)
281 void *p = NULL;
282 if (s1->uw_pdata) {
283 p = (void*)s1->uw_pdata->sh_addr;
284 RtlAddFunctionTable(
285 (RUNTIME_FUNCTION*)p,
286 s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
287 text_section->sh_addr
289 s1->uw_pdata = NULL;
291 return p;;
294 static void win64_del_function_table(void *p)
296 if (p) {
297 RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p);
300 #endif
302 /* ------------------------------------------------------------- */
303 #ifdef CONFIG_TCC_BACKTRACE
305 ST_FUNC void tcc_set_num_callers(int n)
307 rt_num_callers = n;
310 /* print the position in the source file of PC value 'pc' by reading
311 the stabs debug information */
312 static addr_t rt_printline(addr_t wanted_pc, const char *msg)
314 char func_name[128], last_func_name[128];
315 addr_t func_addr, last_pc, pc;
316 const char *incl_files[INCLUDE_STACK_SIZE];
317 int incl_index, len, last_line_num, i;
318 const char *str, *p;
320 Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym;
321 int stab_len = 0;
322 char *stab_str = NULL;
324 if (stab_section) {
325 stab_len = stab_section->data_offset;
326 stab_sym = (Stab_Sym *)stab_section->data;
327 stab_str = (char *) stabstr_section->data;
330 func_name[0] = '\0';
331 func_addr = 0;
332 incl_index = 0;
333 last_func_name[0] = '\0';
334 last_pc = (addr_t)-1;
335 last_line_num = 1;
337 if (!stab_sym)
338 goto no_stabs;
340 stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len);
341 for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
342 switch(sym->n_type) {
343 /* function start or end */
344 case N_FUN:
345 if (sym->n_strx == 0) {
346 /* we test if between last line and end of function */
347 pc = sym->n_value + func_addr;
348 if (wanted_pc >= last_pc && wanted_pc < pc)
349 goto found;
350 func_name[0] = '\0';
351 func_addr = 0;
352 } else {
353 str = stab_str + sym->n_strx;
354 p = strchr(str, ':');
355 if (!p) {
356 pstrcpy(func_name, sizeof(func_name), str);
357 } else {
358 len = p - str;
359 if (len > sizeof(func_name) - 1)
360 len = sizeof(func_name) - 1;
361 memcpy(func_name, str, len);
362 func_name[len] = '\0';
364 func_addr = sym->n_value;
366 break;
367 /* line number info */
368 case N_SLINE:
369 pc = sym->n_value + func_addr;
370 if (wanted_pc >= last_pc && wanted_pc < pc)
371 goto found;
372 last_pc = pc;
373 last_line_num = sym->n_desc;
374 /* XXX: slow! */
375 strcpy(last_func_name, func_name);
376 break;
377 /* include files */
378 case N_BINCL:
379 str = stab_str + sym->n_strx;
380 add_incl:
381 if (incl_index < INCLUDE_STACK_SIZE) {
382 incl_files[incl_index++] = str;
384 break;
385 case N_EINCL:
386 if (incl_index > 1)
387 incl_index--;
388 break;
389 case N_SO:
390 if (sym->n_strx == 0) {
391 incl_index = 0; /* end of translation unit */
392 } else {
393 str = stab_str + sym->n_strx;
394 /* do not add path */
395 len = strlen(str);
396 if (len > 0 && str[len - 1] != '/')
397 goto add_incl;
399 break;
403 no_stabs:
404 /* second pass: we try symtab symbols (no line number info) */
405 incl_index = 0;
406 if (symtab_section)
408 ElfW(Sym) *sym, *sym_end;
409 int type;
411 sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
412 for(sym = (ElfW(Sym) *)symtab_section->data + 1;
413 sym < sym_end;
414 sym++) {
415 type = ELFW(ST_TYPE)(sym->st_info);
416 if (type == STT_FUNC || type == STT_GNU_IFUNC) {
417 if (wanted_pc >= sym->st_value &&
418 wanted_pc < sym->st_value + sym->st_size) {
419 pstrcpy(last_func_name, sizeof(last_func_name),
420 (char *) strtab_section->data + sym->st_name);
421 func_addr = sym->st_value;
422 goto found;
427 /* did not find any info: */
428 fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc);
429 fflush(stderr);
430 return 0;
431 found:
432 i = incl_index;
433 if (i > 0)
434 fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num);
435 fprintf(stderr, "%s %p", msg, (void*)wanted_pc);
436 if (last_func_name[0] != '\0')
437 fprintf(stderr, " %s()", last_func_name);
438 if (--i >= 0) {
439 fprintf(stderr, " (included from ");
440 for (;;) {
441 fprintf(stderr, "%s", incl_files[i]);
442 if (--i < 0)
443 break;
444 fprintf(stderr, ", ");
446 fprintf(stderr, ")");
448 fprintf(stderr, "\n");
449 fflush(stderr);
450 return func_addr;
453 /* emit a run time error at position 'pc' */
454 static void rt_error(ucontext_t *uc, const char *fmt, ...)
456 va_list ap;
457 addr_t pc;
458 int i;
460 fprintf(stderr, "Runtime error: ");
461 va_start(ap, fmt);
462 vfprintf(stderr, fmt, ap);
463 va_end(ap);
464 fprintf(stderr, "\n");
466 for(i=0;i<rt_num_callers;i++) {
467 if (rt_get_caller_pc(&pc, uc, i) < 0)
468 break;
469 pc = rt_printline(pc, i ? "by" : "at");
470 if (pc == (addr_t)rt_prog_main && pc)
471 break;
475 /* ------------------------------------------------------------- */
476 #ifndef _WIN32
478 /* signal handler for fatal errors */
479 static void sig_error(int signum, siginfo_t *siginf, void *puc)
481 ucontext_t *uc = puc;
483 switch(signum) {
484 case SIGFPE:
485 switch(siginf->si_code) {
486 case FPE_INTDIV:
487 case FPE_FLTDIV:
488 rt_error(uc, "division by zero");
489 break;
490 default:
491 rt_error(uc, "floating point exception");
492 break;
494 break;
495 case SIGBUS:
496 case SIGSEGV:
497 if (rt_bound_error_msg && *rt_bound_error_msg)
498 rt_error(uc, *rt_bound_error_msg);
499 else
500 rt_error(uc, "dereferencing invalid pointer");
501 break;
502 case SIGILL:
503 rt_error(uc, "illegal instruction");
504 break;
505 case SIGABRT:
506 rt_error(uc, "abort() called");
507 break;
508 default:
509 rt_error(uc, "caught signal %d", signum);
510 break;
512 exit(255);
515 #ifndef SA_SIGINFO
516 # define SA_SIGINFO 0x00000004u
517 #endif
519 /* Generate a stack backtrace when a CPU exception occurs. */
520 static void set_exception_handler(void)
522 struct sigaction sigact;
523 /* install TCC signal handlers to print debug info on fatal
524 runtime errors */
525 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
526 sigact.sa_sigaction = sig_error;
527 sigemptyset(&sigact.sa_mask);
528 sigaction(SIGFPE, &sigact, NULL);
529 sigaction(SIGILL, &sigact, NULL);
530 sigaction(SIGSEGV, &sigact, NULL);
531 sigaction(SIGBUS, &sigact, NULL);
532 sigaction(SIGABRT, &sigact, NULL);
535 /* ------------------------------------------------------------- */
536 #ifdef __i386__
538 /* fix for glibc 2.1 */
539 #ifndef REG_EIP
540 #define REG_EIP EIP
541 #define REG_EBP EBP
542 #endif
544 /* return the PC at frame level 'level'. Return negative if not found */
545 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
547 addr_t fp;
548 int i;
550 if (level == 0) {
551 #if defined(__APPLE__)
552 *paddr = uc->uc_mcontext->__ss.__eip;
553 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
554 *paddr = uc->uc_mcontext.mc_eip;
555 #elif defined(__dietlibc__)
556 *paddr = uc->uc_mcontext.eip;
557 #elif defined(__NetBSD__)
558 *paddr = uc->uc_mcontext.__gregs[_REG_EIP];
559 #elif defined(__OpenBSD__)
560 *paddr = uc->sc_eip;
561 #else
562 *paddr = uc->uc_mcontext.gregs[REG_EIP];
563 #endif
564 return 0;
565 } else {
566 #if defined(__APPLE__)
567 fp = uc->uc_mcontext->__ss.__ebp;
568 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
569 fp = uc->uc_mcontext.mc_ebp;
570 #elif defined(__dietlibc__)
571 fp = uc->uc_mcontext.ebp;
572 #elif defined(__NetBSD__)
573 fp = uc->uc_mcontext.__gregs[_REG_EBP];
574 #elif defined(__OpenBSD__)
575 *paddr = uc->sc_ebp;
576 #else
577 fp = uc->uc_mcontext.gregs[REG_EBP];
578 #endif
579 for(i=1;i<level;i++) {
580 /* XXX: check address validity with program info */
581 if (fp <= 0x1000 || fp >= 0xc0000000)
582 return -1;
583 fp = ((addr_t *)fp)[0];
585 *paddr = ((addr_t *)fp)[1];
586 return 0;
590 /* ------------------------------------------------------------- */
591 #elif defined(__x86_64__)
593 /* return the PC at frame level 'level'. Return negative if not found */
594 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
596 addr_t fp;
597 int i;
599 if (level == 0) {
600 /* XXX: only support linux */
601 #if defined(__APPLE__)
602 *paddr = uc->uc_mcontext->__ss.__rip;
603 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
604 *paddr = uc->uc_mcontext.mc_rip;
605 #elif defined(__NetBSD__)
606 *paddr = uc->uc_mcontext.__gregs[_REG_RIP];
607 #else
608 *paddr = uc->uc_mcontext.gregs[REG_RIP];
609 #endif
610 return 0;
611 } else {
612 #if defined(__APPLE__)
613 fp = uc->uc_mcontext->__ss.__rbp;
614 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
615 fp = uc->uc_mcontext.mc_rbp;
616 #elif defined(__NetBSD__)
617 fp = uc->uc_mcontext.__gregs[_REG_RBP];
618 #else
619 fp = uc->uc_mcontext.gregs[REG_RBP];
620 #endif
621 for(i=1;i<level;i++) {
622 /* XXX: check address validity with program info */
623 if (fp <= 0x1000)
624 return -1;
625 fp = ((addr_t *)fp)[0];
627 *paddr = ((addr_t *)fp)[1];
628 return 0;
632 /* ------------------------------------------------------------- */
633 #elif defined(__arm__)
635 /* return the PC at frame level 'level'. Return negative if not found */
636 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
638 addr_t fp, sp;
639 int i;
641 if (level == 0) {
642 /* XXX: only supports linux */
643 #if defined(__linux__)
644 *paddr = uc->uc_mcontext.arm_pc;
645 #else
646 return -1;
647 #endif
648 return 0;
649 } else {
650 #if defined(__linux__)
651 fp = uc->uc_mcontext.arm_fp;
652 sp = uc->uc_mcontext.arm_sp;
653 if (sp < 0x1000)
654 sp = 0x1000;
655 #else
656 return -1;
657 #endif
658 /* XXX: specific to tinycc stack frames */
659 if (fp < sp + 12 || fp & 3)
660 return -1;
661 for(i = 1; i < level; i++) {
662 sp = ((addr_t *)fp)[-2];
663 if (sp < fp || sp - fp > 16 || sp & 3)
664 return -1;
665 fp = ((addr_t *)fp)[-3];
666 if (fp <= sp || fp - sp < 12 || fp & 3)
667 return -1;
669 /* XXX: check address validity with program info */
670 *paddr = ((addr_t *)fp)[-1];
671 return 0;
675 /* ------------------------------------------------------------- */
676 #elif defined(__aarch64__)
678 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
680 if (level < 0)
681 return -1;
682 else if (level == 0) {
683 *paddr = uc->uc_mcontext.pc;
684 return 0;
686 else {
687 addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
688 int i;
689 for (i = 1; i < level; i++)
690 fp = (addr_t *)fp[0];
691 *paddr = fp[1];
692 return 0;
696 /* ------------------------------------------------------------- */
697 #else
699 #warning add arch specific rt_get_caller_pc()
700 static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
702 return -1;
705 #endif /* !__i386__ */
707 /* ------------------------------------------------------------- */
708 #else /* WIN32 */
710 static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
712 EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
713 CONTEXT *uc = ex_info->ContextRecord;
714 switch (er->ExceptionCode) {
715 case EXCEPTION_ACCESS_VIOLATION:
716 if (rt_bound_error_msg && *rt_bound_error_msg)
717 rt_error(uc, *rt_bound_error_msg);
718 else
719 rt_error(uc, "access violation");
720 break;
721 case EXCEPTION_STACK_OVERFLOW:
722 rt_error(uc, "stack overflow");
723 break;
724 case EXCEPTION_INT_DIVIDE_BY_ZERO:
725 rt_error(uc, "division by zero");
726 break;
727 default:
728 rt_error(uc, "exception caught");
729 break;
731 return EXCEPTION_EXECUTE_HANDLER;
734 /* Generate a stack backtrace when a CPU exception occurs. */
735 static void set_exception_handler(void)
737 SetUnhandledExceptionFilter(cpu_exception_handler);
740 /* return the PC at frame level 'level'. Return non zero if not found */
741 static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
743 addr_t fp, pc;
744 int i;
745 #ifdef _WIN64
746 pc = uc->Rip;
747 fp = uc->Rbp;
748 #else
749 pc = uc->Eip;
750 fp = uc->Ebp;
751 #endif
752 if (level > 0) {
753 for(i=1;i<level;i++) {
754 /* XXX: check address validity with program info */
755 if (fp <= 0x1000 || fp >= 0xc0000000)
756 return -1;
757 fp = ((addr_t*)fp)[0];
759 pc = ((addr_t*)fp)[1];
761 *paddr = pc;
762 return 0;
765 #endif /* _WIN32 */
766 #endif /* CONFIG_TCC_BACKTRACE */
767 /* ------------------------------------------------------------- */
768 #ifdef CONFIG_TCC_STATIC
770 /* dummy function for profiling */
771 ST_FUNC void *dlopen(const char *filename, int flag)
773 return NULL;
776 ST_FUNC void dlclose(void *p)
780 ST_FUNC const char *dlerror(void)
782 return "error";
785 typedef struct TCCSyms {
786 char *str;
787 void *ptr;
788 } TCCSyms;
791 /* add the symbol you want here if no dynamic linking is done */
792 static TCCSyms tcc_syms[] = {
793 #if !defined(CONFIG_TCCBOOT)
794 #define TCCSYM(a) { #a, &a, },
795 TCCSYM(printf)
796 TCCSYM(fprintf)
797 TCCSYM(fopen)
798 TCCSYM(fclose)
799 #undef TCCSYM
800 #endif
801 { NULL, NULL },
804 ST_FUNC void *dlsym(void *handle, const char *symbol)
806 TCCSyms *p;
807 p = tcc_syms;
808 while (p->str != NULL) {
809 if (!strcmp(p->str, symbol))
810 return p->ptr;
811 p++;
813 return NULL;
816 #endif /* CONFIG_TCC_STATIC */
817 #endif /* TCC_IS_NATIVE */
818 /* ------------------------------------------------------------- */