summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2003-03-06 19:21:30 +0000
committerAndrew Cagney <cagney@redhat.com>2003-03-06 19:21:30 +0000
commitb51cddb805f0e4cf2d59678ebdfb88fc029eb1e7 (patch)
treee81656231d74f3c9705e59e6b91135a91f309634
parentada25ff8b02cd70298e538164b415b2c14958a3b (diff)
downloadgdb-b51cddb805f0e4cf2d59678ebdfb88fc029eb1e7.tar.gz
2003-03-06 Andrew Cagney <cagney@redhat.com>
* gdbarch.sh (gdbarch_unwind_pc): New method. * gdbarch.h, gdbarch.c: Regenerate. * frame.c (frame_pc_unwind): Rewrite. Prefer gdbarch_unwind_pc, but use read_pc and FRAME_SAVED_PC as fall backs. (frame_saved_regs_pc_unwind): Delete function. (trad_frame_unwinder): Update. * frame-unwind.h (frame_unwind_pc_ftype): Delete declaration. (struct frame_unwind): Update. * dummy-frame.c (dummy_frame_pc_unwind): Delete function. (dummy_frame_unwind): Update. * sentinel-frame.c (sentinel_frame_pc_unwind): Delete function. (sentinel_frame_unwinder): Update. * d10v-tdep.c (d10v_frame_pc_unwind): Delete function. (d10v_frame_unwind): Update. (d10v_unwind_pc): New function. (d10v_gdbarch_init): Set unwind_pc. 2003-03-05 Andrew Cagney <cagney@redhat.com> * dummy-frame.c (dummy_frame_id_unwind): Abort if called. (cached_find_dummy_frame): Add hack to obtain this thread's id without calling id unwind. * frame.h: Merge with mainline. * d10v-tdep.c: Merge with mainline. * frame.c: Merge with mainline.
-rw-r--r--gdb/ChangeLog28
-rw-r--r--gdb/d10v-tdep.c137
-rw-r--r--gdb/dummy-frame.c36
-rw-r--r--gdb/frame-unwind.h21
-rw-r--r--gdb/frame.c235
-rw-r--r--gdb/frame.h10
-rw-r--r--gdb/gdbarch.c37
-rw-r--r--gdb/gdbarch.h8
-rwxr-xr-xgdb/gdbarch.sh2
-rw-r--r--gdb/sentinel-frame.c12
10 files changed, 291 insertions, 235 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8ac3ae9487c..b2510c3a36d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,31 @@
+2003-03-06 Andrew Cagney <cagney@redhat.com>
+
+ * gdbarch.sh (gdbarch_unwind_pc): New method.
+ * gdbarch.h, gdbarch.c: Regenerate.
+ * frame.c (frame_pc_unwind): Rewrite. Prefer gdbarch_unwind_pc,
+ but use read_pc and FRAME_SAVED_PC as fall backs.
+ (frame_saved_regs_pc_unwind): Delete function.
+ (trad_frame_unwinder): Update.
+ * frame-unwind.h (frame_unwind_pc_ftype): Delete declaration.
+ (struct frame_unwind): Update.
+ * dummy-frame.c (dummy_frame_pc_unwind): Delete function.
+ (dummy_frame_unwind): Update.
+ * sentinel-frame.c (sentinel_frame_pc_unwind): Delete function.
+ (sentinel_frame_unwinder): Update.
+ * d10v-tdep.c (d10v_frame_pc_unwind): Delete function.
+ (d10v_frame_unwind): Update.
+ (d10v_unwind_pc): New function.
+ (d10v_gdbarch_init): Set unwind_pc.
+
+2003-03-05 Andrew Cagney <cagney@redhat.com>
+
+ * dummy-frame.c (dummy_frame_id_unwind): Abort if called.
+ (cached_find_dummy_frame): Add hack to obtain this thread's id
+ without calling id unwind.
+ * frame.h: Merge with mainline.
+ * d10v-tdep.c: Merge with mainline.
+ * frame.c: Merge with mainline.
+
2003-03-04 Andrew Cagney <cagney@redhat.com>
* d10v-tdep.c (struct d10v_unwind_cache): Add field "r11_addr",
diff --git a/gdb/d10v-tdep.c b/gdb/d10v-tdep.c
index 5cbdddcdce5..0fe222ec2fe 100644
--- a/gdb/d10v-tdep.c
+++ b/gdb/d10v-tdep.c
@@ -616,8 +616,11 @@ struct d10v_unwind_cache
CORE_ADDR base;
int size;
CORE_ADDR *saved_regs;
- LONGEST next_addr;
- LONGEST r11_addr;
+ /* How far the SP and r11 (FP) have been offset from the start of
+ the stack frame (as defined by the previous frame's stack
+ pointer). */
+ LONGEST sp_offset;
+ LONGEST r11_offset;
int uses_frame;
void **regs;
};
@@ -632,8 +635,8 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op,
if ((op & 0x7E1F) == 0x6C1F)
{
n = (op & 0x1E0) >> 5;
- info->next_addr -= 2;
- info->saved_regs[n] = info->next_addr;
+ info->sp_offset -= 2;
+ info->saved_regs[n] = info->sp_offset;
return 1;
}
@@ -641,9 +644,9 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op,
else if ((op & 0x7E3F) == 0x6E1F)
{
n = (op & 0x1E0) >> 5;
- info->next_addr -= 4;
- info->saved_regs[n] = info->next_addr;
- info->saved_regs[n + 1] = info->next_addr + 2;
+ info->sp_offset -= 4;
+ info->saved_regs[n] = info->sp_offset;
+ info->saved_regs[n + 1] = info->sp_offset + 2;
return 1;
}
@@ -653,7 +656,7 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op,
n = (op & 0x1E) >> 1;
if (n == 0)
n = 16;
- info->next_addr -= n;
+ info->sp_offset -= n;
return 1;
}
@@ -661,7 +664,7 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op,
if (op == 0x417E)
{
info->uses_frame = 1;
- info->r11_addr = info->next_addr;
+ info->r11_offset = info->sp_offset;
return 1;
}
@@ -669,7 +672,7 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op,
if ((op & 0x7E1F) == 0x6816)
{
n = (op & 0x1E0) >> 5;
- info->saved_regs[n] = info->r11_addr;
+ info->saved_regs[n] = info->r11_offset;
return 1;
}
@@ -681,7 +684,7 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op,
if ((op & 0x7E1F) == 0x681E)
{
n = (op & 0x1E0) >> 5;
- info->saved_regs[n] = info->next_addr;
+ info->saved_regs[n] = info->sp_offset;
return 1;
}
@@ -689,8 +692,8 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op,
if ((op & 0x7E3F) == 0x3A1E)
{
n = (op & 0x1E0) >> 5;
- info->saved_regs[n] = info->next_addr;
- info->saved_regs[n + 1] = info->next_addr + 2;
+ info->saved_regs[n] = info->sp_offset;
+ info->saved_regs[n + 1] = info->sp_offset + 2;
return 1;
}
@@ -708,8 +711,8 @@ d10v_frame_unwind_cache (struct frame_info *next_frame,
void **this_cache)
{
CORE_ADDR pc;
- ULONGEST sp;
- ULONGEST base;
+ ULONGEST prev_sp;
+ ULONGEST this_base;
unsigned long op;
unsigned short op1, op2;
int i;
@@ -724,7 +727,7 @@ d10v_frame_unwind_cache (struct frame_info *next_frame,
info->size = 0;
- info->next_addr = 0;
+ info->sp_offset = 0;
pc = get_pc_function_start (frame_pc_unwind (next_frame));
@@ -739,22 +742,22 @@ d10v_frame_unwind_cache (struct frame_info *next_frame,
{
/* add3 sp,sp,n */
short n = op & 0xFFFF;
- info->next_addr += n;
+ info->sp_offset += n;
}
else if ((op & 0x3F0F0000) == 0x340F0000)
{
/* st rn, @(offset,sp) */
short offset = op & 0xFFFF;
short n = (op >> 20) & 0xF;
- info->saved_regs[n] = info->next_addr + offset;
+ info->saved_regs[n] = info->sp_offset + offset;
}
else if ((op & 0x3F1F0000) == 0x350F0000)
{
/* st2w rn, @(offset,sp) */
short offset = op & 0xFFFF;
short n = (op >> 20) & 0xF;
- info->saved_regs[n] = info->next_addr + offset;
- info->saved_regs[n + 1] = info->next_addr + offset + 2;
+ info->saved_regs[n] = info->sp_offset + offset;
+ info->saved_regs[n + 1] = info->sp_offset + offset + 2;
}
else
break;
@@ -779,52 +782,50 @@ d10v_frame_unwind_cache (struct frame_info *next_frame,
pc += 4;
}
- info->size = -info->next_addr;
+ info->size = -info->sp_offset;
- /* Compute the frame's base. */
+ /* Compute the frame's base, and the previous frame's SP. */
if (info->uses_frame)
{
- /* The SP was moved into the FP. This indicates that a new
- frame was created. Get THIS frame's FP value by unwinding it
- from the next frame. */
- frame_unwind_unsigned_register (next_frame, FP_REGNUM, &base);
+ /* The SP was moved to the FP. This indicates that a new frame
+ was created. Get THIS frame's FP value by unwinding it from
+ the next frame. */
+ frame_unwind_unsigned_register (next_frame, FP_REGNUM, &this_base);
/* The FP points at the last saved register. Adjust the FP back
to before the first saved register giving the SP. */
- sp = base + info->size;
+ prev_sp = this_base + info->size;
}
else if (info->saved_regs[SP_REGNUM])
{
/* The SP was saved (which is very unusual), the frame base is
just the PREV's frame's TOP-OF-STACK. */
- base = read_memory_unsigned_integer (info->saved_regs[SP_REGNUM],
- register_size (current_gdbarch,
- SP_REGNUM));
- sp = base;
+ this_base = read_memory_unsigned_integer (info->saved_regs[SP_REGNUM],
+ register_size (current_gdbarch,
+ SP_REGNUM));
+ prev_sp = this_base;
}
else
{
/* Assume that the FP is this frame's SP but with that pushed
stack space added back. */
- frame_unwind_unsigned_register (next_frame, SP_REGNUM, &base);
- sp = base + info->size;
+ frame_unwind_unsigned_register (next_frame, SP_REGNUM, &this_base);
+ prev_sp = this_base + info->size;
}
- info->base = d10v_make_daddr (base);
- sp = d10v_make_daddr (sp);
+ info->base = d10v_make_daddr (this_base);
+ prev_sp = d10v_make_daddr (prev_sp);
/* Adjust all the saved registers so that they contain addresses and
not offsets. */
for (i = 0; i < NUM_REGS - 1; i++)
- {
- if (info->saved_regs[i])
- {
- info->saved_regs[i] = (sp + info->saved_regs[i]);
- }
- }
+ if (info->saved_regs[i])
+ {
+ info->saved_regs[i] = (prev_sp + info->saved_regs[i]);
+ }
/* The SP_REGNUM is special. Instead of the address of the SP, the
previous frame's SP value is saved. */
- info->saved_regs[SP_REGNUM] = sp;
+ info->saved_regs[SP_REGNUM] = prev_sp;
return info;
}
@@ -1432,22 +1433,12 @@ display_trace (int low, int high)
}
}
-
static CORE_ADDR
-d10v_frame_pc_unwind (struct frame_info *next_frame,
- void **this_cache)
+d10v_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- /* FIXME: This shouldn't be needed. Instead single per-architecture
- method should be called for all frames. */
- CORE_ADDR lr;
- struct d10v_unwind_cache *info
- = d10v_frame_unwind_cache (next_frame, this_cache);
- void *buffer = alloca (max_register_size (current_gdbarch));
- saved_regs_unwind (next_frame, info->saved_regs, LR_REGNUM, buffer);
- lr = extract_unsigned_integer (buffer, register_size (current_gdbarch,
- LR_REGNUM));
- return d10v_make_iaddr (lr);
-
+ ULONGEST pc;
+ frame_unwind_unsigned_register (next_frame, PC_REGNUM, &pc);
+ return d10v_make_iaddr (pc);
}
/* Given the next frame, determine the address of this function's
@@ -1587,18 +1578,6 @@ d10v_frame_register_unwind (struct frame_info *next_frame,
lvalp, addrp, realnump, bufferp);
}
-
-static struct frame_id
-d10v_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- ULONGEST base;
- struct frame_id id;
- id.pc = frame_pc_unwind (next_frame);
- frame_unwind_unsigned_register (next_frame, SP_REGNUM, &base);
- id.base = d10v_make_daddr (base);
- return id;
-}
-
static void
d10v_frame_pop (struct frame_info *next_frame, void **this_cache,
struct regcache *regcache)
@@ -1635,7 +1614,6 @@ d10v_frame_pop (struct frame_info *next_frame, void **this_cache,
static struct frame_unwind d10v_frame_unwind = {
d10v_frame_pop,
- d10v_frame_pc_unwind,
d10v_frame_id_unwind,
d10v_frame_register_unwind
};
@@ -1646,6 +1624,22 @@ d10v_frame_p (CORE_ADDR pc)
return &d10v_frame_unwind;
}
+/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+ dummy frame. The frame ID's base needs to match the TOS value
+ saved by save_dummy_frame_tos(), and the PC match the dummy frame's
+ breakpoint. */
+
+static struct frame_id
+d10v_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ ULONGEST base;
+ struct frame_id id;
+ id.pc = frame_pc_unwind (next_frame);
+ frame_unwind_unsigned_register (next_frame, SP_REGNUM, &base);
+ id.base = d10v_make_daddr (base);
+ return id;
+}
+
static gdbarch_init_ftype d10v_gdbarch_init;
static struct gdbarch *
@@ -1782,9 +1776,14 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_print_registers_info (gdbarch, d10v_print_registers_info);
frame_unwind_append_predicate (gdbarch, d10v_frame_p);
+
+ /* Methods for saving / extracting a dummy frame's ID. */
set_gdbarch_unwind_dummy_id (gdbarch, d10v_unwind_dummy_id);
set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+ /* Return the unwound PC value. */
+ set_gdbarch_unwind_pc (gdbarch, d10v_unwind_pc);
+
return gdbarch;
}
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
index 6812ed92d1e..a44f4510dbc 100644
--- a/gdb/dummy-frame.c
+++ b/gdb/dummy-frame.c
@@ -108,8 +108,13 @@ struct dummy_frame *
cached_find_dummy_frame (struct frame_info *next_frame, void **this_cache)
{
if ((*this_cache) == NULL)
- (*this_cache) = find_dummy_frame (frame_pc_unwind (next_frame),
- frame_id_unwind (next_frame).base);
+ {
+ /* FIXME: hack to find the frame ID of this frame. Need to do
+ this better. */
+ gdb_assert (next_frame->prev != NULL);
+ (*this_cache) = find_dummy_frame (frame_pc_unwind (next_frame),
+ next_frame->prev->frame);
+ }
return (*this_cache);
}
@@ -371,23 +376,6 @@ dummy_frame_register_unwind (struct frame_info *next_frame, void **this_cache,
}
}
-/* Assuming that FRAME is a dummy, return the resume address for the
- previous frame. */
-
-static CORE_ADDR
-dummy_frame_pc_unwind (struct frame_info *next_frame,
- void **this_cache)
-{
- struct dummy_frame *dummy = cached_find_dummy_frame (next_frame, this_cache);
- /* Oops! In a dummy-frame but can't find the stack dummy. Pretend
- that the frame doesn't unwind. Should this function instead
- return a has-no-caller indication? */
- if (dummy == NULL)
- return 0;
- return dummy->pc;
-}
-
-
/* Assuming that FRAME is a dummy, return the ID of the calling frame
(the frame that the dummy has the saved state of). */
@@ -396,6 +384,7 @@ dummy_frame_id_unwind (struct frame_info *next_frame,
void **this_cache,
struct frame_id *this_id)
{
+#if 0
struct dummy_frame *dummy = cached_find_dummy_frame (next_frame, this_cache);
/* Oops! In a dummy-frame but can't find the stack dummy. Pretend
that the frame doesn't unwind. Should this function instead
@@ -404,12 +393,19 @@ dummy_frame_id_unwind (struct frame_info *next_frame,
(*this_id) = null_frame_id;
else
(*this_id) = dummy->id;
+#else
+ /* FIXME - with all the frames shuffled by one, it becomes possible
+ to move the dummy frame unwind code to here. This is because,
+ unlike the mainline, this function is called when determining the
+ ID of the dummy, and not the ID of the dummy's caller. For the
+ moment, this function is never called. */
+ internal_error (__FILE__, __LINE__, "dummy_frame_pc_unwind called");
+#endif
}
static struct frame_unwind dummy_frame_unwind =
{
dummy_frame_pop,
- dummy_frame_pc_unwind,
dummy_frame_id_unwind,
dummy_frame_register_unwind
};
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index 0ee0bc366d6..4d00b2f5e19 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -104,26 +104,6 @@ typedef void (frame_unwind_reg_ftype) (struct frame_info *next_frame,
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
use the NEXT frame, and its register unwind method, to unwind THIS
- frame's PC, returning the value of PC (the return address) in PREV
- frame.
-
- Traditionally, THIS frame's PC was unwound by examining THIS
- frame's function prolog and identifying where (in a register or on
- the stack) that return address was saved.
-
- Please note that this per-frame method may be superseeded by an
- architecture specific method that determines the unwound PC (aka
- return address) using just the register unwind methods.
-
- THIS_CACHE can be used to share any prologue analysis data with the
- other unwind methods. Memory for that cache should be allocated
- using frame_obstack_zalloc(). */
-
-typedef CORE_ADDR (frame_unwind_pc_ftype) (struct frame_info *next_frame,
- void **this_cache);
-
-/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
- use the NEXT frame, and its register unwind method, to unwind THIS
frame's entire stack, writing PREV's frames register values into
REGCACHE.
@@ -151,7 +131,6 @@ struct frame_unwind
/* Should an attribute indicating the frame's address-in-block go
here? */
frame_unwind_pop_ftype *pop;
- frame_unwind_pc_ftype *pc;
frame_unwind_id_ftype *id;
frame_unwind_reg_ftype *reg;
};
diff --git a/gdb/frame.c b/gdb/frame.c
index dd3cd68aad7..d61ec08ee8c 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -135,27 +135,54 @@ frame_find_by_id (struct frame_id id)
}
CORE_ADDR
-frame_pc_unwind (struct frame_info *this_frame)
+frame_pc_unwind (struct frame_info *next_frame)
{
- if (!this_frame->pc_unwind_cache_p)
+ if (!next_frame->pc_unwind_cache_p)
{
- this_frame->pc_unwind_cache
- = this_frame->unwind->pc (this_frame->next, &this_frame->unwind_cache);
- this_frame->pc_unwind_cache_p = 1;
- }
- return this_frame->pc_unwind_cache;
-}
-
-struct frame_id
-frame_id_unwind (struct frame_info *this_frame)
-{
- if (!this_frame->id_unwind_cache_p)
- {
- this_frame->unwind->id (this_frame->next, &this_frame->unwind_cache,
- &this_frame->id_unwind_cache);
- this_frame->id_unwind_cache_p = 1;
+ CORE_ADDR pc;
+ if (gdbarch_unwind_pc_p (current_gdbarch))
+ {
+ /* The right way. The `pure' way. The one true way. This
+ method depends solely on the register-unwind code to
+ determine the value of registers in THIS frame, and hence
+ the value of this frame's PC (resume address). A typical
+ implementation is no more than:
+
+ frame_unwind_register (next_frame, ISA_PC_REGNUM, buf);
+ return extract_address (buf, size of ISA_PC_REGNUM);
+
+ Note: this method is very heavily dependent on a correct
+ register-unwind implementation, it pays to fix that
+ method first; this method is frame type agnostic, since
+ it only deals with register values, it works with any
+ 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 (current_gdbarch, next_frame);
+ }
+ else if (next_frame->level < 0)
+ {
+ /* FIXME: cagney/2003-03-06: Old code and and a sentinel
+ frame. Do like was always done. Fetch the PC's value
+ direct from the global registers array (via read_pc).
+ This assumes that this frame belongs to the current
+ global register cache. The assumption is dangerous. */
+ pc = read_pc ();
+ }
+ else if (FRAME_SAVED_PC_P ())
+ {
+ /* FIXME: cagney/2003-03-06: Old code, but not a sentinel
+ frame. Do like was always done. Note that this method,
+ unlike unwind_pc(), tries to handle all the different
+ frame cases directly. It fails. */
+ pc = FRAME_SAVED_PC (next_frame);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "No gdbarch_unwind_pc method");
+ next_frame->pc_unwind_cache = pc;
+ next_frame->pc_unwind_cache_p = 1;
}
- return this_frame->id_unwind_cache;
+ return next_frame->pc_unwind_cache;
}
void
@@ -682,13 +709,6 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
bufferp);
}
-static CORE_ADDR
-frame_saved_regs_pc_unwind (struct frame_info *frame, void **cache)
-{
- gdb_assert (FRAME_SAVED_PC_P ());
- return FRAME_SAVED_PC (frame);
-}
-
static void
frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache,
struct frame_id *id)
@@ -760,7 +780,6 @@ frame_saved_regs_pop (struct frame_info *fi, void **cache,
const struct frame_unwind trad_frame_unwinder = {
frame_saved_regs_pop,
- frame_saved_regs_pc_unwind,
frame_saved_regs_id_unwind,
frame_saved_regs_register_unwind
};
@@ -1346,83 +1365,87 @@ get_prev_frame (struct frame_info *next_frame)
prev_frame->pc);
/* Find the prev's frame's ID. */
- {
- switch (prev_frame->type)
- {
- case DUMMY_FRAME:
- /* A dummy doesn't have anything resembling either a sane
- frame or PC. The PC is sitting in the entry code and the
- stack, which has nothing to do with that entry address, is
- a down right mess. Trying to use the standard frame ID
- unwind code to get the previous frame ID is just asking for
- trouble. */
- if (gdbarch_unwind_dummy_id_p (current_gdbarch))
- {
- /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS,
- previously saved the dummy ID that is being obtained
- here. Things only work if the two match. */
- gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
- /* Use an architecture specific method to extract the
- prev's dummy ID from the next frame. Note that this
- method typically uses frame_register_unwind to obtain
- register values needed to determine the dummy ID. */
- next_frame->id_unwind_cache =
- gdbarch_unwind_dummy_id (current_gdbarch, next_frame);
- }
- else if (next_frame->level == 0)
- {
- /* We're `unwinding' the sentinel frame. Just fake up the
- ID the same way that the traditional hacks did it. */
- next_frame->id_unwind_cache.pc = read_pc ();
- next_frame->id_unwind_cache.pc = read_fp ();
- }
- else
- {
- /* Outch! We're not on the innermost frame yet we're
- trying to unwind to a dummy. The architecture must
- provide the unwind_dummy_id() method. */
- internal_error (__FILE__, __LINE__,
+ switch (prev_frame->type)
+ {
+ case DUMMY_FRAME:
+ /* When unwinding a normal frame, the stack structure is
+ determined by analyzing the frame's function's code (be it
+ using brute force prologue analysis, or the dwarf2 CFI). In
+ the case of a dummy frame, that simply isn't possible. The
+ The PC is either the program entry point, or some random
+ address on the stack. Trying to use that PC to apply
+ standard frame ID unwind techniques is just asking for
+ trouble. */
+ if (gdbarch_unwind_dummy_id_p (current_gdbarch))
+ {
+ /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS,
+ previously saved the dummy frame's ID. Things only work
+ if the two return the same value. */
+ gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
+ /* Use an architecture specific method to extract the prev's
+ dummy ID from the next frame. Note that this method uses
+ frame_register_unwind to obtain the register values
+ needed to determine the dummy frame's ID. */
+ prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch,
+ next_frame);
+ }
+ else if (next_frame->level < 0)
+ {
+ /* We're unwinding a sentinel frame, the PC of which is
+ pointing at a stack dummy. Fake up the dummy frame's ID
+ using the same sequence as is found a traditional
+ unwinder. Once all architectures supply the
+ unwind_dummy_id method, this code can go away. */
+ prev_frame->id.base = read_fp ();
+ prev_frame->id.pc = read_pc ();
+ }
+ else
+ {
+ /* Outch! We're not on the innermost frame yet we're trying
+ to unwind to a dummy. The architecture must provide the
+ unwind_dummy_id() method. Abandon the unwind process but
+ only after first warning the user. */
+ internal_warning (__FILE__, __LINE__,
"Missing unwind_dummy_id architecture method");
- }
- break;
- case NORMAL_FRAME:
- case SIGTRAMP_FRAME:
- prev_frame->unwind->id (next_frame, &prev_frame->unwind_cache,
- &next_frame->id_unwind_cache);
- /* Check that the unwound ID is valid. */
- if (!frame_id_p (next_frame->id_unwind_cache))
- {
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - unwound frame ID invalid\n");
- return NULL;
- }
- /* Check that the new frame isn't inner to (younger, below,
- next) the old frame. If that happens the frame unwind is
- going backwards. */
- /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since
- that doesn't have a valid frame ID. Should instead set the
- sentinel frame's frame ID to a `sentinel'. Leave it until
- after the switch to storing the frame ID, instead of the
- frame base, in the frame object. */
- if (next_frame->level >= 0
- && frame_id_inner (next_frame->id_unwind_cache,
- get_frame_id (next_frame)))
- error ("Unwound frame inner-to selected frame (corrupt stack?)");
- /* Note that, due to frameless functions, the stronger test of
- the new frame being outer to the old frame can't be used -
- frameless functions differ by only their PC value. */
- break;
- default:
- internal_error (__FILE__, __LINE__, "bad switch");
- }
- /* FIXME: cagney/2002-12-18: Instead of this hack, the frame ID
- should be directly stored in the `struct frame_info'.
- Unfortunatly, GDB isn't quite ready for this, need to get HP/UX
- multi-arch and make 'struct frame_info' opaque. */
- next_frame->id_unwind_cache_p = 1;
- prev_frame->frame = next_frame->id_unwind_cache.base;
- }
+ return NULL;
+ }
+ break;
+ case NORMAL_FRAME:
+ case SIGTRAMP_FRAME:
+ prev_frame->unwind->id (next_frame, &prev_frame->unwind_cache,
+ &prev_frame->id);
+ /* Check that the unwound ID is valid. */
+ if (!frame_id_p (prev_frame->id))
+ {
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Outermost frame - unwound frame ID invalid\n");
+ return NULL;
+ }
+ /* Check that the new frame isn't inner to (younger, below,
+ next) the old frame. If that happens the frame unwind is
+ going backwards. */
+ /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since
+ that doesn't have a valid frame ID. Should instead set the
+ sentinel frame's frame ID to a `sentinel'. Leave it until
+ after the switch to storing the frame ID, instead of the
+ frame base, in the frame object. */
+ if (next_frame->level >= 0
+ && frame_id_inner (prev_frame->id, get_frame_id (next_frame)))
+ error ("Unwound frame inner-to selected frame (corrupt stack?)");
+ /* Note that, due to frameless functions, the stronger test of
+ the new frame being outer to the old frame can't be used -
+ frameless functions differ by only their PC value. */
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+
+ /* FIXME: cagney/2002-12-18: Instead of this hack, should only store
+ the frame ID in PREV_FRAME. Unfortunatly, some architectures
+ (HP/UX) still reply on EXTRA_FRAME_INFO and, hence, still poke at
+ the "struct frame_info" object directly. */
+ prev_frame->frame = prev_frame->id.base;
/* Link it in. */
next_frame->prev = prev_frame;
@@ -1557,11 +1580,11 @@ void
deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
{
/* See comment in "frame.h". */
- gdb_assert (frame->next != NULL);
- /* Fix up this PC's value. */
frame->pc = pc;
- /* While we're at it, also update the cache, in NEXT, that also
- contains that value. */
+ /* While we're at it, update this frame's cached PC value, found in
+ the next frame. Oh, for the day when "struct frame_info" is
+ opaque and this hack on hack can go. */
+ gdb_assert (frame->next != NULL);
frame->next->pc_unwind_cache = pc;
frame->next->pc_unwind_cache_p = 1;
}
diff --git a/gdb/frame.h b/gdb/frame.h
index bd20ba7aec1..18c4df4397f 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -310,10 +310,6 @@ extern const char *frame_map_regnum_to_name (int regnum);
extern CORE_ADDR frame_pc_unwind (struct frame_info *frame);
-/* Unwind the frame ID. Return an ID that uniquely identifies the
- caller's frame. */
-extern struct frame_id frame_id_unwind (struct frame_info *frame);
-
/* Discard the specified frame. Restoring the registers to the state
of the caller. */
extern void frame_pop (struct frame_info *frame);
@@ -412,9 +408,9 @@ struct frame_info
int pc_unwind_cache_p;
CORE_ADDR pc_unwind_cache;
- /* Cached copy of the previous frame's ID. */
- int id_unwind_cache_p;
- struct frame_id id_unwind_cache;
+ /* This frame's ID. Note that the frame's ID, base and PC contain
+ redundant information. */
+ struct frame_id id;
/* Pointers to the next (down, inner, younger) and previous (up,
outer, older) frame_info's in the frame cache. */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 636349c7be2..8b5a475375c 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -242,6 +242,7 @@ struct gdbarch
gdbarch_frame_chain_ftype *frame_chain;
gdbarch_frame_chain_valid_ftype *frame_chain_valid;
gdbarch_frame_saved_pc_ftype *frame_saved_pc;
+ gdbarch_unwind_pc_ftype *unwind_pc;
gdbarch_frame_args_address_ftype *frame_args_address;
gdbarch_frame_locals_address_ftype *frame_locals_address;
gdbarch_saved_pc_after_call_ftype *saved_pc_after_call;
@@ -433,6 +434,7 @@ struct gdbarch startup_gdbarch =
0,
0,
0,
+ 0,
generic_in_function_epilogue_p,
construct_inferior_arguments,
0,
@@ -759,6 +761,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of frame_chain, has predicate */
/* Skip verify of frame_chain_valid, has predicate */
/* Skip verify of frame_saved_pc, has predicate */
+ /* Skip verify of unwind_pc, has predicate */
/* Skip verify of frame_args_address, invalid_p == 0 */
/* Skip verify of frame_locals_address, invalid_p == 0 */
if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
@@ -2578,6 +2581,14 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: unwind_dummy_id = 0x%08lx\n",
(long) current_gdbarch->unwind_dummy_id);
+ if (GDB_MULTI_ARCH)
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
+ gdbarch_unwind_pc_p (current_gdbarch));
+ if (GDB_MULTI_ARCH)
+ fprintf_unfiltered (file,
+ "gdbarch_dump: unwind_pc = 0x%08lx\n",
+ (long) current_gdbarch->unwind_pc);
#ifdef USE_STRUCT_CONVENTION
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
@@ -4845,6 +4856,32 @@ set_gdbarch_frame_saved_pc (struct gdbarch *gdbarch,
gdbarch->frame_saved_pc = frame_saved_pc;
}
+int
+gdbarch_unwind_pc_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->unwind_pc != 0;
+}
+
+CORE_ADDR
+gdbarch_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch->unwind_pc == 0)
+ internal_error (__FILE__, __LINE__,
+ "gdbarch: gdbarch_unwind_pc invalid");
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_pc called\n");
+ return gdbarch->unwind_pc (gdbarch, next_frame);
+}
+
+void
+set_gdbarch_unwind_pc (struct gdbarch *gdbarch,
+ gdbarch_unwind_pc_ftype unwind_pc)
+{
+ gdbarch->unwind_pc = unwind_pc;
+}
+
CORE_ADDR
gdbarch_frame_args_address (struct gdbarch *gdbarch, struct frame_info *fi)
{
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index b1cb72bd185..ee77461cf13 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -2230,6 +2230,8 @@ extern void set_gdbarch_frame_chain_valid (struct gdbarch *gdbarch, gdbarch_fram
#endif
#endif
+/* NOTE: FRAME_SAVED_PC is replaced by UNWIND_PC */
+
#if defined (FRAME_SAVED_PC)
/* Legacy for systems yet to multi-arch FRAME_SAVED_PC */
#if !defined (FRAME_SAVED_PC_P)
@@ -2267,6 +2269,12 @@ extern void set_gdbarch_frame_saved_pc (struct gdbarch *gdbarch, gdbarch_frame_s
#endif
#endif
+extern int gdbarch_unwind_pc_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_unwind_pc_ftype) (struct gdbarch *gdbarch, struct frame_info *next_frame);
+extern CORE_ADDR gdbarch_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame);
+extern void set_gdbarch_unwind_pc (struct gdbarch *gdbarch, gdbarch_unwind_pc_ftype *unwind_pc);
+
/* Default (function) for non- multi-arch platforms. */
#if (!GDB_MULTI_ARCH) && !defined (FRAME_ARGS_ADDRESS)
#define FRAME_ARGS_ADDRESS(fi) (get_frame_base (fi))
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index b367fda7b7f..8380a601820 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -591,7 +591,9 @@ v:2:FRAME_ARGS_SKIP:CORE_ADDR:frame_args_skip::::0:-1
f:2:FRAMELESS_FUNCTION_INVOCATION:int:frameless_function_invocation:struct frame_info *fi:fi:::generic_frameless_function_invocation_not::0
F:2:FRAME_CHAIN:CORE_ADDR:frame_chain:struct frame_info *frame:frame::0:0
F:2:FRAME_CHAIN_VALID:int:frame_chain_valid:CORE_ADDR chain, struct frame_info *thisframe:chain, thisframe::0:0
+# NOTE: FRAME_SAVED_PC is replaced by UNWIND_PC
F:2:FRAME_SAVED_PC:CORE_ADDR:frame_saved_pc:struct frame_info *fi:fi::0:0
+M::UNWIND_PC:CORE_ADDR:unwind_pc:struct frame_info *next_frame:next_frame:
f:2:FRAME_ARGS_ADDRESS:CORE_ADDR:frame_args_address:struct frame_info *fi:fi::0:get_frame_base::0
f:2:FRAME_LOCALS_ADDRESS:CORE_ADDR:frame_locals_address:struct frame_info *fi:fi::0:get_frame_base::0
f:2:SAVED_PC_AFTER_CALL:CORE_ADDR:saved_pc_after_call:struct frame_info *frame:frame::0:0
diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c
index ef8113da4e4..046655f0687 100644
--- a/gdb/sentinel-frame.c
+++ b/gdb/sentinel-frame.c
@@ -76,17 +76,6 @@ sentinel_frame_register_unwind (struct frame_info *next_frame,
}
}
-CORE_ADDR
-sentinel_frame_pc_unwind (struct frame_info *next_frame,
- void **this_cache)
-{
- /* FIXME: cagney/2003-01-08: This should be using a per-architecture
- method that doesn't suffer from DECR_PC_AFTER_BREAK problems.
- Such a method would take unwind_cache, regcache and stop reason
- parameters. */
- return read_pc ();
-}
-
void
sentinel_frame_id_unwind (struct frame_info *next_frame,
void **this_cache,
@@ -106,7 +95,6 @@ sentinel_frame_pop (struct frame_info *next_frame,
const struct frame_unwind sentinel_frame_unwinder =
{
sentinel_frame_pop,
- sentinel_frame_pc_unwind,
sentinel_frame_id_unwind,
sentinel_frame_register_unwind
};