source: EcnlProtoTool/trunk/tcc-0.9.27/tccrun.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 24.9 KB
Line 
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#ifndef _WIN32
27# include <sys/mman.h>
28#endif
29
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
39ST_DATA int rt_num_callers = 6;
40ST_DATA const char **rt_bound_error_msg;
41ST_DATA void *rt_prog_main;
42static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
43static void rt_error(ucontext_t *uc, const char *fmt, ...);
44static void set_exception_handler(void);
45#endif
46
47static void set_pages_executable(void *ptr, unsigned long length);
48static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
49
50#ifdef _WIN64
51static void *win64_add_function_table(TCCState *s1);
52static void win64_del_function_table(void *);
53#endif
54
55/* ------------------------------------------------------------- */
56/* Do all relocations (needed before using tcc_get_symbol())
57 Returns -1 on error. */
58
59LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
60{
61 int size;
62 addr_t ptr_diff = 0;
63
64 if (TCC_RELOCATE_AUTO != ptr)
65 return tcc_relocate_ex(s1, ptr, 0);
66
67 size = tcc_relocate_ex(s1, NULL, 0);
68 if (size < 0)
69 return -1;
70
71#ifdef HAVE_SELINUX
72{
73 /* Using mmap instead of malloc */
74 void *prx;
75 char tmpfname[] = "/tmp/.tccrunXXXXXX";
76 int fd = mkstemp(tmpfname);
77 unlink(tmpfname);
78 ftruncate(fd, size);
79
80 ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
81 prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
82 if (ptr == MAP_FAILED || prx == MAP_FAILED)
83 tcc_error("tccrun: could not map memory");
84 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
85 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx);
86 ptr_diff = (char*)prx - (char*)ptr;
87}
88#else
89 ptr = tcc_malloc(size);
90#endif
91 tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */
92 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
93 return 0;
94}
95
96ST_FUNC void tcc_run_free(TCCState *s1)
97{
98 int i;
99
100 for (i = 0; i < s1->nb_runtime_mem; ++i) {
101#ifdef HAVE_SELINUX
102 unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
103 munmap(s1->runtime_mem[i++], size);
104 munmap(s1->runtime_mem[i], size);
105#else
106#ifdef _WIN64
107 win64_del_function_table(*(void**)s1->runtime_mem[i]);
108#endif
109 tcc_free(s1->runtime_mem[i]);
110#endif
111 }
112 tcc_free(s1->runtime_mem);
113}
114
115/* launch the compiled program with the given arguments */
116LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
117{
118 int (*prog_main)(int, char **);
119
120 s1->runtime_main = "main";
121 if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
122 return 0;
123 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
124 return -1;
125 prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
126
127#ifdef CONFIG_TCC_BACKTRACE
128 if (s1->do_debug) {
129 set_exception_handler();
130 rt_prog_main = prog_main;
131 }
132#endif
133
134 errno = 0; /* clean errno value */
135
136#ifdef CONFIG_TCC_BCHECK
137 if (s1->do_bounds_check) {
138 void (*bound_init)(void);
139 void (*bound_exit)(void);
140 void (*bound_new_region)(void *p, addr_t size);
141 int (*bound_delete_region)(void *p);
142 int i, ret;
143
144 /* set error function */
145 rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
146 /* XXX: use .init section so that it also work in binary ? */
147 bound_init = tcc_get_symbol_err(s1, "__bound_init");
148 bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
149 bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
150 bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
151
152 bound_init();
153 /* mark argv area as valid */
154 bound_new_region(argv, argc*sizeof(argv[0]));
155 for (i=0; i<argc; ++i)
156 bound_new_region(argv[i], strlen(argv[i]) + 1);
157
158 ret = (*prog_main)(argc, argv);
159
160 /* unmark argv area */
161 for (i=0; i<argc; ++i)
162 bound_delete_region(argv[i]);
163 bound_delete_region(argv);
164 bound_exit();
165 return ret;
166 }
167#endif
168 return (*prog_main)(argc, argv);
169}
170
171#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
172 #define RUN_SECTION_ALIGNMENT 63
173#else
174 #define RUN_SECTION_ALIGNMENT 15
175#endif
176
177/* relocate code. Return -1 on error, required size if ptr is NULL,
178 otherwise copy code into buffer passed by the caller */
179static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
180{
181 Section *s;
182 unsigned offset, length, fill, i, k;
183 addr_t mem;
184
185 if (NULL == ptr) {
186 s1->nb_errors = 0;
187#ifdef TCC_TARGET_PE
188 pe_output_file(s1, NULL);
189#else
190 tcc_add_runtime(s1);
191 resolve_common_syms(s1);
192 build_got_entries(s1);
193#endif
194 if (s1->nb_errors)
195 return -1;
196 }
197
198 offset = 0, mem = (addr_t)ptr;
199 fill = -mem & RUN_SECTION_ALIGNMENT;
200#ifdef _WIN64
201 offset += sizeof (void*);
202#endif
203 for (k = 0; k < 2; ++k) {
204 for(i = 1; i < s1->nb_sections; i++) {
205 s = s1->sections[i];
206 if (0 == (s->sh_flags & SHF_ALLOC))
207 continue;
208 if (k != !(s->sh_flags & SHF_EXECINSTR))
209 continue;
210 offset += fill;
211 if (!mem)
212 s->sh_addr = 0;
213 else if (s->sh_flags & SHF_EXECINSTR)
214 s->sh_addr = mem + offset + ptr_diff;
215 else
216 s->sh_addr = mem + offset;
217#if 0
218 if (mem)
219 printf("%-16s +%02lx %p %04x\n",
220 s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset);
221#endif
222 offset += s->data_offset;
223 fill = -(mem + offset) & 15;
224 }
225#if RUN_SECTION_ALIGNMENT > 15
226 /* To avoid that x86 processors would reload cached instructions each time
227 when data is written in the near, we need to make sure that code and data
228 do not share the same 64 byte unit */
229 fill = -(mem + offset) & RUN_SECTION_ALIGNMENT;
230#endif
231 }
232
233 /* relocate symbols */
234 relocate_syms(s1, s1->symtab, 1);
235 if (s1->nb_errors)
236 return -1;
237
238 if (0 == mem)
239 return offset + RUN_SECTION_ALIGNMENT;
240
241#ifdef TCC_TARGET_PE
242 s1->pe_imagebase = mem;
243#endif
244
245 /* relocate each section */
246 for(i = 1; i < s1->nb_sections; i++) {
247 s = s1->sections[i];
248 if (s->reloc)
249 relocate_section(s1, s);
250 }
251 relocate_plt(s1);
252
253 for(i = 1; i < s1->nb_sections; i++) {
254 s = s1->sections[i];
255 if (0 == (s->sh_flags & SHF_ALLOC))
256 continue;
257 length = s->data_offset;
258 ptr = (void*)s->sh_addr;
259 if (s->sh_flags & SHF_EXECINSTR)
260 ptr = (char*)ptr - ptr_diff;
261 if (NULL == s->data || s->sh_type == SHT_NOBITS)
262 memset(ptr, 0, length);
263 else
264 memcpy(ptr, s->data, length);
265 /* mark executable sections as executable in memory */
266 if (s->sh_flags & SHF_EXECINSTR)
267 set_pages_executable((char*)ptr + ptr_diff, length);
268 }
269
270#ifdef _WIN64
271 *(void**)mem = win64_add_function_table(s1);
272#endif
273
274 return 0;
275}
276
277/* ------------------------------------------------------------- */
278/* allow to run code in memory */
279
280static void set_pages_executable(void *ptr, unsigned long length)
281{
282#ifdef _WIN32
283 unsigned long old_protect;
284 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
285#else
286 void __clear_cache(void *beginning, void *end);
287# ifndef HAVE_SELINUX
288 addr_t start, end;
289# ifndef PAGESIZE
290# define PAGESIZE 4096
291# endif
292 start = (addr_t)ptr & ~(PAGESIZE - 1);
293 end = (addr_t)ptr + length;
294 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
295 if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
296 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
297# endif
298# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
299 __clear_cache(ptr, (char *)ptr + length);
300# endif
301#endif
302}
303
304#ifdef _WIN64
305static void *win64_add_function_table(TCCState *s1)
306{
307 void *p = NULL;
308 if (s1->uw_pdata) {
309 p = (void*)s1->uw_pdata->sh_addr;
310 RtlAddFunctionTable(
311 (RUNTIME_FUNCTION*)p,
312 s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
313 s1->pe_imagebase
314 );
315 s1->uw_pdata = NULL;
316 }
317 return p;
318}
319
320static void win64_del_function_table(void *p)
321{
322 if (p) {
323 RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p);
324 }
325}
326#endif
327
328/* ------------------------------------------------------------- */
329#ifdef CONFIG_TCC_BACKTRACE
330
331ST_FUNC void tcc_set_num_callers(int n)
332{
333 rt_num_callers = n;
334}
335
336/* print the position in the source file of PC value 'pc' by reading
337 the stabs debug information */
338static addr_t rt_printline(addr_t wanted_pc, const char *msg)
339{
340 char func_name[128], last_func_name[128];
341 addr_t func_addr, last_pc, pc;
342 const char *incl_files[INCLUDE_STACK_SIZE];
343 int incl_index, len, last_line_num, i;
344 const char *str, *p;
345
346 Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym;
347 int stab_len = 0;
348 char *stab_str = NULL;
349
350 if (stab_section) {
351 stab_len = stab_section->data_offset;
352 stab_sym = (Stab_Sym *)stab_section->data;
353 stab_str = (char *) stabstr_section->data;
354 }
355
356 func_name[0] = '\0';
357 func_addr = 0;
358 incl_index = 0;
359 last_func_name[0] = '\0';
360 last_pc = (addr_t)-1;
361 last_line_num = 1;
362
363 if (!stab_sym)
364 goto no_stabs;
365
366 stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len);
367 for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
368 switch(sym->n_type) {
369 /* function start or end */
370 case N_FUN:
371 if (sym->n_strx == 0) {
372 /* we test if between last line and end of function */
373 pc = sym->n_value + func_addr;
374 if (wanted_pc >= last_pc && wanted_pc < pc)
375 goto found;
376 func_name[0] = '\0';
377 func_addr = 0;
378 } else {
379 str = stab_str + sym->n_strx;
380 p = strchr(str, ':');
381 if (!p) {
382 pstrcpy(func_name, sizeof(func_name), str);
383 } else {
384 len = p - str;
385 if (len > sizeof(func_name) - 1)
386 len = sizeof(func_name) - 1;
387 memcpy(func_name, str, len);
388 func_name[len] = '\0';
389 }
390 func_addr = sym->n_value;
391 }
392 break;
393 /* line number info */
394 case N_SLINE:
395 pc = sym->n_value + func_addr;
396 if (wanted_pc >= last_pc && wanted_pc < pc)
397 goto found;
398 last_pc = pc;
399 last_line_num = sym->n_desc;
400 /* XXX: slow! */
401 strcpy(last_func_name, func_name);
402 break;
403 /* include files */
404 case N_BINCL:
405 str = stab_str + sym->n_strx;
406 add_incl:
407 if (incl_index < INCLUDE_STACK_SIZE) {
408 incl_files[incl_index++] = str;
409 }
410 break;
411 case N_EINCL:
412 if (incl_index > 1)
413 incl_index--;
414 break;
415 case N_SO:
416 if (sym->n_strx == 0) {
417 incl_index = 0; /* end of translation unit */
418 } else {
419 str = stab_str + sym->n_strx;
420 /* do not add path */
421 len = strlen(str);
422 if (len > 0 && str[len - 1] != '/')
423 goto add_incl;
424 }
425 break;
426 }
427 }
428
429no_stabs:
430 /* second pass: we try symtab symbols (no line number info) */
431 incl_index = 0;
432 if (symtab_section)
433 {
434 ElfW(Sym) *sym, *sym_end;
435 int type;
436
437 sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
438 for(sym = (ElfW(Sym) *)symtab_section->data + 1;
439 sym < sym_end;
440 sym++) {
441 type = ELFW(ST_TYPE)(sym->st_info);
442 if (type == STT_FUNC || type == STT_GNU_IFUNC) {
443 if (wanted_pc >= sym->st_value &&
444 wanted_pc < sym->st_value + sym->st_size) {
445 pstrcpy(last_func_name, sizeof(last_func_name),
446 (char *) symtab_section->link->data + sym->st_name);
447 func_addr = sym->st_value;
448 goto found;
449 }
450 }
451 }
452 }
453 /* did not find any info: */
454 fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc);
455 fflush(stderr);
456 return 0;
457 found:
458 i = incl_index;
459 if (i > 0)
460 fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num);
461 fprintf(stderr, "%s %p", msg, (void*)wanted_pc);
462 if (last_func_name[0] != '\0')
463 fprintf(stderr, " %s()", last_func_name);
464 if (--i >= 0) {
465 fprintf(stderr, " (included from ");
466 for (;;) {
467 fprintf(stderr, "%s", incl_files[i]);
468 if (--i < 0)
469 break;
470 fprintf(stderr, ", ");
471 }
472 fprintf(stderr, ")");
473 }
474 fprintf(stderr, "\n");
475 fflush(stderr);
476 return func_addr;
477}
478
479/* emit a run time error at position 'pc' */
480static void rt_error(ucontext_t *uc, const char *fmt, ...)
481{
482 va_list ap;
483 addr_t pc;
484 int i;
485
486 fprintf(stderr, "Runtime error: ");
487 va_start(ap, fmt);
488 vfprintf(stderr, fmt, ap);
489 va_end(ap);
490 fprintf(stderr, "\n");
491
492 for(i=0;i<rt_num_callers;i++) {
493 if (rt_get_caller_pc(&pc, uc, i) < 0)
494 break;
495 pc = rt_printline(pc, i ? "by" : "at");
496 if (pc == (addr_t)rt_prog_main && pc)
497 break;
498 }
499}
500
501/* ------------------------------------------------------------- */
502#ifndef _WIN32
503
504/* signal handler for fatal errors */
505static void sig_error(int signum, siginfo_t *siginf, void *puc)
506{
507 ucontext_t *uc = puc;
508
509 switch(signum) {
510 case SIGFPE:
511 switch(siginf->si_code) {
512 case FPE_INTDIV:
513 case FPE_FLTDIV:
514 rt_error(uc, "division by zero");
515 break;
516 default:
517 rt_error(uc, "floating point exception");
518 break;
519 }
520 break;
521 case SIGBUS:
522 case SIGSEGV:
523 if (rt_bound_error_msg && *rt_bound_error_msg)
524 rt_error(uc, *rt_bound_error_msg);
525 else
526 rt_error(uc, "dereferencing invalid pointer");
527 break;
528 case SIGILL:
529 rt_error(uc, "illegal instruction");
530 break;
531 case SIGABRT:
532 rt_error(uc, "abort() called");
533 break;
534 default:
535 rt_error(uc, "caught signal %d", signum);
536 break;
537 }
538 exit(255);
539}
540
541#ifndef SA_SIGINFO
542# define SA_SIGINFO 0x00000004u
543#endif
544
545/* Generate a stack backtrace when a CPU exception occurs. */
546static void set_exception_handler(void)
547{
548 struct sigaction sigact;
549 /* install TCC signal handlers to print debug info on fatal
550 runtime errors */
551 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
552 sigact.sa_sigaction = sig_error;
553 sigemptyset(&sigact.sa_mask);
554 sigaction(SIGFPE, &sigact, NULL);
555 sigaction(SIGILL, &sigact, NULL);
556 sigaction(SIGSEGV, &sigact, NULL);
557 sigaction(SIGBUS, &sigact, NULL);
558 sigaction(SIGABRT, &sigact, NULL);
559}
560
561/* ------------------------------------------------------------- */
562#ifdef __i386__
563
564/* fix for glibc 2.1 */
565#ifndef REG_EIP
566#define REG_EIP EIP
567#define REG_EBP EBP
568#endif
569
570/* return the PC at frame level 'level'. Return negative if not found */
571static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
572{
573 addr_t fp;
574 int i;
575
576 if (level == 0) {
577#if defined(__APPLE__)
578 *paddr = uc->uc_mcontext->__ss.__eip;
579#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
580 *paddr = uc->uc_mcontext.mc_eip;
581#elif defined(__dietlibc__)
582 *paddr = uc->uc_mcontext.eip;
583#elif defined(__NetBSD__)
584 *paddr = uc->uc_mcontext.__gregs[_REG_EIP];
585#elif defined(__OpenBSD__)
586 *paddr = uc->sc_eip;
587#else
588 *paddr = uc->uc_mcontext.gregs[REG_EIP];
589#endif
590 return 0;
591 } else {
592#if defined(__APPLE__)
593 fp = uc->uc_mcontext->__ss.__ebp;
594#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
595 fp = uc->uc_mcontext.mc_ebp;
596#elif defined(__dietlibc__)
597 fp = uc->uc_mcontext.ebp;
598#elif defined(__NetBSD__)
599 fp = uc->uc_mcontext.__gregs[_REG_EBP];
600#elif defined(__OpenBSD__)
601 *paddr = uc->sc_ebp;
602#else
603 fp = uc->uc_mcontext.gregs[REG_EBP];
604#endif
605 for(i=1;i<level;i++) {
606 /* XXX: check address validity with program info */
607 if (fp <= 0x1000 || fp >= 0xc0000000)
608 return -1;
609 fp = ((addr_t *)fp)[0];
610 }
611 *paddr = ((addr_t *)fp)[1];
612 return 0;
613 }
614}
615
616/* ------------------------------------------------------------- */
617#elif defined(__x86_64__)
618
619/* return the PC at frame level 'level'. Return negative if not found */
620static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
621{
622 addr_t fp;
623 int i;
624
625 if (level == 0) {
626 /* XXX: only support linux */
627#if defined(__APPLE__)
628 *paddr = uc->uc_mcontext->__ss.__rip;
629#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
630 *paddr = uc->uc_mcontext.mc_rip;
631#elif defined(__NetBSD__)
632 *paddr = uc->uc_mcontext.__gregs[_REG_RIP];
633#else
634 *paddr = uc->uc_mcontext.gregs[REG_RIP];
635#endif
636 return 0;
637 } else {
638#if defined(__APPLE__)
639 fp = uc->uc_mcontext->__ss.__rbp;
640#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
641 fp = uc->uc_mcontext.mc_rbp;
642#elif defined(__NetBSD__)
643 fp = uc->uc_mcontext.__gregs[_REG_RBP];
644#else
645 fp = uc->uc_mcontext.gregs[REG_RBP];
646#endif
647 for(i=1;i<level;i++) {
648 /* XXX: check address validity with program info */
649 if (fp <= 0x1000)
650 return -1;
651 fp = ((addr_t *)fp)[0];
652 }
653 *paddr = ((addr_t *)fp)[1];
654 return 0;
655 }
656}
657
658/* ------------------------------------------------------------- */
659#elif defined(__arm__)
660
661/* return the PC at frame level 'level'. Return negative if not found */
662static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
663{
664 addr_t fp, sp;
665 int i;
666
667 if (level == 0) {
668 /* XXX: only supports linux */
669#if defined(__linux__)
670 *paddr = uc->uc_mcontext.arm_pc;
671#else
672 return -1;
673#endif
674 return 0;
675 } else {
676#if defined(__linux__)
677 fp = uc->uc_mcontext.arm_fp;
678 sp = uc->uc_mcontext.arm_sp;
679 if (sp < 0x1000)
680 sp = 0x1000;
681#else
682 return -1;
683#endif
684 /* XXX: specific to tinycc stack frames */
685 if (fp < sp + 12 || fp & 3)
686 return -1;
687 for(i = 1; i < level; i++) {
688 sp = ((addr_t *)fp)[-2];
689 if (sp < fp || sp - fp > 16 || sp & 3)
690 return -1;
691 fp = ((addr_t *)fp)[-3];
692 if (fp <= sp || fp - sp < 12 || fp & 3)
693 return -1;
694 }
695 /* XXX: check address validity with program info */
696 *paddr = ((addr_t *)fp)[-1];
697 return 0;
698 }
699}
700
701/* ------------------------------------------------------------- */
702#elif defined(__aarch64__)
703
704static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
705{
706 if (level < 0)
707 return -1;
708 else if (level == 0) {
709 *paddr = uc->uc_mcontext.pc;
710 return 0;
711 }
712 else {
713 addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
714 int i;
715 for (i = 1; i < level; i++)
716 fp = (addr_t *)fp[0];
717 *paddr = fp[1];
718 return 0;
719 }
720}
721
722/* ------------------------------------------------------------- */
723#else
724
725#warning add arch specific rt_get_caller_pc()
726static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
727{
728 return -1;
729}
730
731#endif /* !__i386__ */
732
733/* ------------------------------------------------------------- */
734#else /* WIN32 */
735
736static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
737{
738 EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
739 CONTEXT *uc = ex_info->ContextRecord;
740 switch (er->ExceptionCode) {
741 case EXCEPTION_ACCESS_VIOLATION:
742 if (rt_bound_error_msg && *rt_bound_error_msg)
743 rt_error(uc, *rt_bound_error_msg);
744 else
745 rt_error(uc, "access violation");
746 break;
747 case EXCEPTION_STACK_OVERFLOW:
748 rt_error(uc, "stack overflow");
749 break;
750 case EXCEPTION_INT_DIVIDE_BY_ZERO:
751 rt_error(uc, "division by zero");
752 break;
753 default:
754 rt_error(uc, "exception caught");
755 break;
756 }
757 return EXCEPTION_EXECUTE_HANDLER;
758}
759
760/* Generate a stack backtrace when a CPU exception occurs. */
761static void set_exception_handler(void)
762{
763 SetUnhandledExceptionFilter(cpu_exception_handler);
764}
765
766/* return the PC at frame level 'level'. Return non zero if not found */
767static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
768{
769 addr_t fp, pc;
770 int i;
771#ifdef _WIN64
772 pc = uc->Rip;
773 fp = uc->Rbp;
774#else
775 pc = uc->Eip;
776 fp = uc->Ebp;
777#endif
778 if (level > 0) {
779 for(i=1;i<level;i++) {
780 /* XXX: check address validity with program info */
781 if (fp <= 0x1000 || fp >= 0xc0000000)
782 return -1;
783 fp = ((addr_t*)fp)[0];
784 }
785 pc = ((addr_t*)fp)[1];
786 }
787 *paddr = pc;
788 return 0;
789}
790
791#endif /* _WIN32 */
792#endif /* CONFIG_TCC_BACKTRACE */
793/* ------------------------------------------------------------- */
794#ifdef CONFIG_TCC_STATIC
795
796/* dummy function for profiling */
797ST_FUNC void *dlopen(const char *filename, int flag)
798{
799 return NULL;
800}
801
802ST_FUNC void dlclose(void *p)
803{
804}
805
806ST_FUNC const char *dlerror(void)
807{
808 return "error";
809}
810
811typedef struct TCCSyms {
812 char *str;
813 void *ptr;
814} TCCSyms;
815
816#if !defined(CONFIG_TCCBOOT)
817extern int __environ;
818extern int __expand_heap;
819extern int __get_handler_set;
820extern int __get_locale;
821extern int __gmt;
822extern int __h_errno_location;
823extern int __hwcap;
824extern int __init_tls;
825extern int __libc;
826extern int __libc_sigaction;
827extern int __libc_start_main;
828extern int __malloc0;
829extern int __ofl_lock;
830extern int __ofl_unlock;
831extern int __progname;
832extern int __progname_full;
833extern int __secs_to_zone;
834extern int __sigaction;
835extern int __sysinfo;
836extern int __tm_to_tzname;
837//extern int atexit;
838//extern int environ;
839//extern int free;
840extern int gethostbyname2;
841//extern int getopt;
842extern int getpwnam;
843//extern int gmtime;
844//extern int localtime;
845//extern int malloc;
846extern int mbrtowc;
847//extern int optarg;
848extern int optind;
849//extern int rand;
850//extern int realloc;
851//extern int setenv;
852extern int setlocale;
853//extern int sigaction;
854//extern int srand;
855//extern int stderr;
856//extern int stdin;
857//extern int stdout;
858//extern int strtok;
859extern int syslog;
860extern int vsyslog;
861#endif
862
863/* add the symbol you want here if no dynamic linking is done */
864static TCCSyms tcc_syms[] = {
865#if !defined(CONFIG_TCCBOOT)
866#define TCCSYM(a) { #a, &a, },
867 TCCSYM(__environ)
868 TCCSYM(__expand_heap)
869 TCCSYM(__get_handler_set)
870 TCCSYM(__get_locale)
871 TCCSYM(__gmt)
872 TCCSYM(__h_errno_location)
873 TCCSYM(__hwcap)
874 TCCSYM(__init_tls)
875 TCCSYM(__libc)
876 TCCSYM(__libc_sigaction)
877 TCCSYM(__libc_start_main)
878 TCCSYM(__malloc0)
879 TCCSYM(__ofl_lock)
880 TCCSYM(__ofl_unlock)
881 TCCSYM(__progname)
882 TCCSYM(__progname_full)
883 TCCSYM(__secs_to_zone)
884 TCCSYM(__sigaction)
885 TCCSYM(__sysinfo)
886 TCCSYM(__tm_to_tzname)
887 TCCSYM(atexit)
888 TCCSYM(environ)
889 TCCSYM(free)
890 TCCSYM(gethostbyname2)
891 TCCSYM(getopt)
892 TCCSYM(getpwnam)
893 TCCSYM(gmtime)
894 TCCSYM(localtime)
895 TCCSYM(malloc)
896 TCCSYM(mbrtowc)
897 TCCSYM(optarg)
898 TCCSYM(optind)
899 TCCSYM(rand)
900 TCCSYM(realloc)
901 TCCSYM(setenv)
902 TCCSYM(setlocale)
903 TCCSYM(sigaction)
904 TCCSYM(srand)
905 TCCSYM(stderr)
906 TCCSYM(stdin)
907 TCCSYM(stdout)
908 TCCSYM(strtok)
909 TCCSYM(syslog)
910 TCCSYM(vsyslog)
911#undef TCCSYM
912#endif
913 { NULL, NULL },
914};
915
916ST_FUNC void *dlsym(void *handle, const char *symbol)
917{
918 TCCSyms *p;
919 p = tcc_syms;
920 while (p->str != NULL) {
921 if (!strcmp(p->str, symbol))
922 return p->ptr;
923 p++;
924 }
925 return NULL;
926}
927
928#endif /* CONFIG_TCC_STATIC */
929#endif /* TCC_IS_NATIVE */
930/* ------------------------------------------------------------- */
Note: See TracBrowser for help on using the repository browser.