| 1 |
24 |
jeremybenn |
/* Code dealing with dummy stack frames, for GDB, the GNU debugger.
|
| 2 |
|
|
|
| 3 |
|
|
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
|
| 4 |
|
|
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008
|
| 5 |
|
|
Free Software Foundation, Inc.
|
| 6 |
|
|
|
| 7 |
|
|
This file is part of GDB.
|
| 8 |
|
|
|
| 9 |
|
|
This program is free software; you can redistribute it and/or modify
|
| 10 |
|
|
it under the terms of the GNU General Public License as published by
|
| 11 |
|
|
the Free Software Foundation; either version 3 of the License, or
|
| 12 |
|
|
(at your option) any later version.
|
| 13 |
|
|
|
| 14 |
|
|
This program is distributed in the hope that it will be useful,
|
| 15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 17 |
|
|
GNU General Public License for more details.
|
| 18 |
|
|
|
| 19 |
|
|
You should have received a copy of the GNU General Public License
|
| 20 |
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
| 21 |
|
|
|
| 22 |
|
|
|
| 23 |
|
|
#include "defs.h"
|
| 24 |
|
|
#include "dummy-frame.h"
|
| 25 |
|
|
#include "regcache.h"
|
| 26 |
|
|
#include "frame.h"
|
| 27 |
|
|
#include "inferior.h"
|
| 28 |
|
|
#include "gdb_assert.h"
|
| 29 |
|
|
#include "frame-unwind.h"
|
| 30 |
|
|
#include "command.h"
|
| 31 |
|
|
#include "gdbcmd.h"
|
| 32 |
|
|
#include "gdb_string.h"
|
| 33 |
|
|
|
| 34 |
|
|
/* Dummy frame. This saves the processor state just prior to setting
|
| 35 |
|
|
up the inferior function call. Older targets save the registers
|
| 36 |
|
|
on the target stack (but that really slows down function calls). */
|
| 37 |
|
|
|
| 38 |
|
|
struct dummy_frame
|
| 39 |
|
|
{
|
| 40 |
|
|
struct dummy_frame *next;
|
| 41 |
|
|
/* This frame's ID. Must match the value returned by
|
| 42 |
|
|
gdbarch_unwind_dummy_id. */
|
| 43 |
|
|
struct frame_id id;
|
| 44 |
|
|
/* The caller's regcache. */
|
| 45 |
|
|
struct regcache *regcache;
|
| 46 |
|
|
};
|
| 47 |
|
|
|
| 48 |
|
|
static struct dummy_frame *dummy_frame_stack = NULL;
|
| 49 |
|
|
|
| 50 |
|
|
/* Function: deprecated_pc_in_call_dummy (pc)
|
| 51 |
|
|
|
| 52 |
|
|
Return non-zero if the PC falls in a dummy frame created by gdb for
|
| 53 |
|
|
an inferior call. The code below which allows gdbarch_decr_pc_after_break
|
| 54 |
|
|
is for infrun.c, which may give the function a PC without that
|
| 55 |
|
|
subtracted out.
|
| 56 |
|
|
|
| 57 |
|
|
FIXME: cagney/2002-11-23: This is silly. Surely "infrun.c" can
|
| 58 |
|
|
figure out what the real PC (as in the resume address) is BEFORE
|
| 59 |
|
|
calling this function.
|
| 60 |
|
|
|
| 61 |
|
|
NOTE: cagney/2004-08-02: I'm pretty sure that, with the introduction of
|
| 62 |
|
|
infrun.c:adjust_pc_after_break (thanks), this function is now
|
| 63 |
|
|
always called with a correctly adjusted PC!
|
| 64 |
|
|
|
| 65 |
|
|
NOTE: cagney/2004-08-02: Code should not need to call this. */
|
| 66 |
|
|
|
| 67 |
|
|
int
|
| 68 |
|
|
deprecated_pc_in_call_dummy (CORE_ADDR pc)
|
| 69 |
|
|
{
|
| 70 |
|
|
struct dummy_frame *dummyframe;
|
| 71 |
|
|
for (dummyframe = dummy_frame_stack;
|
| 72 |
|
|
dummyframe != NULL;
|
| 73 |
|
|
dummyframe = dummyframe->next)
|
| 74 |
|
|
{
|
| 75 |
|
|
if ((pc >= dummyframe->id.code_addr)
|
| 76 |
|
|
&& (pc <= dummyframe->id.code_addr
|
| 77 |
|
|
+ gdbarch_decr_pc_after_break (current_gdbarch)))
|
| 78 |
|
|
return 1;
|
| 79 |
|
|
}
|
| 80 |
|
|
return 0;
|
| 81 |
|
|
}
|
| 82 |
|
|
|
| 83 |
|
|
/* Push the caller's state, along with the dummy frame info, onto a
|
| 84 |
|
|
dummy-frame stack. */
|
| 85 |
|
|
|
| 86 |
|
|
void
|
| 87 |
|
|
dummy_frame_push (struct regcache *caller_regcache,
|
| 88 |
|
|
const struct frame_id *dummy_id)
|
| 89 |
|
|
{
|
| 90 |
|
|
struct gdbarch *gdbarch = get_regcache_arch (caller_regcache);
|
| 91 |
|
|
struct dummy_frame *dummy_frame;
|
| 92 |
|
|
|
| 93 |
|
|
/* Check to see if there are stale dummy frames, perhaps left over
|
| 94 |
|
|
from when a longjump took us out of a function that was called by
|
| 95 |
|
|
the debugger. */
|
| 96 |
|
|
dummy_frame = dummy_frame_stack;
|
| 97 |
|
|
while (dummy_frame)
|
| 98 |
|
|
/* FIXME: cagney/2004-08-02: Should just test IDs. */
|
| 99 |
|
|
if (frame_id_inner (gdbarch, dummy_frame->id, (*dummy_id)))
|
| 100 |
|
|
/* Stale -- destroy! */
|
| 101 |
|
|
{
|
| 102 |
|
|
dummy_frame_stack = dummy_frame->next;
|
| 103 |
|
|
regcache_xfree (dummy_frame->regcache);
|
| 104 |
|
|
xfree (dummy_frame);
|
| 105 |
|
|
dummy_frame = dummy_frame_stack;
|
| 106 |
|
|
}
|
| 107 |
|
|
else
|
| 108 |
|
|
dummy_frame = dummy_frame->next;
|
| 109 |
|
|
|
| 110 |
|
|
dummy_frame = XZALLOC (struct dummy_frame);
|
| 111 |
|
|
dummy_frame->regcache = caller_regcache;
|
| 112 |
|
|
dummy_frame->id = (*dummy_id);
|
| 113 |
|
|
dummy_frame->next = dummy_frame_stack;
|
| 114 |
|
|
dummy_frame_stack = dummy_frame;
|
| 115 |
|
|
}
|
| 116 |
|
|
|
| 117 |
|
|
/* Return the dummy frame cache, it contains both the ID, and a
|
| 118 |
|
|
pointer to the regcache. */
|
| 119 |
|
|
struct dummy_frame_cache
|
| 120 |
|
|
{
|
| 121 |
|
|
struct frame_id this_id;
|
| 122 |
|
|
struct regcache *prev_regcache;
|
| 123 |
|
|
};
|
| 124 |
|
|
|
| 125 |
|
|
int
|
| 126 |
|
|
dummy_frame_sniffer (const struct frame_unwind *self,
|
| 127 |
|
|
struct frame_info *next_frame,
|
| 128 |
|
|
void **this_prologue_cache)
|
| 129 |
|
|
{
|
| 130 |
|
|
struct dummy_frame *dummyframe;
|
| 131 |
|
|
struct frame_id this_id;
|
| 132 |
|
|
|
| 133 |
|
|
/* When unwinding a normal frame, the stack structure is determined
|
| 134 |
|
|
by analyzing the frame's function's code (be it using brute force
|
| 135 |
|
|
prologue analysis, or the dwarf2 CFI). In the case of a dummy
|
| 136 |
|
|
frame, that simply isn't possible. The PC is either the program
|
| 137 |
|
|
entry point, or some random address on the stack. Trying to use
|
| 138 |
|
|
that PC to apply standard frame ID unwind techniques is just
|
| 139 |
|
|
asking for trouble. */
|
| 140 |
|
|
|
| 141 |
|
|
/* Don't bother unles there is at least one dummy frame. */
|
| 142 |
|
|
if (dummy_frame_stack != NULL)
|
| 143 |
|
|
{
|
| 144 |
|
|
/* Use an architecture specific method to extract the prev's
|
| 145 |
|
|
dummy ID from the next frame. Note that this method uses
|
| 146 |
|
|
frame_register_unwind to obtain the register values needed to
|
| 147 |
|
|
determine the dummy frame's ID. */
|
| 148 |
|
|
this_id = gdbarch_unwind_dummy_id (get_frame_arch (next_frame),
|
| 149 |
|
|
next_frame);
|
| 150 |
|
|
|
| 151 |
|
|
/* Use that ID to find the corresponding cache entry. */
|
| 152 |
|
|
for (dummyframe = dummy_frame_stack;
|
| 153 |
|
|
dummyframe != NULL;
|
| 154 |
|
|
dummyframe = dummyframe->next)
|
| 155 |
|
|
{
|
| 156 |
|
|
if (frame_id_eq (dummyframe->id, this_id))
|
| 157 |
|
|
{
|
| 158 |
|
|
struct dummy_frame_cache *cache;
|
| 159 |
|
|
cache = FRAME_OBSTACK_ZALLOC (struct dummy_frame_cache);
|
| 160 |
|
|
cache->prev_regcache = dummyframe->regcache;
|
| 161 |
|
|
cache->this_id = this_id;
|
| 162 |
|
|
(*this_prologue_cache) = cache;
|
| 163 |
|
|
return 1;
|
| 164 |
|
|
}
|
| 165 |
|
|
}
|
| 166 |
|
|
}
|
| 167 |
|
|
return 0;
|
| 168 |
|
|
}
|
| 169 |
|
|
|
| 170 |
|
|
/* Given a call-dummy dummy-frame, return the registers. Here the
|
| 171 |
|
|
register value is taken from the local copy of the register buffer. */
|
| 172 |
|
|
|
| 173 |
|
|
static void
|
| 174 |
|
|
dummy_frame_prev_register (struct frame_info *next_frame,
|
| 175 |
|
|
void **this_prologue_cache,
|
| 176 |
|
|
int regnum, int *optimized,
|
| 177 |
|
|
enum lval_type *lvalp, CORE_ADDR *addrp,
|
| 178 |
|
|
int *realnum, gdb_byte *bufferp)
|
| 179 |
|
|
{
|
| 180 |
|
|
/* The dummy-frame sniffer always fills in the cache. */
|
| 181 |
|
|
struct dummy_frame_cache *cache = (*this_prologue_cache);
|
| 182 |
|
|
gdb_assert (cache != NULL);
|
| 183 |
|
|
|
| 184 |
|
|
/* Describe the register's location. Generic dummy frames always
|
| 185 |
|
|
have the register value in an ``expression''. */
|
| 186 |
|
|
*optimized = 0;
|
| 187 |
|
|
*lvalp = not_lval;
|
| 188 |
|
|
*addrp = 0;
|
| 189 |
|
|
*realnum = -1;
|
| 190 |
|
|
|
| 191 |
|
|
/* If needed, find and return the value of the register. */
|
| 192 |
|
|
if (bufferp != NULL)
|
| 193 |
|
|
{
|
| 194 |
|
|
/* Return the actual value. */
|
| 195 |
|
|
/* Use the regcache_cooked_read() method so that it, on the fly,
|
| 196 |
|
|
constructs either a raw or pseudo register from the raw
|
| 197 |
|
|
register cache. */
|
| 198 |
|
|
regcache_cooked_read (cache->prev_regcache, regnum, bufferp);
|
| 199 |
|
|
}
|
| 200 |
|
|
}
|
| 201 |
|
|
|
| 202 |
|
|
/* Assuming that THIS frame is a dummy (remember, the NEXT and not
|
| 203 |
|
|
THIS frame is passed in), return the ID of THIS frame. That ID is
|
| 204 |
|
|
determined by examining the NEXT frame's unwound registers using
|
| 205 |
|
|
the method unwind_dummy_id(). As a side effect, THIS dummy frame's
|
| 206 |
|
|
dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */
|
| 207 |
|
|
|
| 208 |
|
|
static void
|
| 209 |
|
|
dummy_frame_this_id (struct frame_info *next_frame,
|
| 210 |
|
|
void **this_prologue_cache,
|
| 211 |
|
|
struct frame_id *this_id)
|
| 212 |
|
|
{
|
| 213 |
|
|
/* The dummy-frame sniffer always fills in the cache. */
|
| 214 |
|
|
struct dummy_frame_cache *cache = (*this_prologue_cache);
|
| 215 |
|
|
gdb_assert (cache != NULL);
|
| 216 |
|
|
(*this_id) = cache->this_id;
|
| 217 |
|
|
}
|
| 218 |
|
|
|
| 219 |
|
|
static const struct frame_unwind dummy_frame_unwinder =
|
| 220 |
|
|
{
|
| 221 |
|
|
DUMMY_FRAME,
|
| 222 |
|
|
dummy_frame_this_id,
|
| 223 |
|
|
dummy_frame_prev_register,
|
| 224 |
|
|
NULL,
|
| 225 |
|
|
dummy_frame_sniffer,
|
| 226 |
|
|
};
|
| 227 |
|
|
|
| 228 |
|
|
const struct frame_unwind *const dummy_frame_unwind = {
|
| 229 |
|
|
&dummy_frame_unwinder
|
| 230 |
|
|
};
|
| 231 |
|
|
|
| 232 |
|
|
static void
|
| 233 |
|
|
fprint_dummy_frames (struct ui_file *file)
|
| 234 |
|
|
{
|
| 235 |
|
|
struct dummy_frame *s;
|
| 236 |
|
|
for (s = dummy_frame_stack; s != NULL; s = s->next)
|
| 237 |
|
|
{
|
| 238 |
|
|
gdb_print_host_address (s, file);
|
| 239 |
|
|
fprintf_unfiltered (file, ":");
|
| 240 |
|
|
fprintf_unfiltered (file, " id=");
|
| 241 |
|
|
fprint_frame_id (file, s->id);
|
| 242 |
|
|
fprintf_unfiltered (file, "\n");
|
| 243 |
|
|
}
|
| 244 |
|
|
}
|
| 245 |
|
|
|
| 246 |
|
|
static void
|
| 247 |
|
|
maintenance_print_dummy_frames (char *args, int from_tty)
|
| 248 |
|
|
{
|
| 249 |
|
|
if (args == NULL)
|
| 250 |
|
|
fprint_dummy_frames (gdb_stdout);
|
| 251 |
|
|
else
|
| 252 |
|
|
{
|
| 253 |
|
|
struct ui_file *file = gdb_fopen (args, "w");
|
| 254 |
|
|
if (file == NULL)
|
| 255 |
|
|
perror_with_name (_("maintenance print dummy-frames"));
|
| 256 |
|
|
fprint_dummy_frames (file);
|
| 257 |
|
|
ui_file_delete (file);
|
| 258 |
|
|
}
|
| 259 |
|
|
}
|
| 260 |
|
|
|
| 261 |
|
|
extern void _initialize_dummy_frame (void);
|
| 262 |
|
|
|
| 263 |
|
|
void
|
| 264 |
|
|
_initialize_dummy_frame (void)
|
| 265 |
|
|
{
|
| 266 |
|
|
add_cmd ("dummy-frames", class_maintenance, maintenance_print_dummy_frames,
|
| 267 |
|
|
_("Print the contents of the internal dummy-frame stack."),
|
| 268 |
|
|
&maintenanceprintlist);
|
| 269 |
|
|
|
| 270 |
|
|
}
|