]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Refactor Nios II GDB support to use helper functions for disassembly and
authorSandra Loosemore <sandra@codesourcery.com>
Wed, 26 Nov 2014 02:34:51 +0000 (18:34 -0800)
committerSandra Loosemore <sandra@codesourcery.com>
Wed, 26 Nov 2014 02:34:51 +0000 (18:34 -0800)
instruction matching.

2014-11-25  Sandra Loosemore  <sandra@codesourcery.com>

gdb/
* nios2-tdep.c (nios2_fetch_insn): Move up in file.  Disassemble
the instruction as well as reading it from memory.
(nios2_match_add): New.
(nios2_match_sub): New.
(nios2_match_addi): New.
(nios2_match_orhi): New.
(nios2_match_stw): New.
(nios2_match_ldw): New.
(nios2_match_rdctl): New.
(enum branch_condition): New.
(nios2_match_branch): New.
(nios2_match_jmpi): New.
(nios2_match_calli): New.
(nios2_match_jmpr): New.
(nios2_match_callr): New.
(nios2_match_break): New.
(nios2_match_trap): New.
(nios2_in_epilogue_p): Rewrite to use new functions.
(nios2_analyze_prologue): Likewise.
(nios2_skip_prologue): Delete unused local limit_pc.
(nios2_breakpoint_from_pc): Make R1-specific encodings explicit.
(nios2_get_next_pc): Rewrite to use new functions.

gdb/ChangeLog
gdb/nios2-tdep.c

index 7726bd2184c67aeaf5368a2a170e3454a5d99310..a992925ec82b824637c2815fe824cfd10138c1fa 100644 (file)
@@ -1,3 +1,28 @@
+2014-11-25  Sandra Loosemore  <sandra@codesourcery.com>
+
+       * nios2-tdep.c (nios2_fetch_insn): Move up in file.  Disassemble
+       the instruction as well as reading it from memory.
+       (nios2_match_add): New.
+       (nios2_match_sub): New.
+       (nios2_match_addi): New.
+       (nios2_match_orhi): New.
+       (nios2_match_stw): New.
+       (nios2_match_ldw): New.
+       (nios2_match_rdctl): New.
+       (enum branch_condition): New.
+       (nios2_match_branch): New.
+       (nios2_match_jmpi): New.
+       (nios2_match_calli): New.
+       (nios2_match_jmpr): New.
+       (nios2_match_callr): New.
+       (nios2_match_break): New.
+       (nios2_match_trap): New.
+       (nios2_in_epilogue_p): Rewrite to use new functions.
+       (nios2_analyze_prologue): Likewise.
+       (nios2_skip_prologue): Delete unused local limit_pc.
+       (nios2_breakpoint_from_pc): Make R1-specific encodings explicit.
+       (nios2_get_next_pc): Rewrite to use new functions.
+
 2014-11-24  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * gdbtypes.c (resolve_dynamic_type_internal): Reindent the code.
index 1b647ac941b2334a19906d8ebe175487f14b2bf7..aa26af97066cad7f7c81747442c8075a72c86c44 100644 (file)
@@ -275,45 +275,360 @@ nios2_init_cache (struct nios2_unwind_cache *cache, CORE_ADDR pc)
   nios2_setup_default (cache);
 }
 
