gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / microblaze-tdep.c
index dcf556fb63c3ad424e11a33f792be5d5b730af95..5c804133040df7ab0e9f03fecaffc0f4c3912279 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for Xilinx MicroBlaze.
 
-   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+   Copyright (C) 2009-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "inferior.h"
 #include "regcache.h"
 #include "target.h"
-#include "frame.h"
 #include "frame-base.h"
 #include "frame-unwind.h"
-#include "dwarf2-frame.h"
+#include "dwarf2/frame.h"
 #include "osabi.h"
-
-#include "gdb_assert.h"
-#include "gdb_string.h"
 #include "target-descriptions.h"
 #include "opcodes/microblaze-opcm.h"
 #include "opcodes/microblaze-dis.h"
 #include "microblaze-tdep.h"
+#include "remote.h"
+
+#include "features/microblaze-with-stack-protect.c"
+#include "features/microblaze.c"
 \f
 /* Instruction macros used for analyzing the prologue.  */
 /* This set of instruction macros need to be changed whenever the
@@ -74,14 +74,15 @@ static const char *microblaze_register_names[] =
   "rpc",  "rmsr", "rear", "resr", "rfsr", "rbtr",
   "rpvr0", "rpvr1", "rpvr2", "rpvr3", "rpvr4", "rpvr5", "rpvr6",
   "rpvr7", "rpvr8", "rpvr9", "rpvr10", "rpvr11",
-  "redr", "rpid", "rzpr", "rtlbx", "rtlbsx", "rtlblo", "rtlbhi"
+  "redr", "rpid", "rzpr", "rtlbx", "rtlbsx", "rtlblo", "rtlbhi",
+  "rslr", "rshr"
 };
 
 #define MICROBLAZE_NUM_REGS ARRAY_SIZE (microblaze_register_names)
 \f
 static unsigned int microblaze_debug_flag = 0;
 
-static void
+static void ATTRIBUTE_PRINTF (1, 2)
 microblaze_debug (const char *fmt, ...)
 { 
   if (microblaze_debug_flag)
@@ -127,45 +128,16 @@ microblaze_fetch_instruction (CORE_ADDR pc)
   gdb_byte buf[4];
 
   /* If we can't read the instruction at PC, return zero.  */
-  if (target_read_memory (pc, buf, sizeof (buf)))
+  if (target_read_code (pc, buf, sizeof (buf)))
     return 0;
 
   return extract_unsigned_integer (buf, 4, byte_order);
 }
 \f
+constexpr gdb_byte microblaze_break_insn[] = MICROBLAZE_BREAKPOINT;
 
-static CORE_ADDR
-microblaze_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
-                           CORE_ADDR funcaddr,
-                           struct value **args, int nargs,
-                           struct type *value_type,
-                           CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
-                           struct regcache *regcache)
-{
-  error (_("push_dummy_code not implemented"));
-  return sp;
-}
-
+typedef BP_MANIPULATION (microblaze_break_insn) microblaze_breakpoint;
 
-static CORE_ADDR
-microblaze_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
-                           struct regcache *regcache, CORE_ADDR bp_addr,
-                           int nargs, struct value **args, CORE_ADDR sp,
-                           int struct_return, CORE_ADDR struct_addr)
-{
-  error (_("store_arguments not implemented"));
-  return sp;
-}
-
-static const gdb_byte *
-microblaze_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc, 
-                              int *len)
-{
-  static gdb_byte break_insn[] = MICROBLAZE_BREAKPOINT;
-
-  *len = sizeof (break_insn);
-  return break_insn;
-}
 \f
 /* Allocate and initialize a frame cache.  */
 
@@ -381,12 +353,13 @@ microblaze_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
         instruction.  */
 
       {
-       unsigned op = (unsigned)insn >> 26;
+       unsigned ctrl_op = (unsigned)insn >> 26;
 
        /* continue if not control flow (branch, return).  */
-       if (op != 0x26 && op != 0x27 && op != 0x2d && op != 0x2e && op != 0x2f)
+       if (ctrl_op != 0x26 && ctrl_op != 0x27 && ctrl_op != 0x2d
+           && ctrl_op != 0x2e && ctrl_op != 0x2f)
          continue;
-       else if (op == 0x2c)
+       else if (ctrl_op == 0x2c)
          continue;    /* continue if imm.  */
       }
 
