Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  TCC - Tiny C Compiler - Support for -run switch
  3.  *
  4.  *  Copyright (c) 2001-2004 Fabrice Bellard
  5.  *
  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.
  10.  *
  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.
  15.  *
  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
  19.  */
  20.  
  21. #include "tcc.h"
  22.  
  23. /* only native compiler supports -run */
  24. #ifdef TCC_IS_NATIVE
  25.  
  26. #ifdef CONFIG_TCC_BACKTRACE
  27. ST_DATA int rt_num_callers = 6;
  28. ST_DATA const char **rt_bound_error_msg;
  29. ST_DATA void *rt_prog_main;
  30. #endif
  31.  
  32. #ifdef _WIN32
  33. #define ucontext_t CONTEXT
  34. #endif
  35.  
  36. static void set_pages_executable(void *ptr, unsigned long length);
  37. static void set_exception_handler(void);
  38. static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
  39. static void rt_error(ucontext_t *uc, const char *fmt, ...);
  40. static int tcc_relocate_ex(TCCState *s1, void *ptr);
  41.  
  42. #ifdef _WIN64
  43. static void win64_add_function_table(TCCState *s1);
  44. #endif
  45.  
  46. /* ------------------------------------------------------------- */
  47. /* Do all relocations (needed before using tcc_get_symbol())
  48.    Returns -1 on error. */
  49.  
  50. LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
  51. {
  52.     int ret;
  53.  
  54.     if (TCC_RELOCATE_AUTO != ptr)
  55.         return tcc_relocate_ex(s1, ptr);
  56.  
  57.     ret = tcc_relocate_ex(s1, NULL);
  58.     if (ret < 0)
  59.         return ret;
  60.  
  61. #ifdef HAVE_SELINUX
  62.     {   /* Use mmap instead of malloc for Selinux.  Ref:
  63.            http://www.gnu.org/s/libc/manual/html_node/File-Size.html */
  64.  
  65.         char tmpfname[] = "/tmp/.tccrunXXXXXX";
  66.         int fd = mkstemp (tmpfname);
  67.  
  68.         s1->mem_size = ret;
  69.         unlink (tmpfname);
  70.         ftruncate (fd, s1->mem_size);
  71.  
  72.         s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
  73.             MAP_SHARED, fd, 0);
  74.         if (s1->write_mem == MAP_FAILED)
  75.             tcc_error("/tmp not writeable");
  76.  
  77.         s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
  78.             MAP_SHARED, fd, 0);
  79.         if (s1->runtime_mem == MAP_FAILED)
  80.             tcc_error("/tmp not executable");
  81.  
  82.         ret = tcc_relocate_ex(s1, s1->write_mem);
  83.     }
  84. #else
  85.     s1->runtime_mem = tcc_malloc(ret);
  86.     ret = tcc_relocate_ex(s1, s1->runtime_mem);
  87. #endif
  88.     return ret;
  89. }
  90.  
  91. /* launch the compiled program with the given arguments */
  92. LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
  93. {
  94.     int (*prog_main)(int, char **);
  95.     int ret;
  96.  
  97.     if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
  98.         return -1;
  99.  
  100.     prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
  101.  
  102. #ifdef CONFIG_TCC_BACKTRACE
  103.     if (s1->do_debug) {
  104.         set_exception_handler();
  105.         rt_prog_main = prog_main;
  106.     }
  107. #endif
  108.  
  109. #ifdef CONFIG_TCC_BCHECK
  110.     if (s1->do_bounds_check) {
  111.         void (*bound_init)(void);
  112.         void (*bound_exit)(void);
  113.         void (*bound_new_region)(void *p, addr_t size);
  114.         int  (*bound_delete_region)(void *p);
  115.         int i;
  116.  
  117.         /* set error function */
  118.         rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
  119.         /* XXX: use .init section so that it also work in binary ? */
  120.         bound_init = tcc_get_symbol_err(s1, "__bound_init");
  121.         bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
  122.         bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
  123.         bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
  124.         bound_init();
  125.         /* mark argv area as valid */
  126.         bound_new_region(argv, argc*sizeof(argv[0]));
  127.         for (i=0; i<argc; ++i)
  128.             bound_new_region(argv[i], strlen(argv[i]));
  129.  
  130.         errno = 0; /* clean errno value */
  131.         ret = (*prog_main)(argc, argv);
  132.  
  133.         /* unmark argv area */
  134.         for (i=0; i<argc; ++i)
  135.             bound_delete_region(argv[i]);
  136.         bound_delete_region(argv);
  137.  
  138.         bound_exit();
  139.     } else
  140. #endif
  141.     {
  142.         errno = 0; /* clean errno value */
  143.         ret = (*prog_main)(argc, argv);
  144.     }
  145.     return ret;
  146. }
  147.  
  148. /* relocate code. Return -1 on error, required size if ptr is NULL,
  149.    otherwise copy code into buffer passed by the caller */
  150. static int tcc_relocate_ex(TCCState *s1, void *ptr)
  151. {
  152.     Section *s;
  153.     unsigned long offset, length;
  154.     addr_t mem;
  155.     int i;
  156.  
  157.     if (NULL == ptr) {
  158.         s1->nb_errors = 0;
  159. #ifdef TCC_TARGET_PE
  160.         pe_output_file(s1, NULL);
  161. #else
  162.         tcc_add_runtime(s1);
  163.         relocate_common_syms();
  164.         tcc_add_linker_symbols(s1);
  165.         build_got_entries(s1);
  166. #endif
  167.         if (s1->nb_errors)
  168.             return -1;
  169.     }
  170.  
  171.     offset = 0, mem = (addr_t)ptr;
  172.     for(i = 1; i < s1->nb_sections; i++) {
  173.         s = s1->sections[i];
  174.         if (0 == (s->sh_flags & SHF_ALLOC))
  175.             continue;
  176.         length = s->data_offset;
  177.         s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
  178.         offset = (offset + length + 15) & ~15;
  179.     }
  180.     offset += 16;
  181.  
  182.     /* relocate symbols */
  183.     relocate_syms(s1, 1);
  184.     if (s1->nb_errors)
  185.         return -1;
  186.  
  187.     if (0 == mem)
  188.         return offset;
  189.  
  190.     /* relocate each section */
  191.     for(i = 1; i < s1->nb_sections; i++) {
  192.         s = s1->sections[i];
  193.         if (s->reloc)
  194.             relocate_section(s1, s);
  195.     }
  196.     relocate_plt(s1);
  197.  
  198.     for(i = 1; i < s1->nb_sections; i++) {
  199.         s = s1->sections[i];
  200.         if (0 == (s->sh_flags & SHF_ALLOC))
  201.             continue;
  202.         length = s->data_offset;
  203.         // printf("%-12s %08lx %04x\n", s->name, s->sh_addr, length);
  204.         ptr = (void*)s->sh_addr;
  205.         if (NULL == s->data || s->sh_type == SHT_NOBITS)
  206.             memset(ptr, 0, length);
  207.         else
  208.             memcpy(ptr, s->data, length);
  209.         /* mark executable sections as executable in memory */
  210.         if (s->sh_flags & SHF_EXECINSTR)
  211.             set_pages_executable(ptr, length);
  212.     }
  213.  
  214. #ifdef _WIN64
  215.     win64_add_function_table(s1);
  216. #endif
  217.     return 0;
  218. }
  219.  
  220. /* ------------------------------------------------------------- */
  221. /* allow to run code in memory */
  222.  
  223. static void set_pages_executable(void *ptr, unsigned long length)
  224. {
  225. #ifdef _WIN32
  226.     unsigned long old_protect;
  227.     VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
  228. #else
  229.     extern void __clear_cache(void *beginning, void *end);
  230. #ifndef PAGESIZE
  231. # define PAGESIZE 4096
  232. #endif
  233.     addr_t start, end;
  234.     start = (addr_t)ptr & ~(PAGESIZE - 1);
  235.     end = (addr_t)ptr + length;
  236.     end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
  237.     mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
  238.   #ifndef __PCC__
  239.     __clear_cache(ptr, (char *)ptr + length);
  240.   #else
  241.     /* pcc 1.2.0.DEVEL 20141206 don't have such proc */
  242.   #endif
  243. #endif
  244. }
  245.  
  246. /* ------------------------------------------------------------- */
  247. #ifdef CONFIG_TCC_BACKTRACE
  248.  
  249. ST_FUNC void tcc_set_num_callers(int n)
  250. {
  251.     rt_num_callers = n;
  252. }
  253.  
  254. /* print the position in the source file of PC value 'pc' by reading
  255.    the stabs debug information */
  256. static addr_t rt_printline(addr_t wanted_pc, const char *msg)
  257. {
  258.     char func_name[128], last_func_name[128];
  259.     addr_t func_addr, last_pc, pc;
  260.     const char *incl_files[INCLUDE_STACK_SIZE];
  261.     int incl_index, len, last_line_num, i;
  262.     const char *str, *p;
  263.  
  264.     Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym;
  265.     int stab_len = 0;
  266.     char *stab_str = NULL;
  267.  
  268.     if (stab_section) {
  269.         stab_len = stab_section->data_offset;
  270.         stab_sym = (Stab_Sym *)stab_section->data;
  271.         stab_str = (char *) stabstr_section->data;
  272.     }
  273.  
  274.     func_name[0] = '\0';
  275.     func_addr = 0;
  276.     incl_index = 0;
  277.     last_func_name[0] = '\0';
  278.     last_pc = (addr_t)-1;
  279.     last_line_num = 1;
  280.  
  281.     if (!stab_sym)
  282.         goto no_stabs;
  283.  
  284.     stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len);
  285.     for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
  286.         switch(sym->n_type) {
  287.             /* function start or end */
  288.         case N_FUN:
  289.             if (sym->n_strx == 0) {
  290.                 /* we test if between last line and end of function */
  291.                 pc = sym->n_value + func_addr;
  292.                 if (wanted_pc >= last_pc && wanted_pc < pc)
  293.                     goto found;
  294.                 func_name[0] = '\0';
  295.                 func_addr = 0;
  296.             } else {
  297.                 str = stab_str + sym->n_strx;
  298.                 p = strchr(str, ':');
  299.                 if (!p) {
  300.                     pstrcpy(func_name, sizeof(func_name), str);
  301.                 } else {
  302.                     len = p - str;
  303.                     if (len > sizeof(func_name) - 1)
  304.                         len = sizeof(func_name) - 1;
  305.                     memcpy(func_name, str, len);
  306.                     func_name[len] = '\0';
  307.                 }
  308.                 func_addr = sym->n_value;
  309.             }
  310.             break;
  311.             /* line number info */
  312.         case N_SLINE:
  313.             pc = sym->n_value + func_addr;
  314.             if (wanted_pc >= last_pc && wanted_pc < pc)
  315.                 goto found;
  316.             last_pc = pc;
  317.             last_line_num = sym->n_desc;
  318.             /* XXX: slow! */
  319.             strcpy(last_func_name, func_name);
  320.             break;
  321.             /* include files */
  322.         case N_BINCL:
  323.             str = stab_str + sym->n_strx;
  324.         add_incl:
  325.             if (incl_index < INCLUDE_STACK_SIZE) {
  326.                 incl_files[incl_index++] = str;
  327.             }
  328.             break;
  329.         case N_EINCL:
  330.             if (incl_index > 1)
  331.                 incl_index--;
  332.             break;
  333.         case N_SO:
  334.             if (sym->n_strx == 0) {
  335.                 incl_index = 0; /* end of translation unit */
  336.             } else {
  337.                 str = stab_str + sym->n_strx;
  338.                 /* do not add path */
  339.                 len = strlen(str);
  340.                 if (len > 0 && str[len - 1] != '/')
  341.                     goto add_incl;
  342.             }
  343.             break;
  344.         }
  345.     }
  346.  
  347. no_stabs:
  348.     /* second pass: we try symtab symbols (no line number info) */
  349.     incl_index = 0;
  350.     if (symtab_section)
  351.     {
  352.         ElfW(Sym) *sym, *sym_end;
  353.         int type;
  354.  
  355.         sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
  356.         for(sym = (ElfW(Sym) *)symtab_section->data + 1;
  357.             sym < sym_end;
  358.             sym++) {
  359.             type = ELFW(ST_TYPE)(sym->st_info);
  360.             if (type == STT_FUNC || type == STT_GNU_IFUNC) {
  361.                 if (wanted_pc >= sym->st_value &&
  362.                     wanted_pc < sym->st_value + sym->st_size) {
  363.                     pstrcpy(last_func_name, sizeof(last_func_name),
  364.                             (char *) strtab_section->data + sym->st_name);
  365.                     func_addr = sym->st_value;
  366.                     goto found;
  367.                 }
  368.             }
  369.         }
  370.     }
  371.     /* did not find any info: */
  372.     fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc);
  373.     fflush(stderr);
  374.     return 0;
  375.  found:
  376.     i = incl_index;
  377.     if (i > 0)
  378.         fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num);
  379.     fprintf(stderr, "%s %p", msg, (void*)wanted_pc);
  380.     if (last_func_name[0] != '\0')
  381.         fprintf(stderr, " %s()", last_func_name);
  382.     if (--i >= 0) {
  383.         fprintf(stderr, " (included from ");
  384.         for (;;) {
  385.             fprintf(stderr, "%s", incl_files[i]);
  386.             if (--i < 0)
  387.                 break;
  388.             fprintf(stderr, ", ");
  389.         }
  390.         fprintf(stderr, ")");
  391.     }
  392.     fprintf(stderr, "\n");
  393.     fflush(stderr);
  394.     return func_addr;
  395. }
  396.  
  397. /* emit a run time error at position 'pc' */
  398. static void rt_error(ucontext_t *uc, const char *fmt, ...)
  399. {
  400.     va_list ap;
  401.     addr_t pc;
  402.     int i;
  403.  
  404.     fprintf(stderr, "Runtime error: ");
  405.     va_start(ap, fmt);
  406.     vfprintf(stderr, fmt, ap);
  407.     va_end(ap);
  408.     fprintf(stderr, "\n");
  409.  
  410.     for(i=0;i<rt_num_callers;i++) {
  411.         if (rt_get_caller_pc(&pc, uc, i) < 0)
  412.             break;
  413.         pc = rt_printline(pc, i ? "by" : "at");
  414.         if (pc == (addr_t)rt_prog_main && pc)
  415.             break;
  416.     }
  417. }
  418.  
  419. /* ------------------------------------------------------------- */
  420. #ifndef _WIN32
  421.  
  422. /* signal handler for fatal errors */
  423. static void sig_error(int signum, siginfo_t *siginf, void *puc)
  424. {
  425.     ucontext_t *uc = puc;
  426.  
  427.     switch(signum) {
  428.     case SIGFPE:
  429.         switch(siginf->si_code) {
  430.         case FPE_INTDIV:
  431.         case FPE_FLTDIV:
  432.             rt_error(uc, "division by zero");
  433.             break;
  434.         default:
  435.             rt_error(uc, "floating point exception");
  436.             break;
  437.         }
  438.         break;
  439.     case SIGBUS:
  440.     case SIGSEGV:
  441.         if (rt_bound_error_msg && *rt_bound_error_msg)
  442.             rt_error(uc, *rt_bound_error_msg);
  443.         else
  444.             rt_error(uc, "dereferencing invalid pointer");
  445.         break;
  446.     case SIGILL:
  447.         rt_error(uc, "illegal instruction");
  448.         break;
  449.     case SIGABRT:
  450.         rt_error(uc, "abort() called");
  451.         break;
  452.     default:
  453.         rt_error(uc, "caught signal %d", signum);
  454.         break;
  455.     }
  456.     exit(255);
  457. }
  458.  
  459. #ifndef SA_SIGINFO
  460. # define SA_SIGINFO 0x00000004u
  461. #endif
  462.  
  463. /* Generate a stack backtrace when a CPU exception occurs. */
  464. static void set_exception_handler(void)
  465. {
  466.     struct sigaction sigact;
  467.     /* install TCC signal handlers to print debug info on fatal
  468.        runtime errors */
  469.     sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
  470.     sigact.sa_sigaction = sig_error;
  471.     sigemptyset(&sigact.sa_mask);
  472.     sigaction(SIGFPE, &sigact, NULL);
  473.     sigaction(SIGILL, &sigact, NULL);
  474.     sigaction(SIGSEGV, &sigact, NULL);
  475.     sigaction(SIGBUS, &sigact, NULL);
  476.     sigaction(SIGABRT, &sigact, NULL);
  477. }
  478.  
  479. /* ------------------------------------------------------------- */
  480. #ifdef __i386__
  481.  
  482. /* fix for glibc 2.1 */
  483. #ifndef REG_EIP
  484. #define REG_EIP EIP
  485. #define REG_EBP EBP
  486. #endif
  487.  
  488. /* return the PC at frame level 'level'. Return negative if not found */
  489. static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
  490. {
  491.     addr_t fp;
  492.     int i;
  493.  
  494.     if (level == 0) {
  495. #if defined(__APPLE__)
  496.         *paddr = uc->uc_mcontext->__ss.__eip;
  497. #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
  498.         *paddr = uc->uc_mcontext.mc_eip;
  499. #elif defined(__dietlibc__)
  500.         *paddr = uc->uc_mcontext.eip;
  501. #elif defined(__NetBSD__)
  502.         *paddr = uc->uc_mcontext.__gregs[_REG_EIP];
  503. #else
  504.         *paddr = uc->uc_mcontext.gregs[REG_EIP];
  505. #endif
  506.         return 0;
  507.     } else {
  508. #if defined(__APPLE__)
  509.         fp = uc->uc_mcontext->__ss.__ebp;
  510. #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
  511.         fp = uc->uc_mcontext.mc_ebp;
  512. #elif defined(__dietlibc__)
  513.         fp = uc->uc_mcontext.ebp;
  514. #elif defined(__NetBSD__)
  515.         fp = uc->uc_mcontext.__gregs[_REG_EBP];
  516. #else
  517.         fp = uc->uc_mcontext.gregs[REG_EBP];
  518. #endif
  519.         for(i=1;i<level;i++) {
  520.             /* XXX: check address validity with program info */
  521.             if (fp <= 0x1000 || fp >= 0xc0000000)
  522.                 return -1;
  523.             fp = ((addr_t *)fp)[0];
  524.         }
  525.         *paddr = ((addr_t *)fp)[1];
  526.         return 0;
  527.     }
  528. }
  529.  
  530. /* ------------------------------------------------------------- */
  531. #elif defined(__x86_64__)
  532.  
  533. /* return the PC at frame level 'level'. Return negative if not found */
  534. static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
  535. {
  536.     addr_t fp;
  537.     int i;
  538.  
  539.     if (level == 0) {
  540.         /* XXX: only support linux */
  541. #if defined(__APPLE__)
  542.         *paddr = uc->uc_mcontext->__ss.__rip;
  543. #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
  544.         *paddr = uc->uc_mcontext.mc_rip;
  545. #elif defined(__NetBSD__)
  546.         *paddr = uc->uc_mcontext.__gregs[_REG_RIP];
  547. #else
  548.         *paddr = uc->uc_mcontext.gregs[REG_RIP];
  549. #endif
  550.         return 0;
  551.     } else {
  552. #if defined(__APPLE__)
  553.         fp = uc->uc_mcontext->__ss.__rbp;
  554. #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
  555.         fp = uc->uc_mcontext.mc_rbp;
  556. #elif defined(__NetBSD__)
  557.         fp = uc->uc_mcontext.__gregs[_REG_RBP];
  558. #else
  559.         fp = uc->uc_mcontext.gregs[REG_RBP];
  560. #endif
  561.         for(i=1;i<level;i++) {
  562.             /* XXX: check address validity with program info */
  563.             if (fp <= 0x1000)
  564.                 return -1;
  565.             fp = ((addr_t *)fp)[0];
  566.         }
  567.         *paddr = ((addr_t *)fp)[1];
  568.         return 0;
  569.     }
  570. }
  571.  
  572. /* ------------------------------------------------------------- */
  573. #elif defined(__arm__)
  574.  
  575. /* return the PC at frame level 'level'. Return negative if not found */
  576. static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
  577. {
  578.     addr_t fp, sp;
  579.     int i;
  580.  
  581.     if (level == 0) {
  582.         /* XXX: only supports linux */
  583. #if defined(__linux__)
  584.         *paddr = uc->uc_mcontext.arm_pc;
  585. #else
  586.         return -1;
  587. #endif
  588.         return 0;
  589.     } else {
  590. #if defined(__linux__)
  591.         fp = uc->uc_mcontext.arm_fp;
  592.         sp = uc->uc_mcontext.arm_sp;
  593.         if (sp < 0x1000)
  594.             sp = 0x1000;
  595. #else
  596.         return -1;
  597. #endif
  598.         /* XXX: specific to tinycc stack frames */
  599.         if (fp < sp + 12 || fp & 3)
  600.             return -1;
  601.         for(i = 1; i < level; i++) {
  602.             sp = ((addr_t *)fp)[-2];
  603.             if (sp < fp || sp - fp > 16 || sp & 3)
  604.                 return -1;
  605.             fp = ((addr_t *)fp)[-3];
  606.             if (fp <= sp || fp - sp < 12 || fp & 3)
  607.                 return -1;
  608.         }
  609.         /* XXX: check address validity with program info */
  610.         *paddr = ((addr_t *)fp)[-1];
  611.         return 0;
  612.     }
  613. }
  614.  
  615. /* ------------------------------------------------------------- */
  616. #elif defined(__aarch64__)
  617.  
  618. static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
  619. {
  620.     if (level < 0)
  621.         return -1;
  622.     else if (level == 0) {
  623.         *paddr = uc->uc_mcontext.pc;
  624.         return 0;
  625.     }
  626.     else {
  627.         addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
  628.         int i;
  629.         for (i = 1; i < level; i++)
  630.             fp = (addr_t *)fp[0];
  631.         *paddr = fp[1];
  632.         return 0;
  633.     }
  634. }
  635.  
  636. /* ------------------------------------------------------------- */
  637. #else
  638.  
  639. #warning add arch specific rt_get_caller_pc()
  640. static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
  641. {
  642.     return -1;
  643. }
  644.  
  645. #endif /* !__i386__ */
  646.  
  647. /* ------------------------------------------------------------- */
  648. #else /* WIN32 */
  649.  
  650. static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
  651. {
  652.     EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
  653.     CONTEXT *uc = ex_info->ContextRecord;
  654.     switch (er->ExceptionCode) {
  655.     case EXCEPTION_ACCESS_VIOLATION:
  656.         if (rt_bound_error_msg && *rt_bound_error_msg)
  657.             rt_error(uc, *rt_bound_error_msg);
  658.         else
  659.             rt_error(uc, "access violation");
  660.         break;
  661.     case EXCEPTION_STACK_OVERFLOW:
  662.         rt_error(uc, "stack overflow");
  663.         break;
  664.     case EXCEPTION_INT_DIVIDE_BY_ZERO:
  665.         rt_error(uc, "division by zero");
  666.         break;
  667.     default:
  668.         rt_error(uc, "exception caught");
  669.         break;
  670.     }
  671.     return EXCEPTION_EXECUTE_HANDLER;
  672. }
  673.  
  674. /* Generate a stack backtrace when a CPU exception occurs. */
  675. static void set_exception_handler(void)
  676. {
  677.     SetUnhandledExceptionFilter(cpu_exception_handler);
  678. }
  679.  
  680. #ifdef _WIN64
  681. static void win64_add_function_table(TCCState *s1)
  682. {
  683.     RtlAddFunctionTable(
  684.         (RUNTIME_FUNCTION*)s1->uw_pdata->sh_addr,
  685.         s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
  686.         text_section->sh_addr
  687.         );
  688. }
  689. #endif
  690.  
  691. /* return the PC at frame level 'level'. Return non zero if not found */
  692. static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
  693. {
  694.     addr_t fp, pc;
  695.     int i;
  696. #ifdef _WIN64
  697.     pc = uc->Rip;
  698.     fp = uc->Rbp;
  699. #else
  700.     pc = uc->Eip;
  701.     fp = uc->Ebp;
  702. #endif
  703.     if (level > 0) {
  704.         for(i=1;i<level;i++) {
  705.             /* XXX: check address validity with program info */
  706.             if (fp <= 0x1000 || fp >= 0xc0000000)
  707.                 return -1;
  708.             fp = ((addr_t*)fp)[0];
  709.         }
  710.         pc = ((addr_t*)fp)[1];
  711.     }
  712.     *paddr = pc;
  713.     return 0;
  714. }
  715.  
  716. #endif /* _WIN32 */
  717. #endif /* CONFIG_TCC_BACKTRACE */
  718. /* ------------------------------------------------------------- */
  719. #ifdef CONFIG_TCC_STATIC
  720.  
  721. /* dummy function for profiling */
  722. ST_FUNC void *dlopen(const char *filename, int flag)
  723. {
  724.     return NULL;
  725. }
  726.  
  727. ST_FUNC void dlclose(void *p)
  728. {
  729. }
  730.  
  731. ST_FUNC const char *dlerror(void)
  732. {
  733.     return "error";
  734. }
  735.  
  736. typedef struct TCCSyms {
  737.     char *str;
  738.     void *ptr;
  739. } TCCSyms;
  740.  
  741.  
  742. /* add the symbol you want here if no dynamic linking is done */
  743. static TCCSyms tcc_syms[] = {
  744. #if !defined(CONFIG_TCCBOOT)
  745. #define TCCSYM(a) { #a, &a, },
  746.     TCCSYM(printf)
  747.     TCCSYM(fprintf)
  748.     TCCSYM(fopen)
  749.     TCCSYM(fclose)
  750. #undef TCCSYM
  751. #endif
  752.     { NULL, NULL },
  753. };
  754.  
  755. ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol)
  756. {
  757.     TCCSyms *p;
  758.     p = tcc_syms;
  759.     while (p->str != NULL) {
  760.         if (!strcmp(p->str, symbol))
  761.             return p->ptr;
  762.         p++;
  763.     }
  764.     return NULL;
  765. }
  766.  
  767. #elif !defined(_WIN32)
  768.  
  769. ST_FUNC void *resolve_sym(TCCState *s1, const char *sym)
  770. {
  771.     return dlsym(RTLD_DEFAULT, sym);
  772. }
  773.  
  774. #endif /* CONFIG_TCC_STATIC */
  775. #endif /* TCC_IS_NATIVE */
  776. /* ------------------------------------------------------------- */
  777.