summaryrefslogtreecommitdiff
path: root/gdb/blockframe.c
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2002-06-01 20:44:21 +0000
committerAndrew Cagney <cagney@redhat.com>2002-06-01 20:44:21 +0000
commitba944fbb321cf4fac89b7b58de118865680616c4 (patch)
treec747321ba216ad08fcf65d73bc3181c24c97f23e /gdb/blockframe.c
parentb057c94ddeb8141fcb1742d9f074260840d902c4 (diff)
downloadgdb-ba944fbb321cf4fac89b7b58de118865680616c4.tar.gz
* stack.c (frame_info): Use frame_register_unwind instead of
saved_regs. Mention when the SP is on the stack or in a register. * frame.h (frame_register_unwind_ftype): Define. Document. (struct frame_info): Add field register_unwind and register_unwind_cache. (frame_register_unwind): Declare. (generic_unwind_get_saved_register): Declare. * frame.c (frame_register_unwind): New function. (generic_unwind_get_saved_register): New function. * blockframe.c (generic_call_dummy_register_unwind): New function. (frame_saved_regs_register_unwind): New function. (set_unwind_by_pc): New function. (create_new_frame): New function. (get_prev_frame): New function.
Diffstat (limited to 'gdb/blockframe.c')
-rw-r--r--gdb/blockframe.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
index 706d0283cf1..deeda4c7df6 100644
--- a/gdb/blockframe.c
+++ b/gdb/blockframe.c
@@ -34,9 +34,28 @@
#include "inferior.h" /* for read_pc */
#include "annotate.h"
#include "regcache.h"
+#include "gdb_assert.h"
/* Prototypes for exported functions. */
+static void generic_call_dummy_register_unwind (struct frame_info *frame,
+ void **cache,
+ int regnum,
+ int *optimized,
+ enum lval_type *lval,
+ CORE_ADDR *addrp,
+ int *realnum,
+ void *raw_buffer);
+static void frame_saved_regs_register_unwind (struct frame_info *frame,
+ void **cache,
+ int regnum,
+ int *optimized,
+ enum lval_type *lval,
+ CORE_ADDR *addrp,
+ int *realnum,
+ void *buffer);
+
+
void _initialize_blockframe (void);
/* A default FRAME_CHAIN_VALID, in the form that is suitable for most
@@ -208,6 +227,27 @@ set_current_frame (struct frame_info *frame)
current_frame = frame;
}
+
+/* Using the PC, select a mechanism for unwinding a frame returning
+ the previous frame. The register unwind function should, on
+ demand, initialize the ->context object. */
+
+static void
+set_unwind_by_pc (CORE_ADDR pc, CORE_ADDR fp,
+ frame_register_unwind_ftype **unwind)
+{
+ if (!USE_GENERIC_DUMMY_FRAMES)
+ /* Still need to set this to something. The ``info frame'' code
+ calls this function to find out where the saved registers are.
+ Hopefully this is robust enough to stop any core dumps and
+ return vaguely correct values.. */
+ *unwind = frame_saved_regs_register_unwind;
+ else if (PC_IN_CALL_DUMMY (pc, fp, fp))
+ *unwind = generic_call_dummy_register_unwind;
+ else
+ *unwind = frame_saved_regs_register_unwind;
+}
+
/* Create an arbitrary (i.e. address specified by user) or innermost frame.
Always returns a non-NULL value. */
@@ -232,6 +272,9 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
if (INIT_EXTRA_FRAME_INFO_P ())
INIT_EXTRA_FRAME_INFO (0, fi);
+ /* Select/initialize an unwind function. */
+ set_unwind_by_pc (fi->pc, fi->frame, &fi->register_unwind);
+
return fi;
}
@@ -456,6 +499,12 @@ get_prev_frame (struct frame_info *next_frame)
}
}
+ /* Initialize the code used to unwind the frame PREV based on the PC
+ (and probably other architectural information). The PC lets you
+ check things like the debug info at that point (dwarf2cfi?) and
+ use that to decide how the frame should be unwound. */
+ set_unwind_by_pc (prev->pc, prev->frame, &prev->register_unwind);
+
find_pc_partial_function (prev->pc, &name,
(CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
if (PC_IN_SIGTRAMP (prev->pc, name))
@@ -1269,6 +1318,141 @@ generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
return;
}
+/* Given a call-dummy dummy-frame, return the registers. Here the
+ register value is taken from the local copy of the register buffer. */
+
+static void
+generic_call_dummy_register_unwind (struct frame_info *frame, void **cache,
+ int regnum, int *optimized,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnum, void *bufferp)
+{
+ gdb_assert (frame != NULL);
+ gdb_assert (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame));
+
+ /* Describe the register's location. Generic dummy frames always
+ have the register value in an ``expression''. */
+ *optimized = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnum = -1;
+
+ /* If needed, find and return the value of the register. */
+ if (bufferp != NULL)
+ {
+ char *registers;
+#if 1
+ /* Get the address of the register buffer that contains all the
+ saved registers for this dummy frame. Cache that address. */
+ registers = (*cache);
+ if (registers == NULL)
+ {
+ registers = generic_find_dummy_frame (frame->pc, frame->frame);
+ (*cache) = registers;
+ }
+#else
+ /* Get the address of the register buffer that contains the
+ saved registers and then extract the value from that. */
+ registers = generic_find_dummy_frame (frame->pc, frame->frame);
+#endif
+ gdb_assert (registers != NULL);
+ /* Return the actual value. */
+ memcpy (bufferp, registers + REGISTER_BYTE (regnum),
+ REGISTER_RAW_SIZE (regnum));
+ }
+}
+
+/* Return the register saved in the simplistic ``saved_regs'' cache.
+ If the value isn't here AND a value is needed, try the next inner
+ most frame. */
+
+static void
+frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ /* There is always a frame at this point. And THIS is the frame
+ we're interested in. */
+ gdb_assert (frame != NULL);
+ gdb_assert (!PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame));
+
+ /* Load the saved_regs register cache. */
+ if (frame->saved_regs == NULL)
+ FRAME_INIT_SAVED_REGS (frame);
+
+ if (frame->saved_regs != NULL
+ && frame->saved_regs[regnum] != 0)
+ {
+ if (regnum == SP_REGNUM)
+ {
+ /* SP register treated specially. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (bufferp != NULL)
+ store_address (bufferp, REGISTER_RAW_SIZE (regnum),
+ frame->saved_regs[regnum]);
+ }
+ else
+ {
+ /* Any other register is saved in memory, fetch it but cache
+ a local copy of its value. */
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = frame->saved_regs[regnum];
+ *realnump = -1;
+ if (bufferp != NULL)
+ {
+#if 1
+ /* Save each register value, as it is read in, in a
+ frame based cache. */
+ void **regs = (*cache);
+ if (regs == NULL)
+ {
+ int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
+ * sizeof (void *));
+ regs = frame_obstack_alloc (sizeof_cache);
+ memset (regs, 0, sizeof_cache);
+ (*cache) = regs;
+ }
+ if (regs[regnum] == NULL)
+ {
+ regs[regnum]
+ = frame_obstack_alloc (REGISTER_RAW_SIZE (regnum));
+ read_memory (frame->saved_regs[regnum], regs[regnum],
+ REGISTER_RAW_SIZE (regnum));
+ }
+ memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum));
+#else
+ /* Read the value in from memory. */
+ read_memory (frame->saved_regs[regnum], bufferp,
+ REGISTER_RAW_SIZE (regnum));
+#endif
+ }
+ }
+ return;
+ }
+
+ /* No luck, assume this and the next frame have the same register
+ value. If a value is needed, pass the request on down the chain;
+ otherwise just return an indication that the value is in the same
+ register as the next frame. */
+ if (bufferp == NULL)
+ {
+ *optimizedp = 0;
+ *lvalp = lval_register;
+ *addrp = 0;
+ *realnump = regnum;
+ }
+ else
+ {
+ frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
+ }
+}
+
/* Function: get_saved_register
Find register number REGNUM relative to FRAME and put its (raw,
target format) contents in *RAW_BUFFER.