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 /* runtime debug info block */
28 typedef struct rt_context
30 /* tccelf.c:tcc_add_btstub() wants these in that order: */
34 Stab_Sym
*stab_sym_end
;
38 unsigned char *dwarf_line
;
39 unsigned char *dwarf_line_end
;
40 unsigned char *dwarf_line_str
;
43 ElfW(Sym
) *esym_start
;
50 struct rt_context
*next
;
56 /* linked list of rt_contexts */
57 static rt_context
*g_rc
;
58 static int signal_set
;
59 static void set_exception_handler(void);
60 #endif /* def CONFIG_TCC_BACKTRACE */
62 typedef struct rt_frame
{
66 static TCCState
*g_s1
;
67 /* semaphore to protect it */
68 TCC_SEM(static rt_sem
);
69 static void rt_wait_sem(void) { WAIT_SEM(&rt_sem
); }
70 static void rt_post_sem(void) { POST_SEM(&rt_sem
); }
71 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*f
, int level
);
72 static void rt_exit(rt_frame
*f
, int code
);
74 /* ------------------------------------------------------------- */
75 /* defined when included from lib/bt-exe.c */
76 #ifndef CONFIG_TCC_BACKTRACE_ONLY
79 # include <sys/mman.h>
82 static int protect_pages(void *ptr
, unsigned long length
, int mode
);
83 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, unsigned ptr_diff
);
84 static void st_link(TCCState
*s1
);
85 static void st_unlink(TCCState
*s1
);
86 #ifdef CONFIG_TCC_BACKTRACE
87 static int _tcc_backtrace(rt_frame
*f
, const char *fmt
, va_list ap
);
90 static void *win64_add_function_table(TCCState
*s1
);
91 static void win64_del_function_table(void *);
95 # if defined _SC_PAGESIZE
96 # define PAGESIZE sysconf(_SC_PAGESIZE)
97 # elif defined __APPLE__
98 # include <libkern/OSCacheControl.h>
99 # define PAGESIZE getpagesize()
101 # define PAGESIZE 4096
105 #define PAGEALIGN(n) ((addr_t)n + (-(addr_t)n & (PAGESIZE-1)))
107 #if !_WIN32 && !__APPLE__
108 //#define HAVE_SELINUX 1
111 static int rt_mem(TCCState
*s1
, int size
)
116 /* Using mmap instead of malloc */
118 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
119 int fd
= mkstemp(tmpfname
);
123 ptr
= mmap(NULL
, size
* 2, PROT_READ
|PROT_EXEC
, MAP_SHARED
, fd
, 0);
124 /* mmap RW memory at fixed distance */
125 prw
= mmap((char*)ptr
+ size
, size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_FIXED
, fd
, 0);
127 if (ptr
== MAP_FAILED
|| prw
== MAP_FAILED
)
128 return tcc_error_noabort("tccrun: could not map memory");
129 ptr_diff
= (char*)prw
- (char*)ptr
; /* = size; */
130 //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
133 ptr
= tcc_malloc(size
+= PAGESIZE
); /* one extra page to align malloc memory */
140 /* ------------------------------------------------------------- */
141 /* Do all relocations (needed before using tcc_get_symbol())
142 Returns -1 on error. */
144 LIBTCCAPI
int tcc_relocate(TCCState
*s1
)
146 int size
, ret
, ptr_diff
;
149 exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
150 #ifdef CONFIG_TCC_BACKTRACE
151 if (s1
->do_backtrace
)
152 tcc_add_symbol(s1
, "_tcc_backtrace", _tcc_backtrace
); /* for bt-log.c */
154 size
= tcc_relocate_ex(s1
, NULL
, 0);
157 ptr_diff
= rt_mem(s1
, size
);
160 ret
= tcc_relocate_ex(s1
, s1
->run_ptr
, ptr_diff
);
166 ST_FUNC
void tcc_run_free(TCCState
*s1
)
172 /* free any loaded DLLs */
173 for ( i
= 0; i
< s1
->nb_loaded_dlls
; i
++) {
174 DLLReference
*ref
= s1
->loaded_dlls
[i
];
177 FreeLibrary((HMODULE
)ref
->handle
);
179 dlclose(ref
->handle
);
182 /* unmap or unprotect and free memory */
191 /* unprotect memory to make it usable for malloc again */
192 protect_pages((void*)PAGEALIGN(ptr
), size
- PAGESIZE
, 2 /*rw*/);
194 win64_del_function_table(s1
->run_function_table
);
200 /* launch the compiled program with the given arguments */
201 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
203 int (*prog_main
)(int, char **, char **), ret
;
207 #if defined(__APPLE__) || defined(__FreeBSD__)
209 #elif defined(__OpenBSD__) || defined(__NetBSD__)
210 extern char **environ
;
211 char **envp
= environ
;
213 char **envp
= environ
;
216 /* tcc -dt -run ... nothing to do if no main() */
217 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, "main", 0, 1))
220 tcc_add_symbol(s1
, "__rt_exit", rt_exit
);
222 s1
->run_main
= top_sym
= "_start";
224 tcc_add_support(s1
, "runmain.o");
225 s1
->run_main
= "_runmain";
228 if (tcc_relocate(s1
) < 0)
231 prog_main
= (void*)get_sym_addr(s1
, s1
->run_main
, 1, 1);
232 if ((addr_t
)-1 == (addr_t
)prog_main
)
234 errno
= 0; /* clean errno value */
238 ret
= tcc_setjmp(s1
, main_jb
, tcc_get_symbol(s1
, top_sym
));
240 ret
= prog_main(argc
, argv
, envp
);
244 if (s1
->dflag
& 16 && ret
) /* tcc -dt -run ... */
245 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
249 /* ------------------------------------------------------------- */
250 /* remove all STB_LOCAL symbols */
251 static void cleanup_symbols(TCCState
*s1
)
253 Section
*s
= s1
->symtab
;
254 int sym_index
, end_sym
= s
->data_offset
/ sizeof (ElfSym
);
256 s
->data_offset
= s
->link
->data_offset
= s
->hash
->data_offset
= 0;
258 /* add global symbols again */
259 for (sym_index
= 1; sym_index
< end_sym
; ++sym_index
) {
260 ElfW(Sym
) *sym
= &((ElfW(Sym
) *)s
->data
)[sym_index
];
261 const char *name
= (char *)s
->link
->data
+ sym
->st_name
;
262 if (ELFW(ST_BIND
)(sym
->st_info
) == STB_LOCAL
)
264 //printf("sym %s\n", name);
265 put_elf_sym(s
, sym
->st_value
, sym
->st_size
, sym
->st_info
, sym
->st_other
, sym
->st_shndx
, name
);
269 /* free all sections except symbols */
270 static void cleanup_sections(TCCState
*s1
)
272 struct { Section
**secs
; int nb_secs
; } *p
= (void*)&s1
->sections
;
275 for (i
= --f
; i
< p
->nb_secs
; i
++) {
276 Section
*s
= p
->secs
[i
];
277 if (s
== s1
->symtab
|| s
== s1
->symtab
->link
|| s
== s1
->symtab
->hash
) {
278 s
->data
= tcc_realloc(s
->data
, s
->data_allocated
= s
->data_offset
);
280 free_section(s
), tcc_free(s
), p
->secs
[i
] = NULL
;
286 /* ------------------------------------------------------------- */
287 /* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */
288 /* 1 = .text rx other rw (memory >= 3 pages) */
289 /* 2 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
291 /* Some targets implement secutiry options that do not allow write in
292 executable code. These targets need CONFIG_RUNMEM_RO=1.
293 The disadvantage of this is that it requires a little bit more memory. */
295 #ifndef CONFIG_RUNMEM_RO
297 # define CONFIG_RUNMEM_RO 1
299 # define CONFIG_RUNMEM_RO 0
303 /* relocate code. Return -1 on error, required size if ptr is NULL,
304 otherwise copy code into buffer passed by the caller */
305 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, unsigned ptr_diff
)
308 unsigned offset
, length
, align
, i
, k
, f
;
314 pe_output_file(s1
, NULL
);
317 resolve_common_syms(s1
);
318 build_got_entries(s1
, 0);
325 if (s1
->verbose
== 2 && copy
)
326 printf(&"-----------------------------------------------------\n"[PTR_SIZE
*2 - 8]);
332 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
334 for(i
= 1; i
< s1
->nb_sections
; i
++) {
335 static const char shf
[] = {
336 SHF_ALLOC
|SHF_EXECINSTR
, SHF_ALLOC
, SHF_ALLOC
|SHF_WRITE
339 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
341 length
= s
->data_offset
;
345 n
= (s
->sh_addr
- addr
) + length
;
348 if (copy
) { /* final step: copy section data to memory */
349 if (s1
->verbose
== 2)
350 printf("%d: %-16s %p len %05x align %04x\n",
351 k
, s
->name
, (void*)s
->sh_addr
, length
, s
->sh_addralign
);
352 ptr
= (void*)s
->sh_addr
;
354 ptr
= (void*)(s
->sh_addr
+ ptr_diff
);
355 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
356 memset(ptr
, 0, length
);
358 memcpy(ptr
, s
->data
, length
);
362 align
= s
->sh_addralign
;
364 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
365 /* To avoid that x86 processors would reload cached instructions
366 each time when data is written in the near, we need to make
367 sure that code and data do not share the same 64 byte unit */
371 /* start new page for different permissions */
372 if (k
<= CONFIG_RUNMEM_RO
)
375 s
->sh_addralign
= align
;
376 addr
= k
? mem
+ ptr_diff
: mem
;
377 offset
+= -(addr
+ offset
) & (align
- 1);
378 s
->sh_addr
= mem
? addr
+ offset
: 0;
381 if (copy
== 2) { /* set permissions */
382 if (n
== 0) /* no data */
385 if (k
== 0) /* SHF_EXECINSTR has its own mapping */
389 if (f
>= CONFIG_RUNMEM_RO
) {
392 f
= 3; /* change only SHF_EXECINSTR to rwx */
395 if (s1
->verbose
== 2) {
396 printf("protect %3s %p len %05x\n",
397 &"rx\0ro\0rw\0rwx"[f
*3], (void*)addr
, (unsigned)n
);
399 if (protect_pages((void*)addr
, n
, f
) < 0)
400 return tcc_error_noabort(
401 "mprotect failed (did you mean to configure --with-selinux?)");
406 return PAGEALIGN(offset
);
413 s1
->run_function_table
= win64_add_function_table(s1
);
415 /* remove local symbols and free sections except symtab */
417 cleanup_sections(s1
);
421 /* relocate symbols */
422 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
423 /* relocate sections */
425 s1
->pe_imagebase
= mem
;
429 relocate_sections(s1
);
433 /* ------------------------------------------------------------- */
434 /* allow to run code in memory */
436 static int protect_pages(void *ptr
, unsigned long length
, int mode
)
439 static const unsigned char protect
[] = {
443 PAGE_EXECUTE_READWRITE
446 if (!VirtualProtect(ptr
, length
, protect
[mode
], &old
))
449 static const unsigned char protect
[] = {
450 PROT_READ
| PROT_EXEC
,
452 PROT_READ
| PROT_WRITE
,
453 PROT_READ
| PROT_WRITE
| PROT_EXEC
455 if (mprotect(ptr
, length
, protect
[mode
]))
457 /* XXX: BSD sometimes dump core with bad system call */
458 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
459 if (mode
== 0 || mode
== 3) {
460 void __clear_cache(void *beginning
, void *end
);
461 __clear_cache(ptr
, (char *)ptr
+ length
);
469 static void *win64_add_function_table(TCCState
*s1
)
473 p
= (void*)s1
->uw_pdata
->sh_addr
;
475 (RUNTIME_FUNCTION
*)p
,
476 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
484 static void win64_del_function_table(void *p
)
487 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
492 static void bt_link(TCCState
*s1
)
494 #ifdef CONFIG_TCC_BACKTRACE
498 if (!s1
->do_backtrace
)
500 rc
= tcc_get_symbol(s1
, "__rt_info");
503 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
504 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
505 rc
->elf_str
= (char *)symtab_section
->link
->data
;
506 if (PTR_SIZE
== 8 && !s1
->dwarf
)
507 rc
->prog_base
&= 0xffffffff00000000ULL
;
508 #ifdef CONFIG_TCC_BCHECK
509 if (s1
->do_bounds_check
) {
510 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
511 ((void(*)(void*,int))p
)(rc
->bounds_start
, 1);
514 rc
->next
= g_rc
, g_rc
= rc
, s1
->rc
= rc
;
516 set_exception_handler(), signal_set
= 1;
520 static void st_link(TCCState
*s1
)
523 s1
->next
= g_s1
, g_s1
= s1
;
528 /* remove 'el' from 'list' */
529 static void ptr_unlink(void *list
, void *e
, unsigned next
)
532 for (pp
= list
; !!(p
= *pp
); pp
= nn
) {
533 nn
= (void*)((char*)p
+ next
); /* nn = &p->next; */
541 static void st_unlink(TCCState
*s1
)
544 #ifdef CONFIG_TCC_BACKTRACE
545 ptr_unlink(&g_rc
, s1
->rc
, offsetof(rt_context
, next
));
547 ptr_unlink(&g_s1
, s1
, offsetof(TCCState
, next
));
551 LIBTCCAPI
void *_tcc_setjmp(TCCState
*s1
, void *p_jmp_buf
, void *func
, void *p_longjmp
)
553 s1
->run_lj
= p_longjmp
;
554 s1
->run_jb
= p_jmp_buf
;
555 #ifdef CONFIG_TCC_BACKTRACE
557 s1
->rc
->top_func
= func
;
562 LIBTCCAPI
void tcc_set_backtrace_func(TCCState
*s1
, void *data
, TCCBtFunc
*func
)
568 static TCCState
*rt_find_state(rt_frame
*f
)
575 if (NULL
== s
|| NULL
== s
->next
) {
576 /* play it safe in the simple case when there is only one state */
579 for (level
= 0; level
< 8; ++level
) {
580 if (rt_get_caller_pc(&pc
, f
, level
) < 0)
582 for (s
= g_s1
; s
; s
= s
->next
) {
583 if (pc
>= (addr_t
)s
->run_ptr
584 && pc
< (addr_t
)s
->run_ptr
+ s
->run_size
)
591 static void rt_exit(rt_frame
*f
, int code
)
595 s
= rt_find_state(f
);
597 if (s
&& s
->run_lj
) {
600 ((void(*)(void*,int))s
->run_lj
)(s
->run_jb
, code
);
605 /* ------------------------------------------------------------- */
606 #else // if defined CONFIG_TCC_BACKTRACE_ONLY
607 static void rt_exit(rt_frame
*f
, int code
)
611 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
612 /* ------------------------------------------------------------- */
613 #ifdef CONFIG_TCC_BACKTRACE
615 static int rt_vprintf(const char *fmt
, va_list ap
)
617 int ret
= vfprintf(stderr
, fmt
, ap
);
622 static int rt_printf(const char *fmt
, ...)
627 r
= rt_vprintf(fmt
, ap
);
632 static char *rt_elfsym(rt_context
*rc
, addr_t wanted_pc
, addr_t
*func_addr
)
635 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
636 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
637 if ((type
== STT_FUNC
|| type
== STT_GNU_IFUNC
)
638 && wanted_pc
>= esym
->st_value
639 && wanted_pc
< esym
->st_value
+ esym
->st_size
) {
640 *func_addr
= esym
->st_value
;
641 return rc
->elf_str
+ esym
->st_name
;
647 typedef struct bt_info
655 /* print the position in the source file of PC value 'pc' by reading
656 the stabs debug information */
657 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
, bt_info
*bi
)
660 addr_t func_addr
, last_pc
, pc
;
661 const char *incl_files
[INCLUDE_STACK_SIZE
];
662 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
669 last_pc
= (addr_t
)-1;
673 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
674 str
= rc
->stab_str
+ sym
->n_strx
;
677 switch(sym
->n_type
) {
685 if (sym
->n_strx
== 0) /* end of function */
689 /* Stab_Sym.n_value is only 32bits */
696 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
701 switch(sym
->n_type
) {
702 /* function start or end */
704 if (sym
->n_strx
== 0)
706 p
= strchr(str
, ':');
707 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
708 len
= sizeof func_name
;
709 pstrcpy(func_name
, len
, str
);
712 /* line number info */
715 last_line_num
= sym
->n_desc
;
716 last_incl_index
= incl_index
;
720 if (incl_index
< INCLUDE_STACK_SIZE
)
721 incl_files
[incl_index
++] = str
;
727 /* start/end of translation unit */
731 /* do not add path */
733 if (len
> 0 && str
[len
- 1] != '/')
734 incl_files
[incl_index
++] = str
;
739 last_pc
= (addr_t
)-1;
741 /* alternative file name (from #line or #include directives) */
744 incl_files
[incl_index
-1] = str
;
748 last_incl_index
= 0, func_name
[0] = 0, func_addr
= 0;
752 pstrcpy(bi
->file
, sizeof bi
->file
, incl_files
[--i
]);
753 bi
->line
= last_line_num
;
755 pstrcpy(bi
->func
, sizeof bi
->func
, func_name
);
756 bi
->func_pc
= func_addr
;
760 /* ------------------------------------------------------------- */
761 /* rt_printline - dwarf version */
763 #define MAX_128 ((8 * sizeof (long long) + 6) / 7)
765 #define DIR_TABLE_SIZE (64)
766 #define FILE_TABLE_SIZE (512)
768 #define dwarf_read_1(ln,end) \
769 ((ln) < (end) ? *(ln)++ : 0)
770 #define dwarf_read_2(ln,end) \
771 ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
772 #define dwarf_read_4(ln,end) \
773 ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
774 #define dwarf_read_8(ln,end) \
775 ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
776 #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \
777 switch (entry_format[j].form) { \
778 case DW_FORM_data1: (ln) += 1; break; \
779 case DW_FORM_data2: (ln) += 2; break; \
780 case DW_FORM_data4: (ln) += 3; break; \
781 case DW_FORM_data8: (ln) += 8; break; \
782 case DW_FORM_data16: (ln) += 16; break; \
783 case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \
784 default: goto next_line; \
787 static unsigned long long
788 dwarf_read_uleb128(unsigned char **ln
, unsigned char *end
)
790 unsigned char *cp
= *ln
;
791 unsigned long long retval
= 0;
794 for (i
= 0; i
< MAX_128
; i
++) {
795 unsigned long long byte
= dwarf_read_1(cp
, end
);
797 retval
|= (byte
& 0x7f) << (i
* 7);
798 if ((byte
& 0x80) == 0)
806 dwarf_read_sleb128(unsigned char **ln
, unsigned char *end
)
808 unsigned char *cp
= *ln
;
809 long long retval
= 0;
812 for (i
= 0; i
< MAX_128
; i
++) {
813 unsigned long long byte
= dwarf_read_1(cp
, end
);
815 retval
|= (byte
& 0x7f) << (i
* 7);
816 if ((byte
& 0x80) == 0) {
817 if ((byte
& 0x40) && (i
+ 1) * 7 < 64)
818 retval
|= -1LL << ((i
+ 1) * 7);
826 static addr_t
rt_printline_dwarf (rt_context
*rc
, addr_t wanted_pc
, bt_info
*bi
)
831 unsigned char *opcode_length
;
832 unsigned long long size
;
834 unsigned char version
;
835 unsigned int min_insn_length
;
836 unsigned int max_ops_per_insn
;
838 unsigned int line_range
;
839 unsigned int opcode_base
;
840 unsigned int opindex
;
845 unsigned long long value
;
850 unsigned int dir_size
;
852 char *dirs
[DIR_TABLE_SIZE
];
854 unsigned int filename_size
;
855 struct /*dwarf_filename_struct*/ {
856 unsigned int dir_entry
;
858 } filename_table
[FILE_TABLE_SIZE
];
872 while (ln
< rc
->dwarf_line_end
) {
882 size
= dwarf_read_4(ln
, rc
->dwarf_line_end
);
883 if (size
== 0xffffffffu
) // dwarf 64
884 length
= 8, size
= dwarf_read_8(ln
, rc
->dwarf_line_end
);
886 if (end
< ln
|| end
> rc
->dwarf_line_end
)
888 version
= dwarf_read_2(ln
, end
);
890 ln
+= length
+ 2; // address size, segment selector, prologue Length
892 ln
+= length
; // prologue Length
893 min_insn_length
= dwarf_read_1(ln
, end
);
895 max_ops_per_insn
= dwarf_read_1(ln
, end
);
897 max_ops_per_insn
= 1;
898 ln
++; // Initial value of 'is_stmt'
899 line_base
= dwarf_read_1(ln
, end
);
900 line_base
|= line_base
>= 0x80 ? ~0xff : 0;
901 line_range
= dwarf_read_1(ln
, end
);
902 opcode_base
= dwarf_read_1(ln
, end
);
904 ln
+= opcode_base
- 1;
907 col
= dwarf_read_1(ln
, end
);
908 for (i
= 0; i
< col
; i
++) {
909 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
910 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
912 dir_size
= dwarf_read_uleb128(&ln
, end
);
913 for (i
= 0; i
< dir_size
; i
++) {
914 for (j
= 0; j
< col
; j
++) {
915 if (entry_format
[j
].type
== DW_LNCT_path
) {
916 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
919 value
= length
== 4 ? dwarf_read_4(ln
, end
)
920 : dwarf_read_8(ln
, end
);
921 if (i
< DIR_TABLE_SIZE
)
922 dirs
[i
] = (char *)rc
->dwarf_line_str
+ value
;
924 length
== 4 ? dwarf_read_4(ln
, end
)
925 : dwarf_read_8(ln
, end
);
929 dwarf_ignore_type(ln
, end
);
932 col
= dwarf_read_1(ln
, end
);
933 for (i
= 0; i
< col
; i
++) {
934 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
935 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
937 filename_size
= dwarf_read_uleb128(&ln
, end
);
938 for (i
= 0; i
< filename_size
; i
++)
939 for (j
= 0; j
< col
; j
++) {
940 if (entry_format
[j
].type
== DW_LNCT_path
) {
941 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
943 value
= length
== 4 ? dwarf_read_4(ln
, end
)
944 : dwarf_read_8(ln
, end
);
945 if (i
< FILE_TABLE_SIZE
)
946 filename_table
[i
].name
=
947 (char *)rc
->dwarf_line_str
+ value
;
949 else if (entry_format
[j
].type
== DW_LNCT_directory_index
) {
950 switch (entry_format
[j
].form
) {
951 case DW_FORM_data1
: value
= dwarf_read_1(ln
, end
); break;
952 case DW_FORM_data2
: value
= dwarf_read_2(ln
, end
); break;
953 case DW_FORM_data4
: value
= dwarf_read_4(ln
, end
); break;
954 case DW_FORM_udata
: value
= dwarf_read_uleb128(&ln
, end
); break;
955 default: goto next_line
;
957 if (i
< FILE_TABLE_SIZE
)
958 filename_table
[i
].dir_entry
= value
;
961 dwarf_ignore_type(ln
, end
);
965 while ((dwarf_read_1(ln
, end
))) {
967 if (++dir_size
< DIR_TABLE_SIZE
)
968 dirs
[dir_size
- 1] = (char *)ln
- 1;
970 while (dwarf_read_1(ln
, end
)) {}
972 while ((dwarf_read_1(ln
, end
))) {
973 if (++filename_size
< FILE_TABLE_SIZE
) {
974 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
975 while (dwarf_read_1(ln
, end
)) {}
976 filename_table
[filename_size
- 1].dir_entry
=
977 dwarf_read_uleb128(&ln
, end
);
980 while (dwarf_read_1(ln
, end
)) {}
981 dwarf_read_uleb128(&ln
, end
);
983 dwarf_read_uleb128(&ln
, end
); // time
984 dwarf_read_uleb128(&ln
, end
); // size
987 if (filename_size
>= 1)
988 filename
= filename_table
[0].name
;
991 i
= dwarf_read_1(ln
, end
);
992 if (i
>= opcode_base
) {
993 if (max_ops_per_insn
== 1)
994 pc
+= ((i
- opcode_base
) / line_range
) * min_insn_length
;
996 pc
+= (opindex
+ (i
- opcode_base
) / line_range
) /
997 max_ops_per_insn
* min_insn_length
;
998 opindex
= (opindex
+ (i
- opcode_base
) / line_range
) %
1001 i
= (int)((i
- opcode_base
) % line_range
) + line_base
;
1003 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
1010 len
= dwarf_read_uleb128(&ln
, end
);
1015 switch (dwarf_read_1(cp
, end
)) {
1016 case DW_LNE_end_sequence
:
1018 case DW_LNE_set_address
:
1020 pc
= dwarf_read_4(cp
, end
);
1022 pc
= dwarf_read_8(cp
, end
);
1024 #if defined TCC_TARGET_MACHO
1025 pc
+= rc
->prog_base
;
1029 case DW_LNE_define_file
: /* deprecated */
1030 if (++filename_size
< FILE_TABLE_SIZE
) {
1031 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
1032 while (dwarf_read_1(ln
, end
)) {}
1033 filename_table
[filename_size
- 1].dir_entry
=
1034 dwarf_read_uleb128(&ln
, end
);
1037 while (dwarf_read_1(ln
, end
)) {}
1038 dwarf_read_uleb128(&ln
, end
);
1040 dwarf_read_uleb128(&ln
, end
); // time
1041 dwarf_read_uleb128(&ln
, end
); // size
1043 case DW_LNE_hi_user
- 1:
1044 function
= (char *)cp
;
1051 case DW_LNS_advance_pc
:
1052 if (max_ops_per_insn
== 1)
1053 pc
+= dwarf_read_uleb128(&ln
, end
) * min_insn_length
;
1055 unsigned long long off
= dwarf_read_uleb128(&ln
, end
);
1057 pc
+= (opindex
+ off
) / max_ops_per_insn
*
1059 opindex
= (opindex
+ off
) % max_ops_per_insn
;
1063 case DW_LNS_advance_line
:
1064 line
+= dwarf_read_sleb128(&ln
, end
);
1066 case DW_LNS_set_file
:
1067 i
= dwarf_read_uleb128(&ln
, end
);
1068 i
-= i
> 0 && version
< 5;
1069 if (i
< FILE_TABLE_SIZE
&& i
< filename_size
)
1070 filename
= filename_table
[i
].name
;
1072 case DW_LNS_const_add_pc
:
1073 if (max_ops_per_insn
== 1)
1074 pc
+= ((255 - opcode_base
) / line_range
) * min_insn_length
;
1076 unsigned int off
= (255 - opcode_base
) / line_range
;
1078 pc
+= ((opindex
+ off
) / max_ops_per_insn
) *
1080 opindex
= (opindex
+ off
) % max_ops_per_insn
;
1084 case DW_LNS_fixed_advance_pc
:
1085 i
= dwarf_read_2(ln
, end
);
1091 for (j
= 0; j
< opcode_length
[i
- 1]; j
++)
1092 dwarf_read_uleb128 (&ln
, end
);
1100 filename
= function
= NULL
, func_addr
= 0;
1103 pstrcpy(bi
->file
, sizeof bi
->file
, filename
), bi
->line
= line
;
1105 pstrcpy(bi
->func
, sizeof bi
->func
, function
);
1106 bi
->func_pc
= func_addr
;
1107 return (addr_t
)func_addr
;
1109 /* ------------------------------------------------------------- */
1110 #ifndef CONFIG_TCC_BACKTRACE_ONLY
1113 int _tcc_backtrace(rt_frame
*f
, const char *fmt
, va_list ap
)
1115 rt_context
*rc
, *rc2
;
1117 char skip
[40], msg
[200];
1118 int i
, level
, ret
, n
, one
;
1121 addr_t (*getinfo
)(rt_context
*, addr_t
, bt_info
*);
1124 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
1125 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
1126 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
1130 /* hack for bcheck.c:dprintf(): one level, no newline */
1131 if (fmt
[0] == '\001')
1133 vsnprintf(msg
, sizeof msg
, fmt
, ap
);
1137 getinfo
= rt_printline
, n
= 6;
1140 getinfo
= rt_printline_dwarf
;
1141 if (rc
->num_callers
)
1142 n
= rc
->num_callers
;
1145 for (i
= level
= 0; level
< n
; i
++) {
1146 ret
= rt_get_caller_pc(&pc
, f
, i
);
1149 memset(&bi
, 0, sizeof bi
);
1150 for (rc2
= rc
; rc2
; rc2
= rc2
->next
) {
1151 if (getinfo(rc2
, pc
, &bi
))
1153 /* we try symtab symbols (no line number info) */
1154 if (!!(a
= rt_elfsym(rc2
, pc
, &bi
.func_pc
))) {
1155 pstrcpy(bi
.func
, sizeof bi
.func
, a
);
1159 //fprintf(stderr, "%d rc %p %p\n", i, (void*)pcfunc, (void*)pc);
1160 if (skip
[0] && strstr(bi
.file
, skip
))
1162 #ifndef CONFIG_TCC_BACKTRACE_ONLY
1164 TCCState
*s
= rt_find_state(f
);
1165 if (s
&& s
->bt_func
) {
1169 bi
.file
[0] ? bi
.file
: NULL
,
1171 bi
.func
[0] ? bi
.func
: NULL
,
1172 level
== 0 ? msg
: NULL
1181 rt_printf("%s:%d", bi
.file
, bi
.line
);
1183 rt_printf("0x%08llx", (long long)pc
);
1185 rt_printf(": %s %s", level
? "by" : "at", bi
.func
[0] ? bi
.func
: "???");
1187 rt_printf(": %s", msg
);
1193 #ifndef CONFIG_TCC_BACKTRACE_ONLY
1198 && bi
.func_pc
== (addr_t
)rc2
->top_func
)
1206 /* emit a run time error at position 'pc' */
1207 static int rt_error(rt_frame
*f
, const char *fmt
, ...)
1209 va_list ap
; char msg
[200]; int ret
;
1211 snprintf(msg
, sizeof msg
, "RUNTIME ERROR: %s", fmt
);
1212 ret
= _tcc_backtrace(f
, msg
, ap
);
1217 /* ------------------------------------------------------------- */
1220 # include <signal.h>
1221 # ifndef __OpenBSD__
1222 # include <sys/ucontext.h>
1225 # define ucontext_t CONTEXT
1228 /* translate from ucontext_t* to internal rt_context * */
1229 static void rt_getcontext(ucontext_t
*uc
, rt_frame
*rc
)
1235 #elif defined _WIN32
1239 #elif defined __i386__
1240 # if defined(__APPLE__)
1241 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
1242 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
1243 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1244 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
1245 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
1246 # elif defined(__dietlibc__)
1247 rc
->ip
= uc
->uc_mcontext
.eip
;
1248 rc
->fp
= uc
->uc_mcontext
.ebp
;
1249 # elif defined(__NetBSD__)
1250 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
1251 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
1252 # elif defined(__OpenBSD__)
1253 rc
->ip
= uc
->sc_eip
;
1254 rc
->fp
= uc
->sc_ebp
;
1255 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
1256 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
1257 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
1259 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1260 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
1262 #elif defined(__x86_64__)
1263 # if defined(__APPLE__)
1264 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
1265 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
1266 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1267 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
1268 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
1269 # elif defined(__NetBSD__)
1270 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
1271 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
1272 # elif defined(__OpenBSD__)
1273 rc
->ip
= uc
->sc_rip
;
1274 rc
->fp
= uc
->sc_rbp
;
1276 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1277 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
1279 #elif defined(__arm__) && defined(__NetBSD__)
1280 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1281 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1282 #elif defined(__arm__) && defined(__OpenBSD__)
1284 rc
->fp
= uc
->sc_r11
;
1285 #elif defined(__arm__) && defined(__FreeBSD__)
1286 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1287 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1288 #elif defined(__arm__)
1289 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
1290 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
1291 #elif defined(__aarch64__) && defined(__APPLE__)
1293 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
1294 rc
->ip
= uc
->uc_mcontext
->__ss
.__pc
;
1295 rc
->fp
= uc
->uc_mcontext
->__ss
.__fp
;
1296 #elif defined(__aarch64__) && defined(__FreeBSD__)
1297 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
1298 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
1299 #elif defined(__aarch64__) && defined(__NetBSD__)
1300 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1301 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1302 #elif defined(__aarch64__) && defined(__OpenBSD__)
1303 rc
->ip
= uc
->sc_elr
;
1304 rc
->fp
= uc
->sc_x
[29];
1305 #elif defined(__aarch64__)
1306 rc
->ip
= uc
->uc_mcontext
.pc
;
1307 rc
->fp
= uc
->uc_mcontext
.regs
[29];
1308 #elif defined(__riscv) && defined(__OpenBSD__)
1309 rc
->ip
= uc
->sc_sepc
;
1310 rc
->fp
= uc
->sc_s
[0];
1311 #elif defined(__riscv)
1312 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
1313 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
1317 /* ------------------------------------------------------------- */
1319 /* signal handler for fatal errors */
1320 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
1323 rt_getcontext(puc
, &f
);
1327 switch(siginf
->si_code
) {
1330 rt_error(&f
, "division by zero");
1333 rt_error(&f
, "floating point exception");
1339 rt_error(&f
, "invalid memory access");
1342 rt_error(&f
, "illegal instruction");
1345 rt_error(&f
, "abort() called");
1348 rt_error(&f
, "caught signal %d", signum
);
1354 sigaddset(&s
, signum
);
1355 sigprocmask(SIG_UNBLOCK
, &s
, NULL
);
1361 # define SA_SIGINFO 0x00000004u
1364 /* Generate a stack backtrace when a CPU exception occurs. */
1365 static void set_exception_handler(void)
1367 struct sigaction sigact
;
1368 /* install TCC signal handlers to print debug info on fatal
1370 sigemptyset (&sigact
.sa_mask
);
1371 sigact
.sa_flags
= SA_SIGINFO
; //| SA_RESETHAND;
1372 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
1373 sigact
.sa_flags
|= SA_ONSTACK
;
1375 sigact
.sa_sigaction
= sig_error
;
1376 sigaction(SIGFPE
, &sigact
, NULL
);
1377 sigaction(SIGILL
, &sigact
, NULL
);
1378 sigaction(SIGSEGV
, &sigact
, NULL
);
1379 sigaction(SIGBUS
, &sigact
, NULL
);
1380 sigaction(SIGABRT
, &sigact
, NULL
);
1382 /* This allows stack overflow to be reported instead of a SEGV */
1385 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
1388 ss
.ss_size
= SIGSTKSZ
;
1390 sigaltstack(&ss
, NULL
);
1397 /* signal handler for fatal errors */
1398 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
1402 rt_getcontext(ex_info
->ContextRecord
, &f
);
1404 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
1405 case EXCEPTION_ACCESS_VIOLATION
:
1406 rt_error(&f
, "invalid memory access");
1408 case EXCEPTION_STACK_OVERFLOW
:
1409 rt_error(&f
, "stack overflow");
1411 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
1412 rt_error(&f
, "division by zero");
1414 case EXCEPTION_BREAKPOINT
:
1415 case EXCEPTION_SINGLE_STEP
:
1416 f
.ip
= *(addr_t
*)f
.sp
;
1417 rt_error(&f
, "breakpoint/single-step exception:");
1418 return EXCEPTION_CONTINUE_SEARCH
;
1420 rt_error(&f
, "caught exception %08x", code
);
1424 return EXCEPTION_EXECUTE_HANDLER
;
1427 /* Generate a stack backtrace when a CPU exception occurs. */
1428 static void set_exception_handler(void)
1430 SetUnhandledExceptionFilter(cpu_exception_handler
);
1435 /* ------------------------------------------------------------- */
1436 /* return the PC at frame level 'level'. Return negative if not found */
1437 #if defined(__i386__) || defined(__x86_64__)
1438 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1449 /* XXX: check address validity with program info */
1450 fp
= ((addr_t
*)fp
)[0];
1452 *paddr
= ((addr_t
*)fp
)[1];
1457 /* XXX: only supports linux/bsd */
1458 #elif defined(__arm__) && !defined(_WIN32)
1459 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1470 fp
= ((addr_t
*)fp
)[0];
1472 *paddr
= ((addr_t
*)fp
)[2];
1477 #elif defined(__aarch64__)
1478 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1489 fp
= ((addr_t
*)fp
)[0];
1491 *paddr
= ((addr_t
*)fp
)[1];
1496 #elif defined(__riscv)
1497 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1508 fp
= ((addr_t
*)fp
)[-2];
1510 *paddr
= ((addr_t
*)fp
)[-1];
1516 #warning add arch specific rt_get_caller_pc()
1517 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1523 #else // for runmain.c:exit(); when CONFIG_TCC_BACKTRACE == 0 */
1524 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*f
, int level
)
1531 #endif /* CONFIG_TCC_BACKTRACE */
1532 /* ------------------------------------------------------------- */
1533 #ifdef CONFIG_TCC_STATIC
1535 /* dummy function for profiling */
1536 ST_FUNC
void *dlopen(const char *filename
, int flag
)
1541 ST_FUNC
void dlclose(void *p
)
1545 ST_FUNC
const char *dlerror(void)
1550 typedef struct TCCSyms
{
1556 /* add the symbol you want here if no dynamic linking is done */
1557 static TCCSyms tcc_syms
[] = {
1558 #if !defined(CONFIG_TCCBOOT)
1559 #define TCCSYM(a) { #a, &a, },
1569 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
1573 while (p
->str
!= NULL
) {
1574 if (!strcmp(p
->str
, symbol
))
1581 #endif /* CONFIG_TCC_STATIC */
1582 #endif /* TCC_IS_NATIVE */
1583 /* ------------------------------------------------------------- */