Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6429 siemargl 1
/*
2
 *  TCC - Tiny C Compiler - Support for -run switch
3
 *
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
 
21
#include "tcc.h"
22
 
23
/* only native compiler supports -run */
24
#ifdef TCC_IS_NATIVE
25
 
26
#ifdef CONFIG_TCC_BACKTRACE
27
ST_DATA int rt_num_callers = 6;
28
ST_DATA const char **rt_bound_error_msg;
29
ST_DATA void *rt_prog_main;
30
#endif
31
 
32
#ifdef _WIN32
33
#define ucontext_t CONTEXT
34
#endif
35
 
36
static void set_pages_executable(void *ptr, unsigned long length);
37
static void set_exception_handler(void);
38
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
39
static void rt_error(ucontext_t *uc, const char *fmt, ...);
40
static int tcc_relocate_ex(TCCState *s1, void *ptr);
41
 
42
#ifdef _WIN64
43
static void win64_add_function_table(TCCState *s1);
44
#endif
45
 
46
/* ------------------------------------------------------------- */
47
/* Do all relocations (needed before using tcc_get_symbol())
48
   Returns -1 on error. */
49
 
50
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
51
{
52
    int ret;
53
 
54
    if (TCC_RELOCATE_AUTO != ptr)
55
        return tcc_relocate_ex(s1, ptr);
56
 
57
    ret = tcc_relocate_ex(s1, NULL);
58
    if (ret < 0)
59
        return ret;
60
 
61
#ifdef HAVE_SELINUX
62
    {   /* 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
 
68
        s1->mem_size = ret;
69
        unlink (tmpfname);
70
        ftruncate (fd, s1->mem_size);
71
 
72
        s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
73
            MAP_SHARED, fd, 0);
74
        if (s1->write_mem == MAP_FAILED)
75
            tcc_error("/tmp not writeable");
76
 
77
        s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
78
            MAP_SHARED, fd, 0);
79
        if (s1->runtime_mem == MAP_FAILED)
80
            tcc_error("/tmp not executable");
81
 
82
        ret = tcc_relocate_ex(s1, s1->write_mem);
83
    }
84
#else
85
    s1->runtime_mem = tcc_malloc(ret);
86
    ret = tcc_relocate_ex(s1, s1->runtime_mem);
87
#endif
88
    return ret;
89
}
90
 
91
/* launch the compiled program with the given arguments */
92
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
93
{
94
    int (*prog_main)(int, char **);
95
    int ret;
96
 
97
    if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
98
        return -1;
99
 
100
    prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
101
 
102
#ifdef CONFIG_TCC_BACKTRACE
103
    if (s1->do_debug) {
104
        set_exception_handler();
105
        rt_prog_main = prog_main;
106
    }
107
#endif
108
 
109
#ifdef CONFIG_TCC_BCHECK
110
    if (s1->do_bounds_check) {
111
        void (*bound_init)(void);
112
        void (*bound_exit)(void);
113
        void (*bound_new_region)(void *p, addr_t size);
114
        int  (*bound_delete_region)(void *p);
115
        int i;
116
 
117
        /* set error function */
118
        rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
119
        /* 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");
122
        bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
123
        bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
124
        bound_init();
125
        /* mark argv area as valid */
126
        bound_new_region(argv, argc*sizeof(argv[0]));
127
        for (i=0; i
128
            bound_new_region(argv[i], strlen(argv[i]));
129
 
130
	errno = 0; /* clean errno value */
131
        ret = (*prog_main)(argc, argv);
132
 
133
        /* unmark argv area */
134
        for (i=0; i
135
            bound_delete_region(argv[i]);
136
        bound_delete_region(argv);
137
 
138
        bound_exit();
139
    } else
140
#endif
141
    {
142
	errno = 0; /* clean errno value */
143
        ret = (*prog_main)(argc, argv);
144
    }
145
    return ret;
146
}
147
 
148
/* relocate code. Return -1 on error, required size if ptr is NULL,
149
   otherwise copy code into buffer passed by the caller */
150
static int tcc_relocate_ex(TCCState *s1, void *ptr)
151
{
152
    Section *s;
153
    unsigned long offset, length;
154
    addr_t mem;
155
    int i;
156
 
157
    if (NULL == ptr) {
158
        s1->nb_errors = 0;
159
#ifdef TCC_TARGET_PE
160
        pe_output_file(s1, NULL);
161
#else
162
        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
    }
170
 
171
    offset = 0, mem = (addr_t)ptr;
172
    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
 
187
    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
    }
196
    relocate_plt(s1);
197
 
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;
203
        // printf("%-12s %08lx %04x\n", s->name, s->sh_addr, length);
204
        ptr = (void*)s->sh_addr;
205
        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
 
214
#ifdef _WIN64
215
    win64_add_function_table(s1);
216
#endif
217
    return 0;
218
}
219
 
220
/* ------------------------------------------------------------- */
221
/* allow to run code in memory */
222
 
223
static 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
229
    extern void __clear_cache(void *beginning, void *end);
230
#ifndef PAGESIZE
231
# define PAGESIZE 4096
232
#endif
233
    addr_t start, end;
234
    start = (addr_t)ptr & ~(PAGESIZE - 1);
235
    end = (addr_t)ptr + length;
236
    end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
237
    mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
238
  #ifndef __PCC__
239
    __clear_cache(ptr, (char *)ptr + length);
240
  #else
241
    /* pcc 1.2.0.DEVEL 20141206 don't have such proc */
242
  #endif
243
#endif
244
}
245
 
246
/* ------------------------------------------------------------- */
247
#ifdef CONFIG_TCC_BACKTRACE
248
 
249
ST_FUNC void tcc_set_num_callers(int n)
250
{
251
    rt_num_callers = n;
252
}
253
 
254
/* print the position in the source file of PC value 'pc' by reading
255
   the stabs debug information */
256
static addr_t rt_printline(addr_t wanted_pc, const char *msg)
257
{
258
    char func_name[128], last_func_name[128];
259
    addr_t func_addr, last_pc, pc;
260
    const char *incl_files[INCLUDE_STACK_SIZE];
261
    int incl_index, len, last_line_num, i;
262
    const char *str, *p;
263
 
264
    Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym;
265
    int stab_len = 0;
266
    char *stab_str = NULL;
267
 
268
    if (stab_section) {
269
        stab_len = stab_section->data_offset;
270
        stab_sym = (Stab_Sym *)stab_section->data;
271
        stab_str = (char *) stabstr_section->data;
272
    }
273
 
274
    func_name[0] = '\0';
275
    func_addr = 0;
276
    incl_index = 0;
277
    last_func_name[0] = '\0';
278
    last_pc = (addr_t)-1;
279
    last_line_num = 1;
280
 
281
    if (!stab_sym)
282
        goto no_stabs;
283
 
284
    stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len);
285
    for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
286
        switch(sym->n_type) {
287
            /* function start or end */
288
        case N_FUN:
289
            if (sym->n_strx == 0) {
290
                /* we test if between last line and end of function */
291
                pc = sym->n_value + func_addr;
292
                if (wanted_pc >= last_pc && wanted_pc < pc)
293
                    goto found;
294
                func_name[0] = '\0';
295
                func_addr = 0;
296
            } else {
297
                str = stab_str + sym->n_strx;
298
                p = strchr(str, ':');
299
                if (!p) {
300
                    pstrcpy(func_name, sizeof(func_name), str);
301
                } else {
302
                    len = p - str;
303
                    if (len > sizeof(func_name) - 1)
304
                        len = sizeof(func_name) - 1;
305
                    memcpy(func_name, str, len);
306
                    func_name[len] = '\0';
307
                }
308
                func_addr = sym->n_value;
309
            }
310
            break;
311
            /* line number info */
312
        case N_SLINE:
313
            pc = sym->n_value + func_addr;
314
            if (wanted_pc >= last_pc && wanted_pc < pc)
315
                goto found;
316
            last_pc = pc;
317
            last_line_num = sym->n_desc;
318
            /* XXX: slow! */
319
            strcpy(last_func_name, func_name);
320
            break;
321
            /* include files */
322
        case N_BINCL:
323
            str = stab_str + sym->n_strx;
324
        add_incl:
325
            if (incl_index < INCLUDE_STACK_SIZE) {
326
                incl_files[incl_index++] = str;
327
            }
328
            break;
329
        case N_EINCL:
330
            if (incl_index > 1)
331
                incl_index--;
332
            break;
333
        case N_SO:
334
            if (sym->n_strx == 0) {
335
                incl_index = 0; /* end of translation unit */
336
            } else {
337
                str = stab_str + sym->n_strx;
338
                /* do not add path */
339
                len = strlen(str);
340
                if (len > 0 && str[len - 1] != '/')
341
                    goto add_incl;
342
            }
343
            break;
344
        }
345
    }
346
 
347
no_stabs:
348
    /* second pass: we try symtab symbols (no line number info) */
349
    incl_index = 0;
350
    if (symtab_section)
351
    {
352
        ElfW(Sym) *sym, *sym_end;
353
        int type;
354
 
355
        sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
356
        for(sym = (ElfW(Sym) *)symtab_section->data + 1;
357
            sym < sym_end;
358
            sym++) {
359
            type = ELFW(ST_TYPE)(sym->st_info);
360
            if (type == STT_FUNC || type == STT_GNU_IFUNC) {
361
                if (wanted_pc >= sym->st_value &&
362
                    wanted_pc < sym->st_value + sym->st_size) {
363
                    pstrcpy(last_func_name, sizeof(last_func_name),
364
                            (char *) strtab_section->data + sym->st_name);
365
                    func_addr = sym->st_value;
366
                    goto found;
367
                }
368
            }
369
        }
370
    }
371
    /* did not find any info: */
372
    fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc);
