[Ada] Re-implement `info tasks' command using ui-out
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index 5d2b6322a82c6066b0e3988b3ed89d14cfd11de6..1a75af14bcdec9b09235415b48ad80ba2193a079 100644 (file)
 #include "vec.h"
 
 #include "features/arm-with-m.c"
+#include "features/arm-with-iwmmxt.c"
+#include "features/arm-with-vfpv2.c"
+#include "features/arm-with-vfpv3.c"
+#include "features/arm-with-neon.c"
 
 static int arm_debug;
 
@@ -133,6 +137,13 @@ static const char *arm_mode_strings[] =
 static const char *arm_fallback_mode_string = "auto";
 static const char *arm_force_mode_string = "auto";
 
+/* Internal override of the execution mode.  -1 means no override,
+   0 means override to ARM mode, 1 means override to Thumb mode.
+   The effect is the same as if arm_force_mode has been set by the
+   user (except the internal override has precedence over a user's
+   arm_force_mode override).  */
+static int arm_override_mode = -1;
+
 /* Number of different reg name sets (options).  */
 static int num_disassembly_options;
 
@@ -213,9 +224,9 @@ static void convert_from_extended (const struct floatformat *, const void *,
 static void convert_to_extended (const struct floatformat *, void *,
                                 const void *, int);
 
-static void arm_neon_quad_read (struct gdbarch *gdbarch,
-                               struct regcache *regcache,
-                               int regnum, gdb_byte *buf);
+static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch,
+                                               struct regcache *regcache,
+                                               int regnum, gdb_byte *buf);
 static void arm_neon_quad_write (struct gdbarch *gdbarch,
                                 struct regcache *regcache,
                                 int regnum, const gdb_byte *buf);
@@ -262,7 +273,7 @@ int arm_apcs_32 = 1;
 
 /* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode.  */
 
-static int
+int
 arm_psr_thumb_bit (struct gdbarch *gdbarch)
 {
   if (gdbarch_tdep (gdbarch)->is_m)
@@ -356,24 +367,39 @@ arm_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start)
   return 0;
 }
 
-static CORE_ADDR arm_get_next_pc_raw (struct frame_info *frame, 
-                                     CORE_ADDR pc, int insert_bkpt);
-
 /* Determine if the program counter specified in MEMADDR is in a Thumb
    function.  This function should be called for addresses unrelated to
    any executing frame; otherwise, prefer arm_frame_is_thumb.  */
 
-static int
+int
 arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
 {
   struct obj_section *sec;
   struct minimal_symbol *sym;
   char type;
+  struct displaced_step_closure* dsc
+    = get_displaced_step_closure_by_addr(memaddr);
+
+  /* If checking the mode of displaced instruction in copy area, the mode
+     should be determined by instruction on the original address.  */
+  if (dsc)
+    {
+      if (debug_displaced)
+       fprintf_unfiltered (gdb_stdlog,
+                           "displaced: check mode of %.8lx instead of %.8lx\n",
+                           (unsigned long) dsc->insn_addr,
+                           (unsigned long) memaddr);
+      memaddr = dsc->insn_addr;
+    }
 
   /* If bit 0 of the address is set, assume this is a Thumb address.  */
   if (IS_THUMB_ADDR (memaddr))
     return 1;
 
+  /* Respect internal mode override if active.  */
+  if (arm_override_mode != -1)
+    return arm_override_mode;
+
   /* If the user wants to override the symbol table, let him.  */
   if (strcmp (arm_force_mode_string, "arm") == 0)
     return 0;
@@ -404,29 +430,9 @@ arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
      target, then trust the current value of $cpsr.  This lets
      "display/i $pc" always show the correct mode (though if there is
      a symbol table we will not reach here, so it still may not be
-     displayed in the mode it will be executed).  
-   
-     As a further heuristic if we detect that we are doing a single-step we
-     see what state executing the current instruction ends up with us being
-     in.  */
+     displayed in the mode it will be executed).  */
   if (target_has_registers)
-    {
-      struct frame_info *current_frame = get_current_frame ();
-      CORE_ADDR current_pc = get_frame_pc (current_frame);
-      int is_thumb = arm_frame_is_thumb (current_frame);
-      CORE_ADDR next_pc;
-      if (memaddr == current_pc)
-       return is_thumb;
-      else
-       {
-         struct gdbarch *gdbarch = get_frame_arch (current_frame);
-         next_pc = arm_get_next_pc_raw (current_frame, current_pc, FALSE);
-         if (memaddr == gdbarch_addr_bits_remove (gdbarch, next_pc))
-           return IS_THUMB_ADDR (next_pc);
-         else
-           return is_thumb;
-       }
-    }
+    return arm_frame_is_thumb (get_current_frame ());
 
   /* Otherwise we're out of luck; we assume ARM.  */
   return 0;
@@ -451,39 +457,55 @@ arm_smash_text_address (struct gdbarch *gdbarch, CORE_ADDR val)
 }
 
 /* Return 1 if PC is the start of a compiler helper function which
-   can be safely ignored during prologue skipping.  */
+   can be safely ignored during prologue skipping.  IS_THUMB is true
+   if the function is known to be a Thumb function due to the way it
+   is being called.  */
 static int
-skip_prologue_function (CORE_ADDR pc)
+skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb)
 {
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
   struct minimal_symbol *msym;
-  const char *name;
 
   msym = lookup_minimal_symbol_by_pc (pc);
-  if (msym == NULL || SYMBOL_VALUE_ADDRESS (msym) != pc)
-    return 0;
+  if (msym != NULL
+      && SYMBOL_VALUE_ADDRESS (msym) == pc
+      && SYMBOL_LINKAGE_NAME (msym) != NULL)
+    {
+      const char *name = SYMBOL_LINKAGE_NAME (msym);
 
-  name = SYMBOL_LINKAGE_NAME (msym);
-  if (name == NULL)
-    return 0;
+      /* The GNU linker's Thumb call stub to foo is named
+        __foo_from_thumb.  */
+      if (strstr (name, "_from_thumb") != NULL)
+       name += 2;
 
-  /* The GNU linker's Thumb call stub to foo is named
-     __foo_from_thumb.  */
-  if (strstr (name, "_from_thumb") != NULL)
-    name += 2;
+      /* On soft-float targets, __truncdfsf2 is called to convert promoted
+        arguments to their argument types in non-prototyped
+        functions.  */
+      if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
+       return 1;
+      if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
+       return 1;
 
-  /* On soft-float targets, __truncdfsf2 is called to convert promoted
-     arguments to their argument types in non-prototyped
-     functions.  */
-  if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
-    return 1;
-  if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
-    return 1;
+      /* Internal functions related to thread-local storage.  */
+      if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0)
+       return 1;
+      if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0)
+       return 1;
+    }
+  else
+    {
+      /* If we run against a stripped glibc, we may be unable to identify
+        special functions by name.  Check for one important case,
+        __aeabi_read_tp, by comparing the *code* against the default
+        implementation (this is hand-written ARM assembler in glibc).  */
 
-  /* Internal functions related to thread-local storage.  */
-  if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0)
-    return 1;
-  if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0)
-    return 1;
+      if (!is_thumb
+         && read_memory_unsigned_integer (pc, 4, byte_order_for_code)
+            == 0xe3e00a0f /* mov r0, #0xffff0fff */
+         && read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code)
+            == 0xe240f01f) /* sub pc, r0, #31 */
+       return 1;
+    }
 
   return 0;
 }
@@ -842,7 +864,8 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
              if (bit (inst2, 12) == 0)
                nextpc = nextpc & 0xfffffffc;
 
-             if (!skip_prologue_function (nextpc))
+             if (!skip_prologue_function (gdbarch, nextpc,
+                                          bit (inst2, 12) != 0))
                break;
            }
 
@@ -1279,7 +1302,8 @@ arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch)
      instruction sequence is not for stack protector.  If symbol is
      removed, we conservatively think this sequence is for stack protector.  */
   if (stack_chk_guard
-      && strcmp (SYMBOL_LINKAGE_NAME(stack_chk_guard), "__stack_chk_guard"))
+      && strncmp (SYMBOL_LINKAGE_NAME (stack_chk_guard), "__stack_chk_guard",
+                 strlen ("__stack_chk_guard")) != 0)
    return pc;
 
   if (is_thumb)
@@ -1814,7 +1838,7 @@ arm_analyze_prologue (struct gdbarch *gdbarch,
             the stack.  */
          CORE_ADDR dest = BranchDest (current_pc, insn);
 
-         if (skip_prologue_function (dest))
+         if (skip_prologue_function (gdbarch, dest, 0))
            continue;
          else
            break;
@@ -1824,23 +1848,15 @@ arm_analyze_prologue (struct gdbarch *gdbarch,
       else if (arm_instruction_changes_pc (insn))
        /* Don't scan past anything that might change control flow.  */
        break;
-      else if ((insn & 0xfe500000) == 0xe8100000)      /* ldm */
-       {
-         /* Ignore block loads from the stack, potentially copying
-            parameters from memory.  */
-         if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
-           continue;
-         else
-           break;
-       }
-      else if ((insn & 0xfc500000) == 0xe4100000)
-       {
-         /* Similarly ignore single loads from the stack.  */
-         if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
-           continue;
-         else
-           break;
-       }
+      else if ((insn & 0xfe500000) == 0xe8100000       /* ldm */
+              && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+       /* Ignore block loads from the stack, potentially copying
+          parameters from memory.  */
+       continue;
+      else if ((insn & 0xfc500000) == 0xe4100000
+              && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+       /* Similarly ignore single loads from the stack.  */
+       continue;
       else if ((insn & 0xffff0ff0) == 0xe1a00000)
        /* MOV Rd, Rm.  Skip register copies, i.e. saves to another
           register instead of the stack.  */
@@ -2114,6 +2130,7 @@ arm_prologue_prev_register (struct frame_info *this_frame,
 
 struct frame_unwind arm_prologue_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   arm_prologue_this_id,
   arm_prologue_prev_register,
   NULL,
@@ -2194,7 +2211,7 @@ arm_obj_section_from_vma (struct objfile *objfile, bfd_vma vma)
 static void
 arm_exidx_new_objfile (struct objfile *objfile)
 {
-  struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+  struct cleanup *cleanups;
   struct arm_exidx_data *data;
   asection *exidx, *extab;
   bfd_vma exidx_vma = 0, extab_vma = 0;
@@ -2205,6 +2222,7 @@ arm_exidx_new_objfile (struct objfile *objfile)
   /* If we've already touched this file, do nothing.  */
   if (!objfile || objfile_data (objfile, arm_exidx_data_key) != NULL)
     return;
+  cleanups = make_cleanup (null_cleanup, NULL);
 
   /* Read contents of exception table and index.  */
   exidx = bfd_get_section_by_name (objfile->obfd, ".ARM.exidx");
@@ -2852,6 +2870,7 @@ arm_exidx_unwind_sniffer (const struct frame_unwind *self,
 
 struct frame_unwind arm_exidx_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   arm_prologue_this_id,
   arm_prologue_prev_register,
   NULL,
@@ -2907,6 +2926,7 @@ arm_stub_unwind_sniffer (const struct frame_unwind *self,
 
 struct frame_unwind arm_stub_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   arm_stub_this_id,
   arm_prologue_prev_register,
   NULL,
@@ -3543,7 +3563,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* Walk through the list of args and determine how large a temporary
      stack is required.  Need to take care here as structs may be
-     passed on the stack, and we have to to push them.  */
+     passed on the stack, and we have to push them.  */
   nstack = 0;
 
   argreg = ARM_A1_REGNUM;
@@ -4112,7 +4132,7 @@ shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
   else
     shift = bits (inst, 7, 11);
 
-  res = (rm == 15
+  res = (rm == ARM_PC_REGNUM
         ? (pc_val + (bit (inst, 4) ? 12 : 8))
         : get_frame_register_unsigned (frame, rm));
 
@@ -4189,7 +4209,7 @@ thumb_advance_itstate (unsigned int itstate)
    another breakpoint by our caller.  */
 
 static CORE_ADDR
-thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
+thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct address_space *aspace = get_frame_address_space (frame);
@@ -4287,8 +4307,8 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
 
              /* Set a breakpoint on the following instruction.  */
              gdb_assert ((itstate & 0x0f) != 0);
-             if (insert_bkpt)
-               insert_single_step_breakpoint (gdbarch, aspace, pc);
+             arm_insert_single_step_breakpoint (gdbarch, aspace,
+                                                MAKE_THUMB_ADDR (pc));
              cond_negated = (itstate >> 4) & 1;
 
              /* Skip all following instructions with the same
@@ -4466,7 +4486,7 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
 
          rn = bits (inst1, 0, 3);
          base = get_frame_register_unsigned (frame, rn);
-         if (rn == 15)
+         if (rn == ARM_PC_REGNUM)
            {
              base = (base + 4) & ~(CORE_ADDR) 0x3;
              if (bit (inst1, 7))
@@ -4560,8 +4580,7 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
 }
 
 /* Get the raw next address.  PC is the current program counter, in 
-   FRAME.  INSERT_BKPT should be TRUE if we want a breakpoint set on 
-   the alternative next instruction if there are two options.
+   FRAME, which is assumed to be executing in ARM mode.
 
    The value returned has the execution state of the next instruction 
    encoded in it.  Use IS_THUMB_ADDR () to see whether the instruction is
@@ -4569,7 +4588,7 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
    address.  */
 
 static CORE_ADDR
-arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
+arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -4579,9 +4598,6 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
   unsigned long status;
   CORE_ADDR nextpc;
 
-  if (arm_frame_is_thumb (frame))
-    return thumb_get_next_pc_raw (frame, pc, insert_bkpt);
-
   pc_val = (unsigned long) pc;
   this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
 
@@ -4633,16 +4649,19 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
                || bits (this_instr, 4, 27) == 0x12fff3)
              {
                rn = bits (this_instr, 0, 3);
-               nextpc = (rn == 15) ? pc_val + 8
-                                   : get_frame_register_unsigned (frame, rn);
+               nextpc = ((rn == ARM_PC_REGNUM)
+                         ? (pc_val + 8)
+                         : get_frame_register_unsigned (frame, rn));
+
                return nextpc;
              }
 
            /* Multiply into PC.  */
            c = (status & FLAG_C) ? 1 : 0;
            rn = bits (this_instr, 16, 19);
-           operand1 = (rn == 15) ? pc_val + 8
-                                 : get_frame_register_unsigned (frame, rn);
+           operand1 = ((rn == ARM_PC_REGNUM)
+                       ? (pc_val + 8)
+                       : get_frame_register_unsigned (frame, rn));
 
            if (bit (this_instr, 25))
              {
@@ -4742,8 +4761,10 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
 
                  /* byte write to PC */
                  rn = bits (this_instr, 16, 19);
-                 base = (rn == 15) ? pc_val + 8
-                                   : get_frame_register_unsigned (frame, rn);
+                 base = ((rn == ARM_PC_REGNUM)
+                         ? (pc_val + 8)
+                         : get_frame_register_unsigned (frame, rn));
+
                  if (bit (this_instr, 24))
                    {
                      /* pre-indexed */
@@ -4829,18 +4850,51 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
   return nextpc;
 }
 
+/* Determine next PC after current instruction executes.  Will call either
+   arm_get_next_pc_raw or thumb_get_next_pc_raw.  Error out if infinite
+   loop is detected.  */
+
 CORE_ADDR
 arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  CORE_ADDR nextpc = 
-    gdbarch_addr_bits_remove (gdbarch, 
-                             arm_get_next_pc_raw (frame, pc, TRUE));
-  if (nextpc == pc)
-    error (_("Infinite loop detected"));
+  CORE_ADDR nextpc;
+
+  if (arm_frame_is_thumb (frame))
+    {
+      nextpc = thumb_get_next_pc_raw (frame, pc);
+      if (nextpc == MAKE_THUMB_ADDR (pc))
+       error (_("Infinite loop detected"));
+    }
+  else
+    {
+      nextpc = arm_get_next_pc_raw (frame, pc);
+      if (nextpc == pc)
+       error (_("Infinite loop detected"));
+    }
+
   return nextpc;
 }
 
+/* Like insert_single_step_breakpoint, but make sure we use a breakpoint
+   of the appropriate mode (as encoded in the PC value), even if this
+   differs from what would be expected according to the symbol tables.  */
+
+void
+arm_insert_single_step_breakpoint (struct gdbarch *gdbarch,
+                                  struct address_space *aspace,
+                                  CORE_ADDR pc)
+{
+  struct cleanup *old_chain
+    = make_cleanup_restore_integer (&arm_override_mode);
+
+  arm_override_mode = IS_THUMB_ADDR (pc);
+  pc = gdbarch_addr_bits_remove (gdbarch, pc);
+
+  insert_single_step_breakpoint (gdbarch, aspace, pc);
+
+  do_cleanups (old_chain);
+}
+
 /* single_step() is called just before we want to resume the inferior,
    if we want to single-step it but there is no hardware or kernel
    single-step support.  We find the target of the coming instruction
@@ -4851,13 +4905,9 @@ arm_software_single_step (struct frame_info *frame)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct address_space *aspace = get_frame_address_space (frame);
-
-  /* NOTE: This may insert the wrong breakpoint instruction when
-     single-stepping over a mode-changing instruction, if the
-     CPSR heuristics are used.  */
-
   CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
-  insert_single_step_breakpoint (gdbarch, aspace, next_pc);
+
+  arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
 
   return 1;
 }
@@ -5079,16 +5129,29 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
    location.  */
 
 ULONGEST
-displaced_read_reg (struct regcache *regs, CORE_ADDR from, int regno)
+displaced_read_reg (struct regcache *regs, struct displaced_step_closure *dsc,
+                   int regno)
 {
   ULONGEST ret;
+  CORE_ADDR from = dsc->insn_addr;
 
-  if (regno == 15)
+  if (regno == ARM_PC_REGNUM)
     {
+      /* Compute pipeline offset:
+        - When executing an ARM instruction, PC reads as the address of the
+        current instruction plus 8.
+        - When executing a Thumb instruction, PC reads as the address of the
+        current instruction plus 4.  */
+
+      if (!dsc->is_thumb)
+       from += 8;
+      else
+       from += 4;
+
       if (debug_displaced)
        fprintf_unfiltered (gdb_stdlog, "displaced: read pc value %.8lx\n",
-                           (unsigned long) from + 8);
-      return (ULONGEST) from + 8;  /* Pipeline offset.  */
+                           (unsigned long) from);
+      return (ULONGEST) from;
     }
   else
     {
@@ -5114,9 +5177,10 @@ displaced_in_arm_mode (struct regcache *regs)
 /* Write to the PC as from a branch instruction.  */
 
 static void
-branch_write_pc (struct regcache *regs, ULONGEST val)
+branch_write_pc (struct regcache *regs, struct displaced_step_closure *dsc,
+                ULONGEST val)
 {
-  if (displaced_in_arm_mode (regs))
+  if (!dsc->is_thumb)
     /* Note: If bits 0/1 are set, this branch would be unpredictable for
        architecture versions < 6.  */
     regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM,
@@ -5159,23 +5223,25 @@ bx_write_pc (struct regcache *regs, ULONGEST val)
 /* Write to the PC as if from a load instruction.  */
 
 static void
-load_write_pc (struct regcache *regs, ULONGEST val)
+load_write_pc (struct regcache *regs, struct displaced_step_closure *dsc,
+              ULONGEST val)
 {
   if (DISPLACED_STEPPING_ARCH_VERSION >= 5)
     bx_write_pc (regs, val);
   else
-    branch_write_pc (regs, val);
+    branch_write_pc (regs, dsc, val);
 }
 
 /* Write to the PC as if from an ALU instruction.  */
 
 static void
-alu_write_pc (struct regcache *regs, ULONGEST val)
+alu_write_pc (struct regcache *regs, struct displaced_step_closure *dsc,
+             ULONGEST val)
 {
-  if (DISPLACED_STEPPING_ARCH_VERSION >= 7 && displaced_in_arm_mode (regs))
+  if (DISPLACED_STEPPING_ARCH_VERSION >= 7 && !dsc->is_thumb)
     bx_write_pc (regs, val);
   else
-    branch_write_pc (regs, val);
+    branch_write_pc (regs, dsc, val);
 }
 
 /* Helper for writing to registers for displaced stepping.  Writing to the PC
@@ -5186,7 +5252,7 @@ void
 displaced_write_reg (struct regcache *regs, struct displaced_step_closure *dsc,
                     int regno, ULONGEST val, enum pc_write_style write_pc)
 {
-  if (regno == 15)
+  if (regno == ARM_PC_REGNUM)
     {
       if (debug_displaced)
        fprintf_unfiltered (gdb_stdlog, "displaced: writing pc %.8lx\n",
@@ -5194,7 +5260,7 @@ displaced_write_reg (struct regcache *regs, struct displaced_step_closure *dsc,
       switch (write_pc)
        {
        case BRANCH_WRITE_PC:
-         branch_write_pc (regs, val);
+         branch_write_pc (regs, dsc, val);
          break;
 
        case BX_WRITE_PC:
@@ -5202,11 +5268,11 @@ displaced_write_reg (struct regcache *regs, struct displaced_step_closure *dsc,
          break;
 
        case LOAD_WRITE_PC:
-         load_write_pc (regs, val);
+         load_write_pc (regs, dsc, val);
          break;
 
        case ALU_WRITE_PC:
-         alu_write_pc (regs, val);
+         alu_write_pc (regs, dsc, val);
          break;
 
        case CANNOT_WRITE_PC:
@@ -5266,8 +5332,8 @@ insn_references_pc (uint32_t insn, uint32_t bitmask)
    matter what address they are executed at: in those cases, use this.  */
 
 static int
-copy_unmodified (struct gdbarch *gdbarch, uint32_t insn,
-                const char *iname, struct displaced_step_closure *dsc)
+arm_copy_unmodified (struct gdbarch *gdbarch, uint32_t insn,
+                    const char *iname, struct displaced_step_closure *dsc)
 {
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.8lx, "
@@ -5290,78 +5356,90 @@ cleanup_preload (struct gdbarch *gdbarch,
     displaced_write_reg (regs, dsc, 1, dsc->tmp[1], CANNOT_WRITE_PC);
 }
 
-static int
-copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
-             struct displaced_step_closure *dsc)
+static void
+install_preload (struct gdbarch *gdbarch, struct regcache *regs,
+                struct displaced_step_closure *dsc, unsigned int rn)
 {
-  unsigned int rn = bits (insn, 16, 19);
   ULONGEST rn_val;
-  CORE_ADDR from = dsc->insn_addr;
-
-  if (!insn_references_pc (insn, 0x000f0000ul))
-    return copy_unmodified (gdbarch, insn, "preload", dsc);
-
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n",
-                       (unsigned long) insn);
-
   /* Preload instructions:
 
      {pli/pld} [rn, #+/-imm]
      ->
      {pli/pld} [r0, #+/-imm].  */
 
-  dsc->tmp[0] = displaced_read_reg (regs, from, 0);
-  rn_val = displaced_read_reg (regs, from, rn);
+  dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+  rn_val = displaced_read_reg (regs, dsc, rn);
   displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
-
   dsc->u.preload.immed = 1;
 
-  dsc->modinsn[0] = insn & 0xfff0ffff;
-
   dsc->cleanup = &cleanup_preload;
-
-  return 0;
 }
 
-/* Preload instructions with register offset.  */
-
 static int
-copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn,
-                 struct regcache *regs,
+arm_copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
                  struct displaced_step_closure *dsc)
 {
   unsigned int rn = bits (insn, 16, 19);
-  unsigned int rm = bits (insn, 0, 3);
-  ULONGEST rn_val, rm_val;
-  CORE_ADDR from = dsc->insn_addr;
 
-  if (!insn_references_pc (insn, 0x000f000ful))
-    return copy_unmodified (gdbarch, insn, "preload reg", dsc);
+  if (!insn_references_pc (insn, 0x000f0000ul))
+    return arm_copy_unmodified (gdbarch, insn, "preload", dsc);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n",
                        (unsigned long) insn);
 
+  dsc->modinsn[0] = insn & 0xfff0ffff;
+
+  install_preload (gdbarch, regs, dsc, rn);
+
+  return 0;
+}
+
+/* Preload instructions with register offset.  */
+
+static void
+install_preload_reg(struct gdbarch *gdbarch, struct regcache *regs,
+                   struct displaced_step_closure *dsc, unsigned int rn,
+                   unsigned int rm)
+{
+  ULONGEST rn_val, rm_val;
+
   /* Preload register-offset instructions:
 
      {pli/pld} [rn, rm {, shift}]
      ->
      {pli/pld} [r0, r1 {, shift}].  */
 
-  dsc->tmp[0] = displaced_read_reg (regs, from, 0);
-  dsc->tmp[1] = displaced_read_reg (regs, from, 1);
-  rn_val = displaced_read_reg (regs, from, rn);
-  rm_val = displaced_read_reg (regs, from, rm);
+  dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+  dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
+  rn_val = displaced_read_reg (regs, dsc, rn);
+  rm_val = displaced_read_reg (regs, dsc, rm);
   displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 1, rm_val, CANNOT_WRITE_PC);
-
   dsc->u.preload.immed = 0;
 
-  dsc->modinsn[0] = (insn & 0xfff0fff0) | 0x1;
-
   dsc->cleanup = &cleanup_preload;
+}
+
+static int
+arm_copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn,
+                     struct regcache *regs,
+                     struct displaced_step_closure *dsc)
+{
+  unsigned int rn = bits (insn, 16, 19);
+  unsigned int rm = bits (insn, 0, 3);
+
+
+  if (!insn_references_pc (insn, 0x000f000ful))
+    return arm_copy_unmodified (gdbarch, insn, "preload reg", dsc);
+
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n",
+                       (unsigned long) insn);
 
+  dsc->modinsn[0] = (insn & 0xfff0fff0) | 0x1;
+
+  install_preload_reg (gdbarch, regs, dsc, rn, rm);
   return 0;
 }
 
@@ -5372,7 +5450,7 @@ cleanup_copro_load_store (struct gdbarch *gdbarch,
                          struct regcache *regs,
                          struct displaced_step_closure *dsc)
 {
-  ULONGEST rn_val = displaced_read_reg (regs, dsc->insn_addr, 0);
+  ULONGEST rn_val = displaced_read_reg (regs, dsc, 0);
 
   displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
 
@@ -5380,21 +5458,12 @@ cleanup_copro_load_store (struct gdbarch *gdbarch,
     displaced_write_reg (regs, dsc, dsc->u.ldst.rn, rn_val, LOAD_WRITE_PC);
 }
 
-static int
-copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn,
-                      struct regcache *regs,
-                      struct displaced_step_closure *dsc)
+static void
+install_copro_load_store (struct gdbarch *gdbarch, struct regcache *regs,
+                         struct displaced_step_closure *dsc,
+                         int writeback, unsigned int rn)
 {
-  unsigned int rn = bits (insn, 16, 19);
   ULONGEST rn_val;
-  CORE_ADDR from = dsc->insn_addr;
-
-  if (!insn_references_pc (insn, 0x000f0000ul))
-    return copy_unmodified (gdbarch, insn, "copro load/store", dsc);
-
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: copying coprocessor "
-                       "load/store insn %.8lx\n", (unsigned long) insn);
 
   /* Coprocessor load/store instructions:
 
@@ -5404,16 +5473,33 @@ copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn,
 
      ldc/ldc2 are handled identically.  */
 
-  dsc->tmp[0] = displaced_read_reg (regs, from, 0);
-  rn_val = displaced_read_reg (regs, from, rn);
+  dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+  rn_val = displaced_read_reg (regs, dsc, rn);
   displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
 
-  dsc->u.ldst.writeback = bit (insn, 25);
+  dsc->u.ldst.writeback = writeback;
   dsc->u.ldst.rn = rn;
 
+  dsc->cleanup = &cleanup_copro_load_store;
+}
+
+static int
+arm_copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn,
+                          struct regcache *regs,
+                          struct displaced_step_closure *dsc)
+{
+  unsigned int rn = bits (insn, 16, 19);
+
+  if (!insn_references_pc (insn, 0x000f0000ul))
+    return arm_copy_unmodified (gdbarch, insn, "copro load/store", dsc);
+
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: copying coprocessor "
+                       "load/store insn %.8lx\n", (unsigned long) insn);
+
   dsc->modinsn[0] = insn & 0xfff0ffff;
 
-  dsc->cleanup = &cleanup_copro_load_store;
+  install_copro_load_store (gdbarch, regs, dsc, bit (insn, 25), rn);
 
   return 0;
 }
@@ -5425,8 +5511,7 @@ static void
 cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs,
                struct displaced_step_closure *dsc)
 {
-  ULONGEST from = dsc->insn_addr;
-  uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM);
+  uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
   int branch_taken = condition_true (dsc->u.branch.cond, status);
   enum pc_write_style write_pc = dsc->u.branch.exchange
                                 ? BX_WRITE_PC : BRANCH_WRITE_PC;
@@ -5436,38 +5521,60 @@ cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs,
 
   if (dsc->u.branch.link)
     {
-      ULONGEST pc = displaced_read_reg (regs, from, 15);
-      displaced_write_reg (regs, dsc, 14, pc - 4, CANNOT_WRITE_PC);
+      /* The value of LR should be the next insn of current one.  In order
+       not to confuse logic hanlding later insn `bx lr', if current insn mode
+       is Thumb, the bit 0 of LR value should be set to 1.  */
+      ULONGEST next_insn_addr = dsc->insn_addr + dsc->insn_size;
+
+      if (dsc->is_thumb)
+       next_insn_addr |= 0x1;
+
+      displaced_write_reg (regs, dsc, ARM_LR_REGNUM, next_insn_addr,
+                          CANNOT_WRITE_PC);
     }
 
