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 #endif /* CONFIG_TCC_BACKTRACE */
59 /* defined when included from lib/bt-exe.c */
60 #ifndef CONFIG_TCC_BACKTRACE_ONLY
63 # include <sys/mman.h>
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
);
70 static void *win64_add_function_table(TCCState
*s1
);
71 static void win64_del_function_table(void *);
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
)
83 if (TCC_RELOCATE_AUTO
!= ptr
)
84 return tcc_relocate_ex(s1
, ptr
, 0);
86 size
= tcc_relocate_ex(s1
, NULL
, 0);
92 /* Using mmap instead of malloc */
94 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
95 int fd
= mkstemp(tmpfname
);
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
;
107 //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
110 ptr
= tcc_malloc(size
);
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
);
118 ST_FUNC
void tcc_run_free(TCCState
*s1
)
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];
126 munmap(ptr
, size
* 2);
128 /* unprotect memory to make it usable for malloc again */
129 set_pages_executable(s1
, 2, ptr
, size
);
131 win64_del_function_table(*(void**)ptr
);
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);
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
;
156 #if defined(__APPLE__) || defined(__FreeBSD__)
158 #elif defined(__OpenBSD__) || defined(__NetBSD__)
159 extern char **environ
;
160 char **envp
= environ
;
162 char **envp
= environ
;
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))
168 #ifdef CONFIG_TCC_BACKTRACE
170 tcc_add_symbol(s1
, "exit", rt_exit
);
172 if (tcc_relocate(s1
, TCC_RELOCATE_AUTO
) < 0)
174 prog_main
= (void*)get_sym_addr(s1
, s1
->runtime_main
, 1, 1);
176 #ifdef CONFIG_TCC_BACKTRACE
177 memset(rc
, 0, sizeof *rc
);
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
;
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
;
197 rc
->prog_base
= text_section
->sh_addr
& 0xffffffff00000000ULL
;
199 rc
->top_func
= tcc_get_symbol(s1
, "main");
200 rc
->num_callers
= s1
->rt_num_callers
;
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);
211 set_exception_handler();
215 errno
= 0; /* clean errno value */
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)))
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
);
232 #define DEBUG_RUNMEN 0
234 /* enable rx/ro/rw permissions */
235 #define CONFIG_RUNMEM_RO 1
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
245 # define PAGE_ALIGN 1
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
)
253 unsigned offset
, length
, align
, max_align
, i
, k
, f
;
260 pe_output_file(s1
, NULL
);
263 resolve_common_syms(s1
);
264 build_got_entries(s1
, 0);
270 offset
= max_align
= 0, mem
= (addr_t
)ptr
;
272 offset
+= sizeof (void*); /* space for function_table pointer */
276 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
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
283 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
285 length
= s
->data_offset
;
289 n
= (s
->sh_addr
- addr
) + length
;
290 ptr
= (void*)s
->sh_addr
;
292 ptr
= (void*)(s
->sh_addr
- ptr_diff
);
293 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
294 memset(ptr
, 0, length
);
296 memcpy(ptr
, s
->data
, length
);
298 if (s
== s1
->uw_pdata
)
299 *(void**)mem
= win64_add_function_table(s1
);
304 s
->data_allocated
= 0;
309 align
= s
->sh_addralign
- 1;
310 if (++n
== 1 && align
< (PAGE_ALIGN
- 1))
311 align
= (PAGE_ALIGN
- 1);
312 if (max_align
< align
)
314 addr
= k
? mem
: mem
+ ptr_diff
;
315 offset
+= -(addr
+ offset
) & align
;
316 s
->sh_addr
= mem
? addr
+ offset
: 0;
320 printf("%d: %-16s %p len %04x align %04x\n",
321 k
, s
->name
, (void*)s
->sh_addr
, length
, align
+ 1);
324 if (copy
) { /* set permissions */
325 if (k
== 0 && ptr_diff
)
326 continue; /* not with HAVE_SELINUX */
328 #if !CONFIG_RUNMEM_RO
331 f
= 3; /* change only SHF_EXECINSTR to rwx */
334 printf("protect %d %p %04x\n", f
, (void*)addr
, n
);
337 set_pages_executable(s1
, f
, (void*)addr
, n
);
344 /* relocate symbols */
345 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
349 return offset
+ max_align
;
352 s1
->pe_imagebase
= mem
;
355 /* relocate sections */
356 #ifndef TCC_TARGET_PE
359 relocate_sections(s1
);
364 /* ------------------------------------------------------------- */
365 /* allow to run code in memory */
367 static void set_pages_executable(TCCState
*s1
, int mode
, void *ptr
, unsigned long length
)
370 static const unsigned char protect
[] = {
374 PAGE_EXECUTE_READWRITE
377 VirtualProtect(ptr
, length
, protect
[mode
], &old
);
379 static const unsigned char protect
[] = {
380 PROT_READ
| PROT_EXEC
,
382 PROT_READ
| PROT_WRITE
,
383 PROT_READ
| PROT_WRITE
| PROT_EXEC
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
);
404 static void *win64_add_function_table(TCCState
*s1
)
408 p
= (void*)s1
->uw_pdata
->sh_addr
;
410 (RUNTIME_FUNCTION
*)p
,
411 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
419 static void win64_del_function_table(void *p
)
422 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
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
);
437 static int rt_printf(const char *fmt
, ...)
442 r
= rt_vprintf(fmt
, ap
);
447 static char *rt_elfsym(rt_context
*rc
, addr_t wanted_pc
, addr_t
*func_addr
)
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
;
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
)
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
;
480 last_pc
= (addr_t
)-1;
484 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
485 str
= rc
->stab_str
+ sym
->n_strx
;
488 switch(sym
->n_type
) {
496 if (sym
->n_strx
== 0) /* end of function */
500 /* Stab_Sym.n_value is only 32bits */
507 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
512 switch(sym
->n_type
) {
513 /* function start or end */
515 if (sym
->n_strx
== 0)
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
);
523 /* line number info */
526 last_line_num
= sym
->n_desc
;
527 last_incl_index
= incl_index
;
531 if (incl_index
< INCLUDE_STACK_SIZE
)
532 incl_files
[incl_index
++] = str
;
538 /* start/end of translation unit */
542 /* do not add path */
544 if (len
> 0 && str
[len
- 1] != '/')
545 incl_files
[incl_index
++] = str
;
550 last_pc
= (addr_t
)-1;
552 /* alternative file name (from #line or #include directives) */
555 incl_files
[incl_index
-1] = str
;
563 /* we try symtab symbols (no line number info) */
564 p
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
566 pstrcpy(func_name
, sizeof func_name
, p
);
574 str
= incl_files
[--i
];
575 if (skip
[0] && strstr(str
, skip
))
577 rt_printf("%s:%d: ", str
, last_line_num
);
579 rt_printf("%08llx : ", (long long)wanted_pc
);
580 rt_printf("%s %s", msg
, func_name
[0] ? func_name
: "???");
583 rt_printf(" (included from ");
585 rt_printf("%s", incl_files
[i
]);
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;
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)
642 dwarf_read_sleb128(unsigned char **ln
, unsigned char *end
)
644 unsigned char *cp
= *ln
;
645 long long retval
= 0;
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);
662 static addr_t
rt_printline_dwarf (rt_context
*rc
, addr_t wanted_pc
,
663 const char *msg
, const char *skip
)
668 unsigned char *opcode_length
;
669 unsigned long long size
;
671 unsigned char version
;
672 unsigned int min_insn_length
;
673 unsigned int max_ops_per_insn
;
675 unsigned int line_range
;
676 unsigned int opcode_base
;
677 unsigned int opindex
;
682 unsigned long long value
;
687 unsigned int dir_size
;
689 char *dirs
[DIR_TABLE_SIZE
];
691 unsigned int filename_size
;
692 struct dwarf_filename_struct
{
693 unsigned int dir_entry
;
695 } filename_table
[FILE_TABLE_SIZE
];
705 while (ln
< rc
->dwarf_line_end
) {
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
);
719 if (end
< ln
|| end
> rc
->dwarf_line_end
)
721 version
= dwarf_read_2(ln
, end
);
723 ln
+= length
+ 2; // address size, segment selector, prologue Length
725 ln
+= length
; // prologue Length
726 min_insn_length
= dwarf_read_1(ln
, end
);
728 max_ops_per_insn
= dwarf_read_1(ln
, end
);
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
);
737 ln
+= opcode_base
- 1;
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
)
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
;
757 length
== 4 ? dwarf_read_4(ln
, end
)
758 : dwarf_read_8(ln
, end
);
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
)
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
;
794 dwarf_ignore_type(ln
, end
);
798 while ((dwarf_read_1(ln
, end
))) {
800 if (++dir_size
< DIR_TABLE_SIZE
)
801 dirs
[dir_size
- 1] = (char *)ln
- 1;
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
);
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
;
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
;
829 pc
+= (opindex
+ (i
- opcode_base
) / line_range
) /
830 max_ops_per_insn
* min_insn_length
;
831 opindex
= (opindex
+ (i
- opcode_base
) / line_range
) %
834 i
= (int)((i
- opcode_base
) % line_range
) + line_base
;
836 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
843 len
= dwarf_read_uleb128(&ln
, end
);
848 switch (dwarf_read_1(cp
, end
)) {
849 case DW_LNE_end_sequence
:
851 case DW_LNE_set_address
:
853 pc
= dwarf_read_4(cp
, end
);
855 pc
= dwarf_read_8(cp
, end
);
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
);
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
873 case DW_LNE_hi_user
- 1:
874 function
= (char *)cp
;
881 case DW_LNS_advance_pc
:
882 if (max_ops_per_insn
== 1)
883 pc
+= dwarf_read_uleb128(&ln
, end
) * min_insn_length
;
885 unsigned long long off
= dwarf_read_uleb128(&ln
, end
);
887 pc
+= (opindex
+ off
) / max_ops_per_insn
*
889 opindex
= (opindex
+ off
) % max_ops_per_insn
;
893 case DW_LNS_advance_line
:
894 line
+= dwarf_read_sleb128(&ln
, end
);
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
;
901 case DW_LNS_const_add_pc
:
902 if (max_ops_per_insn
== 1)
903 pc
+= ((255 - opcode_base
) / line_range
) * min_insn_length
;
905 unsigned int off
= (255 - opcode_base
) / line_range
;
907 pc
+= ((opindex
+ off
) / max_ops_per_insn
) *
909 opindex
= (opindex
+ off
) % max_ops_per_insn
;
913 case DW_LNS_fixed_advance_pc
:
914 i
= dwarf_read_2(ln
, end
);
920 for (j
= 0; j
< opcode_length
[i
- 1]; j
++)
921 dwarf_read_uleb128 (&ln
, end
);
932 /* we try symtab symbols (no line number info) */
933 function
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
940 if (skip
[0] && strstr(filename
, skip
))
942 rt_printf("%s:%d: ", filename
, line
);
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
;
958 int i
, level
, ret
, n
;
959 const char *a
, *b
, *msg
;
962 /* we're called from tcc_backtrace. */
967 /* we're called from signal/exception handler */
968 msg
= "RUNTIME ERROR: ";
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;
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
);
984 pc
= rt_printline_dwarf(rc
, pc
, level
? "by" : "at", skip
);
986 pc
= rt_printline(rc
, pc
, level
? "by" : "at", skip
);
987 if (pc
== (addr_t
)-1)
994 } else if (ret
== -1)
997 if (ret
== -1 || (pc
== (addr_t
)rc
->top_func
&& pc
))
1002 rc
->ip
= rc
->fp
= 0;
1006 /* emit a run time error at position 'pc' */
1007 static int rt_error(const char *fmt
, ...)
1012 ret
= _rt_error(0, 0, fmt
, ap
);
1017 static void rt_exit(int code
)
1019 rt_context
*rc
= &g_rtctxt
;
1021 longjmp(rc
->jmp_buf, code
? code
: 256);
1025 /* ------------------------------------------------------------- */
1028 # include <signal.h>
1029 # ifndef __OpenBSD__
1030 # include <sys/ucontext.h>
1033 # define ucontext_t CONTEXT
1036 /* translate from ucontext_t* to internal rt_context * */
1037 static void rt_getcontext(ucontext_t
*uc
, rt_context
*rc
)
1043 #elif defined _WIN32
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
];
1067 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1068 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
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
;
1084 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1085 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
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__)
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__)
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
];
1125 /* ------------------------------------------------------------- */
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
);
1135 switch(siginf
->si_code
) {
1138 rt_error("division by zero");
1141 rt_error("floating point exception");
1147 rt_error("invalid memory access");
1150 rt_error("illegal instruction");
1153 rt_error("abort() called");
1156 rt_error("caught signal %d", signum
);
1163 # define SA_SIGINFO 0x00000004u
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
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
;
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
);
1185 /* This allows stack overflow to be reported instead of a SEGV */
1188 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
1191 ss
.ss_size
= SIGSTKSZ
;
1193 sigaltstack(&ss
, NULL
);
1200 /* signal handler for fatal errors */
1201 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
1203 rt_context
*rc
= &g_rtctxt
;
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");
1211 case EXCEPTION_STACK_OVERFLOW
:
1212 rt_error("stack overflow");
1214 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
1215 rt_error("division by zero");
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
;
1223 rt_error("caught exception %08x", code
);
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
);
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
)
1251 /* XXX: check address validity with program info */
1254 fp
= ((addr_t
*)fp
)[0];
1257 ip
= ((addr_t
*)fp
)[1];
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__)
1278 fp
= ((addr_t
*)fp
)[0];
1279 *paddr
= ((addr_t
*)fp
)[2];
1285 #elif defined(__aarch64__)
1286 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
1291 addr_t
*fp
= (addr_t
*)rc
->fp
;
1293 fp
= (addr_t
*)fp
[0];
1299 #elif defined(__riscv)
1300 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
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)
1316 #warning add arch specific rt_get_caller_pc()
1317 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
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
)
1333 ST_FUNC
void dlclose(void *p
)
1337 ST_FUNC
const char *dlerror(void)
1342 typedef struct 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, },
1361 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
1365 while (p
->str
!= NULL
) {
1366 if (!strcmp(p
->str
, symbol
))
1373 #endif /* CONFIG_TCC_STATIC */
1374 #endif /* TCC_IS_NATIVE */
1375 /* ------------------------------------------------------------- */