gdb/MAINTAINERS: add Luis Machado as global maintainer
[binutils-gdb.git] / gdb / rx-tdep.c
index de9eec634829068d77987031569d4e3c6ba2af68..87f1afd7a66a72a0394efa8cae817dd1a807cc88 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for the Renesas RX for GDB, the GNU debugger.
 
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008-2023 Free Software Foundation, Inc.
 
    Contributed by Red Hat, Inc.
 
 #include "frame-base.h"
 #include "value.h"
 #include "gdbcore.h"
-#include "dwarf2-frame.h"
+#include "dwarf2/frame.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "gdbarch.h"
+#include "inferior.h"
 
 #include "elf/rx.h"
 #include "elf-bfd.h"
+#include <algorithm>
+
+#include "features/rx.c"
 
 /* Certain important register numbers.  */
 enum
@@ -45,21 +52,43 @@ enum
   RX_R4_REGNUM = 4,
   RX_FP_REGNUM = 6,
   RX_R15_REGNUM = 15,
+  RX_USP_REGNUM = 16,
+  RX_PSW_REGNUM = 18,
   RX_PC_REGNUM = 19,
+  RX_BPSW_REGNUM = 21,
+  RX_BPC_REGNUM = 22,
+  RX_FPSW_REGNUM = 24,
   RX_ACC_REGNUM = 25,
   RX_NUM_REGS = 26
 };
 
+/* RX frame types.  */
+enum rx_frame_type {
+  RX_FRAME_TYPE_NORMAL,
+  RX_FRAME_TYPE_EXCEPTION,
+  RX_FRAME_TYPE_FAST_INTERRUPT
+};
+
 /* Architecture specific data.  */