373
    fflush(stderr);
374
    return 0;
375
 found:
376
    i = incl_index;
377
    if (i > 0)
378
        fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num);
379
    fprintf(stderr, "%s %p", msg, (void*)wanted_pc);
380
    if (last_func_name[0] != '\0')
381
        fprintf(stderr, " %s()", last_func_name);
382
    if (--i >= 0) {
383
        fprintf(stderr, " (included from ");
384
        for (;;) {
385
            fprintf(stderr, "%s", incl_files[i]);
386
            if (--i < 0)
387
                break;
388
            fprintf(stderr, ", ");
389
        }
390
        fprintf(stderr, ")");
391
    }
392
    fprintf(stderr, "\n");
393
    fflush(stderr);
394
    return func_addr;
395
}
396
 
397
/* emit a run time error at position 'pc' */
398
static void rt_error(ucontext_t *uc, const char *fmt, ...)
399
{
400
    va_list ap;
401
    addr_t pc;
402
    int i;
403
 
404
    fprintf(stderr, "Runtime error: ");
405
    va_start(ap, fmt);
406
    vfprintf(stderr, fmt, ap);
407
    va_end(ap);
408
    fprintf(stderr, "\n");
409
 
410
    for(i=0;i
411
        if (rt_get_caller_pc(&pc, uc, i) < 0)
412
            break;
413
        pc = rt_printline(pc, i ? "by" : "at");
414
        if (pc == (addr_t)rt_prog_main && pc)
415
            break;
416
    }
417
}
418
 