@@ -460,11 +433,10 @@ microblaze_frame_cache (struct frame_info *next_frame, void **this_cache)
 {
   struct microblaze_frame_cache *cache;
   struct gdbarch *gdbarch = get_frame_arch (next_frame);
-  CORE_ADDR func;
   int rn;
 
   if (*this_cache)
-    return *this_cache;
+    return (struct microblaze_frame_cache *) *this_cache;
 
   cache = microblaze_alloc_frame_cache ();
   *this_cache = cache;
@@ -474,7 +446,8 @@ microblaze_frame_cache (struct frame_info *next_frame, void **this_cache)
   for (rn = 0; rn < gdbarch_num_regs (gdbarch); rn++)
     cache->register_offsets[rn] = -1;
 
-  func = get_frame_func (next_frame);
+  /* Call for side effects.  */
+  get_frame_func (next_frame);
 
   cache->pc = get_frame_address_in_block (next_frame);
 
@@ -557,17 +530,17 @@ microblaze_extract_return_value (struct type *type, struct regcache *regcache,
   switch (TYPE_LENGTH (type))
     {
       case 1:  /* return last byte in the register.  */
-       regcache_cooked_read (regcache, MICROBLAZE_RETVAL_REGNUM, buf);
+       regcache->cooked_read (MICROBLAZE_RETVAL_REGNUM, buf);
        memcpy(valbuf, buf + MICROBLAZE_REGISTER_SIZE - 1, 1);
        return;
       case 2:  /* return last 2 bytes in register.  */
-       regcache_cooked_read (regcache, MICROBLAZE_RETVAL_REGNUM, buf);
+       regcache->cooked_read (MICROBLAZE_RETVAL_REGNUM, buf);
        memcpy(valbuf, buf + MICROBLAZE_REGISTER_SIZE - 2, 2);
        return;
       case 4:  /* for sizes 4 or 8, copy the required length.  */
       case 8:
-       regcache_cooked_read (regcache, MICROBLAZE_RETVAL_REGNUM, buf);
-       regcache_cooked_read (regcache, MICROBLAZE_RETVAL_REGNUM+1, buf+4);
+       regcache->cooked_read (MICROBLAZE_RETVAL_REGNUM, buf);
+       regcache->cooked_read (MICROBLAZE_RETVAL_REGNUM + 1, buf+4);
        memcpy (valbuf, buf, TYPE_LENGTH (type));
        return;
       default:
@@ -601,13 +574,13 @@ microblaze_store_return_value (struct type *type, struct regcache *regcache,
     {
        gdb_assert (len == 8);
        memcpy (buf, valbuf, 8);
-       regcache_cooked_write (regcache, MICROBLAZE_RETVAL_REGNUM+1, buf + 4);
+       regcache->cooked_write (MICROBLAZE_RETVAL_REGNUM+1, buf + 4);
     }
   else
     /* ??? Do we need to do any sign-extension here?  */
     memcpy (buf + 4 - len, valbuf, len);
 
-  regcache_cooked_write (regcache, MICROBLAZE_RETVAL_REGNUM, buf);
+  regcache->cooked_write (MICROBLAZE_RETVAL_REGNUM, buf);
 }
 
 static enum return_value_convention
@@ -629,11 +602,6 @@ microblaze_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
   return (TYPE_LENGTH (type) == 16);
 }
 
-static void
-microblaze_write_pc (struct regcache *regcache, CORE_ADDR pc)
-{
-  regcache_cooked_write_unsigned (regcache, MICROBLAZE_PC_REGNUM, pc);
-}
 \f
 static int dwarf2_to_reg_map[78] =
 { 0  /* r0  */,   1  /* r1  */,   2  /* r2  */,   3  /* r3  */,  /*  0- 3 */
@@ -661,8 +629,21 @@ static int dwarf2_to_reg_map[78] =
 static int
 microblaze_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int reg)
 {
-  gdb_assert (reg < sizeof (dwarf2_to_reg_map));
-  return dwarf2_to_reg_map[reg];
+  if (reg >= 0 && reg < sizeof (dwarf2_to_reg_map))
+    return dwarf2_to_reg_map[reg];
+  return -1;
+}
+
+static void
+microblaze_register_g_packet_guesses (struct gdbarch *gdbarch)
+{
+  register_remote_g_packet_guess (gdbarch,
+                                  4 * MICROBLAZE_NUM_CORE_REGS,
+                                  tdesc_microblaze);
+
+  register_remote_g_packet_guess (gdbarch,
+                                  4 * MICROBLAZE_NUM_REGS,
+                                  tdesc_microblaze_with_stack_protect);
 }
 
 static struct gdbarch *
@@ -670,14 +651,55 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
   struct gdbarch_tdep *tdep;
   struct gdbarch *gdbarch;
+  struct tdesc_arch_data *tdesc_data = NULL;
+  const struct target_desc *tdesc = info.target_desc;
 
   /* If there is already a candidate, use it.  */
   arches = gdbarch_list_lookup_by_info (arches, &info);
   if (arches != NULL)
     return arches->gdbarch;
+  if (tdesc == NULL)
+    tdesc = tdesc_microblaze;
+
+  /* Check any target description for validity.  */
+  if (tdesc_has_registers (tdesc))
+    {
+      const struct tdesc_feature *feature;
+      int valid_p;
+      int i;
+
+      feature = tdesc_find_feature (tdesc,
+                                    "org.gnu.gdb.microblaze.core");
+      if (feature == NULL)
+        return NULL;
+      tdesc_data = tdesc_data_alloc ();
+
+      valid_p = 1;
+      for (i = 0; i < MICROBLAZE_NUM_CORE_REGS; i++)
+        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                            microblaze_register_names[i]);
+      feature = tdesc_find_feature (tdesc,
+                                    "org.gnu.gdb.microblaze.stack-protect");
+      if (feature != NULL)
+        {
+          valid_p = 1;
+          valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                              MICROBLAZE_SLR_REGNUM,
+                                              "rslr");
+          valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                              MICROBLAZE_SHR_REGNUM,
+                                              "rshr");
+        }
+
+      if (!valid_p)
+        {
+          tdesc_data_cleanup (tdesc_data);
+          return NULL;
+        }
+    }
 
   /* Allocate space for the new architecture.  */