-struct gdbarch_tdep
+struct rx_gdbarch_tdep : gdbarch_tdep_base
 {
   /* The ELF header flags specify the multilib used.  */
-  int elf_flags;
+  int elf_flags = 0;
+
+  /* Type of PSW and BPSW.  */
+  struct type *rx_psw_type = nullptr;
+
+  /* Type of FPSW.  */
+  struct type *rx_fpsw_type = nullptr;
 };
 
 /* This structure holds the results of a prologue analysis.  */
 struct rx_prologue
 {
+  /* Frame type, either a normal frame or one of two types of exception
+     frames.  */
+  enum rx_frame_type frame_type;
+
   /* The offset from the frame base to the stack pointer --- always
      zero or negative.
 
@@ -91,57 +120,17 @@ struct rx_prologue
   int reg_offset[RX_NUM_REGS];
 };
 
-/* Implement the "register_name" gdbarch method.  */
-static const char *
-rx_register_name (struct gdbarch *gdbarch, int regnr)
-{
-  static const char *const reg_names[] = {
-    "r0",
-    "r1",
-    "r2",
-    "r3",
-    "r4",
-    "r5",
-    "r6",
-    "r7",
-    "r8",
-    "r9",
-    "r10",
-    "r11",
-    "r12",
-    "r13",
-    "r14",
-    "r15",
-    "usp",
-    "isp",
-    "psw",
-    "pc",
-    "intb",
-    "bpsw",
-    "bpc",
-    "fintv",
-    "fpsw",
-    "acc"
-  };
-
-  return reg_names[regnr];
-}
-
-/* Implement the "register_type" gdbarch method.  */
-static struct type *
-rx_register_type (struct gdbarch *gdbarch, int reg_nr)
-{
-  if (reg_nr == RX_PC_REGNUM)
-    return builtin_type (gdbarch)->builtin_func_ptr;
-  else if (reg_nr == RX_ACC_REGNUM)
-    return builtin_type (gdbarch)->builtin_unsigned_long_long;
-  else
-    return builtin_type (gdbarch)->builtin_unsigned_long;
-}
+/* RX register names */
+static const char *const rx_register_names[] = {
+  "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+  "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+  "usp", "isp", "psw", "pc",  "intb", "bpsw","bpc","fintv",
+  "fpsw", "acc",
+};
 
 
 /* Function for finding saved registers in a 'struct pv_area'; this
-   function is passed to pv_area_scan.
+   function is passed to pv_area::scan.
 
    If VALUE is a saved register, ADDR says it was saved at a constant
    offset from the frame base, and SIZE indicates that the whole
@@ -154,7 +143,7 @@ check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
   if (value.kind == pvk_register
       && value.k == 0
       && pv_is_register (addr, RX_SP_REGNUM)
-      && size == register_size (target_gdbarch, value.reg))
+      && size == register_size (current_inferior ()->arch (), value.reg))
     result->reg_offset[value.reg] = addr.k;
 }
 
@@ -172,11 +161,12 @@ struct rx_get_opcode_byte_handle
 static int
 rx_get_opcode_byte (void *handle)
 {
-  struct rx_get_opcode_byte_handle *opcdata = handle;
+  struct rx_get_opcode_byte_handle *opcdata
+    = (struct rx_get_opcode_byte_handle *) handle;
   int status;
   gdb_byte byte;
 
-  status = target_read_memory (opcdata->pc, &byte, 1);
+  status = target_read_code (opcdata->pc, &byte, 1);
   if (status == 0)
     {
       opcdata->pc += 1;
@@ -188,31 +178,53 @@ rx_get_opcode_byte (void *handle)
 
 /* Analyze a prologue starting at START_PC, going no further than
    LIMIT_PC.  Fill in RESULT as appropriate.  */
+
 static void
-rx_analyze_prologue (CORE_ADDR start_pc,
-                    CORE_ADDR limit_pc, struct rx_prologue *result)
+rx_analyze_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
+                    enum rx_frame_type frame_type,
+                    struct rx_prologue *result)
 {
   CORE_ADDR pc, next_pc;
   int rn;
   pv_t reg[RX_NUM_REGS];
-  struct pv_area *stack;
-  struct cleanup *back_to;
   CORE_ADDR after_last_frame_setup_insn = start_pc;
 
   memset (result, 0, sizeof (*result));
 
+  result->frame_type = frame_type;
+
   for (rn = 0; rn < RX_NUM_REGS; rn++)
     {
       reg[rn] = pv_register (rn, 0);
       result->reg_offset[rn] = 1;
     }
 
-  stack = make_pv_area (RX_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
-  back_to = make_cleanup_free_pv_area (stack);
+  pv_area stack (RX_SP_REGNUM, gdbarch_addr_bit (current_inferior ()->arch ()));
+
+  if (frame_type == RX_FRAME_TYPE_FAST_INTERRUPT)
+    {
+      /* This code won't do anything useful at present, but this is
+        what happens for fast interrupts.  */
+      reg[RX_BPSW_REGNUM] = reg[RX_PSW_REGNUM];
+      reg[RX_BPC_REGNUM] = reg[RX_PC_REGNUM];
+    }
+  else
+    {
+      /* When an exception occurs, the PSW is saved to the interrupt stack
+        first.  */
+      if (frame_type == RX_FRAME_TYPE_EXCEPTION)
+       {
+         reg[RX_SP_REGNUM] = pv_add_constant (reg[RX_SP_REGNUM], -4);
+         stack.store (reg[RX_SP_REGNUM], 4, reg[RX_PSW_REGNUM]);
+       }
+
+      /* The call instruction (or an exception/interrupt) has saved the return
+         address on the stack.  */
+      reg[RX_SP_REGNUM] = pv_add_constant (reg[RX_SP_REGNUM], -4);
+      stack.store (reg[RX_SP_REGNUM], 4, reg[RX_PC_REGNUM]);
+
+    }
 
-  /* The call instruction has saved the return address on the stack.  */
-  reg[RX_SP_REGNUM] = pv_add_constant (reg[RX_SP_REGNUM], -4);
-  pv_area_store (stack, reg[RX_SP_REGNUM], 4, reg[RX_PC_REGNUM]);
 
   pc = start_pc;
   while (pc < limit_pc)
@@ -238,7 +250,7 @@ rx_analyze_prologue (CORE_ADDR start_pc,
          for (r = r2; r >= r1; r--)
            {
              reg[RX_SP_REGNUM] = pv_add_constant (reg[RX_SP_REGNUM], -4);
-             pv_area_store (stack, reg[RX_SP_REGNUM], 4, reg[r]);
+             stack.store (reg[RX_SP_REGNUM], 4, reg[r]);
            }
          after_last_frame_setup_insn = next_pc;
        }
@@ -265,7 +277,7 @@ rx_analyze_prologue (CORE_ADDR start_pc,
 
          rsrc = opc.op[1].reg;
          reg[RX_SP_REGNUM] = pv_add_constant (reg[RX_SP_REGNUM], -4);
-         pv_area_store (stack, reg[RX_SP_REGNUM], 4, reg[rsrc]);
+         stack.store (reg[RX_SP_REGNUM], 4, reg[rsrc]);
          after_last_frame_setup_insn = next_pc;
        }
       else if (opc.id == RXO_add       /* add #const, rsrc, rdst */
@@ -296,7 +308,6 @@ rx_analyze_prologue (CORE_ADDR start_pc,
        }
       else if (opc.id == RXO_branch
               && opc.op[0].type == RX_Operand_Immediate
-              && opc.op[1].type == RX_Operand_Condition
               && next_pc < opc.op[0].addend)
        {
          /* When a loop appears as the first statement of a function
@@ -342,11 +353,9 @@ rx_analyze_prologue (CORE_ADDR start_pc,
     }
 
   /* Record where all the registers were saved.  */
-  pv_area_scan (stack, check_for_saved, (void *) result);
+  stack.scan (check_for_saved, (void *) result);
 
   result->prologue_end = after_last_frame_setup_insn;
-
-  do_cleanups (back_to);
 }
 
 
@@ -354,7 +363,7 @@ rx_analyze_prologue (CORE_ADDR start_pc,
 static CORE_ADDR
 rx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
-  char *name;
+  const char *name;
   CORE_ADDR func_addr, func_end;
   struct rx_prologue p;
 
@@ -362,7 +371,9 @@ rx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
   if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
     return pc;
 
-  rx_analyze_prologue (pc, func_end, &p);
+  /* The frame type doesn't matter here, since we only care about
+     where the prologue ends.  We'll use RX_FRAME_TYPE_NORMAL.  */
+  rx_analyze_prologue (pc, func_end, RX_FRAME_TYPE_NORMAL, &p);
   return p.prologue_end;
 }
 
@@ -370,8 +381,10 @@ rx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
    associated function if there is not cache entry as specified by
    THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
    return that struct as the value of this function.  */
+
 static struct rx_prologue *
-rx_analyze_frame_prologue (struct frame_info *this_frame,
+rx_analyze_frame_prologue (frame_info_ptr this_frame,
+                          enum rx_frame_type frame_type,
                           void **this_prologue_cache)
 {
   if (!*this_prologue_cache)
@@ -384,23 +397,80 @@ rx_analyze_frame_prologue (struct frame_info *this_frame,
       stop_addr = get_frame_pc (this_frame);
 
       /* If we couldn't find any function containing the PC, then
-         just initialize the prologue cache, but don't do anything.  */
+        just initialize the prologue cache, but don't do anything.  */
       if (!func_start)
        stop_addr = func_start;
 
-      rx_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+      rx_analyze_prologue (func_start, stop_addr, frame_type,
+                          (struct rx_prologue *) *this_prologue_cache);
+    }
+
+  return (struct rx_prologue *) *this_prologue_cache;
+}
+
+/* Determine type of frame by scanning the function for a return
+   instruction.  */
+
+static enum rx_frame_type
+rx_frame_type (frame_info_ptr this_frame, void **this_cache)
+{
+  const char *name;
+  CORE_ADDR pc, start_pc, lim_pc;
+  int bytes_read;
+  struct rx_get_opcode_byte_handle opcode_handle;
+  RX_Opcode_Decoded opc;
+
+  gdb_assert (this_cache != NULL);
+
+  /* If we have a cached value, return it.  */
+
+  if (*this_cache != NULL)
+    {
+      struct rx_prologue *p = (struct rx_prologue *) *this_cache;
+
+      return p->frame_type;
     }
 
-  return *this_prologue_cache;
+  /* No cached value; scan the function.  The frame type is cached in
+     rx_analyze_prologue / rx_analyze_frame_prologue.  */
+  
+  pc = get_frame_pc (this_frame);
+  
+  /* Attempt to find the last address in the function.  If it cannot
+     be determined, set the limit to be a short ways past the frame's
+     pc.  */
+  if (!find_pc_partial_function (pc, &name, &start_pc, &lim_pc))
+    lim_pc = pc + 20;
+
+  while (pc < lim_pc)
+    {
+      opcode_handle.pc = pc;
+      bytes_read = rx_decode_opcode (pc, &opc, rx_get_opcode_byte,
+                                    &opcode_handle);
+
+      if (bytes_read <= 0 || opc.id == RXO_rts)
+       return RX_FRAME_TYPE_NORMAL;
+      else if (opc.id == RXO_rtfi)
+       return RX_FRAME_TYPE_FAST_INTERRUPT;
+      else if (opc.id == RXO_rte)
+       return RX_FRAME_TYPE_EXCEPTION;
+
+      pc += bytes_read;
+    }
+
+  return RX_FRAME_TYPE_NORMAL;
 }
 
+
 /* Given the next frame and a prologue cache, return this frame's
    base.  */
+
 static CORE_ADDR
-rx_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+rx_frame_base (frame_info_ptr this_frame, void **this_cache)
 {
+  enum rx_frame_type frame_type = rx_frame_type (this_frame, this_cache);
   struct rx_prologue *p
-    = rx_analyze_frame_prologue (this_frame, this_prologue_cache);
+    = rx_analyze_frame_prologue (this_frame, frame_type, this_cache);
 
   /* In functions that use alloca, the distance between the stack
      pointer and the frame base varies dynamically, so we can't use
@@ -421,81 +491,176 @@ rx_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
 }
 
 /* Implement the "frame_this_id" method for unwinding frames.  */
+
 static void
-rx_frame_this_id (struct frame_info *this_frame,
-                 void **this_prologue_cache, struct frame_id *this_id)
+rx_frame_this_id (frame_info_ptr this_frame, void **this_cache,
+                 struct frame_id *this_id)
 {
-  *this_id = frame_id_build (rx_frame_base (this_frame, this_prologue_cache),
+  *this_id = frame_id_build (rx_frame_base (this_frame, this_cache),
                             get_frame_func (this_frame));
 }
 
 /* Implement the "frame_prev_register" method for unwinding frames.  */
+
 static struct value *
-rx_frame_prev_register (struct frame_info *this_frame,
-                       void **this_prologue_cache, int regnum)
+rx_frame_prev_register (frame_info_ptr this_frame, void **this_cache,
+                       int regnum)
 {
+  enum rx_frame_type frame_type = rx_frame_type (this_frame, this_cache);
   struct rx_prologue *p
-    = rx_analyze_frame_prologue (this_frame, this_prologue_cache);
-  CORE_ADDR frame_base = rx_frame_base (this_frame, this_prologue_cache);
-  int reg_size = register_size (get_frame_arch (this_frame), regnum);
+    = rx_analyze_frame_prologue (this_frame, frame_type, this_cache);
+  CORE_ADDR frame_base = rx_frame_base (this_frame, this_cache);
 
   if (regnum == RX_SP_REGNUM)
-    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+    {
+      if (frame_type == RX_FRAME_TYPE_EXCEPTION)
+       {
+         struct value *psw_val;
+         CORE_ADDR psw;
+
+         psw_val = rx_frame_prev_register (this_frame, this_cache,
+                                           RX_PSW_REGNUM);
+         psw = extract_unsigned_integer
+           (psw_val->contents_all ().data (), 4,
+            gdbarch_byte_order (get_frame_arch (this_frame)));
+
+         if ((psw & 0x20000 /* U bit */) != 0)
+           return rx_frame_prev_register (this_frame, this_cache,
+                                          RX_USP_REGNUM);
+
+         /* Fall through for the case where U bit is zero.  */
+       }
+
+      return frame_unwind_got_constant (this_frame, regnum, frame_base);
+    }
+
+  if (frame_type == RX_FRAME_TYPE_FAST_INTERRUPT)
+    {
+      if (regnum == RX_PC_REGNUM)
+       return rx_frame_prev_register (this_frame, this_cache,
+                                      RX_BPC_REGNUM);
+      if (regnum == RX_PSW_REGNUM)
+       return rx_frame_prev_register (this_frame, this_cache,
+                                      RX_BPSW_REGNUM);
+    }
 
   /* If prologue analysis says we saved this register somewhere,
      return a description of the stack slot holding it.  */
-  else if (p->reg_offset[regnum] != 1)
+  if (p->reg_offset[regnum] != 1)
     return frame_unwind_got_memory (this_frame, regnum,
                                    frame_base + p->reg_offset[regnum]);
 
   /* Otherwise, presume we haven't changed the value of this
      register, and get it from the next frame.  */
-  else
-    return frame_unwind_got_register (this_frame, regnum, regnum);
+  return frame_unwind_got_register (this_frame, regnum, regnum);
 }
 
-static const struct frame_unwind rx_frame_unwind = {
-  NORMAL_FRAME,
-  rx_frame_this_id,
-  rx_frame_prev_register,
-  NULL,
-  default_frame_sniffer
-};
+/* Return TRUE if the frame indicated by FRAME_TYPE is a normal frame.  */
 
-/* Implement the "unwind_pc" gdbarch method.  */
-static CORE_ADDR
-rx_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+static int
+normal_frame_p (enum rx_frame_type frame_type)
 {
-  ULONGEST pc;
+  return (frame_type == RX_FRAME_TYPE_NORMAL);
+}
 
-  pc = frame_unwind_register_unsigned (this_frame, RX_PC_REGNUM);
-  return pc;
+/* Return TRUE if the frame indicated by FRAME_TYPE is an exception
+   frame.  */
+
+static int
+exception_frame_p (enum rx_frame_type frame_type)
+{
+  return (frame_type == RX_FRAME_TYPE_EXCEPTION
+         || frame_type == RX_FRAME_TYPE_FAST_INTERRUPT);
 }
 
-/* Implement the "unwind_sp" gdbarch method.  */
-static CORE_ADDR
-rx_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+/* Common code used by both normal and exception frame sniffers.  */
+
+static int
+rx_frame_sniffer_common (const struct frame_unwind *self,
+                        frame_info_ptr this_frame,
+                        void **this_cache,
+                        int (*sniff_p)(enum rx_frame_type) )
 {
-  ULONGEST sp;
+  gdb_assert (this_cache != NULL);
+
+  if (*this_cache == NULL)
+    {
+      enum rx_frame_type frame_type = rx_frame_type (this_frame, this_cache);
+
+      if (sniff_p (frame_type))
+       {
+         /* The call below will fill in the cache, including the frame
+            type.  */
+         (void) rx_analyze_frame_prologue (this_frame, frame_type, this_cache);
+
+         return 1;
+       }
+      else
+       return 0;
+    }
+  else
+    {
+      struct rx_prologue *p = (struct rx_prologue *) *this_cache;
 
-  sp = frame_unwind_register_unsigned (this_frame, RX_SP_REGNUM);
-  return sp;
+      return sniff_p (p->frame_type);
+    }
 }
 
-/* Implement the "dummy_id" gdbarch method.  */
-static struct frame_id
-rx_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+/* Frame sniffer for normal (non-exception) frames.  */
+
+static int
+rx_frame_sniffer (const struct frame_unwind *self,
+                 frame_info_ptr this_frame,
+                 void **this_cache)
 {
-  return
-    frame_id_build (get_frame_register_unsigned (this_frame, RX_SP_REGNUM),
-                   get_frame_pc (this_frame));
+  return rx_frame_sniffer_common (self, this_frame, this_cache,
+                                 normal_frame_p);
 }
 
+/* Frame sniffer for exception frames.  */
+
+static int
+rx_exception_sniffer (const struct frame_unwind *self,
+                            frame_info_ptr this_frame,
+                            void **this_cache)
+{
+  return rx_frame_sniffer_common (self, this_frame, this_cache,
+                                 exception_frame_p);
+}
+
+/* Data structure for normal code using instruction-based prologue
+   analyzer.  */
+
+static const struct frame_unwind rx_frame_unwind = {
+  "rx prologue",
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  rx_frame_this_id,
+  rx_frame_prev_register,
+  NULL,
+  rx_frame_sniffer
+};
+
+/* Data structure for exception code using instruction-based prologue
+   analyzer.  */
+
+static const struct frame_unwind rx_exception_unwind = {
+  "rx exception",
+  /* SIGTRAMP_FRAME could be used here, but backtraces are less informative.  */
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  rx_frame_this_id,
+  rx_frame_prev_register,
+  NULL,
+  rx_exception_sniffer
+};
+
 /* Implement the "push_dummy_call" gdbarch method.  */
 static CORE_ADDR
 rx_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,
+                   struct value **args, CORE_ADDR sp,
+                   function_call_return_method return_method,
                    CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -504,15 +669,15 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   CORE_ADDR cfa;
   int num_register_candidate_args;
 
-  struct type *func_type = value_type (function);
+  struct type *func_type = function->type ();
 
   /* Dereference function pointer types.  */
-  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
-    func_type = TYPE_TARGET_TYPE (func_type);
+  while (func_type->code () == TYPE_CODE_PTR)
+    func_type = func_type->target_type ();
 
   /* The end result had better be a function or a method.  */
-  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
-             || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+  gdb_assert (func_type->code () == TYPE_CODE_FUNC
+             || func_type->code () == TYPE_CODE_METHOD);
 
   /* Functions with a variable number of arguments have all of their
      variable arguments and the last non-variable argument passed
@@ -525,8 +690,8 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      requiring multiple registers, etc.  We rely instead on the value
      of the ``arg_reg'' variable to get these other details correct.  */
 
-  if (TYPE_VARARGS (func_type))
-    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  if (func_type->has_varargs ())
+    num_register_candidate_args = func_type->num_fields () - 1;
   else
     num_register_candidate_args = 4;
 
@@ -541,15 +706,15 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        sp = align_down (sp - sp_off, 4);
       sp_off = 0;
 
-      if (struct_return)
+      if (return_method == return_method_struct)
        {
-         struct type *return_type = TYPE_TARGET_TYPE (func_type);
+         struct type *return_type = func_type->target_type ();
 
-         gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
-                     || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+         gdb_assert (return_type->code () == TYPE_CODE_STRUCT
+                     || func_type->code () == TYPE_CODE_UNION);
 
-         if (TYPE_LENGTH (return_type) > 16
-             || TYPE_LENGTH (return_type) % 4 != 0)
+         if (return_type->length () > 16
+             || return_type->length () % 4 != 0)
            {
              if (write_pass)
                regcache_cooked_write_unsigned (regcache, RX_R15_REGNUM,
@@ -561,24 +726,26 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       for (i = 0; i < nargs; i++)
        {
          struct value *arg = args[i];
-         const gdb_byte *arg_bits = value_contents_all (arg);
-         struct type *arg_type = check_typedef (value_type (arg));
-         ULONGEST arg_size = TYPE_LENGTH (arg_type);
+         const gdb_byte *arg_bits = arg->contents_all ().data ();
+         struct type *arg_type = check_typedef (arg->type ());
+         ULONGEST arg_size = arg_type->length ();
 
-         if (i == 0 && struct_addr != 0 && !struct_return
-             && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+         if (i == 0 && struct_addr != 0
+             && return_method != return_method_struct
+             && arg_type->code () == TYPE_CODE_PTR
              && extract_unsigned_integer (arg_bits, 4,
                                           byte_order) == struct_addr)
            {
              /* This argument represents the address at which C++ (and
-                possibly other languages) store their return value.
-                Put this value in R15.  */
+                possibly other languages) store their return value.
+                Put this value in R15.  */
              if (write_pass)
                regcache_cooked_write_unsigned (regcache, RX_R15_REGNUM,
                                                struct_addr);
            }
-         else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
-                  && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+         else if (arg_type->code () != TYPE_CODE_STRUCT
+                  && arg_type->code () != TYPE_CODE_UNION
+                  && arg_size <= 8)
            {
              /* Argument is a scalar.  */
              if (arg_size == 8)
@@ -587,8 +754,8 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      && arg_reg <= RX_R4_REGNUM - 1)
                    {
                      /* If argument registers are going to be used to pass
-                        an 8 byte scalar, the ABI specifies that two registers
-                        must be available.  */
+                        an 8 byte scalar, the ABI specifies that two registers
+                        must be available.  */
                      if (write_pass)
                        {
                          regcache_cooked_write_unsigned (regcache, arg_reg,
@@ -632,12 +799,12 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                    {
                      int p_arg_size = 4;
 
-                     if (TYPE_PROTOTYPED (func_type)
-                         && i < TYPE_NFIELDS (func_type))
+                     if (func_type->is_prototyped ()
+                         && i < func_type->num_fields ())
                        {
                          struct type *p_arg_type =
-                           TYPE_FIELD_TYPE (func_type, i);
-                         p_arg_size = TYPE_LENGTH (p_arg_type);
+                           func_type->field (i).type ();
+                         p_arg_size = p_arg_type->length ();
                        }
 
                      sp_off = align_up (sp_off, p_arg_size);
@@ -653,7 +820,7 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          else
            {
              /* Argument is a struct or union.  Pass as much of the struct
-                in registers, if possible.  Pass the rest on the stack.  */
+                in registers, if possible.  Pass the rest on the stack.  */
              while (arg_size > 0)
                {
                  if (i < num_register_candidate_args
@@ -661,7 +828,7 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      && arg_size <= 4 * (RX_R4_REGNUM - arg_reg + 1)
                      && arg_size % 4 == 0)
                    {
-                     int len = min (arg_size, 4);
+                     int len = std::min (arg_size, (ULONGEST) 4);
 
                      if (write_pass)
                        regcache_cooked_write_unsigned (regcache, arg_reg,
@@ -702,18 +869,18 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 /* Implement the "return_value" gdbarch method.  */
 static enum return_value_convention
 rx_return_value (struct gdbarch *gdbarch,
-                struct type *func_type,
+                struct value *function,
                 struct type *valtype,
                 struct regcache *regcache,
                 gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+  ULONGEST valtype_len = valtype->length ();
 
-  if (TYPE_LENGTH (valtype) > 16
-      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
-          || TYPE_CODE (valtype) == TYPE_CODE_UNION)
-         && TYPE_LENGTH (valtype) % 4 != 0))
+  if (valtype->length () > 16
+      || ((valtype->code () == TYPE_CODE_STRUCT
+          || valtype->code () == TYPE_CODE_UNION)
+         && valtype->length () % 4 != 0))
     return RETURN_VALUE_STRUCT_CONVENTION;
 
   if (readbuf)
@@ -724,7 +891,7 @@ rx_return_value (struct gdbarch *gdbarch,
 
       while (valtype_len > 0)
        {
-         int len = min (valtype_len, 4);
+         int len = std::min (valtype_len, (ULONGEST) 4);
 
          regcache_cooked_read_unsigned (regcache, argreg, &u);
          store_unsigned_integer (readbuf + offset, len, byte_order, u);
@@ -742,7 +909,7 @@ rx_return_value (struct gdbarch *gdbarch,
 
       while (valtype_len > 0)
        {
-         int len = min (valtype_len, 4);
+         int len = std::min (valtype_len, (ULONGEST) 4);
 
          u = extract_unsigned_integer (writebuf + offset, len, byte_order);
          regcache_cooked_write_unsigned (regcache, argreg, u);
@@ -755,22 +922,32 @@ rx_return_value (struct gdbarch *gdbarch,
   return RETURN_VALUE_REGISTER_CONVENTION;
 }
 
-/* Implement the "breakpoint_from_pc" gdbarch method.  */
-const gdb_byte *
-rx_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
+constexpr gdb_byte rx_break_insn[] = { 0x00 };
+
+typedef BP_MANIPULATION (rx_break_insn) rx_breakpoint;
+
+/* Implement the dwarf_reg_to_regnum" gdbarch method.  */
+
+static int
+rx_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
 {
-  static gdb_byte breakpoint[] = { 0x00 };
-  *lenptr = sizeof breakpoint;
-  return breakpoint;
+  if (0 <= reg && reg <= 15)
+    return reg;
+  else if (reg == 16)
+    return RX_PSW_REGNUM;
+  else if (reg == 17)
+    return RX_PC_REGNUM;
+  else
+    return -1;
 }
 
 /* Allocate and initialize a gdbarch object.  */
 static struct gdbarch *
 rx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
-  struct gdbarch *gdbarch;
-  struct gdbarch_tdep *tdep;
   int elf_flags;
+  tdesc_arch_data_up tdesc_data;
+  const struct target_desc *tdesc = info.target_desc;
 
   /* Extract the elf_flags if available.  */
   if (info.abfd != NULL
@@ -786,34 +963,58 @@ rx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        arches != NULL;
        arches = gdbarch_list_lookup_by_info (arches->next, &info))
     {
-      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+      rx_gdbarch_tdep *tdep
+       = gdbarch_tdep<rx_gdbarch_tdep> (arches->gdbarch);
+
+      if (tdep->elf_flags != elf_flags)
        continue;
 
       return arches->gdbarch;
     }
 
-  /* None found, create a new architecture from the information
-     provided.  */
-  tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
-  gdbarch = gdbarch_alloc (&info, tdep);
+  if (tdesc == NULL)
+      tdesc = tdesc_rx;
+
+  /* Check any target description for validity.  */
+  if (tdesc_has_registers (tdesc))
+    {
+      const struct tdesc_feature *feature;
+      bool valid_p = true;
+
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.rx.core");
+
+      if (feature != NULL)
+       {
+         tdesc_data = tdesc_data_alloc ();
+         for (int i = 0; i < RX_NUM_REGS; i++)
+           valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i,
+                                               rx_register_names[i]);
+       }
+
+      if (!valid_p)
+       return NULL;
+    }
+
+  gdb_assert(tdesc_data != NULL);
+
+  gdbarch *gdbarch
+    = gdbarch_alloc (&info, gdbarch_tdep_up (new rx_gdbarch_tdep));
+  rx_gdbarch_tdep *tdep = gdbarch_tdep<rx_gdbarch_tdep> (gdbarch);
+
   tdep->elf_flags = elf_flags;
 
   set_gdbarch_num_regs (gdbarch, RX_NUM_REGS);
+  tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
+
   set_gdbarch_num_pseudo_regs (gdbarch, 0);
-  set_gdbarch_register_name (gdbarch, rx_register_name);
-  set_gdbarch_register_type (gdbarch, rx_register_type);
   set_gdbarch_pc_regnum (gdbarch, RX_PC_REGNUM);
   set_gdbarch_sp_regnum (gdbarch, RX_SP_REGNUM);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_decr_pc_after_break (gdbarch, 1);
-  set_gdbarch_breakpoint_from_pc (gdbarch, rx_breakpoint_from_pc);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch, rx_breakpoint::kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch, rx_breakpoint::bp_from_kind);
   set_gdbarch_skip_prologue (gdbarch, rx_skip_prologue);
 
-  set_gdbarch_print_insn (gdbarch, print_insn_rx);
-
-  set_gdbarch_unwind_pc (gdbarch, rx_unwind_pc);
-  set_gdbarch_unwind_sp (gdbarch, rx_unwind_sp);
-
   /* Target builtin data types.  */
   set_gdbarch_char_signed (gdbarch, 0);
   set_gdbarch_short_bit (gdbarch, 16);
@@ -823,6 +1024,7 @@ rx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_ptr_bit (gdbarch, 32);
   set_gdbarch_float_bit (gdbarch, 32);
   set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+
   if (elf_flags & E_FLAG_RX_64BIT_DOUBLES)
     {
       set_gdbarch_double_bit (gdbarch, 64);
@@ -838,18 +1040,16 @@ rx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_long_double_format (gdbarch, floatformats_ieee_single);
     }
 
+  /* DWARF register mapping.  */
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, rx_dwarf_reg_to_regnum);
+
   /* Frame unwinding.  */
-#if 0
-  /* Note: The test results are better with the dwarf2 unwinder disabled,
-     so it's turned off for now.  */
+  frame_unwind_append_unwinder (gdbarch, &rx_exception_unwind);
   dwarf2_append_unwinders (gdbarch);
-#endif
   frame_unwind_append_unwinder (gdbarch, &rx_frame_unwind);
 
-  /* 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_dummy_id (gdbarch, rx_dummy_id);
+  /* Methods setting up a dummy call, and extracting the return value from
+     a call.  */
   set_gdbarch_push_dummy_call (gdbarch, rx_push_dummy_call);
   set_gdbarch_return_value (gdbarch, rx_return_value);
 
@@ -860,8 +1060,11 @@ rx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 }
 
 /* Register the above initialization routine.  */
+
+void _initialize_rx_tdep ();
 void
-_initialize_rx_tdep (void)
+_initialize_rx_tdep ()
 {
-  register_gdbarch_init (bfd_arch_rx, rx_gdbarch_init);
+  gdbarch_register (bfd_arch_rx, rx_gdbarch_init);
+  initialize_tdesc_rx ();
 }