Fix null pointer constants
[tinycc.git] / tccrun.c
blob826e52ca6d0e0da249fe537fbffba53626d2fd10
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 #ifdef CONFIG_TCC_BACKTRACE
27 typedef struct rt_context
29 /* --> tccelf.c:tcc_add_btstub wants those below in that order: */
30 union {
31 struct {
32 Stab_Sym *stab_sym, *stab_sym_end;
33 char *stab_str;
35 struct {
36 unsigned char *dwarf_line, *dwarf_line_end, *dwarf_line_str;
39 addr_t dwarf;
40 ElfW(Sym) *esym_start, *esym_end;
41 char *elf_str;
42 addr_t prog_base;
43 void *bounds_start;
44 struct rt_context *next;
45 /* <-- */
46 int num_callers;
47 addr_t ip, fp, sp;
48 void *top_func;
49 jmp_buf jmp_buf;
50 char do_jmp;
51 } rt_context;
53 static rt_context g_rtctxt;
54 static void set_exception_handler(void);
55 static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
56 static void rt_exit(int code);
57 #endif /* CONFIG_TCC_BACKTRACE */
59 /* defined when included from lib/bt-exe.c */
60 #ifndef CONFIG_TCC_BACKTRACE_ONLY
62 #ifndef _WIN32
63 # include <sys/mman.h>
64 #endif
66 static void set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long length);
67 static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
69 #ifdef _WIN64
70 static void *win64_add_function_table(TCCState *s1);
71 static void win64_del_function_table(void *);
72 #endif
74 /* ------------------------------------------------------------- */
75 /* Do all relocations (needed before using tcc_get_symbol())
76 Returns -1 on error. */
78 LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
80 int size;
81 addr_t ptr_diff = 0;
83 if (TCC_RELOCATE_AUTO != ptr)
84 return tcc_relocate_ex(s1, ptr, 0);
86 size = tcc_relocate_ex(s1, NULL, 0);
87 if (size < 0)
88 return -1;
90 #ifdef HAVE_SELINUX
92 /* Using mmap instead of malloc */
93 void *prx;
94 char tmpfname[] = "/tmp/.tccrunXXXXXX";
95 int fd = mkstemp(tmpfname);
96 unlink(tmpfname);
97 ftruncate(fd, size);
99 size = (size + (PAGESIZE-1)) & ~(PAGESIZE-1);
100 ptr = mmap(NULL, size * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
101 /* mmap RX memory at a fixed distance */
102 prx = mmap((char*)ptr + size, size, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_FIXED, fd, 0);
103 if (ptr == MAP_FAILED || prx == MAP_FAILED)
104 tcc_error("tccrun: could not map memory");
105 ptr_diff = (char*)prx - (char*)ptr;
106 close(fd);
107 //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
109 #else
110 ptr = tcc_malloc(size);
111 #endif
112 tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */
113 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
114 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
115 return 0;
118 ST_FUNC void tcc_run_free(TCCState *s1)
120 int i;
122 for (i = 0; i < s1->nb_runtime_mem; i += 2) {
123 unsigned size = (unsigned)(addr_t)s1->runtime_mem[i];
124 void *ptr = s1->runtime_mem[i+1];
125 #ifdef HAVE_SELINUX
126 munmap(ptr, size * 2);
127 #else
128 /* unprotect memory to make it usable for malloc again */
129 set_pages_executable(s1, 2, ptr, size);
130 #ifdef _WIN64
131 win64_del_function_table(*(void**)ptr);
132 #endif
133 tcc_free(ptr);
134 #endif
136 tcc_free(s1->runtime_mem);
139 static void run_cdtors(TCCState *s1, const char *start, const char *end,
140 int argc, char **argv, char **envp)
142 void **a = (void **)get_sym_addr(s1, start, 0, 0);
143 void **b = (void **)get_sym_addr(s1, end, 0, 0);
144 while (a != b)
145 ((void(*)(int, char **, char **))*a++)(argc, argv, envp);
148 /* launch the compiled program with the given arguments */
149 LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
151 int (*prog_main)(int, char **, char **), ret;
152 #ifdef CONFIG_TCC_BACKTRACE
153 rt_context *rc = &g_rtctxt;
154 #endif
156 #if defined(__APPLE__) || defined(__FreeBSD__)
157 char **envp = NULL;
158 #elif defined(__OpenBSD__) || defined(__NetBSD__)
159 extern char **environ;
160 char **envp = environ;
161 #else
162 char **envp = environ;
163 #endif
165 s1->runtime_main = s1->nostdlib ? "_start" : "main";
166 if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->runtime_main, 0, 1))
167 return 0;
168 #ifdef CONFIG_TCC_BACKTRACE
169 if (s1->do_debug)
170 tcc_add_symbol(s1, "exit", rt_exit);
171 #endif
172 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
173 return -1;
174 prog_main = (void*)get_sym_addr(s1, s1->runtime_main, 1, 1);
176 #ifdef CONFIG_TCC_BACKTRACE
177 memset(rc, 0, sizeof *rc);
178 if (s1->do_debug) {
179 void *p;
180 if (s1->dwarf) {
181 rc->dwarf_line = dwarf_line_section->data;
182 rc->dwarf_line_end = dwarf_line_section->data + dwarf_line_section->data_offset;
183 if (dwarf_line_str_section)
184 rc->dwarf_line_str = dwarf_line_str_section->data;
186 else
188 rc->stab_sym = (Stab_Sym *)stab_section->data;
189 rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
190 rc->stab_str = (char *)stab_section->link->data;
192 rc->dwarf = s1->dwarf;
193 rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
194 rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
195 rc->elf_str = (char *)symtab_section->link->data;
196 #if PTR_SIZE == 8
197 rc->prog_base = text_section->sh_addr & 0xffffffff00000000ULL;
198 #endif
199 rc->top_func = tcc_get_symbol(s1, "main");
200 rc->num_callers = s1->rt_num_callers;
201 rc->do_jmp = 1;
202 if ((p = tcc_get_symbol(s1, "__rt_error")))
203 *(void**)p = _rt_error;
204 #ifdef CONFIG_TCC_BCHECK
205 if (s1->do_bounds_check) {
206 rc->bounds_start = (void*)bounds_section->sh_addr;
207 if ((p = tcc_get_symbol(s1, "__bound_init")))
208 ((void(*)(void*,int))p)(rc->bounds_start, 1);
210 #endif
211 set_exception_handler();
213 #endif
215 errno = 0; /* clean errno value */
216 fflush(stdout);
217 fflush(stderr);
218 /* These aren't C symbols, so don't need leading underscore handling. */
219 run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp);
220 #ifdef CONFIG_TCC_BACKTRACE
221 if (!rc->do_jmp || !(ret = setjmp(rc->jmp_buf)))
222 #endif
224 ret = prog_main(argc, argv, envp);
226 run_cdtors(s1, "__fini_array_start", "__fini_array_end", 0, NULL, NULL);
227 if ((s1->dflag & 16) && ret)
228 fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
229 return ret;
232 #define DEBUG_RUNMEN 0
234 /* enable rx/ro/rw permissions */
235 #define CONFIG_RUNMEM_RO 1
237 #if CONFIG_RUNMEM_RO
238 # define PAGE_ALIGN PAGESIZE
239 #elif defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
240 /* To avoid that x86 processors would reload cached instructions
241 each time when data is written in the near, we need to make
242 sure that code and data do not share the same 64 byte unit */
243 # define PAGE_ALIGN 64
244 #else
245 # define PAGE_ALIGN 1
246 #endif
248 /* relocate code. Return -1 on error, required size if ptr is NULL,
249 otherwise copy code into buffer passed by the caller */
250 static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
252 Section *s;
253 unsigned offset, length, align, max_align, i, k, f;
254 unsigned n, copy;
255 addr_t mem, addr;
257 if (NULL == ptr) {
258 s1->nb_errors = 0;
259 #ifdef TCC_TARGET_PE
260 pe_output_file(s1, NULL);
261 #else
262 tcc_add_runtime(s1);
263 resolve_common_syms(s1);
264 build_got_entries(s1, 0);
265 #endif
266 if (s1->nb_errors)
267 return -1;
270 offset = max_align = 0, mem = (addr_t)ptr;
271 #ifdef _WIN64
272 offset += sizeof (void*); /* space for function_table pointer */
273 #endif
274 copy = 0;
275 redo:
276 for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
277 n = 0; addr = 0;
278 for(i = 1; i < s1->nb_sections; i++) {
279 static const char shf[] = {
280 SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, SHF_ALLOC|SHF_WRITE
282 s = s1->sections[i];
283 if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
284 continue;
285 length = s->data_offset;
286 if (copy) {
287 if (addr == 0)
288 addr = s->sh_addr;
289 n = (s->sh_addr - addr) + length;
290 ptr = (void*)s->sh_addr;
291 if (k == 0)
292 ptr = (void*)(s->sh_addr - ptr_diff);
293 if (NULL == s->data || s->sh_type == SHT_NOBITS)
294 memset(ptr, 0, length);
295 else
296 memcpy(ptr, s->data, length);
297 #ifdef _WIN64
298 if (s == s1->uw_pdata)
299 *(void**)mem = win64_add_function_table(s1);
300 #endif
301 if (s->data) {
302 tcc_free(s->data);
303 s->data = NULL;
304 s->data_allocated = 0;
306 s->data_offset = 0;
307 continue;
309 align = s->sh_addralign - 1;
310 if (++n == 1 && align < (PAGE_ALIGN - 1))
311 align = (PAGE_ALIGN - 1);
312 if (max_align < align)
313 max_align = align;
314 addr = k ? mem : mem + ptr_diff;
315 offset += -(addr + offset) & align;
316 s->sh_addr = mem ? addr + offset : 0;
317 offset += length;
318 #if DEBUG_RUNMEN
319 if (mem)
320 printf("%d: %-16s %p len %04x align %04x\n",
321 k, s->name, (void*)s->sh_addr, length, align + 1);
322 #endif
324 if (copy) { /* set permissions */
325 if (k == 0 && ptr_diff)
326 continue; /* not with HAVE_SELINUX */
327 f = k;
328 #if !CONFIG_RUNMEM_RO
329 if (f != 0)
330 continue;
331 f = 3; /* change only SHF_EXECINSTR to rwx */
332 #endif
333 #if DEBUG_RUNMEN
334 printf("protect %d %p %04x\n", f, (void*)addr, n);
335 #endif
336 if (n)
337 set_pages_executable(s1, f, (void*)addr, n);
341 if (copy)
342 return 0;
344 /* relocate symbols */
345 relocate_syms(s1, s1->symtab, !(s1->nostdlib));
346 if (s1->nb_errors)
347 return -1;
348 if (0 == mem)
349 return offset + max_align;
351 #ifdef TCC_TARGET_PE
352 s1->pe_imagebase = mem;
353 #endif
355 /* relocate sections */
356 #ifndef TCC_TARGET_PE
357 relocate_plt(s1);
358 #endif
359 relocate_sections(s1);
360 copy = 1;
361 goto redo;
364 /* ------------------------------------------------------------- */
365 /* allow to run code in memory */
367 static void set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long length)
369 #ifdef _WIN32
370 static const unsigned char protect[] = {
371 PAGE_EXECUTE_READ,
372 PAGE_READONLY,
373 PAGE_READWRITE,
374 PAGE_EXECUTE_READWRITE
376 DWORD old;
377 VirtualProtect(ptr, length, protect[mode], &old);
378 #else
379 static const unsigned char protect[] = {
380 PROT_READ | PROT_EXEC,
381 PROT_READ,
382 PROT_READ | PROT_WRITE,
383 PROT_READ | PROT_WRITE | PROT_EXEC
385 addr_t start, end;
386 start = (addr_t)ptr & ~(PAGESIZE - 1);
387 end = (addr_t)ptr + length;
388 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
389 if (mprotect((void *)start, end - start, protect[mode]))
390 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
392 /* XXX: BSD sometimes dump core with bad system call */
393 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
394 if (mode == 0 || mode == 3) {
395 void __clear_cache(void *beginning, void *end);
396 __clear_cache(ptr, (char *)ptr + length);
398 # endif
400 #endif
403 #ifdef _WIN64
404 static void *win64_add_function_table(TCCState *s1)
406 void *p = NULL;
407 if (s1->uw_pdata) {
408 p = (void*)s1->uw_pdata->sh_addr;
409 RtlAddFunctionTable(
410 (RUNTIME_FUNCTION*)p,
411 s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
412 s1->pe_imagebase
414 s1->uw_pdata = NULL;
416 return p;
419 static void win64_del_function_table(void *p)
421 if (p) {
422 RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p);
425 #endif
426 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
427 /* ------------------------------------------------------------- */
428 #ifdef CONFIG_TCC_BACKTRACE
430 static int rt_vprintf(const char *fmt, va_list ap)
432 int ret = vfprintf(stderr, fmt, ap);
433 fflush(stderr);
434 return ret;
437 static int rt_printf(const char *fmt, ...)
439 va_list ap;
440 int r;
441 va_start(ap, fmt);
442 r = rt_vprintf(fmt, ap);
443 va_end(ap);
444 return r;
447 static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr)
449 ElfW(Sym) *esym;
450 for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) {
451 int type = ELFW(ST_TYPE)(esym->st_info);
452 if ((type == STT_FUNC || type == STT_GNU_IFUNC)
453 && wanted_pc >= esym->st_value
454 && wanted_pc < esym->st_value + esym->st_size) {
455 *func_addr = esym->st_value;
456 return rc->elf_str + esym->st_name;
459 return NULL;
462 #define INCLUDE_STACK_SIZE 32
464 /* print the position in the source file of PC value 'pc' by reading
465 the stabs debug information */
466 static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
467 const char *msg, const char *skip)
469 char func_name[128];
470 addr_t func_addr, last_pc, pc;
471 const char *incl_files[INCLUDE_STACK_SIZE];
472 int incl_index, last_incl_index, len, last_line_num, i;
473 const char *str, *p;
474 Stab_Sym *sym;
476 next:
477 func_name[0] = '\0';
478 func_addr = 0;
479 incl_index = 0;
480 last_pc = (addr_t)-1;
481 last_line_num = 1;
482 last_incl_index = 0;
484 for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) {
485 str = rc->stab_str + sym->n_strx;
486 pc = sym->n_value;
488 switch(sym->n_type) {
489 case N_SLINE:
490 if (func_addr)
491 goto rel_pc;
492 case N_SO:
493 case N_SOL:
494 goto abs_pc;
495 case N_FUN:
496 if (sym->n_strx == 0) /* end of function */
497 goto rel_pc;
498 abs_pc:
499 #if PTR_SIZE == 8
500 /* Stab_Sym.n_value is only 32bits */
501 pc += rc->prog_base;
502 #endif
503 goto check_pc;
504 rel_pc:
505 pc += func_addr;
506 check_pc:
507 if (pc >= wanted_pc && wanted_pc >= last_pc)
508 goto found;
509 break;
512 switch(sym->n_type) {
513 /* function start or end */
514 case N_FUN:
515 if (sym->n_strx == 0)
516 goto reset_func;
517 p = strchr(str, ':');
518 if (0 == p || (len = p - str + 1, len > sizeof func_name))
519 len = sizeof func_name;
520 pstrcpy(func_name, len, str);
521 func_addr = pc;
522 break;
523 /* line number info */
524 case N_SLINE:
525 last_pc = pc;
526 last_line_num = sym->n_desc;
527 last_incl_index = incl_index;
528 break;
529 /* include files */
530 case N_BINCL:
531 if (incl_index < INCLUDE_STACK_SIZE)
532 incl_files[incl_index++] = str;
533 break;
534 case N_EINCL:
535 if (incl_index > 1)
536 incl_index--;
537 break;
538 /* start/end of translation unit */
539 case N_SO:
540 incl_index = 0;
541 if (sym->n_strx) {
542 /* do not add path */
543 len = strlen(str);
544 if (len > 0 && str[len - 1] != '/')
545 incl_files[incl_index++] = str;
547 reset_func:
548 func_name[0] = '\0';
549 func_addr = 0;
550 last_pc = (addr_t)-1;
551 break;
552 /* alternative file name (from #line or #include directives) */
553 case N_SOL:
554 if (incl_index)
555 incl_files[incl_index-1] = str;
556 break;
560 func_name[0] = '\0';
561 func_addr = 0;
562 last_incl_index = 0;
563 /* we try symtab symbols (no line number info) */
564 p = rt_elfsym(rc, wanted_pc, &func_addr);
565 if (p) {
566 pstrcpy(func_name, sizeof func_name, p);
567 goto found;
569 if ((rc = rc->next))
570 goto next;
571 found:
572 i = last_incl_index;
573 if (i > 0) {
574 str = incl_files[--i];
575 if (skip[0] && strstr(str, skip))
576 return (addr_t)-1;
577 rt_printf("%s:%d: ", str, last_line_num);
578 } else
579 rt_printf("%08llx : ", (long long)wanted_pc);
580 rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
581 #if 0
582 if (--i >= 0) {
583 rt_printf(" (included from ");
584 for (;;) {
585 rt_printf("%s", incl_files[i]);
586 if (--i < 0)
587 break;
588 rt_printf(", ");
590 rt_printf(")");
592 #endif
593 return func_addr;
596 /* ------------------------------------------------------------- */
597 /* rt_printline - dwarf version */
599 #define MAX_128 ((8 * sizeof (long long) + 6) / 7)
601 #define DIR_TABLE_SIZE (64)
602 #define FILE_TABLE_SIZE (512)
604 #define dwarf_read_1(ln,end) \
605 ((ln) < (end) ? *(ln)++ : 0)
606 #define dwarf_read_2(ln,end) \
607 ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
608 #define dwarf_read_4(ln,end) \
609 ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
610 #define dwarf_read_8(ln,end) \
611 ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
612 #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \
613 switch (entry_format[j].form) { \
614 case DW_FORM_data1: (ln) += 1; break; \
615 case DW_FORM_data2: (ln) += 2; break; \
616 case DW_FORM_data4: (ln) += 3; break; \
617 case DW_FORM_data8: (ln) += 8; break; \
618 case DW_FORM_data16: (ln) += 16; break; \
619 case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \
620 default: goto next_line; \
623 static unsigned long long
624 dwarf_read_uleb128(unsigned char **ln, unsigned char *end)
626 unsigned char *cp = *ln;
627 unsigned long long retval = 0;
628 int i;
630 for (i = 0; i < MAX_128; i++) {
631 unsigned long long byte = dwarf_read_1(cp, end);
633 retval |= (byte & 0x7f) << (i * 7);
634 if ((byte & 0x80) == 0)
635 break;
637 *ln = cp;
638 return retval;
641 static long long
642 dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
644 unsigned char *cp = *ln;
645 long long retval = 0;
646 int i;
648 for (i = 0; i < MAX_128; i++) {
649 unsigned long long byte = dwarf_read_1(cp, end);
651 retval |= (byte & 0x7f) << (i * 7);
652 if ((byte & 0x80) == 0) {
653 if ((byte & 0x40) && (i + 1) * 7 < 64)
654 retval |= -1LL << ((i + 1) * 7);
655 break;
658 *ln = cp;
659 return retval;
662 static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
663 const char *msg, const char *skip)
665 unsigned char *ln;
666 unsigned char *cp;
667 unsigned char *end;
668 unsigned char *opcode_length;
669 unsigned long long size;
670 unsigned int length;
671 unsigned char version;
672 unsigned int min_insn_length;
673 unsigned int max_ops_per_insn;
674 int line_base;
675 unsigned int line_range;
676 unsigned int opcode_base;
677 unsigned int opindex;
678 unsigned int col;
679 unsigned int i;
680 unsigned int j;
681 unsigned int len;
682 unsigned long long value;
683 struct {
684 unsigned int type;
685 unsigned int form;
686 } entry_format[256];
687 unsigned int dir_size;
688 #if 0
689 char *dirs[DIR_TABLE_SIZE];
690 #endif
691 unsigned int filename_size;
692 struct dwarf_filename_struct {
693 unsigned int dir_entry;
694 char *name;
695 } filename_table[FILE_TABLE_SIZE];
696 addr_t last_pc;
697 addr_t pc;
698 addr_t func_addr;
699 int line;
700 char *filename;
701 char *function;
703 next:
704 ln = rc->dwarf_line;
705 while (ln < rc->dwarf_line_end) {
706 dir_size = 0;
707 filename_size = 0;
708 last_pc = 0;
709 pc = 0;
710 func_addr = 0;
711 line = 1;
712 filename = NULL;
713 function = NULL;
714 length = 4;
715 size = dwarf_read_4(ln, rc->dwarf_line_end);
716 if (size == 0xffffffffu) // dwarf 64
717 length = 8, size = dwarf_read_8(ln, rc->dwarf_line_end);
718 end = ln + size;
719 if (end < ln || end > rc->dwarf_line_end)
720 break;
721 version = dwarf_read_2(ln, end);
722 if (version >= 5)
723 ln += length + 2; // address size, segment selector, prologue Length
724 else
725 ln += length; // prologue Length
726 min_insn_length = dwarf_read_1(ln, end);
727 if (version >= 4)
728 max_ops_per_insn = dwarf_read_1(ln, end);
729 else
730 max_ops_per_insn = 1;
731 ln++; // Initial value of 'is_stmt'
732 line_base = dwarf_read_1(ln, end);
733 line_base |= line_base >= 0x80 ? ~0xff : 0;
734 line_range = dwarf_read_1(ln, end);
735 opcode_base = dwarf_read_1(ln, end);
736 opcode_length = ln;
737 ln += opcode_base - 1;
738 opindex = 0;
739 if (version >= 5) {
740 col = dwarf_read_1(ln, end);
741 for (i = 0; i < col; i++) {
742 entry_format[i].type = dwarf_read_uleb128(&ln, end);
743 entry_format[i].form = dwarf_read_uleb128(&ln, end);
745 dir_size = dwarf_read_uleb128(&ln, end);
746 for (i = 0; i < dir_size; i++) {
747 for (j = 0; j < col; j++) {
748 if (entry_format[j].type == DW_LNCT_path) {
749 if (entry_format[j].form != DW_FORM_line_strp)
750 goto next_line;
751 #if 0
752 value = length == 4 ? dwarf_read_4(ln, end)
753 : dwarf_read_8(ln, end);
754 if (i < DIR_TABLE_SIZE)
755 dirs[i] = (char *)rc->dwarf_line_str + value;
756 #else
757 length == 4 ? dwarf_read_4(ln, end)
758 : dwarf_read_8(ln, end);
759 #endif
761 else
762 dwarf_ignore_type(ln, end);
765 col = dwarf_read_1(ln, end);
766 for (i = 0; i < col; i++) {
767 entry_format[i].type = dwarf_read_uleb128(&ln, end);
768 entry_format[i].form = dwarf_read_uleb128(&ln, end);
770 filename_size = dwarf_read_uleb128(&ln, end);
771 for (i = 0; i < filename_size; i++)
772 for (j = 0; j < col; j++) {
773 if (entry_format[j].type == DW_LNCT_path) {
774 if (entry_format[j].form != DW_FORM_line_strp)
775 goto next_line;
776 value = length == 4 ? dwarf_read_4(ln, end)
777 : dwarf_read_8(ln, end);
778 if (i < FILE_TABLE_SIZE)
779 filename_table[i].name =
780 (char *)rc->dwarf_line_str + value;
782 else if (entry_format[j].type == DW_LNCT_directory_index) {
783 switch (entry_format[j].form) {
784 case DW_FORM_data1: value = dwarf_read_1(ln, end); break;
785 case DW_FORM_data2: value = dwarf_read_2(ln, end); break;
786 case DW_FORM_data4: value = dwarf_read_4(ln, end); break;
787 case DW_FORM_udata: value = dwarf_read_uleb128(&ln, end); break;
788 default: goto next_line;
790 if (i < FILE_TABLE_SIZE)
791 filename_table[i].dir_entry = value;
793 else
794 dwarf_ignore_type(ln, end);
797 else {
798 while ((dwarf_read_1(ln, end))) {
799 #if 0
800 if (++dir_size < DIR_TABLE_SIZE)
801 dirs[dir_size - 1] = (char *)ln - 1;
802 #endif
803 while (dwarf_read_1(ln, end)) {}
805 while ((dwarf_read_1(ln, end))) {
806 if (++filename_size < FILE_TABLE_SIZE) {
807 filename_table[filename_size - 1].name = (char *)ln - 1;
808 while (dwarf_read_1(ln, end)) {}
809 filename_table[filename_size - 1].dir_entry =
810 dwarf_read_uleb128(&ln, end);
812 else {
813 while (dwarf_read_1(ln, end)) {}
814 dwarf_read_uleb128(&ln, end);
816 dwarf_read_uleb128(&ln, end); // time
817 dwarf_read_uleb128(&ln, end); // size
820 if (filename_size >= 1)
821 filename = filename_table[0].name;
822 while (ln < end) {
823 last_pc = pc;
824 i = dwarf_read_1(ln, end);
825 if (i >= opcode_base) {
826 if (max_ops_per_insn == 1)
827 pc += ((i - opcode_base) / line_range) * min_insn_length;
828 else {
829 pc += (opindex + (i - opcode_base) / line_range) /
830 max_ops_per_insn * min_insn_length;
831 opindex = (opindex + (i - opcode_base) / line_range) %
832 max_ops_per_insn;
834 i = (int)((i - opcode_base) % line_range) + line_base;
835 check_pc:
836 if (pc >= wanted_pc && wanted_pc >= last_pc)
837 goto found;
838 line += i;
840 else {
841 switch (i) {
842 case 0:
843 len = dwarf_read_uleb128(&ln, end);
844 cp = ln;
845 ln += len;
846 if (len == 0)
847 goto next_line;
848 switch (dwarf_read_1(cp, end)) {
849 case DW_LNE_end_sequence:
850 break;
851 case DW_LNE_set_address:
852 #if PTR_SIZE == 4
853 pc = dwarf_read_4(cp, end);
854 #else
855 pc = dwarf_read_8(cp, end);
856 #endif
857 opindex = 0;
858 break;
859 case DW_LNE_define_file: /* deprecated */
860 if (++filename_size < FILE_TABLE_SIZE) {
861 filename_table[filename_size - 1].name = (char *)ln - 1;
862 while (dwarf_read_1(ln, end)) {}
863 filename_table[filename_size - 1].dir_entry =
864 dwarf_read_uleb128(&ln, end);
866 else {
867 while (dwarf_read_1(ln, end)) {}
868 dwarf_read_uleb128(&ln, end);
870 dwarf_read_uleb128(&ln, end); // time
871 dwarf_read_uleb128(&ln, end); // size
872 break;
873 case DW_LNE_hi_user - 1:
874 function = (char *)cp;
875 func_addr = pc;
876 break;
877 default:
878 break;
880 break;
881 case DW_LNS_advance_pc:
882 if (max_ops_per_insn == 1)
883 pc += dwarf_read_uleb128(&ln, end) * min_insn_length;
884 else {
885 unsigned long long off = dwarf_read_uleb128(&ln, end);
887 pc += (opindex + off) / max_ops_per_insn *
888 min_insn_length;
889 opindex = (opindex + off) % max_ops_per_insn;
891 i = 0;
892 goto check_pc;
893 case DW_LNS_advance_line:
894 line += dwarf_read_sleb128(&ln, end);
895 break;
896 case DW_LNS_set_file:
897 i = dwarf_read_uleb128(&ln, end);
898 if (i < FILE_TABLE_SIZE && i < filename_size)
899 filename = filename_table[i].name;
900 break;
901 case DW_LNS_const_add_pc:
902 if (max_ops_per_insn == 1)
903 pc += ((255 - opcode_base) / line_range) * min_insn_length;
904 else {
905 unsigned int off = (255 - opcode_base) / line_range;
907 pc += ((opindex + off) / max_ops_per_insn) *
908 min_insn_length;
909 opindex = (opindex + off) % max_ops_per_insn;
911 i = 0;
912 goto check_pc;
913 case DW_LNS_fixed_advance_pc:
914 i = dwarf_read_2(ln, end);
915 pc += i;
916 opindex = 0;
917 i = 0;
918 goto check_pc;
919 default:
920 for (j = 0; j < opcode_length[i - 1]; j++)
921 dwarf_read_uleb128 (&ln, end);
922 break;
926 next_line:
927 ln = end;
930 filename = NULL;
931 func_addr = 0;
932 /* we try symtab symbols (no line number info) */
933 function = rt_elfsym(rc, wanted_pc, &func_addr);
934 if (function)
935 goto found;
936 if ((rc = rc->next))
937 goto next;
938 found:
939 if (filename) {
940 if (skip[0] && strstr(filename, skip))
941 return (addr_t)-1;
942 rt_printf("%s:%d: ", filename, line);
944 else
945 rt_printf("0x%08llx : ", (long long)wanted_pc);
946 rt_printf("%s %s", msg, function ? function : "???");
947 return (addr_t)func_addr;
949 /* ------------------------------------------------------------- */
951 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
953 static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
955 rt_context *rc = &g_rtctxt;
956 addr_t pc = 0;
957 char skip[100];
958 int i, level, ret, n;
959 const char *a, *b, *msg;
961 if (fp) {
962 /* we're called from tcc_backtrace. */
963 rc->fp = (addr_t)fp;
964 rc->ip = (addr_t)ip;
965 msg = "";
966 } else {
967 /* we're called from signal/exception handler */
968 msg = "RUNTIME ERROR: ";
971 skip[0] = 0;
972 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
973 if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) {
974 memcpy(skip, a, b - a), skip[b - a] = 0;
975 fmt = b + 1;
978 n = rc->num_callers ? rc->num_callers : 6;
979 for (i = level = 0; level < n; i++) {
980 ret = rt_get_caller_pc(&pc, rc, i);
981 a = "%s";
982 if (ret != -1) {
983 if (rc->dwarf)
984 pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip);
985 else
986 pc = rt_printline(rc, pc, level ? "by" : "at", skip);
987 if (pc == (addr_t)-1)
988 continue;
989 a = ": %s";
991 if (level == 0) {
992 rt_printf(a, msg);
993 rt_vprintf(fmt, ap);
994 } else if (ret == -1)
995 break;
996 rt_printf("\n");
997 if (ret == -1 || (pc == (addr_t)rc->top_func && pc))
998 break;
999 ++level;
1002 rc->ip = rc->fp = 0;
1003 return 0;
1006 /* emit a run time error at position 'pc' */
1007 static int rt_error(const char *fmt, ...)
1009 va_list ap;
1010 int ret;
1011 va_start(ap, fmt);
1012 ret = _rt_error(0, 0, fmt, ap);
1013 va_end(ap);
1014 return ret;
1017 static void rt_exit(int code)
1019 rt_context *rc = &g_rtctxt;
1020 if (rc->do_jmp)
1021 longjmp(rc->jmp_buf, code ? code : 256);
1022 exit(code);
1025 /* ------------------------------------------------------------- */
1027 #ifndef _WIN32
1028 # include <signal.h>
1029 # ifndef __OpenBSD__
1030 # include <sys/ucontext.h>
1031 # endif
1032 #else
1033 # define ucontext_t CONTEXT
1034 #endif
1036 /* translate from ucontext_t* to internal rt_context * */
1037 static void rt_getcontext(ucontext_t *uc, rt_context *rc)
1039 #if defined _WIN64
1040 rc->ip = uc->Rip;
1041 rc->fp = uc->Rbp;
1042 rc->sp = uc->Rsp;
1043 #elif defined _WIN32
1044 rc->ip = uc->Eip;
1045 rc->fp = uc->Ebp;
1046 rc->sp = uc->Esp;
1047 #elif defined __i386__
1048 # if defined(__APPLE__)
1049 rc->ip = uc->uc_mcontext->__ss.__eip;
1050 rc->fp = uc->uc_mcontext->__ss.__ebp;
1051 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1052 rc->ip = uc->uc_mcontext.mc_eip;
1053 rc->fp = uc->uc_mcontext.mc_ebp;
1054 # elif defined(__dietlibc__)
1055 rc->ip = uc->uc_mcontext.eip;
1056 rc->fp = uc->uc_mcontext.ebp;
1057 # elif defined(__NetBSD__)
1058 rc->ip = uc->uc_mcontext.__gregs[_REG_EIP];
1059 rc->fp = uc->uc_mcontext.__gregs[_REG_EBP];
1060 # elif defined(__OpenBSD__)
1061 rc->ip = uc->sc_eip;
1062 rc->fp = uc->sc_ebp;
1063 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
1064 rc->ip = uc->uc_mcontext.gregs[EIP];
1065 rc->fp = uc->uc_mcontext.gregs[EBP];
1066 # else
1067 rc->ip = uc->uc_mcontext.gregs[REG_EIP];
1068 rc->fp = uc->uc_mcontext.gregs[REG_EBP];
1069 # endif
1070 #elif defined(__x86_64__)
1071 # if defined(__APPLE__)
1072 rc->ip = uc->uc_mcontext->__ss.__rip;
1073 rc->fp = uc->uc_mcontext->__ss.__rbp;
1074 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1075 rc->ip = uc->uc_mcontext.mc_rip;
1076 rc->fp = uc->uc_mcontext.mc_rbp;
1077 # elif defined(__NetBSD__)
1078 rc->ip = uc->uc_mcontext.__gregs[_REG_RIP];
1079 rc->fp = uc->uc_mcontext.__gregs[_REG_RBP];
1080 # elif defined(__OpenBSD__)
1081 rc->ip = uc->sc_rip;
1082 rc->fp = uc->sc_rbp;
1083 # else
1084 rc->ip = uc->uc_mcontext.gregs[REG_RIP];
1085 rc->fp = uc->uc_mcontext.gregs[REG_RBP];
1086 # endif
1087 #elif defined(__arm__) && defined(__NetBSD__)
1088 rc->ip = uc->uc_mcontext.__gregs[_REG_PC];
1089 rc->fp = uc->uc_mcontext.__gregs[_REG_FP];
1090 #elif defined(__arm__) && defined(__OpenBSD__)
1091 rc->ip = uc->sc_pc;
1092 rc->fp = uc->sc_r11;
1093 #elif defined(__arm__) && defined(__FreeBSD__)
1094 rc->ip = uc->uc_mcontext.__gregs[_REG_PC];
1095 rc->fp = uc->uc_mcontext.__gregs[_REG_FP];
1096 #elif defined(__arm__)
1097 rc->ip = uc->uc_mcontext.arm_pc;
1098 rc->fp = uc->uc_mcontext.arm_fp;
1099 #elif defined(__aarch64__) && defined(__APPLE__)
1100 // see:
1101 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
1102 rc->ip = uc->uc_mcontext->__ss.__pc;
1103 rc->fp = uc->uc_mcontext->__ss.__fp;
1104 #elif defined(__aarch64__) && defined(__FreeBSD__)
1105 rc->ip = uc->uc_mcontext.mc_gpregs.gp_elr; /* aka REG_PC */
1106 rc->fp = uc->uc_mcontext.mc_gpregs.gp_x[29];
1107 #elif defined(__aarch64__) && defined(__NetBSD__)
1108 rc->ip = uc->uc_mcontext.__gregs[_REG_PC];
1109 rc->fp = uc->uc_mcontext.__gregs[_REG_FP];
1110 #elif defined(__aarch64__) && defined(__OpenBSD__)
1111 rc->ip = uc->sc_elr;
1112 rc->fp = uc->sc_x[29];
1113 #elif defined(__aarch64__)
1114 rc->ip = uc->uc_mcontext.pc;
1115 rc->fp = uc->uc_mcontext.regs[29];
1116 #elif defined(__riscv) && defined(__OpenBSD__)
1117 rc->ip = uc->sc_sepc;
1118 rc->fp = uc->sc_s[0];
1119 #elif defined(__riscv)
1120 rc->ip = uc->uc_mcontext.__gregs[REG_PC];
1121 rc->fp = uc->uc_mcontext.__gregs[REG_S0];
1122 #endif
1125 /* ------------------------------------------------------------- */
1126 #ifndef _WIN32
1127 /* signal handler for fatal errors */
1128 static void sig_error(int signum, siginfo_t *siginf, void *puc)
1130 rt_context *rc = &g_rtctxt;
1131 rt_getcontext(puc, rc);
1133 switch(signum) {
1134 case SIGFPE:
1135 switch(siginf->si_code) {
1136 case FPE_INTDIV:
1137 case FPE_FLTDIV:
1138 rt_error("division by zero");
1139 break;
1140 default:
1141 rt_error("floating point exception");
1142 break;
1144 break;
1145 case SIGBUS:
1146 case SIGSEGV:
1147 rt_error("invalid memory access");
1148 break;
1149 case SIGILL:
1150 rt_error("illegal instruction");
1151 break;
1152 case SIGABRT:
1153 rt_error("abort() called");
1154 break;
1155 default:
1156 rt_error("caught signal %d", signum);
1157 break;
1159 rt_exit(255);
1162 #ifndef SA_SIGINFO
1163 # define SA_SIGINFO 0x00000004u
1164 #endif
1166 /* Generate a stack backtrace when a CPU exception occurs. */
1167 static void set_exception_handler(void)
1169 struct sigaction sigact;
1170 /* install TCC signal handlers to print debug info on fatal
1171 runtime errors */
1172 sigemptyset (&sigact.sa_mask);
1173 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
1174 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
1175 sigact.sa_flags |= SA_ONSTACK;
1176 #endif
1177 sigact.sa_sigaction = sig_error;
1178 sigemptyset(&sigact.sa_mask);
1179 sigaction(SIGFPE, &sigact, NULL);
1180 sigaction(SIGILL, &sigact, NULL);
1181 sigaction(SIGSEGV, &sigact, NULL);
1182 sigaction(SIGBUS, &sigact, NULL);
1183 sigaction(SIGABRT, &sigact, NULL);
1184 #if 0//def SIGSTKSZ
1185 /* This allows stack overflow to be reported instead of a SEGV */
1187 stack_t ss;
1188 static unsigned char stack[SIGSTKSZ] __attribute__((aligned(16)));
1190 ss.ss_sp = stack;
1191 ss.ss_size = SIGSTKSZ;
1192 ss.ss_flags = 0;
1193 sigaltstack(&ss, NULL);
1195 #endif
1198 #else /* WIN32 */
1200 /* signal handler for fatal errors */
1201 static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
1203 rt_context *rc = &g_rtctxt;
1204 unsigned code;
1205 rt_getcontext(ex_info->ContextRecord, rc);
1207 switch (code = ex_info->ExceptionRecord->ExceptionCode) {
1208 case EXCEPTION_ACCESS_VIOLATION:
1209 rt_error("invalid memory access");
1210 break;
1211 case EXCEPTION_STACK_OVERFLOW:
1212 rt_error("stack overflow");
1213 break;
1214 case EXCEPTION_INT_DIVIDE_BY_ZERO:
1215 rt_error("division by zero");
1216 break;
1217 case EXCEPTION_BREAKPOINT:
1218 case EXCEPTION_SINGLE_STEP:
1219 rc->ip = *(addr_t*)rc->sp;
1220 rt_error("breakpoint/single-step exception:");
1221 return EXCEPTION_CONTINUE_SEARCH;
1222 default:
1223 rt_error("caught exception %08x", code);
1224 break;
1226 if (rc->do_jmp)
1227 rt_exit(255);
1228 return EXCEPTION_EXECUTE_HANDLER;
1231 /* Generate a stack backtrace when a CPU exception occurs. */
1232 static void set_exception_handler(void)
1234 SetUnhandledExceptionFilter(cpu_exception_handler);
1237 #endif
1239 /* ------------------------------------------------------------- */
1240 /* return the PC at frame level 'level'. Return negative if not found */
1241 #if defined(__i386__) || defined(__x86_64__)
1242 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
1244 addr_t ip, fp;
1245 if (level == 0) {
1246 ip = rc->ip;
1247 } else {
1248 ip = 0;
1249 fp = rc->fp;
1250 while (--level) {
1251 /* XXX: check address validity with program info */
1252 if (fp <= 0x1000)
1253 break;
1254 fp = ((addr_t *)fp)[0];
1256 if (fp > 0x1000)
1257 ip = ((addr_t *)fp)[1];
1259 if (ip <= 0x1000)
1260 return -1;
1261 *paddr = ip;
1262 return 0;
1265 #elif defined(__arm__)
1266 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
1268 /* XXX: only supports linux/bsd */
1269 #if !defined(__linux__) && \
1270 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
1271 return -1;
1272 #else
1273 if (level == 0) {
1274 *paddr = rc->ip;
1275 } else {
1276 addr_t fp = rc->fp;
1277 while (--level)
1278 fp = ((addr_t *)fp)[0];
1279 *paddr = ((addr_t *)fp)[2];
1281 return 0;
1282 #endif
1285 #elif defined(__aarch64__)
1286 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
1288 if (level == 0) {
1289 *paddr = rc->ip;
1290 } else {
1291 addr_t *fp = (addr_t*)rc->fp;
1292 while (--level)
1293 fp = (addr_t *)fp[0];
1294 *paddr = fp[1];
1296 return 0;
1299 #elif defined(__riscv)
1300 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
1302 if (level == 0) {
1303 *paddr = rc->ip;
1304 } else {
1305 addr_t *fp = (addr_t*)rc->fp;
1306 while (--level && fp >= (addr_t*)0x1000)
1307 fp = (addr_t *)fp[-2];
1308 if (fp < (addr_t*)0x1000)
1309 return -1;
1310 *paddr = fp[-1];
1312 return 0;
1315 #else
1316 #warning add arch specific rt_get_caller_pc()
1317 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
1319 return -1;
1322 #endif
1323 #endif /* CONFIG_TCC_BACKTRACE */
1324 /* ------------------------------------------------------------- */
1325 #ifdef CONFIG_TCC_STATIC
1327 /* dummy function for profiling */
1328 ST_FUNC void *dlopen(const char *filename, int flag)
1330 return NULL;
1333 ST_FUNC void dlclose(void *p)
1337 ST_FUNC const char *dlerror(void)
1339 return "error";
1342 typedef struct TCCSyms {
1343 char *str;
1344 void *ptr;
1345 } TCCSyms;
1348 /* add the symbol you want here if no dynamic linking is done */
1349 static TCCSyms tcc_syms[] = {
1350 #if !defined(CONFIG_TCCBOOT)
1351 #define TCCSYM(a) { #a, &a, },
1352 TCCSYM(printf)
1353 TCCSYM(fprintf)
1354 TCCSYM(fopen)
1355 TCCSYM(fclose)
1356 #undef TCCSYM
1357 #endif
1358 { NULL, NULL },
1361 ST_FUNC void *dlsym(void *handle, const char *symbol)
1363 TCCSyms *p;
1364 p = tcc_syms;
1365 while (p->str != NULL) {
1366 if (!strcmp(p->str, symbol))
1367 return p->ptr;
1368 p++;
1370 return NULL;
1373 #endif /* CONFIG_TCC_STATIC */
1374 #endif /* TCC_IS_NATIVE */
1375 /* ------------------------------------------------------------- */