-  displaced_write_reg (regs, dsc, 15, dsc->u.branch.dest, write_pc);
+  displaced_write_reg (regs, dsc, ARM_PC_REGNUM, dsc->u.branch.dest, write_pc);
 }
 
 /* Copy B/BL/BLX instructions with immediate destinations.  */
 
+static void
+install_b_bl_blx (struct gdbarch *gdbarch, struct regcache *regs,
+                 struct displaced_step_closure *dsc,
+                 unsigned int cond, int exchange, int link, long offset)
+{
+  /* Implement "BL<cond> <label>" as:
+
+     Preparation: cond <- instruction condition
+     Insn: mov r0, r0  (nop)
+     Cleanup: if (condition true) { r14 <- pc; pc <- label }.
+
+     B<cond> similar, but don't set r14 in cleanup.  */
+
+  dsc->u.branch.cond = cond;
+  dsc->u.branch.link = link;
+  dsc->u.branch.exchange = exchange;
+
+  if (dsc->is_thumb)
+    dsc->u.branch.dest = dsc->insn_addr + 4 + offset;
+  else
+    dsc->u.branch.dest = dsc->insn_addr + 8 + offset;
+
+  dsc->cleanup = &cleanup_branch;
+}
 static int
-copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
-              struct regcache *regs, struct displaced_step_closure *dsc)
+arm_copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
+                  struct regcache *regs, struct displaced_step_closure *dsc)
 {
   unsigned int cond = bits (insn, 28, 31);
   int exchange = (cond == 0xf);
   int link = exchange || bit (insn, 24);
-  CORE_ADDR from = dsc->insn_addr;
   long offset;
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying %s immediate insn "
                        "%.8lx\n", (exchange) ? "blx" : (link) ? "bl" : "b",
                        (unsigned long) insn);
