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