0.9.4.19:
[sbcl.git] / src / runtime / backtrace.c
1 /*
2  * simple backtrace facility
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
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.
14  */
15
16 #include <stdio.h>
17 #include <signal.h>
18 #include "sbcl.h"
19 #include "runtime.h"
20 #include "globals.h"
21 #include "os.h"
22 #include "interrupt.h"
23 #include "lispregs.h"
24 #ifdef LISP_FEATURE_GENCGC
25 #include "arch.h"
26 #include "gencgc-alloc-region.h"
27 #include "genesis/compiled-debug-fun.h"
28 #include "genesis/compiled-debug-info.h"
29 #include "genesis/package.h"
30 #endif
31 #include "genesis/static-symbols.h"
32 #include "genesis/primitive-objects.h"
33 #include "thread.h"
34
35 #ifdef LISP_FEATURE_OS_PROVIDES_DLADDR
36 /* __USE_GNU needed if we want dladdr() and Dl_Info from glibc. */
37 #define __USE_GNU
38 #include "dlfcn.h"
39 #endif
40
41 #if !(defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64))
42
43 /* KLUDGE: Sigh ... I know what the call frame looks like and it had
44  * better not change. */
45
46 struct call_frame {
47 #ifndef LISP_FEATURE_ALPHA
48         struct call_frame *old_cont;
49 #else
50         u32 old_cont;
51 #endif
52         lispobj saved_lra;
53         lispobj code;
54         lispobj other_state[5];
55 };
56
57 struct call_info {
58 #ifndef LISP_FEATURE_ALPHA
59     struct call_frame *frame;
60 #else
61     u32 frame;
62 #endif
63     int interrupted;
64 #ifndef LISP_FEATURE_ALPHA
65     struct code *code;
66 #else
67     u32 code;
68 #endif
69     lispobj lra;
70     int pc; /* Note: this is the trace file offset, not the actual pc. */
71 };
72
73 #define HEADER_LENGTH(header) ((header)>>8)
74
75 static int previous_info(struct call_info *info);
76
77 static struct code *
78 code_pointer(lispobj object)
79 {
80     lispobj *headerp, header;
81     int type, len;
82
83     headerp = (lispobj *) native_pointer(object);
84     header = *headerp;
85     type = widetag_of(header);
86
87     switch (type) {
88         case CODE_HEADER_WIDETAG:
89             break;
90         case RETURN_PC_HEADER_WIDETAG:
91         case SIMPLE_FUN_HEADER_WIDETAG:
92             len = HEADER_LENGTH(header);
93             if (len == 0)
94                 headerp = NULL;
95             else
96                 headerp -= len;
97             break;
98         default:
99             headerp = NULL;
100     }
101
102     return (struct code *) headerp;
103 }
104
105 static boolean
106 cs_valid_pointer_p(struct call_frame *pointer)
107 {
108     struct thread *thread=arch_os_get_current_thread();
109     return (((char *) thread->control_stack_start <= (char *) pointer) &&
110             ((char *) pointer < (char *) current_control_stack_pointer));
111 }
112
113 static void
114 call_info_from_lisp_state(struct call_info *info)
115 {
116     info->frame = (struct call_frame *)current_control_frame_pointer;
117     info->interrupted = 0;
118     info->code = NULL;
119     info->lra = 0;
120     info->pc = 0;
121
122     previous_info(info);
123 }
124
125 static void
126 call_info_from_context(struct call_info *info, os_context_t *context)
127 {
128     unsigned long pc;
129
130     info->interrupted = 1;
131     if (lowtag_of(*os_context_register_addr(context, reg_CODE))
132         == FUN_POINTER_LOWTAG) {
133         /* We tried to call a function, but crapped out before $CODE could
134          * be fixed up. Probably an undefined function. */
135         info->frame =
136             (struct call_frame *)(*os_context_register_addr(context,
137                                                             reg_OCFP));
138         info->lra = (lispobj)(*os_context_register_addr(context, reg_LRA));
139         info->code = code_pointer(info->lra);
140         pc = (unsigned long)native_pointer(info->lra);
141     }
142     else {
143         info->frame =
144             (struct call_frame *)(*os_context_register_addr(context, reg_CFP));
145         info->code =
146             code_pointer(*os_context_register_addr(context, reg_CODE));
147         info->lra = NIL;
148         pc = *os_context_pc_addr(context);
149     }
150     if (info->code != NULL)
151         info->pc = pc - (unsigned long) info->code -
152 #ifndef LISP_FEATURE_ALPHA
153             (HEADER_LENGTH(info->code->header) * sizeof(lispobj));
154 #else
155             (HEADER_LENGTH(((struct code *)info->code)->header) * sizeof(lispobj));
156 #endif
157     else
158         info->pc = 0;
159 }
160
161 static int
162 previous_info(struct call_info *info)
163 {
164     struct call_frame *this_frame;
165     struct thread *thread=arch_os_get_current_thread();
166     int free;
167
168     if (!cs_valid_pointer_p(info->frame)) {
169         printf("Bogus callee value (0x%08lx).\n", (unsigned long)info->frame);
170         return 0;
171     }
172
173     this_frame = info->frame;
174     info->lra = this_frame->saved_lra;
175     info->frame = this_frame->old_cont;
176     info->interrupted = 0;
177
178     if (info->frame == NULL || info->frame == this_frame)
179         return 0;
180
181     if (info->lra == NIL) {
182         /* We were interrupted. Find the correct signal context. */
183         free = SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX,thread)>>2;
184         while (free-- > 0) {
185             os_context_t *context =
186                 thread->interrupt_contexts[free];
187             if ((struct call_frame *)(*os_context_register_addr(context,
188                                                                 reg_CFP))
189                 == info->frame) {
190                 call_info_from_context(info, context);
191                 break;
192             }
193         }
194     }
195     else {
196         info->code = code_pointer(info->lra);
197         if (info->code != NULL)
198             info->pc = (unsigned long)native_pointer(info->lra) -
199                 (unsigned long)info->code -
200 #ifndef LISP_FEATURE_ALPHA
201                 (HEADER_LENGTH(info->code->header) * sizeof(lispobj));
202 #else
203                 (HEADER_LENGTH(((struct code *)info->code)->header) * sizeof(lispobj));
204 #endif
205         else
206             info->pc = 0;
207     }
208
209     return 1;
210 }
211
212 void
213 backtrace(int nframes)
214 {
215     struct call_info info;
216
217     call_info_from_lisp_state(&info);
218
219     do {
220         printf("<Frame 0x%08lx%s, ", (unsigned long) info.frame,
221                 info.interrupted ? " [interrupted]" : "");
222
223         if (info.code != (struct code *) 0) {
224             lispobj function;
225
226             printf("CODE: 0x%08lX, ", (unsigned long) info.code | OTHER_POINTER_LOWTAG);
227
228 #ifndef LISP_FEATURE_ALPHA
229             function = info.code->entry_points;
230 #else
231             function = ((struct code *)info.code)->entry_points;
232 #endif
233             while (function != NIL) {
234                 struct simple_fun *header;
235                 lispobj name;
236
237                 header = (struct simple_fun *) native_pointer(function);
238                 name = header->name;
239
240                 if (lowtag_of(name) == OTHER_POINTER_LOWTAG) {
241                     lispobj *object;
242
243                     object = (lispobj *) native_pointer(name);
244
245                     if (widetag_of(*object) == SYMBOL_HEADER_WIDETAG) {
246                         struct symbol *symbol;
247
248                         symbol = (struct symbol *) object;
249                         object = (lispobj *) native_pointer(symbol->name);
250                     }
251                     if (widetag_of(*object) == SIMPLE_BASE_STRING_WIDETAG) {
252                         struct vector *string;
253
254                         string = (struct vector *) object;
255                         printf("%s, ", (char *) string->data);
256                     } else
257                         /* FIXME: broken from (VECTOR NIL) */
258                         printf("(Not simple string??\?), ");
259                 } else
260                     printf("(Not other pointer??\?), ");
261
262
263                 function = header->next;
264             }
265         }
266         else
267             printf("CODE: ???, ");
268
269         if (info.lra != NIL)
270             printf("LRA: 0x%08lx, ", (unsigned long)info.lra);
271         else
272             printf("<no LRA>, ");
273
274         if (info.pc)
275             printf("PC: 0x%x>\n", info.pc);
276         else
277             printf("PC: ??\?>\n");
278
279     } while (--nframes > 0 && previous_info(&info));
280 }
281
282 #else
283
284 static int
285 stack_pointer_p (void *p)
286 {
287   return (p < (void *) arch_os_get_current_thread()->control_stack_end
288           && p > (void *) &p
289           && (((unsigned long) p) & 3) == 0);
290 }
291
292 static int
293 ra_pointer_p (void *ra)
294 {
295   return ((unsigned long) ra) > 4096 && !stack_pointer_p (ra);
296 }
297
298 static int
299 x86_call_context (void *fp, void **ra, void **ocfp)
300 {
301   void *lisp_ocfp;
302   void *lisp_ra;
303   void *c_ocfp;
304   void *c_ra;
305   int lisp_valid_p, c_valid_p;
306
307   if (!stack_pointer_p(fp))
308     return 0;
309
310   c_ocfp    = *((void **) fp);
311   c_ra      = *((void **) fp + 1);
312   lisp_ocfp = *((void **) fp - 1);
313   lisp_ra   = *((void **) fp - 2);
314
315   lisp_valid_p = (lisp_ocfp > fp
316                   && stack_pointer_p(lisp_ocfp)
317                   && ra_pointer_p(lisp_ra));
318   c_valid_p = (c_ocfp > fp
319                && stack_pointer_p(c_ocfp)
320                && ra_pointer_p(c_ra));
321
322   if (lisp_valid_p && c_valid_p) {
323     void *lisp_path_fp;
324     void *c_path_fp;
325     void *dummy;
326
327     int lisp_path_p = x86_call_context(lisp_ocfp, &lisp_path_fp, &dummy);
328     int c_path_p = x86_call_context(c_ocfp, &c_path_fp, &dummy);
329
330     if (lisp_path_p && c_path_p) {
331 #if defined __FreeBSD__ && __FreeBSD_version > 400000
332       if (lisp_ocfp > c_ocfp)
333         *ra = lisp_ra, *ocfp = lisp_ocfp;
334       else
335         *ra = c_ra, *ocfp = c_ocfp;
336 #else
337       *ra = lisp_ra, *ocfp = lisp_ocfp;
338 #endif
339     }
340     else if (lisp_path_p)
341       *ra = lisp_ra, *ocfp = lisp_ocfp;
342     else if (c_path_p)
343       *ra = c_ra, *ocfp = c_ocfp;
344     else
345       return 0;
346   }
347   else if (lisp_valid_p)
348     *ra = lisp_ra, *ocfp = lisp_ocfp;
349   else if (c_valid_p)
350     *ra = c_ra, *ocfp = c_ocfp;
351   else
352     return 0;
353
354   return 1;
355 }
356
357 struct compiled_debug_fun *
358 debug_function_from_pc (struct code* code, void *pc)
359 {
360   unsigned long code_header_len = sizeof(lispobj) * HeaderValue(code->header);
361   unsigned long offset
362     = (unsigned long) pc - (unsigned long) code - code_header_len;
363   struct compiled_debug_fun *df;
364   struct compiled_debug_info *di;
365   struct vector *v;
366   int i, len;
367
368   if (lowtag_of(code->debug_info) != INSTANCE_POINTER_LOWTAG)
369     return 0;
370
371   di = (struct compiled_debug_info *) native_pointer(code->debug_info);
372   v = (struct vector *) native_pointer(di->fun_map);
373   len = fixnum_value(v->length);
374   df = (struct compiled_debug_fun *) native_pointer(v->data[0]);
375
376   if (len == 1)
377     return df;
378
379   for (i = 1;; i += 2) {
380     unsigned next_pc;
381
382     if (i == len)
383       return ((struct compiled_debug_fun *) native_pointer(v->data[i - 1]));
384
385     if (offset >= fixnum_value(df->elsewhere_pc)) {
386       struct compiled_debug_fun *p
387         = ((struct compiled_debug_fun *) native_pointer(v->data[i + 1]));
388       next_pc = fixnum_value(p->elsewhere_pc);
389     } else
390       next_pc = fixnum_value(v->data[i]);
391
392     if (offset < next_pc)
393       return ((struct compiled_debug_fun *) native_pointer(v->data[i - 1]));
394   }
395
396   return NULL;
397 }
398
399 static void
400 print_entry_name (lispobj name)
401 {
402   if (lowtag_of (name) == LIST_POINTER_LOWTAG) {
403     putchar('(');
404     while (name != NIL) {
405       struct cons *cons = (struct cons *) native_pointer(name);
406       print_entry_name(cons->car);
407       name = cons->cdr;
408       if (name != NIL)
409         putchar(' ');
410     }
411     putchar(')');
412   } else if (lowtag_of(name) == OTHER_POINTER_LOWTAG) {
413     lispobj *object = (lispobj *) native_pointer(name);
414
415     if (widetag_of(*object) == SYMBOL_HEADER_WIDETAG) {
416       struct symbol *symbol = (struct symbol *) object;
417       struct vector *string;
418
419       if (symbol->package != NIL) {
420         struct package *pkg
421           = (struct package *) native_pointer(symbol->package);
422         lispobj pkg_name = pkg->_name;
423         string = (struct vector *) native_pointer(pkg_name);
424         printf("%s::", (char *) string->data);
425       }
426
427       object = (lispobj *) native_pointer(symbol->name);
428       string = (struct vector *) object;
429       printf("%s", (char *) string->data);
430     } else if (widetag_of(*object) == SIMPLE_BASE_STRING_WIDETAG) {
431       struct vector *string = (struct vector *) object;
432       printf("\"%s\"", (char *) string->data);
433 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
434     } else if (widetag_of(*object) == SIMPLE_CHARACTER_STRING_WIDETAG) {
435       printf("<oops, a unicode string>");                           /* FIXME */
436 #endif
437     } else
438       printf("<??? type %d>", (int) widetag_of(*object));
439   } else
440     printf("<??? lowtag %d>", (int) lowtag_of(name));
441 }
442
443 static void
444 print_entry_points (struct code *code)
445 {
446   lispobj function = code->entry_points;
447
448   while (function != NIL) {
449     struct simple_fun *header = (struct simple_fun *) native_pointer(function);
450     print_entry_name(header->name);
451
452     function = header->next;
453     if (function != NIL)
454       printf (", ");
455   }
456 }
457
458 void
459 backtrace(int nframes)
460 {
461   void *fp;
462   int i;
463
464 #if defined(LISP_FEATURE_X86)
465   asm("movl %%ebp,%0" : "=g" (fp));
466 #elif defined (LISP_FEATURE_X86_64)
467   asm("movq %%rbp,%0" : "=g" (fp));
468 #else
469 #error "How did we get here?"
470 #endif
471
472   for (i = 0; i < nframes; ++i) {
473     lispobj *p;
474     void *ra;
475     void *next_fp;
476
477     if (!x86_call_context(fp, &ra, &next_fp))
478       break;
479
480     printf("%4d: ", i);
481
482     p = (lispobj *) component_ptr_from_pc((lispobj *) ra);
483     if (p) {
484       struct code *cp = (struct code *) p;
485       struct compiled_debug_fun *df = debug_function_from_pc(cp, ra);
486       if (df)
487         print_entry_name(df->name);
488       else
489         print_entry_points(cp);
490     } else {
491 #ifdef LISP_FEATURE_OS_PROVIDES_DLADDR
492         Dl_info info;
493         if (dladdr(ra, &info)) {
494             printf("Foreign function %s, fp = 0x%lx, ra = 0x%lx",
495                    info.dli_sname,
496                    (unsigned long) next_fp,
497                    (unsigned long) ra);
498         } else
499 #endif
500         printf("Foreign fp = 0x%lx, ra = 0x%lx",
501                (unsigned long) next_fp,
502                (unsigned long) ra);
503     }
504
505     putchar('\n');
506     fp = next_fp;
507   }
508 }
509
510 #endif