1130803Smarcel/* Code dealing with dummy stack frames, for GDB, the GNU debugger.
2130803Smarcel
3130803Smarcel   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4130803Smarcel   1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software
5130803Smarcel   Foundation, Inc.
6130803Smarcel
7130803Smarcel   This file is part of GDB.
8130803Smarcel
9130803Smarcel   This program is free software; you can redistribute it and/or modify
10130803Smarcel   it under the terms of the GNU General Public License as published by
11130803Smarcel   the Free Software Foundation; either version 2 of the License, or
12130803Smarcel   (at your option) any later version.
13130803Smarcel
14130803Smarcel   This program is distributed in the hope that it will be useful,
15130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130803Smarcel   GNU General Public License for more details.
18130803Smarcel
19130803Smarcel   You should have received a copy of the GNU General Public License
20130803Smarcel   along with this program; if not, write to the Free Software
21130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
22130803Smarcel   Boston, MA 02111-1307, USA.  */
23130803Smarcel
24130803Smarcel
25130803Smarcel#include "defs.h"
26130803Smarcel#include "dummy-frame.h"
27130803Smarcel#include "regcache.h"
28130803Smarcel#include "frame.h"
29130803Smarcel#include "inferior.h"
30130803Smarcel#include "gdb_assert.h"
31130803Smarcel#include "frame-unwind.h"
32130803Smarcel#include "command.h"
33130803Smarcel#include "gdbcmd.h"
34130803Smarcel
35130803Smarcelstatic void dummy_frame_this_id (struct frame_info *next_frame,
36130803Smarcel				 void **this_prologue_cache,
37130803Smarcel				 struct frame_id *this_id);
38130803Smarcel
39130803Smarcel/* Dummy frame.  This saves the processor state just prior to setting
40130803Smarcel   up the inferior function call.  Older targets save the registers
41130803Smarcel   on the target stack (but that really slows down function calls).  */
42130803Smarcel
43130803Smarcelstruct dummy_frame
44130803Smarcel{
45130803Smarcel  struct dummy_frame *next;
46130803Smarcel
47130803Smarcel  /* These values belong to the caller (the previous frame, the frame
48130803Smarcel     that this unwinds back to).  */
49130803Smarcel  CORE_ADDR pc;
50130803Smarcel  CORE_ADDR fp;
51130803Smarcel  CORE_ADDR sp;
52130803Smarcel  CORE_ADDR top;
53130803Smarcel  struct frame_id id;
54130803Smarcel  struct regcache *regcache;
55130803Smarcel
56130803Smarcel  /* Address range of the call dummy code.  Look for PC in the range
57130803Smarcel     [LO..HI) (after allowing for DECR_PC_AFTER_BREAK).  */
58130803Smarcel  CORE_ADDR call_lo;
59130803Smarcel  CORE_ADDR call_hi;
60130803Smarcel};
61130803Smarcel
62130803Smarcelstatic struct dummy_frame *dummy_frame_stack = NULL;
63130803Smarcel
64130803Smarcel/* Function: find_dummy_frame(pc, fp, sp)
65130803Smarcel
66130803Smarcel   Search the stack of dummy frames for one matching the given PC and
67130803Smarcel   FP/SP.  Unlike pc_in_dummy_frame(), this function doesn't need to
68130803Smarcel   adjust for DECR_PC_AFTER_BREAK.  This is because it is only legal
69130803Smarcel   to call this function after the PC has been adjusted.  */
70130803Smarcel
71130803Smarcelstatic struct dummy_frame *
72130803Smarcelfind_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
73130803Smarcel{
74130803Smarcel  struct dummy_frame *dummyframe;
75130803Smarcel
76130803Smarcel  for (dummyframe = dummy_frame_stack; dummyframe != NULL;
77130803Smarcel       dummyframe = dummyframe->next)
78130803Smarcel    {
79130803Smarcel      /* Does the PC fall within the dummy frame's breakpoint
80130803Smarcel         instruction.  If not, discard this one.  */
81130803Smarcel      if (!(pc >= dummyframe->call_lo && pc < dummyframe->call_hi))
82130803Smarcel	continue;
83130803Smarcel      /* Does the FP match?  */
84130803Smarcel      if (dummyframe->top != 0)
85130803Smarcel	{
86130803Smarcel	  /* If the target architecture explicitly saved the
87130803Smarcel	     top-of-stack before the inferior function call, assume
88130803Smarcel	     that that same architecture will always pass in an FP
89130803Smarcel	     (frame base) value that eactly matches that saved TOS.
90130803Smarcel	     Don't check the saved SP and SP as they can lead to false
91130803Smarcel	     hits.  */
92130803Smarcel	  if (fp != dummyframe->top)
93130803Smarcel	    continue;
94130803Smarcel	}
95130803Smarcel      else
96130803Smarcel	{
97130803Smarcel	  /* An older target that hasn't explicitly or implicitly
98130803Smarcel             saved the dummy frame's top-of-stack.  Try matching the
99130803Smarcel             FP against the saved SP and FP.  NOTE: If you're trying
100130803Smarcel             to fix a problem with GDB not correctly finding a dummy
101130803Smarcel             frame, check the comments that go with FRAME_ALIGN() and
102130803Smarcel             UNWIND_DUMMY_ID().  */
103130803Smarcel	  if (fp != dummyframe->fp && fp != dummyframe->sp)
104130803Smarcel	    continue;
105130803Smarcel	}
106130803Smarcel      /* The FP matches this dummy frame.  */
107130803Smarcel      return dummyframe;
108130803Smarcel    }
109130803Smarcel
110130803Smarcel  return NULL;
111130803Smarcel}
112130803Smarcel
113130803Smarcelstruct regcache *
114130803Smarceldeprecated_find_dummy_frame_regcache (CORE_ADDR pc, CORE_ADDR fp)
115130803Smarcel{
116130803Smarcel  struct dummy_frame *dummy = find_dummy_frame (pc, fp);
117130803Smarcel  if (dummy != NULL)
118130803Smarcel    return dummy->regcache;
119130803Smarcel  else
120130803Smarcel    return NULL;
121130803Smarcel}
122130803Smarcel
123130803Smarcelchar *
124130803Smarceldeprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
125130803Smarcel{
126130803Smarcel  struct regcache *regcache = deprecated_find_dummy_frame_regcache (pc, fp);
127130803Smarcel  if (regcache == NULL)
128130803Smarcel    return NULL;
129130803Smarcel  return deprecated_grub_regcache_for_registers (regcache);
130130803Smarcel}
131130803Smarcel
132130803Smarcel/* Function: pc_in_call_dummy (pc, sp, fp)
133130803Smarcel
134130803Smarcel   Return true if the PC falls in a dummy frame created by gdb for an
135130803Smarcel   inferior call.  The code below which allows DECR_PC_AFTER_BREAK is
136130803Smarcel   for infrun.c, which may give the function a PC without that
137130803Smarcel   subtracted out.  */
138130803Smarcel
139130803Smarcelint
140130803Smarcelgeneric_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR fp)
141130803Smarcel{
142130803Smarcel  return pc_in_dummy_frame (pc);
143130803Smarcel}
144130803Smarcel
145130803Smarcel/* Return non-zero if the PC falls in a dummy frame.
146130803Smarcel
147130803Smarcel   The code below which allows DECR_PC_AFTER_BREAK is for infrun.c,
148130803Smarcel   which may give the function a PC without that subtracted out.
149130803Smarcel
150130803Smarcel   FIXME: cagney/2002-11-23: This is silly.  Surely "infrun.c" can
151130803Smarcel   figure out what the real PC (as in the resume address) is BEFORE
152130803Smarcel   calling this function (Oh, and I'm not even sure that this function
153130803Smarcel   is called with an decremented PC, the call to pc_in_call_dummy() in
154130803Smarcel   that file is conditional on
155130803Smarcel   !DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET_P yet generic dummy
156130803Smarcel   targets set DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET. True?).  */
157130803Smarcel
158130803Smarcelint
159130803Smarcelpc_in_dummy_frame (CORE_ADDR pc)
160130803Smarcel{
161130803Smarcel  struct dummy_frame *dummyframe;
162130803Smarcel  for (dummyframe = dummy_frame_stack;
163130803Smarcel       dummyframe != NULL;
164130803Smarcel       dummyframe = dummyframe->next)
165130803Smarcel    {
166130803Smarcel      if ((pc >= dummyframe->call_lo)
167130803Smarcel	  && (pc < dummyframe->call_hi + DECR_PC_AFTER_BREAK))
168130803Smarcel	return 1;
169130803Smarcel    }
170130803Smarcel  return 0;
171130803Smarcel}
172130803Smarcel
173130803Smarcel/* Function: read_register_dummy
174130803Smarcel   Find a saved register from before GDB calls a function in the inferior */
175130803Smarcel
176130803SmarcelCORE_ADDR
177130803Smarceldeprecated_read_register_dummy (CORE_ADDR pc, CORE_ADDR fp, int regno)
178130803Smarcel{
179130803Smarcel  struct regcache *dummy_regs = deprecated_find_dummy_frame_regcache (pc, fp);
180130803Smarcel
181130803Smarcel  if (dummy_regs)
182130803Smarcel    {
183130803Smarcel      /* NOTE: cagney/2002-08-12: Replaced a call to
184130803Smarcel	 regcache_raw_read_as_address() with a call to
185130803Smarcel	 regcache_cooked_read_unsigned().  The old, ...as_address
186130803Smarcel	 function was eventually calling extract_unsigned_integer (nee
187130803Smarcel	 extract_address) to unpack the registers value.  The below is
188130803Smarcel	 doing an unsigned extract so that it is functionally
189130803Smarcel	 equivalent.  The read needs to be cooked as, otherwise, it
190130803Smarcel	 will never correctly return the value of a register in the
191130803Smarcel	 [NUM_REGS .. NUM_REGS+NUM_PSEUDO_REGS) range.  */
192130803Smarcel      ULONGEST val;
193130803Smarcel      regcache_cooked_read_unsigned (dummy_regs, regno, &val);
194130803Smarcel      return val;
195130803Smarcel    }
196130803Smarcel  else
197130803Smarcel    return 0;
198130803Smarcel}
199130803Smarcel
200130803Smarcel/* Save all the registers on the dummy frame stack.  Most ports save the
201130803Smarcel   registers on the target stack.  This results in lots of unnecessary memory
202130803Smarcel   references, which are slow when debugging via a serial line.  Instead, we
203130803Smarcel   save all the registers internally, and never write them to the stack.  The
204130803Smarcel   registers get restored when the called function returns to the entry point,
205130803Smarcel   where a breakpoint is laying in wait.  */
206130803Smarcel
207130803Smarcelvoid
208130803Smarcelgeneric_push_dummy_frame (void)
209130803Smarcel{
210130803Smarcel  struct dummy_frame *dummy_frame;
211130803Smarcel  CORE_ADDR fp = get_frame_base (get_current_frame ());
212130803Smarcel
213130803Smarcel  /* check to see if there are stale dummy frames,
214130803Smarcel     perhaps left over from when a longjump took us out of a
215130803Smarcel     function that was called by the debugger */
216130803Smarcel
217130803Smarcel  dummy_frame = dummy_frame_stack;
218130803Smarcel  while (dummy_frame)
219130803Smarcel    if (INNER_THAN (dummy_frame->fp, fp))	/* stale -- destroy! */
220130803Smarcel      {
221130803Smarcel	dummy_frame_stack = dummy_frame->next;
222130803Smarcel	regcache_xfree (dummy_frame->regcache);
223130803Smarcel	xfree (dummy_frame);
224130803Smarcel	dummy_frame = dummy_frame_stack;
225130803Smarcel      }
226130803Smarcel    else
227130803Smarcel      dummy_frame = dummy_frame->next;
228130803Smarcel
229130803Smarcel  dummy_frame = xmalloc (sizeof (struct dummy_frame));
230130803Smarcel  dummy_frame->regcache = regcache_xmalloc (current_gdbarch);
231130803Smarcel
232130803Smarcel  dummy_frame->pc = read_pc ();
233130803Smarcel  dummy_frame->sp = read_sp ();
234130803Smarcel  dummy_frame->top = 0;
235130803Smarcel  dummy_frame->fp = fp;
236130803Smarcel  dummy_frame->id = get_frame_id (get_current_frame ());
237130803Smarcel  regcache_cpy (dummy_frame->regcache, current_regcache);
238130803Smarcel  dummy_frame->next = dummy_frame_stack;
239130803Smarcel  dummy_frame_stack = dummy_frame;
240130803Smarcel}
241130803Smarcel
242130803Smarcelvoid
243130803Smarcelgeneric_save_dummy_frame_tos (CORE_ADDR sp)
244130803Smarcel{
245130803Smarcel  dummy_frame_stack->top = sp;
246130803Smarcel}
247130803Smarcel
248130803Smarcel/* Record the upper/lower bounds on the address of the call dummy.  */
249130803Smarcel
250130803Smarcelvoid
251130803Smarcelgeneric_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi)
252130803Smarcel{
253130803Smarcel  dummy_frame_stack->call_lo = lo;
254130803Smarcel  dummy_frame_stack->call_hi = hi;
255130803Smarcel}
256130803Smarcel
257130803Smarcel/* Restore the machine state from either the saved dummy stack or a
258130803Smarcel   real stack frame. */
259130803Smarcel
260130803Smarcelvoid
261130803Smarcelgeneric_pop_current_frame (void (*popper) (struct frame_info * frame))
262130803Smarcel{
263130803Smarcel  struct frame_info *frame = get_current_frame ();
264130803Smarcel  if (get_frame_type (frame) == DUMMY_FRAME)
265130803Smarcel    /* NOTE: cagney/2002-22-23: Does this ever occure?  Surely a dummy
266130803Smarcel       frame will have already been poped by the "infrun.c" code.  */
267130803Smarcel    generic_pop_dummy_frame ();
268130803Smarcel  else
269130803Smarcel    (*popper) (frame);
270130803Smarcel}
271130803Smarcel
272130803Smarcel/* Discard the innermost dummy frame from the dummy frame stack
273130803Smarcel   (passed in as a parameter).  */
274130803Smarcel
275130803Smarcelstatic void
276130803Smarceldiscard_innermost_dummy (struct dummy_frame **stack)
277130803Smarcel{
278130803Smarcel  struct dummy_frame *tbd = (*stack);
279130803Smarcel  (*stack) = (*stack)->next;
280130803Smarcel  regcache_xfree (tbd->regcache);
281130803Smarcel  xfree (tbd);
282130803Smarcel}
283130803Smarcel
284130803Smarcelvoid
285130803Smarcelgeneric_pop_dummy_frame (void)
286130803Smarcel{
287130803Smarcel  struct dummy_frame *dummy_frame = dummy_frame_stack;
288130803Smarcel
289130803Smarcel  /* FIXME: what if the first frame isn't the right one, eg..
290130803Smarcel     because one call-by-hand function has done a longjmp into another one? */
291130803Smarcel
292130803Smarcel  if (!dummy_frame)
293130803Smarcel    error ("Can't pop dummy frame!");
294130803Smarcel  regcache_cpy (current_regcache, dummy_frame->regcache);
295130803Smarcel  flush_cached_frames ();
296130803Smarcel
297130803Smarcel  discard_innermost_dummy (&dummy_frame_stack);
298130803Smarcel}
299130803Smarcel
300130803Smarcel/* Given a call-dummy dummy-frame, return the registers.  Here the
301130803Smarcel   register value is taken from the local copy of the register buffer.  */
302130803Smarcel
303130803Smarcelstatic void
304130803Smarceldummy_frame_prev_register (struct frame_info *next_frame,
305130803Smarcel			   void **this_prologue_cache,
306130803Smarcel			   int regnum, int *optimized,
307130803Smarcel			   enum lval_type *lvalp, CORE_ADDR *addrp,
308130803Smarcel			   int *realnum, void *bufferp)
309130803Smarcel{
310130803Smarcel  struct dummy_frame *dummy;
311130803Smarcel  struct frame_id id;
312130803Smarcel
313130803Smarcel  /* Call the ID method which, if at all possible, will set the
314130803Smarcel     prologue cache.  */
315130803Smarcel  dummy_frame_this_id (next_frame, this_prologue_cache, &id);
316130803Smarcel  dummy = (*this_prologue_cache);
317130803Smarcel  gdb_assert (dummy != NULL);
318130803Smarcel
319130803Smarcel  /* Describe the register's location.  Generic dummy frames always
320130803Smarcel     have the register value in an ``expression''.  */
321130803Smarcel  *optimized = 0;
322130803Smarcel  *lvalp = not_lval;
323130803Smarcel  *addrp = 0;
324130803Smarcel  *realnum = -1;
325130803Smarcel
326130803Smarcel  /* If needed, find and return the value of the register.  */
327130803Smarcel  if (bufferp != NULL)
328130803Smarcel    {
329130803Smarcel      /* Return the actual value.  */
330130803Smarcel      /* Use the regcache_cooked_read() method so that it, on the fly,
331130803Smarcel         constructs either a raw or pseudo register from the raw
332130803Smarcel         register cache.  */
333130803Smarcel      regcache_cooked_read (dummy->regcache, regnum, bufferp);
334130803Smarcel    }
335130803Smarcel}
336130803Smarcel
337130803Smarcel/* Assuming that THIS frame is a dummy (remember, the NEXT and not
338130803Smarcel   THIS frame is passed in), return the ID of THIS frame.  That ID is
339130803Smarcel   determined by examining the NEXT frame's unwound registers using
340130803Smarcel   the method unwind_dummy_id().  As a side effect, THIS dummy frame's
341130803Smarcel   dummy cache is located and and saved in THIS_PROLOGUE_CACHE.  */
342130803Smarcel
343130803Smarcelstatic void
344130803Smarceldummy_frame_this_id (struct frame_info *next_frame,
345130803Smarcel		     void **this_prologue_cache,
346130803Smarcel		     struct frame_id *this_id)
347130803Smarcel{
348130803Smarcel  struct dummy_frame *dummy = (*this_prologue_cache);
349130803Smarcel  if (dummy != NULL)
350130803Smarcel    {
351130803Smarcel      (*this_id) = dummy->id;
352130803Smarcel      return;
353130803Smarcel    }
354130803Smarcel  /* When unwinding a normal frame, the stack structure is determined
355130803Smarcel     by analyzing the frame's function's code (be it using brute force
356130803Smarcel     prologue analysis, or the dwarf2 CFI).  In the case of a dummy
357130803Smarcel     frame, that simply isn't possible.  The The PC is either the
358130803Smarcel     program entry point, or some random address on the stack.  Trying
359130803Smarcel     to use that PC to apply standard frame ID unwind techniques is
360130803Smarcel     just asking for trouble.  */
361130803Smarcel  if (gdbarch_unwind_dummy_id_p (current_gdbarch))
362130803Smarcel    {
363130803Smarcel      /* Use an architecture specific method to extract the prev's
364130803Smarcel	 dummy ID from the next frame.  Note that this method uses
365130803Smarcel	 frame_register_unwind to obtain the register values needed to
366130803Smarcel	 determine the dummy frame's ID.  */
367130803Smarcel      (*this_id) = gdbarch_unwind_dummy_id (current_gdbarch, next_frame);
368130803Smarcel    }
369130803Smarcel  else if (frame_relative_level (next_frame) < 0)
370130803Smarcel    {
371130803Smarcel      /* We're unwinding a sentinel frame, the PC of which is pointing
372130803Smarcel	 at a stack dummy.  Fake up the dummy frame's ID using the
373130803Smarcel	 same sequence as is found a traditional unwinder.  Once all
374130803Smarcel	 architectures supply the unwind_dummy_id method, this code
375130803Smarcel	 can go away.  */
376130803Smarcel      (*this_id) = frame_id_build (deprecated_read_fp (), read_pc ());
377130803Smarcel    }
378130803Smarcel  else if (legacy_frame_p (current_gdbarch)
379130803Smarcel	   && get_prev_frame (next_frame))
380130803Smarcel    {
381130803Smarcel      /* Things are looking seriously grim!  Assume that the legacy
382130803Smarcel         get_prev_frame code has already created THIS frame and linked
383130803Smarcel         it in to the frame chain (a pretty bold assumption), extract
384130803Smarcel         the ID from THIS base / pc.  */
385130803Smarcel      (*this_id) = frame_id_build (get_frame_base (get_prev_frame (next_frame)),
386130803Smarcel				   get_frame_pc (get_prev_frame (next_frame)));
387130803Smarcel    }
388130803Smarcel  else
389130803Smarcel    {
390130803Smarcel      /* Ouch!  We're not trying to find the innermost frame's ID yet
391130803Smarcel	 we're trying to unwind to a dummy.  The architecture must
392130803Smarcel	 provide the unwind_dummy_id() method.  Abandon the unwind
393130803Smarcel	 process but only after first warning the user.  */
394130803Smarcel      internal_warning (__FILE__, __LINE__,
395130803Smarcel			"Missing unwind_dummy_id architecture method");
396130803Smarcel      (*this_id) = null_frame_id;
397130803Smarcel      return;
398130803Smarcel    }
399130803Smarcel  (*this_prologue_cache) = find_dummy_frame ((*this_id).code_addr,
400130803Smarcel					     (*this_id).stack_addr);
401130803Smarcel}
402130803Smarcel
403130803Smarcelstatic struct frame_unwind dummy_frame_unwind =
404130803Smarcel{
405130803Smarcel  DUMMY_FRAME,
406130803Smarcel  dummy_frame_this_id,
407130803Smarcel  dummy_frame_prev_register
408130803Smarcel};
409130803Smarcel
410130803Smarcelconst struct frame_unwind *
411130803Smarceldummy_frame_sniffer (struct frame_info *next_frame)
412130803Smarcel{
413130803Smarcel  CORE_ADDR pc = frame_pc_unwind (next_frame);
414130803Smarcel  if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
415130803Smarcel      ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
416130803Smarcel      : pc_in_dummy_frame (pc))
417130803Smarcel    return &dummy_frame_unwind;
418130803Smarcel  else
419130803Smarcel    return NULL;
420130803Smarcel}
421130803Smarcel
422130803Smarcelstatic void
423130803Smarcelfprint_dummy_frames (struct ui_file *file)
424130803Smarcel{
425130803Smarcel  struct dummy_frame *s;
426130803Smarcel  for (s = dummy_frame_stack; s != NULL; s = s->next)
427130803Smarcel    {
428130803Smarcel      gdb_print_host_address (s, file);
429130803Smarcel      fprintf_unfiltered (file, ":");
430130803Smarcel      fprintf_unfiltered (file, " pc=0x%s", paddr (s->pc));
431130803Smarcel      fprintf_unfiltered (file, " fp=0x%s", paddr (s->fp));
432130803Smarcel      fprintf_unfiltered (file, " sp=0x%s", paddr (s->sp));
433130803Smarcel      fprintf_unfiltered (file, " top=0x%s", paddr (s->top));
434130803Smarcel      fprintf_unfiltered (file, " id=");
435130803Smarcel      fprint_frame_id (file, s->id);
436130803Smarcel      fprintf_unfiltered (file, " call_lo=0x%s", paddr (s->call_lo));
437130803Smarcel      fprintf_unfiltered (file, " call_hi=0x%s", paddr (s->call_hi));
438130803Smarcel      fprintf_unfiltered (file, "\n");
439130803Smarcel    }
440130803Smarcel}
441130803Smarcel
442130803Smarcelstatic void
443130803Smarcelmaintenance_print_dummy_frames (char *args, int from_tty)
444130803Smarcel{
445130803Smarcel  if (args == NULL)
446130803Smarcel    fprint_dummy_frames (gdb_stdout);
447130803Smarcel  else
448130803Smarcel    {
449130803Smarcel      struct ui_file *file = gdb_fopen (args, "w");
450130803Smarcel      if (file == NULL)
451130803Smarcel	perror_with_name ("maintenance print dummy-frames");
452130803Smarcel      fprint_dummy_frames (file);
453130803Smarcel      ui_file_delete (file);
454130803Smarcel    }
455130803Smarcel}
456130803Smarcel
457130803Smarcelextern void _initialize_dummy_frame (void);
458130803Smarcel
459130803Smarcelvoid
460130803Smarcel_initialize_dummy_frame (void)
461130803Smarcel{
462130803Smarcel  add_cmd ("dummy-frames", class_maintenance, maintenance_print_dummy_frames,
463130803Smarcel	   "Print the contents of the internal dummy-frame stack.",
464130803Smarcel	   &maintenanceprintlist);
465130803Smarcel
466130803Smarcel}
467