* m68hc11-tdep.c (struct m68hc11_unwind_cache): New struct to hold
authorStephane Carrez <stcarrez@nerim.fr>
Sun, 27 Jul 2003 21:24:41 +0000 (21:24 +0000)
committerStephane Carrez <stcarrez@nerim.fr>
Sun, 27 Jul 2003 21:24:41 +0000 (21:24 +0000)
frame unwind information.
(m68hc11_scan_prologue): New function from m68hc11_guess_from_prologue
and adapted for frame unwinding.
(m68hc11_skip_prologue): Update to scan prologue in temporary object.
(m68hc11_unwind_pc): New function.
(m68hc11_frame_unwind_cache): New function to analyze frames.
(m68hc11_frame_this_id): New function to create new frame struct.
(m68hc11_frame_prev_register): New function to unwind a register from
the frame.
(m68hc11_frame_unwind): Default 68hc11/68hc12 unwinder.
(m68hc11_frame_p): New function for the above.
(m68hc11_frame_base_address): New function to return fp of frame.
(m68hc11_frame_args_address): Update for frame.
(m68hc11_frame_base): Default 68hc11/68hc12 frame.
(m68hc11_unwind_sp): New function.
(m68hc11_unwind_dummy_id): New function.
(m68hc11_gdbarch_init): Install the above frames; remove deprecated
calls.

gdb/ChangeLog
gdb/m68hc11-tdep.c

index 57659ad07622d2f4f717a6e5115e2984a8be8e24..b1ecf0c1e620a631a1f2af78236693f10c216fe5 100644 (file)
@@ -1,3 +1,25 @@
+2003-07-27  Stephane Carrez  <stcarrez@nerim.fr>
+
+       * m68hc11-tdep.c (struct m68hc11_unwind_cache): New struct to hold
+       frame unwind information.
+       (m68hc11_scan_prologue): New function from m68hc11_guess_from_prologue
+       and adapted for frame unwinding.
+       (m68hc11_skip_prologue): Update to scan prologue in temporary object.
+       (m68hc11_unwind_pc): New function.
+       (m68hc11_frame_unwind_cache): New function to analyze frames.
+       (m68hc11_frame_this_id): New function to create new frame struct.
+       (m68hc11_frame_prev_register): New function to unwind a register from
+       the frame.
+       (m68hc11_frame_unwind): Default 68hc11/68hc12 unwinder.
+       (m68hc11_frame_p): New function for the above.
+       (m68hc11_frame_base_address): New function to return fp of frame.
+       (m68hc11_frame_args_address): Update for frame.
+       (m68hc11_frame_base): Default 68hc11/68hc12 frame.
+       (m68hc11_unwind_sp): New function.
+       (m68hc11_unwind_dummy_id): New function.
+       (m68hc11_gdbarch_init): Install the above frames; remove deprecated
+       calls.
+
 2003-07-27  Stephane Carrez  <stcarrez@nerim.fr>
 
        * m68hc11-tdep.c (m68hc11_analyze_instruction): Don't advance the pc.
index 6d62b2c2e7b73ff350a15544e14a92add374c3d4..70a1649fcba5126663186f926ed304d743d53fe7 100644 (file)
@@ -21,6 +21,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
 #include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "dwarf2-frame.h"
+#include "trad-frame.h"
 #include "symtab.h"
 #include "gdbtypes.h"
 #include "gdbcmd.h"
@@ -157,6 +161,25 @@ struct gdbarch_tdep
 #define STACK_CORRECTION (M6811_TDEP->stack_correction)
 #define USE_PAGE_REGISTER (M6811_TDEP->use_page_register)
 
+struct m68hc11_unwind_cache
+{
+  /* The previous frame's inner most stack address.  Used as this
+     frame ID's stack_addr.  */
+  CORE_ADDR prev_sp;
+  /* The frame's base, optionally used by the high-level debug info.  */
+  CORE_ADDR base;
+  CORE_ADDR pc;
+  int size;
+  int prologue_type;
+  CORE_ADDR return_pc;
+  CORE_ADDR sp_offset;
+  int frameless;
+  enum insn_return_kind return_kind;
+
+  /* Table indicating the location of each and every register.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
 struct frame_extra_info
 {
   CORE_ADDR return_pc;
@@ -412,20 +435,6 @@ m68hc11_frame_saved_pc (struct frame_info *frame)
   return get_frame_extra_info (frame)->return_pc;
 }
 
-static CORE_ADDR
-m68hc11_frame_args_address (struct frame_info *frame)
-{
-  CORE_ADDR addr;
-
-  addr = get_frame_base (frame) + get_frame_extra_info (frame)->size + STACK_CORRECTION + 2;
-  if (get_frame_extra_info (frame)->return_kind == RETURN_RTC)
-    addr += 1;
-  else if (get_frame_extra_info (frame)->return_kind == RETURN_RTI)
-    addr += 7;
-
-  return addr;
-}
-
 /* Discard from the stack the innermost frame, restoring all saved
    registers.  */
 
@@ -660,35 +669,35 @@ m68hc11_get_return_insn (CORE_ADDR pc)
     return RETURN_RTS;
 }
 