-
-  /* Implement "BL<cond> <label>" as:
-
-     Preparation: cond <- instruction condition
-     Insn: mov r0, r0  (nop)
-     Cleanup: if (condition true) { r14 <- pc; pc <- label }.
-
-     B<cond> similar, but don't set r14 in cleanup.  */
-
   if (exchange)
     /* For BLX, set bit 0 of the destination.  The cleanup_branch function will
        then arrange the switch into Thumb mode.  */
@@ -5478,36 +5585,19 @@ copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
   if (bit (offset, 25))
     offset = offset | ~0x3ffffff;
 
-  dsc->u.branch.cond = cond;
-  dsc->u.branch.link = link;
-  dsc->u.branch.exchange = exchange;
-  dsc->u.branch.dest = from + 8 + offset;
-
   dsc->modinsn[0] = ARM_NOP;
 
-  dsc->cleanup = &cleanup_branch;
-
+  install_b_bl_blx (gdbarch, regs, dsc, cond, exchange, link, offset);
   return 0;
 }
 
 /* Copy BX/BLX with register-specified destinations.  */
 
-static int
-copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
-                struct regcache *regs, struct displaced_step_closure *dsc)
+static void
+install_bx_blx_reg (struct gdbarch *gdbarch, struct regcache *regs,
+                   struct displaced_step_closure *dsc, int link,
+                   unsigned int cond, unsigned int rm)
 {
-  unsigned int cond = bits (insn, 28, 31);
-  /* BX:  x12xxx1x
-     BLX: x12xxx3x.  */
-  int link = bit (insn, 5);
-  unsigned int rm = bits (insn, 0, 3);
-  CORE_ADDR from = dsc->insn_addr;
-
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: copying %s register insn "
-                       "%.8lx\n", (link) ? "blx" : "bx",
-                       (unsigned long) insn);
-
   /* Implement {BX,BLX}<cond> <reg>" as:
 
      Preparation: cond <- instruction condition
@@ -5516,16 +5606,33 @@ copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
 
      Don't set r14 in cleanup for BX.  */
 
-  dsc->u.branch.dest = displaced_read_reg (regs, from, rm);
+  dsc->u.branch.dest = displaced_read_reg (regs, dsc, rm);
 
   dsc->u.branch.cond = cond;
   dsc->u.branch.link = link;
-  dsc->u.branch.exchange = 1;
 
-  dsc->modinsn[0] = ARM_NOP;
+  dsc->u.branch.exchange = 1;
 
   dsc->cleanup = &cleanup_branch;
+}
+
+static int
+arm_copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
+                    struct regcache *regs, struct displaced_step_closure *dsc)
+{
+  unsigned int cond = bits (insn, 28, 31);
+  /* BX:  x12xxx1x
+     BLX: x12xxx3x.  */
+  int link = bit (insn, 5);
+  unsigned int rm = bits (insn, 0, 3);
 
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.8lx",
+                       (unsigned long) insn);
+
+  dsc->modinsn[0] = ARM_NOP;
+
+  install_bx_blx_reg (gdbarch, regs, dsc, link, cond, rm);
   return 0;
 }
 
@@ -5535,25 +5642,24 @@ static void
 cleanup_alu_imm (struct gdbarch *gdbarch,
                 struct regcache *regs, struct displaced_step_closure *dsc)
 {
-  ULONGEST rd_val = displaced_read_reg (regs, dsc->insn_addr, 0);
+  ULONGEST rd_val = displaced_read_reg (regs, dsc, 0);
   displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 1, dsc->tmp[1], CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
 }
 
 static int
-copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
-             struct displaced_step_closure *dsc)
+arm_copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
+                 struct displaced_step_closure *dsc)
 {
   unsigned int rn = bits (insn, 16, 19);
   unsigned int rd = bits (insn, 12, 15);
   unsigned int op = bits (insn, 21, 24);
   int is_mov = (op == 0xd);
   ULONGEST rd_val, rn_val;
-  CORE_ADDR from = dsc->insn_addr;
 
   if (!insn_references_pc (insn, 0x000ff000ul))
-    return copy_unmodified (gdbarch, insn, "ALU immediate", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "ALU immediate", dsc);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying immediate %s insn "
@@ -5572,10 +5678,10 @@ copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
      Cleanup: rd <- r0; r0 <- tmp1; r1 <- tmp2
   */
 
-  dsc->tmp[0] = displaced_read_reg (regs, from, 0);
-  dsc->tmp[1] = displaced_read_reg (regs, from, 1);
-  rn_val = displaced_read_reg (regs, from, rn);
-  rd_val = displaced_read_reg (regs, from, rd);
+  dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+  dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
+  rn_val = displaced_read_reg (regs, dsc, rn);
+  rd_val = displaced_read_reg (regs, dsc, rd);
   displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
   dsc->rd = rd;
@@ -5599,7 +5705,7 @@ cleanup_alu_reg (struct gdbarch *gdbarch,
   ULONGEST rd_val;
   int i;
 
-  rd_val = displaced_read_reg (regs, dsc->insn_addr, 0);
+  rd_val = displaced_read_reg (regs, dsc, 0);
 
   for (i = 0; i < 3; i++)
     displaced_write_reg (regs, dsc, i, dsc->tmp[i], CANNOT_WRITE_PC);
@@ -5607,24 +5713,12 @@ cleanup_alu_reg (struct gdbarch *gdbarch,
   displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
 }
 
-static int
-copy_alu_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
-             struct displaced_step_closure *dsc)
+static void
+install_alu_reg (struct gdbarch *gdbarch, struct regcache *regs,
+                struct displaced_step_closure *dsc,
+                unsigned int rd, unsigned int rn, unsigned int rm)
 {
-  unsigned int rn = bits (insn, 16, 19);
-  unsigned int rm = bits (insn, 0, 3);
-  unsigned int rd = bits (insn, 12, 15);
-  unsigned int op = bits (insn, 21, 24);
-  int is_mov = (op == 0xd);
   ULONGEST rd_val, rn_val, rm_val;
-  CORE_ADDR from = dsc->insn_addr;
-
-  if (!insn_references_pc (insn, 0x000ff00ful))
-    return copy_unmodified (gdbarch, insn, "ALU reg", dsc);
-
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: copying reg %s insn %.8lx\n",
-                       is_mov ? "move" : "ALU", (unsigned long) insn);
 
   /* Instruction is of form:
 
@@ -5638,24 +5732,41 @@ copy_alu_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
      Cleanup: rd <- r0; r0, r1, r2 <- tmp1, tmp2, tmp3
   */
 
-  dsc->tmp[0] = displaced_read_reg (regs, from, 0);
-  dsc->tmp[1] = displaced_read_reg (regs, from, 1);
-  dsc->tmp[2] = displaced_read_reg (regs, from, 2);
-  rd_val = displaced_read_reg (regs, from, rd);
-  rn_val = displaced_read_reg (regs, from, rn);
-  rm_val = displaced_read_reg (regs, from, rm);
+  dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+  dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
+  dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
+  rd_val = displaced_read_reg (regs, dsc, rd);
+  rn_val = displaced_read_reg (regs, dsc, rn);
+  rm_val = displaced_read_reg (regs, dsc, rm);
   displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 2, rm_val, CANNOT_WRITE_PC);
   dsc->rd = rd;
 
+  dsc->cleanup = &cleanup_alu_reg;
+}
+
+static int
+arm_copy_alu_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
+                 struct displaced_step_closure *dsc)
+{
+  unsigned int op = bits (insn, 21, 24);
+  int is_mov = (op == 0xd);
+
+  if (!insn_references_pc (insn, 0x000ff00ful))
+    return arm_copy_unmodified (gdbarch, insn, "ALU reg", dsc);
+
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: copying reg %s insn %.8lx\n",
+                       is_mov ? "move" : "ALU", (unsigned long) insn);
+
   if (is_mov)
     dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x2;
   else
     dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x10002;
 
-  dsc->cleanup = &cleanup_alu_reg;
-
+  install_alu_reg (gdbarch, regs, dsc, bits (insn, 12, 15), bits (insn, 16, 19),
+                  bits (insn, 0, 3));
   return 0;
 }
 
@@ -5666,7 +5777,7 @@ cleanup_alu_shifted_reg (struct gdbarch *gdbarch,
                         struct regcache *regs,
                         struct displaced_step_closure *dsc)
 {
-  ULONGEST rd_val = displaced_read_reg (regs, dsc->insn_addr, 0);
+  ULONGEST rd_val = displaced_read_reg (regs, dsc, 0);
   int i;
 
   for (i = 0; i < 4; i++)
@@ -5675,27 +5786,14 @@ cleanup_alu_shifted_reg (struct gdbarch *gdbarch,
   displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
 }
 
-static int
-copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
-                     struct regcache *regs,
-                     struct displaced_step_closure *dsc)
+static void
+install_alu_shifted_reg (struct gdbarch *gdbarch, struct regcache *regs,
+                        struct displaced_step_closure *dsc,
+                        unsigned int rd, unsigned int rn, unsigned int rm,
+                        unsigned rs)
 {
-  unsigned int rn = bits (insn, 16, 19);
-  unsigned int rm = bits (insn, 0, 3);
-  unsigned int rd = bits (insn, 12, 15);
-  unsigned int rs = bits (insn, 8, 11);
-  unsigned int op = bits (insn, 21, 24);
-  int is_mov = (op == 0xd), i;
+  int i;
   ULONGEST rd_val, rn_val, rm_val, rs_val;
-  CORE_ADDR from = dsc->insn_addr;
-
-  if (!insn_references_pc (insn, 0x000fff0ful))
-    return copy_unmodified (gdbarch, insn, "ALU shifted reg", dsc);
-
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: copying shifted reg %s insn "
-                       "%.8lx\n", is_mov ? "move" : "ALU",
-                       (unsigned long) insn);
 
   /* Instruction is of form:
 
@@ -5712,24 +5810,48 @@ copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
   */
 
   for (i = 0; i < 4; i++)
-    dsc->tmp[i] = displaced_read_reg (regs, from, i);
+    dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
 
-  rd_val = displaced_read_reg (regs, from, rd);
-  rn_val = displaced_read_reg (regs, from, rn);
-  rm_val = displaced_read_reg (regs, from, rm);
-  rs_val = displaced_read_reg (regs, from, rs);
+  rd_val = displaced_read_reg (regs, dsc, rd);
+  rn_val = displaced_read_reg (regs, dsc, rn);
+  rm_val = displaced_read_reg (regs, dsc, rm);
+  rs_val = displaced_read_reg (regs, dsc, rs);
   displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 2, rm_val, CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 3, rs_val, CANNOT_WRITE_PC);
   dsc->rd = rd;
+  dsc->cleanup = &cleanup_alu_shifted_reg;
+}
+
+static int
+arm_copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
+                         struct regcache *regs,
+                         struct displaced_step_closure *dsc)
+{
+  unsigned int op = bits (insn, 21, 24);
+  int is_mov = (op == 0xd);
+  unsigned int rd, rn, rm, rs;
+
+  if (!insn_references_pc (insn, 0x000fff0ful))
+    return arm_copy_unmodified (gdbarch, insn, "ALU shifted reg", dsc);
+
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: copying shifted reg %s insn "
+                       "%.8lx\n", is_mov ? "move" : "ALU",
+                       (unsigned long) insn);
+
+  rn = bits (insn, 16, 19);
+  rm = bits (insn, 0, 3);
+  rs = bits (insn, 8, 11);
+  rd = bits (insn, 12, 15);
 
   if (is_mov)
     dsc->modinsn[0] = (insn & 0xfff000f0) | 0x302;
   else
     dsc->modinsn[0] = (insn & 0xfff000f0) | 0x10302;
 
-  dsc->cleanup = &cleanup_alu_shifted_reg;
+  install_alu_shifted_reg (gdbarch, regs, dsc, rd, rn, rm, rs);
 
   return 0;
 }
