+2018-12-19  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * gdb/dummy-frame.c (default_dummy_id): Defined new function.
+       * gdb/dummy-frame.h (default_dummy_id): Declare new function.
+       * gdb/frame-unwind.c (default_unwind_pc): Define new function.
+       (default_unwind_sp): Define new function.
+       * gdb/frame-unwind.h (default_unwind_pc): Declare new function.
+       (default_unwind_sp): Declare new function.
+       * gdb/frame.c (frame_unwind_pc): Assume gdbarch_unwind_pc is
+       available.
+       (get_frame_sp): Assume that gdbarch_unwind_sp is available.
+       * gdb/gdbarch.c: Regenerate.
+       * gdb/gdbarch.h: Regenerate.
+       * gdb/gdbarch.sh: Update definition of dummy_id, unwind_pc, and
+       unwind_sp.  Add additional header files to be included in
+       generated file.
+
 2018-12-19  Dimitar Dimitrov  <dimitar@dinux.eu>
 
        * nat/linux-ptrace.c (linux_ptrace_test_ret_to_nx): Remove
 
   dummy_frame_sniffer,
 };
 
+/* See dummy-frame.h.  */
+
+struct frame_id
+default_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  CORE_ADDR sp, pc;
+
+  sp = get_frame_sp (this_frame);
+  pc = get_frame_pc (this_frame);
+  return frame_id_build (sp, pc);
+}
+
 static void
 fprint_dummy_frames (struct ui_file *file)
 {
 
 extern int find_dummy_frame_dtor (dummy_frame_dtor_ftype *dtor,
                                  void *dtor_data);
 
+/* Default implementation of gdbarch_dummy_id.  Generate a dummy frame_id
+   for THIS_FRAME assuming that the frame is a dummy frame.  */
+
+extern struct frame_id default_dummy_id (struct gdbarch *gdbarch,
+                                        struct frame_info *this_frame);
+
 #endif /* !defined (DUMMY_FRAME_H)  */
 
     return UNWIND_NO_REASON;
 }
 
+/* See frame-unwind.h.  */
+
+CORE_ADDR
+default_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  int pc_regnum = gdbarch_pc_regnum (gdbarch);
+  CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, pc_regnum);
+  pc = gdbarch_addr_bits_remove (gdbarch, pc);
+  return pc;
+}
+
+/* See frame-unwind.h.  */
+
+CORE_ADDR
+default_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  int sp_regnum = gdbarch_sp_regnum (gdbarch);
+  return frame_unwind_register_unsigned (next_frame, sp_regnum);
+}
+
 /* Helper functions for value-based register unwinding.  These return
    a (possibly lazy) value of the appropriate type.  */
 
 
   default_frame_unwind_stop_reason (struct frame_info *this_frame,
                                    void **this_cache);
 
+/* A default unwind_pc callback that simply unwinds the register identified
+   by GDBARCH_PC_REGNUM.  */
+
+extern CORE_ADDR default_unwind_pc (struct gdbarch *gdbarch,
+                                   struct frame_info *next_frame);
+
+/* A default unwind_sp callback that simply unwinds the register identified
+   by GDBARCH_SP_REGNUM.  */
+
+extern CORE_ADDR default_unwind_sp (struct gdbarch *gdbarch,
+                                   struct frame_info *next_frame);
+
 /* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
    use THIS frame, and through it the NEXT frame's register unwind
    method, to determine the frame ID of THIS frame.
 
 {
   if (this_frame->prev_pc.status == CC_UNKNOWN)
     {
-      if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame)))
+      struct gdbarch *prev_gdbarch;
+      CORE_ADDR pc = 0;
+      int pc_p = 0;
+
+      /* 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 (this_frame, ISA_PC_REGNUM, buf);
+        return extract_unsigned_integer (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.  */
+      prev_gdbarch = frame_unwind_arch (this_frame);
+
+      TRY
        {
-         struct gdbarch *prev_gdbarch;
-         CORE_ADDR pc = 0;
-         int pc_p = 0;
-
-         /* 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 (this_frame, ISA_PC_REGNUM, buf);
-            return extract_unsigned_integer (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.  */
-         prev_gdbarch = frame_unwind_arch (this_frame);
-
-         TRY
+         pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
+         pc_p = 1;
+       }
+      CATCH (ex, RETURN_MASK_ERROR)
+       {
+         if (ex.error == NOT_AVAILABLE_ERROR)
            {
-             pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
-             pc_p = 1;
+             this_frame->prev_pc.status = CC_UNAVAILABLE;
+
+             if (frame_debug)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "{ frame_unwind_pc (this_frame=%d)"
+                                   " -> <unavailable> }\n",
+                                   this_frame->level);
            }