-
 /* Analyze the function prologue to find some information
    about the function:
     - the PC of the first line (for m68hc11_skip_prologue)
     - the offset of the previous frame saved address (from current frame)
     - the soft registers which are pushed.  */
-static void
-m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
-                             CORE_ADDR *first_line,
-                             int *frame_offset, CORE_ADDR *pushed_regs)
+static CORE_ADDR
+m68hc11_scan_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+                       struct m68hc11_unwind_cache *info)
 {
-  CORE_ADDR save_addr;
+  LONGEST save_addr;
   CORE_ADDR func_end;
   int size;
   int found_frame_point;
   int saved_reg;
-  CORE_ADDR first_pc;
   int done = 0;
   struct insn_sequence *seq_table;
-  
-  first_pc = get_pc_function_start (pc);
+
+  info->size = 0;
+  info->sp_offset = 0;
+  if (pc >= current_pc)
+    return current_pc;
+
   size = 0;
 
   m68hc11_initialize_register_info ();
-  if (first_pc == 0)
+  if (pc == 0)
     {
-      *frame_offset = 0;
-      *first_line   = pc;
-      return;
+      info->size = 0;
+      return pc;
     }
 
   seq_table = gdbarch_tdep (current_gdbarch)->prologue;
@@ -734,16 +743,15 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
      we find an instruction which is not supposed to appear in the
      prologue (as generated by gcc 2.95, 2.96).
   */
-  pc = first_pc;
   func_end = pc + 128;
   found_frame_point = 0;
-  *frame_offset = 0;
-  save_addr = fp + STACK_CORRECTION;
+  info->size = 0;
+  save_addr = 0;
   while (!done && pc + 2 < func_end)
     {
       struct insn_sequence *seq;
       CORE_ADDR val;
-      
+
       seq = m68hc11_analyze_instruction (seq_table, pc, &val);
       if (seq == 0)
         break;
@@ -764,8 +772,7 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
                 break;
 
               save_addr -= 2;
-              if (pushed_regs)
-                pushed_regs[saved_reg] = save_addr;
+              info->saved_regs[saved_reg].addr = save_addr;
             }
           else
             {
@@ -775,7 +782,7 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
       else if (seq->type == P_SET_FRAME)
         {
           found_frame_point = 1;
-          *frame_offset = size;
+          info->size = size;
         }
       else if (seq->type == P_LOCAL_1)
         {
@@ -794,7 +801,11 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR current_pc, CORE_ADDR fp,
             size -= val;
         }
     }
-  *first_line  = pc;
+  if (found_frame_point == 0)
+    info->sp_offset = size;
+  else
+    info->sp_offset = -1;
+  return pc;
 }
 
 static CORE_ADDR
