fix-mixed-struct (patch by Pip Cet)
[tinycc.git] / tccrun.c
Commit [+]AuthorDateLineData
3db21947 grischka2009-12-19 22:10:26 +01001/*
88a3ccab grischka2009-12-20 01:53:49 +01002 * TCC - Tiny C Compiler - Support for -run switch
3db21947 grischka2009-12-19 22:10:26 +01003 *
4 * Copyright (c) 2001-2004 Fabrice Bellard
5 *
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.
10 *
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.
15 *
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
19 */
20
88a3ccab grischka2009-12-20 01:53:49 +010021#include "tcc.h"
3db21947 grischka2009-12-19 22:10:26 +010022
a35b3059 grischka2012-03-05 20:15:56 +010023/* only native compiler supports -run */
24#ifdef TCC_IS_NATIVE
25
74a24d77 grischka2011-08-11 16:55:30 +020026#ifdef CONFIG_TCC_BACKTRACE
27ST_DATA int rt_num_callers = 6;
28ST_DATA const char **rt_bound_error_msg;
29ST_DATA void *rt_prog_main;
30#endif
31
7fa712e0 grischka2009-12-19 22:22:43 +010032#ifdef _WIN32
33#define ucontext_t CONTEXT
34#endif
3db21947 grischka2009-12-19 22:10:26 +010035
7fa712e0 grischka2009-12-19 22:22:43 +010036static void set_pages_executable(void *ptr, unsigned long length);
37static void set_exception_handler(void);
82bcbd02 grischka2013-02-04 16:08:06 +010038static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
7fa712e0 grischka2009-12-19 22:22:43 +010039static void rt_error(ucontext_t *uc, const char *fmt, ...);
40static int tcc_relocate_ex(TCCState *s1, void *ptr);
3db21947 grischka2009-12-19 22:10:26 +010041
5775911d Andrew Mulbrook2012-03-03 10:12:06 -060042#ifdef _WIN64
df4c0892 grischka2011-07-14 19:09:49 +020043static void win64_add_function_table(TCCState *s1);
44#endif
45
7fa712e0 grischka2009-12-19 22:22:43 +010046/* ------------------------------------------------------------- */
47/* Do all relocations (needed before using tcc_get_symbol())
48 Returns -1 on error. */
3db21947 grischka2009-12-19 22:10:26 +010049
ca38792d grischka2012-09-01 11:33:34 +020050LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
3db21947 grischka2009-12-19 22:10:26 +010051{
7fa712e0 grischka2009-12-19 22:22:43 +010052 int ret;
ca38792d grischka2012-09-01 11:33:34 +020053
54 if (TCC_RELOCATE_AUTO != ptr)
55 return tcc_relocate_ex(s1, ptr);
56
05108a3b grischka2013-02-12 19:13:28 +010057 ret = tcc_relocate_ex(s1, NULL);
58 if (ret < 0)
59 return ret;
60
2ab42855 Henry Kroll III2010-04-24 03:28:54 -070061#ifdef HAVE_SELINUX
8e724128
I
Iavael2014-01-12 09:26:41 +040062 { /* Use mmap instead of malloc for Selinux. Ref:
63 http://www.gnu.org/s/libc/manual/html_node/File-Size.html */
64
65 char tmpfname[] = "/tmp/.tccrunXXXXXX";
66 int fd = mkstemp (tmpfname);
67
80b36ab6 keren2014-01-10 10:23:11 -080068 s1->mem_size = ret;
8e724128
I
Iavael2014-01-12 09:26:41 +040069 unlink (tmpfname);
70 ftruncate (fd, s1->mem_size);
80b36ab6 keren2014-01-10 10:23:11 -080071
05108a3b grischka2013-02-12 19:13:28 +010072 s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
8e724128 Iavael2014-01-12 09:26:41 +040073 MAP_SHARED, fd, 0);
05108a3b grischka2013-02-12 19:13:28 +010074 if (s1->write_mem == MAP_FAILED)
8e724128 Iavael2014-01-12 09:26:41 +040075 tcc_error("/tmp not writeable");
05108a3b grischka2013-02-12 19:13:28 +010076
77 s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
8e724128 Iavael2014-01-12 09:26:41 +040078 MAP_SHARED, fd, 0);
05108a3b grischka2013-02-12 19:13:28 +010079 if (s1->runtime_mem == MAP_FAILED)
8e724128 Iavael2014-01-12 09:26:41 +040080 tcc_error("/tmp not executable");
05108a3b grischka2013-02-12 19:13:28 +010081
82 ret = tcc_relocate_ex(s1, s1->write_mem);
2ab42855 Henry Kroll III2010-04-24 03:28:54 -070083 }
2ab42855 Henry Kroll III2010-04-24 03:28:54 -070084#else
05108a3b grischka2013-02-12 19:13:28 +010085 s1->runtime_mem = tcc_malloc(ret);
86 ret = tcc_relocate_ex(s1, s1->runtime_mem);
2ab42855 Henry Kroll III2010-04-24 03:28:54 -070087#endif
7fa712e0 grischka2009-12-19 22:22:43 +010088 return ret;
3db21947 grischka2009-12-19 22:10:26 +010089}
90
7fa712e0 grischka2009-12-19 22:22:43 +010091/* launch the compiled program with the given arguments */
74a24d77 grischka2011-08-11 16:55:30 +020092LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
3db21947 grischka2009-12-19 22:10:26 +010093{
7fa712e0 grischka2009-12-19 22:22:43 +010094 int (*prog_main)(int, char **);
d483ab32 grischka2010-09-15 13:43:40 +020095 int ret;
2ab42855 Henry Kroll III2010-04-24 03:28:54 -070096
ca38792d grischka2012-09-01 11:33:34 +020097 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
7fa712e0 grischka2009-12-19 22:22:43 +010098 return -1;
2ab42855 Henry Kroll III2010-04-24 03:28:54 -070099
73faaea2 grischka2013-08-28 22:55:05 +0200100 prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
3db21947 grischka2009-12-19 22:10:26 +0100101
7fa712e0 grischka2009-12-19 22:22:43 +0100102#ifdef CONFIG_TCC_BACKTRACE
d483ab32 grischka2010-09-15 13:43:40 +0200103 if (s1->do_debug) {
7fa712e0 grischka2009-12-19 22:22:43 +0100104 set_exception_handler();
d483ab32 grischka2010-09-15 13:43:40 +0200105 rt_prog_main = prog_main;
106 }
3db21947 grischka2009-12-19 22:10:26 +0100107#endif
3db21947 grischka2009-12-19 22:10:26 +0100108
7fa712e0 grischka2009-12-19 22:22:43 +0100109#ifdef CONFIG_TCC_BCHECK
110 if (s1->do_bounds_check) {
111 void (*bound_init)(void);
112 void (*bound_exit)(void);
acef4ff2 seyko2015-03-26 07:47:45 +0300113 void (*bound_new_region)(void *p, addr_t size);
75118780
KS
Kirill Smelkov2014-01-19 16:35:20 +0400114 int (*bound_delete_region)(void *p);
115 int i;
116
7fa712e0 grischka2009-12-19 22:22:43 +0100117 /* set error function */
118 rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
7fa712e0 grischka2009-12-19 22:22:43 +0100119 /* XXX: use .init section so that it also work in binary ? */
120 bound_init = tcc_get_symbol_err(s1, "__bound_init");
121 bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
75118780
KS
Kirill Smelkov2014-01-19 16:35:20 +0400122 bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
123 bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
7fa712e0 grischka2009-12-19 22:22:43 +0100124 bound_init();
75118780
KS
Kirill Smelkov2014-01-19 16:35:20 +0400125 /* mark argv area as valid */
126 bound_new_region(argv, argc*sizeof(argv[0]));
127 for (i=0; i<argc; ++i)
128 bound_new_region(argv[i], strlen(argv[i]));
129
cde79a80 seyko2015-03-25 13:26:11 +0300130 errno = 0; /* clean errno value */
7fa712e0 grischka2009-12-19 22:22:43 +0100131 ret = (*prog_main)(argc, argv);
75118780
KS
Kirill Smelkov2014-01-19 16:35:20 +0400132
133 /* unmark argv area */
134 for (i=0; i<argc; ++i)
135 bound_delete_region(argv[i]);
136 bound_delete_region(argv);
137
7fa712e0 grischka2009-12-19 22:22:43 +0100138 bound_exit();
d483ab32 grischka2010-09-15 13:43:40 +0200139 } else
50b040ef grischka2009-12-19 22:40:28 +0100140#endif
cde79a80 seyko2015-03-25 13:26:11 +0300141 {
142 errno = 0; /* clean errno value */
d483ab32 grischka2010-09-15 13:43:40 +0200143 ret = (*prog_main)(argc, argv);
cde79a80 seyko2015-03-25 13:26:11 +0300144 }
d483ab32 grischka2010-09-15 13:43:40 +0200145 return ret;
3db21947 grischka2009-12-19 22:10:26 +0100146}
147
7fa712e0 grischka2009-12-19 22:22:43 +0100148/* relocate code. Return -1 on error, required size if ptr is NULL,
149 otherwise copy code into buffer passed by the caller */
150static int tcc_relocate_ex(TCCState *s1, void *ptr)
151{
152 Section *s;
153 unsigned long offset, length;
82bcbd02 grischka2013-02-04 16:08:06 +0100154 addr_t mem;
7fa712e0 grischka2009-12-19 22:22:43 +0100155 int i;
156
05108a3b grischka2013-02-12 19:13:28 +0100157 if (NULL == ptr) {
7fa712e0 grischka2009-12-19 22:22:43 +0100158 s1->nb_errors = 0;
159#ifdef TCC_TARGET_PE
160 pe_output_file(s1, NULL);
3db21947 grischka2009-12-19 22:10:26 +0100161#else
7fa712e0 grischka2009-12-19 22:22:43 +0100162 tcc_add_runtime(s1);
163 relocate_common_syms();
164 tcc_add_linker_symbols(s1);
165 build_got_entries(s1);
166#endif
167 if (s1->nb_errors)
168 return -1;
169 }
3db21947 grischka2009-12-19 22:10:26 +0100170
82bcbd02 grischka2013-02-04 16:08:06 +0100171 offset = 0, mem = (addr_t)ptr;
7fa712e0 grischka2009-12-19 22:22:43 +0100172 for(i = 1; i < s1->nb_sections; i++) {
173 s = s1->sections[i];
174 if (0 == (s->sh_flags & SHF_ALLOC))
175 continue;
176 length = s->data_offset;
177 s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
178 offset = (offset + length + 15) & ~15;
179 }
180 offset += 16;
181
182 /* relocate symbols */
183 relocate_syms(s1, 1);
184 if (s1->nb_errors)
185 return -1;
186
7fa712e0 grischka2009-12-19 22:22:43 +0100187 if (0 == mem)
188 return offset;
189
190 /* relocate each section */
191 for(i = 1; i < s1->nb_sections; i++) {
192 s = s1->sections[i];
193 if (s->reloc)
194 relocate_section(s1, s);
195 }
9750d0b7 Michael Matz2014-04-06 00:30:22 +0200196 relocate_plt(s1);
7fa712e0 grischka2009-12-19 22:22:43 +0100197
198 for(i = 1; i < s1->nb_sections; i++) {
199 s = s1->sections[i];
200 if (0 == (s->sh_flags & SHF_ALLOC))
201 continue;
202 length = s->data_offset;
6d055312 Michael Matz2015-02-22 05:59:06 +0100203 // printf("%-12s %08lx %04x\n", s->name, s->sh_addr, length);
82bcbd02 grischka2013-02-04 16:08:06 +0100204 ptr = (void*)s->sh_addr;
7fa712e0 grischka2009-12-19 22:22:43 +0100205 if (NULL == s->data || s->sh_type == SHT_NOBITS)
206 memset(ptr, 0, length);
207 else
208 memcpy(ptr, s->data, length);
209 /* mark executable sections as executable in memory */
210 if (s->sh_flags & SHF_EXECINSTR)
211 set_pages_executable(ptr, length);
212 }
213
5775911d Andrew Mulbrook2012-03-03 10:12:06 -0600214#ifdef _WIN64
df4c0892 grischka2011-07-14 19:09:49 +0200215 win64_add_function_table(s1);
216#endif
7fa712e0 grischka2009-12-19 22:22:43 +0100217 return 0;
3db21947 grischka2009-12-19 22:10:26 +0100218}
219
7fa712e0 grischka2009-12-19 22:22:43 +0100220/* ------------------------------------------------------------- */
221/* allow to run code in memory */
3db21947 grischka2009-12-19 22:10:26 +0100222
7fa712e0 grischka2009-12-19 22:22:43 +0100223static void set_pages_executable(void *ptr, unsigned long length)
224{
225#ifdef _WIN32
226 unsigned long old_protect;
227 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
228#else
b46f7461 Christian Jullien2014-02-08 08:31:32 +0100229 extern void __clear_cache(char *beginning, char *end);
05108a3b grischka2013-02-12 19:13:28 +0100230#ifndef PAGESIZE
231# define PAGESIZE 4096
232#endif
82bcbd02 grischka2013-02-04 16:08:06 +0100233 addr_t start, end;
234 start = (addr_t)ptr & ~(PAGESIZE - 1);
235 end = (addr_t)ptr + length;
7fa712e0 grischka2009-12-19 22:22:43 +0100236 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
237 mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
c68af2db Thomas Preud'homme2013-03-19 14:03:15 +0100238 __clear_cache(ptr, ptr + length);
7fa712e0 grischka2009-12-19 22:22:43 +0100239#endif
240}
3db21947 grischka2009-12-19 22:10:26 +0100241
7fa712e0 grischka2009-12-19 22:22:43 +0100242/* ------------------------------------------------------------- */
3db21947 grischka2009-12-19 22:10:26 +0100243#ifdef CONFIG_TCC_BACKTRACE
244
05108a3b grischka2013-02-12 19:13:28 +0100245ST_FUNC void tcc_set_num_callers(int n)
74a24d77 grischka2011-08-11 16:55:30 +0200246{
247 rt_num_callers = n;
248}
249
3db21947 grischka2009-12-19 22:10:26 +0100250/* print the position in the source file of PC value 'pc' by reading
251 the stabs debug information */
82bcbd02 grischka2013-02-04 16:08:06 +0100252static addr_t rt_printline(addr_t wanted_pc, const char *msg)
3db21947 grischka2009-12-19 22:10:26 +0100253{
3db21947 grischka2009-12-19 22:10:26 +0100254 char func_name[128], last_func_name[128];
82bcbd02 grischka2013-02-04 16:08:06 +0100255 addr_t func_addr, last_pc, pc;
3db21947 grischka2009-12-19 22:10:26 +0100256 const char *incl_files[INCLUDE_STACK_SIZE];
257 int incl_index, len, last_line_num, i;
258 const char *str, *p;
259
d59bd8be grischka2010-09-15 13:43:09 +0200260 Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym;
261 int stab_len = 0;
262 char *stab_str = NULL;
263
264 if (stab_section) {
265 stab_len = stab_section->data_offset;
266 stab_sym = (Stab_Sym *)stab_section->data;
62d1da1b Thomas Preud'homme2014-03-09 22:52:31 +0800267 stab_str = (char *) stabstr_section->data;
d59bd8be grischka2010-09-15 13:43:09 +0200268 }
269
3db21947 grischka2009-12-19 22:10:26 +0100270 func_name[0] = '\0';
271 func_addr = 0;
272 incl_index = 0;
273 last_func_name[0] = '\0';
82bcbd02 grischka2013-02-04 16:08:06 +0100274 last_pc = (addr_t)-1;
3db21947 grischka2009-12-19 22:10:26 +0100275 last_line_num = 1;
d59bd8be grischka2010-09-15 13:43:09 +0200276
277 if (!stab_sym)
278 goto no_stabs;
279
280 stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len);
281 for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
3db21947 grischka2009-12-19 22:10:26 +0100282 switch(sym->n_type) {
283 /* function start or end */
284 case N_FUN:
285 if (sym->n_strx == 0) {
286 /* we test if between last line and end of function */
287 pc = sym->n_value + func_addr;
288 if (wanted_pc >= last_pc && wanted_pc < pc)
289 goto found;
290 func_name[0] = '\0';
291 func_addr = 0;
292 } else {
d59bd8be grischka2010-09-15 13:43:09 +0200293 str = stab_str + sym->n_strx;
3db21947 grischka2009-12-19 22:10:26 +0100294 p = strchr(str, ':');
295 if (!p) {
296 pstrcpy(func_name, sizeof(func_name), str);
297 } else {
298 len = p - str;
299 if (len > sizeof(func_name) - 1)
300 len = sizeof(func_name) - 1;
301 memcpy(func_name, str, len);
302 func_name[len] = '\0';
303 }
304 func_addr = sym->n_value;
305 }
306 break;
307 /* line number info */
308 case N_SLINE:
309 pc = sym->n_value + func_addr;
310 if (wanted_pc >= last_pc && wanted_pc < pc)
311 goto found;
312 last_pc = pc;
313 last_line_num = sym->n_desc;
314 /* XXX: slow! */
315 strcpy(last_func_name, func_name);
316 break;
317 /* include files */
318 case N_BINCL:
d59bd8be grischka2010-09-15 13:43:09 +0200319 str = stab_str + sym->n_strx;
3db21947 grischka2009-12-19 22:10:26 +0100320 add_incl:
321 if (incl_index < INCLUDE_STACK_SIZE) {
322 incl_files[incl_index++] = str;
323 }
324 break;
325 case N_EINCL:
326 if (incl_index > 1)
327 incl_index--;
328 break;
329 case N_SO:
330 if (sym->n_strx == 0) {
331 incl_index = 0; /* end of translation unit */
332 } else {
d59bd8be grischka2010-09-15 13:43:09 +0200333 str = stab_str + sym->n_strx;
3db21947 grischka2009-12-19 22:10:26 +0100334 /* do not add path */
335 len = strlen(str);
336 if (len > 0 && str[len - 1] != '/')
337 goto add_incl;
338 }
339 break;
340 }
3db21947 grischka2009-12-19 22:10:26 +0100341 }
342
d59bd8be grischka2010-09-15 13:43:09 +0200343no_stabs:
3db21947 grischka2009-12-19 22:10:26 +0100344 /* second pass: we try symtab symbols (no line number info) */
345 incl_index = 0;
d59bd8be grischka2010-09-15 13:43:09 +0200346 if (symtab_section)
3db21947 grischka2009-12-19 22:10:26 +0100347 {
348 ElfW(Sym) *sym, *sym_end;
349 int type;
350
351 sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
352 for(sym = (ElfW(Sym) *)symtab_section->data + 1;
353 sym < sym_end;
354 sym++) {
355 type = ELFW(ST_TYPE)(sym->st_info);
036d9411 Thomas Preud'homme2010-10-10 16:23:25 +0200356 if (type == STT_FUNC || type == STT_GNU_IFUNC) {
3db21947 grischka2009-12-19 22:10:26 +0100357 if (wanted_pc >= sym->st_value &&
358 wanted_pc < sym->st_value + sym->st_size) {
359 pstrcpy(last_func_name, sizeof(last_func_name),
62d1da1b Thomas Preud'homme2014-03-09 22:52:31 +0800360 (char *) strtab_section->data + sym->st_name);
3db21947 grischka2009-12-19 22:10:26 +0100361 func_addr = sym->st_value;
362 goto found;
363 }
364 }
365 }
366 }
367 /* did not find any info: */
af839938 grischka2010-09-15 13:42:52 +0200368 fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc);
369 fflush(stderr);
3db21947 grischka2009-12-19 22:10:26 +0100370 return 0;
371 found:
af839938 grischka2010-09-15 13:42:52 +0200372 i = incl_index;
373 if (i > 0)
374 fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num);
375 fprintf(stderr, "%s %p", msg, (void*)wanted_pc);
376 if (last_func_name[0] != '\0')
3db21947 grischka2009-12-19 22:10:26 +0100377 fprintf(stderr, " %s()", last_func_name);
af839938 grischka2010-09-15 13:42:52 +0200378 if (--i >= 0) {
379 fprintf(stderr, " (included from ");
380 for (;;) {
381 fprintf(stderr, "%s", incl_files[i]);
382 if (--i < 0)
383 break;
384 fprintf(stderr, ", ");
385 }
3db21947 grischka2009-12-19 22:10:26 +0100386 fprintf(stderr, ")");
387 }
388 fprintf(stderr, "\n");
af839938 grischka2010-09-15 13:42:52 +0200389 fflush(stderr);
3db21947 grischka2009-12-19 22:10:26 +0100390 return func_addr;
391}
392
7fa712e0 grischka2009-12-19 22:22:43 +0100393/* emit a run time error at position 'pc' */
394static void rt_error(ucontext_t *uc, const char *fmt, ...)
395{
396 va_list ap;
82bcbd02 grischka2013-02-04 16:08:06 +0100397 addr_t pc;
7fa712e0 grischka2009-12-19 22:22:43 +0100398 int i;
399
7fa712e0 grischka2009-12-19 22:22:43 +0100400 fprintf(stderr, "Runtime error: ");
d483ab32 grischka2010-09-15 13:43:40 +0200401 va_start(ap, fmt);
7fa712e0 grischka2009-12-19 22:22:43 +0100402 vfprintf(stderr, fmt, ap);
d483ab32 grischka2010-09-15 13:43:40 +0200403 va_end(ap);
7fa712e0 grischka2009-12-19 22:22:43 +0100404 fprintf(stderr, "\n");
405
74a24d77 grischka2011-08-11 16:55:30 +0200406 for(i=0;i<rt_num_callers;i++) {
7fa712e0 grischka2009-12-19 22:22:43 +0100407 if (rt_get_caller_pc(&pc, uc, i) < 0)
408 break;
af839938 grischka2010-09-15 13:42:52 +0200409 pc = rt_printline(pc, i ? "by" : "at");
82bcbd02 grischka2013-02-04 16:08:06 +0100410 if (pc == (addr_t)rt_prog_main && pc)
7fa712e0 grischka2009-12-19 22:22:43 +0100411 break;
412 }
7fa712e0 grischka2009-12-19 22:22:43 +0100413}
414
415/* ------------------------------------------------------------- */
416#ifndef _WIN32
417
418/* signal handler for fatal errors */
419static void sig_error(int signum, siginfo_t *siginf, void *puc)
420{
421 ucontext_t *uc = puc;
422
423 switch(signum) {
424 case SIGFPE:
425 switch(siginf->si_code) {
426 case FPE_INTDIV:
427 case FPE_FLTDIV:
428 rt_error(uc, "division by zero");
429 break;
430 default:
431 rt_error(uc, "floating point exception");
432 break;
433 }
434 break;
435 case SIGBUS:
436 case SIGSEGV:
437 if (rt_bound_error_msg && *rt_bound_error_msg)
438 rt_error(uc, *rt_bound_error_msg);
439 else
440 rt_error(uc, "dereferencing invalid pointer");
441 break;
442 case SIGILL:
443 rt_error(uc, "illegal instruction");
444 break;
445 case SIGABRT:
446 rt_error(uc, "abort() called");
447 break;
448 default:
449 rt_error(uc, "caught signal %d", signum);
450 break;
451 }
452 exit(255);
453}
454
05108a3b grischka2013-02-12 19:13:28 +0100455#ifndef SA_SIGINFO
456# define SA_SIGINFO 0x00000004u
457#endif
458
7fa712e0 grischka2009-12-19 22:22:43 +0100459/* Generate a stack backtrace when a CPU exception occurs. */
460static void set_exception_handler(void)
461{
462 struct sigaction sigact;
463 /* install TCC signal handlers to print debug info on fatal
464 runtime errors */
465 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
466 sigact.sa_sigaction = sig_error;
467 sigemptyset(&sigact.sa_mask);
468 sigaction(SIGFPE, &sigact, NULL);
469 sigaction(SIGILL, &sigact, NULL);
470 sigaction(SIGSEGV, &sigact, NULL);
471 sigaction(SIGBUS, &sigact, NULL);
472 sigaction(SIGABRT, &sigact, NULL);
473}
474
475/* ------------------------------------------------------------- */
3db21947 grischka2009-12-19 22:10:26 +0100476#ifdef __i386__
7fa712e0 grischka2009-12-19 22:22:43 +0100477
3db21947 grischka2009-12-19 22:10:26 +0100478/* fix for glibc 2.1 */
479#ifndef REG_EIP
480#define REG_EIP EIP
481#define REG_EBP EBP
482#endif
483
4b539aa6 grischka2013-02-04 17:24:03 +0100484/* return the PC at frame level 'level'. Return negative if not found */
82bcbd02 grischka2013-02-04 16:08:06 +0100485static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
3db21947 grischka2009-12-19 22:10:26 +0100486{
4b539aa6 grischka2013-02-04 17:24:03 +0100487 addr_t fp;
3db21947 grischka2009-12-19 22:10:26 +0100488 int i;
489
490 if (level == 0) {
8ca8b088
MJ
Milutin Jovanovic2012-02-09 12:53:17 -0500491#if defined(__APPLE__)
492 *paddr = uc->uc_mcontext->__ss.__eip;
9714d2e7 minux2014-04-12 01:42:46 -0400493#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
3db21947 grischka2009-12-19 22:10:26 +0100494 *paddr = uc->uc_mcontext.mc_eip;
495#elif defined(__dietlibc__)
496 *paddr = uc->uc_mcontext.eip;
9714d2e7 minux2014-04-12 01:42:46 -0400497#elif defined(__NetBSD__)
498 *paddr = uc->uc_mcontext.__gregs[_REG_EIP];
3db21947 grischka2009-12-19 22:10:26 +0100499#else
500 *paddr = uc->uc_mcontext.gregs[REG_EIP];
501#endif
502 return 0;
503 } else {
8ca8b088
MJ
Milutin Jovanovic2012-02-09 12:53:17 -0500504#if defined(__APPLE__)
505 fp = uc->uc_mcontext->__ss.__ebp;
9714d2e7 minux2014-04-12 01:42:46 -0400506#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
3db21947 grischka2009-12-19 22:10:26 +0100507 fp = uc->uc_mcontext.mc_ebp;
508#elif defined(__dietlibc__)
509 fp = uc->uc_mcontext.ebp;
9714d2e7 minux2014-04-12 01:42:46 -0400510#elif defined(__NetBSD__)
511 fp = uc->uc_mcontext.__gregs[_REG_EBP];
3db21947 grischka2009-12-19 22:10:26 +0100512#else
513 fp = uc->uc_mcontext.gregs[REG_EBP];
514#endif
515 for(i=1;i<level;i++) {
516 /* XXX: check address validity with program info */
517 if (fp <= 0x1000 || fp >= 0xc0000000)
518 return -1;
4b539aa6 grischka2013-02-04 17:24:03 +0100519 fp = ((addr_t *)fp)[0];
3db21947 grischka2009-12-19 22:10:26 +0100520 }
4b539aa6 grischka2013-02-04 17:24:03 +0100521 *paddr = ((addr_t *)fp)[1];
3db21947 grischka2009-12-19 22:10:26 +0100522 return 0;
523 }
524}
7fa712e0 grischka2009-12-19 22:22:43 +0100525
526/* ------------------------------------------------------------- */
3db21947 grischka2009-12-19 22:10:26 +0100527#elif defined(__x86_64__)
7fa712e0 grischka2009-12-19 22:22:43 +0100528
4b539aa6 grischka2013-02-04 17:24:03 +0100529/* return the PC at frame level 'level'. Return negative if not found */
530static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
3db21947 grischka2009-12-19 22:10:26 +0100531{
4b539aa6 grischka2013-02-04 17:24:03 +0100532 addr_t fp;
3db21947 grischka2009-12-19 22:10:26 +0100533 int i;
534
535 if (level == 0) {
536 /* XXX: only support linux */
8ca8b088
MJ
Milutin Jovanovic2012-02-09 12:53:17 -0500537#if defined(__APPLE__)
538 *paddr = uc->uc_mcontext->__ss.__rip;
8d3e0b30 minux2014-04-12 00:52:20 -0400539#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
3db21947 grischka2009-12-19 22:10:26 +0100540 *paddr = uc->uc_mcontext.mc_rip;
9714d2e7 minux2014-04-12 01:42:46 -0400541#elif defined(__NetBSD__)
542 *paddr = uc->uc_mcontext.__gregs[_REG_RIP];
3db21947 grischka2009-12-19 22:10:26 +0100543#else
544 *paddr = uc->uc_mcontext.gregs[REG_RIP];
545#endif
546 return 0;
547 } else {
8ca8b088
MJ
Milutin Jovanovic2012-02-09 12:53:17 -0500548#if defined(__APPLE__)
549 fp = uc->uc_mcontext->__ss.__rbp;
8d3e0b30 minux2014-04-12 00:52:20 -0400550#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
3db21947 grischka2009-12-19 22:10:26 +0100551 fp = uc->uc_mcontext.mc_rbp;
9714d2e7 minux2014-04-12 01:42:46 -0400552#elif defined(__NetBSD__)
553 fp = uc->uc_mcontext.__gregs[_REG_RBP];
3db21947 grischka2009-12-19 22:10:26 +0100554#else
555 fp = uc->uc_mcontext.gregs[REG_RBP];
556#endif
557 for(i=1;i<level;i++) {
558 /* XXX: check address validity with program info */
559 if (fp <= 0x1000)
560 return -1;
4b539aa6 grischka2013-02-04 17:24:03 +0100561 fp = ((addr_t *)fp)[0];
3db21947 grischka2009-12-19 22:10:26 +0100562 }
4b539aa6 grischka2013-02-04 17:24:03 +0100563 *paddr = ((addr_t *)fp)[1];
3db21947 grischka2009-12-19 22:10:26 +0100564 return 0;
565 }
566}
7fa712e0 grischka2009-12-19 22:22:43 +0100567
568/* ------------------------------------------------------------- */
20a1cba2
DG
Daniel Glöckner2010-05-14 14:22:32 +0200569#elif defined(__arm__)
570
571/* return the PC at frame level 'level'. Return negative if not found */
4b539aa6 grischka2013-02-04 17:24:03 +0100572static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
20a1cba2 Daniel Glöckner2010-05-14 14:22:32 +0200573{
4b539aa6 grischka2013-02-04 17:24:03 +0100574 addr_t fp, sp;
20a1cba2
DG
Daniel Glöckner2010-05-14 14:22:32 +0200575 int i;
576
577 if (level == 0) {
578 /* XXX: only supports linux */
579#if defined(__linux__)
580 *paddr = uc->uc_mcontext.arm_pc;
581#else
582 return -1;
583#endif
584 return 0;
585 } else {
586#if defined(__linux__)
587 fp = uc->uc_mcontext.arm_fp;
588 sp = uc->uc_mcontext.arm_sp;
589 if (sp < 0x1000)
590 sp = 0x1000;
591#else
592 return -1;
593#endif
594 /* XXX: specific to tinycc stack frames */
595 if (fp < sp + 12 || fp & 3)
596 return -1;
597 for(i = 1; i < level; i++) {
4b539aa6 grischka2013-02-04 17:24:03 +0100598 sp = ((addr_t *)fp)[-2];
20a1cba2
DG
Daniel Glöckner2010-05-14 14:22:32 +0200599 if (sp < fp || sp - fp > 16 || sp & 3)
600 return -1;
4b539aa6 grischka2013-02-04 17:24:03 +0100601 fp = ((addr_t *)fp)[-3];
20a1cba2
DG
Daniel Glöckner2010-05-14 14:22:32 +0200602 if (fp <= sp || fp - sp < 12 || fp & 3)
603 return -1;
604 }
605 /* XXX: check address validity with program info */
4b539aa6 grischka2013-02-04 17:24:03 +0100606 *paddr = ((addr_t *)fp)[-1];
20a1cba2
DG
Daniel Glöckner2010-05-14 14:22:32 +0200607 return 0;
608 }
609}
610
611/* ------------------------------------------------------------- */
b14ef0e2
EGE
Edmund Grimley Evans2015-02-13 18:58:31 +0000612#elif defined(__aarch64__)
613
614static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
615{
616 if (level < 0)
617 return -1;
618 else if (level == 0) {
619 *paddr = uc->uc_mcontext.pc;
620 return 0;
621 }
622 else {
623 addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
624 int i;
625 for (i = 1; i < level; i++)
626 fp = (addr_t *)fp[0];
627 *paddr = fp[1];
628 return 0;
629 }
630}
631
632/* ------------------------------------------------------------- */
3db21947 grischka2009-12-19 22:10:26 +0100633#else
7fa712e0 grischka2009-12-19 22:22:43 +0100634
3db21947 grischka2009-12-19 22:10:26 +0100635#warning add arch specific rt_get_caller_pc()
4b539aa6 grischka2013-02-04 17:24:03 +0100636static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
3db21947 grischka2009-12-19 22:10:26 +0100637{
638 return -1;
639}
3db21947 grischka2009-12-19 22:10:26 +0100640
7fa712e0 grischka2009-12-19 22:22:43 +0100641#endif /* !__i386__ */
3db21947 grischka2009-12-19 22:10:26 +0100642
7fa712e0 grischka2009-12-19 22:22:43 +0100643/* ------------------------------------------------------------- */
644#else /* WIN32 */
3db21947 grischka2009-12-19 22:10:26 +0100645
7fa712e0 grischka2009-12-19 22:22:43 +0100646static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
3db21947 grischka2009-12-19 22:10:26 +0100647{
7fa712e0 grischka2009-12-19 22:22:43 +0100648 EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
d483ab32 grischka2010-09-15 13:43:40 +0200649 CONTEXT *uc = ex_info->ContextRecord;
650 switch (er->ExceptionCode) {
651 case EXCEPTION_ACCESS_VIOLATION:
652 if (rt_bound_error_msg && *rt_bound_error_msg)
653 rt_error(uc, *rt_bound_error_msg);
654 else
655 rt_error(uc, "access violation");
656 break;
657 case EXCEPTION_STACK_OVERFLOW:
658 rt_error(uc, "stack overflow");
659 break;
660 case EXCEPTION_INT_DIVIDE_BY_ZERO:
661 rt_error(uc, "division by zero");
662 break;
663 default:
664 rt_error(uc, "exception caught");
665 break;
666 }
d5f4df09 grischka2013-02-05 14:27:38 +0100667 return EXCEPTION_EXECUTE_HANDLER;
3db21947 grischka2009-12-19 22:10:26 +0100668}
669
7fa712e0 grischka2009-12-19 22:22:43 +0100670/* Generate a stack backtrace when a CPU exception occurs. */
671static void set_exception_handler(void)
3db21947 grischka2009-12-19 22:10:26 +0100672{
7fa712e0 grischka2009-12-19 22:22:43 +0100673 SetUnhandledExceptionFilter(cpu_exception_handler);
3db21947 grischka2009-12-19 22:10:26 +0100674}
675
5775911d Andrew Mulbrook2012-03-03 10:12:06 -0600676#ifdef _WIN64
df4c0892 grischka2011-07-14 19:09:49 +0200677static void win64_add_function_table(TCCState *s1)
678{
679 RtlAddFunctionTable(
82bcbd02 grischka2013-02-04 16:08:06 +0100680 (RUNTIME_FUNCTION*)s1->uw_pdata->sh_addr,
df4c0892 grischka2011-07-14 19:09:49 +0200681 s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
82bcbd02 grischka2013-02-04 16:08:06 +0100682 text_section->sh_addr
df4c0892 grischka2011-07-14 19:09:49 +0200683 );
684}
685#endif
686
7fa712e0 grischka2009-12-19 22:22:43 +0100687/* return the PC at frame level 'level'. Return non zero if not found */
82bcbd02 grischka2013-02-04 16:08:06 +0100688static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
3db21947 grischka2009-12-19 22:10:26 +0100689{
82bcbd02 grischka2013-02-04 16:08:06 +0100690 addr_t fp, pc;
3db21947 grischka2009-12-19 22:10:26 +0100691 int i;
08083ddb grischka2010-09-15 13:43:25 +0200692#ifdef _WIN64
693 pc = uc->Rip;
694 fp = uc->Rbp;
695#else
696 pc = uc->Eip;
697 fp = uc->Ebp;
698#endif
699 if (level > 0) {
700 for(i=1;i<level;i++) {
7fa712e0 grischka2009-12-19 22:22:43 +0100701 /* XXX: check address validity with program info */
702 if (fp <= 0x1000 || fp >= 0xc0000000)
703 return -1;
82bcbd02 grischka2013-02-04 16:08:06 +0100704 fp = ((addr_t*)fp)[0];
7fa712e0 grischka2009-12-19 22:22:43 +0100705 }
82bcbd02 grischka2013-02-04 16:08:06 +0100706 pc = ((addr_t*)fp)[1];
3db21947 grischka2009-12-19 22:10:26 +0100707 }
08083ddb grischka2010-09-15 13:43:25 +0200708 *paddr = pc;
709 return 0;
7fa712e0 grischka2009-12-19 22:22:43 +0100710}
3db21947 grischka2009-12-19 22:10:26 +0100711
7fa712e0 grischka2009-12-19 22:22:43 +0100712#endif /* _WIN32 */
713#endif /* CONFIG_TCC_BACKTRACE */
714/* ------------------------------------------------------------- */
7fa712e0 grischka2009-12-19 22:22:43 +0100715#ifdef CONFIG_TCC_STATIC
3db21947 grischka2009-12-19 22:10:26 +0100716
7fa712e0 grischka2009-12-19 22:22:43 +0100717/* dummy function for profiling */
74a24d77 grischka2011-08-11 16:55:30 +0200718ST_FUNC void *dlopen(const char *filename, int flag)
7fa712e0 grischka2009-12-19 22:22:43 +0100719{
720 return NULL;
3db21947 grischka2009-12-19 22:10:26 +0100721}
722
74a24d77 grischka2011-08-11 16:55:30 +0200723ST_FUNC void dlclose(void *p)
8bbde91f grischka2009-12-19 22:11:12 +0100724{
8bbde91f grischka2009-12-19 22:11:12 +0100725}
05108a3b grischka2013-02-12 19:13:28 +0100726
727ST_FUNC const char *dlerror(void)
3db21947 grischka2009-12-19 22:10:26 +0100728{
7fa712e0 grischka2009-12-19 22:22:43 +0100729 return "error";
730}
05108a3b grischka2013-02-12 19:13:28 +0100731
7fa712e0 grischka2009-12-19 22:22:43 +0100732typedef struct TCCSyms {
733 char *str;
734 void *ptr;
735} TCCSyms;
3db21947 grischka2009-12-19 22:10:26 +0100736
3db21947 grischka2009-12-19 22:10:26 +0100737
7fa712e0 grischka2009-12-19 22:22:43 +0100738/* add the symbol you want here if no dynamic linking is done */
739static TCCSyms tcc_syms[] = {
740#if !defined(CONFIG_TCCBOOT)
05108a3b grischka2013-02-12 19:13:28 +0100741#define TCCSYM(a) { #a, &a, },
7fa712e0 grischka2009-12-19 22:22:43 +0100742 TCCSYM(printf)
743 TCCSYM(fprintf)
744 TCCSYM(fopen)
745 TCCSYM(fclose)
05108a3b grischka2013-02-12 19:13:28 +0100746#undef TCCSYM
3db21947 grischka2009-12-19 22:10:26 +0100747#endif
7fa712e0 grischka2009-12-19 22:22:43 +0100748 { NULL, NULL },
749};
750
74a24d77 grischka2011-08-11 16:55:30 +0200751ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol)
7fa712e0 grischka2009-12-19 22:22:43 +0100752{
753 TCCSyms *p;
754 p = tcc_syms;
755 while (p->str != NULL) {
756 if (!strcmp(p->str, symbol))
757 return p->ptr;
758 p++;
3db21947 grischka2009-12-19 22:10:26 +0100759 }
7fa712e0 grischka2009-12-19 22:22:43 +0100760 return NULL;
761}
3db21947 grischka2009-12-19 22:10:26 +0100762
88a3ccab grischka2009-12-20 01:53:49 +0100763#elif !defined(_WIN32)
7fa712e0 grischka2009-12-19 22:22:43 +0100764
74a24d77 grischka2011-08-11 16:55:30 +0200765ST_FUNC void *resolve_sym(TCCState *s1, const char *sym)
7fa712e0 grischka2009-12-19 22:22:43 +0100766{
767 return dlsym(RTLD_DEFAULT, sym);
3db21947 grischka2009-12-19 22:10:26 +0100768}
769
7fa712e0 grischka2009-12-19 22:22:43 +0100770#endif /* CONFIG_TCC_STATIC */
82bcbd02 grischka2013-02-04 16:08:06 +0100771#endif /* TCC_IS_NATIVE */
7fa712e0 grischka2009-12-19 22:22:43 +0100772/* ------------------------------------------------------------- */