Adapt GDB integration to newest patches
[bpt/guile.git] / libguile / stacks.c
CommitLineData
aa3f6951 1/* A stack holds a frame chain
8de051da 2 * Copyright (C) 1996,1997,2000,2001, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation
782d171c 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
782d171c 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
782d171c 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
782d171c 21\f
dbb605f5
LC
22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif
782d171c 25
a0599745 26#include "libguile/_scm.h"
06dcb9df 27#include "libguile/control.h"
a0599745
MD
28#include "libguile/eval.h"
29#include "libguile/debug.h"
30#include "libguile/continuations.h"
31#include "libguile/struct.h"
32#include "libguile/macros.h"
33#include "libguile/procprop.h"
34#include "libguile/modules.h"
35#include "libguile/root.h"
36#include "libguile/strings.h"
b1b942b7
AW
37#include "libguile/vm.h" /* to capture vm stacks */
38#include "libguile/frames.h" /* vm frames */
a0599745
MD
39
40#include "libguile/validate.h"
41#include "libguile/stacks.h"
22fc179a
HWN
42#include "libguile/private-options.h"
43
782d171c 44
06dcb9df
AW
45static SCM scm_sys_stacks;
46
782d171c 47\f
aa3f6951 48/* {Stacks}
782d171c 49 *
aa3f6951
AW
50 * The stack is represented as a struct that holds a frame. The frame itself is
51 * linked to the next frame, or #f.
782d171c
MD
52 *
53 * Stacks
54 * Constructor
55 * make-stack
7115d1e4
MD
56 * Selectors
57 * stack-id
782d171c
MD
58 * stack-ref
59 * Inspector
60 * stack-length
aa3f6951 61 */
782d171c
MD
62
63\f
64
aa3f6951 65/* Count number of debug info frames on a stack, beginning with FRAME.
782d171c 66 */
b1b942b7 67static long
3b14dd2f 68stack_depth (enum scm_vm_frame_kind kind, const struct scm_frame *frame)
782d171c 69{
3b14dd2f
AW
70 struct scm_frame tmp;
71 long n = 1;
72 memcpy (&tmp, frame, sizeof tmp);
73 while (scm_c_frame_previous (kind, &tmp))
93dbc31b 74 ++n;
782d171c
MD
75 return n;
76}
77
c3a6c6f9
MD
78/* Narrow STACK by cutting away stackframes (mutatingly).
79 *
80 * Inner frames (most recent) are cut by advancing the frames pointer.
81 * Outer frames are cut by decreasing the recorded length.
82 *
83 * Cut maximally INNER inner frames and OUTER outer frames using
84 * the keys INNER_KEY and OUTER_KEY.
85 *
86 * Frames are cut away starting at the end points and moving towards
87 * the center of the stack. The key is normally compared to the
88 * operator in application frames. Frames up to and including the key
89 * are cut.
90 *
91 * If INNER_KEY is #t a different scheme is used for inner frames:
92 *
93 * Frames up to but excluding the first source frame originating from
94 * a user module are cut, except for possible application frames
95 * between the user frame and the last system frame previously
96 * encountered.
97 */
98
0bca90aa 99static scm_t_ptrdiff
06dcb9df
AW
100find_prompt (SCM key)
101{
0bca90aa 102 scm_t_ptrdiff fp_offset;
9ede013f
AW
103
104 if (!scm_dynstack_find_prompt (&SCM_I_CURRENT_THREAD->dynstack, key,
0bca90aa 105 NULL, &fp_offset, NULL, NULL, NULL))
9ede013f
AW
106 scm_misc_error ("make-stack", "Prompt tag not found while narrowing stack",
107 scm_list_1 (key));
108
0bca90aa 109 return fp_offset;
06dcb9df
AW
110}
111
3b14dd2f
AW
112static long
113narrow_stack (long len, enum scm_vm_frame_kind kind, struct scm_frame *frame,
114 SCM inner_cut, SCM outer_cut)
7115d1e4 115{
de0233af
AW
116 /* Resolve procedure cuts to address ranges, if possible. If the
117 debug information has been stripped, this might not be
118 possible. */
119 if (scm_is_true (scm_program_p (inner_cut)))
120 {
121 SCM addr_range = scm_program_address_range (inner_cut);
122 if (scm_is_pair (addr_range))
123 inner_cut = addr_range;
124 }
125 if (scm_is_true (scm_program_p (outer_cut)))
126 {
127 SCM addr_range = scm_program_address_range (outer_cut);
128 if (scm_is_pair (addr_range))
129 outer_cut = addr_range;
130 }
131
7115d1e4 132 /* Cut inner part. */
99d7688b 133 if (scm_is_true (scm_procedure_p (inner_cut)))
c3a6c6f9 134 {
06dcb9df 135 /* Cut until the given procedure is seen. */
99d7688b 136 for (; len ;)
aa3f6951 137 {
3b14dd2f 138 SCM proc = scm_c_frame_closure (kind, frame);
aa3f6951 139 len--;
3b14dd2f 140 scm_c_frame_previous (kind, frame);
99d7688b 141 if (scm_is_eq (proc, inner_cut))
06dcb9df 142 break;
aa3f6951 143 }
c3a6c6f9 144 }
de0233af
AW
145 else if (scm_is_pair (inner_cut)
146 && scm_is_integer (scm_car (inner_cut))
147 && scm_is_integer (scm_cdr (inner_cut)))
148 {
149 /* Cut until an IP within the given range is found. */
150 scm_t_uintptr low_pc, high_pc, pc;
151
152 low_pc = scm_to_uintptr_t (scm_car (inner_cut));
153 high_pc = scm_to_uintptr_t (scm_cdr (inner_cut));
154
155 for (; len ;)
156 {
157 pc = (scm_t_uintptr) frame->ip;
158 len--;
159 scm_c_frame_previous (kind, frame);
160 if (low_pc <= pc && pc < high_pc)
161 break;
162 }
163 }
99d7688b 164 else if (scm_is_integer (inner_cut))
c3a6c6f9 165 {
06dcb9df 166 /* Cut specified number of frames. */
99d7688b
NL
167 long inner = scm_to_int (inner_cut);
168
06dcb9df 169 for (; inner && len; --inner)
aa3f6951 170 {
aa3f6951 171 len--;
3b14dd2f 172 scm_c_frame_previous (kind, frame);
aa3f6951 173 }
c3a6c6f9 174 }
99d7688b
NL
175 else
176 {
177 /* Cut until the given prompt tag is seen. */
0bca90aa 178 scm_t_ptrdiff fp_offset = find_prompt (inner_cut);
3b14dd2f
AW
179 for (; len; len--, scm_c_frame_previous (kind, frame))
180 if (fp_offset == frame->fp_offset)
99d7688b
NL
181 break;
182 }
aa3f6951 183
7115d1e4 184 /* Cut outer part. */
99d7688b 185 if (scm_is_true (scm_procedure_p (outer_cut)))
aa3f6951 186 {
3b14dd2f
AW
187 long i, new_len;
188 struct scm_frame tmp;
189
190 memcpy (&tmp, frame, sizeof tmp);
191
06dcb9df 192 /* Cut until the given procedure is seen. */
3b14dd2f
AW
193 for (new_len = i = 0; i < len; i++, scm_c_frame_previous (kind, &tmp))
194 if (scm_is_eq (scm_c_frame_closure (kind, &tmp), outer_cut))
195 new_len = i;
196
de0233af
AW
197 len = new_len;
198 }
199 else if (scm_is_pair (outer_cut)
200 && scm_is_integer (scm_car (outer_cut))
201 && scm_is_integer (scm_cdr (outer_cut)))
202 {
203 /* Cut until an IP within the given range is found. */
204 scm_t_uintptr low_pc, high_pc, pc;
205 long i, new_len;
206 struct scm_frame tmp;
207
208 low_pc = scm_to_uintptr_t (scm_car (outer_cut));
209 high_pc = scm_to_uintptr_t (scm_cdr (outer_cut));
210
211 memcpy (&tmp, frame, sizeof tmp);
212
213 /* Cut until the given procedure is seen. */
214 for (new_len = i = 0; i < len; i++, scm_c_frame_previous (kind, &tmp))
215 {
216 pc = (scm_t_uintptr) tmp.ip;
217 if (low_pc <= pc && pc < high_pc)
218 new_len = i;
219 }
220
3b14dd2f 221 len = new_len;
06dcb9df 222 }
99d7688b
NL
223 else if (scm_is_integer (outer_cut))
224 {
225 /* Cut specified number of frames. */
226 long outer = scm_to_int (outer_cut);
227
228 if (outer < len)
229 len -= outer;
230 else
231 len = 0;
232 }
233 else
06dcb9df 234 {
99d7688b 235 /* Cut until the given prompt tag is seen. */
3b14dd2f
AW
236 long i;
237 struct scm_frame tmp;
0bca90aa 238 scm_t_ptrdiff fp_offset = find_prompt (outer_cut);
3b14dd2f
AW
239
240 memcpy (&tmp, frame, sizeof tmp);
241
242 for (i = 0; i < len; i++, scm_c_frame_previous (kind, &tmp))
243 if (tmp.fp_offset == fp_offset)
244 break;
245
246 if (i < len)
247 len = i;
248 else
249 len = 0;
06dcb9df 250 }
7115d1e4 251
3b14dd2f 252 return len;
7115d1e4
MD
253}
254
782d171c
MD
255\f
256
257/* Stacks
258 */
259
762e289a 260SCM scm_stack_type;
66f45472 261
a1ec6916 262SCM_DEFINE (scm_stack_p, "stack?", 1, 0, 0,
1bbd0b84 263 (SCM obj),
b380b885 264 "Return @code{#t} if @var{obj} is a calling stack.")
1bbd0b84 265#define FUNC_NAME s_scm_stack_p
66f45472 266{
7888309b 267 return scm_from_bool(SCM_STACKP (obj));
66f45472 268}
1bbd0b84 269#undef FUNC_NAME
66f45472 270
af45e3b0
DH
271SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
272 (SCM obj, SCM args),
67941e3c
MG
273 "Create a new stack. If @var{obj} is @code{#t}, the current\n"
274 "evaluation stack is used for creating the stack frames,\n"
275 "otherwise the frames are taken from @var{obj} (which must be\n"
06dcb9df
AW
276 "a continuation or a frame object).\n"
277 "\n"
baffb19f 278 "@var{args} should be a list containing any combination of\n"
de0233af
AW
279 "integer, procedure, address range, prompt tag and @code{#t}\n"
280 "values.\n"
06dcb9df 281 "\n"
baffb19f
NJ
282 "These values specify various ways of cutting away uninteresting\n"
283 "stack frames from the top and bottom of the stack that\n"
284 "@code{make-stack} returns. They come in pairs like this:\n"
285 "@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}\n"
06dcb9df
AW
286 "@var{outer_cut_2} @dots{})}.\n"
287 "\n"
de0233af
AW
288 "Each @var{inner_cut_i} can be an integer, a procedure, an\n"
289 "address range, or a prompt tag. An integer means to cut away\n"
290 "exactly that number of frames. A procedure means to cut\n"
291 "away all frames up to but excluding the frame whose procedure\n"
292 "matches the specified one. An address range is a pair of\n"
293 "integers indicating the low and high addresses of a procedure's\n"
294 "code, and is the same as cutting away to a procedure (though\n"
295 "with less work). Anything else is interpreted as a prompt tag\n"
296 "which cuts away all frames that are inside a prompt with the\n"
297 "given tag.\n"
06dcb9df 298 "\n"
de0233af
AW
299 "Each @var{outer_cut_i} can be an integer, a procedure, an\n"
300 "address range, or a prompt tag. An integer means to cut away\n"
301 "that number of frames. A procedure means to cut away frames\n"
302 "down to but excluding the frame whose procedure matches the\n"
303 "specified one. An address range is the same, but with the\n"
304 "procedure's code specified as an address range. Anything else\n"
305 "is taken to be a prompt tag, which cuts away all frames that are\n"
306 "outside a prompt with the given tag.\n"
06dcb9df 307 "\n"
de0233af
AW
308 "If the @var{outer_cut_i} of the last pair is missing, it is\n"
309 "taken as 0.")
1bbd0b84 310#define FUNC_NAME s_scm_make_stack
782d171c 311{
aa3f6951 312 long n;
af45e3b0 313 SCM inner_cut, outer_cut;
3b14dd2f
AW
314 enum scm_vm_frame_kind kind;
315 struct scm_frame frame;
f6f88e0d
MD
316
317 /* Extract a pointer to the innermost frame of whatever object
318 scm_make_stack was given. */
bc36d050 319 if (scm_is_eq (obj, SCM_BOOL_T))
782d171c 320 {
aa3f6951
AW
321 SCM cont;
322 struct scm_vm_cont *c;
323
9ede013f 324 cont = scm_i_capture_current_stack ();
8de051da 325 c = SCM_VM_CONT_DATA (cont);
3b14dd2f
AW
326
327 kind = SCM_VM_FRAME_KIND_CONT;
328 frame.stack_holder = c;
329 frame.fp_offset = (c->fp + c->reloc) - c->stack_base;
330 frame.sp_offset = (c->sp + c->reloc) - c->stack_base;
331 frame.ip = c->ra;
13dcb666 332 }
b1b942b7 333 else if (SCM_VM_FRAME_P (obj))
3b14dd2f
AW
334 {
335 kind = SCM_VM_FRAME_KIND (obj);
336 memcpy (&frame, SCM_VM_FRAME_DATA (obj), sizeof frame);
337 }
13dcb666 338 else if (SCM_CONTINUATIONP (obj))
06dcb9df
AW
339 /* FIXME: Narrowing to prompt tags should narrow with respect to the prompts
340 that were in place when the continuation was captured. */
3b14dd2f
AW
341 {
342 kind = SCM_VM_FRAME_KIND_CONT;
343 if (!scm_i_continuation_to_frame (obj, &frame))
344 return SCM_BOOL_F;
345 }
4cfa92d6
AW
346 else if (SCM_PROGRAM_P (obj) && SCM_PROGRAM_IS_PARTIAL_CONTINUATION (obj))
347 {
348 kind = SCM_VM_FRAME_KIND_CONT;
349 if (!scm_i_vm_cont_to_frame (SCM_PROGRAM_FREE_VARIABLE_REF (obj, 0),
350 &frame))
351 return SCM_BOOL_F;
352 }
13dcb666
DH
353 else
354 {
355 SCM_WRONG_TYPE_ARG (SCM_ARG1, obj);
356 /* not reached */
782d171c
MD
357 }
358
3b14dd2f
AW
359 /* Skip initial boot frame, if any. This is possible if the frame
360 originates from a captured continuation. */
361 if (SCM_PROGRAM_P (scm_c_frame_closure (kind, &frame))
362 && SCM_PROGRAM_IS_BOOT (scm_c_frame_closure (kind, &frame))
363 && !scm_c_frame_previous (kind, &frame))
14aa25e4
AW
364 return SCM_BOOL_F;
365
f6f88e0d
MD
366 /* Count number of frames. Also get stack id tag and check whether
367 there are more stackframes than we want to record
368 (SCM_BACKTRACE_MAXDEPTH). */
3b14dd2f 369 n = stack_depth (kind, &frame);
782d171c 370
f6f88e0d 371 /* Narrow the stack according to the arguments given to scm_make_stack. */
af45e3b0 372 SCM_VALIDATE_REST_ARGUMENT (args);
d2e53ed6 373 while (n > 0 && !scm_is_null (args))
f6f88e0d
MD
374 {
375 inner_cut = SCM_CAR (args);
376 args = SCM_CDR (args);
d2e53ed6 377 if (scm_is_null (args))
af45e3b0 378 {
13dcb666 379 outer_cut = SCM_INUM0;
af45e3b0
DH
380 }
381 else
f6f88e0d
MD
382 {
383 outer_cut = SCM_CAR (args);
384 args = SCM_CDR (args);
385 }
f6f88e0d 386
3b14dd2f 387 n = narrow_stack (n, kind, &frame, inner_cut, outer_cut);
f6f88e0d
MD
388 }
389
7115d1e4 390 if (n > 0)
3b14dd2f
AW
391 {
392 /* Make the stack object. */
393 SCM stack = scm_make_struct (scm_stack_type, SCM_INUM0, SCM_EOL);
394 SCM_SET_STACK_LENGTH (stack, n);
395 SCM_SET_STACK_ID (stack, scm_stack_id (obj));
396 SCM_SET_STACK_FRAME (stack, scm_c_make_frame (kind, &frame));
397 return stack;
398 }
7115d1e4
MD
399 else
400 return SCM_BOOL_F;
782d171c 401}
1bbd0b84 402#undef FUNC_NAME
782d171c 403
a1ec6916 404SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
1bbd0b84 405 (SCM stack),
b380b885 406 "Return the identifier given to @var{stack} by @code{start-stack}.")
1bbd0b84 407#define FUNC_NAME s_scm_stack_id
66f45472 408{
06dcb9df
AW
409 if (scm_is_eq (stack, SCM_BOOL_T)
410 /* FIXME: frame case assumes frame still live on the stack, and no
411 intervening start-stack. Hmm... */
412 || SCM_VM_FRAME_P (stack))
7115d1e4 413 {
06dcb9df
AW
414 /* Fetch most recent start-stack tag. */
415 SCM stacks = scm_fluid_ref (scm_sys_stacks);
416 return scm_is_pair (stacks) ? scm_caar (stacks) : SCM_BOOL_F;
13dcb666
DH
417 }
418 else if (SCM_CONTINUATIONP (stack))
06dcb9df
AW
419 /* FIXME: implement me */
420 return SCM_BOOL_F;
4cfa92d6
AW
421 else if (SCM_PROGRAM_P (stack) && SCM_PROGRAM_IS_PARTIAL_CONTINUATION (stack))
422 /* FIXME: implement me */
423 return SCM_BOOL_F;
13dcb666
DH
424 else
425 {
14aa25e4
AW
426 SCM_WRONG_TYPE_ARG (SCM_ARG1, stack);
427 /* not reached */
13dcb666 428 }
66f45472 429}
1bbd0b84 430#undef FUNC_NAME
66f45472 431
a1ec6916 432SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
13dcb666
DH
433 (SCM stack, SCM index),
434 "Return the @var{index}'th frame from @var{stack}.")
1bbd0b84 435#define FUNC_NAME s_scm_stack_ref
782d171c 436{
13dcb666 437 unsigned long int c_index;
aa3f6951 438 SCM frame;
13dcb666
DH
439
440 SCM_VALIDATE_STACK (1, stack);
a55c2b68 441 c_index = scm_to_unsigned_integer (index, 0, SCM_STACK_LENGTH(stack)-1);
aa3f6951
AW
442 frame = SCM_STACK_FRAME (stack);
443 while (c_index--)
93dbc31b 444 frame = scm_frame_previous (frame);
aa3f6951 445 return frame;
782d171c 446}
1bbd0b84 447#undef FUNC_NAME
782d171c 448
3b3b36dd 449SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0,
67941e3c
MG
450 (SCM stack),
451 "Return the length of @var{stack}.")
1bbd0b84 452#define FUNC_NAME s_scm_stack_length
782d171c 453{
34d19ef6 454 SCM_VALIDATE_STACK (1, stack);
aa3f6951 455 return scm_from_long (SCM_STACK_LENGTH (stack));
782d171c 456}
1bbd0b84 457#undef FUNC_NAME
782d171c
MD
458
459\f
460
461void
462scm_init_stacks ()
463{
06dcb9df
AW
464 scm_sys_stacks = scm_make_fluid ();
465 scm_c_define ("%stacks", scm_sys_stacks);
466
f39448c5
AW
467 scm_stack_type = scm_make_vtable (scm_from_locale_string (SCM_STACK_LAYOUT),
468 SCM_UNDEFINED);
cc95e00a 469 scm_set_struct_vtable_name_x (scm_stack_type,
4a655e50 470 scm_from_latin1_symbol ("stack"));
a0599745 471#include "libguile/stacks.x"
782d171c 472}
89e00824
ML
473
474/*
475 Local Variables:
476 c-file-style: "gnu"
477 End:
478*/