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 /* free loaded dlls array */
183 dynarray_reset(&s1
->loaded_dlls
, &s1
->nb_loaded_dlls
);
184 /* unmap or unprotect and free memory */
193 /* unprotect memory to make it usable for malloc again */
194 protect_pages((void*)PAGEALIGN(ptr
), size
- PAGESIZE
, 2 /*rw*/);
196 win64_del_function_table(s1
->run_function_table
);
202 /* launch the compiled program with the given arguments */
203 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
205 int (*prog_main
)(int, char **, char **), ret
;
209 #if defined(__APPLE__) || defined(__FreeBSD__)
211 #elif defined(__OpenBSD__) || defined(__NetBSD__)
212 extern char **environ
;
213 char **envp
= environ
;
215 char **envp
= environ
;
218 /* tcc -dt -run ... nothing to do if no main() */
219 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, "main", 0, 1))
222 tcc_add_symbol(s1
, "__rt_exit", rt_exit
);
224 s1
->run_main
= top_sym
= "_start";
226 tcc_add_support(s1
, "runmain.o");
227 s1
->run_main
= "_runmain";
230 if (tcc_relocate(s1
) < 0)
233 prog_main
= (void*)get_sym_addr(s1
, s1
->run_main
, 1, 1);
234 if ((addr_t
)-1 == (addr_t
)prog_main
)
236 errno
= 0; /* clean errno value */
240 ret
= tcc_setjmp(s1
, main_jb
, tcc_get_symbol(s1
, top_sym
));
242 ret
= prog_main(argc
, argv
, envp
);
246 if (s1
->dflag
& 16 && ret
) /* tcc -dt -run ... */
247 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
251 /* ------------------------------------------------------------- */
252 /* remove all STB_LOCAL symbols */
253 static void cleanup_symbols(TCCState
*s1
)
255 Section
*s
= s1
->symtab
;
256 int sym_index
, end_sym
= s
->data_offset
/ sizeof (ElfSym
);
258 s
->data_offset
= s
->link
->data_offset
= s
->hash
->data_offset
= 0;
260 /* add global symbols again */
261 for (sym_index
= 1; sym_index
< end_sym
; ++sym_index
) {
262 ElfW(Sym
) *sym
= &((ElfW(Sym
) *)s
->data
)[sym_index
];
263 const char *name
= (char *)s
->link
->data
+ sym
->st_name
;
264 if (ELFW(ST_BIND
)(sym
->st_info
) == STB_LOCAL
)
266 //printf("sym %s\n", name);
267 put_elf_sym(s
, sym
->st_value
, sym
->st_size
, sym
->st_info
, sym
->st_other
, sym
->st_shndx
, name
);
271 /* free all sections except symbols */
272 static void cleanup_sections(TCCState
*s1
)
274 struct { Section
**secs
; int nb_secs
; } *p
= (void*)&s1
->sections
;
277 for (i
= --f
; i
< p
->nb_secs
; i
++) {
278 Section
*s
= p
->secs
[i
];
279 if (s
== s1
->symtab
|| s
== s1
->symtab
->link
|| s
== s1
->symtab
->hash
) {
280 s
->data
= tcc_realloc(s
->data
, s
->data_allocated
= s
->data_offset
);
282 free_section(s
), tcc_free(s
), p
->secs
[i
] = NULL
;
288 /* ------------------------------------------------------------- */
289 /* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */
290 /* 1 = .text rx other rw (memory >= 3 pages) */
291 /* 2 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
293 /* Some targets implement secutiry options that do not allow write in
294 executable code. These targets need CONFIG_RUNMEM_RO=1.
295 The disadvantage of this is that it requires a little bit more memory. */
297 #ifndef CONFIG_RUNMEM_RO
299 # define CONFIG_RUNMEM_RO 1
301 # define CONFIG_RUNMEM_RO 0
305 /* relocate code. Return -1 on error, required size if ptr is NULL,
306 otherwise copy code into buffer passed by the caller */
307 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, unsigned ptr_diff
)
310 unsigned offset
, length
, align
, i
, k
, f
;
316 pe_output_file(s1
, NULL
);
319 resolve_common_syms(s1
);
320 build_got_entries(s1
, 0);
327 if (s1
->verbose
== 2 && copy
)
328 printf(&"-----------------------------------------------------\n"[PTR_SIZE
*2 - 8]);
334 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
336 for(i
= 1; i
< s1
->nb_sections
; i
++) {
337 static const char shf
[] = {
338 SHF_ALLOC
|SHF_EXECINSTR
, SHF_ALLOC
, SHF_ALLOC
|SHF_WRITE
341 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
343 length
= s
->data_offset
;
347 n
= (s
->sh_addr
- addr
) + length
;
350 if (copy
) { /* final step: copy section data to memory */
351 if (s1
->verbose
== 2)
352 printf("%d: %-16s %p len %05x align %04x\n",
353 k
, s
->name
, (void*)s
->sh_addr
, length
, s
->sh_addralign
);
354 ptr
= (void*)s
->sh_addr
;
356 ptr
= (void*)(s
->sh_addr
+ ptr_diff
);
357 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
358 memset(ptr
, 0, length
);
360 memcpy(ptr
, s
->data
, length
);
364 align
= s
->sh_addralign
;
366 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
367 /* To avoid that x86 processors would reload cached instructions
368 each time when data is written in the near, we need to make
369 sure that code and data do not share the same 64 byte unit */
373 /* start new page for different permissions */
374 if (k
<= CONFIG_RUNMEM_RO
)
377 s
->sh_addralign
= align
;
378 addr
= k
? mem
+ ptr_diff
: mem
;
379 offset
+= -(addr
+ offset
) & (align
- 1);
380 s
->sh_addr
= mem
? addr
+ offset
: 0;
383 if (copy
== 2) { /* set permissions */
384 if (n
== 0) /* no data */
387 if (k
== 0) /* SHF_EXECINSTR has its own mapping */
391 if (f
>= CONFIG_RUNMEM_RO
) {
394 f
= 3; /* change only SHF_EXECINSTR to rwx */
397 if (s1
->verbose
== 2) {
398 printf("protect %3s %p len %05x\n",
399 &"rx\0ro\0rw\0rwx"[f
*3], (void*)addr
, (unsigned)n
);
401 if (protect_pages((void*)addr
, n
, f
) < 0)
402 return tcc_error_noabort(
403 "mprotect failed (did you mean to configure --with-selinux?)");
408 return PAGEALIGN(offset
);
415 s1
->run_function_table
= win64_add_function_table(s1
);
417 /* remove local symbols and free sections except symtab */
419 cleanup_sections(s1
);
423 /* relocate symbols */
424 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
425 /* relocate sections */
427 s1
->pe_imagebase
= mem
;
431 relocate_sections(s1
);
435 /* ------------------------------------------------------------- */
436 /* allow to run code in memory */
438 static int protect_pages(void *ptr
, unsigned long length
, int mode
)
441 static const unsigned char protect
[] = {
445 PAGE_EXECUTE_READWRITE
448 if (!VirtualProtect(ptr
, length
, protect
[mode
], &old
))
451 static const unsigned char protect
[] = {
452 PROT_READ
| PROT_EXEC
,
454 PROT_READ
| PROT_WRITE
,
455 PROT_READ
| PROT_WRITE
| PROT_EXEC
457 if (mprotect(ptr
, length
, protect
[mode
]))
459 /* XXX: BSD sometimes dump core with bad system call */
460 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
461 if (mode
== 0 || mode
== 3) {
462 void __clear_cache(void *beginning
, void *end
);
463 __clear_cache(ptr
, (char *)ptr
+ length
);
471 static void *win64_add_function_table(TCCState
*s1
)
475 p
= (void*)s1
->uw_pdata
->sh_addr
;
477 (RUNTIME_FUNCTION
*)p
,
478 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
486 static void win64_del_function_table(void *p
)
489 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
494 static void bt_link(TCCState
*s1
)
496 #ifdef CONFIG_TCC_BACKTRACE
500 if (!s1
->do_backtrace
)
502 rc
= tcc_get_symbol(s1
, "__rt_info");
505 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
506 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
507 rc
->elf_str
= (char *)symtab_section
->link
->data
;
508 if (PTR_SIZE
== 8 && !s1
->dwarf
)
509 rc
->prog_base
&= 0xffffffff00000000ULL
;
510 #ifdef CONFIG_TCC_BCHECK
511 if (s1
->do_bounds_check
) {
512 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
513 ((void(*)(void*,int))p
)(rc
->bounds_start
, 1);
516 rc
->next
= g_rc
, g_rc
= rc
, s1
->rc
= rc
;
518 set_exception_handler(), signal_set
= 1;
522 static void st_link(TCCState
*s1
)
525 s1
->next
= g_s1
, g_s1
= s1
;
530 /* remove 'el' from 'list' */
531 static void ptr_unlink(void *list
, void *e
, unsigned next
)
534 for (pp
= list
; !!(p
= *pp
); pp
= nn
) {
535 nn
= (void*)((char*)p
+ next
); /* nn = &p->next; */
543 static void st_unlink(TCCState
*s1
)
546 #ifdef CONFIG_TCC_BACKTRACE
547 ptr_unlink(&g_rc
, s1
->rc
, offsetof(rt_context
, next
));
549 ptr_unlink(&g_s1
, s1
, offsetof(TCCState
, next
));
553 LIBTCCAPI
void *_tcc_setjmp(TCCState
*s1
, void *p_jmp_buf
, void *func
, void *p_longjmp
)
555 s1
->run_lj
= p_longjmp
;
556 s1
->run_jb
= p_jmp_buf
;
557 #ifdef CONFIG_TCC_BACKTRACE
559 s1
->rc
->top_func
= func
;
564 LIBTCCAPI
void tcc_set_backtrace_func(TCCState
*s1
, void *data
, TCCBtFunc
*func
)
570 static TCCState
*rt_find_state(rt_frame
*f
)
577 if (NULL
== s
|| NULL
== s
->next
) {
578 /* play it safe in the simple case when there is only one state */
581 for (level
= 0; level
< 8; ++level
) {
582 if (rt_get_caller_pc(&pc
, f
, level
) < 0)
584 for (s
= g_s1
; s
; s
= s
->next
) {
585 if (pc
>= (addr_t
)s
->run_ptr
586 && pc
< (addr_t
)s
->run_ptr
+ s
->run_size
)
593 static void rt_exit(rt_frame
*f
, int code
)
597 s
= rt_find_state(f
);
599 if (s
&& s
->run_lj
) {
602 ((void(*)(void*,int))s
->run_lj
)(s
->run_jb
, code
);
607 /* ------------------------------------------------------------- */
608 #else // if defined CONFIG_TCC_BACKTRACE_ONLY
609 static void rt_exit(rt_frame
*f
, int code
)
613 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
614 /* ------------------------------------------------------------- */
615 #ifdef CONFIG_TCC_BACKTRACE
617 static int rt_vprintf(const char *fmt
, va_list ap
)
619 int ret
= vfprintf(stderr
, fmt
, ap
);
624 static int rt_printf(const char *fmt
, ...)
629 r
= rt_vprintf(fmt
, ap
);
634 static char *rt_elfsym(rt_context
*rc
, addr_t wanted_pc
, addr_t
*func_addr
)
637 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
638 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
639 if ((type
== STT_FUNC
|| type
== STT_GNU_IFUNC
)
640 && wanted_pc
>= esym
->st_value
641 && wanted_pc
< esym
->st_value
+ esym
->st_size
) {
642 *func_addr
= esym
->st_value
;
643 return rc
->elf_str
+ esym
->st_name
;
649 typedef struct bt_info
657 /* print the position in the source file of PC value 'pc' by reading
658 the stabs debug information */
659 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
, bt_info
*bi
)
662 addr_t func_addr
, last_pc
, pc
;
663 const char *incl_files
[INCLUDE_STACK_SIZE
];
664 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
671 last_pc
= (addr_t
)-1;
675 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
676 str
= rc
->stab_str
+ sym
->n_strx
;
679 switch(sym
->n_type
) {
687 if (sym
->n_strx
== 0) /* end of function */
691 /* Stab_Sym.n_value is only 32bits */
698 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
703 switch(sym
->n_type
) {
704 /* function start or end */
706 if (sym
->n_strx
== 0)
708 p
= strchr(str
, ':');
709 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
710 len
= sizeof func_name
;
711 pstrcpy(func_name
, len
, str
);
714 /* line number info */
717 last_line_num
= sym
->n_desc
;
718 last_incl_index
= incl_index
;
722 if (incl_index
< INCLUDE_STACK_SIZE
)
723 incl_files
[incl_index
++] = str
;
729 /* start/end of translation unit */
733 /* do not add path */
735 if (len
> 0 && str
[len
- 1] != '/')
736 incl_files
[incl_index
++] = str
;
741 last_pc
= (addr_t
)-1;
743 /* alternative file name (from #line or #include directives) */
746 incl_files
[incl_index
-1] = str
;
750 last_incl_index
= 0, func_name
[0] = 0, func_addr
= 0;
754 pstrcpy(bi
->file
, sizeof bi
->file
, incl_files
[--i
]);
755 bi
->line
= last_line_num
;
757 pstrcpy(bi
->func
, sizeof bi
->func
, func_name
);
758 bi
->func_pc
= func_addr
;
762 /* ------------------------------------------------------------- */
763 /* rt_printline - dwarf version */
765 #define MAX_128 ((8 * sizeof (long long) + 6) / 7)
767 #define DIR_TABLE_SIZE (64)
768 #define FILE_TABLE_SIZE (512)
770 #define dwarf_read_1(ln,end) \
771 ((ln) < (end) ? *(ln)++ : 0)
772 #define dwarf_read_2(ln,end) \
773 ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
774 #define dwarf_read_4(ln,end) \
775 ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
776 #define dwarf_read_8(ln,end) \
777 ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
778 #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \
779 switch (entry_format[j].form) { \
780 case DW_FORM_data1: (ln) += 1; break; \
781 case DW_FORM_data2: (ln) += 2; break; \
782 case DW_FORM_data4: (ln) += 3; break; \
783 case DW_FORM_data8: (ln) += 8; break; \
784 case DW_FORM_data16: (ln) += 16; break; \
785 case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \
786 default: goto next_line; \
789 static unsigned long long
790 dwarf_read_uleb128(unsigned char **ln
, unsigned char *end
)
792 unsigned char *cp
= *ln
;
793 unsigned long long retval
= 0;
796 for (i
= 0; i
< MAX_128
; i
++) {
797 unsigned long long byte
= dwarf_read_1(cp
, end
);
799 retval
|= (byte
& 0x7f) << (i
* 7);
800 if ((byte
& 0x80) == 0)
808 dwarf_read_sleb128(unsigned char **ln
, unsigned char *end
)
810 unsigned char *cp
= *ln
;
811 long long retval
= 0;
814 for (i
= 0; i
< MAX_128
; i
++) {
815 unsigned long long byte
= dwarf_read_1(cp
, end
);
817 retval
|= (byte
& 0x7f) << (i
* 7);
818 if ((byte
& 0x80) == 0) {
819 if ((byte
& 0x40) && (i
+ 1) * 7 < 64)
820 retval
|= -1LL << ((i
+ 1) * 7);
828 static addr_t
rt_printline_dwarf (rt_context
*rc
, addr_t wanted_pc
, bt_info
*bi
)
833 unsigned char *opcode_length
;
834 unsigned long long size
;
836 unsigned char version
;
837 unsigned int min_insn_length
;
838 unsigned int max_ops_per_insn
;
840 unsigned int line_range
;
841 unsigned int opcode_base
;
842 unsigned int opindex
;
847 unsigned long long value
;
852 unsigned int dir_size
;
854 char *dirs
[DIR_TABLE_SIZE
];
856 unsigned int filename_size
;
857 struct dwarf_filename_struct
{
858 unsigned int dir_entry
;
860 } filename_table
[FILE_TABLE_SIZE
];
874 while (ln
< rc
->dwarf_line_end
) {
884 size
= dwarf_read_4(ln
, rc
->dwarf_line_end
);
885 if (size
== 0xffffffffu
) // dwarf 64
886 length
= 8, size
= dwarf_read_8(ln
, rc
->dwarf_line_end
);
888 if (end
< ln
|| end
> rc
->dwarf_line_end
)
890 version
= dwarf_read_2(ln
, end
);
892 ln
+= length
+ 2; // address size, segment selector, prologue Length
894 ln
+= length
; // prologue Length
895 min_insn_length
= dwarf_read_1(ln
, end
);
897 max_ops_per_insn
= dwarf_read_1(ln
, end
);
899 max_ops_per_insn
= 1;
900 ln
++; // Initial value of 'is_stmt'
901 line_base
= dwarf_read_1(ln
, end
);
902 line_base
|= line_base
>= 0x80 ? ~0xff : 0;
903 line_range
= dwarf_read_1(ln
, end
);
904 opcode_base
= dwarf_read_1(ln
, end
);
906 ln
+= opcode_base
- 1;
909 col
= dwarf_read_1(ln
, end
);
910 for (i
= 0; i
< col
; i
++) {
911 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
912 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
914 dir_size
= dwarf_read_uleb128(&ln
, end
);
915 for (i
= 0; i
< dir_size
; i
++) {
916 for (j
= 0; j
< col
; j
++) {
917 if (entry_format
[j
].type
== DW_LNCT_path
) {
918 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
921 value
= length
== 4 ? dwarf_read_4(ln
, end
)
922 : dwarf_read_8(ln
, end
);
923 if (i
< DIR_TABLE_SIZE
)
924 dirs
[i
] = (char *)rc
->dwarf_line_str
+ value
;
926 length
== 4 ? dwarf_read_4(ln
, end
)
927 : dwarf_read_8(ln
, end
);
931 dwarf_ignore_type(ln
, end
);
934 col
= dwarf_read_1(ln
, end
);
935 for (i
= 0; i
< col
; i
++) {
936 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
937 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
939 filename_size
= dwarf_read_uleb128(&ln
, end
);
940 for (i
= 0; i
< filename_size
; i
++)
941 for (j
= 0; j
< col
; j
++) {
942 if (entry_format
[j
].type
== DW_LNCT_path
) {
943 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
945 value
= length
== 4 ? dwarf_read_4(ln
, end
)
946 : dwarf_read_8(ln
, end
);
947 if (i
< FILE_TABLE_SIZE
)
948 filename_table
[i
].name
=
949 (char *)rc
->dwarf_line_str
+ value
;
951 else if (entry_format
[j
].type
== DW_LNCT_directory_index
) {
952 switch (entry_format
[j
].form
) {
953 case DW_FORM_data1
: value
= dwarf_read_1(ln
, end
); break;
954 case DW_FORM_data2
: value
= dwarf_read_2(ln
, end
); break;
955 case DW_FORM_data4
: value
= dwarf_read_4(ln
, end
); break;
956 case DW_FORM_udata
: value
= dwarf_read_uleb128(&ln
, end
); break;
957 default: goto next_line
;
959 if (i
< FILE_TABLE_SIZE
)
960 filename_table
[i
].dir_entry
= value
;
963 dwarf_ignore_type(ln
, end
);
967 while ((dwarf_read_1(ln
, end
))) {
969 if (++dir_size
< DIR_TABLE_SIZE
)
970 dirs
[dir_size
- 1] = (char *)ln
- 1;
972 while (dwarf_read_1(ln
, end
)) {}
974 while ((dwarf_read_1(ln
, end
))) {
975 if (++filename_size
< FILE_TABLE_SIZE
) {
976 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
977 while (dwarf_read_1(ln
, end
)) {}
978 filename_table
[filename_size
- 1].dir_entry
=
979 dwarf_read_uleb128(&ln
, end
);
982 while (dwarf_read_1(ln
, end
)) {}
983 dwarf_read_uleb128(&ln
, end
);
985 dwarf_read_uleb128(&ln
, end
); // time
986 dwarf_read_uleb128(&ln
, end
); // size
989 if (filename_size
>= 1)
990 filename
= filename_table
[0].name
;
993 i
= dwarf_read_1(ln
, end
);
994 if (i
>= opcode_base
) {
995 if (max_ops_per_insn
== 1)
996 pc
+= ((i
- opcode_base
) / line_range
) * min_insn_length
;
998 pc
+= (opindex
+ (i
- opcode_base
) / line_range
) /
999 max_ops_per_insn
* min_insn_length
;
1000 opindex
= (opindex
+ (i
- opcode_base
) / line_range
) %
1003 i
= (int)((i
- opcode_base
) % line_range
) + line_base
;
1005 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
1012 len
= dwarf_read_uleb128(&ln
, end
);
1017 switch (dwarf_read_1(cp
, end
)) {
1018 case DW_LNE_end_sequence
:
1020 case DW_LNE_set_address
:
1022 pc
= dwarf_read_4(cp
, end
);
1024 pc
= dwarf_read_8(cp
, end
);
1026 #if defined TCC_TARGET_MACHO
1027 pc
+= rc
->prog_base
;
1031 case DW_LNE_define_file
: /* deprecated */
1032 if (++filename_size
< FILE_TABLE_SIZE
) {
1033 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
1034 while (dwarf_read_1(ln
, end
)) {}
1035 filename_table
[filename_size
- 1].dir_entry
=
1036 dwarf_read_uleb128(&ln
, end
);
1039 while (dwarf_read_1(ln
, end
)) {}
1040 dwarf_read_uleb128(&ln
, end
);
1042 dwarf_read_uleb128(&ln
, end
); // time
1043 dwarf_read_uleb128(&ln
, end
); // size
1045 case DW_LNE_hi_user
- 1:
1046 function
= (char *)cp
;
1053 case DW_LNS_advance_pc
:
1054 if (max_ops_per_insn
== 1)
1055 pc
+= dwarf_read_uleb128(&ln
, end
) * min_insn_length
;
1057 unsigned long long off
= dwarf_read_uleb128(&ln
, end
);
1059 pc
+= (opindex
+ off
) / max_ops_per_insn
*
1061 opindex
= (opindex
+ off
) % max_ops_per_insn
;
1065 case DW_LNS_advance_line
:
1066 line
+= dwarf_read_sleb128(&ln
, end
);
1068 case DW_LNS_set_file
:
1069 i
= dwarf_read_uleb128(&ln
, end
);
1070 i
-= i
> 0 && version
< 5;
1071 if (i
< FILE_TABLE_SIZE
&& i
< filename_size
)
1072 filename
= filename_table
[i
].name
;
1074 case DW_LNS_const_add_pc
:
1075 if (max_ops_per_insn
== 1)
1076 pc
+= ((255 - opcode_base
) / line_range
) * min_insn_length
;
1078 unsigned int off
= (255 - opcode_base
) / line_range
;
1080 pc
+= ((opindex
+ off
) / max_ops_per_insn
) *
1082 opindex
= (opindex
+ off
) % max_ops_per_insn
;
1086 case DW_LNS_fixed_advance_pc
:
1087 i
= dwarf_read_2(ln
, end
);
1093 for (j
= 0; j
< opcode_length
[i
- 1]; j
++)
1094 dwarf_read_uleb128 (&ln
, end
);
1102 filename
= function
= NULL
, func_addr
= 0;
1105 pstrcpy(bi
->file
, sizeof bi
->file
, filename
), bi
->line
= line
;
1107 pstrcpy(bi
->func
, sizeof bi
->func
, function
);
1108 bi
->func_pc
= func_addr
;
1109 return (addr_t
)func_addr
;
1111 /* ------------------------------------------------------------- */
1112 #ifndef CONFIG_TCC_BACKTRACE_ONLY
1115 int _tcc_backtrace(rt_frame
*f
, const char *fmt
, va_list ap
)
1117 rt_context
*rc
, *rc2
;
1119 char skip
[40], msg
[200];
1120 int i
, level
, ret
, n
, one
;
1123 addr_t (*getinfo
)(rt_context
*, addr_t
, bt_info
*);
1126 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
1127 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
1128 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
1132 /* hack for bcheck.c:dprintf(): one level, no newline */
1133 if (fmt
[0] == '\001')
1135 vsnprintf(msg
, sizeof msg
, fmt
, ap
);
1139 getinfo
= rt_printline
, n
= 6;
1142 getinfo
= rt_printline_dwarf
;
1143 if (rc
->num_callers
)
1144 n
= rc
->num_callers
;
1147 for (i
= level
= 0; level
< n
; i
++) {
1148 ret
= rt_get_caller_pc(&pc
, f
, i
);
1151 memset(&bi
, 0, sizeof bi
);
1152 for (rc2
= rc
; rc2
; rc2
= rc2
->next
) {
1153 if (getinfo(rc2
, pc
, &bi
))
1155 /* we try symtab symbols (no line number info) */
1156 if (!!(a
= rt_elfsym(rc2
, pc
, &bi
.func_pc
))) {
1157 pstrcpy(bi
.func
, sizeof bi
.func
, a
);
1161 //fprintf(stderr, "%d rc %p %p\n", i, (void*)pcfunc, (void*)pc);
1162 if (skip
[0] && strstr(bi
.file
, skip
))
1164 #ifndef CONFIG_TCC_BACKTRACE_ONLY
1166 TCCState
*s
= rt_find_state(f
);
1167 if (s
&& s
->bt_func
) {
1171 bi
.file
[0] ? bi
.file
: NULL
,
1173 bi
.func
[0] ? bi
.func
: NULL
,
1174 level
== 0 ? msg
: NULL
1183 rt_printf("%s:%d", bi
.file
, bi
.line
);
1185 rt_printf("0x%08llx", (long long)pc
);
1187 rt_printf(": %s %s", level
? "by" : "at", bi
.func
[0] ? bi
.func
: "???");
1189 rt_printf(": %s", msg
);
1195 #ifndef CONFIG_TCC_BACKTRACE_ONLY
1200 && bi
.func_pc
== (addr_t
)rc2
->top_func
)
1208 /* emit a run time error at position 'pc' */
1209 static int rt_error(rt_frame
*f
, const char *fmt
, ...)
1211 va_list ap
; char msg
[200]; int ret
;
1213 snprintf(msg
, sizeof msg
, "RUNTIME ERROR: %s", fmt
);
1214 ret
= _tcc_backtrace(f
, msg
, ap
);
1219 /* ------------------------------------------------------------- */
1222 # include <signal.h>
1223 # ifndef __OpenBSD__
1224 # include <sys/ucontext.h>
1227 # define ucontext_t CONTEXT
1230 /* translate from ucontext_t* to internal rt_context * */
1231 static void rt_getcontext(ucontext_t
*uc
, rt_frame
*rc
)
1237 #elif defined _WIN32
1241 #elif defined __i386__
1242 # if defined(__APPLE__)
1243 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
1244 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
1245 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1246 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
1247 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
1248 # elif defined(__dietlibc__)
1249 rc
->ip
= uc
->uc_mcontext
.eip
;
1250 rc
->fp
= uc
->uc_mcontext
.ebp
;
1251 # elif defined(__NetBSD__)
1252 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
1253 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
1254 # elif defined(__OpenBSD__)
1255 rc
->ip
= uc
->sc_eip
;
1256 rc
->fp
= uc
->sc_ebp
;
1257 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
1258 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
1259 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
1261 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1262 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
1264 #elif defined(__x86_64__)
1265 # if defined(__APPLE__)
1266 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
1267 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
1268 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1269 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
1270 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
1271 # elif defined(__NetBSD__)
1272 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
1273 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
1274 # elif defined(__OpenBSD__)
1275 rc
->ip
= uc
->sc_rip
;
1276 rc
->fp
= uc
->sc_rbp
;
1278 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1279 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
1281 #elif defined(__arm__) && defined(__NetBSD__)
1282 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1283 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1284 #elif defined(__arm__) && defined(__OpenBSD__)
1286 rc
->fp
= uc
->sc_r11
;
1287 #elif defined(__arm__) && defined(__FreeBSD__)
1288 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1289 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1290 #elif defined(__arm__)
1291 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
1292 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
1293 #elif defined(__aarch64__) && defined(__APPLE__)
1295 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
1296 rc
->ip
= uc
->uc_mcontext
->__ss
.__pc
;
1297 rc
->fp
= uc
->uc_mcontext
->__ss
.__fp
;
1298 #elif defined(__aarch64__) && defined(__FreeBSD__)
1299 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
1300 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
1301 #elif defined(__aarch64__) && defined(__NetBSD__)
1302 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1303 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1304 #elif defined(__aarch64__) && defined(__OpenBSD__)
1305 rc
->ip
= uc
->sc_elr
;
1306 rc
->fp
= uc
->sc_x
[29];
1307 #elif defined(__aarch64__)
1308 rc
->ip
= uc
->uc_mcontext
.pc
;
1309 rc
->fp
= uc
->uc_mcontext
.regs
[29];
1310 #elif defined(__riscv) && defined(__OpenBSD__)
1311 rc
->ip
= uc
->sc_sepc
;
1312 rc
->fp
= uc
->sc_s
[0];
1313 #elif defined(__riscv)
1314 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
1315 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
1319 /* ------------------------------------------------------------- */
1321 /* signal handler for fatal errors */
1322 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
1325 rt_getcontext(puc
, &f
);
1329 switch(siginf
->si_code
) {
1332 rt_error(&f
, "division by zero");
1335 rt_error(&f
, "floating point exception");
1341 rt_error(&f
, "invalid memory access");
1344 rt_error(&f
, "illegal instruction");
1347 rt_error(&f
, "abort() called");
1350 rt_error(&f
, "caught signal %d", signum
);
1356 sigaddset(&s
, signum
);
1357 sigprocmask(SIG_UNBLOCK
, &s
, NULL
);
1363 # define SA_SIGINFO 0x00000004u
1366 /* Generate a stack backtrace when a CPU exception occurs. */
1367 static void set_exception_handler(void)
1369 struct sigaction sigact
;
1370 /* install TCC signal handlers to print debug info on fatal
1372 sigemptyset (&sigact
.sa_mask
);
1373 sigact
.sa_flags
= SA_SIGINFO
; //| SA_RESETHAND;
1374 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
1375 sigact
.sa_flags
|= SA_ONSTACK
;
1377 sigact
.sa_sigaction
= sig_error
;
1378 sigaction(SIGFPE
, &sigact
, NULL
);
1379 sigaction(SIGILL
, &sigact
, NULL
);
1380 sigaction(SIGSEGV
, &sigact
, NULL
);
1381 sigaction(SIGBUS
, &sigact
, NULL
);
1382 sigaction(SIGABRT
, &sigact
, NULL
);
1384 /* This allows stack overflow to be reported instead of a SEGV */
1387 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
1390 ss
.ss_size
= SIGSTKSZ
;
1392 sigaltstack(&ss
, NULL
);
1399 /* signal handler for fatal errors */
1400 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
1404 rt_getcontext(ex_info
->ContextRecord
, &f
);
1406 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
1407 case EXCEPTION_ACCESS_VIOLATION
:
1408 rt_error(&f
, "invalid memory access");
1410 case EXCEPTION_STACK_OVERFLOW
:
1411 rt_error(&f
, "stack overflow");
1413 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
1414 rt_error(&f
, "division by zero");
1416 case EXCEPTION_BREAKPOINT
:
1417 case EXCEPTION_SINGLE_STEP
:
1418 f
.ip
= *(addr_t
*)f
.sp
;
1419 rt_error(&f
, "breakpoint/single-step exception:");
1420 return EXCEPTION_CONTINUE_SEARCH
;
1422 rt_error(&f
, "caught exception %08x", code
);
1426 return EXCEPTION_EXECUTE_HANDLER
;
1429 /* Generate a stack backtrace when a CPU exception occurs. */
1430 static void set_exception_handler(void)
1432 SetUnhandledExceptionFilter(cpu_exception_handler
);
1437 /* ------------------------------------------------------------- */
1438 /* return the PC at frame level 'level'. Return negative if not found */
1439 #if defined(__i386__) || defined(__x86_64__)
1440 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1451 /* XXX: check address validity with program info */
1452 fp
= ((addr_t
*)fp
)[0];
1454 *paddr
= ((addr_t
*)fp
)[1];
1459 /* XXX: only supports linux/bsd */
1460 #elif defined(__arm__) && !defined(_WIN32)
1461 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1472 fp
= ((addr_t
*)fp
)[0];
1474 *paddr
= ((addr_t
*)fp
)[2];
1479 #elif defined(__aarch64__)
1480 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1491 fp
= ((addr_t
*)fp
)[0];
1493 *paddr
= ((addr_t
*)fp
)[1];
1498 #elif defined(__riscv)
1499 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1510 fp
= ((addr_t
*)fp
)[-2];
1512 *paddr
= ((addr_t
*)fp
)[-1];
1518 #warning add arch specific rt_get_caller_pc()
1519 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1525 #else // for runmain.c:exit(); when CONFIG_TCC_BACKTRACE == 0 */
1526 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*f
, int level
)
1533 #endif /* CONFIG_TCC_BACKTRACE */
1534 /* ------------------------------------------------------------- */
1535 #ifdef CONFIG_TCC_STATIC
1537 /* dummy function for profiling */
1538 ST_FUNC
void *dlopen(const char *filename
, int flag
)
1543 ST_FUNC
void dlclose(void *p
)
1547 ST_FUNC
const char *dlerror(void)
1552 typedef struct TCCSyms
{
1558 /* add the symbol you want here if no dynamic linking is done */
1559 static TCCSyms tcc_syms
[] = {
1560 #if !defined(CONFIG_TCCBOOT)
1561 #define TCCSYM(a) { #a, &a, },
1571 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
1575 while (p
->str
!= NULL
) {
1576 if (!strcmp(p
->str
, symbol
))
1583 #endif /* CONFIG_TCC_STATIC */
1584 #endif /* TCC_IS_NATIVE */
1585 /* ------------------------------------------------------------- */