-  tdep = XMALLOC (struct gdbarch_tdep);
+  tdep = XCNEW (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
 
   set_gdbarch_long_double_bit (gdbarch, 128);
@@ -695,8 +717,6 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Call dummy code.  */
   set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
-  set_gdbarch_push_dummy_code (gdbarch, microblaze_push_dummy_code);
-  set_gdbarch_push_dummy_call (gdbarch, microblaze_push_dummy_call);
 
   set_gdbarch_return_value (gdbarch, microblaze_return_value);
   set_gdbarch_stabs_argument_has_addr
@@ -707,16 +727,17 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Stack grows downward.  */
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
 
-  set_gdbarch_breakpoint_from_pc (gdbarch, microblaze_breakpoint_from_pc);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch,
+                                      microblaze_breakpoint::kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch,
+                                      microblaze_breakpoint::bp_from_kind);
 
   set_gdbarch_frame_args_skip (gdbarch, 8);
 
-  set_gdbarch_print_insn (gdbarch, print_insn_microblaze);
-
-  set_gdbarch_write_pc (gdbarch, microblaze_write_pc);
-
   set_gdbarch_unwind_pc (gdbarch, microblaze_unwind_pc);
 
+  microblaze_register_g_packet_guesses (gdbarch);
+
   frame_base_set_default (gdbarch, &microblaze_frame_base);
 
   /* Hook in ABI-specific overrides, if they have been registered.  */
@@ -726,18 +747,20 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   dwarf2_append_unwinders (gdbarch);
   frame_unwind_append_unwinder (gdbarch, &microblaze_frame_unwind);
   frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+  if (tdesc_data != NULL)
+    tdesc_use_registers (gdbarch, tdesc, tdesc_data);
 
   return gdbarch;
 }
 
-/* Provide a prototype to silence -Wmissing-prototypes.  */
-void _initialize_microblaze_tdep (void);
-
+void _initialize_microblaze_tdep ();
 void
-_initialize_microblaze_tdep (void)
+_initialize_microblaze_tdep ()
 {
   register_gdbarch_init (bfd_arch_microblaze, microblaze_gdbarch_init);
 
+  initialize_tdesc_microblaze_with_stack_protect ();
+  initialize_tdesc_microblaze ();
   /* Debug this files internals.  */
   add_setshow_zuinteger_cmd ("microblaze", class_maintenance,
                             &microblaze_debug_flag, _("\
This page took 0.028413 seconds and 4 git commands to generate.