+/* Read and identify an instruction at PC.  If INSNP is non-null,
+   store the instruction word into that location.  Return the opcode
+   pointer or NULL if the memory couldn't be read or disassembled.  */
+
+static const struct nios2_opcode *
+nios2_fetch_insn (struct gdbarch *gdbarch, CORE_ADDR pc,
+                 unsigned int *insnp)
+{
+  LONGEST memword;
+  unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  unsigned int insn;
+
+  if (!safe_read_memory_integer (pc, NIOS2_OPCODE_SIZE,
+                                gdbarch_byte_order (gdbarch), &memword))
+    return NULL;
+
+  insn = (unsigned int) memword;
+  if (insnp)
+    *insnp = insn;
+  return nios2_find_opcode_hash (insn, mach);
+}
+
+
+/* Match and disassemble an ADD-type instruction, with 3 register operands.
+   Returns true on success, and fills in the operand pointers.  */
+
+static int
+nios2_match_add (uint32_t insn, const struct nios2_opcode *op,
+                unsigned long mach, int *ra, int *rb, int *rc)
+{
+  if (op->match == MATCH_R1_ADD || op->match == MATCH_R1_MOV)
+    {
+      *ra = GET_IW_R_A (insn);
+      *rb = GET_IW_R_B (insn);
+      *rc = GET_IW_R_C (insn);
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble a SUB-type instruction, with 3 register operands.
+   Returns true on success, and fills in the operand pointers.  */
+
+static int
+nios2_match_sub (uint32_t insn, const struct nios2_opcode *op,
+                unsigned long mach, int *ra, int *rb, int *rc)
+{
+  if (op->match == MATCH_R1_SUB)
+    {
+      *ra = GET_IW_R_A (insn);
+      *rb = GET_IW_R_B (insn);
+      *rc = GET_IW_R_C (insn);
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble an ADDI-type instruction, with 2 register operands
+   and one immediate operand.
+   Returns true on success, and fills in the operand pointers.  */
+
+static int
+nios2_match_addi (uint32_t insn, const struct nios2_opcode *op,
+                 unsigned long mach, int *ra, int *rb, int *imm)
+{
+  if (op->match == MATCH_R1_ADDI)
+    {
+      *ra = GET_IW_I_A (insn);
+      *rb = GET_IW_I_B (insn);
+      *imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble an ORHI-type instruction, with 2 register operands
+   and one unsigned immediate operand.
+   Returns true on success, and fills in the operand pointers.  */
+
+static int
+nios2_match_orhi (uint32_t insn, const struct nios2_opcode *op,
+                 unsigned long mach, int *ra, int *rb, unsigned int *uimm)
+{
+  if (op->match == MATCH_R1_ORHI)
+    {
+      *ra = GET_IW_I_A (insn);
+      *rb = GET_IW_I_B (insn);
+      *uimm = GET_IW_I_IMM16 (insn);
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble a STW-type instruction, with 2 register operands
+   and one immediate operand.
+   Returns true on success, and fills in the operand pointers.  */
+
+static int
+nios2_match_stw (uint32_t insn, const struct nios2_opcode *op,
+                unsigned long mach, int *ra, int *rb, int *imm)
+{
+  if (op->match == MATCH_R1_STW || op->match == MATCH_R1_STWIO)
+    {
+      *ra = GET_IW_I_A (insn);
+      *rb = GET_IW_I_B (insn);
+      *imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble a LDW-type instruction, with 2 register operands
+   and one immediate operand.
+   Returns true on success, and fills in the operand pointers.  */
+
+static int
+nios2_match_ldw (uint32_t insn, const struct nios2_opcode *op,
+                unsigned long mach, int *ra, int *rb, int *imm)
+{
+  if (op->match == MATCH_R1_LDW || op->match == MATCH_R1_LDWIO)
+    {
+      *ra = GET_IW_I_A (insn);
+      *rb = GET_IW_I_B (insn);
+      *imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble a RDCTL instruction, with 2 register operands.
+   Returns true on success, and fills in the operand pointers.  */
+
+static int
+nios2_match_rdctl (uint32_t insn, const struct nios2_opcode *op,
+                  unsigned long mach, int *ra, int *rc)
+{
+  if (op->match == MATCH_R1_RDCTL)
+    {
+      *ra = GET_IW_R_IMM5 (insn);
+      *rc = GET_IW_R_C (insn);
+      return 1;
+    }
+  return 0;
+}
+
+
+/* Match and disassemble a branch instruction, with (potentially)
+   2 register operands and one immediate operand.
+   Returns true on success, and fills in the operand pointers.  */
+
+enum branch_condition {
+  branch_none,
+  branch_eq,
+  branch_ne,
+  branch_ge,
+  branch_geu,
+  branch_lt,
+  branch_ltu
+};
+  
+static int
+nios2_match_branch (uint32_t insn, const struct nios2_opcode *op,
+                   unsigned long mach, int *ra, int *rb, int *imm,
+                   enum branch_condition *cond)
+{
+  switch (op->match)
+    {
+    case MATCH_R1_BR:
+      *cond = branch_none;
+      break;
+    case MATCH_R1_BEQ:
+      *cond = branch_eq;
+      break;
+    case MATCH_R1_BNE:
+      *cond = branch_ne;
+      break;
+    case MATCH_R1_BGE:
+      *cond = branch_ge;
+      break;
+    case MATCH_R1_BGEU:
+      *cond = branch_geu;
+      break;
+    case MATCH_R1_BLT:
+      *cond = branch_lt;
+      break;
+    case MATCH_R1_BLTU:
+      *cond = branch_ltu;
+      break;
+    default:
+      return 0;
+    }
+  *imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
+  *ra = GET_IW_I_A (insn);
+  *rb = GET_IW_I_B (insn);
+  return 1;
+}
+
+/* Match and disassemble a direct jump instruction, with an
+   unsigned operand.  Returns true on success, and fills in the operand
+   pointer.  */
+
+static int
+nios2_match_jmpi (uint32_t insn, const struct nios2_opcode *op,
+                 unsigned long mach, unsigned int *uimm)
+{
+  if (op->match == MATCH_R1_JMPI)
+    {
+      *uimm = GET_IW_J_IMM26 (insn) << 2;
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble a direct call instruction, with an
+   unsigned operand.  Returns true on success, and fills in the operand
+   pointer.  */
+
+static int
+nios2_match_calli (uint32_t insn, const struct nios2_opcode *op,
+                  unsigned long mach, unsigned int *uimm)
+{
+  if (op->match == MATCH_R1_CALL)
+    {
+      *uimm = GET_IW_J_IMM26 (insn) << 2;
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble an indirect jump instruction, with a
+   (possibly implicit) register operand.  Returns true on success, and fills
+   in the operand pointer.  */
+
+static int
+nios2_match_jmpr (uint32_t insn, const struct nios2_opcode *op,
+                 unsigned long mach, int *ra)
+{
+  switch (op->match)
+    {
+    case MATCH_R1_JMP:
+      *ra = GET_IW_I_A (insn);
+      return 1;
+    case MATCH_R1_RET:
+      *ra = NIOS2_RA_REGNUM;
+      return 1;
+    case MATCH_R1_ERET:
+      *ra = NIOS2_EA_REGNUM;
+      return 1;
+    case MATCH_R1_BRET:
+      *ra = NIOS2_BA_REGNUM;
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+/* Match and disassemble an indirect call instruction, with a register
+   operand.  Returns true on success, and fills in the operand pointer.  */
+
+static int
+nios2_match_callr (uint32_t insn, const struct nios2_opcode *op,
+                  unsigned long mach, int *ra)
+{
+  if (op->match == MATCH_R1_CALLR)
+    {
+      *ra = GET_IW_I_A (insn);
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble a break instruction, with an unsigned operand.
+   Returns true on success, and fills in the operand pointer.  */
+
+static int
+nios2_match_break (uint32_t insn, const struct nios2_opcode *op,
+                 unsigned long mach, unsigned int *uimm)
+{
+  if (op->match == MATCH_R1_BREAK)
+    {
+      *uimm = GET_IW_R_IMM5 (insn);
+      return 1;
+    }
+  return 0;
+}
+
+/* Match and disassemble a trap instruction, with an unsigned operand.
+   Returns true on success, and fills in the operand pointer.  */
+
+static int
+nios2_match_trap (uint32_t insn, const struct nios2_opcode *op,
+                 unsigned long mach, unsigned int *uimm)
+{
+  if (op->match == MATCH_R1_TRAP)
+    {
+      *uimm = GET_IW_R_IMM5 (insn);
+      return 1;
+    }
+  return 0;
+}
+
 /* Helper function to identify when we're in a function epilogue;
    that is, the part of the function from the point at which the
-   stack adjustment is made, to the return or sibcall.  On Nios II,
-   we want to check that the CURRENT_PC is a return-type instruction
-   and that the previous instruction is a stack adjustment.
-   START_PC is the beginning of the function in question.  */
+   stack adjustments are made, to the return or sibcall.
+   Note that we may have several stack adjustment instructions, and
+   this function needs to test whether the stack teardown has already
+   started before current_pc, not whether it has completed.  */
 
 static int
 nios2_in_epilogue_p (struct gdbarch *gdbarch,
                     CORE_ADDR current_pc,
                     CORE_ADDR start_pc)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  unsigned int insn;
+  const struct nios2_opcode *op = NULL;
+  unsigned int uimm;
+  int imm;
+  int ra, rb, rc;
+  enum branch_condition cond;
 
   /* There has to be a previous instruction in the function.  */
   if (current_pc > start_pc)
     {
-
-      /* Check whether the previous instruction was a stack
-        adjustment.  */
-      unsigned int insn
-        = read_memory_unsigned_integer (current_pc - NIOS2_OPCODE_SIZE,
-                                       NIOS2_OPCODE_SIZE, byte_order);
-
-      if ((insn & 0xffc0003c) == 0xdec00004    /* ADDI sp, sp, */
-         || (insn & 0xffc1ffff) == 0xdec1883a  /* ADD  sp, sp, */
-         || (insn & 0xffc0003f) == 0xdec00017) /* LDW  sp, constant(sp) */
-       {
-         /* Then check if it's followed by a return or a tail
-            call.  */
-          insn = read_memory_unsigned_integer (current_pc, NIOS2_OPCODE_SIZE,
-                                              byte_order);
-
-         if (insn == 0xf800283a                        /* RET */
-             || insn == 0xe800083a                     /* ERET */
-             || (insn & 0x07ffffff) == 0x0000683a      /* JMP */
-             || (insn & 0xffc0003f) == 6)              /* BR */
-           return 1;
-       }
+      int ok = 0;
+
+      /* Check whether the previous instruction was a stack adjustment.
+        Possible instructions here include:
+        ADDI sp, sp, n
+        ADD sp, sp, rn
+        LDW sp, n(sp)  */
+      op = nios2_fetch_insn (gdbarch, current_pc - NIOS2_OPCODE_SIZE, &insn);
+      if (op == NULL)
+       return 0;
+
+      /* Was it a stack adjustment?  */
+      if (nios2_match_addi (insn, op, mach, &ra, &rb, &imm))
+       ok = (rb == NIOS2_SP_REGNUM);
+      else if (nios2_match_add (insn, op, mach, &ra, &rb, &rc))
+       ok = (rc == NIOS2_SP_REGNUM);
+      else if (nios2_match_ldw (insn, op, mach, &ra, &rb, &imm))
+       ok = (rb == NIOS2_SP_REGNUM);
+      if (!ok)
+       return 0;
+
+      /* Then check if it's followed by a return or a tail call.  */
+      op = nios2_fetch_insn (gdbarch, current_pc, &insn);
+      if (op == NULL)
+       return 0;
+      if (nios2_match_jmpr (insn, op, mach, &ra)
+         || nios2_match_jmpi (insn, op, mach, &uimm)
+         || (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond)
+             && cond == branch_none))
+       return 1;
     }
   return 0;
 }
@@ -337,31 +652,33 @@ nios2_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
    interested in skipping the prologue.  Otherwise CACHE is filled in
    from the frame information.
 
-   The prologue will consist of the following parts:
-     1) Optional profiling instrumentation.
-        This uses two or three instructions (the last of
-       these might get merged in with the STW which saves RA to the
-       stack).  We interpret these.
+   The prologue may consist of the following parts:
+     1) Profiling instrumentation.  For non-PIC code it looks like:
          mov    r8, ra
          call   mcount
          mov    ra, r8
 
-     2) A stack adjustment or stack which, which will be one of:
-         addi   sp, sp, -constant
-       or:
-         movi   r8, constant
-         sub    sp, sp, r8
-       or
-         movhi  r8, constant
-         addi   r8, r8, constant
-         sub    sp, sp, r8
-       or
+     2) A stack adjustment and save of R4-R7 for varargs functions.
+        This is typically merged with item 3.
+
+     3) A stack adjustment and save of the callee-saved registers;
+       typically an explicit SP decrement and individual register
+       saves.
+
+        There may also be a stack switch here in an exception handler
+       in place of a stack adjustment.  It looks like:
          movhi  rx, %hiadj(newstack)
          addhi  rx, rx, %lo(newstack)
          stw    sp, constant(rx)
          mov    sp, rx
 
-     3) An optional stack check, which can take either of these forms:
+     5) A frame pointer save, which can be either a MOV or ADDI.
+
+     6) A further stack pointer adjustment.  This is normally included
+        adjustment in step 4 unless the total adjustment is too large
+       to be done in one step.
+
+     7) A stack overflow check, which can take either of these forms:
          bgeu   sp, rx, +8
          break  3
        or
@@ -369,32 +686,18 @@ nios2_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
          ...
        .Lstack_overflow:
          break  3
+        If present, this is inserted after the stack pointer adjustments
+       for steps 3, 4, and 6.
 
-     4) Saving any registers which need to be saved.  These will
-        normally just be stored onto the stack:
-         stw    rx, constant(sp)
-       but in the large frame case will use r8 as an offset back
-       to the cfa:
-         add    r8, r8, sp
-         stw    rx, -constant(r8)
-
-       Saving control registers looks slightly different:
-         rdctl  rx, ctlN
-         stw    rx, constant(sp)
-
-     5) An optional FP setup, either if the user has requested a
-        frame pointer or if the function calls alloca.
-        This is always:
-         mov    fp, sp
-
-    The prologue instructions may be interleaved, and the register
-    saves and FP setup can occur in either order.
+    The prologue instructions may be combined or interleaved with other
+    instructions.
 
     To cope with all this variability we decode all the instructions
-    from the start of the prologue until we hit a branch, call or
-    return.  For each of the instructions mentioned in 3, 4 and 5 we
-    handle the limited cases of stores to the stack and operations
-    on constant values.  */
+    from the start of the prologue until we hit an instruction that
+    cannot possibly be a prologue instruction, such as a branch, call,
+    return, or epilogue instruction.  The prologue is considered to end
+    at the last instruction that can definitely be considered a
+    prologue instruction.  */
 
 static CORE_ADDR
 nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
@@ -402,12 +705,13 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
                        struct nios2_unwind_cache *cache,
                        struct frame_info *this_frame)
 {
-  /* Maximum lines of prologue to check.
+  /* Maximum number of possibly-prologue instructions to check.
      Note that this number should not be too large, else we can
      potentially end up iterating through unmapped memory.  */
-  CORE_ADDR limit_pc = start_pc + 200;
+  int ninsns, max_insns = 50;
   int regno;
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
 
   /* Does the frame set up the FP register?  */
   int base_reg = 0;
@@ -428,9 +732,7 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
      functions which switch stacks?  */
   CORE_ADDR frame_high;
 
-  /* Is this the end of the prologue?  */
-  int within_prologue = 1;
-
+  /* The last definitely-prologue instruction seen.  */
   CORE_ADDR prologue_end;
 
   /* Is this the innermost function?  */
@@ -444,15 +746,19 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
 
   /* Set up the default values of the registers.  */
   nios2_setup_default (cache);
-  prologue_end = start_pc;
 
   /* Find the prologue instructions.  */
-  while (pc < limit_pc && within_prologue)
+  prologue_end = start_pc;
+  for (ninsns = 0; ninsns < max_insns; ninsns++)
     {
       /* Present instruction.  */
       uint32_t insn;
-
-      int prologue_insn = 0;
+      const struct nios2_opcode *op;
+      int ra, rb, rc, imm;
+      unsigned int uimm;
+      unsigned int reglist;
+      int wb, ret;
+      enum branch_condition cond;
 
       if (pc == current_pc)
       {
@@ -466,22 +772,21 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
          fprintf_unfiltered (gdb_stdlog, "*");
       }
 
-      insn = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order);
-      pc += NIOS2_OPCODE_SIZE;
+      op = nios2_fetch_insn (gdbarch, pc, &insn);
+
+      /* Unknown opcode?  Stop scanning.  */
+      if (op == NULL)
+       break;
+      pc += op->size;
 
       if (nios2_debug)
        fprintf_unfiltered (gdb_stdlog, "[%08X]", insn);
 
       /* The following instructions can appear in the prologue.  */
 
-      if ((insn & MASK_R1_ADD) == MATCH_R1_ADD)
+      if (nios2_match_add (insn, op, mach, &ra, &rb, &rc))
        {
          /* ADD   rc, ra, rb  (also used for MOV) */
-
-         int ra = GET_IW_R_A (insn);
-         int rb = GET_IW_R_B (insn);
-         int rc = GET_IW_R_C (insn);
-
          if (rc == NIOS2_SP_REGNUM
              && rb == 0
              && value[ra].reg == cache->reg_saved[NIOS2_SP_REGNUM].basereg)
@@ -522,17 +827,13 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
                value[rc].reg = -1;
              value[rc].offset = value[ra].offset + value[rb].offset;
            }
-         prologue_insn = 1;
-       }
 
-      else if ((insn & MASK_R1_SUB) == MATCH_R1_SUB)
+         prologue_end = pc;
+       }
+      
+      else if (nios2_match_sub (insn, op, mach, &ra, &rb, &rc))
        {
          /* SUB   rc, ra, rb */
-
-         int ra = GET_IW_R_A (insn);
-         int rb = GET_IW_R_B (insn);
-         int rc = GET_IW_R_C (insn);
-
          if (rc != 0)
            {
              if (value[rb].reg == 0)
@@ -543,12 +844,9 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
            }
        }
 
-      else if ((insn & MASK_R1_ADDI) == MATCH_R1_ADDI)
+      else if (nios2_match_addi (insn, op, mach, &ra, &rb, &imm))
        {
-         /* ADDI  rb, ra, immed   (also used for MOVI) */
-         short immed = GET_IW_I_IMM16 (insn);
-         int ra = GET_IW_I_A (insn);
-         int rb = GET_IW_I_B (insn);
+         /* ADDI    rb, ra, imm */
 
          /* The first stack adjustment is part of the prologue.
             Any subsequent stack adjustments are either down to
@@ -561,166 +859,136 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
          if (rb != 0)
            {
              value[rb].reg    = value[ra].reg;
-             value[rb].offset = value[ra].offset + immed;
+             value[rb].offset = value[ra].offset + imm;
            }
 
-         prologue_insn = 1;
+         prologue_end = pc;
        }
 
-      else if ((insn & MASK_R1_ORHI) == MATCH_R1_ORHI)
+      else if (nios2_match_orhi (insn, op, mach, &ra, &rb, &uimm))
        {
-         /* ORHI  rb, ra, immed   (also used for MOVHI) */
-         unsigned int immed = GET_IW_I_IMM16 (insn);
-         int ra = GET_IW_I_A (insn);
-         int rb = GET_IW_I_B (insn);
-
+         /* ORHI  rb, ra, uimm   (also used for MOVHI) */
          if (rb != 0)
            {
              value[rb].reg    = (value[ra].reg == 0) ? 0 : -1;
-             value[rb].offset = value[ra].offset | (immed << 16);
+             value[rb].offset = value[ra].offset | (uimm << 16);
            }
        }
 
-      else if ((insn & MASK_R1_STW) == MATCH_R1_STW
-              || (insn & MASK_R1_STWIO) == MATCH_R1_STWIO)
+      else if (nios2_match_stw (insn, op, mach, &ra, &rb, &imm))
         {
-         /* STW rb, immediate(ra) */
+         /* STW rb, imm(ra) */
 
-         short immed16 = GET_IW_I_IMM16 (insn);
-         int ra = GET_IW_I_A (insn);
-         int rb = GET_IW_I_B (insn);
-
-         /* Are we storing the original value of a register?
+         /* Are we storing the original value of a register to the stack?
             For exception handlers the value of EA-4 (return
             address from interrupts etc) is sometimes stored.  */
          int orig = value[rb].reg;
          if (orig > 0
              && (value[rb].offset == 0
-                 || (orig == NIOS2_EA_REGNUM && value[rb].offset == -4)))
-           {
-             /* We are most interested in stores to the stack, but
-                also take note of stores to other places as they
-                might be useful later.  */
-             if ((value[ra].reg == NIOS2_SP_REGNUM
+                 || (orig == NIOS2_EA_REGNUM && value[rb].offset == -4))
+             && ((value[ra].reg == NIOS2_SP_REGNUM
                   && cache->reg_saved[orig].basereg != NIOS2_SP_REGNUM)
-                 || cache->reg_saved[orig].basereg == -1)
+                 || cache->reg_saved[orig].basereg == -1))
+           {
+             if (pc < current_pc)
                {
-                 if (pc < current_pc)
-                   {
-                     /* Save off callee saved registers.  */
-                     cache->reg_saved[orig].basereg = value[ra].reg;
-                     cache->reg_saved[orig].addr = value[ra].offset + immed16;
-                   }
-
-                 prologue_insn = 1;
-
-                 if (orig == NIOS2_EA_REGNUM || orig == NIOS2_ESTATUS_REGNUM)
-                   exception_handler = 1;
+                 /* Save off callee saved registers.  */
+                 cache->reg_saved[orig].basereg = value[ra].reg;
+                 cache->reg_saved[orig].addr = value[ra].offset + imm;
                }
+             
+             prologue_end = pc;
+             
+             if (orig == NIOS2_EA_REGNUM || orig == NIOS2_ESTATUS_REGNUM)
+               exception_handler = 1;
            }
          else
-           /* Non-stack memory writes are not part of the
-              prologue.  */
-           within_prologue = 0;
+           /* Non-stack memory writes cannot appear in the prologue.  */
+           break;
         }
 
-      else if ((insn & MASK_R1_RDCTL) == MATCH_R1_RDCTL)
+      else if (nios2_match_rdctl (insn, op, mach, &ra, &rc))
        {
-         /* RDCTL rC, ctlN */
-         int rc = GET_IW_R_C (insn);
-         int n = GET_IW_R_A (insn);
-
+         /* RDCTL rC, ctlN
+            This can appear in exception handlers in combination with
+            a subsequent save to the stack frame.  */
          if (rc != 0)
            {
-             value[rc].reg    = NIOS2_STATUS_REGNUM + n;
+             value[rc].reg    = NIOS2_STATUS_REGNUM + ra;
              value[rc].offset = 0;
            }
-
-         prologue_insn = 1;
         }
 
-      else if ((insn & MASK_R1_CALL) == MATCH_R1_CALL
-              && value[8].reg == NIOS2_RA_REGNUM
-              && value[8].offset == 0
-              && value[NIOS2_SP_REGNUM].reg == NIOS2_SP_REGNUM
-              && value[NIOS2_SP_REGNUM].offset == 0)
+      else if (nios2_match_calli (insn, op, mach, &uimm))
        {
-         /* A CALL instruction.  This is treated as a call to mcount
-            if ra has been stored into r8 beforehand and if it's
-            before the stack adjust.
-            Note mcount corrupts r2-r3, r9-r15 & ra.  */
-         for (i = 2 ; i <= 3 ; i++)
-           value[i].reg = -1;
-         for (i = 9 ; i <= 15 ; i++)
-           value[i].reg = -1;
-         value[NIOS2_RA_REGNUM].reg = -1;
-
-         prologue_insn = 1;
-       }
+         if (value[8].reg == NIOS2_RA_REGNUM
+             && value[8].offset == 0
+             && value[NIOS2_SP_REGNUM].reg == NIOS2_SP_REGNUM
+             && value[NIOS2_SP_REGNUM].offset == 0)
+           {
+             /* A CALL instruction.  This is treated as a call to mcount
+                if ra has been stored into r8 beforehand and if it's
+                before the stack adjust.
+                Note mcount corrupts r2-r3, r9-r15 & ra.  */
+             for (i = 2 ; i <= 3 ; i++)
+               value[i].reg = -1;
+             for (i = 9 ; i <= 15 ; i++)
+               value[i].reg = -1;
+             value[NIOS2_RA_REGNUM].reg = -1;
+
+             prologue_end = pc;
+           }
 
-      else if ((insn & 0xf83fffff) == 0xd800012e)
-       {
-          /* BGEU sp, rx, +8
-             BREAK 3
-             This instruction sequence is used in stack checking;
-             we can ignore it.  */
-         unsigned int next_insn
-           = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order);
-
-         if (next_insn != 0x003da0fa)
-           within_prologue = 0;
+         /* Other calls are not part of the prologue.  */
          else
-           pc += NIOS2_OPCODE_SIZE;
-       }
-
-      else if ((insn & 0xf800003f) == 0xd8000036)
-       {
-          /* BLTU sp, rx, .Lstackoverflow
-             If the location branched to holds a BREAK 3 instruction
-             then this is also stack overflow detection.  We can
-             ignore it.  */
-         CORE_ADDR target_pc = pc + ((insn & 0x3fffc0) >> 6);
-         unsigned int target_insn
-           = read_memory_unsigned_integer (target_pc, NIOS2_OPCODE_SIZE,
-                                           byte_order);
-
-         if (target_insn != 0x003da0fa)
-           within_prologue = 0;
+           break;
        }
 
-      /* Any other instructions are allowed to be moved up into the
-        prologue.  If we reach a branch, call or return then the
-        prologue is considered over.  We also consider a second stack
-        adjustment as terminating the prologue (see above).  */
-      else
+      else if (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond))
        {
-         switch (GET_IW_R1_OP (insn))
+         /* Branches not involving a stack overflow check aren't part of
+            the prologue.  */
+         if (ra != NIOS2_SP_REGNUM)
+           break;
+         else if (cond == branch_geu)
            {
-           case R1_OP_BEQ:
-           case R1_OP_BGE:
-           case R1_OP_BGEU:
-           case R1_OP_BLT:
-           case R1_OP_BLTU:
-           case R1_OP_BNE:
-           case R1_OP_BR:
-           case R1_OP_CALL:
-             within_prologue = 0;
-             break;
-           case R1_OP_OPX:
-             if (GET_IW_R_OPX (insn) == R1_OPX_RET
-                 || GET_IW_R_OPX (insn) == R1_OPX_ERET
-                 || GET_IW_R_OPX (insn) == R1_OPX_BRET
-                 || GET_IW_R_OPX (insn) == R1_OPX_CALLR
-                 || GET_IW_R_OPX (insn) == R1_OPX_JMP)
-               within_prologue = 0;
-             break;
-           default:
-             break;
+             /* BGEU sp, rx, +8
+                BREAK 3
+                This instruction sequence is used in stack checking;
+                we can ignore it.  */
+             unsigned int next_insn;
+             const struct nios2_opcode *next_op
+               = nios2_fetch_insn (gdbarch, pc, &next_insn);
+             if (next_op != NULL
+                 && nios2_match_break (next_insn, op, mach, &uimm))
+               pc += next_op->size;
+             else
+               break;
            }
+         else if (cond == branch_ltu)
+           {
+             /* BLTU sp, rx, .Lstackoverflow
+                If the location branched to holds a BREAK 3 instruction
+                then this is also stack overflow detection.  */
+             unsigned int next_insn;
+             const struct nios2_opcode *next_op
+               = nios2_fetch_insn (gdbarch, pc + imm, &next_insn);
+             if (next_op != NULL
+                 && nios2_match_break (next_insn, op, mach, &uimm))
+               ;
+             else
+               break;
+           }
+         else
+           break;
        }
 
-      if (prologue_insn)
-       prologue_end = pc;
+      /* All other calls or jumps (including returns) terminate 
+        the prologue.  */
+      else if (nios2_match_callr (insn, op, mach, &ra)
+              || nios2_match_jmpr (insn, op, mach, &ra)
+              || nios2_match_jmpi (insn, op, mach, &uimm))
+       break;
     }
 
   /* If THIS_FRAME is NULL, we are being called from skip_prologue
@@ -858,7 +1126,6 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
 static CORE_ADDR
 nios2_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
 {
-  CORE_ADDR limit_pc;
   CORE_ADDR func_addr;
 
   struct nios2_unwind_cache cache;
@@ -886,21 +1153,19 @@ static const gdb_byte*
 nios2_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr,
                          int *bp_size)
 {
-  /* break encoding: 31->27  26->22  21->17  16->11 10->6 5->0 */
-  /*                 00000   00000   0x1d    0x2d   11111 0x3a */
-  /*                 00000   00000   11101   101101 11111 111010 */
-  /* In bytes:       00000000 00111011 01101111 11111010 */
-  /*                 0x0       0x3b    0x6f     0xfa */
-  static const gdb_byte breakpoint_le[] = {0xfa, 0x6f, 0x3b, 0x0};
-  static const gdb_byte breakpoint_be[] = {0x0, 0x3b, 0x6f, 0xfa};
-
   enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-
-  *bp_size = 4;
-  if (gdbarch_byte_order_for_code (gdbarch) == BFD_ENDIAN_BIG)
-    return breakpoint_be;
+  unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+
+  /* R1 break encoding:
+     ((0x1e << 17) | (0x34 << 11) | (0x1f << 6) | (0x3a << 0))
+     0x003da7fa */
+  static const gdb_byte r1_breakpoint_le[] = {0xfa, 0xa7, 0x3d, 0x0};
+  static const gdb_byte r1_breakpoint_be[] = {0x0, 0x3d, 0xa7, 0xfa};
+  *bp_size = NIOS2_OPCODE_SIZE;
+  if (byte_order_for_code == BFD_ENDIAN_BIG)
+    return r1_breakpoint_be;
   else
-    return breakpoint_le;
+    return r1_breakpoint_le;
 }
 
 /* Implement the print_insn gdbarch method.  */
@@ -1256,15 +1521,7 @@ static const struct frame_unwind nios2_stub_frame_unwind =
   nios2_stub_frame_sniffer
 };
 