419
/* ------------------------------------------------------------- */
420
#ifndef _WIN32
421
 
422
/* signal handler for fatal errors */
423
static void sig_error(int signum, siginfo_t *siginf, void *puc)
424
{
425
    ucontext_t *uc = puc;
426
 
427
    switch(signum) {
428
    case SIGFPE:
429
        switch(siginf->si_code) {
430
        case FPE_INTDIV:
431
        case FPE_FLTDIV:
432
            rt_error(uc, "division by zero");
433
            break;
434
        default:
435
            rt_error(uc, "floating point exception");
436
            break;
437
        }
438
        break;
439
    case SIGBUS:
440
    case SIGSEGV:
441
        if (rt_bound_error_msg && *rt_bound_error_msg)
442
            rt_error(uc, *rt_bound_error_msg);
443
        else
444
            rt_error(uc, "dereferencing invalid pointer");
445
        break;
446
    case SIGILL:
447
        rt_error(uc, "illegal instruction");
448
        break;
449
    case SIGABRT:
450
        rt_error(uc, "abort() called");
451
        break;
452
    default:
453
        rt_error(uc, "caught signal %d", signum);
454
        break;
455
    }
456
    exit(255);
457
}
458
 
459
#ifndef SA_SIGINFO
460
# define SA_SIGINFO 0x00000004u
461
#endif
462
 
463
/* Generate a stack backtrace when a CPU exception occurs. */
464
static void set_exception_handler(void)
465
{
466
    struct sigaction sigact;
467
    /* install TCC signal handlers to print debug info on fatal
468
       runtime errors */
469
    sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
470
    sigact.sa_sigaction = sig_error;
471
    sigemptyset(&sigact.sa_mask);
472
    sigaction(SIGFPE, &sigact, NULL);
473
    sigaction(SIGILL, &sigact, NULL);
474
    sigaction(SIGSEGV, &sigact, NULL);
475
    sigaction(SIGBUS, &sigact, NULL);
476
    sigaction(SIGABRT, &sigact, NULL);
477
}
478
 
479
/* ------------------------------------------------------------- */
480
#ifdef __i386__
481
 
482
/* fix for glibc 2.1 */
483
#ifndef REG_EIP
484
#define REG_EIP EIP
485
#define REG_EBP EBP
486
#endif
487
 