@@ -802,7 +813,7 @@ m68hc11_skip_prologue (CORE_ADDR pc)
 {
   CORE_ADDR func_addr, func_end;
   struct symtab_and_line sal;
-  int frame_offset;
+  struct m68hc11_unwind_cache tmp_cache = { 0 };
 
   /* If we have line debugging information, then the end of the
      prologue should be the first assembly instruction of the
@@ -814,7 +825,7 @@ m68hc11_skip_prologue (CORE_ADDR pc)
        return sal.end;
     }
 
-  m68hc11_guess_from_prologue (pc, pc, 0, &pc, &frame_offset, 0);
+  pc = m68hc11_scan_prologue (pc, (CORE_ADDR) -1, &tmp_cache);
   return pc;
 }
 
@@ -846,7 +857,7 @@ m68hc11_frame_chain (struct frame_info *frame)
   addr = read_memory_unsigned_integer (addr, 2) & 0x0FFFF;
   return addr;
 }  
-
+#if 0
 /* Put here the code to store, into a struct frame_saved_regs, the
    addresses of the saved registers of frame described by FRAME_INFO.
    This includes special registers such as pc and fp saved in special
@@ -928,6 +939,261 @@ m68hc11_init_extra_frame_info (int fromleaf, struct frame_info *fi)
       get_frame_extra_info (fi)->return_pc = addr;
     }
 }
+#endif
+
+static CORE_ADDR
+m68hc11_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  ULONGEST pc;
+
+  frame_unwind_unsigned_register (next_frame, gdbarch_pc_regnum (gdbarch),
+                                  &pc);
+  return pc;
+}
+
+/* Put here the code to store, into fi->saved_regs, the addresses of
+   the saved registers of frame described by FRAME_INFO.  This
+   includes special registers such as pc and fp saved in special ways
+   in the stack frame.  sp is even more special: the address we return
+   for it IS the sp for the next frame. */
+
+struct m68hc11_unwind_cache *
+m68hc11_frame_unwind_cache (struct frame_info *next_frame,
+                            void **this_prologue_cache)
+{
+  ULONGEST prev_sp;
+  ULONGEST this_base;
+  struct m68hc11_unwind_cache *info;
+  CORE_ADDR current_pc;
+  int i;
+
+  if ((*this_prologue_cache))
+    return (*this_prologue_cache);
+
+  info = FRAME_OBSTACK_ZALLOC (struct m68hc11_unwind_cache);
+  (*this_prologue_cache) = info;
+  info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+  info->pc = frame_func_unwind (next_frame);
+
+  info->size = 0;
+  info->return_kind = m68hc11_get_return_insn (info->pc);
+
+  /* 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, SOFT_FP_REGNUM, &this_base);
+  if (this_base == 0)
+    {
+      info->base = 0;
+      return info;
+    }
+
+  current_pc = frame_pc_unwind (next_frame);
+  if (info->pc != 0)
+    m68hc11_scan_prologue (info->pc, current_pc, info);
+
+  info->saved_regs[HARD_PC_REGNUM].addr = info->size;
+
+  if (info->sp_offset != (CORE_ADDR) -1)
+    {
+      info->saved_regs[HARD_PC_REGNUM].addr = info->sp_offset;
+      frame_unwind_unsigned_register (next_frame, HARD_SP_REGNUM, &this_base);
+      prev_sp = this_base + info->sp_offset + 2;
+      this_base += STACK_CORRECTION;
+    }
+  else
+    {
+      /* The FP points at the last saved register.  Adjust the FP back
+         to before the first saved register giving the SP.  */
+      prev_sp = this_base + info->size + 2;
+
+      this_base += STACK_CORRECTION;
+      if (soft_regs[SOFT_FP_REGNUM].name)
+        info->saved_regs[SOFT_FP_REGNUM].addr = info->size - 2;
+   }
+
+  if (info->return_kind == RETURN_RTC)
+    {
+      prev_sp += 1;
+      info->saved_regs[HARD_PAGE_REGNUM].addr = info->size;
+      info->saved_regs[HARD_PC_REGNUM].addr = info->size + 1;
+    }
+  else if (info->return_kind == RETURN_RTI)
+    {
+      prev_sp += 7;
+      info->saved_regs[HARD_CCR_REGNUM].addr = info->size;
+      info->saved_regs[HARD_D_REGNUM].addr = info->size + 1;
+      info->saved_regs[HARD_X_REGNUM].addr = info->size + 3;
+      info->saved_regs[HARD_Y_REGNUM].addr = info->size + 5;
+      info->saved_regs[HARD_PC_REGNUM].addr = info->size + 7;
+    }
+
+  /* Add 1 here to adjust for the post-decrement nature of the push
+     instruction.*/
+  info->prev_sp = prev_sp;
+
+  info->base = this_base;
+
+  /* Adjust all the saved registers so that they contain addresses and not
+     offsets.  */
+  for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS - 1; i++)
+    if (trad_frame_addr_p (info->saved_regs, i))
+      {
+        info->saved_regs[i].addr += this_base;
+      }
+
+  /* The previous frame's SP needed to be computed.  Save the computed
+     value.  */
+  trad_frame_set_value (info->saved_regs, HARD_SP_REGNUM, info->prev_sp);
+
+  return info;
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+   frame.  This will be used to create a new GDB frame struct.  */
+
+static void
+m68hc11_frame_this_id (struct frame_info *next_frame,
+                       void **this_prologue_cache,
+                       struct frame_id *this_id)
+{
+  struct m68hc11_unwind_cache *info
+    = m68hc11_frame_unwind_cache (next_frame, this_prologue_cache);
+  CORE_ADDR base;
+  CORE_ADDR func;
+  struct frame_id id;
+
+  /* The FUNC is easy.  */
+  func = frame_func_unwind (next_frame);
+
+  /* This is meant to halt the backtrace at "_start".  Make sure we
+     don't halt it at a generic dummy frame. */
+  if (inside_entry_file (func))
+    return;
+
+  /* Hopefully the prologue analysis either correctly determined the
+     frame's base (which is the SP from the previous frame), or set
+     that base to "NULL".  */
+  base = info->prev_sp;
+  if (base == 0)
+    return;
+
+  id = frame_id_build (base, func);
+#if 0
+  /* Check that we're not going round in circles with the same frame
+     ID (but avoid applying the test to sentinel frames which do go
+     round in circles).  Can't use frame_id_eq() as that doesn't yet
+     compare the frame's PC value.  */
+  if (frame_relative_level (next_frame) >= 0
+      && get_frame_type (next_frame) != DUMMY_FRAME
+      && frame_id_eq (get_frame_id (next_frame), id))
+    return;
+#endif
+  (*this_id) = id;
+}
+
+static void
+m68hc11_frame_prev_register (struct frame_info *next_frame,
+                             void **this_prologue_cache,
+                             int regnum, int *optimizedp,
+                             enum lval_type *lvalp, CORE_ADDR *addrp,
+                             int *realnump, void *bufferp)
+{
+  struct m68hc11_unwind_cache *info
+    = m68hc11_frame_unwind_cache (next_frame, this_prologue_cache);
+
+  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
+                            optimizedp, lvalp, addrp, realnump, bufferp);
+
+  if (regnum == HARD_PC_REGNUM)
+    {
+      /* Take into account the 68HC12 specific call (PC + page).  */
+      if (info->return_kind == RETURN_RTC
+          && *addrp >= 0x08000 && *addrp < 0x0c000
+          && USE_PAGE_REGISTER)
+        {
+          int page_optimized;
+
+          CORE_ADDR page;
+
+          trad_frame_prev_register (next_frame, info->saved_regs,
+                                    HARD_PAGE_REGNUM, &page_optimized,
+                                    0, &page, 0, 0);
+          *addrp -= 0x08000;
+          *addrp += ((page & 0x0ff) << 14);
+          *addrp += 0x1000000;
+        }
+    }
+}
+
+static const struct frame_unwind m68hc11_frame_unwind = {
+  NORMAL_FRAME,
+  m68hc11_frame_this_id,
+  m68hc11_frame_prev_register
+};
+
+const struct frame_unwind *
+m68hc11_frame_p (CORE_ADDR pc)
+{
+  return &m68hc11_frame_unwind;
+}
+
+static CORE_ADDR
+m68hc11_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+  struct m68hc11_unwind_cache *info
+    = m68hc11_frame_unwind_cache (next_frame, this_cache);
+
+  return info->base;
+}
+
+static CORE_ADDR
+m68hc11_frame_args_address (struct frame_info *next_frame, void **this_cache)
+{
+  CORE_ADDR addr;
+  struct m68hc11_unwind_cache *info
+    = m68hc11_frame_unwind_cache (next_frame, this_cache);
+
+  addr = info->base + info->size;
+  if (info->return_kind == RETURN_RTC)
+    addr += 1;
+  else if (info->return_kind == RETURN_RTI)
+    addr += 7;
+
+  return addr;
+}
+
+static const struct frame_base m68hc11_frame_base = {
+  &m68hc11_frame_unwind,
+  m68hc11_frame_base_address,
+  m68hc11_frame_base_address,
+  m68hc11_frame_args_address
+};
+
+static CORE_ADDR
+m68hc11_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  ULONGEST sp;
+  frame_unwind_unsigned_register (next_frame, HARD_SP_REGNUM, &sp);
+  return sp;
+}
+
+/* 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
+m68hc11_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  ULONGEST tos;
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+  frame_unwind_unsigned_register (next_frame, SOFT_FP_REGNUM, &tos);
+  tos += 2;
+  return frame_id_build (tos, pc);
+}
 
 \f
 /* Get and print the register from the given frame.  */
