Added missing file.
[tinycc/k1w1.git] / tccosposix.c
blobaf5213dd080046415c1733dc4d2d773111db393f
1 /*
2 * Posix OS specific functions for TCC
3 *
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
20 #include "tcc.h"
21 #include <sys/ucontext.h>
23 #ifdef __i386__
24 /* fix for glibc 2.1 */
25 #ifndef REG_EIP
26 #define REG_EIP EIP
27 #define REG_EBP EBP
28 #endif
30 /* return the PC at frame level 'level'. Return non zero if not found */
31 static int rt_get_caller_pc(unsigned long *paddr,
32 ucontext_t *uc, int level)
34 unsigned long fp;
35 int i;
37 if (level == 0) {
38 #if defined(__FreeBSD__)
39 *paddr = uc->uc_mcontext.mc_eip;
40 #elif defined(__dietlibc__)
41 *paddr = uc->uc_mcontext.eip;
42 #else
43 *paddr = uc->uc_mcontext.gregs[REG_EIP];
44 #endif
45 return 0;
46 } else {
47 #if defined(__FreeBSD__)
48 fp = uc->uc_mcontext.mc_ebp;
49 #elif defined(__dietlibc__)
50 fp = uc->uc_mcontext.ebp;
51 #else
52 fp = uc->uc_mcontext.gregs[REG_EBP];
53 #endif
54 for(i=1;i<level;i++) {
55 /* XXX: check address validity with program info */
56 if (fp <= 0x1000 || fp >= 0xc0000000)
57 return -1;
58 fp = ((unsigned long *)fp)[0];
60 *paddr = ((unsigned long *)fp)[1];
61 return 0;
64 #elif defined(__x86_64__)
65 /* return the PC at frame level 'level'. Return non zero if not found */
66 static int rt_get_caller_pc(unsigned long *paddr,
67 ucontext_t *uc, int level)
69 unsigned long fp;
70 int i;
72 if (level == 0) {
73 /* XXX: only support linux */
74 #if defined(__FreeBSD__)
75 *paddr = uc->uc_mcontext.mc_rip;
76 #else
77 *paddr = uc->uc_mcontext.gregs[REG_RIP];
78 #endif
79 return 0;
80 } else {
81 #if defined(__FreeBSD__)
82 fp = uc->uc_mcontext.mc_rbp;
83 #else
84 fp = uc->uc_mcontext.gregs[REG_RBP];
85 #endif
86 for(i=1;i<level;i++) {
87 /* XXX: check address validity with program info */
88 if (fp <= 0x1000)
89 return -1;
90 fp = ((unsigned long *)fp)[0];
92 *paddr = ((unsigned long *)fp)[1];
93 return 0;
96 #else
97 #warning add arch specific rt_get_caller_pc()
98 static int rt_get_caller_pc(unsigned long *paddr,
99 ucontext_t *uc, int level)
101 return -1;
103 #endif
107 /* emit a run time error at position 'pc' */
108 void rt_error(ucontext_t *uc, const char *fmt, ...)
110 va_list ap;
111 unsigned long pc;
112 int i;
114 va_start(ap, fmt);
115 fprintf(stderr, "Runtime error: ");
116 vfprintf(stderr, fmt, ap);
117 fprintf(stderr, "\n");
118 for(i=0;i<num_callers;i++) {
119 if (rt_get_caller_pc(&pc, uc, i) < 0)
120 break;
121 if (i == 0)
122 fprintf(stderr, "at ");
123 else
124 fprintf(stderr, "by ");
125 pc = rt_printline(pc);
126 if (pc == rt_prog_main && pc)
127 break;
129 exit(255);
130 va_end(ap);
133 /* signal handler for fatal errors */
134 static void sig_error(int signum, siginfo_t *siginf, void *puc)
136 ucontext_t *uc = puc;
138 switch(signum) {
139 case SIGFPE:
140 switch(siginf->si_code) {
141 case FPE_INTDIV:
142 case FPE_FLTDIV:
143 rt_error(uc, "division by zero");
144 break;
145 default:
146 rt_error(uc, "floating point exception");
147 break;
149 break;
150 case SIGBUS:
151 case SIGSEGV:
152 if (rt_bound_error_msg && *rt_bound_error_msg)
153 rt_error(uc, *rt_bound_error_msg);
154 else
155 rt_error(uc, "dereferencing invalid pointer");
156 break;
157 case SIGILL:
158 rt_error(uc, "illegal instruction");
159 break;
160 case SIGABRT:
161 rt_error(uc, "abort() called");
162 break;
163 default:
164 rt_error(uc, "caught signal %d", signum);
165 break;
167 exit(255);
170 /* Generate a stack backtrace when a CPU exception occurs. */
171 void handle_cpu_exception(void)
173 struct sigaction sigact;
174 /* install TCC signal handlers to print debug info on fatal
175 runtime errors */
176 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
177 sigact.sa_sigaction = sig_error;
178 sigemptyset(&sigact.sa_mask);
179 sigaction(SIGFPE, &sigact, NULL);
180 sigaction(SIGILL, &sigact, NULL);
181 sigaction(SIGSEGV, &sigact, NULL);
182 sigaction(SIGBUS, &sigact, NULL);
183 sigaction(SIGABRT, &sigact, NULL);