488
/* return the PC at frame level 'level'. Return negative if not found */
489
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
490
{
491
    addr_t fp;
492
    int i;
493
 
494
    if (level == 0) {
495
#if defined(__APPLE__)
496
        *paddr = uc->uc_mcontext->__ss.__eip;
497
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
498
        *paddr = uc->uc_mcontext.mc_eip;
499
#elif defined(__dietlibc__)
500
        *paddr = uc->uc_mcontext.eip;
501
#elif defined(__NetBSD__)
502
        *paddr = uc->uc_mcontext.__gregs[_REG_EIP];
503
#else
504
        *paddr = uc->uc_mcontext.gregs[REG_EIP];
505
#endif
506
        return 0;
507
    } else {
508
#if defined(__APPLE__)
509
        fp = uc->uc_mcontext->__ss.__ebp;
510
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
511
        fp = uc->uc_mcontext.mc_ebp;
512
#elif defined(__dietlibc__)
513
        fp = uc->uc_mcontext.ebp;
514
#elif defined(__NetBSD__)
515
        fp = uc->uc_mcontext.__gregs[_REG_EBP];
516
#else
517
        fp = uc->uc_mcontext.gregs[REG_EBP];
518
#endif
519
        for(i=1;i
520
            /* XXX: check address validity with program info */
521
            if (fp <= 0x1000 || fp >= 0xc0000000)
522
                return -1;
523
            fp = ((addr_t *)fp)[0];
524
        }
525
        *paddr = ((addr_t *)fp)[1];
526
        return 0;
527
    }
528
}
529
 
530
/* ------------------------------------------------------------- */
531
#elif defined(__x86_64__)
532
 
533
/* return the PC at frame level 'level'. Return negative if not found */
534
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
535
{
536
    addr_t fp;
537
    int i;
538
 
539
    if (level == 0) {
540
        /* XXX: only support linux */
541
#if defined(__APPLE__)
542
        *paddr = uc->uc_mcontext->__ss.__rip;
543
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
544
        *paddr = uc->uc_mcontext.mc_rip;
545
#elif defined(__NetBSD__)
546
        *paddr = uc->uc_mcontext.__gregs[_REG_RIP];
547
#else
548
        *paddr = uc->uc_mcontext.gregs[REG_RIP];
549
#endif
550
        return 0;
551
    } else {
552
#if defined(__APPLE__)
553
        fp = uc->uc_mcontext->__ss.__rbp;
554
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
555
        fp = uc->uc_mcontext.mc_rbp;
556
#elif defined(__NetBSD__)
557
        fp = uc->uc_mcontext.__gregs[_REG_RBP];
558
#else
559
        fp = uc->uc_mcontext.gregs[REG_RBP];
560
#endif
561
        for(i=1;i
562
            /* XXX: check address validity with program info */
563
            if (fp <= 0x1000)
564
                return -1;
565
            fp = ((addr_t *)fp)[0];
566
        }
567
        *paddr = ((addr_t *)fp)[1];
568
        return 0;
569
    }
570
}
571
 
572
/* ------------------------------------------------------------- */
573
#elif defined(__arm__)
574
 
575
/* return the PC at frame level 'level'. Return negative if not found */
576
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
577
{
578
    addr_t fp, sp;
579
    int i;
580
 
581
    if (level == 0) {
582
        /* XXX: only supports linux */
583
#if defined(__linux__)
584
        *paddr = uc->uc_mcontext.arm_pc;
585
#else
586
        return -1;
587
#endif
588
        return 0;
589
    } else {
590
#if defined(__linux__)
591
        fp = uc->uc_mcontext.arm_fp;
592
        sp = uc->uc_mcontext.arm_sp;
593
        if (sp < 0x1000)
594
            sp = 0x1000;
595
#else
596
        return -1;
597
#endif
598
        /* XXX: specific to tinycc stack frames */
599
        if (fp < sp + 12 || fp & 3)
600
            return -1;
601
        for(i = 1; i < level; i++) {
602
            sp = ((addr_t *)fp)[-2];
603
            if (sp < fp || sp - fp > 16 || sp & 3)
604
                return -1;
605
            fp = ((addr_t *)fp)[-3];
606
            if (fp <= sp || fp - sp < 12 || fp & 3)
607
                return -1;
608
        }
609
        /* XXX: check address validity with program info */
610
        *paddr = ((addr_t *)fp)[-1];
611
        return 0;
612
    }
613
}
614
 
615
/* ------------------------------------------------------------- */
616
#elif defined(__aarch64__)
617
 
