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