-         CATCH (ex, RETURN_MASK_ERROR)
+         else if (ex.error == OPTIMIZED_OUT_ERROR)
            {
-             if (ex.error == NOT_AVAILABLE_ERROR)
-               {
-                 this_frame->prev_pc.status = CC_UNAVAILABLE;
-
-                 if (frame_debug)
-                   fprintf_unfiltered (gdb_stdlog,
-                                       "{ frame_unwind_pc (this_frame=%d)"
-                                       " -> <unavailable> }\n",
-                                       this_frame->level);
-               }
-             else if (ex.error == OPTIMIZED_OUT_ERROR)
-               {
-                 this_frame->prev_pc.status = CC_NOT_SAVED;
-
-                 if (frame_debug)
-                   fprintf_unfiltered (gdb_stdlog,
-                                       "{ frame_unwind_pc (this_frame=%d)"
-                                       " -> <not saved> }\n",
-                                       this_frame->level);
-               }
-             else
-               throw_exception (ex);
-           }
-         END_CATCH
+             this_frame->prev_pc.status = CC_NOT_SAVED;
 
-         if (pc_p)
-           {
-             this_frame->prev_pc.value = pc;
-             this_frame->prev_pc.status = CC_VALUE;
              if (frame_debug)
                fprintf_unfiltered (gdb_stdlog,
-                                   "{ frame_unwind_pc (this_frame=%d) "
-                                   "-> %s }\n",
-                                   this_frame->level,
-                                   hex_string (this_frame->prev_pc.value));
+                                   "{ frame_unwind_pc (this_frame=%d)"
+                                   " -> <not saved> }\n",
+                                   this_frame->level);
            }
+         else
+           throw_exception (ex);
+       }
+      END_CATCH
+
+      if (pc_p)
+       {
+         this_frame->prev_pc.value = pc;
+         this_frame->prev_pc.status = CC_VALUE;
+         if (frame_debug)
+           fprintf_unfiltered (gdb_stdlog,
+                               "{ frame_unwind_pc (this_frame=%d) "
+                               "-> %s }\n",
+                               this_frame->level,
+                               hex_string (this_frame->prev_pc.value));
        }
-      else
-       internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
     }
 
   if (this_frame->prev_pc.status == CC_VALUE)
 {
   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))
-    /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to
-       operate on THIS_FRAME now.  */
-    return gdbarch_unwind_sp (gdbarch, this_frame->next);
-  /* Now things are really are grim.  Hope that the value returned by
-     the gdbarch_sp_regnum register is meaningful.  */
-  if (gdbarch_sp_regnum (gdbarch) >= 0)
-    return get_frame_register_unsigned (this_frame,
-                                       gdbarch_sp_regnum (gdbarch));
-  internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
+  /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to
+     operate on THIS_FRAME now.  */
+  return gdbarch_unwind_sp (gdbarch, this_frame->next);
 }
 
 /* Return the reason why we can't unwind past FRAME.  */
 
 #include "regcache.h"
 #include "objfiles.h"
 #include "auxv.h"
