/* Cache and manage frames for GDB, the GNU debugger.
Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001,
- 2002, 2003, 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GDB.
#include "objfiles.h"
#include "exceptions.h"
#include "gdbthread.h"
+#include "block.h"
+#include "inline-frame.h"
+#include "tracepoint.h"
static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
+static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame);
/* We keep a cache of stack frames, each of which is a "struct
frame_info". The innermost one gets allocated (in
moment leave this as speculation. */
int level;
+ /* The frame's program space. */
+ struct program_space *pspace;
+
+ /* The frame's address space. */
+ struct address_space *aspace;
+
/* The frame's low-level unwinder and corresponding cache. The
low-level unwinder is responsible for unwinding register values
for the previous frame. The low-level unwind methods are
void *prologue_cache;
const struct frame_unwind *unwind;
+ /* Cached copy of the previous frame's architecture. */
+ struct
+ {
+ int p;
+ struct gdbarch *arch;
+ } prev_arch;
+
/* Cached copy of the previous frame's resume address. */
struct {
int p;
enum unwind_stop_reason stop_reason;
};
+/* A frame stash used to speed up frame lookups. */
+
+/* We currently only stash one frame at a time, as this seems to be
+ sufficient for now. */
+static struct frame_info *frame_stash = NULL;
+
+/* Add the following FRAME to the frame stash. */
+
+static void
+frame_stash_add (struct frame_info *frame)
+{
+ frame_stash = frame;
+}
+
+/* Search the frame stash for an entry with the given frame ID.
+ If found, return that frame. Otherwise return NULL. */
+
+static struct frame_info *
+frame_stash_find (struct frame_id id)
+{
+ if (frame_stash && frame_id_eq (frame_stash->this_id.value, id))
+ return frame_stash;
+
+ return NULL;
+}
+
+/* Invalidate the frame stash by removing all entries in it. */
+
+static void
+frame_stash_invalidate (void)
+{
+ frame_stash = NULL;
+}
+
/* Flag to control debugging. */
int frame_debug;
fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr)
{
if (p)
- fprintf_unfiltered (file, "%s=0x%s", name, paddr_nz (addr));
+ fprintf_unfiltered (file, "%s=%s", name, hex_string (addr));
else
fprintf_unfiltered (file, "!%s", name);
}
fprint_field (file, "code", id.code_addr_p, id.code_addr);
fprintf_unfiltered (file, ",");
fprint_field (file, "special", id.special_addr_p, id.special_addr);
+ if (id.inline_depth)
+ fprintf_unfiltered (file, ",inlined=%d", id.inline_depth);
fprintf_unfiltered (file, "}");
}
case DUMMY_FRAME:
fprintf_unfiltered (file, "DUMMY_FRAME");
return;
+ case INLINE_FRAME:
+ fprintf_unfiltered (file, "INLINE_FRAME");
+ return;
+ case SENTINEL_FRAME:
+ fprintf_unfiltered (file, "SENTINEL_FRAME");
+ return;
case SIGTRAMP_FRAME:
fprintf_unfiltered (file, "SIGTRAMP_FRAME");
return;
+ case ARCH_FRAME:
+ fprintf_unfiltered (file, "ARCH_FRAME");
+ return;
default:
fprintf_unfiltered (file, "<unknown type>");
return;
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, "pc=");
if (fi->next != NULL && fi->next->prev_pc.p)
- fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_pc.value));
+ fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_pc.value));
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, "func=");
if (fi->next != NULL && fi->next->prev_func.p)
- fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_func.addr));
+ fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_func.addr));
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, "}");
}
+/* Given FRAME, return the enclosing normal frame for inlined
+ function frames. Otherwise return the original frame. */
+
+static struct frame_info *
+skip_inlined_frames (struct frame_info *frame)
+{
+ while (get_frame_type (frame) == INLINE_FRAME)
+ frame = get_prev_frame (frame);
+
+ return frame;
+}
+
/* Return a frame uniq ID that can be used to, later, re-find the
frame. */
get_frame_id (struct frame_info *fi)
{
if (fi == NULL)
- {
- return null_frame_id;
- }
+ return null_frame_id;
+
if (!fi->this_id.p)
{
if (frame_debug)
if (fi->unwind == NULL)
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
/* Find THIS frame's ID. */
+ /* Default to outermost if no ID is found. */
+ fi->this_id.value = outer_frame_id;
fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
+ gdb_assert (frame_id_p (fi->this_id.value));
fi->this_id.p = 1;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, " }\n");
}
}
+
+ frame_stash_add (fi);
+
return fi->this_id.value;
}
struct frame_id
-frame_unwind_id (struct frame_info *next_frame)
+get_stack_frame_id (struct frame_info *next_frame)
{
- /* Use prev_frame, and not get_prev_frame. The latter will truncate
+ return get_frame_id (skip_inlined_frames (next_frame));
+}
+
+struct frame_id
+frame_unwind_caller_id (struct frame_info *next_frame)
+{
+ struct frame_info *this_frame;
+
+ /* Use get_prev_frame_1, and not get_prev_frame. The latter will truncate
the frame chain, leading to this function unintentionally
returning a null_frame_id (e.g., when a caller requests the frame
ID of "main()"s caller. */
- return get_frame_id (get_prev_frame_1 (next_frame));
+
+ next_frame = skip_inlined_frames (next_frame);
+ this_frame = get_prev_frame_1 (next_frame);
+ if (this_frame)
+ return get_frame_id (skip_inlined_frames (this_frame));
+ else
+ return null_frame_id;
}
const struct frame_id null_frame_id; /* All zeros. */
+const struct frame_id outer_frame_id = { 0, 0, 0, 0, 0, 1, 0 };
struct frame_id
frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
CORE_ADDR special_addr)
{
struct frame_id id = null_frame_id;
+
id.stack_addr = stack_addr;
id.stack_addr_p = 1;
id.code_addr = code_addr;
frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
{
struct frame_id id = null_frame_id;
+
id.stack_addr = stack_addr;
id.stack_addr_p = 1;
id.code_addr = code_addr;
frame_id_build_wild (CORE_ADDR stack_addr)
{
struct frame_id id = null_frame_id;
+
id.stack_addr = stack_addr;
id.stack_addr_p = 1;
return id;
frame_id_p (struct frame_id l)
{
int p;
+
/* The frame is valid iff it has a valid stack address. */
p = l.stack_addr_p;
+ /* outer_frame_id is also valid. */
+ if (!p && memcmp (&l, &outer_frame_id, sizeof (l)) == 0)
+ p = 1;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
return p;
}
+int
+frame_id_inlined_p (struct frame_id l)
+{
+ if (!frame_id_p (l))
+ return 0;
+
+ return (l.inline_depth != 0);
+}
+
int
frame_id_eq (struct frame_id l, struct frame_id r)
{
int eq;
- if (!l.stack_addr_p || !r.stack_addr_p)
+
+ if (!l.stack_addr_p && l.special_addr_p && !r.stack_addr_p && r.special_addr_p)
+ /* The outermost frame marker is equal to itself. This is the
+ dodgy thing about outer_frame_id, since between execution steps
+ we might step into another function - from which we can't
+ unwind either. More thought required to get rid of
+ outer_frame_id. */
+ eq = 1;
+ else if (!l.stack_addr_p || !r.stack_addr_p)
/* Like a NaN, if either ID is invalid, the result is false.
Note that a frame ID is invalid iff it is the null frame ID. */
eq = 0;
else if (l.stack_addr != r.stack_addr)
/* If .stack addresses are different, the frames are different. */
eq = 0;
- else if (!l.code_addr_p || !r.code_addr_p)
- /* An invalid code addr is a wild card, always succeed. */
- eq = 1;
- else if (l.code_addr != r.code_addr)
- /* If .code addresses are different, the frames are different. */
+ else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr)
+ /* An invalid code addr is a wild card. If .code addresses are
+ different, the frames are different. */
eq = 0;
- else if (!l.special_addr_p || !r.special_addr_p)
- /* An invalid special addr is a wild card (or unused), always succeed. */
- eq = 1;
- else if (l.special_addr == r.special_addr)
+ else if (l.special_addr_p && r.special_addr_p
+ && l.special_addr != r.special_addr)
+ /* An invalid special addr is a wild card (or unused). Otherwise
+ if special addresses are different, the frames are different. */
+ eq = 0;
+ else if (l.inline_depth != r.inline_depth)
+ /* If inline depths are different, the frames must be different. */
+ eq = 0;
+ else
/* Frames are equal. */
eq = 1;
- else
- /* No luck. */
- eq = 0;
+
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=");
frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
{
int inner;
+
if (!l.stack_addr_p || !r.stack_addr_p)
/* Like NaN, any operation involving an invalid ID always fails. */
inner = 0;
+ else if (l.inline_depth > r.inline_depth
+ && l.stack_addr == r.stack_addr
+ && l.code_addr_p == r.code_addr_p
+ && l.special_addr_p == r.special_addr_p
+ && l.special_addr == r.special_addr)
+ {
+ /* Same function, different inlined functions. */
+ struct block *lb, *rb;
+
+ gdb_assert (l.code_addr_p && r.code_addr_p);
+
+ lb = block_for_pc (l.code_addr);
+ rb = block_for_pc (r.code_addr);
+
+ if (lb == NULL || rb == NULL)
+ /* Something's gone wrong. */
+ inner = 0;
+ else
+ /* This will return true if LB and RB are the same block, or
+ if the block with the smaller depth lexically encloses the
+ block with the greater depth. */
+ inner = contained_in (lb, rb);
+ }
else
/* Only return non-zero when strictly inner than. Note that, per
comment in "frame.h", there is some fuzz here. Frameless
if (!frame_id_p (id))
return NULL;
+ /* Try using the frame stash first. Finding it there removes the need
+ to perform the search by looping over all frames, which can be very
+ CPU-intensive if the number of frames is very high (the loop is O(n)
+ and get_prev_frame performs a series of checks that are relatively
+ expensive). This optimization is particularly useful when this function
+ is called from another function (such as value_fetch_lazy, case
+ VALUE_LVAL (val) == lval_register) which already loops over all frames,
+ making the overall behavior O(n^2). */
+ frame = frame_stash_find (id);
+ if (frame)
+ return frame;
+
for (frame = get_current_frame (); ; frame = prev_frame)
{
struct frame_id this = get_frame_id (frame);
+
if (frame_id_eq (id, this))
/* An exact match. */
return frame;
return NULL;
}
-CORE_ADDR
-frame_pc_unwind (struct frame_info *this_frame)
+static CORE_ADDR
+frame_unwind_pc (struct frame_info *this_frame)
{
if (!this_frame->prev_pc.p)
{
CORE_ADDR pc;
- if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
+
+ if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame)))
{
/* The right way. The `pure' way. The one true way. This
method depends solely on the register-unwind code to
frame. This is all in stark contrast to the old
FRAME_SAVED_PC which would try to directly handle all the
different ways that a PC could be unwound. */
- pc = gdbarch_unwind_pc (get_frame_arch (this_frame), this_frame);
+ pc = gdbarch_unwind_pc (frame_unwind_arch (this_frame), this_frame);
}
else
internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
this_frame->prev_pc.p = 1;
if (frame_debug)
fprintf_unfiltered (gdb_stdlog,
- "{ frame_pc_unwind (this_frame=%d) -> 0x%s }\n",
+ "{ frame_unwind_caller_pc (this_frame=%d) -> %s }\n",
this_frame->level,
- paddr_nz (this_frame->prev_pc.value));
+ hex_string (this_frame->prev_pc.value));
}
return this_frame->prev_pc.value;
}
+CORE_ADDR
+frame_unwind_caller_pc (struct frame_info *this_frame)
+{
+ return frame_unwind_pc (skip_inlined_frames (this_frame));
+}
+
CORE_ADDR
get_frame_func (struct frame_info *this_frame)
{
next_frame->prev_func.addr = get_pc_function_start (addr_in_block);
if (frame_debug)
fprintf_unfiltered (gdb_stdlog,
- "{ get_frame_func (this_frame=%d) -> 0x%s }\n",
+ "{ get_frame_func (this_frame=%d) -> %s }\n",
this_frame->level,
- paddr_nz (next_frame->prev_func.addr));
+ hex_string (next_frame->prev_func.addr));
}
return next_frame->prev_func.addr;
}
struct regcache *
frame_save_as_regcache (struct frame_info *this_frame)
{
- struct regcache *regcache = regcache_xmalloc (get_frame_arch (this_frame));
+ struct address_space *aspace = get_frame_address_space (this_frame);
+ struct regcache *regcache = regcache_xmalloc (get_frame_arch (this_frame),
+ aspace);
struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
+
regcache_save (regcache, do_frame_register_read, this_frame);
discard_cleanups (cleanups);
return regcache;
*optimizedp = value_optimized_out (value);
*lvalp = VALUE_LVAL (value);
- *addrp = VALUE_ADDRESS (value);
+ *addrp = value_address (value);
*realnump = VALUE_REGNUM (value);
- if (bufferp)
+ if (bufferp && !*optimizedp)
memcpy (bufferp, value_contents_all (value),
TYPE_LENGTH (value_type (value)));
CORE_ADDR addr;
int realnum;
enum lval_type lval;
+
frame_register_unwind (frame, regnum, &optimized, &lval, &addr,
&realnum, buf);
}
struct value *
frame_unwind_register_value (struct frame_info *frame, int regnum)
{
+ struct gdbarch *gdbarch;
struct value *value;
gdb_assert (frame != NULL);
+ gdbarch = frame_unwind_arch (frame);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "\
{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
frame->level, regnum,
- user_reg_map_regnum_to_name
- (get_frame_arch (frame), regnum));
+ user_reg_map_regnum_to_name (gdbarch, regnum));
}
/* Find the unwinder. */
fprintf_unfiltered (gdb_stdlog, " register=%d",
VALUE_REGNUM (value));
else if (VALUE_LVAL (value) == lval_memory)
- fprintf_unfiltered (gdb_stdlog, " address=0x%s",
- paddr_nz (VALUE_ADDRESS (value)));
+ fprintf_unfiltered (gdb_stdlog, " address=%s",
+ paddress (gdbarch,
+ value_address (value)));
else
fprintf_unfiltered (gdb_stdlog, " computed");
fprintf_unfiltered (gdb_stdlog, " bytes=");
fprintf_unfiltered (gdb_stdlog, "[");
- for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
+ for (i = 0; i < register_size (gdbarch, regnum); i++)
fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
fprintf_unfiltered (gdb_stdlog, "]");
}
LONGEST
frame_unwind_register_signed (struct frame_info *frame, int regnum)
{
+ struct gdbarch *gdbarch = frame_unwind_arch (frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int size = register_size (gdbarch, regnum);
gdb_byte buf[MAX_REGISTER_SIZE];
+
frame_unwind_register (frame, regnum, buf);
- return extract_signed_integer (buf, register_size (get_frame_arch (frame),
- regnum));
+ return extract_signed_integer (buf, size, byte_order);
}
LONGEST
ULONGEST
frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
{
+ struct gdbarch *gdbarch = frame_unwind_arch (frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int size = register_size (gdbarch, regnum);
gdb_byte buf[MAX_REGISTER_SIZE];
+
frame_unwind_register (frame, regnum, buf);
- return extract_unsigned_integer (buf, register_size (get_frame_arch (frame),
- regnum));
+ return extract_unsigned_integer (buf, size, byte_order);
}
ULONGEST
int optim;
enum lval_type lval;
CORE_ADDR addr;
+
frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
if (optim)
error (_("Attempt to assign to a value that was optimized out."));
/* FIXME: write_memory doesn't yet take constant buffers.
Arrrg! */
gdb_byte tmp[MAX_REGISTER_SIZE];
+
memcpy (tmp, buf, register_size (gdbarch, regnum));
write_memory (addr, tmp, register_size (gdbarch, regnum));
break;
enum lval_type lval;
CORE_ADDR addr;
int realnum;
+
frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr);
return !optimized;
for (i = regnum; i < numregs; i++)
{
int thissize = register_size (gdbarch, i);
+
if (thissize == 0)
break; /* This register is not available on this architecture. */
maxsize += thissize;
while (len > 0)
{
int curr_len = register_size (gdbarch, regnum) - offset;
+
if (curr_len > len)
curr_len = len;
else
{
gdb_byte buf[MAX_REGISTER_SIZE];
+
if (!frame_register_read (frame, regnum, buf))
return 0;
memcpy (myaddr, buf + offset, curr_len);
while (len > 0)
{
int curr_len = register_size (gdbarch, regnum) - offset;
+
if (curr_len > len)
curr_len = len;
else
{
gdb_byte buf[MAX_REGISTER_SIZE];
+
frame_register_read (frame, regnum, buf);
memcpy (buf + offset, myaddr, curr_len);
put_frame_register (frame, regnum, buf);
/* Create a sentinel frame. */
static struct frame_info *
-create_sentinel_frame (struct regcache *regcache)
+create_sentinel_frame (struct program_space *pspace, struct regcache *regcache)
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+
frame->level = -1;
+ frame->pspace = pspace;
+ frame->aspace = get_regcache_aspace (regcache);
/* Explicitly initialize the sentinel frame's cache. Provide it
with the underlying regcache. In the future additional
information, such as the frame's thread will be added. */
frame_obstack_zalloc (unsigned long size)
{
void *data = obstack_alloc (&frame_cache_obstack, size);
+
memset (data, 0, size);
return data;
}
unwind_to_current_frame (struct ui_out *ui_out, void *args)
{
struct frame_info *frame = get_prev_frame (args);
+
/* A sentinel frame can fail to unwind, e.g., because its PC value
lands in somewhere like start. */
if (frame == NULL)
error (_("No stack."));
if (!target_has_memory)
error (_("No memory."));
- if (is_executing (inferior_ptid))
- error (_("Target is executing."));
+ /* Traceframes are effectively a substitute for the live inferior. */
+ if (get_traceframe_number () < 0)
+ {
+ if (ptid_equal (inferior_ptid, null_ptid))
+ error (_("No selected thread."));
+ if (is_exited (inferior_ptid))
+ error (_("Invalid selected thread."));
+ if (is_executing (inferior_ptid))
+ error (_("Target is executing."));
+ }
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
- create_sentinel_frame (get_current_regcache ());
+ create_sentinel_frame (current_program_space, get_current_regcache ());
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
RETURN_MASK_ERROR) != 0)
{
if (!target_has_registers || !target_has_stack || !target_has_memory)
return 0;
- /* If the current thread is executing, don't try to read from
- it. */
+ /* No current inferior, no frame. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
+ /* Don't try to read from a dead thread. */
+ if (is_exited (inferior_ptid))
+ return 0;
+
+ /* ... or from a spinning thread. */
if (is_executing (inferior_ptid))
return 0;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog,
- "{ create_new_frame (addr=0x%s, pc=0x%s) ",
- paddr_nz (addr), paddr_nz (pc));
+ "{ create_new_frame (addr=%s, pc=%s) ",
+ hex_string (addr), hex_string (pc));
}
fi = FRAME_OBSTACK_ZALLOC (struct frame_info);
- fi->next = create_sentinel_frame (get_current_regcache ());
+ fi->next = create_sentinel_frame (current_program_space, get_current_regcache ());
/* Set/update this frame's cached PC value, found in the next frame.
Do this before looking for this frame's unwinder. A sniffer is
fi->next->prev_pc.value = pc;
fi->next->prev_pc.p = 1;
+ /* We currently assume that frame chain's can't cross spaces. */
+ fi->pspace = fi->next->pspace;
+ fi->aspace = fi->next->aspace;
+
/* Select/initialize both the unwind function and the frame's type
based on the PC. */
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
current_frame = NULL; /* Invalidate cache */
select_frame (NULL);
+ frame_stash_invalidate ();
if (frame_debug)
fprintf_unfiltered (gdb_stdlog, "{ reinit_frame_cache () }\n");
}
static struct frame_info *
get_prev_frame_1 (struct frame_info *this_frame)
{
- struct frame_info *prev_frame;
struct frame_id this_id;
struct gdbarch *gdbarch;
this_frame->prev_p = 1;
this_frame->stop_reason = UNWIND_NO_REASON;
+ /* If we are unwinding from an inline frame, all of the below tests
+ were already performed when we unwound from the next non-inline
+ frame. We must skip them, since we can not get THIS_FRAME's ID
+ until we have unwound all the way down to the previous non-inline
+ frame. */
+ if (get_frame_type (this_frame) == INLINE_FRAME)
+ return get_prev_frame_raw (this_frame);
+
/* Check that this frame's ID was valid. If it wasn't, don't try to
unwind to the prev frame. Be careful to not apply this test to
the sentinel frame. */
this_id = get_frame_id (this_frame);
- if (this_frame->level >= 0 && !frame_id_p (this_id))
+ if (this_frame->level >= 0 && frame_id_eq (this_id, outer_frame_id))
{
if (frame_debug)
{
if (this_frame->level > 0
&& gdbarch_pc_regnum (gdbarch) >= 0
&& get_frame_type (this_frame) == NORMAL_FRAME
- && get_frame_type (this_frame->next) == NORMAL_FRAME)
+ && (get_frame_type (this_frame->next) == NORMAL_FRAME
+ || get_frame_type (this_frame->next) == INLINE_FRAME))
{
int optimized, realnum, nrealnum;
enum lval_type lval, nlval;
}
}
+ return get_prev_frame_raw (this_frame);
+}
+
+/* Construct a new "struct frame_info" and link it previous to
+ this_frame. */
+
+static struct frame_info *
+get_prev_frame_raw (struct frame_info *this_frame)
+{
+ struct frame_info *prev_frame;
+
/* Allocate the new frame but do not wire it in to the frame chain.
Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along
frame->next to pull some fancy tricks (of course such code is, by
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = this_frame->level + 1;
+ /* For now, assume we don't have frame chains crossing address
+ spaces. */
+ prev_frame->pspace = this_frame->pspace;
+ prev_frame->aspace = this_frame->aspace;
+
/* Don't yet compute ->unwind (and hence ->type). It is computed
on-demand in get_frame_type, frame_register_unwind, and
get_frame_id. */
static int
inside_entry_func (struct frame_info *this_frame)
{
- return (get_frame_func (this_frame) == entry_point_address ());
+ CORE_ADDR entry_point;
+
+ if (!entry_point_address_query (&entry_point))
+ return 0;
+
+ return get_frame_func (this_frame) == entry_point;
}
/* Return a structure containing various interesting information about
struct frame_info *
get_prev_frame (struct frame_info *this_frame)
{
- struct frame_info *prev_frame;
-
/* There is always a frame. If this assertion fails, suspect that
something should be calling get_selected_frame() or
get_current_frame(). */
the main function when we created the dummy frame, the dummy frame will
point inside the main function. */
if (this_frame->level >= 0
- && get_frame_type (this_frame) != DUMMY_FRAME
+ && get_frame_type (this_frame) == NORMAL_FRAME
&& !backtrace_past_main
&& inside_main_func (this_frame))
/* Don't unwind past main(). Note, this is done _before_ the
from main returns directly to the caller of main. Since we don't
stop at main, we should at least stop at the entry point of the
application. */
- if (!backtrace_past_entry
- && get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0
+ if (this_frame->level >= 0
+ && get_frame_type (this_frame) == NORMAL_FRAME
+ && !backtrace_past_entry
&& inside_entry_func (this_frame))
{
frame_debug_got_null_frame (this_frame, "inside entry func");
like a SIGSEGV or a dummy frame, and hence that NORMAL frames
will never unwind a zero PC. */
if (this_frame->level > 0
- && get_frame_type (this_frame) == NORMAL_FRAME
+ && (get_frame_type (this_frame) == NORMAL_FRAME
+ || get_frame_type (this_frame) == INLINE_FRAME)
&& get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
&& get_frame_pc (this_frame) == 0)
{
get_frame_pc (struct frame_info *frame)
{
gdb_assert (frame->next != NULL);
- return frame_pc_unwind (frame->next);
+ return frame_unwind_pc (frame->next);
}
/* Return an address that falls within THIS_FRAME's code block. */
We check the type of NEXT_FRAME first, since it is already
known; frame type is determined by the unwinder, and since
we have THIS_FRAME we've already selected an unwinder for
- NEXT_FRAME. */
+ NEXT_FRAME.
+
+ If the next frame is inlined, we need to keep going until we find
+ the real function - for instance, if a signal handler is invoked
+ while in an inlined function, then the code address of the
+ "calling" normal function should not be adjusted either. */
+
+ while (get_frame_type (next_frame) == INLINE_FRAME)
+ next_frame = next_frame->next;
+
if (get_frame_type (next_frame) == NORMAL_FRAME
- && get_frame_type (this_frame) == NORMAL_FRAME)
+ && (get_frame_type (this_frame) == NORMAL_FRAME
+ || get_frame_type (this_frame) == INLINE_FRAME))
return pc - 1;
return pc;
}
-static int
-pc_notcurrent (struct frame_info *frame)
+void
+find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
{
+ struct frame_info *next_frame;
+ int notcurrent;
+
+ /* If the next frame represents an inlined function call, this frame's
+ sal is the "call site" of that inlined function, which can not
+ be inferred from get_frame_pc. */
+ next_frame = get_next_frame (frame);
+ if (frame_inlined_callees (frame) > 0)
+ {
+ struct symbol *sym;
+
+ if (next_frame)
+ sym = get_frame_function (next_frame);
+ else
+ sym = inline_skipped_symbol (inferior_ptid);
+
+ init_sal (sal);
+ if (SYMBOL_LINE (sym) != 0)
+ {
+ sal->symtab = SYMBOL_SYMTAB (sym);
+ sal->line = SYMBOL_LINE (sym);
+ }
+ else
+ /* If the symbol does not have a location, we don't know where
+ the call site is. Do not pretend to. This is jarring, but
+ we can't do much better. */
+ sal->pc = get_frame_pc (frame);
+
+ return;
+ }
+
/* If FRAME is not the innermost frame, that normally means that
FRAME->pc points at the return instruction (which is *after* the
call instruction), and we want to get the line containing the
PC and such a PC indicates the current (rather than next)
instruction/line, consequently, for such cases, want to get the
line containing fi->pc. */
- struct frame_info *next = get_next_frame (frame);
- int notcurrent = (next != NULL && get_frame_type (next) == NORMAL_FRAME);
- return notcurrent;
-}
-
-void
-find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
-{
- (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
+ notcurrent = (get_frame_pc (frame) != get_frame_address_in_block (frame));
+ (*sal) = find_pc_line (get_frame_pc (frame), notcurrent);
}
/* Per "frame.h", return the ``address'' of the frame. Code should
CORE_ADDR
get_frame_locals_address (struct frame_info *fi)
{
- void **cache;
if (get_frame_type (fi) != NORMAL_FRAME)
return 0;
/* If there isn't a frame address method, find it. */
CORE_ADDR
get_frame_args_address (struct frame_info *fi)
{
- void **cache;
if (get_frame_type (fi) != NORMAL_FRAME)
return 0;
/* If there isn't a frame address method, find it. */
return fi->base->this_args (fi, &fi->base_cache);
}
+/* Return true if the frame unwinder for frame FI is UNWINDER; false
+ otherwise. */
+
+int
+frame_unwinder_is (struct frame_info *fi, const struct frame_unwind *unwinder)
+{
+ if (fi->unwind == NULL)
+ fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
+ return fi->unwind == unwinder;
+}
+
/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
or -1 for a NULL frame. */
return frame->unwind->type;
}
+struct program_space *
+get_frame_program_space (struct frame_info *frame)
+{
+ return frame->pspace;
+}
+
+struct program_space *
+frame_unwind_program_space (struct frame_info *this_frame)
+{
+ gdb_assert (this_frame);
+
+ /* This is really a placeholder to keep the API consistent --- we
+ assume for now that we don't have frame chains crossing
+ spaces. */
+ return this_frame->pspace;
+}
+
+struct address_space *
+get_frame_address_space (struct frame_info *frame)
+{
+ return frame->aspace;
+}
+
/* Memory access methods. */
void
get_frame_memory_signed (struct frame_info *this_frame, CORE_ADDR addr,
int len)
{
- return read_memory_integer (addr, len);
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ return read_memory_integer (addr, len, byte_order);
}
ULONGEST
get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr,
int len)
{
- return read_memory_unsigned_integer (addr, len);
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ return read_memory_unsigned_integer (addr, len, byte_order);
}
int
return !target_read_memory (addr, buf, len);
}
-/* Architecture method. */
+/* Architecture methods. */
struct gdbarch *
get_frame_arch (struct frame_info *this_frame)
{
- /* In the future, this function will return a per-frame
- architecture instead of current_gdbarch. Calling the
- routine with a NULL value of this_frame is a bug! */
- gdb_assert (this_frame);
+ return frame_unwind_arch (this_frame->next);
+}
+
+struct gdbarch *
+frame_unwind_arch (struct frame_info *next_frame)
+{
+ if (!next_frame->prev_arch.p)
+ {
+ struct gdbarch *arch;
+
+ if (next_frame->unwind == NULL)
+ next_frame->unwind
+ = frame_unwind_find_by_frame (next_frame,
+ &next_frame->prologue_cache);
- return current_gdbarch;
+ if (next_frame->unwind->prev_arch != NULL)
+ arch = next_frame->unwind->prev_arch (next_frame,
+ &next_frame->prologue_cache);
+ else
+ arch = get_frame_arch (next_frame);
+
+ next_frame->prev_arch.arch = arch;
+ next_frame->prev_arch.p = 1;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_unwind_arch (next_frame=%d) -> %s }\n",
+ next_frame->level,
+ gdbarch_bfd_arch_info (arch)->printable_name);
+ }
+
+ return next_frame->prev_arch.arch;
+}
+
+struct gdbarch *
+frame_unwind_caller_arch (struct frame_info *next_frame)
+{
+ return frame_unwind_arch (skip_inlined_frames (next_frame));
}
/* Stack pointer methods. */
get_frame_sp (struct frame_info *this_frame)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
/* Normality - an architecture that provides a way of obtaining any
frame inner-most address. */
if (gdbarch_unwind_sp_p (gdbarch))