@@ -5741,12 +5863,11 @@ cleanup_load (struct gdbarch *gdbarch, struct regcache *regs,
              struct displaced_step_closure *dsc)
 {
   ULONGEST rt_val, rt_val2 = 0, rn_val;
-  CORE_ADDR from = dsc->insn_addr;
 
-  rt_val = displaced_read_reg (regs, from, 0);
+  rt_val = displaced_read_reg (regs, dsc, 0);
   if (dsc->u.ldst.xfersize == 8)
-    rt_val2 = displaced_read_reg (regs, from, 1);
-  rn_val = displaced_read_reg (regs, from, 2);
+    rt_val2 = displaced_read_reg (regs, dsc, 1);
+  rn_val = displaced_read_reg (regs, dsc, 2);
 
   displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
   if (dsc->u.ldst.xfersize > 4)
@@ -5770,8 +5891,7 @@ static void
 cleanup_store (struct gdbarch *gdbarch, struct regcache *regs,
               struct displaced_step_closure *dsc)
 {
-  CORE_ADDR from = dsc->insn_addr;
-  ULONGEST rn_val = displaced_read_reg (regs, from, 2);
+  ULONGEST rn_val = displaced_read_reg (regs, dsc, 2);
 
   displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
   if (dsc->u.ldst.xfersize > 4)
@@ -5791,8 +5911,8 @@ cleanup_store (struct gdbarch *gdbarch, struct regcache *regs,
    transfers, which have a different encoding to byte/word transfers.  */
 
 static int
-copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unpriveleged,
-                 struct regcache *regs, struct displaced_step_closure *dsc)
+arm_copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unpriveleged,
+                     struct regcache *regs, struct displaced_step_closure *dsc)
 {
   unsigned int op1 = bits (insn, 20, 24);
   unsigned int op2 = bits (insn, 5, 6);
@@ -5804,10 +5924,9 @@ copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unpriveleged,
   int immed = (op1 & 0x4) != 0;
   int opcode;
   ULONGEST rt_val, rt_val2 = 0, rn_val, rm_val = 0;
-  CORE_ADDR from = dsc->insn_addr;
 
   if (!insn_references_pc (insn, 0x000ff00ful))
-    return copy_unmodified (gdbarch, insn, "extra load/store", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "extra load/store", dsc);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying %sextra load/store "
@@ -5820,18 +5939,18 @@ copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unpriveleged,
     internal_error (__FILE__, __LINE__,
                    _("copy_extra_ld_st: instruction decode error"));
 
-  dsc->tmp[0] = displaced_read_reg (regs, from, 0);
-  dsc->tmp[1] = displaced_read_reg (regs, from, 1);
-  dsc->tmp[2] = displaced_read_reg (regs, from, 2);
+  dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+  dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
+  dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
   if (!immed)
-    dsc->tmp[3] = displaced_read_reg (regs, from, 3);
+    dsc->tmp[3] = displaced_read_reg (regs, dsc, 3);
 
-  rt_val = displaced_read_reg (regs, from, rt);
+  rt_val = displaced_read_reg (regs, dsc, rt);
   if (bytesize[opcode] == 8)
-    rt_val2 = displaced_read_reg (regs, from, rt + 1);
-  rn_val = displaced_read_reg (regs, from, rn);
+    rt_val2 = displaced_read_reg (regs, dsc, rt + 1);
+  rn_val = displaced_read_reg (regs, dsc, rn);
   if (!immed)
-    rm_val = displaced_read_reg (regs, from, rm);
+    rm_val = displaced_read_reg (regs, dsc, rm);
 
   displaced_write_reg (regs, dsc, 0, rt_val, CANNOT_WRITE_PC);
   if (bytesize[opcode] == 8)
@@ -5865,65 +5984,87 @@ copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unpriveleged,
 
 /* Copy byte/word loads and stores.  */
 
-static int
-copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
-                       struct regcache *regs,
-                       struct displaced_step_closure *dsc, int load, int byte,
-                       int usermode)
+static void
+install_ldr_str_ldrb_strb (struct gdbarch *gdbarch, struct regcache *regs,
+                          struct displaced_step_closure *dsc, int load,
+                          int immed, int writeback, int byte, int usermode,
+                          int rt, int rm, int rn)
 {
-  int immed = !bit (insn, 25);
-  unsigned int rt = bits (insn, 12, 15);
-  unsigned int rn = bits (insn, 16, 19);
-  unsigned int rm = bits (insn, 0, 3);  /* Only valid if !immed.  */
   ULONGEST rt_val, rn_val, rm_val = 0;
-  CORE_ADDR from = dsc->insn_addr;
-
-  if (!insn_references_pc (insn, 0x000ff00ful))
-    return copy_unmodified (gdbarch, insn, "load/store", dsc);
-
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: copying %s%s insn %.8lx\n",
-                       load ? (byte ? "ldrb" : "ldr")
-                            : (byte ? "strb" : "str"), usermode ? "t" : "",
-                       (unsigned long) insn);
 
-  dsc->tmp[0] = displaced_read_reg (regs, from, 0);
-  dsc->tmp[2] = displaced_read_reg (regs, from, 2);
+  dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
+  dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
   if (!immed)
-    dsc->tmp[3] = displaced_read_reg (regs, from, 3);
+    dsc->tmp[3] = displaced_read_reg (regs, dsc, 3);
   if (!load)
-    dsc->tmp[4] = displaced_read_reg (regs, from, 4);
+    dsc->tmp[4] = displaced_read_reg (regs, dsc, 4);
 
-  rt_val = displaced_read_reg (regs, from, rt);
-  rn_val = displaced_read_reg (regs, from, rn);
+  rt_val = displaced_read_reg (regs, dsc, rt);
+  rn_val = displaced_read_reg (regs, dsc, rn);
   if (!immed)
-    rm_val = displaced_read_reg (regs, from, rm);
+    rm_val = displaced_read_reg (regs, dsc, rm);
 
   displaced_write_reg (regs, dsc, 0, rt_val, CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, 2, rn_val, CANNOT_WRITE_PC);
   if (!immed)
     displaced_write_reg (regs, dsc, 3, rm_val, CANNOT_WRITE_PC);
-
   dsc->rd = rt;
   dsc->u.ldst.xfersize = byte ? 1 : 4;
   dsc->u.ldst.rn = rn;
   dsc->u.ldst.immed = immed;
-  dsc->u.ldst.writeback = bit (insn, 24) == 0 || bit (insn, 21) != 0;
+  dsc->u.ldst.writeback = writeback;
 
   /* To write PC we can do:
 
-     scratch+0:  str pc, temp  (*temp = scratch + 8 + offset)
-     scratch+4:  ldr r4, temp
-     scratch+8:  sub r4, r4, pc  (r4 = scratch + 8 + offset - scratch - 8 - 8)
-     scratch+12: add r4, r4, #8  (r4 = offset)
-     scratch+16: add r0, r0, r4
-     scratch+20: str r0, [r2, #imm] (or str r0, [r2, r3])
-     scratch+24: <temp>
+     Before this sequence of instructions:
+     r0 is the PC value got from displaced_read_reg, so r0 = from + 8;
+     r2 is the Rn value got from dispalced_read_reg.
+
+     Insn1: push {pc} Write address of STR instruction + offset on stack
+     Insn2: pop  {r4} Read it back from stack, r4 = addr(Insn1) + offset
+     Insn3: sub r4, r4, pc   r4 = addr(Insn1) + offset - pc
+                                = addr(Insn1) + offset - addr(Insn3) - 8
+                                = offset - 16
+     Insn4: add r4, r4, #8   r4 = offset - 8
+     Insn5: add r0, r0, r4   r0 = from + 8 + offset - 8
+                                = from + offset
+     Insn6: str r0, [r2, #imm] (or str r0, [r2, r3])
 
      Otherwise we don't know what value to write for PC, since the offset is
-     architecture-dependent (sometimes PC+8, sometimes PC+12).  */
+     architecture-dependent (sometimes PC+8, sometimes PC+12).  More details
+     of this can be found in Section "Saving from r15" in
+     http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204g/Cihbjifh.html */
+
+  dsc->cleanup = load ? &cleanup_load : &cleanup_store;
+}
+
+static int
+arm_copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
+                           struct regcache *regs,
+                           struct displaced_step_closure *dsc,
+                           int load, int byte, int usermode)
+{
+  int immed = !bit (insn, 25);
+  int writeback = (bit (insn, 24) == 0 || bit (insn, 21) != 0);
+  unsigned int rt = bits (insn, 12, 15);
+  unsigned int rn = bits (insn, 16, 19);
+  unsigned int rm = bits (insn, 0, 3);  /* Only valid if !immed.  */
 
-  if (load || rt != 15)
+  if (!insn_references_pc (insn, 0x000ff00ful))
+    return arm_copy_unmodified (gdbarch, insn, "load/store", dsc);
+
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog,
+                       "displaced: copying %s%s r%d [r%d] insn %.8lx\n",
+                       load ? (byte ? "ldrb" : "ldr")
+                            : (byte ? "strb" : "str"), usermode ? "t" : "",
+                       rt, rn,
+                       (unsigned long) insn);
+
+  install_ldr_str_ldrb_strb (gdbarch, regs, dsc, load, immed, writeback, byte,
+                            usermode, rt, rm, rn);
+
+  if (load || rt != ARM_PC_REGNUM)
     {
       dsc->u.ldst.restore_r4 = 0;
 
@@ -5942,9 +6083,8 @@ copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
     {
       /* We need to use r4 as scratch.  Make sure it's restored afterwards.  */
       dsc->u.ldst.restore_r4 = 1;
-
-      dsc->modinsn[0] = 0xe58ff014;  /* str pc, [pc, #20].  */
-      dsc->modinsn[1] = 0xe59f4010;  /* ldr r4, [pc, #16].  */
+      dsc->modinsn[0] = 0xe92d8000;  /* push {pc} */
+      dsc->modinsn[1] = 0xe8bd0010;  /* pop  {r4} */
       dsc->modinsn[2] = 0xe044400f;  /* sub r4, r4, pc.  */
       dsc->modinsn[3] = 0xe2844008;  /* add r4, r4, #8.  */
       dsc->modinsn[4] = 0xe0800004;  /* add r0, r0, r4.  */
@@ -5955,9 +6095,6 @@ copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
       else
        dsc->modinsn[5] = (insn & 0xfff00ff0) | 0x20003;
 
-      dsc->modinsn[6] = 0x0;  /* breakpoint location.  */
-      dsc->modinsn[7] = 0x0;  /* scratch space.  */
-
       dsc->numinsns = 6;
     }
 
@@ -5990,7 +6127,6 @@ static void
 cleanup_block_load_all (struct gdbarch *gdbarch, struct regcache *regs,
                        struct displaced_step_closure *dsc)
 {
-  ULONGEST from = dsc->insn_addr;
   int inc = dsc->u.block.increment;
   int bump_before = dsc->u.block.before ? (inc ? 4 : -4) : 0;
   int bump_after = dsc->u.block.before ? 0 : (inc ? 4 : -4);
@@ -5999,7 +6135,7 @@ cleanup_block_load_all (struct gdbarch *gdbarch, struct regcache *regs,
   CORE_ADDR xfer_addr = dsc->u.block.xfer_addr;
   int exception_return = dsc->u.block.load && dsc->u.block.user
                         && (regmask & 0x8000) != 0;
-  uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM);
+  uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
   int do_transfer = condition_true (dsc->u.block.cond, status);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
@@ -6025,7 +6161,7 @@ cleanup_block_load_all (struct gdbarch *gdbarch, struct regcache *regs,
       uint32_t memword;
 
       if (inc)
-       while (regno <= 15 && (regmask & (1 << regno)) == 0)
+       while (regno <= ARM_PC_REGNUM && (regmask & (1 << regno)) == 0)
          regno++;
       else
        while (regno >= 0 && (regmask & (1 << regno)) == 0)
@@ -6052,8 +6188,7 @@ static void
 cleanup_block_store_pc (struct gdbarch *gdbarch, struct regcache *regs,
                        struct displaced_step_closure *dsc)
 {
-  ULONGEST from = dsc->insn_addr;
-  uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM);
+  uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
   int store_executed = condition_true (dsc->u.block.cond, status);
   CORE_ADDR pc_stored_at, transferred_regs = bitcount (dsc->u.block.regmask);
   CORE_ADDR stm_insn_addr;
@@ -6104,10 +6239,9 @@ cleanup_block_load_pc (struct gdbarch *gdbarch,
                       struct regcache *regs,
                       struct displaced_step_closure *dsc)
 {
-  ULONGEST from = dsc->insn_addr;
-  uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM);
+  uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
   int load_executed = condition_true (dsc->u.block.cond, status), i;
-  unsigned int mask = dsc->u.block.regmask, write_reg = 15;
+  unsigned int mask = dsc->u.block.regmask, write_reg = ARM_PC_REGNUM;
   unsigned int regs_loaded = bitcount (mask);
   unsigned int num_to_shuffle = regs_loaded, clobbered;
 
@@ -6128,7 +6262,7 @@ cleanup_block_load_pc (struct gdbarch *gdbarch,
 
          if (read_reg != write_reg)
            {
-             ULONGEST rval = displaced_read_reg (regs, from, read_reg);
+             ULONGEST rval = displaced_read_reg (regs, dsc, read_reg);
              displaced_write_reg (regs, dsc, write_reg, rval, LOAD_WRITE_PC);
              if (debug_displaced)
                fprintf_unfiltered (gdb_stdlog, _("displaced: LDM: move "
@@ -6181,8 +6315,9 @@ cleanup_block_load_pc (struct gdbarch *gdbarch,
    in user-level code (in particular exception return, ldm rn, {...pc}^).  */
 
 static int
-copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
-                struct displaced_step_closure *dsc)
+arm_copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn,
+                    struct regcache *regs,
+                    struct displaced_step_closure *dsc)
 {
   int load = bit (insn, 20);
   int user = bit (insn, 22);
@@ -6190,25 +6325,24 @@ copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
   int before = bit (insn, 24);
   int writeback = bit (insn, 21);
   int rn = bits (insn, 16, 19);
-  CORE_ADDR from = dsc->insn_addr;
 
   /* Block transfers which don't mention PC can be run directly
      out-of-line.  */
-  if (rn != 15 && (insn & 0x8000) == 0)
-    return copy_unmodified (gdbarch, insn, "ldm/stm", dsc);
+  if (rn != ARM_PC_REGNUM && (insn & 0x8000) == 0)
+    return arm_copy_unmodified (gdbarch, insn, "ldm/stm", dsc);
 
-  if (rn == 15)
+  if (rn == ARM_PC_REGNUM)
     {
       warning (_("displaced: Unpredictable LDM or STM with "
                 "base register r15"));
-      return copy_unmodified (gdbarch, insn, "unpredictable ldm/stm", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "unpredictable ldm/stm", dsc);
     }
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying block transfer insn "
                        "%.8lx\n", (unsigned long) insn);
 
-  dsc->u.block.xfer_addr = displaced_read_reg (regs, from, rn);
+  dsc->u.block.xfer_addr = displaced_read_reg (regs, dsc, rn);
   dsc->u.block.rn = rn;
 
   dsc->u.block.load = load;
@@ -6244,7 +6378,7 @@ copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
          unsigned int to = 0, from = 0, i, new_rn;
 
          for (i = 0; i < num_in_list; i++)
-           dsc->tmp[i] = displaced_read_reg (regs, from, i);
+           dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
 
          /* Writeback makes things complicated.  We need to avoid clobbering
             the base register with one of the registers in our modified
@@ -6301,8 +6435,7 @@ static void
 cleanup_svc (struct gdbarch *gdbarch, struct regcache *regs,
             struct displaced_step_closure *dsc)
 {
-  CORE_ADDR from = dsc->insn_addr;
-  CORE_ADDR resume_addr = from + 4;
+  CORE_ADDR resume_addr = dsc->insn_addr + dsc->insn_size;
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: cleanup for svc, resume at "
@@ -6312,14 +6445,10 @@ cleanup_svc (struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
-         struct regcache *regs, struct displaced_step_closure *dsc)
-{
-  CORE_ADDR from = dsc->insn_addr;
 
-  /* Allow OS-specific code to override SVC handling.  */
-  if (dsc->u.svc.copy_svc_os)
-    return dsc->u.svc.copy_svc_os (gdbarch, insn, to, regs, dsc);
+arm_copy_svc (struct gdbarch *gdbarch, uint32_t insn,
+             struct regcache *regs, struct displaced_step_closure *dsc)
+{
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying svc insn %.8lx\n",
@@ -6331,19 +6460,26 @@ copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
 
   dsc->modinsn[0] = insn;
 
-  dsc->cleanup = &cleanup_svc;
   /* Pretend we wrote to the PC, so cleanup doesn't set PC to the next
      instruction.  */
   dsc->wrote_to_pc = 1;
 
-  return 0;
+  /* Allow OS-specific code to override SVC handling.  */
+  if (dsc->u.svc.copy_svc_os)
+    return dsc->u.svc.copy_svc_os (gdbarch, regs, dsc);
+  else
+    {
+      dsc->cleanup = &cleanup_svc;
+      return 0;
+    }
+
 }
 
 /* Copy undefined instructions.  */
 
 static int
-copy_undef (struct gdbarch *gdbarch, uint32_t insn,
-           struct displaced_step_closure *dsc)
+arm_copy_undef (struct gdbarch *gdbarch, uint32_t insn,
+               struct displaced_step_closure *dsc)
 {
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog,
@@ -6358,8 +6494,8 @@ copy_undef (struct gdbarch *gdbarch, uint32_t insn,
 /* Copy unpredictable instructions.  */
 
 static int
-copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
-            struct displaced_step_closure *dsc)
+arm_copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
+                struct displaced_step_closure *dsc)
 {
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying unpredictable insn "
@@ -6374,95 +6510,96 @@ copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
    the presentation in the ARM ARM.  */
 
 static int
-decode_misc_memhint_neon (struct gdbarch *gdbarch, uint32_t insn,
-                         struct regcache *regs,
-                         struct displaced_step_closure *dsc)
+arm_decode_misc_memhint_neon (struct gdbarch *gdbarch, uint32_t insn,
+                             struct regcache *regs,
+                             struct displaced_step_closure *dsc)
 {
   unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
   unsigned int rn = bits (insn, 16, 19);
 
   if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
-    return copy_unmodified (gdbarch, insn, "cps", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "cps", dsc);
   else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
-    return copy_unmodified (gdbarch, insn, "setend", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "setend", dsc);
   else if ((op1 & 0x60) == 0x20)
-    return copy_unmodified (gdbarch, insn, "neon dataproc", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "neon dataproc", dsc);
   else if ((op1 & 0x71) == 0x40)
-    return copy_unmodified (gdbarch, insn, "neon elt/struct load/store", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "neon elt/struct load/store",
+                               dsc);
   else if ((op1 & 0x77) == 0x41)
-    return copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
   else if ((op1 & 0x77) == 0x45)
-    return copy_preload (gdbarch, insn, regs, dsc);  /* pli.  */
+    return arm_copy_preload (gdbarch, insn, regs, dsc);  /* pli.  */
   else if ((op1 & 0x77) == 0x51)
     {
       if (rn != 0xf)
-       return copy_preload (gdbarch, insn, regs, dsc);  /* pld/pldw.  */
+       return arm_copy_preload (gdbarch, insn, regs, dsc);  /* pld/pldw.  */
       else
-       return copy_unpred (gdbarch, insn, dsc);
+       return arm_copy_unpred (gdbarch, insn, dsc);
     }
   else if ((op1 & 0x77) == 0x55)
-    return copy_preload (gdbarch, insn, regs, dsc);  /* pld/pldw.  */
+    return arm_copy_preload (gdbarch, insn, regs, dsc);  /* pld/pldw.  */
   else if (op1 == 0x57)
     switch (op2)
       {
-      case 0x1: return copy_unmodified (gdbarch, insn, "clrex", dsc);
-      case 0x4: return copy_unmodified (gdbarch, insn, "dsb", dsc);
-      case 0x5: return copy_unmodified (gdbarch, insn, "dmb", dsc);
-      case 0x6: return copy_unmodified (gdbarch, insn, "isb", dsc);
-      default: return copy_unpred (gdbarch, insn, dsc);
+      case 0x1: return arm_copy_unmodified (gdbarch, insn, "clrex", dsc);
+      case 0x4: return arm_copy_unmodified (gdbarch, insn, "dsb", dsc);
+      case 0x5: return arm_copy_unmodified (gdbarch, insn, "dmb", dsc);
+      case 0x6: return arm_copy_unmodified (gdbarch, insn, "isb", dsc);
+      default: return arm_copy_unpred (gdbarch, insn, dsc);
       }
   else if ((op1 & 0x63) == 0x43)
-    return copy_unpred (gdbarch, insn, dsc);
+    return arm_copy_unpred (gdbarch, insn, dsc);
   else if ((op2 & 0x1) == 0x0)
     switch (op1 & ~0x80)
       {
       case 0x61:
-       return copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
       case 0x65:
-       return copy_preload_reg (gdbarch, insn, regs, dsc);  /* pli reg.  */
+       return arm_copy_preload_reg (gdbarch, insn, regs, dsc);  /* pli reg.  */
       case 0x71: case 0x75:
         /* pld/pldw reg.  */
-       return copy_preload_reg (gdbarch, insn, regs, dsc);
+       return arm_copy_preload_reg (gdbarch, insn, regs, dsc);
       case 0x63: case 0x67: case 0x73: case 0x77:
-       return copy_unpred (gdbarch, insn, dsc);
+       return arm_copy_unpred (gdbarch, insn, dsc);
       default:
-       return copy_undef (gdbarch, insn, dsc);
+       return arm_copy_undef (gdbarch, insn, dsc);
       }
   else
-    return copy_undef (gdbarch, insn, dsc);  /* Probably unreachable.  */
+    return arm_copy_undef (gdbarch, insn, dsc);  /* Probably unreachable.  */
 }
 
 static int
-decode_unconditional (struct gdbarch *gdbarch, uint32_t insn,
-                     struct regcache *regs,
-                     struct displaced_step_closure *dsc)
+arm_decode_unconditional (struct gdbarch *gdbarch, uint32_t insn,
+                         struct regcache *regs,
+                         struct displaced_step_closure *dsc)
 {
   if (bit (insn, 27) == 0)
-    return decode_misc_memhint_neon (gdbarch, insn, regs, dsc);
+    return arm_decode_misc_memhint_neon (gdbarch, insn, regs, dsc);
   /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx.  */
   else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
     {
     case 0x0: case 0x2:
-      return copy_unmodified (gdbarch, insn, "srs", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "srs", dsc);
 
     case 0x1: case 0x3:
-      return copy_unmodified (gdbarch, insn, "rfe", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "rfe", dsc);
 
     case 0x4: case 0x5: case 0x6: case 0x7:
-      return copy_b_bl_blx (gdbarch, insn, regs, dsc);
+      return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc);
 
     case 0x8:
       switch ((insn & 0xe00000) >> 21)
        {
        case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
          /* stc/stc2.  */
-         return copy_copro_load_store (gdbarch, insn, regs, dsc);
+         return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
 
        case 0x2:
-         return copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
+         return arm_copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
 
        default:
-         return copy_undef (gdbarch, insn, dsc);
+         return arm_copy_undef (gdbarch, insn, dsc);
        }
 
     case 0x9:
@@ -6472,55 +6609,55 @@ decode_unconditional (struct gdbarch *gdbarch, uint32_t insn,
          {
          case 0x1: case 0x3:
            /* ldc/ldc2 imm (undefined for rn == pc).  */
-           return rn_f ? copy_undef (gdbarch, insn, dsc)
-                       : copy_copro_load_store (gdbarch, insn, regs, dsc);
+           return rn_f ? arm_copy_undef (gdbarch, insn, dsc)
+                       : arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
 
          case 0x2:
-           return copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
+           return arm_copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
 
          case 0x4: case 0x5: case 0x6: case 0x7:
            /* ldc/ldc2 lit (undefined for rn != pc).  */
-           return rn_f ? copy_copro_load_store (gdbarch, insn, regs, dsc)
-                       : copy_undef (gdbarch, insn, dsc);
+           return rn_f ? arm_copy_copro_load_store (gdbarch, insn, regs, dsc)
+                       : arm_copy_undef (gdbarch, insn, dsc);
 
          default:
-           return copy_undef (gdbarch, insn, dsc);
+           return arm_copy_undef (gdbarch, insn, dsc);
          }
       }
 
     case 0xa:
-      return copy_unmodified (gdbarch, insn, "stc/stc2", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "stc/stc2", dsc);
 
     case 0xb:
       if (bits (insn, 16, 19) == 0xf)
         /* ldc/ldc2 lit.  */
-       return copy_copro_load_store (gdbarch, insn, regs, dsc);
+       return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
       else
-       return copy_undef (gdbarch, insn, dsc);
+       return arm_copy_undef (gdbarch, insn, dsc);
 
     case 0xc:
       if (bit (insn, 4))
-       return copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
       else
-       return copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
 
     case 0xd:
       if (bit (insn, 4))
-       return copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
       else
-       return copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
 
     default:
-      return copy_undef (gdbarch, insn, dsc);
+      return arm_copy_undef (gdbarch, insn, dsc);
     }
 }
 
 /* Decode miscellaneous instructions in dp/misc encoding space.  */
 
 static int
-decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn,
-                     struct regcache *regs,
-                     struct displaced_step_closure *dsc)
+arm_decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn,
+                         struct regcache *regs,
+                         struct displaced_step_closure *dsc)
 {
   unsigned int op2 = bits (insn, 4, 6);
   unsigned int op = bits (insn, 21, 22);
@@ -6529,84 +6666,85 @@ decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn,
   switch (op2)
     {
     case 0x0:
-      return copy_unmodified (gdbarch, insn, "mrs/msr", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "mrs/msr", dsc);
 
     case 0x1:
       if (op == 0x1)  /* bx.  */
-       return copy_bx_blx_reg (gdbarch, insn, regs, dsc);
+       return arm_copy_bx_blx_reg (gdbarch, insn, regs, dsc);
       else if (op == 0x3)
-       return copy_unmodified (gdbarch, insn, "clz", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "clz", dsc);
       else
-       return copy_undef (gdbarch, insn, dsc);
+       return arm_copy_undef (gdbarch, insn, dsc);
 
     case 0x2:
       if (op == 0x1)
         /* Not really supported.  */
-       return copy_unmodified (gdbarch, insn, "bxj", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "bxj", dsc);
       else
-       return copy_undef (gdbarch, insn, dsc);
+       return arm_copy_undef (gdbarch, insn, dsc);
 
     case 0x3:
       if (op == 0x1)
-       return copy_bx_blx_reg (gdbarch, insn,
+       return arm_copy_bx_blx_reg (gdbarch, insn,
                                regs, dsc);  /* blx register.  */
       else
-       return copy_undef (gdbarch, insn, dsc);
+       return arm_copy_undef (gdbarch, insn, dsc);
 
     case 0x5:
-      return copy_unmodified (gdbarch, insn, "saturating add/sub", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "saturating add/sub", dsc);
 
     case 0x7:
       if (op == 0x1)
-       return copy_unmodified (gdbarch, insn, "bkpt", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "bkpt", dsc);
       else if (op == 0x3)
         /* Not really supported.  */
-       return copy_unmodified (gdbarch, insn, "smc", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "smc", dsc);
 
     default:
-      return copy_undef (gdbarch, insn, dsc);
+      return arm_copy_undef (gdbarch, insn, dsc);
     }
 }
 
 static int
-decode_dp_misc (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
-               struct displaced_step_closure *dsc)
+arm_decode_dp_misc (struct gdbarch *gdbarch, uint32_t insn,
+                   struct regcache *regs,
+                   struct displaced_step_closure *dsc)
 {
   if (bit (insn, 25))
     switch (bits (insn, 20, 24))
       {
       case 0x10:
-       return copy_unmodified (gdbarch, insn, "movw", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "movw", dsc);
 
       case 0x14:
-       return copy_unmodified (gdbarch, insn, "movt", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "movt", dsc);
 
       case 0x12: case 0x16:
-       return copy_unmodified (gdbarch, insn, "msr imm", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "msr imm", dsc);
 
       default:
-       return copy_alu_imm (gdbarch, insn, regs, dsc);
+       return arm_copy_alu_imm (gdbarch, insn, regs, dsc);
       }
   else
     {
       uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
 
       if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
-       return copy_alu_reg (gdbarch, insn, regs, dsc);
+       return arm_copy_alu_reg (gdbarch, insn, regs, dsc);
       else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
-       return copy_alu_shifted_reg (gdbarch, insn, regs, dsc);
+       return arm_copy_alu_shifted_reg (gdbarch, insn, regs, dsc);
       else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
-       return decode_miscellaneous (gdbarch, insn, regs, dsc);
+       return arm_decode_miscellaneous (gdbarch, insn, regs, dsc);
       else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
-       return copy_unmodified (gdbarch, insn, "halfword mul/mla", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "halfword mul/mla", dsc);
       else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
-       return copy_unmodified (gdbarch, insn, "mul/mla", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "mul/mla", dsc);
       else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
-       return copy_unmodified (gdbarch, insn, "synch", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "synch", dsc);
       else if (op2 == 0xb || (op2 & 0xd) == 0xd)
        /* 2nd arg means "unpriveleged".  */
-       return copy_extra_ld_st (gdbarch, insn, (op1 & 0x12) == 0x02, regs,
-                                dsc);
+       return arm_copy_extra_ld_st (gdbarch, insn, (op1 & 0x12) == 0x02, regs,
+                                    dsc);
     }
 
   /* Should be unreachable.  */
@@ -6614,9 +6752,9 @@ decode_dp_misc (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
 }
 
 static int
-decode_ld_st_word_ubyte (struct gdbarch *gdbarch, uint32_t insn,
-                        struct regcache *regs,
-                        struct displaced_step_closure *dsc)
+arm_decode_ld_st_word_ubyte (struct gdbarch *gdbarch, uint32_t insn,
+                            struct regcache *regs,
+                            struct displaced_step_closure *dsc)
 {
   int a = bit (insn, 25), b = bit (insn, 4);
   uint32_t op1 = bits (insn, 20, 24);
@@ -6624,83 +6762,83 @@ decode_ld_st_word_ubyte (struct gdbarch *gdbarch, uint32_t insn,
 
   if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
       || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
-    return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 0, 0);
+    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 0, 0);
   else if ((!a && (op1 & 0x17) == 0x02)
            || (a && (op1 & 0x17) == 0x02 && !b))
-    return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 0, 1);
+    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 0, 1);
   else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
            || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
-    return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 0, 0);
+    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 0, 0);
   else if ((!a && (op1 & 0x17) == 0x03)
           || (a && (op1 & 0x17) == 0x03 && !b))
-    return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 0, 1);
+    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 0, 1);
   else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
            || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
