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 # define CONFIG_RUNMEM_ALIGNED 0
97 # ifndef CONFIG_RUNMEM_ALIGNED
98 # define CONFIG_RUNMEM_ALIGNED 1
100 # if CONFIG_RUNMEM_ALIGNED
101 # include <malloc.h> /* memalign() */
105 #if !_WIN32 && !__APPLE__
106 //#define HAVE_SELINUX 1
109 static int rt_mem(TCCState
*s1
, int size
)
114 /* Using mmap instead of malloc */
116 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
117 int fd
= mkstemp(tmpfname
);
121 ptr
= mmap(NULL
, size
* 2, PROT_READ
|PROT_EXEC
, MAP_SHARED
, fd
, 0);
122 /* mmap RW memory at fixed distance */
123 prw
= mmap((char*)ptr
+ size
, size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_FIXED
, fd
, 0);
125 if (ptr
== MAP_FAILED
|| prw
== MAP_FAILED
)
126 return tcc_error_noabort("tccrun: could not map memory");
127 ptr_diff
= (char*)prw
- (char*)ptr
; /* = size; */
128 //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
130 # if !CONFIG_RUNMEM_ALIGNED
131 ptr
= tcc_malloc(size
+= PAGESIZE
);
133 ptr
= _aligned_malloc(size
, PAGESIZE
);
135 ptr
= memalign(PAGESIZE
, size
);
138 return tcc_error_noabort("tccrun: could not allocate memory");
145 /* ------------------------------------------------------------- */
146 /* Do all relocations (needed before using tcc_get_symbol())
147 Returns -1 on error. */
149 LIBTCCAPI
int tcc_relocate(TCCState
*s1
)
151 int size
, ret
, ptr_diff
;
154 exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
155 #ifdef CONFIG_TCC_BACKTRACE
156 if (s1
->do_backtrace
)
157 tcc_add_symbol(s1
, "_tcc_backtrace", _tcc_backtrace
); /* for bt-log.c */
159 size
= tcc_relocate_ex(s1
, NULL
, 0);
162 ptr_diff
= rt_mem(s1
, size
);
165 ret
= tcc_relocate_ex(s1
, s1
->run_ptr
, ptr_diff
);
171 ST_FUNC
void tcc_run_free(TCCState
*s1
)
177 /* free any loaded DLLs */
178 for ( i
= 0; i
< s1
->nb_loaded_dlls
; i
++) {
179 DLLReference
*ref
= s1
->loaded_dlls
[i
];
182 FreeLibrary((HMODULE
)ref
->handle
);
184 dlclose(ref
->handle
);
187 /* free loaded dlls array */
188 dynarray_reset(&s1
->loaded_dlls
, &s1
->nb_loaded_dlls
);
189 /* unmap or unprotect and free memory */
196 munmap(ptr
, size
* 2);
198 /* unprotect memory to make it usable for malloc again */
199 protect_pages(ptr
, size
, 2 /*rw*/);
201 win64_del_function_table(s1
->run_function_table
);
203 # if !CONFIG_RUNMEM_ALIGNED
213 /* launch the compiled program with the given arguments */
214 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
216 int (*prog_main
)(int, char **, char **), ret
;
220 #if defined(__APPLE__) || defined(__FreeBSD__)
222 #elif defined(__OpenBSD__) || defined(__NetBSD__)
223 extern char **environ
;
224 char **envp
= environ
;
226 char **envp
= environ
;
229 /* tcc -dt -run ... nothing to do if no main() */
230 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, "main", 0, 1))
233 tcc_add_symbol(s1
, "__rt_exit", rt_exit
);
235 s1
->run_main
= top_sym
= "_start";
237 tcc_add_support(s1
, "runmain.o");
238 s1
->run_main
= "_runmain";
241 if (tcc_relocate(s1
) < 0)
244 prog_main
= (void*)get_sym_addr(s1
, s1
->run_main
, 1, 1);
245 if ((addr_t
)-1 == (addr_t
)prog_main
)
247 errno
= 0; /* clean errno value */
251 ret
= tcc_setjmp(s1
, main_jb
, tcc_get_symbol(s1
, top_sym
));
253 ret
= prog_main(argc
, argv
, envp
);
257 if (s1
->dflag
& 16 && ret
) /* tcc -dt -run ... */
258 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
262 /* ------------------------------------------------------------- */
263 /* remove all STB_LOCAL symbols */
264 static void cleanup_symbols(TCCState
*s1
)
266 Section
*s
= s1
->symtab
;
267 int sym_index
, end_sym
= s
->data_offset
/ sizeof (ElfSym
);
269 s
->data_offset
= s
->link
->data_offset
= s
->hash
->data_offset
= 0;
271 /* add global symbols again */
272 for (sym_index
= 1; sym_index
< end_sym
; ++sym_index
) {
273 ElfW(Sym
) *sym
= &((ElfW(Sym
) *)s
->data
)[sym_index
];
274 const char *name
= (char *)s
->link
->data
+ sym
->st_name
;
275 if (ELFW(ST_BIND
)(sym
->st_info
) == STB_LOCAL
)
277 //printf("sym %s\n", name);
278 put_elf_sym(s
, sym
->st_value
, sym
->st_size
, sym
->st_info
, sym
->st_other
, sym
->st_shndx
, name
);
282 /* free all sections except symbols */
283 static void cleanup_sections(TCCState
*s1
)
285 struct { Section
**secs
; int nb_secs
; } *p
= (void*)&s1
->sections
;
288 for (i
= --f
; i
< p
->nb_secs
; i
++) {
289 Section
*s
= p
->secs
[i
];
290 if (s
== s1
->symtab
|| s
== s1
->symtab
->link
|| s
== s1
->symtab
->hash
) {
291 s
->data
= tcc_realloc(s
->data
, s
->data_allocated
= s
->data_offset
);
293 free_section(s
), tcc_free(s
), p
->secs
[i
] = NULL
;
299 /* ------------------------------------------------------------- */
300 /* 0 = .text rwx other rw */
301 /* 1 = .text rx .rdata r .data/.bss rw */
302 #ifndef CONFIG_RUNMEM_RO
303 # define CONFIG_RUNMEM_RO 1
306 /* relocate code. Return -1 on error, required size if ptr is NULL,
307 otherwise copy code into buffer passed by the caller */
308 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, unsigned ptr_diff
)
311 unsigned offset
, length
, align
, i
, k
, f
;
317 pe_output_file(s1
, NULL
);
320 resolve_common_syms(s1
);
321 build_got_entries(s1
, 0);
328 if (s1
->verbose
== 2 && copy
) {
329 printf(&"-----------------------------------------------------\n"[PTR_SIZE
*2 - 8]);
331 printf("memory %p len %05x\n", ptr
, s1
->run_size
);
338 for (k
= 0; k
< 3; ++k
) { /* 0:rx, 1:ro, 2:rw sections */
340 for(i
= 1; i
< s1
->nb_sections
; i
++) {
341 static const char shf
[] = {
342 SHF_ALLOC
|SHF_EXECINSTR
, SHF_ALLOC
, SHF_ALLOC
|SHF_WRITE
345 if (shf
[k
] != (s
->sh_flags
& (SHF_ALLOC
|SHF_WRITE
|SHF_EXECINSTR
)))
347 length
= s
->data_offset
;
349 if (copy
) { /* final step: copy section data to memory */
350 if (s1
->verbose
== 2)
351 printf("%d: %-16s %p len %05x align %04x\n",
352 k
, s
->name
, (void*)s
->sh_addr
, length
, s
->sh_addralign
);
355 n
= (s
->sh_addr
- addr
) + length
;
356 ptr
= (void*)s
->sh_addr
;
358 ptr
= (void*)(s
->sh_addr
+ ptr_diff
);
359 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
360 memset(ptr
, 0, length
);
362 memcpy(ptr
, s
->data
, length
);
364 if (s
== s1
->uw_pdata
)
365 s1
->run_function_table
= win64_add_function_table(s1
);
370 align
= s
->sh_addralign
;
372 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
373 /* To avoid that x86 processors would reload cached instructions
374 each time when data is written in the near, we need to make
375 sure that code and data do not share the same 64 byte unit */
379 /* start new page for different permissions */
380 if (CONFIG_RUNMEM_RO
|| k
< 2)
383 s
->sh_addralign
= align
;
385 addr
= k
? mem
+ ptr_diff
: mem
;
386 offset
+= -(addr
+ offset
) & (align
- 1);
387 s
->sh_addr
= mem
? addr
+ offset
: 0;
390 if (copy
) { /* set permissions */
391 if (n
== 0) /* no data */
394 if (k
== 0) /* SHF_EXECINSTR has its own mapping */
398 if (CONFIG_RUNMEM_RO
== 0) {
401 f
= 3; /* change only SHF_EXECINSTR to rwx */
403 n
= (n
+ PAGESIZE
-1) & ~(PAGESIZE
-1);
404 if (s1
->verbose
== 2) {
405 printf("protect %3s %p len %05x\n",
406 &"rx\0r \0rw\0rwx"[f
*3], (void*)addr
, (unsigned)n
);
408 if (protect_pages((void*)addr
, n
, f
) < 0)
409 return tcc_error_noabort(
410 "mprotect failed (did you mean to configure --with-selinux?)");
415 return (offset
+ (PAGESIZE
-1)) & ~(PAGESIZE
-1);
418 /* remove local symbols and free sections except symtab */
420 cleanup_sections(s1
);
424 /* relocate symbols */
425 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
426 /* relocate sections */
428 s1
->pe_imagebase
= mem
;
432 relocate_sections(s1
);
436 /* ------------------------------------------------------------- */
437 /* allow to run code in memory */
439 static int protect_pages(void *ptr
, unsigned long length
, int mode
)
442 static const unsigned char protect
[] = {
446 PAGE_EXECUTE_READWRITE
449 if (!VirtualProtect(ptr
, length
, protect
[mode
], &old
))
453 static const unsigned char protect
[] = {
454 PROT_READ
| PROT_EXEC
,
456 PROT_READ
| PROT_WRITE
,
457 PROT_READ
| PROT_WRITE
| PROT_EXEC
460 start
= (addr_t
)ptr
& ~(PAGESIZE
- 1);
461 end
= (addr_t
)ptr
+ length
;
462 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
463 if (mprotect((void *)start
, end
- start
, protect
[mode
]))
465 /* XXX: BSD sometimes dump core with bad system call */
466 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
467 if (mode
== 0 || mode
== 3) {
468 void __clear_cache(void *beginning
, void *end
);
469 __clear_cache(ptr
, (char *)ptr
+ length
);
477 static void *win64_add_function_table(TCCState
*s1
)
481 p
= (void*)s1
->uw_pdata
->sh_addr
;
483 (RUNTIME_FUNCTION
*)p
,
484 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
492 static void win64_del_function_table(void *p
)
495 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
500 static void bt_link(TCCState
*s1
)
502 #ifdef CONFIG_TCC_BACKTRACE
506 if (!s1
->do_backtrace
)
508 rc
= tcc_get_symbol(s1
, "__rt_info");
511 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
512 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
513 rc
->elf_str
= (char *)symtab_section
->link
->data
;
514 if (PTR_SIZE
== 8 && !s1
->dwarf
)
515 rc
->prog_base
&= 0xffffffff00000000ULL
;
516 #ifdef CONFIG_TCC_BCHECK
517 if (s1
->do_bounds_check
) {
518 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
519 ((void(*)(void*,int))p
)(rc
->bounds_start
, 1);
522 rc
->next
= g_rc
, g_rc
= rc
, s1
->rc
= rc
;
524 set_exception_handler(), signal_set
= 1;
528 static void st_link(TCCState
*s1
)
531 s1
->next
= g_s1
, g_s1
= s1
;
536 /* remove 'el' from 'list' */
537 static void ptr_unlink(void *list
, void *e
, unsigned next
)
540 for (pp
= list
; !!(p
= *pp
); pp
= nn
) {
541 nn
= (void*)((char*)p
+ next
); /* nn = &p->next; */
549 static void st_unlink(TCCState
*s1
)
552 #ifdef CONFIG_TCC_BACKTRACE
553 ptr_unlink(&g_rc
, s1
->rc
, offsetof(rt_context
, next
));
555 ptr_unlink(&g_s1
, s1
, offsetof(TCCState
, next
));
560 # define GETTID() GetCurrentThreadId()
561 #elif defined __linux__
562 # define GETTID() gettid()
564 # define GETTID() 1234 // threads not supported
567 LIBTCCAPI
void *_tcc_setjmp(TCCState
*s1
, void *p_jmp_buf
, void *func
, void *p_longjmp
)
573 for (s
= g_s1
; s
; s
= s
->next
)
574 if (s
->run_tid
== tid
)
576 s1
->run_tid
= (int)tid
;
579 s1
->run_lj
= p_longjmp
;
580 s1
->run_jb
= p_jmp_buf
;
581 #ifdef CONFIG_TCC_BACKTRACE
583 s1
->rc
->top_func
= func
;
588 LIBTCCAPI
void tcc_set_backtrace_func(TCCState
*s1
, void *data
, TCCBtFunc
*func
)
594 static TCCState
*rt_find_state(rt_frame
*f
)
599 for (s
= g_s1
; s
; s
= s
->next
)
600 if (s
->run_tid
== tid
)
609 if (NULL
== s
|| NULL
== s
->next
) {
610 /* play it safe in the simple case when there is only one state */
613 for (level
= 0; level
< 8; ++level
) {
614 if (rt_get_caller_pc(&pc
, f
, level
) < 0)
616 for (s
= g_s1
; s
; s
= s
->next
) {
617 if (pc
>= (addr_t
)s
->run_ptr
618 && pc
< (addr_t
)s
->run_ptr
+ s
->run_size
)
626 static void rt_exit(rt_frame
*f
, int code
)
630 s
= rt_find_state(f
);
632 if (s
&& s
->run_lj
) {
635 ((void(*)(void*,int))s
->run_lj
)(s
->run_jb
, code
);
640 /* ------------------------------------------------------------- */
641 #else // if defined CONFIG_TCC_BACKTRACE_ONLY
642 static void rt_exit(rt_frame
*f
, int code
)
646 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
647 /* ------------------------------------------------------------- */
648 #ifdef CONFIG_TCC_BACKTRACE
650 static int rt_vprintf(const char *fmt
, va_list ap
)
652 int ret
= vfprintf(stderr
, fmt
, ap
);
657 static int rt_printf(const char *fmt
, ...)
662 r
= rt_vprintf(fmt
, ap
);
667 static char *rt_elfsym(rt_context
*rc
, addr_t wanted_pc
, addr_t
*func_addr
)
670 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
671 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
672 if ((type
== STT_FUNC
|| type
== STT_GNU_IFUNC
)
673 && wanted_pc
>= esym
->st_value
674 && wanted_pc
< esym
->st_value
+ esym
->st_size
) {
675 *func_addr
= esym
->st_value
;
676 return rc
->elf_str
+ esym
->st_name
;
682 typedef struct bt_info
690 /* print the position in the source file of PC value 'pc' by reading
691 the stabs debug information */
692 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
, bt_info
*bi
)
695 addr_t func_addr
, last_pc
, pc
;
696 const char *incl_files
[INCLUDE_STACK_SIZE
];
697 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
704 last_pc
= (addr_t
)-1;
708 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
709 str
= rc
->stab_str
+ sym
->n_strx
;
712 switch(sym
->n_type
) {
720 if (sym
->n_strx
== 0) /* end of function */
724 /* Stab_Sym.n_value is only 32bits */
731 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
736 switch(sym
->n_type
) {
737 /* function start or end */
739 if (sym
->n_strx
== 0)
741 p
= strchr(str
, ':');
742 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
743 len
= sizeof func_name
;
744 pstrcpy(func_name
, len
, str
);
747 /* line number info */
750 last_line_num
= sym
->n_desc
;
751 last_incl_index
= incl_index
;
755 if (incl_index
< INCLUDE_STACK_SIZE
)
756 incl_files
[incl_index
++] = str
;
762 /* start/end of translation unit */
766 /* do not add path */
768 if (len
> 0 && str
[len
- 1] != '/')
769 incl_files
[incl_index
++] = str
;
774 last_pc
= (addr_t
)-1;
776 /* alternative file name (from #line or #include directives) */
779 incl_files
[incl_index
-1] = str
;
783 last_incl_index
= 0, func_name
[0] = 0, func_addr
= 0;
787 pstrcpy(bi
->file
, sizeof bi
->file
, incl_files
[--i
]);
788 bi
->line
= last_line_num
;
790 pstrcpy(bi
->func
, sizeof bi
->func
, func_name
);
791 bi
->func_pc
= func_addr
;
795 /* ------------------------------------------------------------- */
796 /* rt_printline - dwarf version */
798 #define MAX_128 ((8 * sizeof (long long) + 6) / 7)
800 #define DIR_TABLE_SIZE (64)
801 #define FILE_TABLE_SIZE (512)
803 #define dwarf_read_1(ln,end) \
804 ((ln) < (end) ? *(ln)++ : 0)
805 #define dwarf_read_2(ln,end) \
806 ((ln) + 2 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
807 #define dwarf_read_4(ln,end) \
808 ((ln) + 4 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
809 #define dwarf_read_8(ln,end) \
810 ((ln) + 8 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
811 #define dwarf_ignore_type(ln, end) /* timestamp/size/md5/... */ \
812 switch (entry_format[j].form) { \
813 case DW_FORM_data1: (ln) += 1; break; \
814 case DW_FORM_data2: (ln) += 2; break; \
815 case DW_FORM_data4: (ln) += 3; break; \
816 case DW_FORM_data8: (ln) += 8; break; \
817 case DW_FORM_data16: (ln) += 16; break; \
818 case DW_FORM_udata: dwarf_read_uleb128(&(ln), (end)); break; \
819 default: goto next_line; \
822 static unsigned long long
823 dwarf_read_uleb128(unsigned char **ln
, unsigned char *end
)
825 unsigned char *cp
= *ln
;
826 unsigned long long retval
= 0;
829 for (i
= 0; i
< MAX_128
; i
++) {
830 unsigned long long byte
= dwarf_read_1(cp
, end
);
832 retval
|= (byte
& 0x7f) << (i
* 7);
833 if ((byte
& 0x80) == 0)
841 dwarf_read_sleb128(unsigned char **ln
, unsigned char *end
)
843 unsigned char *cp
= *ln
;
844 long long retval
= 0;
847 for (i
= 0; i
< MAX_128
; i
++) {
848 unsigned long long byte
= dwarf_read_1(cp
, end
);
850 retval
|= (byte
& 0x7f) << (i
* 7);
851 if ((byte
& 0x80) == 0) {
852 if ((byte
& 0x40) && (i
+ 1) * 7 < 64)
853 retval
|= -1LL << ((i
+ 1) * 7);
861 static addr_t
rt_printline_dwarf (rt_context
*rc
, addr_t wanted_pc
, bt_info
*bi
)
866 unsigned char *opcode_length
;
867 unsigned long long size
;
869 unsigned char version
;
870 unsigned int min_insn_length
;
871 unsigned int max_ops_per_insn
;
873 unsigned int line_range
;
874 unsigned int opcode_base
;
875 unsigned int opindex
;
880 unsigned long long value
;
885 unsigned int dir_size
;
887 char *dirs
[DIR_TABLE_SIZE
];
889 unsigned int filename_size
;
890 struct dwarf_filename_struct
{
891 unsigned int dir_entry
;
893 } filename_table
[FILE_TABLE_SIZE
];
907 while (ln
< rc
->dwarf_line_end
) {
917 size
= dwarf_read_4(ln
, rc
->dwarf_line_end
);
918 if (size
== 0xffffffffu
) // dwarf 64
919 length
= 8, size
= dwarf_read_8(ln
, rc
->dwarf_line_end
);
921 if (end
< ln
|| end
> rc
->dwarf_line_end
)
923 version
= dwarf_read_2(ln
, end
);
925 ln
+= length
+ 2; // address size, segment selector, prologue Length
927 ln
+= length
; // prologue Length
928 min_insn_length
= dwarf_read_1(ln
, end
);
930 max_ops_per_insn
= dwarf_read_1(ln
, end
);
932 max_ops_per_insn
= 1;
933 ln
++; // Initial value of 'is_stmt'
934 line_base
= dwarf_read_1(ln
, end
);
935 line_base
|= line_base
>= 0x80 ? ~0xff : 0;
936 line_range
= dwarf_read_1(ln
, end
);
937 opcode_base
= dwarf_read_1(ln
, end
);
939 ln
+= opcode_base
- 1;
942 col
= dwarf_read_1(ln
, end
);
943 for (i
= 0; i
< col
; i
++) {
944 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
945 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
947 dir_size
= dwarf_read_uleb128(&ln
, end
);
948 for (i
= 0; i
< dir_size
; i
++) {
949 for (j
= 0; j
< col
; j
++) {
950 if (entry_format
[j
].type
== DW_LNCT_path
) {
951 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
954 value
= length
== 4 ? dwarf_read_4(ln
, end
)
955 : dwarf_read_8(ln
, end
);
956 if (i
< DIR_TABLE_SIZE
)
957 dirs
[i
] = (char *)rc
->dwarf_line_str
+ value
;
959 length
== 4 ? dwarf_read_4(ln
, end
)
960 : dwarf_read_8(ln
, end
);
964 dwarf_ignore_type(ln
, end
);
967 col
= dwarf_read_1(ln
, end
);
968 for (i
= 0; i
< col
; i
++) {
969 entry_format
[i
].type
= dwarf_read_uleb128(&ln
, end
);
970 entry_format
[i
].form
= dwarf_read_uleb128(&ln
, end
);
972 filename_size
= dwarf_read_uleb128(&ln
, end
);
973 for (i
= 0; i
< filename_size
; i
++)
974 for (j
= 0; j
< col
; j
++) {
975 if (entry_format
[j
].type
== DW_LNCT_path
) {
976 if (entry_format
[j
].form
!= DW_FORM_line_strp
)
978 value
= length
== 4 ? dwarf_read_4(ln
, end
)
979 : dwarf_read_8(ln
, end
);
980 if (i
< FILE_TABLE_SIZE
)
981 filename_table
[i
].name
=
982 (char *)rc
->dwarf_line_str
+ value
;
984 else if (entry_format
[j
].type
== DW_LNCT_directory_index
) {
985 switch (entry_format
[j
].form
) {
986 case DW_FORM_data1
: value
= dwarf_read_1(ln
, end
); break;
987 case DW_FORM_data2
: value
= dwarf_read_2(ln
, end
); break;
988 case DW_FORM_data4
: value
= dwarf_read_4(ln
, end
); break;
989 case DW_FORM_udata
: value
= dwarf_read_uleb128(&ln
, end
); break;
990 default: goto next_line
;
992 if (i
< FILE_TABLE_SIZE
)
993 filename_table
[i
].dir_entry
= value
;
996 dwarf_ignore_type(ln
, end
);
1000 while ((dwarf_read_1(ln
, end
))) {
1002 if (++dir_size
< DIR_TABLE_SIZE
)
1003 dirs
[dir_size
- 1] = (char *)ln
- 1;
1005 while (dwarf_read_1(ln
, end
)) {}
1007 while ((dwarf_read_1(ln
, end
))) {
1008 if (++filename_size
< FILE_TABLE_SIZE
) {
1009 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
1010 while (dwarf_read_1(ln
, end
)) {}
1011 filename_table
[filename_size
- 1].dir_entry
=
1012 dwarf_read_uleb128(&ln
, end
);
1015 while (dwarf_read_1(ln
, end
)) {}
1016 dwarf_read_uleb128(&ln
, end
);
1018 dwarf_read_uleb128(&ln
, end
); // time
1019 dwarf_read_uleb128(&ln
, end
); // size
1022 if (filename_size
>= 1)
1023 filename
= filename_table
[0].name
;
1026 i
= dwarf_read_1(ln
, end
);
1027 if (i
>= opcode_base
) {
1028 if (max_ops_per_insn
== 1)
1029 pc
+= ((i
- opcode_base
) / line_range
) * min_insn_length
;
1031 pc
+= (opindex
+ (i
- opcode_base
) / line_range
) /
1032 max_ops_per_insn
* min_insn_length
;
1033 opindex
= (opindex
+ (i
- opcode_base
) / line_range
) %
1036 i
= (int)((i
- opcode_base
) % line_range
) + line_base
;
1038 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
1045 len
= dwarf_read_uleb128(&ln
, end
);
1050 switch (dwarf_read_1(cp
, end
)) {
1051 case DW_LNE_end_sequence
:
1053 case DW_LNE_set_address
:
1055 pc
= dwarf_read_4(cp
, end
);
1057 pc
= dwarf_read_8(cp
, end
);
1059 #if defined TCC_TARGET_MACHO
1060 pc
+= rc
->prog_base
;
1064 case DW_LNE_define_file
: /* deprecated */
1065 if (++filename_size
< FILE_TABLE_SIZE
) {
1066 filename_table
[filename_size
- 1].name
= (char *)ln
- 1;
1067 while (dwarf_read_1(ln
, end
)) {}
1068 filename_table
[filename_size
- 1].dir_entry
=
1069 dwarf_read_uleb128(&ln
, end
);
1072 while (dwarf_read_1(ln
, end
)) {}
1073 dwarf_read_uleb128(&ln
, end
);
1075 dwarf_read_uleb128(&ln
, end
); // time
1076 dwarf_read_uleb128(&ln
, end
); // size
1078 case DW_LNE_hi_user
- 1:
1079 function
= (char *)cp
;
1086 case DW_LNS_advance_pc
:
1087 if (max_ops_per_insn
== 1)
1088 pc
+= dwarf_read_uleb128(&ln
, end
) * min_insn_length
;
1090 unsigned long long off
= dwarf_read_uleb128(&ln
, end
);
1092 pc
+= (opindex
+ off
) / max_ops_per_insn
*
1094 opindex
= (opindex
+ off
) % max_ops_per_insn
;
1098 case DW_LNS_advance_line
:
1099 line
+= dwarf_read_sleb128(&ln
, end
);
1101 case DW_LNS_set_file
:
1102 i
= dwarf_read_uleb128(&ln
, end
);
1103 i
-= i
> 0 && version
< 5;
1104 if (i
< FILE_TABLE_SIZE
&& i
< filename_size
)
1105 filename
= filename_table
[i
].name
;
1107 case DW_LNS_const_add_pc
:
1108 if (max_ops_per_insn
== 1)
1109 pc
+= ((255 - opcode_base
) / line_range
) * min_insn_length
;
1111 unsigned int off
= (255 - opcode_base
) / line_range
;
1113 pc
+= ((opindex
+ off
) / max_ops_per_insn
) *
1115 opindex
= (opindex
+ off
) % max_ops_per_insn
;
1119 case DW_LNS_fixed_advance_pc
:
1120 i
= dwarf_read_2(ln
, end
);
1126 for (j
= 0; j
< opcode_length
[i
- 1]; j
++)
1127 dwarf_read_uleb128 (&ln
, end
);
1135 filename
= function
= NULL
, func_addr
= 0;
1138 pstrcpy(bi
->file
, sizeof bi
->file
, filename
), bi
->line
= line
;
1140 pstrcpy(bi
->func
, sizeof bi
->func
, function
);
1141 bi
->func_pc
= func_addr
;
1142 return (addr_t
)func_addr
;
1144 /* ------------------------------------------------------------- */
1145 #ifndef CONFIG_TCC_BACKTRACE_ONLY
1148 int _tcc_backtrace(rt_frame
*f
, const char *fmt
, va_list ap
)
1150 rt_context
*rc
, *rc2
;
1152 char skip
[40], msg
[200];
1153 int i
, level
, ret
, n
, one
;
1156 addr_t (*getinfo
)(rt_context
*, addr_t
, bt_info
*);
1159 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
1160 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
1161 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
1165 /* hack for bcheck.c:dprintf(): one level, no newline */
1166 if (fmt
[0] == '\001')
1168 vsnprintf(msg
, sizeof msg
, fmt
, ap
);
1172 getinfo
= rt_printline
, n
= 6;
1175 getinfo
= rt_printline_dwarf
;
1176 if (rc
->num_callers
)
1177 n
= rc
->num_callers
;
1180 for (i
= level
= 0; level
< n
; i
++) {
1181 ret
= rt_get_caller_pc(&pc
, f
, i
);
1184 memset(&bi
, 0, sizeof bi
);
1185 for (rc2
= rc
; rc2
; rc2
= rc2
->next
) {
1186 if (getinfo(rc2
, pc
, &bi
))
1188 /* we try symtab symbols (no line number info) */
1189 if (!!(a
= rt_elfsym(rc2
, pc
, &bi
.func_pc
))) {
1190 pstrcpy(bi
.func
, sizeof bi
.func
, a
);
1194 //fprintf(stderr, "%d rc %p %p\n", i, (void*)pcfunc, (void*)pc);
1195 if (skip
[0] && strstr(bi
.file
, skip
))
1197 #ifndef CONFIG_TCC_BACKTRACE_ONLY
1199 TCCState
*s
= rt_find_state(f
);
1200 if (s
&& s
->bt_func
) {
1204 bi
.file
[0] ? bi
.file
: NULL
,
1206 bi
.func
[0] ? bi
.func
: NULL
,
1207 level
== 0 ? msg
: NULL
1216 rt_printf("%s:%d", bi
.file
, bi
.line
);
1218 rt_printf("0x%08llx", (long long)pc
);
1220 rt_printf(": %s %s", level
? "by" : "at", bi
.func
[0] ? bi
.func
: "???");
1222 rt_printf(": %s", msg
);
1231 && bi
.func_pc
== (addr_t
)rc2
->top_func
)
1239 /* emit a run time error at position 'pc' */
1240 static int rt_error(rt_frame
*f
, const char *fmt
, ...)
1242 va_list ap
; char msg
[200]; int ret
;
1244 snprintf(msg
, sizeof msg
, "RUNTIME ERROR: %s", fmt
);
1245 ret
= _tcc_backtrace(f
, msg
, ap
);
1250 /* ------------------------------------------------------------- */
1253 # include <signal.h>
1254 # ifndef __OpenBSD__
1255 # include <sys/ucontext.h>
1258 # define ucontext_t CONTEXT
1261 /* translate from ucontext_t* to internal rt_context * */
1262 static void rt_getcontext(ucontext_t
*uc
, rt_frame
*rc
)
1268 #elif defined _WIN32
1272 #elif defined __i386__
1273 # if defined(__APPLE__)
1274 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
1275 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
1276 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1277 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
1278 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
1279 # elif defined(__dietlibc__)
1280 rc
->ip
= uc
->uc_mcontext
.eip
;
1281 rc
->fp
= uc
->uc_mcontext
.ebp
;
1282 # elif defined(__NetBSD__)
1283 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
1284 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
1285 # elif defined(__OpenBSD__)
1286 rc
->ip
= uc
->sc_eip
;
1287 rc
->fp
= uc
->sc_ebp
;
1288 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
1289 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
1290 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
1292 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1293 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
1295 #elif defined(__x86_64__)
1296 # if defined(__APPLE__)
1297 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
1298 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
1299 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1300 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
1301 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
1302 # elif defined(__NetBSD__)
1303 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
1304 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
1305 # elif defined(__OpenBSD__)
1306 rc
->ip
= uc
->sc_rip
;
1307 rc
->fp
= uc
->sc_rbp
;
1309 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1310 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
1312 #elif defined(__arm__) && defined(__NetBSD__)
1313 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1314 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1315 #elif defined(__arm__) && defined(__OpenBSD__)
1317 rc
->fp
= uc
->sc_r11
;
1318 #elif defined(__arm__) && defined(__FreeBSD__)
1319 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1320 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1321 #elif defined(__arm__)
1322 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
1323 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
1324 #elif defined(__aarch64__) && defined(__APPLE__)
1326 // /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/usr/include/mach/arm/_structs.h
1327 rc
->ip
= uc
->uc_mcontext
->__ss
.__pc
;
1328 rc
->fp
= uc
->uc_mcontext
->__ss
.__fp
;
1329 #elif defined(__aarch64__) && defined(__FreeBSD__)
1330 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
1331 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
1332 #elif defined(__aarch64__) && defined(__NetBSD__)
1333 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
1334 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
1335 #elif defined(__aarch64__) && defined(__OpenBSD__)
1336 rc
->ip
= uc
->sc_elr
;
1337 rc
->fp
= uc
->sc_x
[29];
1338 #elif defined(__aarch64__)
1339 rc
->ip
= uc
->uc_mcontext
.pc
;
1340 rc
->fp
= uc
->uc_mcontext
.regs
[29];
1341 #elif defined(__riscv) && defined(__OpenBSD__)
1342 rc
->ip
= uc
->sc_sepc
;
1343 rc
->fp
= uc
->sc_s
[0];
1344 #elif defined(__riscv)
1345 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
1346 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
1350 /* ------------------------------------------------------------- */
1352 /* signal handler for fatal errors */
1353 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
1356 rt_getcontext(puc
, &f
);
1360 switch(siginf
->si_code
) {
1363 rt_error(&f
, "division by zero");
1366 rt_error(&f
, "floating point exception");
1372 rt_error(&f
, "invalid memory access");
1375 rt_error(&f
, "illegal instruction");
1378 rt_error(&f
, "abort() called");
1381 rt_error(&f
, "caught signal %d", signum
);
1387 sigaddset(&s
, signum
);
1388 sigprocmask(SIG_UNBLOCK
, &s
, NULL
);
1394 # define SA_SIGINFO 0x00000004u
1397 /* Generate a stack backtrace when a CPU exception occurs. */
1398 static void set_exception_handler(void)
1400 struct sigaction sigact
;
1401 /* install TCC signal handlers to print debug info on fatal
1403 sigemptyset (&sigact
.sa_mask
);
1404 sigact
.sa_flags
= SA_SIGINFO
; //| SA_RESETHAND;
1405 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
1406 sigact
.sa_flags
|= SA_ONSTACK
;
1408 sigact
.sa_sigaction
= sig_error
;
1409 sigaction(SIGFPE
, &sigact
, NULL
);
1410 sigaction(SIGILL
, &sigact
, NULL
);
1411 sigaction(SIGSEGV
, &sigact
, NULL
);
1412 sigaction(SIGBUS
, &sigact
, NULL
);
1413 sigaction(SIGABRT
, &sigact
, NULL
);
1415 /* This allows stack overflow to be reported instead of a SEGV */
1418 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
1421 ss
.ss_size
= SIGSTKSZ
;
1423 sigaltstack(&ss
, NULL
);
1430 /* signal handler for fatal errors */
1431 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
1435 rt_getcontext(ex_info
->ContextRecord
, &f
);
1437 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
1438 case EXCEPTION_ACCESS_VIOLATION
:
1439 rt_error(&f
, "invalid memory access");
1441 case EXCEPTION_STACK_OVERFLOW
:
1442 rt_error(&f
, "stack overflow");
1444 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
1445 rt_error(&f
, "division by zero");
1447 case EXCEPTION_BREAKPOINT
:
1448 case EXCEPTION_SINGLE_STEP
:
1449 f
.ip
= *(addr_t
*)f
.sp
;
1450 rt_error(&f
, "breakpoint/single-step exception:");
1451 return EXCEPTION_CONTINUE_SEARCH
;
1453 rt_error(&f
, "caught exception %08x", code
);
1457 return EXCEPTION_EXECUTE_HANDLER
;
1460 /* Generate a stack backtrace when a CPU exception occurs. */
1461 static void set_exception_handler(void)
1463 SetUnhandledExceptionFilter(cpu_exception_handler
);
1468 /* ------------------------------------------------------------- */
1469 /* return the PC at frame level 'level'. Return negative if not found */
1470 #if defined(__i386__) || defined(__x86_64__)
1471 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1482 /* XXX: check address validity with program info */
1483 fp
= ((addr_t
*)fp
)[0];
1485 *paddr
= ((addr_t
*)fp
)[1];
1490 /* XXX: only supports linux/bsd */
1491 #elif defined(__arm__) && !defined(_WIN32)
1492 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1503 fp
= ((addr_t
*)fp
)[0];
1505 *paddr
= ((addr_t
*)fp
)[2];
1510 #elif defined(__aarch64__)
1511 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1522 fp
= ((addr_t
*)fp
)[0];
1524 *paddr
= ((addr_t
*)fp
)[1];
1529 #elif defined(__riscv)
1530 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1541 fp
= ((addr_t
*)fp
)[-2];
1543 *paddr
= ((addr_t
*)fp
)[-1];
1549 #warning add arch specific rt_get_caller_pc()
1550 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*rc
, int level
)
1556 #else // for runmain.c:exit(); when CONFIG_TCC_BACKTRACE == 0 */
1557 static int rt_get_caller_pc(addr_t
*paddr
, rt_frame
*f
, int level
)
1564 #endif /* CONFIG_TCC_BACKTRACE */
1565 /* ------------------------------------------------------------- */
1566 #ifdef CONFIG_TCC_STATIC
1568 /* dummy function for profiling */
1569 ST_FUNC
void *dlopen(const char *filename
, int flag
)
1574 ST_FUNC
void dlclose(void *p
)
1578 ST_FUNC
const char *dlerror(void)
1583 typedef struct TCCSyms
{
1589 /* add the symbol you want here if no dynamic linking is done */
1590 static TCCSyms tcc_syms
[] = {
1591 #if !defined(CONFIG_TCCBOOT)
1592 #define TCCSYM(a) { #a, &a, },
1602 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
1606 while (p
->str
!= NULL
) {
1607 if (!strcmp(p
->str
, symbol
))
1614 #endif /* CONFIG_TCC_STATIC */
1615 #endif /* TCC_IS_NATIVE */
1616 /* ------------------------------------------------------------- */