+#include "frame-unwind.h"
+#include "dummy-frame.h"
 
 /* Static function declarations */
 
   gdbarch->ecoff_reg_to_regnum = no_op_reg_to_regnum;
   gdbarch->sdb_reg_to_regnum = no_op_reg_to_regnum;
   gdbarch->dwarf2_reg_to_regnum = no_op_reg_to_regnum;
+  gdbarch->dummy_id = default_dummy_id;
   gdbarch->deprecated_fp_regnum = -1;
   gdbarch->call_dummy_location = AT_ENTRY_POINT;
   gdbarch->code_of_frame_writable = default_code_of_frame_writable;
   gdbarch->memory_insert_breakpoint = default_memory_insert_breakpoint;
   gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint;
   gdbarch->remote_register_number = default_remote_register_number;
+  gdbarch->unwind_pc = default_unwind_pc;
+  gdbarch->unwind_sp = default_unwind_sp;
   gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
   gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity;
   gdbarch->addr_bits_remove = core_addr_identity;
   if (gdbarch->register_name == 0)
     log.puts ("\n\tregister_name");
   /* Skip verify of register_type, has predicate.  */
-  /* Skip verify of dummy_id, has predicate.  */
+  /* Skip verify of dummy_id, invalid_p == 0 */
   /* Skip verify of deprecated_fp_regnum, invalid_p == 0 */
   /* Skip verify of push_dummy_call, has predicate.  */
   /* Skip verify of call_dummy_location, invalid_p == 0 */
   /* Skip verify of remote_register_number, invalid_p == 0 */
   /* Skip verify of fetch_tls_load_module_address, has predicate.  */
   /* Skip verify of frame_args_skip, invalid_p == 0 */
-  /* Skip verify of unwind_pc, has predicate.  */
-  /* Skip verify of unwind_sp, has predicate.  */
+  /* Skip verify of unwind_pc, invalid_p == 0 */
+  /* Skip verify of unwind_sp, invalid_p == 0 */
   /* Skip verify of frame_num_args, has predicate.  */
   /* Skip verify of frame_align, has predicate.  */
   /* Skip verify of stabs_argument_has_addr, invalid_p == 0 */
   fprintf_unfiltered (file,
                       "gdbarch_dump: dtrace_probe_is_enabled = <%s>\n",
                       host_address_to_string (gdbarch->dtrace_probe_is_enabled));
-  fprintf_unfiltered (file,
-                      "gdbarch_dump: gdbarch_dummy_id_p() = %d\n",
-                      gdbarch_dummy_id_p (gdbarch));
   fprintf_unfiltered (file,
                       "gdbarch_dump: dummy_id = <%s>\n",
                       host_address_to_string (gdbarch->dummy_id));
   fprintf_unfiltered (file,
                       "gdbarch_dump: type_align = <%s>\n",
                       host_address_to_string (gdbarch->type_align));
-  fprintf_unfiltered (file,
-                      "gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
-                      gdbarch_unwind_pc_p (gdbarch));
   fprintf_unfiltered (file,
                       "gdbarch_dump: unwind_pc = <%s>\n",
                       host_address_to_string (gdbarch->unwind_pc));
-  fprintf_unfiltered (file,
-                      "gdbarch_dump: gdbarch_unwind_sp_p() = %d\n",
-                      gdbarch_unwind_sp_p (gdbarch));
   fprintf_unfiltered (file,
                       "gdbarch_dump: unwind_sp = <%s>\n",
                       host_address_to_string (gdbarch->unwind_sp));
   gdbarch->register_type = register_type;
 }
 
-int
-gdbarch_dummy_id_p (struct gdbarch *gdbarch)
-{
-  gdb_assert (gdbarch != NULL);
-  return gdbarch->dummy_id != NULL;
-}
-
 struct frame_id
 gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
   gdbarch->frame_args_skip = frame_args_skip;
 }
 