618
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
619
{
620
    if (level < 0)
621
        return -1;
622
    else if (level == 0) {
623
        *paddr = uc->uc_mcontext.pc;
624
        return 0;
625
    }
626
    else {
627
        addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
628
        int i;
629
        for (i = 1; i < level; i++)
630
            fp = (addr_t *)fp[0];
631
        *paddr = fp[1];
632
        return 0;
633
    }
634
}
635
 
636
/* ------------------------------------------------------------- */
637
#else
638
 
639
#warning add arch specific rt_get_caller_pc()
640
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
641
{
642
    return -1;
643
}
644
 
645
#endif /* !__i386__ */
646
 
647
/* ------------------------------------------------------------- */
648
#else /* WIN32 */
649
 
650
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
651
{
652
    EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
653
    CONTEXT *uc = ex_info->ContextRecord;
654
    switch (er->ExceptionCode) {
655
    case EXCEPTION_ACCESS_VIOLATION:
656
        if (rt_bound_error_msg && *rt_bound_error_msg)
657
            rt_error(uc, *rt_bound_error_msg);
658
        else
659
	    rt_error(uc, "access violation");
660
        break;
661
    case EXCEPTION_STACK_OVERFLOW:
662
        rt_error(uc, "stack overflow");
663
        break;
664
    case EXCEPTION_INT_DIVIDE_BY_ZERO:
665
        rt_error(uc, "division by zero");
666
        break;
667
    default:
668
        rt_error(uc, "exception caught");
669
        break;
670
    }
671
    return EXCEPTION_EXECUTE_HANDLER;
672
}
673
 
674
/* Generate a stack backtrace when a CPU exception occurs. */
675
static void set_exception_handler(void)
676
{
677
    SetUnhandledExceptionFilter(cpu_exception_handler);
678
}
679
 
680
#ifdef _WIN64
681
static void win64_add_function_table(TCCState *s1)
682
{
683
    RtlAddFunctionTable(
684
        (RUNTIME_FUNCTION*)s1->uw_pdata->sh_addr,
685
        s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
686
        text_section->sh_addr
687
        );
688
}
689
#endif
690
 
691
/* return the PC at frame level 'level'. Return non zero if not found */
692
static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
693
{
694
    addr_t fp, pc;
695
    int i;
696
#ifdef _WIN64
697
    pc = uc->Rip;
698
    fp = uc->Rbp;
699
#else
700
    pc = uc->Eip;
701
    fp = uc->Ebp;
702
#endif
703
    if (level > 0) {
704
        for(i=1;i
705
	    /* XXX: check address validity with program info */
706
	    if (fp <= 0x1000 || fp >= 0xc0000000)
707
		return -1;
708
	    fp = ((addr_t*)fp)[0];
709
	}
710
        pc = ((addr_t*)fp)[1];
711
    }
712
    *paddr = pc;
713
    return 0;
714
}
715
 
716
#endif /* _WIN32 */
717
#endif /* CONFIG_TCC_BACKTRACE */
718
/* ------------------------------------------------------------- */
719
#ifdef CONFIG_TCC_STATIC
720
 
721
/* dummy function for profiling */
722
ST_FUNC void *dlopen(const char *filename, int flag)
723
{
724
    return NULL;
725
}
726
 
727
ST_FUNC void dlclose(void *p)
728
{
729
}
730
 
731
ST_FUNC const char *dlerror(void)
732
{
733
    return "error";
734
}
735
 
736
typedef struct TCCSyms {
737
    char *str;
738
    void *ptr;
739
} TCCSyms;
740
 
741
 
742
/* add the symbol you want here if no dynamic linking is done */
743
static TCCSyms tcc_syms[] = {
744
#if !defined(CONFIG_TCCBOOT)
745
#define TCCSYM(a) { #a, &a, },
746
    TCCSYM(printf)
747
    TCCSYM(fprintf)
748
    TCCSYM(fopen)
749
    TCCSYM(fclose)
750
#undef TCCSYM
751
#endif
752
    { NULL, NULL },
753
};
754
 
755
ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol)
756
{
757
    TCCSyms *p;
758
    p = tcc_syms;
759
    while (p->str != NULL) {
760
        if (!strcmp(p->str, symbol))
761
            return p->ptr;
762
        p++;
763
    }
764
    return NULL;
765
}
766
 
767
#elif !defined(_WIN32)
768
 
769
ST_FUNC void *resolve_sym(TCCState *s1, const char *sym)
770
{
771
    return dlsym(RTLD_DEFAULT, sym);
772
}
773
 
774
#endif /* CONFIG_TCC_STATIC */
775
#endif /* TCC_IS_NATIVE */
776
/* ------------------------------------------------------------- */