12f954f7305cff61dc401e5dbabe2daac31c7834
[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 "runtime.h"
19 #include "sbcl.h"
20 #include "globals.h"
21 #include "os.h"
22 #include "interrupt.h"
23 #include "lispregs.h"
24 #include "genesis/static-symbols.h"
25 #include "genesis/primitive-objects.h"
26
27 #ifndef __i386__
28
29 /* KLUDGE: Sigh ... I know what the call frame looks like and it had
30  * better not change. */
31
32 struct call_frame {
33 #ifndef alpha
34         struct call_frame *old_cont;
35 #else
36         u32 old_cont;
37 #endif
38         lispobj saved_lra;
39         lispobj code;
40         lispobj other_state[5];
41 };
42
43 struct call_info {
44 #ifndef alpha
45     struct call_frame *frame;
46 #else
47     u32 frame;
48 #endif
49     int interrupted;
50 #ifndef alpha
51     struct code *code;
52 #else
53     u32 code;
54 #endif
55     lispobj lra;
56     int pc; /* Note: this is the trace file offset, not the actual pc. */
57 };
58
59 #define HEADER_LENGTH(header) ((header)>>8)
60
61 static int previous_info(struct call_info *info);
62
63 static struct code *
64 code_pointer(lispobj object)
65 {
66     lispobj *headerp, header;
67     int type, len;
68
69     headerp = (lispobj *) native_pointer(object);
70     header = *headerp;
71     type = widetag_of(header);
72
73     switch (type) {
74         case CODE_HEADER_WIDETAG:
75             break;
76         case RETURN_PC_HEADER_WIDETAG:
77         case SIMPLE_FUN_HEADER_WIDETAG:
78         case CLOSURE_FUN_HEADER_WIDETAG:
79             len = HEADER_LENGTH(header);
80             if (len == 0)
81                 headerp = NULL;
82             else
83                 headerp -= len;
84             break;
85         default:
86             headerp = NULL;
87     }
88
89     return (struct code *) headerp;
90 }
91
92 static boolean
93 cs_valid_pointer_p(struct call_frame *pointer)
94 {
95     return (((char *) CONTROL_STACK_START <= (char *) pointer) &&
96             ((char *) pointer < (char *) current_control_stack_pointer));
97 }
98
99 static void
100 call_info_from_lisp_state(struct call_info *info)
101 {
102     info->frame = (struct call_frame *)current_control_frame_pointer;
103     info->interrupted = 0;
104     info->code = NULL;
105     info->lra = 0;
106     info->pc = 0;
107
108     previous_info(info);
109 }
110
111 static void
112 call_info_from_context(struct call_info *info, os_context_t *context)
113 {
114     unsigned long pc;
115
116     info->interrupted = 1;
117     if (lowtag_of(*os_context_register_addr(context, reg_CODE))
118         == FUN_POINTER_LOWTAG) {
119         /* We tried to call a function, but crapped out before $CODE could
120          * be fixed up. Probably an undefined function. */
121         info->frame =
122             (struct call_frame *)(*os_context_register_addr(context,
123                                                             reg_OCFP));
124         info->lra = (lispobj)(*os_context_register_addr(context, reg_LRA));
125         info->code = code_pointer(info->lra);
126         pc = (unsigned long)native_pointer(info->lra);
127     }
128     else {
129         info->frame =
130             (struct call_frame *)(*os_context_register_addr(context, reg_CFP));
131         info->code =
132             code_pointer(*os_context_register_addr(context, reg_CODE));
133         info->lra = NIL;
134         pc = *os_context_pc_addr(context);
135     }
136     if (info->code != NULL)
137         info->pc = pc - (unsigned long) info->code -
138 #ifndef alpha
139             (HEADER_LENGTH(info->code->header) * sizeof(lispobj));
140 #else
141             (HEADER_LENGTH(((struct code *)info->code)->header) * sizeof(lispobj));
142 #endif
143     else
144         info->pc = 0;
145 }
146
147 static int
148 previous_info(struct call_info *info)
149 {
150     struct call_frame *this_frame;
151     int free;
152
153     if (!cs_valid_pointer_p(info->frame)) {
154         printf("Bogus callee value (0x%08x).\n", (unsigned long)info->frame);
155         return 0;
156     }
157
158     this_frame = info->frame;
159     info->lra = this_frame->saved_lra;
160     info->frame = this_frame->old_cont;
161     info->interrupted = 0;
162
163     if (info->frame == NULL || info->frame == this_frame)
164         return 0;
165
166     if (info->lra == NIL) {
167         /* We were interrupted. Find the correct signal context. */
168         free = SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX)>>2;
169         while (free-- > 0) {
170             os_context_t *context = 
171                 lisp_interrupt_contexts[free];
172             if ((struct call_frame *)(*os_context_register_addr(context,
173                                                                 reg_CFP))
174                 == info->frame) {
175                 call_info_from_context(info, context);
176                 break;
177             }
178         }
179     }
180     else {
181         info->code = code_pointer(info->lra);
182         if (info->code != NULL)
183             info->pc = (unsigned long)native_pointer(info->lra) -
184                 (unsigned long)info->code -
185 #ifndef alpha
186                 (HEADER_LENGTH(info->code->header) * sizeof(lispobj));
187 #else
188                 (HEADER_LENGTH(((struct code *)info->code)->header) * sizeof(lispobj));
189 #endif
190         else
191             info->pc = 0;
192     }
193
194     return 1;
195 }
196
197 void
198 backtrace(int nframes)
199 {
200     struct call_info info;
201         
202     call_info_from_lisp_state(&info);
203
204     do {
205         printf("<Frame 0x%08x%s, ", (unsigned long) info.frame,
206                 info.interrupted ? " [interrupted]" : "");
207
208         if (info.code != (struct code *) 0) {
209             lispobj function;
210
211             printf("CODE: 0x%08X, ", (unsigned long) info.code | OTHER_POINTER_LOWTAG);
212
213 #ifndef alpha
214             function = info.code->entry_points;
215 #else
216             function = ((struct code *)info.code)->entry_points;
217 #endif
218             while (function != NIL) {
219                 struct simple_fun *header;
220                 lispobj name;
221
222                 header = (struct simple_fun *) native_pointer(function);
223                 name = header->name;
224
225                 if (lowtag_of(name) == OTHER_POINTER_LOWTAG) {
226                     lispobj *object;
227
228                     object = (lispobj *) native_pointer(name);
229
230                     if (widetag_of(*object) == SYMBOL_HEADER_WIDETAG) {
231                         struct symbol *symbol;
232
233                         symbol = (struct symbol *) object;
234                         object = (lispobj *) native_pointer(symbol->name);
235                     }
236                     if (widetag_of(*object) == SIMPLE_STRING_WIDETAG) {
237                         struct vector *string;
238
239                         string = (struct vector *) object;
240                         printf("%s, ", (char *) string->data);
241                     } else
242                         printf("(Not simple string??\?), ");
243                 } else
244                     printf("(Not other pointer??\?), ");
245
246
247                 function = header->next;
248             }
249         }
250         else
251             printf("CODE: ???, ");
252
253         if (info.lra != NIL)
254             printf("LRA: 0x%08x, ", (unsigned long)info.lra);
255         else
256             printf("<no LRA>, ");
257
258         if (info.pc)
259             printf("PC: 0x%x>\n", info.pc);
260         else
261             printf("PC: ??\?>\n");
262
263     } while (--nframes > 0 && previous_info(&info));
264 }
265
266 #else
267
268 void
269 backtrace(int nframes)
270 {
271     printf("Can't backtrace on this hardware platform.\n");
272 }
273
274 #endif