-    return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 0);
+    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 0);
   else if ((!a && (op1 & 0x17) == 0x06)
           || (a && (op1 & 0x17) == 0x06 && !b))
-    return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 1);
+    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 1);
   else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
           || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
-    return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 0);
+    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 0);
   else if ((!a && (op1 & 0x17) == 0x07)
           || (a && (op1 & 0x17) == 0x07 && !b))
-    return copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 1);
+    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 1);
 
   /* Should be unreachable.  */
   return 1;
 }
 
 static int
-decode_media (struct gdbarch *gdbarch, uint32_t insn,
-             struct displaced_step_closure *dsc)
+arm_decode_media (struct gdbarch *gdbarch, uint32_t insn,
+                 struct displaced_step_closure *dsc)
 {
   switch (bits (insn, 20, 24))
     {
     case 0x00: case 0x01: case 0x02: case 0x03:
-      return copy_unmodified (gdbarch, insn, "parallel add/sub signed", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "parallel add/sub signed", dsc);
 
     case 0x04: case 0x05: case 0x06: case 0x07:
-      return copy_unmodified (gdbarch, insn, "parallel add/sub unsigned", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "parallel add/sub unsigned", dsc);
 
     case 0x08: case 0x09: case 0x0a: case 0x0b:
     case 0x0c: case 0x0d: case 0x0e: case 0x0f:
-      return copy_unmodified (gdbarch, insn,
+      return arm_copy_unmodified (gdbarch, insn,
                              "decode/pack/unpack/saturate/reverse", dsc);
 
     case 0x18:
       if (bits (insn, 5, 7) == 0)  /* op2.  */
         {
          if (bits (insn, 12, 15) == 0xf)
-           return copy_unmodified (gdbarch, insn, "usad8", dsc);
+           return arm_copy_unmodified (gdbarch, insn, "usad8", dsc);
          else
-           return copy_unmodified (gdbarch, insn, "usada8", dsc);
+           return arm_copy_unmodified (gdbarch, insn, "usada8", dsc);
        }
       else
-        return copy_undef (gdbarch, insn, dsc);
+        return arm_copy_undef (gdbarch, insn, dsc);
 
     case 0x1a: case 0x1b:
       if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
-       return copy_unmodified (gdbarch, insn, "sbfx", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "sbfx", dsc);
       else
-       return copy_undef (gdbarch, insn, dsc);
+       return arm_copy_undef (gdbarch, insn, dsc);
 
     case 0x1c: case 0x1d:
       if (bits (insn, 5, 6) == 0x0)  /* op2[1:0].  */
         {
          if (bits (insn, 0, 3) == 0xf)
-           return copy_unmodified (gdbarch, insn, "bfc", dsc);
+           return arm_copy_unmodified (gdbarch, insn, "bfc", dsc);
          else
-           return copy_unmodified (gdbarch, insn, "bfi", dsc);
+           return arm_copy_unmodified (gdbarch, insn, "bfi", dsc);
        }
       else
-       return copy_undef (gdbarch, insn, dsc);
+       return arm_copy_undef (gdbarch, insn, dsc);
 
     case 0x1e: case 0x1f:
       if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
-       return copy_unmodified (gdbarch, insn, "ubfx", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "ubfx", dsc);
       else
-       return copy_undef (gdbarch, insn, dsc);
+       return arm_copy_undef (gdbarch, insn, dsc);
     }
 
   /* Should be unreachable.  */
@@ -6708,40 +6846,41 @@ decode_media (struct gdbarch *gdbarch, uint32_t insn,
 }
 
 static int
-decode_b_bl_ldmstm (struct gdbarch *gdbarch, int32_t insn,
-                   struct regcache *regs, struct displaced_step_closure *dsc)
+arm_decode_b_bl_ldmstm (struct gdbarch *gdbarch, int32_t insn,
+                       struct regcache *regs,
+                       struct displaced_step_closure *dsc)
 {
   if (bit (insn, 25))
-    return copy_b_bl_blx (gdbarch, insn, regs, dsc);
+    return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc);
   else
-    return copy_block_xfer (gdbarch, insn, regs, dsc);
+    return arm_copy_block_xfer (gdbarch, insn, regs, dsc);
 }
 
 static int
-decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint32_t insn,
-                     struct regcache *regs,
-                     struct displaced_step_closure *dsc)
+arm_decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint32_t insn,
+                         struct regcache *regs,
+                         struct displaced_step_closure *dsc)
 {
   unsigned int opcode = bits (insn, 20, 24);
 
   switch (opcode)
     {
     case 0x04: case 0x05:  /* VFP/Neon mrrc/mcrr.  */
-      return copy_unmodified (gdbarch, insn, "vfp/neon mrrc/mcrr", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "vfp/neon mrrc/mcrr", dsc);
 
     case 0x08: case 0x0a: case 0x0c: case 0x0e:
     case 0x12: case 0x16:
-      return copy_unmodified (gdbarch, insn, "vfp/neon vstm/vpush", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "vfp/neon vstm/vpush", dsc);
 
     case 0x09: case 0x0b: case 0x0d: case 0x0f:
     case 0x13: case 0x17:
-      return copy_unmodified (gdbarch, insn, "vfp/neon vldm/vpop", dsc);
+      return arm_copy_unmodified (gdbarch, insn, "vfp/neon vldm/vpop", dsc);
 
     case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
     case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
       /* Note: no writeback for these instructions.  Bit 25 will always be
         zero though (via caller), so the following works OK.  */
-      return copy_copro_load_store (gdbarch, insn, regs, dsc);
+      return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
     }
 
   /* Should be unreachable.  */
@@ -6749,8 +6888,8 @@ decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint32_t insn,
 }
 
 static int
-decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
-                 struct regcache *regs, struct displaced_step_closure *dsc)
+arm_decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
+                     struct regcache *regs, struct displaced_step_closure *dsc)
 {
   unsigned int op1 = bits (insn, 20, 25);
   int op = bit (insn, 4);
@@ -6758,52 +6897,58 @@ decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
   unsigned int rn = bits (insn, 16, 19);
 
   if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
-    return decode_ext_reg_ld_st (gdbarch, insn, regs, dsc);
+    return arm_decode_ext_reg_ld_st (gdbarch, insn, regs, dsc);
   else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
           && (coproc & 0xe) != 0xa)
     /* stc/stc2.  */
-    return copy_copro_load_store (gdbarch, insn, regs, dsc);
+    return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
   else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
           && (coproc & 0xe) != 0xa)
     /* ldc/ldc2 imm/lit.  */
-    return copy_copro_load_store (gdbarch, insn, regs, dsc);
+    return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
   else if ((op1 & 0x3e) == 0x00)
-    return copy_undef (gdbarch, insn, dsc);
+    return arm_copy_undef (gdbarch, insn, dsc);
   else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
-    return copy_unmodified (gdbarch, insn, "neon 64bit xfer", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "neon 64bit xfer", dsc);
   else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
-    return copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
   else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
-    return copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
   else if ((op1 & 0x30) == 0x20 && !op)
     {
       if ((coproc & 0xe) == 0xa)
-       return copy_unmodified (gdbarch, insn, "vfp dataproc", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "vfp dataproc", dsc);
       else
-       return copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+       return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
     }
   else if ((op1 & 0x30) == 0x20 && op)