-int
-gdbarch_unwind_pc_p (struct gdbarch *gdbarch)
-{
-  gdb_assert (gdbarch != NULL);
-  return gdbarch->unwind_pc != NULL;
-}
-
 CORE_ADDR
 gdbarch_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   gdbarch->unwind_pc = unwind_pc;
 }
 
-int
-gdbarch_unwind_sp_p (struct gdbarch *gdbarch)
-{
-  gdb_assert (gdbarch != NULL);
-  return gdbarch->unwind_sp != NULL;
-}
-
 CORE_ADDR
 gdbarch_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
 
 extern struct type * gdbarch_register_type (struct gdbarch *gdbarch, int reg_nr);
 extern void set_gdbarch_register_type (struct gdbarch *gdbarch, gdbarch_register_type_ftype *register_type);
 
-extern int gdbarch_dummy_id_p (struct gdbarch *gdbarch);
+/* Generate a dummy frame_id for THIS_FRAME assuming that the frame is
+   a dummy frame.  A dummy frame is created before an inferior call,
+   the frame_id returned here must match the frame_id that was built
+   for the inferior call.  Usually this means the returned frame_id's
+   stack address should match the address returned by
+   gdbarch_push_dummy_call, and the returned frame_id's code address
+   should match the address at which the breakpoint was set in the dummy
+   frame. */
 
 typedef struct frame_id (gdbarch_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame);
 extern struct frame_id gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame);
 extern CORE_ADDR gdbarch_frame_args_skip (struct gdbarch *gdbarch);
 extern void set_gdbarch_frame_args_skip (struct gdbarch *gdbarch, CORE_ADDR frame_args_skip);
 
-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);
 
-extern int gdbarch_unwind_sp_p (struct gdbarch *gdbarch);
-
 typedef CORE_ADDR (gdbarch_unwind_sp_ftype) (struct gdbarch *gdbarch, struct frame_info *next_frame);
 extern CORE_ADDR gdbarch_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame);
 extern void set_gdbarch_unwind_sp (struct gdbarch *gdbarch, gdbarch_unwind_sp_ftype *unwind_sp);
 
 # use "register_type".
 M;struct type *;register_type;int reg_nr;reg_nr
 
-M;struct frame_id;dummy_id;struct frame_info *this_frame;this_frame
+# Generate a dummy frame_id for THIS_FRAME assuming that the frame is
+# a dummy frame.  A dummy frame is created before an inferior call,
+# the frame_id returned here must match the frame_id that was built
+# for the inferior call.  Usually this means the returned frame_id's
+# stack address should match the address returned by
+# gdbarch_push_dummy_call, and the returned frame_id's code address
+# should match the address at which the breakpoint was set in the dummy
+# frame.
+m;struct frame_id;dummy_id;struct frame_info *this_frame;this_frame;;default_dummy_id;;0
 # Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
 # deprecated_fp_regnum.
 v;int;deprecated_fp_regnum;;;-1;-1;;0
 F;CORE_ADDR;fetch_tls_load_module_address;struct objfile *objfile;objfile
 #
 v;CORE_ADDR;frame_args_skip;;;0;;;0
-M;CORE_ADDR;unwind_pc;struct frame_info *next_frame;next_frame
-M;CORE_ADDR;unwind_sp;struct frame_info *next_frame;next_frame
+m;CORE_ADDR;unwind_pc;struct frame_info *next_frame;next_frame;;default_unwind_pc;;0
+m;CORE_ADDR;unwind_sp;struct frame_info *next_frame;next_frame;;default_unwind_sp;;0
 # DEPRECATED_FRAME_LOCALS_ADDRESS as been replaced by the per-frame
 # frame-base.  Enable frame-base before frame-unwind.
 F;int;frame_num_args;struct frame_info *frame;frame
 #include "regcache.h"
 #include "objfiles.h"
 #include "auxv.h"
+#include "frame-unwind.h"
+#include "dummy-frame.h"
 
 /* Static function declarations */