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