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 if (!(ret
= setjmp(rc
->jb
)))
267 ret
= prog_main(argc
, argv
, envp
);
268 run_cdtors(s1
, "__fini_array_start", "__fini_array_end", 0, NULL
, NULL
);
270 if (s1
->dflag
& 16 && ret
) /* tcc -dt -run ... */
271 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
275 #define DEBUG_RUNMEN 0
277 /* enable rx/ro/rw permissions */
278 #define CONFIG_RUNMEM_RO 1
281 # define PAGE_ALIGN PAGESIZE
282 #elif defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
283 /* To avoid that x86 processors would reload cached instructions
284 each time when data is written in the near, we need to make
285 sure that code and data do not share the same 64 byte unit */
286 # define PAGE_ALIGN 64
288 # define PAGE_ALIGN 1
291 /* relocate code. Return -1 on error, required size if ptr is NULL,
292 otherwise copy code into buffer passed by the caller */
293 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
)
296 unsigned offset
, length
, align
, max_align
, i
, k
, f
;
303 pe_output_file(s1
, NULL
);
306 resolve_common_syms(s1
);
307 build_got_entries(s1
, 0);
313 offset
= max_align
= 0, mem
= (addr_t
)ptr
;
315 offset
+= sizeof (void*); /* space for function_table pointer */
319 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
321 for(i
= 1; i
< s1
->nb_sections
; i
++) {
322 static const char shf
[] = {
323 SHF_ALLOC
|SHF_EXECINSTR
, SHF_ALLOC
, SHF_ALLOC
|SHF_WRITE
326 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
328 length
= s
->data_offset
;
332 n
= (s
->sh_addr
- addr
) + length
;
333 ptr
= (void*)s
->sh_addr
;
335 ptr
= (void*)(s
->sh_addr
- ptr_diff
);
336 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
337 memset(ptr
, 0, length
);
339 memcpy(ptr
, s
->data
, length
);
341 if (s
== s1
->uw_pdata
)
342 *(void**)mem
= win64_add_function_table(s1
);
347 s
->data_allocated
= 0;
352 align
= s
->sh_addralign
- 1;
353 if (++n
== 1 && align
< (PAGE_ALIGN
- 1))
354 align
= (PAGE_ALIGN
- 1);
355 if (max_align
< align
)
357 addr
= k
? mem
: mem
+ ptr_diff
;
358 offset
+= -(addr
+ offset
) & align
;
359 s
->sh_addr
= mem
? addr
+ offset
: 0;
363 printf("%d: %-16s %p len %04x align %04x\n",
364 k
, s
->name
, (void*)s
->sh_addr
, length
, align
+ 1);
367 if (copy
) { /* set permissions */
368 if (k
== 0 && ptr_diff
)
369 continue; /* not with HAVE_SELINUX */
371 #if !CONFIG_RUNMEM_RO
374 f
= 3; /* change only SHF_EXECINSTR to rwx */
377 printf("protect %d %p %04x\n", f
, (void*)addr
, n
);
380 if (set_pages_executable(s1
, f
, (void*)addr
, n
))
389 /* relocate symbols */
390 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
394 return offset
+ max_align
;
397 s1
->pe_imagebase
= mem
;
400 /* relocate sections */
401 #ifndef TCC_TARGET_PE
404 relocate_sections(s1
);
409 /* ------------------------------------------------------------- */
410 /* allow to run code in memory */
412 static int set_pages_executable(TCCState
*s1
, int mode
, void *ptr
, unsigned long length
)
415 static const unsigned char protect
[] = {
419 PAGE_EXECUTE_READWRITE
422 if (!VirtualProtect(ptr
, length
, protect
[mode
], &old
))
426 static const unsigned char protect
[] = {
427 PROT_READ
| PROT_EXEC
,
429 PROT_READ
| PROT_WRITE
,
430 PROT_READ
| PROT_WRITE
| PROT_EXEC
433 start
= (addr_t
)ptr
& ~(PAGESIZE
- 1);
434 end
= (addr_t
)ptr
+ length
;
435 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
436 if (mprotect((void *)start
, end
- start
, protect
[mode
]))
437 return tcc_error_noabort("mprotect failed: did you mean to configure --with-selinux?");
438 /* XXX: BSD sometimes dump core with bad system call */
439 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
440 if (mode
== 0 || mode
== 3) {
441 void __clear_cache(void *beginning
, void *end
);
442 __clear_cache(ptr
, (char *)ptr
+ length
);
450 static void *win64_add_function_table(TCCState
*s1
)
454 p
= (void*)s1
->uw_pdata
->sh_addr
;
456 (RUNTIME_FUNCTION
*)p
,
457 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
465 static void win64_del_function_table(void *p
)
468 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
472 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
473 /* ------------------------------------------------------------- */
474 #ifdef CONFIG_TCC_BACKTRACE
476 static int rt_vprintf(const char *fmt
, va_list ap
)
478 int ret
= vfprintf(stderr
, fmt
, ap
);
483 static int rt_printf(const char *fmt
, ...)
488 r
= rt_vprintf(fmt
, ap
);
493 static char *rt_elfsym(rt_context
*rc
, addr_t wanted_pc
, addr_t
*func_addr
)
496 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
497 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
498 if ((type
== STT_FUNC
|| type
== STT_GNU_IFUNC
)
499 && wanted_pc
>= esym
->st_value
500 && wanted_pc
< esym
->st_value
+ esym
->st_size
) {
501 *func_addr
= esym
->st_value
;
502 return rc
->elf_str
+ esym
->st_name
;
509 /* print the position in the source file of PC value 'pc' by reading
510 the stabs debug information */
511 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
,
512 const char *msg
, const char *skip
)
515 addr_t func_addr
, last_pc
, pc
;
516 const char *incl_files
[INCLUDE_STACK_SIZE
];
517 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
525 last_pc
= (addr_t
)-1;
529 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
530 str
= rc
->stab_str
+ sym
->n_strx
;
533 switch(sym
->n_type
) {
541 if (sym
->n_strx
== 0) /* end of function */
545 /* Stab_Sym.n_value is only 32bits */
552 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
557 switch(sym
->n_type
) {
558 /* function start or end */
560 if (sym
->n_strx
== 0)
562 p
= strchr(str
, ':');
563 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
564 len
= sizeof func_name
;
565 pstrcpy(func_name
, len
, str
);
568 /* line number info */
571 last_line_num
= sym
->n_desc
;
572 last_incl_index
= incl_index
;
576 if (incl_index
< INCLUDE_STACK_SIZE
)
577 incl_files
[incl_index
++] = str
;
583 /* start/end of translation unit */
587 /* do not add path */
589 if (len
> 0 && str
[len
- 1] != '/')
590 incl_files
[incl_index
++] = str
;
595 last_pc
= (addr_t
)-1;
597 /* alternative file name (from #line or #include directives) */
600 incl_files
[incl_index
-1] = str
;
608 /* we try symtab symbols (no line number info) */
609 p
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
611 pstrcpy(func_name
, sizeof func_name
, p
);
619 str
= incl_files
[--i
];
620 if (skip
[0] && strstr(str
, skip
))
622 rt_printf("%s:%d: ", str
, last_line_num
);
624 rt_printf("%08llx : ", (long long)wanted_pc
);
625 rt_printf("%s %s", msg
, func_name
[0] ? func_name
: "???");
628 rt_printf(" (included from ");
630 rt_printf("%s", incl_files
[i
]);
641 /* ------------------------------------------------------------- */
642 /* rt_printline - dwarf version */
644 #define MAX_128 ((8 * sizeof (long long) + 6) / 7)
646 #define DIR_TABLE_SIZE (64)
647 #define FILE_TABLE_SIZE (512)
649 #define dwarf_read_1(ln,end) \
650 ((ln) < (end) ? *(ln)++ : 0)
651 #define dwarf_read_2(ln,end) \
652 ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
653 #define dwarf_read_4(ln,end) \
654 ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
655 #define dwarf_read_8(ln,end) \
656 ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
657 #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \
658 switch (entry_format[j].form) { \
659 case DW_FORM_data1: (ln) += 1; break; \
660 case DW_FORM_data2: (ln) += 2; break; \
661 case DW_FORM_data4: (ln) += 3; break; \
662 case DW_FORM_data8: (ln) += 8; break; \
663 case DW_FORM_data16: (ln) += 16; break; \
664 case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \
665 default: goto next_line; \
668 static unsigned long long
669 dwarf_read_uleb128(unsigned char **ln
, unsigned char *end
)
671 unsigned char *cp
= *ln
;
672 unsigned long long retval
= 0;
675 for (i
= 0; i
< MAX_128
; i
++) {
676 unsigned long long byte
= dwarf_read_1(cp
, end
);
678 retval
|= (byte
& 0x7f) << (i
* 7);
679 if ((byte
& 0x80) == 0)
687 dwarf_read_sleb128(unsigned char **ln
, unsigned char *end
)
689 unsigned char *cp
= *ln
;
690 long long retval
= 0;
693 for (i
= 0; i
< MAX_128
; i
++) {
694 unsigned long long byte
= dwarf_read_1(cp
, end
);
696 retval
|= (byte
& 0x7f) << (i
* 7);
697 if ((byte
& 0x80) == 0) {
698 if ((byte
& 0x40) && (i
+ 1) * 7 < 64)
699 retval
|= -1LL << ((i
+ 1) * 7);
707 static addr_t
rt_printline_dwarf (rt_context
*rc
, addr_t wanted_pc
,
708 const char *msg
, const char *skip
)
713 unsigned char *opcode_length
;
714 unsigned long long size
;
716 unsigned char version
;
717 unsigned int min_insn_length
;
718 unsigned int max_ops_per_insn
;
720 unsigned int line_range
;
721 unsigned int opcode_base
;
722 unsigned int opindex
;
727 unsigned long long value
;
732 unsigned int dir_size
;
734 char *dirs
[DIR_TABLE_SIZE
];
736 unsigned int filename_size
;
737 struct dwarf_filename_struct
{
738 unsigned int dir_entry
;
740 } filename_table
[FILE_TABLE_SIZE
];
750 while (ln
< rc
->dwarf_line_end
) {
760 size
= dwarf_read_4(ln
, rc
->dwarf_line_end
);
761 if (size
== 0xffffffffu
) // dwarf 64
762 length
= 8, size
= dwarf_read_8(ln
, rc
->dwarf_line_end
);
764 if (end
< ln
|| end
> rc
->dwarf_line_end
)
766 version
= dwarf_read_2(ln
, end
);
768 ln
+= length
+ 2; // address size, segment selector, prologue Length
770 ln
+= length
; // prologue Length
771 min_insn_length
= dwarf_read_1(ln
, end
);
773 max_ops_per_insn
= dwarf_read_1(ln
, end
);
775 max_ops_per_insn
= 1;
776 ln
++; // Initial value of 'is_stmt'
777 line_base
= dwarf_read_1(ln
, end
);
778 line_base
|= line_base
>= 0x80 ? ~0xff : 0;
779 line_range
= dwarf_read_1(ln
, end
);
780 opcode_base
= dwarf_read_1(ln
, end
);
782 ln
+= opcode_base
- 1;
785 col
= dwarf_read_1(ln
, end
);
786 for (i
= 0; i
< col
; i
++) {
787 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
788 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
790 dir_size
= dwarf_read_uleb128(&ln
, end
);
791 for (i
= 0; i
< dir_size
; i
++) {
792 for (j
= 0; j
< col
; j
++) {
793 if (entry_format
[j
].type
== DW_LNCT_path
) {
794 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
797 value
= length
== 4 ? dwarf_read_4(ln
, end
)
798 : dwarf_read_8(ln
, end
);
799 if (i
< DIR_TABLE_SIZE
)
800 dirs
[i
] = (char *)rc
->dwarf_line_str
+ value
;
802 length
== 4 ? dwarf_read_4(ln
, end
)
803 : dwarf_read_8(ln
, end
);
807 dwarf_ignore_type(ln
, end
);
810 col
= dwarf_read_1(ln
, end
);
811 for (i
= 0; i
< col
; i
++) {
812 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
813 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
815 filename_size
= dwarf_read_uleb128(&ln
, end
);
816 for (i
= 0; i
< filename_size
; i
++)
817 for (j
= 0; j
< col
; j
++) {
818 if (entry_format
[j
].type
== DW_LNCT_path
) {
819 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
821 value
= length
== 4 ? dwarf_read_4(ln
, end
)
822 : dwarf_read_8(ln
, end
);
823 if (i
< FILE_TABLE_SIZE
)
824 filename_table
[i
].name
=
825 (char *)rc
->dwarf_line_str
+ value
;
827 else if (entry_format
[j
].type
== DW_LNCT_directory_index
) {
828 switch (entry_format
[j
].form
) {
829 case DW_FORM_data1
: value
= dwarf_read_1(ln
, end
); break;
830 case DW_FORM_data2
: value
= dwarf_read_2(ln
, end
); break;
831 case DW_FORM_data4
: value
= dwarf_read_4(ln
, end
); break;
832 case DW_FORM_udata
: value
= dwarf_read_uleb128(&ln
, end
); break;
833 default: goto next_line
;
835 if (i
< FILE_TABLE_SIZE
)
836 filename_table
[i
].dir_entry
= value
;
839 dwarf_ignore_type(ln
, end
);
843 while ((dwarf_read_1(ln
, end
))) {
845 if (++dir_size
< DIR_TABLE_SIZE
)
846 dirs
[dir_size
- 1] = (char *)ln
- 1;
848 while (dwarf_read_1(ln
, end
)) {}
850 while ((dwarf_read_1(ln
, end
))) {
851 if (++filename_size
< FILE_TABLE_SIZE
) {
852 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
853 while (dwarf_read_1(ln
, end
)) {}
854 filename_table
[filename_size
- 1].dir_entry
=
855 dwarf_read_uleb128(&ln
, end
);
858 while (dwarf_read_1(ln
, end
)) {}
859 dwarf_read_uleb128(&ln
, end
);
861 dwarf_read_uleb128(&ln
, end
); // time
862 dwarf_read_uleb128(&ln
, end
); // size
865 if (filename_size
>= 1)
866 filename
= filename_table
[0].name
;
869 i
= dwarf_read_1(ln
, end
);
870 if (i
>= opcode_base
) {
871 if (max_ops_per_insn
== 1)
872 pc
+= ((i
- opcode_base
) / line_range
) * min_insn_length
;
874 pc
+= (opindex
+ (i
- opcode_base
) / line_range
) /
875 max_ops_per_insn
* min_insn_length
;
876 opindex
= (opindex
+ (i
- opcode_base
) / line_range
) %
879 i
= (int)((i
- opcode_base
) % line_range
) + line_base
;
881 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
888 len
= dwarf_read_uleb128(&ln
, end
);
893 switch (dwarf_read_1(cp
, end
)) {
894 case DW_LNE_end_sequence
:
896 case DW_LNE_set_address
:
898 pc
= dwarf_read_4(cp
, end
);
900 pc
= dwarf_read_8(cp
, end
);
902 #if defined TCC_TARGET_MACHO
903 if (rc
->prog_base
!= (addr_t
) -1)
908 case DW_LNE_define_file
: /* deprecated */
909 if (++filename_size
< FILE_TABLE_SIZE
) {
910 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
911 while (dwarf_read_1(ln
, end
)) {}
912 filename_table
[filename_size
- 1].dir_entry
=
913 dwarf_read_uleb128(&ln
, end
);
916 while (dwarf_read_1(ln
, end
)) {}
917 dwarf_read_uleb128(&ln
, end
);
919 dwarf_read_uleb128(&ln
, end
); // time
920 dwarf_read_uleb128(&ln
, end
); // size
922 case DW_LNE_hi_user
- 1:
923 function
= (char *)cp
;
930 case DW_LNS_advance_pc
:
931 if (max_ops_per_insn
== 1)
932 pc
+= dwarf_read_uleb128(&ln
, end
) * min_insn_length
;
934 unsigned long long off
= dwarf_read_uleb128(&ln
, end
);
936 pc
+= (opindex
+ off
) / max_ops_per_insn
*
938 opindex
= (opindex
+ off
) % max_ops_per_insn
;
942 case DW_LNS_advance_line
:
943 line
+= dwarf_read_sleb128(&ln
, end
);
945 case DW_LNS_set_file
:
946 i
= dwarf_read_uleb128(&ln
, end
);
947 i
-= i
> 0 && version
< 5;
948 if (i
< FILE_TABLE_SIZE
&& i
< filename_size
)
949 filename
= filename_table
[i
].name
;
951 case DW_LNS_const_add_pc
:
952 if (max_ops_per_insn
== 1)
953 pc
+= ((255 - opcode_base
) / line_range
) * min_insn_length
;
955 unsigned int off
= (255 - opcode_base
) / line_range
;
957 pc
+= ((opindex
+ off
) / max_ops_per_insn
) *
959 opindex
= (opindex
+ off
) % max_ops_per_insn
;
963 case DW_LNS_fixed_advance_pc
:
964 i
= dwarf_read_2(ln
, end
);
970 for (j
= 0; j
< opcode_length
[i
- 1]; j
++)
971 dwarf_read_uleb128 (&ln
, end
);
982 /* we try symtab symbols (no line number info) */
983 function
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
990 if (skip
[0] && strstr(filename
, skip
))
992 rt_printf("%s:%d: ", filename
, line
);
995 rt_printf("0x%08llx : ", (long long)wanted_pc
);
996 rt_printf("%s %s", msg
, function
? function
: "???");
997 return (addr_t
)func_addr
;
999 /* ------------------------------------------------------------- */
1001 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
);
1003 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
)
1005 rt_context
*rc
= &g_rtctxt
;
1008 int i
, level
, ret
, n
, one
;
1009 const char *a
, *b
, *msg
;
1012 /* we're called from tcc_backtrace. */
1013 rc
->fp
= (addr_t
)fp
;
1014 rc
->ip
= (addr_t
)ip
;
1017 /* we're called from signal/exception handler */
1018 msg
= "RUNTIME ERROR: ";
1022 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
1023 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
1024 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
1028 /* hack for bcheck.c:dprintf(): one level, no newline */
1029 if (fmt
[0] == '\001')
1032 n
= rc
->num_callers
? rc
->num_callers
: 6;
1033 for (i
= level
= 0; level
< n
; i
++) {
1034 ret
= rt_get_caller_pc(&pc
, rc
, i
);
1038 pc
= rt_printline_dwarf(rc
, pc
, level
? "by" : "at", skip
);
1040 pc
= rt_printline(rc
, pc
, level
? "by" : "at", skip
);
1041 if (pc
== (addr_t
)-1)
1047 rt_vprintf(fmt
, ap
);
1048 } else if (ret
== -1)
1053 if (ret
== -1 || (pc
== (addr_t
)rc
->top_func
&& pc
))
1058 rc
->ip
= rc
->fp
= 0;
1062 /* emit a run time error at position 'pc' */
1063 static int rt_error(const char *fmt
, ...)
1068 ret
= _rt_error(0, 0, fmt
, ap
);
1073 /* ------------------------------------------------------------- */
1076 # include <signal.h>
1077 # ifndef __OpenBSD__
1078 # include <sys/ucontext.h>
1081 # define ucontext_t CONTEXT
1084 /* translate from ucontext_t* to internal rt_context * */
1085 static void rt_getcontext(ucontext_t
*uc
, rt_context
*rc
)
1091 #elif defined _WIN32
1095 #elif defined __i386__
1096 # if defined(__APPLE__)
1097 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
1098 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
1099 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1100 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
1101 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
1102 # elif defined(__dietlibc__)
1103 rc
->ip
= uc
->uc_mcontext
.eip
;
1104 rc
->fp
= uc
->uc_mcontext
.ebp
;
1105 # elif defined(__NetBSD__)
1106 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
1107 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
1108 # elif defined(__OpenBSD__)
1109 rc
->ip
= uc
->sc_eip
;
1110 rc
->fp
= uc
->sc_ebp
;
1111 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
1112 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
1113 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
1115 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1116 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
1118 #elif defined(__x86_64__)
1119 # if defined(__APPLE__)
1120 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
1121 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
1122 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1123 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
1124 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
1125 # elif defined(__NetBSD__)
1126 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
1127 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
1128 # elif defined(__OpenBSD__)
1129 rc
->ip
= uc
->sc_rip
;
1130 rc
->fp
= uc
->sc_rbp
;
1132 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1133 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
1135 #elif defined(__arm__) && defined(__NetBSD__)
1136 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1137 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1138 #elif defined(__arm__) && defined(__OpenBSD__)
1140 rc
->fp
= uc
->sc_r11
;
1141 #elif defined(__arm__) && defined(__FreeBSD__)
1142 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1143 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1144 #elif defined(__arm__)
1145 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
1146 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
1147 #elif defined(__aarch64__) && defined(__APPLE__)
1149 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
1150 rc
->ip
= uc
->uc_mcontext
->__ss
.__pc
;
1151 rc
->fp
= uc
->uc_mcontext
->__ss
.__fp
;
1152 #elif defined(__aarch64__) && defined(__FreeBSD__)
1153 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
1154 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
1155 #elif defined(__aarch64__) && defined(__NetBSD__)
1156 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1157 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1158 #elif defined(__aarch64__) && defined(__OpenBSD__)
1159 rc
->ip
= uc
->sc_elr
;
1160 rc
->fp
= uc
->sc_x
[29];
1161 #elif defined(__aarch64__)
1162 rc
->ip
= uc
->uc_mcontext
.pc
;
1163 rc
->fp
= uc
->uc_mcontext
.regs
[29];
1164 #elif defined(__riscv) && defined(__OpenBSD__)
1165 rc
->ip
= uc
->sc_sepc
;
1166 rc
->fp
= uc
->sc_s
[0];
1167 #elif defined(__riscv)
1168 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
1169 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
1173 /* ------------------------------------------------------------- */
1175 /* signal handler for fatal errors */
1176 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
1178 rt_context
*rc
= &g_rtctxt
;
1179 rt_getcontext(puc
, rc
);
1183 switch(siginf
->si_code
) {
1186 rt_error("division by zero");
1189 rt_error("floating point exception");
1195 rt_error("invalid memory access");
1198 rt_error("illegal instruction");
1201 rt_error("abort() called");
1204 rt_error("caught signal %d", signum
);
1211 # define SA_SIGINFO 0x00000004u
1214 /* Generate a stack backtrace when a CPU exception occurs. */
1215 static void set_exception_handler(void)
1217 struct sigaction sigact
;
1218 /* install TCC signal handlers to print debug info on fatal
1220 sigemptyset (&sigact
.sa_mask
);
1221 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
1222 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
1223 sigact
.sa_flags
|= SA_ONSTACK
;
1225 sigact
.sa_sigaction
= sig_error
;
1226 sigemptyset(&sigact
.sa_mask
);
1227 sigaction(SIGFPE
, &sigact
, NULL
);
1228 sigaction(SIGILL
, &sigact
, NULL
);
1229 sigaction(SIGSEGV
, &sigact
, NULL
);
1230 sigaction(SIGBUS
, &sigact
, NULL
);
1231 sigaction(SIGABRT
, &sigact
, NULL
);
1233 /* This allows stack overflow to be reported instead of a SEGV */
1236 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
1239 ss
.ss_size
= SIGSTKSZ
;
1241 sigaltstack(&ss
, NULL
);
1248 /* signal handler for fatal errors */
1249 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
1251 rt_context
*rc
= &g_rtctxt
;
1253 rt_getcontext(ex_info
->ContextRecord
, rc
);
1255 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
1256 case EXCEPTION_ACCESS_VIOLATION
:
1257 rt_error("invalid memory access");
1259 case EXCEPTION_STACK_OVERFLOW
:
1260 rt_error("stack overflow");
1262 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
1263 rt_error("division by zero");
1265 case EXCEPTION_BREAKPOINT
:
1266 case EXCEPTION_SINGLE_STEP
:
1267 rc
->ip
= *(addr_t
*)rc
->sp
;
1268 rt_error("breakpoint/single-step exception:");
1269 return EXCEPTION_CONTINUE_SEARCH
;
1271 rt_error("caught exception %08x", code
);
1276 return EXCEPTION_EXECUTE_HANDLER
;
1279 /* Generate a stack backtrace when a CPU exception occurs. */
1280 static void set_exception_handler(void)
1282 SetUnhandledExceptionFilter(cpu_exception_handler
);
1287 /* ------------------------------------------------------------- */
1288 /* return the PC at frame level 'level'. Return negative if not found */
1289 #if defined(__i386__) || defined(__x86_64__)
1290 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1299 /* XXX: check address validity with program info */
1302 fp
= ((addr_t
*)fp
)[0];
1305 ip
= ((addr_t
*)fp
)[1];
1313 #elif defined(__arm__)
1314 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1316 /* XXX: only supports linux/bsd */
1317 #if !defined(__linux__) && \
1318 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
1326 fp
= ((addr_t
*)fp
)[0];
1327 *paddr
= ((addr_t
*)fp
)[2];
1333 #elif defined(__aarch64__)
1334 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1339 addr_t
*fp
= (addr_t
*)rc
->fp
;
1341 fp
= (addr_t
*)fp
[0];
1347 #elif defined(__riscv)
1348 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1353 addr_t
*fp
= (addr_t
*)rc
->fp
;
1354 while (--level
&& fp
>= (addr_t
*)0x1000)
1355 fp
= (addr_t
*)fp
[-2];
1356 if (fp
< (addr_t
*)0x1000)
1364 #warning add arch specific rt_get_caller_pc()
1365 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1371 #endif /* CONFIG_TCC_BACKTRACE */
1372 /* ------------------------------------------------------------- */
1373 #ifdef CONFIG_TCC_STATIC
1375 /* dummy function for profiling */
1376 ST_FUNC
void *dlopen(const char *filename
, int flag
)
1381 ST_FUNC
void dlclose(void *p
)
1385 ST_FUNC
const char *dlerror(void)
1390 typedef struct TCCSyms
{
1396 /* add the symbol you want here if no dynamic linking is done */
1397 static TCCSyms tcc_syms
[] = {
1398 #if !defined(CONFIG_TCCBOOT)
1399 #define TCCSYM(a) { #a, &a, },
1409 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
1413 while (p
->str
!= NULL
) {
1414 if (!strcmp(p
->str
, symbol
))
1421 #endif /* CONFIG_TCC_STATIC */
1422 #endif /* TCC_IS_NATIVE */
1423 /* ------------------------------------------------------------- */