Make host-constant-to-core use a hashtable for cycle detection.
[sbcl.git] / src / runtime / interr.c
blob85af040448808e0d904979cfe1add773a03f8c20
1 /*
2 * stuff to handle internal errors
3 */
5 /*
6 * This software is part of the SBCL system. See the README file for
7 * more information.
9 * This software is derived from the CMU CL system, which was
10 * written at Carnegie Mellon University and released into the
11 * public domain. The software is in the public domain and is
12 * provided with absolutely no warranty. See the COPYING and CREDITS
13 * files for more information.
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <stdlib.h>
20 #include "sbcl.h"
21 #include "arch.h"
22 #include "signal.h"
24 #include "runtime.h"
25 #include "interr.h"
26 #include "print.h"
27 #include "lispregs.h"
28 #include "genesis/static-symbols.h"
29 #include "genesis/vector.h"
30 #include "genesis/code.h"
31 #include "thread.h"
32 #include "monitor.h"
33 #include "breakpoint.h"
35 /* the way that we shut down the system on a fatal error */
37 static void
38 default_lossage_handler(void)
40 exit(1);
42 static void (*lossage_handler)(void) = default_lossage_handler;
44 #if QSHOW
45 static void
46 configurable_lossage_handler()
48 void lisp_backtrace(int frames);
50 if (dyndebug_config.dyndebug_backtrace_when_lost) {
51 fprintf(stderr, "lose: backtrace follows as requested\n");
52 lisp_backtrace(100);
55 if (dyndebug_config.dyndebug_sleep_when_lost) {
56 fprintf(stderr,
57 "The system is too badly corrupted or confused to continue at the Lisp.\n"
58 "level. The monitor was enabled, but you requested `sleep_when_lost'\n"
59 "behaviour though dyndebug. To help with your debugging effort, this\n"
60 "thread will not enter the monitor, and instead proceed immediately to an\n"
61 "infinite sleep call, maximizing your chances that the thread's current\n"
62 "state can be preserved until you attach an external debugger. Good luck!\n");
63 for (;;)
64 # ifdef LISP_FEATURE_WIN32
65 Sleep(10000);
66 # else
67 sleep(10);
68 # endif
71 monitor_or_something();
73 #endif
75 void enable_lossage_handler(void)
77 #if QSHOW
78 lossage_handler = configurable_lossage_handler;
79 #else
80 lossage_handler = monitor_or_something;
81 #endif
83 void disable_lossage_handler(void)
85 lossage_handler = default_lossage_handler;
88 static
89 void print_message(char *fmt, va_list ap)
91 fprintf(stderr, " in SBCL pid %d",getpid());
92 #if defined(LISP_FEATURE_SB_THREAD)
93 fprintf(stderr, "(tid %lu)", (uword_t) thread_self());
94 #endif
95 if (fmt) {
96 fprintf(stderr, ":\n");
97 vfprintf(stderr, fmt, ap);
99 fprintf(stderr, "\n");
102 static inline void
103 call_lossage_handler() never_returns;
105 static inline void
106 call_lossage_handler()
108 lossage_handler();
109 fprintf(stderr, "Argh! lossage_handler() returned, total confusion..\n");
110 exit(1);
113 void
114 lose(char *fmt, ...)
116 va_list ap;
117 /* Block signals to prevent other threads, timers and such from
118 * interfering. If only all threads could be stopped somehow. */
119 block_blockable_signals(0, 0);
120 fprintf(stderr, "fatal error encountered");
121 va_start(ap, fmt);
122 print_message(fmt, ap);
123 va_end(ap);
124 fprintf(stderr, "\n");
125 fflush(stderr);
126 call_lossage_handler();
129 boolean lose_on_corruption_p = 0;
131 void
132 corruption_warning_and_maybe_lose(char *fmt, ...)
134 va_list ap;
135 #ifndef LISP_FEATURE_WIN32
136 sigset_t oldset;
137 block_blockable_signals(0, &oldset);
138 #endif
139 fprintf(stderr, "CORRUPTION WARNING");
140 va_start(ap, fmt);
141 print_message(fmt, ap);
142 va_end(ap);
143 fprintf(stderr, "The integrity of this image is possibly compromised.\n");
144 if (lose_on_corruption_p)
145 fprintf(stderr, "Exiting.\n");
146 else
147 fprintf(stderr, "Continuing with fingers crossed.\n");
148 fflush(stderr);
149 if (lose_on_corruption_p)
150 call_lossage_handler();
151 #ifndef LISP_FEATURE_WIN32
152 else
153 thread_sigmask(SIG_SETMASK,&oldset,0);
154 #endif
157 void print_constant(os_context_t *context, int offset) {
158 lispobj code = find_code(context);
159 if (code != NIL) {
160 struct code *codeptr = (struct code *)native_pointer(code);
161 int length = HeaderValue(codeptr->header);
162 putchar('\t');
163 if (offset >= length) {
164 printf("Constant offset %d out of bounds for the code object of length %d.\n",
165 offset, length);
166 } else {
167 brief_print(codeptr->constants[offset -
168 (offsetof(struct code, constants) >> WORD_SHIFT)]);
173 char *internal_error_descriptions[] = {INTERNAL_ERROR_NAMES};
174 /* internal error handler for when the Lisp error system doesn't exist
176 * FIXME: Shouldn't error output go to stderr instead of stdout? (Alas,
177 * this'd require changes in a number of things like brief_print(..),
178 * or I'd have changed it immediately.) */
179 void
180 describe_internal_error(os_context_t *context)
182 unsigned char *ptr = arch_internal_error_arguments(context);
183 int len, scoffset, sc, offset, ch;
185 #ifdef LISP_FEATURE_ARM64
186 u32 trap_instruction = *(u32 *)ptr;
187 unsigned code = trap_instruction >> 13 & 0xFF;
188 printf("Internal error #%d \"%s\" at %p\n", code,
189 internal_error_descriptions[code],
190 (void*)*os_context_pc_addr(context));
191 ptr += 4;
192 len = *ptr++;
193 #else
194 len = *ptr++;
195 printf("Internal error #%d \"%s\" at %p\n", *ptr,
196 internal_error_descriptions[*ptr],
197 (void*)*os_context_pc_addr(context));
198 ptr++;
199 len--;
200 #endif
202 while (len > 0) {
203 scoffset = *ptr++;
204 len--;
205 if (scoffset == 253) {
206 scoffset = *ptr++;
207 len--;
209 else if (scoffset == 254) {
210 scoffset = ptr[0] + ptr[1]*256;
211 ptr += 2;
212 len -= 2;
214 else if (scoffset == 255) {
215 scoffset = ptr[0] + (ptr[1]<<8) + (ptr[2]<<16) + (ptr[3]<<24);
216 ptr += 4;
217 len -= 4;
219 sc = scoffset & 0x3F;
220 offset = scoffset >> 6;
222 printf(" SC: %d, Offset: %d", sc, offset);
223 switch (sc) {
224 case sc_AnyReg:
225 case sc_DescriptorReg:
226 putchar('\t');
227 brief_print(*os_context_register_addr(context, offset));
228 break;
230 case sc_CharacterReg:
231 ch = *os_context_register_addr(context, offset);
232 #ifdef LISP_FEATURE_X86
233 if (offset&1)
234 ch = ch>>8;
235 ch = ch & 0xff;
236 #endif
237 switch (ch) {
238 case '\n': printf("\t'\\n'\n"); break;
239 case '\b': printf("\t'\\b'\n"); break;
240 case '\t': printf("\t'\\t'\n"); break;
241 case '\r': printf("\t'\\r'\n"); break;
242 default:
243 if (ch < 32 || ch > 127)
244 printf("\\%03o", ch);
245 else
246 printf("\t'%c'\n", ch);
247 break;
249 break;
250 case sc_SapReg:
251 #ifdef sc_WordPointerReg
252 case sc_WordPointerReg:
253 #endif
254 printf("\t0x%08lx\n", (unsigned long) *os_context_register_addr(context, offset));
255 break;
256 case sc_SignedReg:
257 printf("\t%ld\n", (long) *os_context_register_addr(context, offset));
258 break;
259 case sc_UnsignedReg:
260 printf("\t%lu\n", (unsigned long) *os_context_register_addr(context, offset));
261 break;
262 #ifdef sc_SingleFloatReg
263 case sc_SingleFloatReg:
264 printf("\t%g\n", *(float *)&context->sc_fpregs[offset]);
265 break;
266 #endif
267 #ifdef sc_DoubleFloatReg
268 case sc_DoubleFloatReg:
269 printf("\t%g\n", *(double *)&context->sc_fpregs[offset]);
270 break;
271 #endif
272 case sc_Constant:
273 print_constant(context, offset);
274 break;
275 default:
276 printf("\t???\n");
277 break;
282 /* utility routines used by miscellaneous pieces of code */
284 lispobj debug_print(lispobj string)
286 /* This is a kludge. It's not actually safe - in general - to use
287 %primitive print on the alpha, because it skips half of the
288 number stack setup that should usually be done on a function
289 call, so the called routine (i.e. this one) ends up being able
290 to overwrite local variables in the caller. Rather than fix
291 this everywhere that %primitive print is used (it's only a
292 debugging aid anyway) we just guarantee our safety by putting
293 an unused buffer on the stack before doing anything else
294 here */
295 char untouched[32];
296 fprintf(stderr, "%s\n",
297 (char *)(((struct vector *)native_pointer(string))->data));
298 /* shut GCC up about not using this, because that's the point.. */
299 (void)untouched;
300 return NIL;