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 typedef struct rt_context
28 #ifdef CONFIG_TCC_BACKTRACE
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
;
52 # define NR_AT_EXIT 32
54 void *exitfunc
[NR_AT_EXIT
];
55 void *exitarg
[NR_AT_EXIT
];
58 static rt_context g_rtctxt
;
59 static void rt_exit(int code
)
61 rt_context
*rc
= &g_rtctxt
;
63 longjmp(rc
->jb
, code
? code
: 256);
67 #ifdef CONFIG_TCC_BACKTRACE
68 static void set_exception_handler(void);
69 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
);
70 #endif /* CONFIG_TCC_BACKTRACE */
72 /* defined when included from lib/bt-exe.c */
73 #ifndef CONFIG_TCC_BACKTRACE_ONLY
76 # include <sys/mman.h>
79 static int set_pages_executable(TCCState
*s1
, int mode
, void *ptr
, unsigned long length
);
80 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
);
83 static void *win64_add_function_table(TCCState
*s1
);
84 static void win64_del_function_table(void *);
87 /* ------------------------------------------------------------- */
88 /* Do all relocations (needed before using tcc_get_symbol())
89 Returns -1 on error. */
91 LIBTCCAPI
int tcc_relocate(TCCState
*s1
, void *ptr
)
96 if (TCC_RELOCATE_AUTO
!= ptr
)
97 return tcc_relocate_ex(s1
, ptr
, 0);
99 size
= tcc_relocate_ex(s1
, NULL
, 0);
105 /* Using mmap instead of malloc */
107 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
108 int fd
= mkstemp(tmpfname
);
112 size
= (size
+ (PAGESIZE
-1)) & ~(PAGESIZE
-1);
113 ptr
= mmap(NULL
, size
* 2, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
114 /* mmap RX memory at a fixed distance */
115 prx
= mmap((char*)ptr
+ size
, size
, PROT_READ
|PROT_EXEC
, MAP_SHARED
|MAP_FIXED
, fd
, 0);
117 if (ptr
== MAP_FAILED
|| prx
== MAP_FAILED
)
118 return tcc_error_noabort("tccrun: could not map memory");
119 ptr_diff
= (char*)prx
- (char*)ptr
;
120 //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
123 ptr
= tcc_malloc(size
);
125 if (tcc_relocate_ex(s1
, ptr
, ptr_diff
))
127 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, (void*)(addr_t
)size
);
128 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, ptr
);
132 ST_FUNC
void tcc_run_free(TCCState
*s1
)
136 for (i
= 0; i
< s1
->nb_runtime_mem
; i
+= 2) {
137 unsigned size
= (unsigned)(addr_t
)s1
->runtime_mem
[i
];
138 void *ptr
= s1
->runtime_mem
[i
+1];
140 munmap(ptr
, size
* 2);
142 /* unprotect memory to make it usable for malloc again */
143 set_pages_executable(s1
, 2, ptr
, size
);
145 win64_del_function_table(*(void**)ptr
);
150 tcc_free(s1
->runtime_mem
);
153 static void run_cdtors(TCCState
*s1
, const char *start
, const char *end
,
154 int argc
, char **argv
, char **envp
)
156 void **a
= (void **)get_sym_addr(s1
, start
, 0, 0);
157 void **b
= (void **)get_sym_addr(s1
, end
, 0, 0);
159 ((void(*)(int, char **, char **))*a
++)(argc
, argv
, envp
);
162 static void run_on_exit(int ret
)
164 rt_context
*rc
= &g_rtctxt
;
167 --n
, ((void(*)(int,void*))rc
->exitfunc
[n
])(ret
, rc
->exitarg
[n
]);
170 static int rt_on_exit(void *function
, void *arg
)
172 rt_context
*rc
= &g_rtctxt
;
173 if (rc
->nr_exit
< NR_AT_EXIT
) {
174 rc
->exitfunc
[rc
->nr_exit
] = function
;
175 rc
->exitarg
[rc
->nr_exit
++] = arg
;
181 static int rt_atexit(void *function
)
183 return rt_on_exit(function
, NULL
);
186 /* launch the compiled program with the given arguments */
187 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
189 int (*prog_main
)(int, char **, char **), ret
;
190 rt_context
*rc
= &g_rtctxt
;
192 #if defined(__APPLE__) || defined(__FreeBSD__)
194 #elif defined(__OpenBSD__) || defined(__NetBSD__)
195 extern char **environ
;
196 char **envp
= environ
;
198 char **envp
= environ
;
201 s1
->runtime_main
= s1
->nostdlib
? "_start" : "main";
202 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, s1
->runtime_main
, 0, 1))
205 tcc_add_symbol(s1
, "exit", rt_exit
);
206 tcc_add_symbol(s1
, "atexit", rt_atexit
);
207 tcc_add_symbol(s1
, "on_exit", rt_on_exit
);
208 if (tcc_relocate(s1
, TCC_RELOCATE_AUTO
) < 0)
211 prog_main
= (void*)get_sym_addr(s1
, s1
->runtime_main
, 1, 1);
212 if ((addr_t
)-1 == (addr_t
)prog_main
)
215 memset(rc
, 0, sizeof *rc
);
218 #ifdef CONFIG_TCC_BACKTRACE
222 rc
->dwarf_line
= dwarf_line_section
->data
;
223 rc
->dwarf_line_end
= dwarf_line_section
->data
+ dwarf_line_section
->data_offset
;
224 if (dwarf_line_str_section
)
225 rc
->dwarf_line_str
= dwarf_line_str_section
->data
;
229 rc
->stab_sym
= (Stab_Sym
*)stab_section
->data
;
230 rc
->stab_sym_end
= (Stab_Sym
*)(stab_section
->data
+ stab_section
->data_offset
);
231 rc
->stab_str
= (char *)stab_section
->link
->data
;
233 rc
->dwarf
= s1
->dwarf
;
234 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
235 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
236 rc
->elf_str
= (char *)symtab_section
->link
->data
;
238 rc
->prog_base
= text_section
->sh_addr
& 0xffffffff00000000ULL
;
239 #if defined TCC_TARGET_MACHO
241 rc
->prog_base
= (addr_t
) -1;
245 rc
->top_func
= tcc_get_symbol(s1
, "main");
246 rc
->num_callers
= s1
->rt_num_callers
;
247 if ((p
= tcc_get_symbol(s1
, "__rt_error")))
248 *(void**)p
= _rt_error
;
249 #ifdef CONFIG_TCC_BCHECK
250 if (s1
->do_bounds_check
) {
251 rc
->bounds_start
= (void*)bounds_section
->sh_addr
;
252 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
253 ((void(*)(void*,int))p
)(rc
->bounds_start
, 1);
256 set_exception_handler();
260 errno
= 0; /* clean errno value */
264 /* These aren't C symbols, so don't need leading underscore handling. */
265 run_cdtors(s1
, "__init_array_start", "__init_array_end", argc
, argv
, envp
);
266 ret
= setjmp(rc
->jb
);
268 ret
= prog_main(argc
, argv
, envp
);
271 run_cdtors(s1
, "__fini_array_start", "__fini_array_end", 0, NULL
, NULL
);
273 if (s1
->dflag
& 16 && ret
) /* tcc -dt -run ... */
274 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
278 #define DEBUG_RUNMEN 0
280 /* enable rx/ro/rw permissions */
281 #define CONFIG_RUNMEM_RO 1
284 # define PAGE_ALIGN PAGESIZE
285 #elif defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
286 /* To avoid that x86 processors would reload cached instructions
287 each time when data is written in the near, we need to make
288 sure that code and data do not share the same 64 byte unit */
289 # define PAGE_ALIGN 64
291 # define PAGE_ALIGN 1
294 /* relocate code. Return -1 on error, required size if ptr is NULL,
295 otherwise copy code into buffer passed by the caller */
296 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
)
299 unsigned offset
, length
, align
, max_align
, i
, k
, f
;
306 pe_output_file(s1
, NULL
);
309 resolve_common_syms(s1
);
310 build_got_entries(s1
, 0);
316 offset
= max_align
= 0, mem
= (addr_t
)ptr
;
318 offset
+= sizeof (void*); /* space for function_table pointer */
322 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
324 for(i
= 1; i
< s1
->nb_sections
; i
++) {
325 static const char shf
[] = {
326 SHF_ALLOC
|SHF_EXECINSTR
, SHF_ALLOC
, SHF_ALLOC
|SHF_WRITE
329 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
331 length
= s
->data_offset
;
335 n
= (s
->sh_addr
- addr
) + length
;
336 ptr
= (void*)s
->sh_addr
;
338 ptr
= (void*)(s
->sh_addr
- ptr_diff
);
339 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
340 memset(ptr
, 0, length
);
342 memcpy(ptr
, s
->data
, length
);
344 if (s
== s1
->uw_pdata
)
345 *(void**)mem
= win64_add_function_table(s1
);
350 s
->data_allocated
= 0;
355 align
= s
->sh_addralign
- 1;
356 if (++n
== 1 && align
< (PAGE_ALIGN
- 1))
357 align
= (PAGE_ALIGN
- 1);
358 if (max_align
< align
)
360 addr
= k
? mem
: mem
+ ptr_diff
;
361 offset
+= -(addr
+ offset
) & align
;
362 s
->sh_addr
= mem
? addr
+ offset
: 0;
366 printf("%d: %-16s %p len %04x align %04x\n",
367 k
, s
->name
, (void*)s
->sh_addr
, length
, align
+ 1);
370 if (copy
) { /* set permissions */
371 if (k
== 0 && ptr_diff
)
372 continue; /* not with HAVE_SELINUX */
374 #if !CONFIG_RUNMEM_RO
377 f
= 3; /* change only SHF_EXECINSTR to rwx */
380 printf("protect %d %p %04x\n", f
, (void*)addr
, n
);
383 if (set_pages_executable(s1
, f
, (void*)addr
, n
))
392 /* relocate symbols */
393 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
397 return offset
+ max_align
;
400 s1
->pe_imagebase
= mem
;
403 /* relocate sections */
404 #ifndef TCC_TARGET_PE
407 relocate_sections(s1
);
412 /* ------------------------------------------------------------- */
413 /* allow to run code in memory */
415 static int set_pages_executable(TCCState
*s1
, int mode
, void *ptr
, unsigned long length
)
418 static const unsigned char protect
[] = {
422 PAGE_EXECUTE_READWRITE
425 if (!VirtualProtect(ptr
, length
, protect
[mode
], &old
))
429 static const unsigned char protect
[] = {
430 PROT_READ
| PROT_EXEC
,
432 PROT_READ
| PROT_WRITE
,
433 PROT_READ
| PROT_WRITE
| PROT_EXEC
436 start
= (addr_t
)ptr
& ~(PAGESIZE
- 1);
437 end
= (addr_t
)ptr
+ length
;
438 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
439 if (mprotect((void *)start
, end
- start
, protect
[mode
]))
440 return tcc_error_noabort("mprotect failed: did you mean to configure --with-selinux?");
441 /* XXX: BSD sometimes dump core with bad system call */
442 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
443 if (mode
== 0 || mode
== 3) {
444 void __clear_cache(void *beginning
, void *end
);
445 __clear_cache(ptr
, (char *)ptr
+ length
);
453 static void *win64_add_function_table(TCCState
*s1
)
457 p
= (void*)s1
->uw_pdata
->sh_addr
;
459 (RUNTIME_FUNCTION
*)p
,
460 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
468 static void win64_del_function_table(void *p
)
471 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
475 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
476 /* ------------------------------------------------------------- */
477 #ifdef CONFIG_TCC_BACKTRACE
479 static int rt_vprintf(const char *fmt
, va_list ap
)
481 int ret
= vfprintf(stderr
, fmt
, ap
);
486 static int rt_printf(const char *fmt
, ...)
491 r
= rt_vprintf(fmt
, ap
);
496 static char *rt_elfsym(rt_context
*rc
, addr_t wanted_pc
, addr_t
*func_addr
)
499 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
500 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
501 if ((type
== STT_FUNC
|| type
== STT_GNU_IFUNC
)
502 && wanted_pc
>= esym
->st_value
503 && wanted_pc
< esym
->st_value
+ esym
->st_size
) {
504 *func_addr
= esym
->st_value
;
505 return rc
->elf_str
+ esym
->st_name
;
512 /* print the position in the source file of PC value 'pc' by reading
513 the stabs debug information */
514 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
,
515 const char *msg
, const char *skip
)
518 addr_t func_addr
, last_pc
, pc
;
519 const char *incl_files
[INCLUDE_STACK_SIZE
];
520 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
528 last_pc
= (addr_t
)-1;
532 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
533 str
= rc
->stab_str
+ sym
->n_strx
;
536 switch(sym
->n_type
) {
544 if (sym
->n_strx
== 0) /* end of function */
548 /* Stab_Sym.n_value is only 32bits */
555 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
560 switch(sym
->n_type
) {
561 /* function start or end */
563 if (sym
->n_strx
== 0)
565 p
= strchr(str
, ':');
566 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
567 len
= sizeof func_name
;
568 pstrcpy(func_name
, len
, str
);
571 /* line number info */
574 last_line_num
= sym
->n_desc
;
575 last_incl_index
= incl_index
;
579 if (incl_index
< INCLUDE_STACK_SIZE
)
580 incl_files
[incl_index
++] = str
;
586 /* start/end of translation unit */
590 /* do not add path */
592 if (len
> 0 && str
[len
- 1] != '/')
593 incl_files
[incl_index
++] = str
;
598 last_pc
= (addr_t
)-1;
600 /* alternative file name (from #line or #include directives) */
603 incl_files
[incl_index
-1] = str
;
611 /* we try symtab symbols (no line number info) */
612 p
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
614 pstrcpy(func_name
, sizeof func_name
, p
);
622 str
= incl_files
[--i
];
623 if (skip
[0] && strstr(str
, skip
))
625 rt_printf("%s:%d: ", str
, last_line_num
);
627 rt_printf("%08llx : ", (long long)wanted_pc
);
628 rt_printf("%s %s", msg
, func_name
[0] ? func_name
: "???");
631 rt_printf(" (included from ");
633 rt_printf("%s", incl_files
[i
]);
644 /* ------------------------------------------------------------- */
645 /* rt_printline - dwarf version */
647 #define MAX_128 ((8 * sizeof (long long) + 6) / 7)
649 #define DIR_TABLE_SIZE (64)
650 #define FILE_TABLE_SIZE (512)
652 #define dwarf_read_1(ln,end) \
653 ((ln) < (end) ? *(ln)++ : 0)
654 #define dwarf_read_2(ln,end) \
655 ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
656 #define dwarf_read_4(ln,end) \
657 ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
658 #define dwarf_read_8(ln,end) \
659 ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
660 #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \
661 switch (entry_format[j].form) { \
662 case DW_FORM_data1: (ln) += 1; break; \
663 case DW_FORM_data2: (ln) += 2; break; \
664 case DW_FORM_data4: (ln) += 3; break; \
665 case DW_FORM_data8: (ln) += 8; break; \
666 case DW_FORM_data16: (ln) += 16; break; \
667 case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \
668 default: goto next_line; \
671 static unsigned long long
672 dwarf_read_uleb128(unsigned char **ln
, unsigned char *end
)
674 unsigned char *cp
= *ln
;
675 unsigned long long retval
= 0;
678 for (i
= 0; i
< MAX_128
; i
++) {
679 unsigned long long byte
= dwarf_read_1(cp
, end
);
681 retval
|= (byte
& 0x7f) << (i
* 7);
682 if ((byte
& 0x80) == 0)
690 dwarf_read_sleb128(unsigned char **ln
, unsigned char *end
)
692 unsigned char *cp
= *ln
;
693 long long retval
= 0;
696 for (i
= 0; i
< MAX_128
; i
++) {
697 unsigned long long byte
= dwarf_read_1(cp
, end
);
699 retval
|= (byte
& 0x7f) << (i
* 7);
700 if ((byte
& 0x80) == 0) {
701 if ((byte
& 0x40) && (i
+ 1) * 7 < 64)
702 retval
|= -1LL << ((i
+ 1) * 7);
710 static addr_t
rt_printline_dwarf (rt_context
*rc
, addr_t wanted_pc
,
711 const char *msg
, const char *skip
)
716 unsigned char *opcode_length
;
717 unsigned long long size
;
719 unsigned char version
;
720 unsigned int min_insn_length
;
721 unsigned int max_ops_per_insn
;
723 unsigned int line_range
;
724 unsigned int opcode_base
;
725 unsigned int opindex
;
730 unsigned long long value
;
735 unsigned int dir_size
;
737 char *dirs
[DIR_TABLE_SIZE
];
739 unsigned int filename_size
;
740 struct dwarf_filename_struct
{
741 unsigned int dir_entry
;
743 } filename_table
[FILE_TABLE_SIZE
];
753 while (ln
< rc
->dwarf_line_end
) {
763 size
= dwarf_read_4(ln
, rc
->dwarf_line_end
);
764 if (size
== 0xffffffffu
) // dwarf 64
765 length
= 8, size
= dwarf_read_8(ln
, rc
->dwarf_line_end
);
767 if (end
< ln
|| end
> rc
->dwarf_line_end
)
769 version
= dwarf_read_2(ln
, end
);
771 ln
+= length
+ 2; // address size, segment selector, prologue Length
773 ln
+= length
; // prologue Length
774 min_insn_length
= dwarf_read_1(ln
, end
);
776 max_ops_per_insn
= dwarf_read_1(ln
, end
);
778 max_ops_per_insn
= 1;
779 ln
++; // Initial value of 'is_stmt'
780 line_base
= dwarf_read_1(ln
, end
);
781 line_base
|= line_base
>= 0x80 ? ~0xff : 0;
782 line_range
= dwarf_read_1(ln
, end
);
783 opcode_base
= dwarf_read_1(ln
, end
);
785 ln
+= opcode_base
- 1;
788 col
= dwarf_read_1(ln
, end
);
789 for (i
= 0; i
< col
; i
++) {
790 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
791 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
793 dir_size
= dwarf_read_uleb128(&ln
, end
);
794 for (i
= 0; i
< dir_size
; i
++) {
795 for (j
= 0; j
< col
; j
++) {
796 if (entry_format
[j
].type
== DW_LNCT_path
) {
797 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
800 value
= length
== 4 ? dwarf_read_4(ln
, end
)
801 : dwarf_read_8(ln
, end
);
802 if (i
< DIR_TABLE_SIZE
)
803 dirs
[i
] = (char *)rc
->dwarf_line_str
+ value
;
805 length
== 4 ? dwarf_read_4(ln
, end
)
806 : dwarf_read_8(ln
, end
);
810 dwarf_ignore_type(ln
, end
);
813 col
= dwarf_read_1(ln
, end
);
814 for (i
= 0; i
< col
; i
++) {
815 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
816 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
818 filename_size
= dwarf_read_uleb128(&ln
, end
);
819 for (i
= 0; i
< filename_size
; i
++)
820 for (j
= 0; j
< col
; j
++) {
821 if (entry_format
[j
].type
== DW_LNCT_path
) {
822 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
824 value
= length
== 4 ? dwarf_read_4(ln
, end
)
825 : dwarf_read_8(ln
, end
);
826 if (i
< FILE_TABLE_SIZE
)
827 filename_table
[i
].name
=
828 (char *)rc
->dwarf_line_str
+ value
;
830 else if (entry_format
[j
].type
== DW_LNCT_directory_index
) {
831 switch (entry_format
[j
].form
) {
832 case DW_FORM_data1
: value
= dwarf_read_1(ln
, end
); break;
833 case DW_FORM_data2
: value
= dwarf_read_2(ln
, end
); break;
834 case DW_FORM_data4
: value
= dwarf_read_4(ln
, end
); break;
835 case DW_FORM_udata
: value
= dwarf_read_uleb128(&ln
, end
); break;
836 default: goto next_line
;
838 if (i
< FILE_TABLE_SIZE
)
839 filename_table
[i
].dir_entry
= value
;
842 dwarf_ignore_type(ln
, end
);
846 while ((dwarf_read_1(ln
, end
))) {
848 if (++dir_size
< DIR_TABLE_SIZE
)
849 dirs
[dir_size
- 1] = (char *)ln
- 1;
851 while (dwarf_read_1(ln
, end
)) {}
853 while ((dwarf_read_1(ln
, end
))) {
854 if (++filename_size
< FILE_TABLE_SIZE
) {
855 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
856 while (dwarf_read_1(ln
, end
)) {}
857 filename_table
[filename_size
- 1].dir_entry
=
858 dwarf_read_uleb128(&ln
, end
);
861 while (dwarf_read_1(ln
, end
)) {}
862 dwarf_read_uleb128(&ln
, end
);
864 dwarf_read_uleb128(&ln
, end
); // time
865 dwarf_read_uleb128(&ln
, end
); // size
868 if (filename_size
>= 1)
869 filename
= filename_table
[0].name
;
872 i
= dwarf_read_1(ln
, end
);
873 if (i
>= opcode_base
) {
874 if (max_ops_per_insn
== 1)
875 pc
+= ((i
- opcode_base
) / line_range
) * min_insn_length
;
877 pc
+= (opindex
+ (i
- opcode_base
) / line_range
) /
878 max_ops_per_insn
* min_insn_length
;
879 opindex
= (opindex
+ (i
- opcode_base
) / line_range
) %
882 i
= (int)((i
- opcode_base
) % line_range
) + line_base
;
884 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
891 len
= dwarf_read_uleb128(&ln
, end
);
896 switch (dwarf_read_1(cp
, end
)) {
897 case DW_LNE_end_sequence
:
899 case DW_LNE_set_address
:
901 pc
= dwarf_read_4(cp
, end
);
903 pc
= dwarf_read_8(cp
, end
);
905 #if defined TCC_TARGET_MACHO
906 if (rc
->prog_base
!= (addr_t
) -1)
911 case DW_LNE_define_file
: /* deprecated */
912 if (++filename_size
< FILE_TABLE_SIZE
) {
913 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
914 while (dwarf_read_1(ln
, end
)) {}
915 filename_table
[filename_size
- 1].dir_entry
=
916 dwarf_read_uleb128(&ln
, end
);
919 while (dwarf_read_1(ln
, end
)) {}
920 dwarf_read_uleb128(&ln
, end
);
922 dwarf_read_uleb128(&ln
, end
); // time
923 dwarf_read_uleb128(&ln
, end
); // size
925 case DW_LNE_hi_user
- 1:
926 function
= (char *)cp
;
933 case DW_LNS_advance_pc
:
934 if (max_ops_per_insn
== 1)
935 pc
+= dwarf_read_uleb128(&ln
, end
) * min_insn_length
;
937 unsigned long long off
= dwarf_read_uleb128(&ln
, end
);
939 pc
+= (opindex
+ off
) / max_ops_per_insn
*
941 opindex
= (opindex
+ off
) % max_ops_per_insn
;
945 case DW_LNS_advance_line
:
946 line
+= dwarf_read_sleb128(&ln
, end
);
948 case DW_LNS_set_file
:
949 i
= dwarf_read_uleb128(&ln
, end
);
950 i
-= i
> 0 && version
< 5;
951 if (i
< FILE_TABLE_SIZE
&& i
< filename_size
)
952 filename
= filename_table
[i
].name
;
954 case DW_LNS_const_add_pc
:
955 if (max_ops_per_insn
== 1)
956 pc
+= ((255 - opcode_base
) / line_range
) * min_insn_length
;
958 unsigned int off
= (255 - opcode_base
) / line_range
;
960 pc
+= ((opindex
+ off
) / max_ops_per_insn
) *
962 opindex
= (opindex
+ off
) % max_ops_per_insn
;
966 case DW_LNS_fixed_advance_pc
:
967 i
= dwarf_read_2(ln
, end
);
973 for (j
= 0; j
< opcode_length
[i
- 1]; j
++)
974 dwarf_read_uleb128 (&ln
, end
);
985 /* we try symtab symbols (no line number info) */
986 function
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
993 if (skip
[0] && strstr(filename
, skip
))
995 rt_printf("%s:%d: ", filename
, line
);
998 rt_printf("0x%08llx : ", (long long)wanted_pc
);
999 rt_printf("%s %s", msg
, function
? function
: "???");
1000 return (addr_t
)func_addr
;
1002 /* ------------------------------------------------------------- */
1004 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
);
1006 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
)
1008 rt_context
*rc
= &g_rtctxt
;
1011 int i
, level
, ret
, n
, one
;
1012 const char *a
, *b
, *msg
;
1015 /* we're called from tcc_backtrace. */
1016 rc
->fp
= (addr_t
)fp
;
1017 rc
->ip
= (addr_t
)ip
;
1020 /* we're called from signal/exception handler */
1021 msg
= "RUNTIME ERROR: ";
1025 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
1026 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
1027 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
1031 /* hack for bcheck.c:dprintf(): one level, no newline */
1032 if (fmt
[0] == '\001')
1035 n
= rc
->num_callers
? rc
->num_callers
: 6;
1036 for (i
= level
= 0; level
< n
; i
++) {
1037 ret
= rt_get_caller_pc(&pc
, rc
, i
);
1041 pc
= rt_printline_dwarf(rc
, pc
, level
? "by" : "at", skip
);
1043 pc
= rt_printline(rc
, pc
, level
? "by" : "at", skip
);
1044 if (pc
== (addr_t
)-1)
1050 rt_vprintf(fmt
, ap
);
1051 } else if (ret
== -1)
1056 if (ret
== -1 || (pc
== (addr_t
)rc
->top_func
&& pc
))
1061 rc
->ip
= rc
->fp
= 0;
1065 /* emit a run time error at position 'pc' */
1066 static int rt_error(const char *fmt
, ...)
1071 ret
= _rt_error(0, 0, fmt
, ap
);
1076 /* ------------------------------------------------------------- */
1079 # include <signal.h>
1080 # ifndef __OpenBSD__
1081 # include <sys/ucontext.h>
1084 # define ucontext_t CONTEXT
1087 /* translate from ucontext_t* to internal rt_context * */
1088 static void rt_getcontext(ucontext_t
*uc
, rt_context
*rc
)
1094 #elif defined _WIN32
1098 #elif defined __i386__
1099 # if defined(__APPLE__)
1100 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
1101 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
1102 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1103 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
1104 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
1105 # elif defined(__dietlibc__)
1106 rc
->ip
= uc
->uc_mcontext
.eip
;
1107 rc
->fp
= uc
->uc_mcontext
.ebp
;
1108 # elif defined(__NetBSD__)
1109 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
1110 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
1111 # elif defined(__OpenBSD__)
1112 rc
->ip
= uc
->sc_eip
;
1113 rc
->fp
= uc
->sc_ebp
;
1114 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
1115 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
1116 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
1118 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1119 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
1121 #elif defined(__x86_64__)
1122 # if defined(__APPLE__)
1123 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
1124 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
1125 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1126 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
1127 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
1128 # elif defined(__NetBSD__)
1129 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
1130 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
1131 # elif defined(__OpenBSD__)
1132 rc
->ip
= uc
->sc_rip
;
1133 rc
->fp
= uc
->sc_rbp
;
1135 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1136 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
1138 #elif defined(__arm__) && defined(__NetBSD__)
1139 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1140 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1141 #elif defined(__arm__) && defined(__OpenBSD__)
1143 rc
->fp
= uc
->sc_r11
;
1144 #elif defined(__arm__) && defined(__FreeBSD__)
1145 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1146 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1147 #elif defined(__arm__)
1148 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
1149 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
1150 #elif defined(__aarch64__) && defined(__APPLE__)
1152 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
1153 rc
->ip
= uc
->uc_mcontext
->__ss
.__pc
;
1154 rc
->fp
= uc
->uc_mcontext
->__ss
.__fp
;
1155 #elif defined(__aarch64__) && defined(__FreeBSD__)
1156 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
1157 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
1158 #elif defined(__aarch64__) && defined(__NetBSD__)
1159 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1160 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1161 #elif defined(__aarch64__) && defined(__OpenBSD__)
1162 rc
->ip
= uc
->sc_elr
;
1163 rc
->fp
= uc
->sc_x
[29];
1164 #elif defined(__aarch64__)
1165 rc
->ip
= uc
->uc_mcontext
.pc
;
1166 rc
->fp
= uc
->uc_mcontext
.regs
[29];
1167 #elif defined(__riscv) && defined(__OpenBSD__)
1168 rc
->ip
= uc
->sc_sepc
;
1169 rc
->fp
= uc
->sc_s
[0];
1170 #elif defined(__riscv)
1171 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
1172 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
1176 /* ------------------------------------------------------------- */
1178 /* signal handler for fatal errors */
1179 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
1181 rt_context
*rc
= &g_rtctxt
;
1182 rt_getcontext(puc
, rc
);
1186 switch(siginf
->si_code
) {
1189 rt_error("division by zero");
1192 rt_error("floating point exception");
1198 rt_error("invalid memory access");
1201 rt_error("illegal instruction");
1204 rt_error("abort() called");
1207 rt_error("caught signal %d", signum
);
1214 # define SA_SIGINFO 0x00000004u
1217 /* Generate a stack backtrace when a CPU exception occurs. */
1218 static void set_exception_handler(void)
1220 struct sigaction sigact
;
1221 /* install TCC signal handlers to print debug info on fatal
1223 sigemptyset (&sigact
.sa_mask
);
1224 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
1225 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
1226 sigact
.sa_flags
|= SA_ONSTACK
;
1228 sigact
.sa_sigaction
= sig_error
;
1229 sigemptyset(&sigact
.sa_mask
);
1230 sigaction(SIGFPE
, &sigact
, NULL
);
1231 sigaction(SIGILL
, &sigact
, NULL
);
1232 sigaction(SIGSEGV
, &sigact
, NULL
);
1233 sigaction(SIGBUS
, &sigact
, NULL
);
1234 sigaction(SIGABRT
, &sigact
, NULL
);
1236 /* This allows stack overflow to be reported instead of a SEGV */
1239 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
1242 ss
.ss_size
= SIGSTKSZ
;
1244 sigaltstack(&ss
, NULL
);
1251 /* signal handler for fatal errors */
1252 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
1254 rt_context
*rc
= &g_rtctxt
;
1256 rt_getcontext(ex_info
->ContextRecord
, rc
);
1258 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
1259 case EXCEPTION_ACCESS_VIOLATION
:
1260 rt_error("invalid memory access");
1262 case EXCEPTION_STACK_OVERFLOW
:
1263 rt_error("stack overflow");
1265 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
1266 rt_error("division by zero");
1268 case EXCEPTION_BREAKPOINT
:
1269 case EXCEPTION_SINGLE_STEP
:
1270 rc
->ip
= *(addr_t
*)rc
->sp
;
1271 rt_error("breakpoint/single-step exception:");
1272 return EXCEPTION_CONTINUE_SEARCH
;
1274 rt_error("caught exception %08x", code
);
1279 return EXCEPTION_EXECUTE_HANDLER
;
1282 /* Generate a stack backtrace when a CPU exception occurs. */
1283 static void set_exception_handler(void)
1285 SetUnhandledExceptionFilter(cpu_exception_handler
);
1290 /* ------------------------------------------------------------- */
1291 /* return the PC at frame level 'level'. Return negative if not found */
1292 #if defined(__i386__) || defined(__x86_64__)
1293 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1302 /* XXX: check address validity with program info */
1305 fp
= ((addr_t
*)fp
)[0];
1308 ip
= ((addr_t
*)fp
)[1];
1316 #elif defined(__arm__)
1317 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1319 /* XXX: only supports linux/bsd */
1320 #if !defined(__linux__) && \
1321 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
1329 fp
= ((addr_t
*)fp
)[0];
1330 *paddr
= ((addr_t
*)fp
)[2];
1336 #elif defined(__aarch64__)
1337 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1342 addr_t
*fp
= (addr_t
*)rc
->fp
;
1344 fp
= (addr_t
*)fp
[0];
1350 #elif defined(__riscv)
1351 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1356 addr_t
*fp
= (addr_t
*)rc
->fp
;
1357 while (--level
&& fp
>= (addr_t
*)0x1000)
1358 fp
= (addr_t
*)fp
[-2];
1359 if (fp
< (addr_t
*)0x1000)
1367 #warning add arch specific rt_get_caller_pc()
1368 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1374 #endif /* CONFIG_TCC_BACKTRACE */
1375 /* ------------------------------------------------------------- */
1376 #ifdef CONFIG_TCC_STATIC
1378 /* dummy function for profiling */
1379 ST_FUNC
void *dlopen(const char *filename
, int flag
)
1384 ST_FUNC
void dlclose(void *p
)
1388 ST_FUNC
const char *dlerror(void)
1393 typedef struct TCCSyms
{
1399 /* add the symbol you want here if no dynamic linking is done */
1400 static TCCSyms tcc_syms
[] = {
1401 #if !defined(CONFIG_TCCBOOT)
1402 #define TCCSYM(a) { #a, &a, },
1412 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
1416 while (p
->str
!= NULL
) {
1417 if (!strcmp(p
->str
, symbol
))
1424 #endif /* CONFIG_TCC_STATIC */
1425 #endif /* TCC_IS_NATIVE */
1426 /* ------------------------------------------------------------- */