1 /* A stack holds a frame chain
2 * Copyright (C) 1996,1997,2000,2001, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation
4 * This library is free software; you can redistribute it and/or
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.
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
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
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 #include "libguile/_scm.h"
27 #include "libguile/control.h"
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"
37 #include "libguile/vm.h" /* to capture vm stacks */
38 #include "libguile/frames.h" /* vm frames */
40 #include "libguile/validate.h"
41 #include "libguile/stacks.h"
42 #include "libguile/private-options.h"
45 static SCM scm_sys_stacks
;
50 * The stack is represented as a struct that holds a frame. The frame itself is
51 * linked to the next frame, or #f.
65 /* Count number of debug info frames on a stack, beginning with FRAME.
68 stack_depth (enum scm_vm_frame_kind kind
, const struct scm_frame
*frame
)
72 memcpy (&tmp
, frame
, sizeof tmp
);
73 while (scm_c_frame_previous (kind
, &tmp
))
78 /* Narrow STACK by cutting away stackframes (mutatingly).
80 * Inner frames (most recent) are cut by advancing the frames pointer.
81 * Outer frames are cut by decreasing the recorded length.
83 * Cut maximally INNER inner frames and OUTER outer frames using
84 * the keys INNER_KEY and OUTER_KEY.
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
91 * If INNER_KEY is #t a different scheme is used for inner frames:
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
100 find_prompt (SCM key
)
102 scm_t_ptrdiff fp_offset
;
104 if (!scm_dynstack_find_prompt (&SCM_I_CURRENT_THREAD
->dynstack
, key
,
105 NULL
, &fp_offset
, NULL
, NULL
, NULL
))
106 scm_misc_error ("make-stack", "Prompt tag not found while narrowing stack",
113 narrow_stack (long len
, enum scm_vm_frame_kind kind
, struct scm_frame
*frame
,
114 SCM inner_cut
, SCM outer_cut
)
116 /* Resolve procedure cuts to address ranges, if possible. If the
117 debug information has been stripped, this might not be
119 if (scm_is_true (scm_program_p (inner_cut
)))
121 SCM addr_range
= scm_program_address_range (inner_cut
);
122 if (scm_is_pair (addr_range
))
123 inner_cut
= addr_range
;
125 if (scm_is_true (scm_program_p (outer_cut
)))
127 SCM addr_range
= scm_program_address_range (outer_cut
);
128 if (scm_is_pair (addr_range
))
129 outer_cut
= addr_range
;
132 /* Cut inner part. */
133 if (scm_is_true (scm_procedure_p (inner_cut
)))
135 /* Cut until the given procedure is seen. */
138 SCM proc
= scm_c_frame_closure (kind
, frame
);
140 scm_c_frame_previous (kind
, frame
);
141 if (scm_is_eq (proc
, inner_cut
))
145 else if (scm_is_pair (inner_cut
)
146 && scm_is_integer (scm_car (inner_cut
))
147 && scm_is_integer (scm_cdr (inner_cut
)))
149 /* Cut until an IP within the given range is found. */
150 scm_t_uintptr low_pc
, high_pc
, pc
;
152 low_pc
= scm_to_uintptr_t (scm_car (inner_cut
));
153 high_pc
= scm_to_uintptr_t (scm_cdr (inner_cut
));
157 pc
= (scm_t_uintptr
) frame
->ip
;
159 scm_c_frame_previous (kind
, frame
);
160 if (low_pc
<= pc
&& pc
< high_pc
)
164 else if (scm_is_integer (inner_cut
))
166 /* Cut specified number of frames. */
167 long inner
= scm_to_int (inner_cut
);
169 for (; inner
&& len
; --inner
)
172 scm_c_frame_previous (kind
, frame
);
177 /* Cut until the given prompt tag is seen. */
178 scm_t_ptrdiff fp_offset
= find_prompt (inner_cut
);
179 for (; len
; len
--, scm_c_frame_previous (kind
, frame
))
180 if (fp_offset
== frame
->fp_offset
)
184 /* Cut outer part. */
185 if (scm_is_true (scm_procedure_p (outer_cut
)))
188 struct scm_frame tmp
;
190 memcpy (&tmp
, frame
, sizeof tmp
);
192 /* Cut until the given procedure is seen. */
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
))
199 else if (scm_is_pair (outer_cut
)
200 && scm_is_integer (scm_car (outer_cut
))
201 && scm_is_integer (scm_cdr (outer_cut
)))
203 /* Cut until an IP within the given range is found. */
204 scm_t_uintptr low_pc
, high_pc
, pc
;
206 struct scm_frame tmp
;
208 low_pc
= scm_to_uintptr_t (scm_car (outer_cut
));
209 high_pc
= scm_to_uintptr_t (scm_cdr (outer_cut
));
211 memcpy (&tmp
, frame
, sizeof tmp
);
213 /* Cut until the given procedure is seen. */
214 for (new_len
= i
= 0; i
< len
; i
++, scm_c_frame_previous (kind
, &tmp
))
216 pc
= (scm_t_uintptr
) tmp
.ip
;
217 if (low_pc
<= pc
&& pc
< high_pc
)
223 else if (scm_is_integer (outer_cut
))
225 /* Cut specified number of frames. */
226 long outer
= scm_to_int (outer_cut
);
235 /* Cut until the given prompt tag is seen. */
237 struct scm_frame tmp
;
238 scm_t_ptrdiff fp_offset
= find_prompt (outer_cut
);
240 memcpy (&tmp
, frame
, sizeof tmp
);
242 for (i
= 0; i
< len
; i
++, scm_c_frame_previous (kind
, &tmp
))
243 if (tmp
.fp_offset
== fp_offset
)
262 SCM_DEFINE (scm_stack_p
, "stack?", 1, 0, 0,
264 "Return @code{#t} if @var{obj} is a calling stack.")
265 #define FUNC_NAME s_scm_stack_p
267 return scm_from_bool(SCM_STACKP (obj
));
271 SCM_DEFINE (scm_make_stack
, "make-stack", 1, 0, 1,
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"
276 "a continuation or a frame object).\n"
278 "@var{args} should be a list containing any combination of\n"
279 "integer, procedure, address range, prompt tag and @code{#t}\n"
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"
286 "@var{outer_cut_2} @dots{})}.\n"
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"
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"
308 "If the @var{outer_cut_i} of the last pair is missing, it is\n"
310 #define FUNC_NAME s_scm_make_stack
313 SCM inner_cut
, outer_cut
;
314 enum scm_vm_frame_kind kind
;
315 struct scm_frame frame
;
317 /* Extract a pointer to the innermost frame of whatever object
318 scm_make_stack was given. */
319 if (scm_is_eq (obj
, SCM_BOOL_T
))
322 struct scm_vm_cont
*c
;
324 cont
= scm_i_capture_current_stack ();
325 c
= SCM_VM_CONT_DATA (cont
);
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
;
333 else if (SCM_VM_FRAME_P (obj
))
335 kind
= SCM_VM_FRAME_KIND (obj
);
336 memcpy (&frame
, SCM_VM_FRAME_DATA (obj
), sizeof frame
);
338 else if (SCM_CONTINUATIONP (obj
))
339 /* FIXME: Narrowing to prompt tags should narrow with respect to the prompts
340 that were in place when the continuation was captured. */
342 kind
= SCM_VM_FRAME_KIND_CONT
;
343 if (!scm_i_continuation_to_frame (obj
, &frame
))
346 else if (SCM_PROGRAM_P (obj
) && SCM_PROGRAM_IS_PARTIAL_CONTINUATION (obj
))
348 kind
= SCM_VM_FRAME_KIND_CONT
;
349 if (!scm_i_vm_cont_to_frame (SCM_PROGRAM_FREE_VARIABLE_REF (obj
, 0),
355 SCM_WRONG_TYPE_ARG (SCM_ARG1
, obj
);
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
))
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). */
369 n
= stack_depth (kind
, &frame
);
371 /* Narrow the stack according to the arguments given to scm_make_stack. */
372 SCM_VALIDATE_REST_ARGUMENT (args
);
373 while (n
> 0 && !scm_is_null (args
))
375 inner_cut
= SCM_CAR (args
);
376 args
= SCM_CDR (args
);
377 if (scm_is_null (args
))
379 outer_cut
= SCM_INUM0
;
383 outer_cut
= SCM_CAR (args
);
384 args
= SCM_CDR (args
);
387 n
= narrow_stack (n
, kind
, &frame
, inner_cut
, outer_cut
);
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
));
404 SCM_DEFINE (scm_stack_id
, "stack-id", 1, 0, 0,
406 "Return the identifier given to @var{stack} by @code{start-stack}.")
407 #define FUNC_NAME s_scm_stack_id
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
))
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
;
418 else if (SCM_CONTINUATIONP (stack
))
419 /* FIXME: implement me */
421 else if (SCM_PROGRAM_P (stack
) && SCM_PROGRAM_IS_PARTIAL_CONTINUATION (stack
))
422 /* FIXME: implement me */
426 SCM_WRONG_TYPE_ARG (SCM_ARG1
, stack
);
432 SCM_DEFINE (scm_stack_ref
, "stack-ref", 2, 0, 0,
433 (SCM stack
, SCM index
),
434 "Return the @var{index}'th frame from @var{stack}.")
435 #define FUNC_NAME s_scm_stack_ref
437 unsigned long int c_index
;
440 SCM_VALIDATE_STACK (1, stack
);
441 c_index
= scm_to_unsigned_integer (index
, 0, SCM_STACK_LENGTH(stack
)-1);
442 frame
= SCM_STACK_FRAME (stack
);
444 frame
= scm_frame_previous (frame
);
449 SCM_DEFINE (scm_stack_length
, "stack-length", 1, 0, 0,
451 "Return the length of @var{stack}.")
452 #define FUNC_NAME s_scm_stack_length
454 SCM_VALIDATE_STACK (1, stack
);
455 return scm_from_long (SCM_STACK_LENGTH (stack
));
464 scm_sys_stacks
= scm_make_fluid ();
465 scm_c_define ("%stacks", scm_sys_stacks
);
467 scm_stack_type
= scm_make_vtable (scm_from_locale_string (SCM_STACK_LAYOUT
),
469 scm_set_struct_vtable_name_x (scm_stack_type
,
470 scm_from_latin1_symbol ("stack"));
471 #include "libguile/stacks.x"