@@ -1410,10 +1676,6 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
   gdbarch = gdbarch_alloc (&info, tdep);
   tdep->elf_flags = elf_flags;
 
-  /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
-     ready to unwind the PC first (see frame.c:get_prev_frame()).  */
-  set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
-
   switch (info.bfd_arch_info->arch)
     {
     case bfd_arch_m68hc11:
@@ -1461,16 +1723,16 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
   /* Characters are unsigned.  */
   set_gdbarch_char_signed (gdbarch, 0);
 
+  set_gdbarch_unwind_pc (gdbarch, m68hc11_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, m68hc11_unwind_sp);
+
   /* Set register info.  */
   set_gdbarch_fp0_regnum (gdbarch, -1);
-  set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, m68hc11_frame_init_saved_regs);
   set_gdbarch_frame_args_skip (gdbarch, 0);
 
   set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
-  set_gdbarch_deprecated_dummy_write_sp (gdbarch, deprecated_write_sp);
 
   set_gdbarch_sp_regnum (gdbarch, HARD_SP_REGNUM);
-  set_gdbarch_deprecated_fp_regnum (gdbarch, SOFT_FP_REGNUM);
   set_gdbarch_register_name (gdbarch, m68hc11_register_name);
   set_gdbarch_register_type (gdbarch, m68hc11_register_type);
   set_gdbarch_pseudo_register_read (gdbarch, m68hc11_pseudo_register_read);
