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: */
33 Stab_Sym
*stab_sym_end
;
37 unsigned char *dwarf_line
;
38 unsigned char *dwarf_line_end
;
39 unsigned char *dwarf_line_str
;
42 ElfW(Sym
) *esym_start
;
50 struct rt_context
*next
;
55 } rt_context
; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */
57 typedef struct rt_frame
62 /* linked list of rt_contexts */
63 static rt_context
*g_rc
;
64 /* semaphore to protect it */
65 TCC_SEM(static rt_sem
);
66 static int signal_set
;
67 static void set_exception_handler(void);
69 int _rt_error(rt_frame
*f
, const char *msg
, const char *fmt
, va_list ap
);
70 void rt_wait_sem(void) { WAIT_SEM(&rt_sem
); }
71 void rt_post_sem(void) { POST_SEM(&rt_sem
); }
72 #endif /* def CONFIG_TCC_BACKTRACE */
74 /* handle exit/atexit for tcc_run() -- thread-unsafe */
77 static int rt_nr_exit
;
78 static void *rt_exitfunc
[32];
79 static void *rt_exitarg
[32];
81 static void rt_exit(int code
)
84 longjmp(rt_jb
, code
? code
: 256);
88 /* ------------------------------------------------------------- */
89 /* defined when included from lib/bt-exe.c */
90 #ifndef CONFIG_TCC_BACKTRACE_ONLY
93 # include <sys/mman.h>
96 static int protect_pages(void *ptr
, unsigned long length
, int mode
);
97 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, unsigned ptr_diff
);
100 static void *win64_add_function_table(TCCState
*s1
);
101 static void win64_del_function_table(void *);
104 static void bt_link(TCCState
*s1
)
106 #ifdef CONFIG_TCC_BACKTRACE
110 if (!s1
->do_backtrace
)
112 rc
= tcc_get_symbol(s1
, "__rt_info");
116 rc
->next
= g_rc
, g_rc
= rc
, rc
->s1
= s1
;
117 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
118 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
119 rc
->elf_str
= (char *)symtab_section
->link
->data
;
120 rc
->top_func
= tcc_get_symbol(s1
, "main");
121 if (PTR_SIZE
== 8 && !s1
->dwarf
)
122 rc
->prog_base
&= 0xffffffff00000000ULL
;
123 #ifdef CONFIG_TCC_BCHECK
124 if (s1
->do_bounds_check
) {
125 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
126 ((void(*)(void*,int))p
)(rc
->bounds_start
, 1);
131 set_exception_handler(), signal_set
= 1;
135 static void bt_unlink(TCCState
*s1
)
137 #ifdef CONFIG_TCC_BACKTRACE
138 rt_context
*rc
, **pp
;
140 for (pp
= &g_rc
; rc
= *pp
, rc
; pp
= &rc
->next
)
149 #if !_WIN32 && !__APPLE__
150 //#define HAVE_SELINUX 1
153 static int rt_mem(TCCState
*s1
, int size
)
158 /* Using mmap instead of malloc */
160 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
161 int fd
= mkstemp(tmpfname
);
165 ptr
= mmap(NULL
, size
* 2, PROT_READ
|PROT_EXEC
, MAP_SHARED
, fd
, 0);
166 /* mmap RW memory at fixed distance */
167 prw
= mmap((char*)ptr
+ size
, size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_FIXED
, fd
, 0);
169 if (ptr
== MAP_FAILED
|| prw
== MAP_FAILED
)
170 return tcc_error_noabort("tccrun: could not map memory");
171 ptr_diff
= (char*)prw
- (char*)ptr
; /* = size; */
172 //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
174 ptr
= tcc_malloc(size
);
181 /* ------------------------------------------------------------- */
182 /* Do all relocations (needed before using tcc_get_symbol())
183 Returns -1 on error. */
185 LIBTCCAPI
int tcc_relocate(TCCState
*s1
)
187 int size
, ret
, ptr_diff
;
190 exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
192 #ifdef CONFIG_TCC_BACKTRACE
193 /* for bt-log.c (but not when 'tcc -bt -run tcc.c') */
194 if (s1
->do_backtrace
&& !tcc_get_symbol(s1
, "_rt_error"))
195 tcc_add_symbol(s1
, "_rt_error", _rt_error
);
198 size
= tcc_relocate_ex(s1
, NULL
, 0);
201 ptr_diff
= rt_mem(s1
, size
);
204 ret
= tcc_relocate_ex(s1
, s1
->run_ptr
, ptr_diff
);
210 ST_FUNC
void tcc_run_free(TCCState
*s1
)
216 /* free any loaded DLLs */
217 for ( i
= 0; i
< s1
->nb_loaded_dlls
; i
++) {
218 DLLReference
*ref
= s1
->loaded_dlls
[i
];
221 FreeLibrary((HMODULE
)ref
->handle
);
223 dlclose(ref
->handle
);
226 /* free loaded dlls array */
227 dynarray_reset(&s1
->loaded_dlls
, &s1
->nb_loaded_dlls
);
229 /* unmap or unprotect and free memory */
236 munmap(ptr
, size
* 2);
238 /* unprotect memory to make it usable for malloc again */
239 protect_pages(ptr
, size
, 2 /*rw*/);
241 win64_del_function_table(s1
->run_function_table
);
247 static void run_cdtors(TCCState
*s1
, const char *start
, const char *end
,
248 int argc
, char **argv
, char **envp
)
250 void **a
= (void **)get_sym_addr(s1
, start
, 0, 0);
251 void **b
= (void **)get_sym_addr(s1
, end
, 0, 0);
253 ((void(*)(int, char **, char **))*a
++)(argc
, argv
, envp
);
256 static void run_on_exit(int ret
)
260 --n
, ((void(*)(int,void*))rt_exitfunc
[n
])(ret
, rt_exitarg
[n
]);
263 static int rt_on_exit(void *function
, void *arg
)
265 if (rt_nr_exit
< countof(rt_exitfunc
)) {
266 rt_exitfunc
[rt_nr_exit
] = function
;
267 rt_exitarg
[rt_nr_exit
++] = arg
;
273 static int rt_atexit(void *function
)
275 return rt_on_exit(function
, NULL
);
278 /* launch the compiled program with the given arguments */
279 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
281 int (*prog_main
)(int, char **, char **), ret
;
283 #if defined(__APPLE__) || defined(__FreeBSD__)
285 #elif defined(__OpenBSD__) || defined(__NetBSD__)
286 extern char **environ
;
287 char **envp
= environ
;
289 char **envp
= environ
;
292 s1
->run_main
= s1
->nostdlib
? "_start" : "main";
293 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, s1
->run_main
, 0, 1))
296 tcc_add_symbol(s1
, "exit", rt_exit
);
297 tcc_add_symbol(s1
, "atexit", rt_atexit
);
298 tcc_add_symbol(s1
, "on_exit", rt_on_exit
);
299 if (tcc_relocate(s1
) < 0)
302 prog_main
= (void*)get_sym_addr(s1
, s1
->run_main
, 1, 1);
303 if ((addr_t
)-1 == (addr_t
)prog_main
)
306 errno
= 0; /* clean errno value */
312 /* These aren't C symbols, so don't need leading underscore handling. */
313 run_cdtors(s1
, "__init_array_start", "__init_array_end", argc
, argv
, envp
);
316 ret
= prog_main(argc
, argv
, envp
);
319 run_cdtors(s1
, "__fini_array_start", "__fini_array_end", 0, NULL
, NULL
);
321 if (s1
->dflag
& 16 && ret
) /* tcc -dt -run ... */
322 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
326 /* ------------------------------------------------------------- */
327 /* remove all STB_LOCAL symbols */
328 static void cleanup_symbols(TCCState
*s1
)
330 Section
*s
= s1
->symtab
;
331 int sym_index
, end_sym
= s
->data_offset
/ sizeof (ElfSym
);
333 s
->data_offset
= s
->link
->data_offset
= s
->hash
->data_offset
= 0;
335 /* add global symbols again */
336 for (sym_index
= 1; sym_index
< end_sym
; ++sym_index
) {
337 ElfW(Sym
) *sym
= &((ElfW(Sym
) *)s
->data
)[sym_index
];
338 const char *name
= (char *)s
->link
->data
+ sym
->st_name
;
339 if (ELFW(ST_BIND
)(sym
->st_info
) == STB_LOCAL
)
341 //printf("sym %s\n", name);
342 put_elf_sym(s
, sym
->st_value
, sym
->st_size
, sym
->st_info
, sym
->st_other
, sym
->st_shndx
, name
);
346 /* free all sections except symbols */
347 static void cleanup_sections(TCCState
*s1
)
349 struct { Section
**secs
; int nb_secs
; } *p
= (void*)&s1
->sections
;
352 for (i
= --f
; i
< p
->nb_secs
; i
++) {
353 Section
*s
= p
->secs
[i
];
354 if (s
== s1
->symtab
|| s
== s1
->symtab
->link
|| s
== s1
->symtab
->hash
) {
355 s
->data
= tcc_realloc(s
->data
, s
->data_allocated
= s
->data_offset
);
357 free_section(s
), tcc_free(s
), p
->secs
[i
] = NULL
;
363 /* ------------------------------------------------------------- */
364 /* 0 = .text rwx other rw */
365 /* 1 = .text rx .rdata r .data/.bss rw */
366 #ifndef CONFIG_RUNMEM_RO
367 # define CONFIG_RUNMEM_RO 1
370 #define DEBUG_RUNMEN 0
372 /* relocate code. Return -1 on error, required size if ptr is NULL,
373 otherwise copy code into buffer passed by the caller */
374 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, unsigned ptr_diff
)
377 unsigned offset
, length
, align
, i
, k
, f
;
384 pe_output_file(s1
, NULL
);
387 resolve_common_syms(s1
);
388 build_got_entries(s1
, 0);
397 fprintf(stderr
, "X: <base> %p len %5x\n",
404 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
406 for(i
= 1; i
< s1
->nb_sections
; i
++) {
407 static const char shf
[] = {
408 SHF_ALLOC
|SHF_EXECINSTR
, SHF_ALLOC
, SHF_ALLOC
|SHF_WRITE
411 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
413 length
= s
->data_offset
;
415 if (copy
) { /* final step: copy section data to memory */
419 n
= (s
->sh_addr
- addr
) + length
;
420 ptr
= (void*)s
->sh_addr
;
422 ptr
= (void*)(s
->sh_addr
+ ptr_diff
);
423 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
424 memset(ptr
, 0, length
);
426 memcpy(ptr
, s
->data
, length
);
428 if (s
== s1
->uw_pdata
)
429 s1
->run_function_table
= win64_add_function_table(s1
);
434 align
= s
->sh_addralign
- 1;
436 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
437 /* To avoid that x86 processors would reload cached instructions
438 each time when data is written in the near, we need to make
439 sure that code and data do not share the same 64 byte unit */
443 /* start new page for different permissions */
444 if (CONFIG_RUNMEM_RO
|| k
< 2)
445 align
= PAGESIZE
- 1;
447 addr
= k
? mem
+ ptr_diff
: mem
;
448 offset
+= -(addr
+ offset
) & align
;
449 s
->sh_addr
= mem
? addr
+ offset
: 0;
453 fprintf(stderr
, "%d: %-16s %p len %5x align %04x\n",
454 k
, s
->name
, (void*)s
->sh_addr
, length
, align
+ 1);
457 if (copy
) { /* set permissions */
458 if (n
== 0) /* no data */
461 if (k
== 0) /* SHF_EXECINSTR has its own mapping */
465 if (CONFIG_RUNMEM_RO
== 0) {
468 f
= 3; /* change only SHF_EXECINSTR to rwx */
471 fprintf(stderr
, "protect %3s %p len %5x\n",
472 &"rx\0r \0rw\0rwx"[f
*3],
473 (void*)addr
, (unsigned)((n
+ PAGESIZE
-1) & ~(PAGESIZE
-1)));
475 if (protect_pages((void*)addr
, n
, f
) < 0)
476 return tcc_error_noabort(
477 "mprotect failed (did you mean to configure --with-selinux?)");
482 offset
= (offset
+ (PAGESIZE
-1)) & ~(PAGESIZE
-1);
484 offset
+= PAGESIZE
; /* extra space to align malloc memory start */
490 /* remove local symbols and free sections except symtab */
492 cleanup_sections(s1
);
496 /* relocate symbols */
497 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
498 /* relocate sections */
500 s1
->pe_imagebase
= mem
;
504 relocate_sections(s1
);
509 /* ------------------------------------------------------------- */
510 /* allow to run code in memory */
512 static int protect_pages(void *ptr
, unsigned long length
, int mode
)
515 static const unsigned char protect
[] = {
519 PAGE_EXECUTE_READWRITE
522 if (!VirtualProtect(ptr
, length
, protect
[mode
], &old
))
526 static const unsigned char protect
[] = {
527 PROT_READ
| PROT_EXEC
,
529 PROT_READ
| PROT_WRITE
,
530 PROT_READ
| PROT_WRITE
| PROT_EXEC
533 start
= (addr_t
)ptr
& ~(PAGESIZE
- 1);
534 end
= (addr_t
)ptr
+ length
;
535 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
536 if (mprotect((void *)start
, end
- start
, protect
[mode
]))
538 /* XXX: BSD sometimes dump core with bad system call */
539 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
540 if (mode
== 0 || mode
== 3) {
541 void __clear_cache(void *beginning
, void *end
);
542 __clear_cache(ptr
, (char *)ptr
+ length
);
550 static void *win64_add_function_table(TCCState
*s1
)
554 p
= (void*)s1
->uw_pdata
->sh_addr
;
556 (RUNTIME_FUNCTION
*)p
,
557 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
565 static void win64_del_function_table(void *p
)
568 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
573 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
574 /* ------------------------------------------------------------- */
575 #ifdef CONFIG_TCC_BACKTRACE
577 static int rt_vprintf(const char *fmt
, va_list ap
)
579 int ret
= vfprintf(stderr
, fmt
, ap
);
584 static int rt_printf(const char *fmt
, ...)
589 r
= rt_vprintf(fmt
, ap
);
594 static char *rt_elfsym(rt_context
*rc
, addr_t wanted_pc
, addr_t
*func_addr
)
597 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
598 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
599 if ((type
== STT_FUNC
|| type
== STT_GNU_IFUNC
)
600 && wanted_pc
>= esym
->st_value
601 && wanted_pc
< esym
->st_value
+ esym
->st_size
) {
602 *func_addr
= esym
->st_value
;
603 return rc
->elf_str
+ esym
->st_name
;
610 /* print the position in the source file of PC value 'pc' by reading
611 the stabs debug information */
612 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
,
613 const char *msg
, const char *skip
)
616 addr_t func_addr
, last_pc
, pc
;
617 const char *incl_files
[INCLUDE_STACK_SIZE
];
618 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
626 last_pc
= (addr_t
)-1;
632 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
633 str
= rc
->stab_str
+ sym
->n_strx
;
636 switch(sym
->n_type
) {
644 if (sym
->n_strx
== 0) /* end of function */
648 /* Stab_Sym.n_value is only 32bits */
655 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
660 switch(sym
->n_type
) {
661 /* function start or end */
663 if (sym
->n_strx
== 0)
665 p
= strchr(str
, ':');
666 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
667 len
= sizeof func_name
;
668 pstrcpy(func_name
, len
, str
);
671 /* line number info */
674 last_line_num
= sym
->n_desc
;
675 last_incl_index
= incl_index
;
679 if (incl_index
< INCLUDE_STACK_SIZE
)
680 incl_files
[incl_index
++] = str
;
686 /* start/end of translation unit */
690 /* do not add path */
692 if (len
> 0 && str
[len
- 1] != '/')
693 incl_files
[incl_index
++] = str
;
698 last_pc
= (addr_t
)-1;
700 /* alternative file name (from #line or #include directives) */
703 incl_files
[incl_index
-1] = str
;
712 /* we try symtab symbols (no line number info) */
713 p
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
715 pstrcpy(func_name
, sizeof func_name
, p
);
724 str
= incl_files
[--i
];
725 if (skip
[0] && strstr(str
, skip
))
727 rt_printf("%s:%d: ", str
, last_line_num
);
729 rt_printf("%08llx : ", (long long)wanted_pc
);
730 rt_printf("%s %s", msg
, func_name
[0] ? func_name
: "???");
733 rt_printf(" (included from ");
735 rt_printf("%s", incl_files
[i
]);
746 /* ------------------------------------------------------------- */
747 /* rt_printline - dwarf version */
749 #define MAX_128 ((8 * sizeof (long long) + 6) / 7)
751 #define DIR_TABLE_SIZE (64)
752 #define FILE_TABLE_SIZE (512)
754 #define dwarf_read_1(ln,end) \
755 ((ln) < (end) ? *(ln)++ : 0)
756 #define dwarf_read_2(ln,end) \
757 ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
758 #define dwarf_read_4(ln,end) \
759 ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
760 #define dwarf_read_8(ln,end) \
761 ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
762 #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \
763 switch (entry_format[j].form) { \
764 case DW_FORM_data1: (ln) += 1; break; \
765 case DW_FORM_data2: (ln) += 2; break; \
766 case DW_FORM_data4: (ln) += 3; break; \
767 case DW_FORM_data8: (ln) += 8; break; \
768 case DW_FORM_data16: (ln) += 16; break; \
769 case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \
770 default: goto next_line; \
773 static unsigned long long
774 dwarf_read_uleb128(unsigned char **ln
, unsigned char *end
)
776 unsigned char *cp
= *ln
;
777 unsigned long long retval
= 0;
780 for (i
= 0; i
< MAX_128
; i
++) {
781 unsigned long long byte
= dwarf_read_1(cp
, end
);
783 retval
|= (byte
& 0x7f) << (i
* 7);
784 if ((byte
& 0x80) == 0)
792 dwarf_read_sleb128(unsigned char **ln
, unsigned char *end
)
794 unsigned char *cp
= *ln
;
795 long long retval
= 0;
798 for (i
= 0; i
< MAX_128
; i
++) {
799 unsigned long long byte
= dwarf_read_1(cp
, end
);
801 retval
|= (byte
& 0x7f) << (i
* 7);
802 if ((byte
& 0x80) == 0) {
803 if ((byte
& 0x40) && (i
+ 1) * 7 < 64)
804 retval
|= -1LL << ((i
+ 1) * 7);
812 static addr_t
rt_printline_dwarf (rt_context
*rc
, addr_t wanted_pc
,
813 const char *msg
, const char *skip
)
818 unsigned char *opcode_length
;
819 unsigned long long size
;
821 unsigned char version
;
822 unsigned int min_insn_length
;
823 unsigned int max_ops_per_insn
;
825 unsigned int line_range
;
826 unsigned int opcode_base
;
827 unsigned int opindex
;
832 unsigned long long value
;
837 unsigned int dir_size
;
839 char *dirs
[DIR_TABLE_SIZE
];
841 unsigned int filename_size
;
842 struct dwarf_filename_struct
{
843 unsigned int dir_entry
;
845 } filename_table
[FILE_TABLE_SIZE
];
860 while (ln
< rc
->dwarf_line_end
) {
870 size
= dwarf_read_4(ln
, rc
->dwarf_line_end
);
871 if (size
== 0xffffffffu
) // dwarf 64
872 length
= 8, size
= dwarf_read_8(ln
, rc
->dwarf_line_end
);
874 if (end
< ln
|| end
> rc
->dwarf_line_end
)
876 version
= dwarf_read_2(ln
, end
);
878 ln
+= length
+ 2; // address size, segment selector, prologue Length
880 ln
+= length
; // prologue Length
881 min_insn_length
= dwarf_read_1(ln
, end
);
883 max_ops_per_insn
= dwarf_read_1(ln
, end
);
885 max_ops_per_insn
= 1;
886 ln
++; // Initial value of 'is_stmt'
887 line_base
= dwarf_read_1(ln
, end
);
888 line_base
|= line_base
>= 0x80 ? ~0xff : 0;
889 line_range
= dwarf_read_1(ln
, end
);
890 opcode_base
= dwarf_read_1(ln
, end
);
892 ln
+= opcode_base
- 1;
895 col
= dwarf_read_1(ln
, end
);
896 for (i
= 0; i
< col
; i
++) {
897 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
898 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
900 dir_size
= dwarf_read_uleb128(&ln
, end
);
901 for (i
= 0; i
< dir_size
; i
++) {
902 for (j
= 0; j
< col
; j
++) {
903 if (entry_format
[j
].type
== DW_LNCT_path
) {
904 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
907 value
= length
== 4 ? dwarf_read_4(ln
, end
)
908 : dwarf_read_8(ln
, end
);
909 if (i
< DIR_TABLE_SIZE
)
910 dirs
[i
] = (char *)rc
->dwarf_line_str
+ value
;
912 length
== 4 ? dwarf_read_4(ln
, end
)
913 : dwarf_read_8(ln
, end
);
917 dwarf_ignore_type(ln
, end
);
920 col
= dwarf_read_1(ln
, end
);
921 for (i
= 0; i
< col
; i
++) {
922 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
923 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
925 filename_size
= dwarf_read_uleb128(&ln
, end
);
926 for (i
= 0; i
< filename_size
; i
++)
927 for (j
= 0; j
< col
; j
++) {
928 if (entry_format
[j
].type
== DW_LNCT_path
) {
929 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
931 value
= length
== 4 ? dwarf_read_4(ln
, end
)
932 : dwarf_read_8(ln
, end
);
933 if (i
< FILE_TABLE_SIZE
)
934 filename_table
[i
].name
=
935 (char *)rc
->dwarf_line_str
+ value
;
937 else if (entry_format
[j
].type
== DW_LNCT_directory_index
) {
938 switch (entry_format
[j
].form
) {
939 case DW_FORM_data1
: value
= dwarf_read_1(ln
, end
); break;
940 case DW_FORM_data2
: value
= dwarf_read_2(ln
, end
); break;
941 case DW_FORM_data4
: value
= dwarf_read_4(ln
, end
); break;
942 case DW_FORM_udata
: value
= dwarf_read_uleb128(&ln
, end
); break;
943 default: goto next_line
;
945 if (i
< FILE_TABLE_SIZE
)
946 filename_table
[i
].dir_entry
= value
;
949 dwarf_ignore_type(ln
, end
);
953 while ((dwarf_read_1(ln
, end
))) {
955 if (++dir_size
< DIR_TABLE_SIZE
)
956 dirs
[dir_size
- 1] = (char *)ln
- 1;
958 while (dwarf_read_1(ln
, end
)) {}
960 while ((dwarf_read_1(ln
, end
))) {
961 if (++filename_size
< FILE_TABLE_SIZE
) {
962 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
963 while (dwarf_read_1(ln
, end
)) {}
964 filename_table
[filename_size
- 1].dir_entry
=
965 dwarf_read_uleb128(&ln
, end
);
968 while (dwarf_read_1(ln
, end
)) {}
969 dwarf_read_uleb128(&ln
, end
);
971 dwarf_read_uleb128(&ln
, end
); // time
972 dwarf_read_uleb128(&ln
, end
); // size
975 if (filename_size
>= 1)
976 filename
= filename_table
[0].name
;
979 i
= dwarf_read_1(ln
, end
);
980 if (i
>= opcode_base
) {
981 if (max_ops_per_insn
== 1)
982 pc
+= ((i
- opcode_base
) / line_range
) * min_insn_length
;
984 pc
+= (opindex
+ (i
- opcode_base
) / line_range
) /
985 max_ops_per_insn
* min_insn_length
;
986 opindex
= (opindex
+ (i
- opcode_base
) / line_range
) %
989 i
= (int)((i
- opcode_base
) % line_range
) + line_base
;
991 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
998 len
= dwarf_read_uleb128(&ln
, end
);
1003 switch (dwarf_read_1(cp
, end
)) {
1004 case DW_LNE_end_sequence
:
1006 case DW_LNE_set_address
:
1008 pc
= dwarf_read_4(cp
, end
);
1010 pc
= dwarf_read_8(cp
, end
);
1012 #if defined TCC_TARGET_MACHO
1013 pc
+= rc
->prog_base
;
1017 case DW_LNE_define_file
: /* deprecated */
1018 if (++filename_size
< FILE_TABLE_SIZE
) {
1019 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
1020 while (dwarf_read_1(ln
, end
)) {}
1021 filename_table
[filename_size
- 1].dir_entry
=
1022 dwarf_read_uleb128(&ln
, end
);
1025 while (dwarf_read_1(ln
, end
)) {}
1026 dwarf_read_uleb128(&ln
, end
);
1028 dwarf_read_uleb128(&ln
, end
); // time
1029 dwarf_read_uleb128(&ln
, end
); // size
1031 case DW_LNE_hi_user
- 1:
1032 function
= (char *)cp
;
1039 case DW_LNS_advance_pc
:
1040 if (max_ops_per_insn
== 1)
1041 pc
+= dwarf_read_uleb128(&ln
, end
) * min_insn_length
;
1043 unsigned long long off
= dwarf_read_uleb128(&ln
, end
);
1045 pc
+= (opindex
+ off
) / max_ops_per_insn
*
1047 opindex
= (opindex
+ off
) % max_ops_per_insn
;
1051 case DW_LNS_advance_line
:
1052 line
+= dwarf_read_sleb128(&ln
, end
);
1054 case DW_LNS_set_file
:
1055 i
= dwarf_read_uleb128(&ln
, end
);
1056 i
-= i
> 0 && version
< 5;
1057 if (i
< FILE_TABLE_SIZE
&& i
< filename_size
)
1058 filename
= filename_table
[i
].name
;
1060 case DW_LNS_const_add_pc
:
1061 if (max_ops_per_insn
== 1)
1062 pc
+= ((255 - opcode_base
) / line_range
) * min_insn_length
;
1064 unsigned int off
= (255 - opcode_base
) / line_range
;
1066 pc
+= ((opindex
+ off
) / max_ops_per_insn
) *
1068 opindex
= (opindex
+ off
) % max_ops_per_insn
;
1072 case DW_LNS_fixed_advance_pc
:
1073 i
= dwarf_read_2(ln
, end
);
1079 for (j
= 0; j
< opcode_length
[i
- 1]; j
++)
1080 dwarf_read_uleb128 (&ln
, end
);
1091 /* we try symtab symbols (no line number info) */
1092 function
= rt_elfsym(rc
, wanted_pc
, &func_addr
);
1100 if (skip
[0] && strstr(filename
, skip
))
1102 rt_printf("%s:%d: ", filename
, line
);
1105 rt_printf("0x%08llx : ", (long long)wanted_pc
);
1106 rt_printf("%s %s", msg
, function
? function
: "???");
1107 return (addr_t
)func_addr
;
1109 /* ------------------------------------------------------------- */
1111 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*f
, int level
);
1113 int _rt_error(rt_frame
*f
, const char *msg
, const char *fmt
, va_list ap
)
1118 int i
, level
, ret
, n
, one
;
1120 addr_t (*printline
)(rt_context
*, addr_t
, const char*, const char*);
1121 addr_t top_func
= 0;
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')
1136 printline
= rt_printline
, n
= 6;
1139 printline
= rt_printline_dwarf
;
1140 if (rc
->num_callers
)
1141 n
= rc
->num_callers
;
1142 top_func
= (addr_t
)rc
->top_func
;
1145 for (i
= level
= 0; level
< n
; i
++) {
1146 ret
= rt_get_caller_pc(&pc
, f
, i
);
1149 pc
= printline(rc
, pc
, level
? "by" : "at", skip
);
1150 if (pc
== (addr_t
)-1)
1156 rt_vprintf(fmt
, ap
);
1157 } else if (ret
== -1)
1162 if (ret
== -1 || (pc
== top_func
&& pc
))
1171 /* emit a run time error at position 'pc' */
1172 static int rt_error(rt_frame
*f
, const char *fmt
, ...)
1177 ret
= _rt_error(f
, "RUNTIME ERROR: ", fmt
, ap
);
1182 /* ------------------------------------------------------------- */
1185 # include <signal.h>
1186 # ifndef __OpenBSD__
1187 # include <sys/ucontext.h>
1190 # define ucontext_t CONTEXT
1193 /* translate from ucontext_t* to internal rt_context * */
1194 static void rt_getcontext(ucontext_t
*uc
, rt_frame
*rc
)
1200 #elif defined _WIN32
1204 #elif defined __i386__
1205 # if defined(__APPLE__)
1206 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
1207 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
1208 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1209 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
1210 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
1211 # elif defined(__dietlibc__)
1212 rc
->ip
= uc
->uc_mcontext
.eip
;
1213 rc
->fp
= uc
->uc_mcontext
.ebp
;
1214 # elif defined(__NetBSD__)
1215 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
1216 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
1217 # elif defined(__OpenBSD__)
1218 rc
->ip
= uc
->sc_eip
;
1219 rc
->fp
= uc
->sc_ebp
;
1220 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
1221 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
1222 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
1224 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1225 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
1227 #elif defined(__x86_64__)
1228 # if defined(__APPLE__)
1229 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
1230 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
1231 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1232 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
1233 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
1234 # elif defined(__NetBSD__)
1235 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
1236 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
1237 # elif defined(__OpenBSD__)
1238 rc
->ip
= uc
->sc_rip
;
1239 rc
->fp
= uc
->sc_rbp
;
1241 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1242 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
1244 #elif defined(__arm__) && defined(__NetBSD__)
1245 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1246 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1247 #elif defined(__arm__) && defined(__OpenBSD__)
1249 rc
->fp
= uc
->sc_r11
;
1250 #elif defined(__arm__) && defined(__FreeBSD__)
1251 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1252 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1253 #elif defined(__arm__)
1254 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
1255 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
1256 #elif defined(__aarch64__) && defined(__APPLE__)
1258 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
1259 rc
->ip
= uc
->uc_mcontext
->__ss
.__pc
;
1260 rc
->fp
= uc
->uc_mcontext
->__ss
.__fp
;
1261 #elif defined(__aarch64__) && defined(__FreeBSD__)
1262 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
1263 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
1264 #elif defined(__aarch64__) && defined(__NetBSD__)
1265 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1266 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1267 #elif defined(__aarch64__) && defined(__OpenBSD__)
1268 rc
->ip
= uc
->sc_elr
;
1269 rc
->fp
= uc
->sc_x
[29];
1270 #elif defined(__aarch64__)
1271 rc
->ip
= uc
->uc_mcontext
.pc
;
1272 rc
->fp
= uc
->uc_mcontext
.regs
[29];
1273 #elif defined(__riscv) && defined(__OpenBSD__)
1274 rc
->ip
= uc
->sc_sepc
;
1275 rc
->fp
= uc
->sc_s
[0];
1276 #elif defined(__riscv)
1277 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
1278 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
1282 /* ------------------------------------------------------------- */
1284 /* signal handler for fatal errors */
1285 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
1288 rt_getcontext(puc
, &f
);
1292 switch(siginf
->si_code
) {
1295 rt_error(&f
, "division by zero");
1298 rt_error(&f
, "floating point exception");
1304 rt_error(&f
, "invalid memory access");
1307 rt_error(&f
, "illegal instruction");
1310 rt_error(&f
, "abort() called");
1313 rt_error(&f
, "caught signal %d", signum
);
1320 # define SA_SIGINFO 0x00000004u
1323 /* Generate a stack backtrace when a CPU exception occurs. */
1324 static void set_exception_handler(void)
1326 struct sigaction sigact
;
1327 /* install TCC signal handlers to print debug info on fatal
1329 sigemptyset (&sigact
.sa_mask
);
1330 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
1331 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
1332 sigact
.sa_flags
|= SA_ONSTACK
;
1334 sigact
.sa_sigaction
= sig_error
;
1335 sigemptyset(&sigact
.sa_mask
);
1336 sigaction(SIGFPE
, &sigact
, NULL
);
1337 sigaction(SIGILL
, &sigact
, NULL
);
1338 sigaction(SIGSEGV
, &sigact
, NULL
);
1339 sigaction(SIGBUS
, &sigact
, NULL
);
1340 sigaction(SIGABRT
, &sigact
, NULL
);
1342 /* This allows stack overflow to be reported instead of a SEGV */
1345 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
1348 ss
.ss_size
= SIGSTKSZ
;
1350 sigaltstack(&ss
, NULL
);
1357 /* signal handler for fatal errors */
1358 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
1363 rt_getcontext(ex_info
->ContextRecord
, &f
);
1365 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
1366 case EXCEPTION_ACCESS_VIOLATION
:
1367 rt_error(&f
, "invalid memory access");
1369 case EXCEPTION_STACK_OVERFLOW
:
1370 rt_error(&f
, "stack overflow");
1372 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
1373 rt_error(&f
, "division by zero");
1375 case EXCEPTION_BREAKPOINT
:
1376 case EXCEPTION_SINGLE_STEP
:
1377 f
.ip
= *(addr_t
*)f
.sp
;
1378 rt_error(&f
, "breakpoint/single-step exception:");
1379 return EXCEPTION_CONTINUE_SEARCH
;
1381 rt_error(&f
, "caught exception %08x", code
);
1386 return EXCEPTION_EXECUTE_HANDLER
;
1389 /* Generate a stack backtrace when a CPU exception occurs. */
1390 static void set_exception_handler(void)
1392 SetUnhandledExceptionFilter(cpu_exception_handler
);
1397 /* ------------------------------------------------------------- */
1398 /* return the PC at frame level 'level'. Return negative if not found */
1399 #if defined(__i386__) || defined(__x86_64__)
1400 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1409 /* XXX: check address validity with program info */
1412 fp
= ((addr_t
*)fp
)[0];
1415 ip
= ((addr_t
*)fp
)[1];
1423 #elif defined(__arm__)
1424 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1426 /* XXX: only supports linux/bsd */
1427 #if !defined(__linux__) && \
1428 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
1436 fp
= ((addr_t
*)fp
)[0];
1437 *paddr
= ((addr_t
*)fp
)[2];
1443 #elif defined(__aarch64__)
1444 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1449 addr_t
*fp
= (addr_t
*)rc
->fp
;
1451 fp
= (addr_t
*)fp
[0];
1457 #elif defined(__riscv)
1458 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1463 addr_t
*fp
= (addr_t
*)rc
->fp
;
1464 while (--level
&& fp
>= (addr_t
*)0x1000)
1465 fp
= (addr_t
*)fp
[-2];
1466 if (fp
< (addr_t
*)0x1000)
1474 #warning add arch specific rt_get_caller_pc()
1475 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1481 #endif /* CONFIG_TCC_BACKTRACE */
1482 /* ------------------------------------------------------------- */
1483 #ifdef CONFIG_TCC_STATIC
1485 /* dummy function for profiling */
1486 ST_FUNC
void *dlopen(const char *filename
, int flag
)
1491 ST_FUNC
void dlclose(void *p
)
1495 ST_FUNC
const char *dlerror(void)
1500 typedef struct TCCSyms
{
1506 /* add the symbol you want here if no dynamic linking is done */
1507 static TCCSyms tcc_syms
[] = {
1508 #if !defined(CONFIG_TCCBOOT)
1509 #define TCCSYM(a) { #a, &a, },
1519 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
1523 while (p
->str
!= NULL
) {
1524 if (!strcmp(p
->str
, symbol
))
1531 #endif /* CONFIG_TCC_STATIC */
1532 #endif /* TCC_IS_NATIVE */
1533 /* ------------------------------------------------------------- */