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
23 /* only native compiler supports -run */
26 #ifdef CONFIG_TCC_BACKTRACE
27 typedef struct rt_context
29 /* --> tccelf.c:tcc_add_btstub wants those below in that order: */
32 Stab_Sym
*stab_sym
, *stab_sym_end
;
36 unsigned char *dwarf_line
, *dwarf_line_end
, *dwarf_line_str
;
40 ElfW(Sym
) *esym_start
, *esym_end
;
44 struct rt_context
*next
;
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 static void init_atexit(void);
58 static void run_atexit(void);
59 static int rt_atexit(void (*function
)(void));
60 #endif /* CONFIG_TCC_BACKTRACE */
62 /* defined when included from lib/bt-exe.c */
63 #ifndef CONFIG_TCC_BACKTRACE_ONLY
66 # include <sys/mman.h>
69 static void set_pages_executable(TCCState
*s1
, int mode
, void *ptr
, unsigned long length
);
70 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
);
73 static void *win64_add_function_table(TCCState
*s1
);
74 static void win64_del_function_table(void *);
77 /* ------------------------------------------------------------- */
78 /* Do all relocations (needed before using tcc_get_symbol())
79 Returns -1 on error. */
81 LIBTCCAPI
int tcc_relocate(TCCState
*s1
, void *ptr
)
86 if (TCC_RELOCATE_AUTO
!= ptr
)
87 return tcc_relocate_ex(s1
, ptr
, 0);
89 size
= tcc_relocate_ex(s1
, NULL
, 0);
95 /* Using mmap instead of malloc */
97 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
98 int fd
= mkstemp(tmpfname
);
102 size
= (size
+ (PAGESIZE
-1)) & ~(PAGESIZE
-1);
103 ptr
= mmap(NULL
, size
* 2, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
104 /* mmap RX memory at a fixed distance */
105 prx
= mmap((char*)ptr
+ size
, size
, PROT_READ
|PROT_EXEC
, MAP_SHARED
|MAP_FIXED
, fd
, 0);
106 if (ptr
== MAP_FAILED
|| prx
== MAP_FAILED
)
107 tcc_error("tccrun: could not map memory");
108 ptr_diff
= (char*)prx
- (char*)ptr
;
110 //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
113 ptr
= tcc_malloc(size
);
115 tcc_relocate_ex(s1
, ptr
, ptr_diff
); /* no more errors expected */
116 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, (void*)(addr_t
)size
);
117 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, ptr
);
121 ST_FUNC
void tcc_run_free(TCCState
*s1
)
125 for (i
= 0; i
< s1
->nb_runtime_mem
; i
+= 2) {
126 unsigned size
= (unsigned)(addr_t
)s1
->runtime_mem
[i
];
127 void *ptr
= s1
->runtime_mem
[i
+1];
129 munmap(ptr
, size
* 2);
131 /* unprotect memory to make it usable for malloc again */
132 set_pages_executable(s1
, 2, ptr
, size
);
134 win64_del_function_table(*(void**)ptr
);
139 tcc_free(s1
->runtime_mem
);
142 static void run_cdtors(TCCState
*s1
, const char *start
, const char *end
,
143 int argc
, char **argv
, char **envp
)
145 void **a
= (void **)get_sym_addr(s1
, start
, 0, 0);
146 void **b
= (void **)get_sym_addr(s1
, end
, 0, 0);
148 ((void(*)(int, char **, char **))*a
++)(argc
, argv
, envp
);
151 /* launch the compiled program with the given arguments */
152 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
154 int (*prog_main
)(int, char **, char **), ret
;
155 #ifdef CONFIG_TCC_BACKTRACE
156 rt_context
*rc
= &g_rtctxt
;
159 #if defined(__APPLE__) || defined(__FreeBSD__)
161 #elif defined(__OpenBSD__) || defined(__NetBSD__)
162 extern char **environ
;
163 char **envp
= environ
;
165 char **envp
= environ
;
168 s1
->runtime_main
= s1
->nostdlib
? "_start" : "main";
169 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, s1
->runtime_main
, 0, 1))
171 #ifdef CONFIG_TCC_BACKTRACE
173 tcc_add_symbol(s1
, "exit", rt_exit
);
175 tcc_add_symbol(s1
, "atexit", rt_atexit
);
176 if (tcc_relocate(s1
, TCC_RELOCATE_AUTO
) < 0)
178 prog_main
= (void*)get_sym_addr(s1
, s1
->runtime_main
, 1, 1);
180 #ifdef CONFIG_TCC_BACKTRACE
181 memset(rc
, 0, sizeof *rc
);
185 rc
->dwarf_line
= dwarf_line_section
->data
;
186 rc
->dwarf_line_end
= dwarf_line_section
->data
+ dwarf_line_section
->data_offset
;
187 if (dwarf_line_str_section
)
188 rc
->dwarf_line_str
= dwarf_line_str_section
->data
;
192 rc
->stab_sym
= (Stab_Sym
*)stab_section
->data
;
193 rc
->stab_sym_end
= (Stab_Sym
*)(stab_section
->data
+ stab_section
->data_offset
);
194 rc
->stab_str
= (char *)stab_section
->link
->data
;
196 rc
->dwarf
= s1
->dwarf
;
197 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
198 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
199 rc
->elf_str
= (char *)symtab_section
->link
->data
;
201 rc
->prog_base
= text_section
->sh_addr
& 0xffffffff00000000ULL
;
203 rc
->top_func
= tcc_get_symbol(s1
, "main");
204 rc
->num_callers
= s1
->rt_num_callers
;
206 if ((p
= tcc_get_symbol(s1
, "__rt_error")))
207 *(void**)p
= _rt_error
;
208 #ifdef CONFIG_TCC_BCHECK
209 if (s1
->do_bounds_check
) {
210 rc
->bounds_start
= (void*)bounds_section
->sh_addr
;
211 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
212 ((void(*)(void*,int))p
)(rc
->bounds_start
, 1);
215 set_exception_handler();
219 errno
= 0; /* clean errno value */
223 /* These aren't C symbols, so don't need leading underscore handling. */
224 run_cdtors(s1
, "__init_array_start", "__init_array_end", argc
, argv
, envp
);
225 #ifdef CONFIG_TCC_BACKTRACE
226 if (!rc
->do_jmp
|| !(ret
= setjmp(rc
->jmp_buf)))
229 ret
= prog_main(argc
, argv
, envp
);
231 run_cdtors(s1
, "__fini_array_start", "__fini_array_end", 0, NULL
, NULL
);
233 if ((s1
->dflag
& 16) && ret
)
234 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
238 #define DEBUG_RUNMEN 0
240 /* enable rx/ro/rw permissions */
241 #define CONFIG_RUNMEM_RO 1
244 # define PAGE_ALIGN PAGESIZE
245 #elif defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
246 /* To avoid that x86 processors would reload cached instructions
247 each time when data is written in the near, we need to make
248 sure that code and data do not share the same 64 byte unit */
249 # define PAGE_ALIGN 64
251 # define PAGE_ALIGN 1
254 /* relocate code. Return -1 on error, required size if ptr is NULL,
255 otherwise copy code into buffer passed by the caller */
256 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
)
259 unsigned offset
, length
, align
, max_align
, i
, k
, f
;
266 pe_output_file(s1
, NULL
);
269 resolve_common_syms(s1
);
270 build_got_entries(s1
, 0);
276 offset
= max_align
= 0, mem
= (addr_t
)ptr
;
278 offset
+= sizeof (void*); /* space for function_table pointer */
282 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
284 for(i
= 1; i
< s1
->nb_sections
; i
++) {
285 static const char shf
[] = {
286 SHF_ALLOC
|SHF_EXECINSTR
, SHF_ALLOC
, SHF_ALLOC
|SHF_WRITE
289 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
291 length
= s
->data_offset
;
295 n
= (s
->sh_addr
- addr
) + length
;
296 ptr
= (void*)s
->sh_addr
;
298 ptr
= (void*)(s
->sh_addr
- ptr_diff
);
299 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
300 memset(ptr
, 0, length
);
302 memcpy(ptr
, s
->data
, length
);
304 if (s
== s1
->uw_pdata
)
305 *(void**)mem
= win64_add_function_table(s1
);
310 s
->data_allocated
= 0;
315 align
= s
->sh_addralign
- 1;
316 if (++n
== 1 && align
< (PAGE_ALIGN
- 1))
317 align
= (PAGE_ALIGN
- 1);
318 if (max_align
< align
)
320 addr
= k
? mem
: mem
+ ptr_diff
;
321 offset
+= -(addr
+ offset
) & align
;
322 s
->sh_addr
= mem
? addr
+ offset
: 0;
326 printf("%d: %-16s %p len %04x align %04x\n",
327 k
, s
->name
, (void*)s
->sh_addr
, length
, align
+ 1);
330 if (copy
) { /* set permissions */
331 if (k
== 0 && ptr_diff
)
332 continue; /* not with HAVE_SELINUX */
334 #if !CONFIG_RUNMEM_RO
337 f
= 3; /* change only SHF_EXECINSTR to rwx */
340 printf("protect %d %p %04x\n", f
, (void*)addr
, n
);
343 set_pages_executable(s1
, f
, (void*)addr
, n
);
350 /* relocate symbols */
351 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
355 return offset
+ max_align
;
358 s1
->pe_imagebase
= mem
;
361 /* relocate sections */
362 #ifndef TCC_TARGET_PE
365 relocate_sections(s1
);
370 /* ------------------------------------------------------------- */
371 /* allow to run code in memory */
373 static void set_pages_executable(TCCState
*s1
, int mode
, void *ptr
, unsigned long length
)
376 static const unsigned char protect
[] = {
380 PAGE_EXECUTE_READWRITE
383 VirtualProtect(ptr
, length
, protect
[mode
], &old
);
385 static const unsigned char protect
[] = {
386 PROT_READ
| PROT_EXEC
,
388 PROT_READ
| PROT_WRITE
,
389 PROT_READ
| PROT_WRITE
| PROT_EXEC
392 start
= (addr_t
)ptr
& ~(PAGESIZE
- 1);
393 end
= (addr_t
)ptr
+ length
;
394 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
395 if (mprotect((void *)start
, end
- start
, protect
[mode
]))
396 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
398 /* XXX: BSD sometimes dump core with bad system call */
399 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
400 if (mode
== 0 || mode
== 3) {
401 void __clear_cache(void *beginning
, void *end
);
402 __clear_cache(ptr
, (char *)ptr
+ length
);
410 static void *win64_add_function_table(TCCState
*s1
)
414 p
= (void*)s1
->uw_pdata
->sh_addr
;
416 (RUNTIME_FUNCTION
*)p
,
417 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
425 static void win64_del_function_table(void *p
)
428 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
432 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
433 /* ------------------------------------------------------------- */
434 #ifdef CONFIG_TCC_BACKTRACE
436 static int rt_vprintf(const char *fmt
, va_list ap
)
438 int ret
= vfprintf(stderr
, fmt
, ap
);
443 static int rt_printf(const char *fmt
, ...)
448 r
= rt_vprintf(fmt
, ap
);
453 static char *rt_elfsym(rt_context
*rc
, addr_t wanted_pc
, addr_t
*func_addr
)
456 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
457 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
458 if ((type
== STT_FUNC
|| type
== STT_GNU_IFUNC
)
459 && wanted_pc
>= esym
->st_value
460 && wanted_pc
< esym
->st_value
+ esym
->st_size
) {
461 *func_addr
= esym
->st_value
;
462 return rc
->elf_str
+ esym
->st_name
;
468 #define INCLUDE_STACK_SIZE 32
470 /* print the position in the source file of PC value 'pc' by reading
471 the stabs debug information */
472 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
,
473 const char *msg
, const char *skip
)
476 addr_t func_addr
, last_pc
, pc
;
477 const char *incl_files
[INCLUDE_STACK_SIZE
];
478 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
486 last_pc
= (addr_t
)-1;
490 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
491 str
= rc
->stab_str
+ sym
->n_strx
;
494 switch(sym
->n_type
) {
502 if (sym
->n_strx
== 0) /* end of function */
506 /* Stab_Sym.n_value is only 32bits */
513 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
518 switch(sym
->n_type
) {
519 /* function start or end */
521 if (sym
->n_strx
== 0)
523 p
= strchr(str
, ':');
524 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
525 len
= sizeof func_name
;
526 pstrcpy(func_name
, len
, str
);
529 /* line number info */
532 last_line_num
= sym
->n_desc
;
533 last_incl_index
= incl_index
;
537 if (incl_index
< INCLUDE_STACK_SIZE
)
538 incl_files
[incl_index
++] = str
;
544 /* start/end of translation unit */
548 /* do not add path */
550 if (len
> 0 && str
[len
- 1] != '/')
551 incl_files
[incl_index
++] = str
;
556 last_pc
= (addr_t
)-1;
558 /* alternative file name (from #line or #include directives) */
561 incl_files
[incl_index
-1] = str
;
569 /* we try symtab symbols (no line number info) */
570 p
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
572 pstrcpy(func_name
, sizeof func_name
, p
);
580 str
= incl_files
[--i
];
581 if (skip
[0] && strstr(str
, skip
))
583 rt_printf("%s:%d: ", str
, last_line_num
);
585 rt_printf("%08llx : ", (long long)wanted_pc
);
586 rt_printf("%s %s", msg
, func_name
[0] ? func_name
: "???");
589 rt_printf(" (included from ");
591 rt_printf("%s", incl_files
[i
]);
602 /* ------------------------------------------------------------- */
603 /* rt_printline - dwarf version */
605 #define MAX_128 ((8 * sizeof (long long) + 6) / 7)
607 #define DIR_TABLE_SIZE (64)
608 #define FILE_TABLE_SIZE (512)
610 #define dwarf_read_1(ln,end) \
611 ((ln) < (end) ? *(ln)++ : 0)
612 #define dwarf_read_2(ln,end) \
613 ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
614 #define dwarf_read_4(ln,end) \
615 ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
616 #define dwarf_read_8(ln,end) \
617 ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
618 #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \
619 switch (entry_format[j].form) { \
620 case DW_FORM_data1: (ln) += 1; break; \
621 case DW_FORM_data2: (ln) += 2; break; \
622 case DW_FORM_data4: (ln) += 3; break; \
623 case DW_FORM_data8: (ln) += 8; break; \
624 case DW_FORM_data16: (ln) += 16; break; \
625 case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \
626 default: goto next_line; \
629 static unsigned long long
630 dwarf_read_uleb128(unsigned char **ln
, unsigned char *end
)
632 unsigned char *cp
= *ln
;
633 unsigned long long retval
= 0;
636 for (i
= 0; i
< MAX_128
; i
++) {
637 unsigned long long byte
= dwarf_read_1(cp
, end
);
639 retval
|= (byte
& 0x7f) << (i
* 7);
640 if ((byte
& 0x80) == 0)
648 dwarf_read_sleb128(unsigned char **ln
, unsigned char *end
)
650 unsigned char *cp
= *ln
;
651 long long retval
= 0;
654 for (i
= 0; i
< MAX_128
; i
++) {
655 unsigned long long byte
= dwarf_read_1(cp
, end
);
657 retval
|= (byte
& 0x7f) << (i
* 7);
658 if ((byte
& 0x80) == 0) {
659 if ((byte
& 0x40) && (i
+ 1) * 7 < 64)
660 retval
|= -1LL << ((i
+ 1) * 7);
668 static addr_t
rt_printline_dwarf (rt_context
*rc
, addr_t wanted_pc
,
669 const char *msg
, const char *skip
)
674 unsigned char *opcode_length
;
675 unsigned long long size
;
677 unsigned char version
;
678 unsigned int min_insn_length
;
679 unsigned int max_ops_per_insn
;
681 unsigned int line_range
;
682 unsigned int opcode_base
;
683 unsigned int opindex
;
688 unsigned long long value
;
693 unsigned int dir_size
;
695 char *dirs
[DIR_TABLE_SIZE
];
697 unsigned int filename_size
;
698 struct dwarf_filename_struct
{
699 unsigned int dir_entry
;
701 } filename_table
[FILE_TABLE_SIZE
];
711 while (ln
< rc
->dwarf_line_end
) {
721 size
= dwarf_read_4(ln
, rc
->dwarf_line_end
);
722 if (size
== 0xffffffffu
) // dwarf 64
723 length
= 8, size
= dwarf_read_8(ln
, rc
->dwarf_line_end
);
725 if (end
< ln
|| end
> rc
->dwarf_line_end
)
727 version
= dwarf_read_2(ln
, end
);
729 ln
+= length
+ 2; // address size, segment selector, prologue Length
731 ln
+= length
; // prologue Length
732 min_insn_length
= dwarf_read_1(ln
, end
);
734 max_ops_per_insn
= dwarf_read_1(ln
, end
);
736 max_ops_per_insn
= 1;
737 ln
++; // Initial value of 'is_stmt'
738 line_base
= dwarf_read_1(ln
, end
);
739 line_base
|= line_base
>= 0x80 ? ~0xff : 0;
740 line_range
= dwarf_read_1(ln
, end
);
741 opcode_base
= dwarf_read_1(ln
, end
);
743 ln
+= opcode_base
- 1;
746 col
= dwarf_read_1(ln
, end
);
747 for (i
= 0; i
< col
; i
++) {
748 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
749 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
751 dir_size
= dwarf_read_uleb128(&ln
, end
);
752 for (i
= 0; i
< dir_size
; i
++) {
753 for (j
= 0; j
< col
; j
++) {
754 if (entry_format
[j
].type
== DW_LNCT_path
) {
755 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
758 value
= length
== 4 ? dwarf_read_4(ln
, end
)
759 : dwarf_read_8(ln
, end
);
760 if (i
< DIR_TABLE_SIZE
)
761 dirs
[i
] = (char *)rc
->dwarf_line_str
+ value
;
763 length
== 4 ? dwarf_read_4(ln
, end
)
764 : dwarf_read_8(ln
, end
);
768 dwarf_ignore_type(ln
, end
);
771 col
= dwarf_read_1(ln
, end
);
772 for (i
= 0; i
< col
; i
++) {
773 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
774 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
776 filename_size
= dwarf_read_uleb128(&ln
, end
);
777 for (i
= 0; i
< filename_size
; i
++)
778 for (j
= 0; j
< col
; j
++) {
779 if (entry_format
[j
].type
== DW_LNCT_path
) {
780 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
782 value
= length
== 4 ? dwarf_read_4(ln
, end
)
783 : dwarf_read_8(ln
, end
);
784 if (i
< FILE_TABLE_SIZE
)
785 filename_table
[i
].name
=
786 (char *)rc
->dwarf_line_str
+ value
;
788 else if (entry_format
[j
].type
== DW_LNCT_directory_index
) {
789 switch (entry_format
[j
].form
) {
790 case DW_FORM_data1
: value
= dwarf_read_1(ln
, end
); break;
791 case DW_FORM_data2
: value
= dwarf_read_2(ln
, end
); break;
792 case DW_FORM_data4
: value
= dwarf_read_4(ln
, end
); break;
793 case DW_FORM_udata
: value
= dwarf_read_uleb128(&ln
, end
); break;
794 default: goto next_line
;
796 if (i
< FILE_TABLE_SIZE
)
797 filename_table
[i
].dir_entry
= value
;
800 dwarf_ignore_type(ln
, end
);
804 while ((dwarf_read_1(ln
, end
))) {
806 if (++dir_size
< DIR_TABLE_SIZE
)
807 dirs
[dir_size
- 1] = (char *)ln
- 1;
809 while (dwarf_read_1(ln
, end
)) {}
811 while ((dwarf_read_1(ln
, end
))) {
812 if (++filename_size
< FILE_TABLE_SIZE
) {
813 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
814 while (dwarf_read_1(ln
, end
)) {}
815 filename_table
[filename_size
- 1].dir_entry
=
816 dwarf_read_uleb128(&ln
, end
);
819 while (dwarf_read_1(ln
, end
)) {}
820 dwarf_read_uleb128(&ln
, end
);
822 dwarf_read_uleb128(&ln
, end
); // time
823 dwarf_read_uleb128(&ln
, end
); // size
826 if (filename_size
>= 1)
827 filename
= filename_table
[0].name
;
830 i
= dwarf_read_1(ln
, end
);
831 if (i
>= opcode_base
) {
832 if (max_ops_per_insn
== 1)
833 pc
+= ((i
- opcode_base
) / line_range
) * min_insn_length
;
835 pc
+= (opindex
+ (i
- opcode_base
) / line_range
) /
836 max_ops_per_insn
* min_insn_length
;
837 opindex
= (opindex
+ (i
- opcode_base
) / line_range
) %
840 i
= (int)((i
- opcode_base
) % line_range
) + line_base
;
842 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
849 len
= dwarf_read_uleb128(&ln
, end
);
854 switch (dwarf_read_1(cp
, end
)) {
855 case DW_LNE_end_sequence
:
857 case DW_LNE_set_address
:
859 pc
= dwarf_read_4(cp
, end
);
861 pc
= dwarf_read_8(cp
, end
);
865 case DW_LNE_define_file
: /* deprecated */
866 if (++filename_size
< FILE_TABLE_SIZE
) {
867 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
868 while (dwarf_read_1(ln
, end
)) {}
869 filename_table
[filename_size
- 1].dir_entry
=
870 dwarf_read_uleb128(&ln
, end
);
873 while (dwarf_read_1(ln
, end
)) {}
874 dwarf_read_uleb128(&ln
, end
);
876 dwarf_read_uleb128(&ln
, end
); // time
877 dwarf_read_uleb128(&ln
, end
); // size
879 case DW_LNE_hi_user
- 1:
880 function
= (char *)cp
;
887 case DW_LNS_advance_pc
:
888 if (max_ops_per_insn
== 1)
889 pc
+= dwarf_read_uleb128(&ln
, end
) * min_insn_length
;
891 unsigned long long off
= dwarf_read_uleb128(&ln
, end
);
893 pc
+= (opindex
+ off
) / max_ops_per_insn
*
895 opindex
= (opindex
+ off
) % max_ops_per_insn
;
899 case DW_LNS_advance_line
:
900 line
+= dwarf_read_sleb128(&ln
, end
);
902 case DW_LNS_set_file
:
903 i
= dwarf_read_uleb128(&ln
, end
);
904 if (i
< FILE_TABLE_SIZE
&& i
< filename_size
)
905 filename
= filename_table
[i
].name
;
907 case DW_LNS_const_add_pc
:
908 if (max_ops_per_insn
== 1)
909 pc
+= ((255 - opcode_base
) / line_range
) * min_insn_length
;
911 unsigned int off
= (255 - opcode_base
) / line_range
;
913 pc
+= ((opindex
+ off
) / max_ops_per_insn
) *
915 opindex
= (opindex
+ off
) % max_ops_per_insn
;
919 case DW_LNS_fixed_advance_pc
:
920 i
= dwarf_read_2(ln
, end
);
926 for (j
= 0; j
< opcode_length
[i
- 1]; j
++)
927 dwarf_read_uleb128 (&ln
, end
);
938 /* we try symtab symbols (no line number info) */
939 function
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
946 if (skip
[0] && strstr(filename
, skip
))
948 rt_printf("%s:%d: ", filename
, line
);
951 rt_printf("0x%08llx : ", (long long)wanted_pc
);
952 rt_printf("%s %s", msg
, function
? function
: "???");
953 return (addr_t
)func_addr
;
955 /* ------------------------------------------------------------- */
957 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
);
959 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
)
961 rt_context
*rc
= &g_rtctxt
;
964 int i
, level
, ret
, n
;
965 const char *a
, *b
, *msg
;
968 /* we're called from tcc_backtrace. */
973 /* we're called from signal/exception handler */
974 msg
= "RUNTIME ERROR: ";
978 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
979 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
980 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
984 n
= rc
->num_callers
? rc
->num_callers
: 6;
985 for (i
= level
= 0; level
< n
; i
++) {
986 ret
= rt_get_caller_pc(&pc
, rc
, i
);
990 pc
= rt_printline_dwarf(rc
, pc
, level
? "by" : "at", skip
);
992 pc
= rt_printline(rc
, pc
, level
? "by" : "at", skip
);
993 if (pc
== (addr_t
)-1)
1000 } else if (ret
== -1)
1003 if (ret
== -1 || (pc
== (addr_t
)rc
->top_func
&& pc
))
1008 rc
->ip
= rc
->fp
= 0;
1012 /* emit a run time error at position 'pc' */
1013 static int rt_error(const char *fmt
, ...)
1018 ret
= _rt_error(0, 0, fmt
, ap
);
1023 static void rt_exit(int code
)
1025 rt_context
*rc
= &g_rtctxt
;
1027 longjmp(rc
->jmp_buf, code
? code
: 256);
1031 #define NR_AT_EXIT 32
1033 static int nr_atexit
= 0;
1034 static void (*at_exitfunc
[NR_AT_EXIT
])(void);
1036 static void init_atexit(void)
1041 static void run_atexit(void)
1044 at_exitfunc
[--nr_atexit
]();
1047 static int rt_atexit(void (*function
)(void))
1049 if (nr_atexit
< NR_AT_EXIT
)
1050 at_exitfunc
[nr_atexit
++] = function
;
1054 /* ------------------------------------------------------------- */
1057 # include <signal.h>
1058 # ifndef __OpenBSD__
1059 # include <sys/ucontext.h>
1062 # define ucontext_t CONTEXT
1065 /* translate from ucontext_t* to internal rt_context * */
1066 static void rt_getcontext(ucontext_t
*uc
, rt_context
*rc
)
1072 #elif defined _WIN32
1076 #elif defined __i386__
1077 # if defined(__APPLE__)
1078 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
1079 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
1080 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1081 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
1082 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
1083 # elif defined(__dietlibc__)
1084 rc
->ip
= uc
->uc_mcontext
.eip
;
1085 rc
->fp
= uc
->uc_mcontext
.ebp
;
1086 # elif defined(__NetBSD__)
1087 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
1088 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
1089 # elif defined(__OpenBSD__)
1090 rc
->ip
= uc
->sc_eip
;
1091 rc
->fp
= uc
->sc_ebp
;
1092 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
1093 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
1094 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
1096 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1097 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
1099 #elif defined(__x86_64__)
1100 # if defined(__APPLE__)
1101 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
1102 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
1103 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1104 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
1105 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
1106 # elif defined(__NetBSD__)
1107 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
1108 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
1109 # elif defined(__OpenBSD__)
1110 rc
->ip
= uc
->sc_rip
;
1111 rc
->fp
= uc
->sc_rbp
;
1113 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1114 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
1116 #elif defined(__arm__) && defined(__NetBSD__)
1117 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1118 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1119 #elif defined(__arm__) && defined(__OpenBSD__)
1121 rc
->fp
= uc
->sc_r11
;
1122 #elif defined(__arm__) && defined(__FreeBSD__)
1123 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1124 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1125 #elif defined(__arm__)
1126 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
1127 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
1128 #elif defined(__aarch64__) && defined(__APPLE__)
1130 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
1131 rc
->ip
= uc
->uc_mcontext
->__ss
.__pc
;
1132 rc
->fp
= uc
->uc_mcontext
->__ss
.__fp
;
1133 #elif defined(__aarch64__) && defined(__FreeBSD__)
1134 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
1135 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
1136 #elif defined(__aarch64__) && defined(__NetBSD__)
1137 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1138 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1139 #elif defined(__aarch64__) && defined(__OpenBSD__)
1140 rc
->ip
= uc
->sc_elr
;
1141 rc
->fp
= uc
->sc_x
[29];
1142 #elif defined(__aarch64__)
1143 rc
->ip
= uc
->uc_mcontext
.pc
;
1144 rc
->fp
= uc
->uc_mcontext
.regs
[29];
1145 #elif defined(__riscv) && defined(__OpenBSD__)
1146 rc
->ip
= uc
->sc_sepc
;
1147 rc
->fp
= uc
->sc_s
[0];
1148 #elif defined(__riscv)
1149 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
1150 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
1154 /* ------------------------------------------------------------- */
1156 /* signal handler for fatal errors */
1157 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
1159 rt_context
*rc
= &g_rtctxt
;
1160 rt_getcontext(puc
, rc
);
1164 switch(siginf
->si_code
) {
1167 rt_error("division by zero");
1170 rt_error("floating point exception");
1176 rt_error("invalid memory access");
1179 rt_error("illegal instruction");
1182 rt_error("abort() called");
1185 rt_error("caught signal %d", signum
);
1192 # define SA_SIGINFO 0x00000004u
1195 /* Generate a stack backtrace when a CPU exception occurs. */
1196 static void set_exception_handler(void)
1198 struct sigaction sigact
;
1199 /* install TCC signal handlers to print debug info on fatal
1201 sigemptyset (&sigact
.sa_mask
);
1202 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
1203 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
1204 sigact
.sa_flags
|= SA_ONSTACK
;
1206 sigact
.sa_sigaction
= sig_error
;
1207 sigemptyset(&sigact
.sa_mask
);
1208 sigaction(SIGFPE
, &sigact
, NULL
);
1209 sigaction(SIGILL
, &sigact
, NULL
);
1210 sigaction(SIGSEGV
, &sigact
, NULL
);
1211 sigaction(SIGBUS
, &sigact
, NULL
);
1212 sigaction(SIGABRT
, &sigact
, NULL
);
1214 /* This allows stack overflow to be reported instead of a SEGV */
1217 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
1220 ss
.ss_size
= SIGSTKSZ
;
1222 sigaltstack(&ss
, NULL
);
1229 /* signal handler for fatal errors */
1230 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
1232 rt_context
*rc
= &g_rtctxt
;
1234 rt_getcontext(ex_info
->ContextRecord
, rc
);
1236 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
1237 case EXCEPTION_ACCESS_VIOLATION
:
1238 rt_error("invalid memory access");
1240 case EXCEPTION_STACK_OVERFLOW
:
1241 rt_error("stack overflow");
1243 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
1244 rt_error("division by zero");
1246 case EXCEPTION_BREAKPOINT
:
1247 case EXCEPTION_SINGLE_STEP
:
1248 rc
->ip
= *(addr_t
*)rc
->sp
;
1249 rt_error("breakpoint/single-step exception:");
1250 return EXCEPTION_CONTINUE_SEARCH
;
1252 rt_error("caught exception %08x", code
);
1257 return EXCEPTION_EXECUTE_HANDLER
;
1260 /* Generate a stack backtrace when a CPU exception occurs. */
1261 static void set_exception_handler(void)
1263 SetUnhandledExceptionFilter(cpu_exception_handler
);
1268 /* ------------------------------------------------------------- */
1269 /* return the PC at frame level 'level'. Return negative if not found */
1270 #if defined(__i386__) || defined(__x86_64__)
1271 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1280 /* XXX: check address validity with program info */
1283 fp
= ((addr_t
*)fp
)[0];
1286 ip
= ((addr_t
*)fp
)[1];
1294 #elif defined(__arm__)
1295 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1297 /* XXX: only supports linux/bsd */
1298 #if !defined(__linux__) && \
1299 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
1307 fp
= ((addr_t
*)fp
)[0];
1308 *paddr
= ((addr_t
*)fp
)[2];
1314 #elif defined(__aarch64__)
1315 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1320 addr_t
*fp
= (addr_t
*)rc
->fp
;
1322 fp
= (addr_t
*)fp
[0];
1328 #elif defined(__riscv)
1329 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1334 addr_t
*fp
= (addr_t
*)rc
->fp
;
1335 while (--level
&& fp
>= (addr_t
*)0x1000)
1336 fp
= (addr_t
*)fp
[-2];
1337 if (fp
< (addr_t
*)0x1000)
1345 #warning add arch specific rt_get_caller_pc()
1346 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1352 #endif /* CONFIG_TCC_BACKTRACE */
1353 /* ------------------------------------------------------------- */
1354 #ifdef CONFIG_TCC_STATIC
1356 /* dummy function for profiling */
1357 ST_FUNC
void *dlopen(const char *filename
, int flag
)
1362 ST_FUNC
void dlclose(void *p
)
1366 ST_FUNC
const char *dlerror(void)
1371 typedef struct TCCSyms
{
1377 /* add the symbol you want here if no dynamic linking is done */
1378 static TCCSyms tcc_syms
[] = {
1379 #if !defined(CONFIG_TCCBOOT)
1380 #define TCCSYM(a) { #a, &a, },
1390 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
1394 while (p
->str
!= NULL
) {
1395 if (!strcmp(p
->str
, symbol
))
1402 #endif /* CONFIG_TCC_STATIC */
1403 #endif /* TCC_IS_NATIVE */
1404 /* ------------------------------------------------------------- */