@@ -1478,27 +1740,15 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
 
   set_gdbarch_push_dummy_call (gdbarch, m68hc11_push_dummy_call);
 
-  set_gdbarch_deprecated_get_saved_register (gdbarch, deprecated_generic_get_saved_register);
   set_gdbarch_extract_return_value (gdbarch, m68hc11_extract_return_value);
   set_gdbarch_return_value_on_stack (gdbarch, m68hc11_return_value_on_stack);
 
-  set_gdbarch_deprecated_store_struct_return (gdbarch, m68hc11_store_struct_return);
   set_gdbarch_store_return_value (gdbarch, m68hc11_store_return_value);
   set_gdbarch_extract_struct_value_address (gdbarch, m68hc11_extract_struct_value_address);
 
-  set_gdbarch_deprecated_frame_chain (gdbarch, m68hc11_frame_chain);
-  set_gdbarch_deprecated_frame_saved_pc (gdbarch, m68hc11_frame_saved_pc);
-  set_gdbarch_deprecated_frame_args_address (gdbarch, m68hc11_frame_args_address);
-  set_gdbarch_deprecated_saved_pc_after_call (gdbarch, m68hc11_saved_pc_after_call);
-
-  set_gdbarch_deprecated_get_saved_register (gdbarch, deprecated_generic_get_saved_register);
-
-  set_gdbarch_deprecated_store_struct_return (gdbarch, m68hc11_store_struct_return);
   set_gdbarch_store_return_value (gdbarch, m68hc11_store_return_value);
   set_gdbarch_extract_struct_value_address (gdbarch, m68hc11_extract_struct_value_address);
   set_gdbarch_use_struct_convention (gdbarch, m68hc11_use_struct_convention);
-  set_gdbarch_deprecated_init_extra_frame_info (gdbarch, m68hc11_init_extra_frame_info);
-  set_gdbarch_deprecated_pop_frame (gdbarch, m68hc11_pop_frame);
   set_gdbarch_skip_prologue (gdbarch, m68hc11_skip_prologue);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_decr_pc_after_break (gdbarch, 0);
@@ -1511,6 +1761,21 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_register_reggroup_p (gdbarch, m68hc11_register_reggroup_p);
   set_gdbarch_print_registers_info (gdbarch, m68hc11_print_registers_info);
 
+  /* Hook in the DWARF CFI frame unwinder.  */
+  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+  set_gdbarch_dwarf2_build_frame_info (gdbarch, dwarf2_build_frame_info);
+
+  frame_unwind_append_predicate (gdbarch, m68hc11_frame_p);
+  frame_base_set_default (gdbarch, &m68hc11_frame_base);
+  
+  /* Methods for saving / extracting a dummy frame's ID.  The ID's
+     stack address must match the SP value returned by
+     PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos.  */
+  set_gdbarch_unwind_dummy_id (gdbarch, m68hc11_unwind_dummy_id);
+
+  /* Return the unwound PC value.  */
+  set_gdbarch_unwind_pc (gdbarch, m68hc11_unwind_pc);
+
   /* Minsymbol frobbing.  */
   set_gdbarch_elf_make_msymbol_special (gdbarch,
                                         m68hc11_elf_make_msymbol_special);