-    return copy_unmodified (gdbarch, insn, "neon 8/16/32 bit xfer", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "neon 8/16/32 bit xfer", dsc);
   else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
-    return copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
   else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
-    return copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
+    return arm_copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
   else if ((op1 & 0x30) == 0x30)
-    return copy_svc (gdbarch, insn, to, regs, dsc);
+    return arm_copy_svc (gdbarch, insn, regs, dsc);
   else
-    return copy_undef (gdbarch, insn, dsc);  /* Possibly unreachable.  */
+    return arm_copy_undef (gdbarch, insn, dsc);  /* Possibly unreachable.  */
+}
+
+static void
+thumb_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
+                             CORE_ADDR to, struct regcache *regs,
+                             struct displaced_step_closure *dsc)
+{
+  error (_("Displaced stepping is only supported in ARM mode"));
 }
 
 void
-arm_process_displaced_insn (struct gdbarch *gdbarch, uint32_t insn,
-                           CORE_ADDR from, CORE_ADDR to,
-                           struct regcache *regs,
+arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
+                           CORE_ADDR to, struct regcache *regs,
                            struct displaced_step_closure *dsc)
 {
   int err = 0;
-
-  if (!displaced_in_arm_mode (regs))
-    error (_("Displaced stepping is only supported in ARM mode"));
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  uint32_t insn;
 
   /* Most displaced instructions use a 1-instruction scratch space, so set this
      here and override below if/when necessary.  */
@@ -6813,28 +6958,39 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, uint32_t insn,
   dsc->cleanup = NULL;
   dsc->wrote_to_pc = 0;
 
+  if (!displaced_in_arm_mode (regs))
+    return thumb_process_displaced_insn (gdbarch, from, to, regs, dsc);
+
+  dsc->is_thumb = 0;
+  dsc->insn_size = 4;
+  insn = read_memory_unsigned_integer (from, 4, byte_order_for_code);
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: stepping insn %.8lx "
+                       "at %.8lx\n", (unsigned long) insn,
+                       (unsigned long) from);
+
   if ((insn & 0xf0000000) == 0xf0000000)
-    err = decode_unconditional (gdbarch, insn, regs, dsc);
+    err = arm_decode_unconditional (gdbarch, insn, regs, dsc);
   else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
     {
     case 0x0: case 0x1: case 0x2: case 0x3:
-      err = decode_dp_misc (gdbarch, insn, regs, dsc);
+      err = arm_decode_dp_misc (gdbarch, insn, regs, dsc);
       break;
 
     case 0x4: case 0x5: case 0x6:
-      err = decode_ld_st_word_ubyte (gdbarch, insn, regs, dsc);
+      err = arm_decode_ld_st_word_ubyte (gdbarch, insn, regs, dsc);
       break;
 
     case 0x7:
-      err = decode_media (gdbarch, insn, dsc);
+      err = arm_decode_media (gdbarch, insn, dsc);
       break;
 
     case 0x8: case 0x9: case 0xa: case 0xb:
-      err = decode_b_bl_ldmstm (gdbarch, insn, regs, dsc);
+      err = arm_decode_b_bl_ldmstm (gdbarch, insn, regs, dsc);
       break;
 
     case 0xc: case 0xd: case 0xe: case 0xf:
-      err = decode_svc_copro (gdbarch, insn, to, regs, dsc);
+      err = arm_decode_svc_copro (gdbarch, insn, to, regs, dsc);
       break;
     }
 
@@ -6850,23 +7006,49 @@ arm_displaced_init_closure (struct gdbarch *gdbarch, CORE_ADDR from,
                            CORE_ADDR to, struct displaced_step_closure *dsc)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  unsigned int i;
+  unsigned int i, len, offset;
   enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  int size = dsc->is_thumb? 2 : 4;
+  const unsigned char *bkp_insn;
 
+  offset = 0;
   /* Poke modified instruction(s).  */
   for (i = 0; i < dsc->numinsns; i++)
     {
       if (debug_displaced)
-       fprintf_unfiltered (gdb_stdlog, "displaced: writing insn %.8lx at "
-                           "%.8lx\n", (unsigned long) dsc->modinsn[i],
-                           (unsigned long) to + i * 4);
-      write_memory_unsigned_integer (to + i * 4, 4, byte_order_for_code,
+       {
+         fprintf_unfiltered (gdb_stdlog, "displaced: writing insn ");
+         if (size == 4)
+           fprintf_unfiltered (gdb_stdlog, "%.8lx",
+                               dsc->modinsn[i]);
+         else if (size == 2)
+           fprintf_unfiltered (gdb_stdlog, "%.4x",
+                               (unsigned short)dsc->modinsn[i]);
+
+         fprintf_unfiltered (gdb_stdlog, " at %.8lx\n",
+                             (unsigned long) to + offset);
+
+       }
+      write_memory_unsigned_integer (to + offset, size,
+                                    byte_order_for_code,
                                     dsc->modinsn[i]);
+      offset += size;
+    }
+
+  /* Choose the correct breakpoint instruction.  */
+  if (dsc->is_thumb)
+    {
+      bkp_insn = tdep->thumb_breakpoint;
+      len = tdep->thumb_breakpoint_size;
+    }
+  else
+    {
+      bkp_insn = tdep->arm_breakpoint;
+      len = tdep->arm_breakpoint_size;
     }
 
   /* Put breakpoint afterwards.  */
-  write_memory (to + dsc->numinsns * 4, tdep->arm_breakpoint,
-               tdep->arm_breakpoint_size);
+  write_memory (to + offset, bkp_insn, len);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copy %s->%s: ",
@@ -6883,15 +7065,7 @@ arm_displaced_step_copy_insn (struct gdbarch *gdbarch,
 {
   struct displaced_step_closure *dsc
     = xmalloc (sizeof (struct displaced_step_closure));
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  uint32_t insn = read_memory_unsigned_integer (from, 4, byte_order_for_code);
-
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: stepping insn %.8lx "
-                       "at %.8lx\n", (unsigned long) insn,
-                       (unsigned long) from);
-
-  arm_process_displaced_insn (gdbarch, insn, from, to, regs, dsc);
+  arm_process_displaced_insn (gdbarch, from, to, regs, dsc);
   arm_displaced_init_closure (gdbarch, from, to, dsc);
 
   return dsc;
@@ -6910,7 +7084,9 @@ arm_displaced_step_fixup (struct gdbarch *gdbarch,
     dsc->cleanup (gdbarch, regs, dsc);
 
   if (!dsc->wrote_to_pc)
-    regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, dsc->insn_addr + 4);
+    regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM,
+                                   dsc->insn_addr + dsc->insn_size);
+
 }
 
 #include "bfd-in2.h"
@@ -7109,8 +7285,9 @@ arm_extract_return_value (struct type *type, struct regcache *regs,
           || TYPE_CODE (type) == TYPE_CODE_REF
           || TYPE_CODE (type) == TYPE_CODE_ENUM)
     {
-      /* If the the type is a plain integer, then the access is
-        straight-forward.  Otherwise we have to play around a bit more.  */
+      /* If the type is a plain integer, then the access is
+        straight-forward.  Otherwise we have to play around a bit
+        more.  */
       int len = TYPE_LENGTH (type);
       int regno = ARM_A1_REGNUM;
       ULONGEST tmp;
@@ -7722,10 +7899,8 @@ coff_sym_is_thumb (int val)
 static void
 arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
 {
-  /* Thumb symbols are of type STT_LOPROC, (synonymous with
-     STT_ARM_TFUNC).  */
-  if (ELF_ST_TYPE (((elf_symbol_type *)sym)->internal_elf_sym.st_info)
-      == STT_LOPROC)
+  if (ARM_SYM_BRANCH_TYPE (&((elf_symbol_type *)sym)->internal_elf_sym)
+      == ST_BRANCH_TO_THUMB)
     MSYMBOL_SET_SPECIAL (msym);
 }
 
@@ -7823,13 +7998,14 @@ arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
    ABI, even if a NEON unit is not present.  REGNUM is the index of
    the quad register, in [0, 15].  */
 
-static void
+static enum register_status
 arm_neon_quad_read (struct gdbarch *gdbarch, struct regcache *regcache,
                    int regnum, gdb_byte *buf)
 {
   char name_buf[4];
   gdb_byte reg_buf[8];
   int offset, double_regnum;
+  enum register_status status;
 
   sprintf (name_buf, "d%d", regnum << 1);
   double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
@@ -7841,15 +8017,21 @@ arm_neon_quad_read (struct gdbarch *gdbarch, struct regcache *regcache,
   else
     offset = 0;
 
-  regcache_raw_read (regcache, double_regnum, reg_buf);
+  status = regcache_raw_read (regcache, double_regnum, reg_buf);
+  if (status != REG_VALID)
+    return status;
   memcpy (buf + offset, reg_buf, 8);
 
   offset = 8 - offset;
-  regcache_raw_read (regcache, double_regnum + 1, reg_buf);
+  status = regcache_raw_read (regcache, double_regnum + 1, reg_buf);
+  if (status != REG_VALID)
+    return status;
   memcpy (buf + offset, reg_buf, 8);
+
+  return REG_VALID;
 }
 
-static void
+static enum register_status
 arm_pseudo_read (struct gdbarch *gdbarch, struct regcache *regcache,
                 int regnum, gdb_byte *buf)
 {
@@ -7863,9 +8045,11 @@ arm_pseudo_read (struct gdbarch *gdbarch, struct regcache *regcache,
 
   if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
     /* Quad-precision register.  */
-    arm_neon_quad_read (gdbarch, regcache, regnum - 32, buf);
+    return arm_neon_quad_read (gdbarch, regcache, regnum - 32, buf);
   else
     {
+      enum register_status status;
+
       /* Single-precision register.  */
       gdb_assert (regnum < 32);
 
@@ -7879,8 +8063,10 @@ arm_pseudo_read (struct gdbarch *gdbarch, struct regcache *regcache,
       double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
                                                   strlen (name_buf));
 
-      regcache_raw_read (regcache, double_regnum, reg_buf);
-      memcpy (buf, reg_buf + offset, 4);
+      status = regcache_raw_read (regcache, double_regnum, reg_buf);
+      if (status == REG_VALID)
+       memcpy (buf, reg_buf + offset, 4);
+      return status;
     }
 }
 
@@ -8294,8 +8480,13 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
              if (!valid_p)
                break;
            }
+         if (!valid_p && i == 16)
+           valid_p = 1;
 
-         if (!valid_p && i != 16)
+         /* Also require FPSCR.  */
+         valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                             ARM_FPSCR_REGNUM, "fpscr");
+         if (!valid_p)
            {
              tdesc_data_cleanup (tdesc_data);
              return NULL;
@@ -8507,6 +8698,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (tdep->arm_abi == ARM_ABI_AUTO)
     tdep->arm_abi = ARM_ABI_APCS;
 
+  /* Watchpoints are not steppable.  */
+  set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
   /* We used to default to FPA for generic ARM, but almost nobody
      uses that now, and we now provide a way for the user to force
      the model.  So default to the most useful variant.  */
@@ -8611,6 +8805,10 @@ _initialize_arm_tdep (void)
 
   /* Initialize the standard target descriptions.  */
   initialize_tdesc_arm_with_m ();
+  initialize_tdesc_arm_with_iwmmxt ();
+  initialize_tdesc_arm_with_vfpv2 ();
+  initialize_tdesc_arm_with_vfpv3 ();
+  initialize_tdesc_arm_with_neon ();
 
   /* Get the number of possible sets of register names defined in opcodes.  */
   num_disassembly_options = get_arm_regname_num_options ();
This page took 0.061103 seconds and 4 git commands to generate.