-/* Helper function to read an instruction at PC.  */
 
-static unsigned long
-nios2_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR pc)
-{
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-
-  return read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order);
-}
 
 /* Determine where to set a single step breakpoint while considering
    branch prediction.  */
@@ -1274,88 +1531,79 @@ nios2_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  unsigned long inst;
-  int op;
-  int imm16;
+  unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  unsigned int insn;
+  const struct nios2_opcode *op = nios2_fetch_insn (gdbarch, pc, &insn);
   int ra;
   int rb;
-  int ras;
-  int rbs;
-  unsigned int rau;
-  unsigned int rbu;
-
-  inst = nios2_fetch_instruction (gdbarch, pc);
-  pc += NIOS2_OPCODE_SIZE;
-
-  imm16 = (short) GET_IW_I_IMM16 (inst);
-  ra = GET_IW_I_A (inst);
-  rb = GET_IW_I_B (inst);
-  ras = get_frame_register_signed (frame, ra);
-  rbs = get_frame_register_signed (frame, rb);
-  rau = get_frame_register_unsigned (frame, ra);
-  rbu = get_frame_register_unsigned (frame, rb);
-
-  switch (GET_IW_R1_OP (inst))
+  int imm;
+  unsigned int uimm;
+  int wb, ret;
+  enum branch_condition cond;
+
+  /* Do something stupid if we can't disassemble the insn at pc.  */
+  if (op == NULL)
+    return pc + NIOS2_OPCODE_SIZE;
+    
+  if (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond))
     {
-    case R1_OP_BEQ:
-      if (ras == rbs)
-       pc += imm16;
-      break;
-
-    case R1_OP_BGE:
-      if (ras >= rbs)
-        pc += imm16;
-      break;
-
-    case R1_OP_BGEU:
-      if (rau >= rbu)
-        pc += imm16;
-      break;
-
-    case R1_OP_BLT:
-      if (ras < rbs)
-        pc += imm16;
-      break;
+      int ras = get_frame_register_signed (frame, ra);
+      int rbs = get_frame_register_signed (frame, rb);
+      unsigned int rau = get_frame_register_unsigned (frame, ra);
+      unsigned int rbu = get_frame_register_unsigned (frame, rb);
 
-    case R1_OP_BLTU:
-      if (rau < rbu)
-        pc += imm16;
-      break;
-
-    case R1_OP_BNE:
-      if (ras != rbs)
-        pc += imm16;
-      break;
-
-    case R1_OP_BR:
-      pc += imm16;
-      break;
-
-    case R1_OP_JMPI:
-    case R1_OP_CALL:
-      pc = (pc & 0xf0000000) | (GET_IW_J_IMM26 (inst) << 2);
-      break;
-
-    case R1_OP_OPX:
-      switch (GET_IW_R_OPX (inst))
+      pc += op->size;
+      switch (cond)
        {
-       case R1_OPX_JMP:
-       case R1_OPX_CALLR:
-       case R1_OPX_RET:
-         pc = ras;
+       case branch_none:
+         pc += imm;
+         break;
+       case branch_eq:
+         if (ras == rbs)
+           pc += imm;
+         break;
+       case branch_ne:
+         if (ras != rbs)
+           pc += imm;
+         break;
+       case branch_ge:
+         if (ras >= rbs)
+           pc += imm;
+         break;
+       case branch_geu:
+         if (rau >= rbu)
+           pc += imm;
+         break;
+       case branch_lt:
+         if (ras < rbs)
+           pc += imm;
+         break;
+       case branch_ltu:
+         if (rau < rbu)
+           pc += imm;
          break;
-
-       case R1_OPX_TRAP:
-         if (tdep->syscall_next_pc != NULL)
-           return tdep->syscall_next_pc (frame);
-
        default:
          break;
        }
-      break;
-    default:
-      break;
     }
+
+  else if (nios2_match_jmpi (insn, op, mach, &uimm)
+          || nios2_match_calli (insn, op, mach, &uimm))
+    pc = (pc & 0xf0000000) | uimm;
+
+  else if (nios2_match_jmpr (insn, op, mach, &ra)
+          || nios2_match_callr (insn, op, mach, &ra))
+    pc = get_frame_register_unsigned (frame, ra);
+
+  else if (nios2_match_trap (insn, op, mach, &uimm))
+    {
+      if (tdep->syscall_next_pc != NULL)
+       return tdep->syscall_next_pc (frame);
+    }
+
+  else
+    pc += op->size;
+
   return pc;
 }