Move error strings from "constants.h" to "errnames.h"
[sbcl.git] / src / runtime / interr.c
blob6e6235c84401a89110e2055b88cbf76e639dda8d
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"
34 #include "var-io.h"
35 #include "sc-offset.h"
37 /* the way that we shut down the system on a fatal error */
39 static void
40 default_lossage_handler(void)
42 exit(1);
44 static void (*lossage_handler)(void) = default_lossage_handler;
46 #if QSHOW
47 static void
48 configurable_lossage_handler()
50 void lisp_backtrace(int frames);
52 if (dyndebug_config.dyndebug_backtrace_when_lost) {
53 fprintf(stderr, "lose: backtrace follows as requested\n");
54 lisp_backtrace(100);
57 if (dyndebug_config.dyndebug_sleep_when_lost) {
58 fprintf(stderr,
59 "The system is too badly corrupted or confused to continue at the Lisp.\n"
60 "level. The monitor was enabled, but you requested `sleep_when_lost'\n"
61 "behaviour though dyndebug. To help with your debugging effort, this\n"
62 "thread will not enter the monitor, and instead proceed immediately to an\n"
63 "infinite sleep call, maximizing your chances that the thread's current\n"
64 "state can be preserved until you attach an external debugger. Good luck!\n");
65 for (;;)
66 # ifdef LISP_FEATURE_WIN32
67 Sleep(10000);
68 # else
69 sleep(10);
70 # endif
73 monitor_or_something();
75 #endif
77 void enable_lossage_handler(void)
79 #if QSHOW
80 lossage_handler = configurable_lossage_handler;
81 #else
82 lossage_handler = monitor_or_something;
83 #endif
85 void disable_lossage_handler(void)
87 lossage_handler = default_lossage_handler;
90 static
91 void print_message(char *fmt, va_list ap)
93 fprintf(stderr, " in SBCL pid %d",getpid());
94 #if defined(LISP_FEATURE_SB_THREAD)
95 fprintf(stderr, "(tid %p)", (void*)thread_self());
96 #endif
97 if (fmt) {
98 fprintf(stderr, ":\n");
99 vfprintf(stderr, fmt, ap);
101 fprintf(stderr, "\n");
104 static inline void
105 call_lossage_handler() never_returns;
107 static inline void
108 call_lossage_handler()
110 lossage_handler();
111 fprintf(stderr, "Argh! lossage_handler() returned, total confusion..\n");
112 exit(1);
115 void
116 lose(char *fmt, ...)
118 va_list ap;
119 /* Block signals to prevent other threads, timers and such from
120 * interfering. If only all threads could be stopped somehow. */
121 block_blockable_signals(0);
122 fprintf(stderr, "fatal error encountered");
123 va_start(ap, fmt);
124 print_message(fmt, ap);
125 va_end(ap);
126 fprintf(stderr, "\n");
127 fflush(stderr);
128 call_lossage_handler();
131 boolean lose_on_corruption_p = 0;
133 void
134 corruption_warning_and_maybe_lose(char *fmt, ...)
136 va_list ap;
137 #ifndef LISP_FEATURE_WIN32
138 sigset_t oldset;
139 block_blockable_signals(&oldset);
140 #endif
141 fprintf(stderr, "CORRUPTION WARNING");
142 va_start(ap, fmt);
143 print_message(fmt, ap);
144 va_end(ap);
145 fprintf(stderr, "The integrity of this image is possibly compromised.\n");
146 if (lose_on_corruption_p)
147 fprintf(stderr, "Exiting.\n");
148 else
149 fprintf(stderr, "Continuing with fingers crossed.\n");
150 fflush(stderr);
151 if (lose_on_corruption_p)
152 call_lossage_handler();
153 #ifndef LISP_FEATURE_WIN32
154 else
155 thread_sigmask(SIG_SETMASK,&oldset,0);
156 #endif
159 void print_constant(os_context_t *context, int offset) {
160 lispobj code = find_code(context);
161 if (code != NIL) {
162 struct code *codeptr = (struct code *)native_pointer(code);
163 int length = code_header_words(codeptr->header);
164 putchar('\t');
165 if (offset >= length) {
166 printf("Constant offset %d out of bounds for the code object of length %d.\n",
167 offset, length);
168 } else {
169 brief_print(codeptr->constants[offset -
170 (offsetof(struct code, constants) >> WORD_SHIFT)]);
175 #include "genesis/errnames.h"
176 char *internal_error_descriptions[] = {INTERNAL_ERROR_NAMES};
177 char internal_error_nargs[] = INTERNAL_ERROR_NARGS;
178 /* internal error handler for when the Lisp error system doesn't exist
180 * FIXME: Shouldn't error output go to stderr instead of stdout? (Alas,
181 * this'd require changes in a number of things like brief_print(..),
182 * or I'd have changed it immediately.) */
183 void
184 describe_internal_error(os_context_t *context)
186 unsigned char *ptr = arch_internal_error_arguments(context);
187 char count;
188 int position, sc_offset, sc_number, offset, ch;
189 void * pc = (void*)*os_context_pc_addr(context);
191 #ifdef LISP_FEATURE_ARM64
192 u32 trap_instruction = *(u32 *)ptr;
193 unsigned char code = trap_instruction >> 13 & 0xFF;
194 ptr += 4;
195 #else
196 unsigned char code = *ptr;
197 ptr++;
198 #endif
200 if (code > sizeof(internal_error_nargs)) {
201 printf("Unknown error code %d at %p\n", code, pc);
203 printf("Internal error #%d \"%s\" at %p\n", code, internal_error_descriptions[code], pc);
205 for (count = internal_error_nargs[code], position = 0;
206 count > 0;
207 --count) {
208 sc_offset = read_var_integer(ptr, &position);
209 sc_number = sc_offset_sc_number(sc_offset);
210 offset = sc_offset_offset(sc_offset);
212 printf(" SC: %d, Offset: %d", sc_number, offset);
213 switch (sc_number) {
214 case sc_AnyReg:
215 case sc_DescriptorReg:
216 putchar('\t');
217 brief_print(*os_context_register_addr(context, offset));
218 break;
220 case sc_CharacterReg:
221 ch = *os_context_register_addr(context, offset);
222 #ifdef LISP_FEATURE_X86
223 if (offset&1)
224 ch = ch>>8;
225 ch = ch & 0xff;
226 #endif
227 switch (ch) {
228 case '\n': printf("\t'\\n'\n"); break;
229 case '\b': printf("\t'\\b'\n"); break;
230 case '\t': printf("\t'\\t'\n"); break;
231 case '\r': printf("\t'\\r'\n"); break;
232 default:
233 if (ch < 32 || ch > 127)
234 printf("\\%03o", ch);
235 else
236 printf("\t'%c'\n", ch);
237 break;
239 break;
240 case sc_SapReg:
241 #ifdef sc_WordPointerReg
242 case sc_WordPointerReg:
243 #endif
244 printf("\t0x%08lx\n", (unsigned long) *os_context_register_addr(context, offset));
245 break;
246 case sc_SignedReg:
247 printf("\t%ld\n", (long) *os_context_register_addr(context, offset));
248 break;
249 case sc_UnsignedReg:
250 printf("\t%lu\n", (unsigned long) *os_context_register_addr(context, offset));
251 break;
252 #ifdef sc_SingleFloatReg
253 case sc_SingleFloatReg:
254 printf("\t%g\n", *(float *)&context->sc_fpregs[offset]);
255 break;
256 #endif
257 #ifdef sc_DoubleFloatReg
258 case sc_DoubleFloatReg:
259 printf("\t%g\n", *(double *)&context->sc_fpregs[offset]);
260 break;
261 #endif
262 case sc_Constant:
263 print_constant(context, offset);
264 break;
265 default:
266 printf("\t???\n");
267 break;
272 /* utility routines used by miscellaneous pieces of code */
274 lispobj debug_print(lispobj string)
276 /* This is a kludge. It's not actually safe - in general - to use
277 %primitive print on the alpha, because it skips half of the
278 number stack setup that should usually be done on a function
279 call, so the called routine (i.e. this one) ends up being able
280 to overwrite local variables in the caller. Rather than fix
281 this everywhere that %primitive print is used (it's only a
282 debugging aid anyway) we just guarantee our safety by putting
283 an unused buffer on the stack before doing anything else
284 here */
285 char untouched[32];
286 fprintf(stderr, "%s\n",
287 (char *)(((struct vector *)native_pointer(string))->data));
288 /* shut GCC up about not using this, because that's the point.. */
289 (void)untouched;
290 return NIL;