diff mbox

[nios2] clean up prologue/epilogue detection code

Message ID 545EA0C1.6050104@codesourcery.com
State New
Headers show

Commit Message

Sandra Loosemore Nov. 8, 2014, 11:01 p.m. UTC
This patch is another installment in the series of Nios II patches aimed 
at removing or isolating hard-wired instruction encodings.  This will 
make the code more extensible for the future addition of new instruction 
set revisions.

In this patch, all explicit matching of opcodes and masks in 
nios2_in_epilogue_p, nios2_analyze_prologue, and nios2_get_net_pc is 
eliminated in favor of invoking the disassembler (via 
nios2_find_opcode_hash) to do that part.  A new set of helper functions 
are introduced to extract instruction operands according to the format 
of the matched instruction opcode.  Future ISA extensions are likely to 
include multiple encodings of some logical operations, such as add or 
subtract, so this organization will allow those details to be 
consolidated in the new helper functions instead of handled inline at 
call sites for those functions.  Also, organizing the analysis by what 
the instructions being examined conceptually do instead of by their 
format and encoding makes it easier to understand.

This patch also fixes an outstanding bug in the code.  Formerly, there 
were assumptions that the prologue and epilogue could only include one 
stack adjustment each.  This used to be true of code emitted by GCC 
except for functions with stack frame too large to be addressed via a 
16-bit offset.  A change made to GCC earlier this year (r208472) to 
correct an ABI conformance issue also means that many functions with 
frame pointers now have an additional stack pointer adjustment too.  In 
lifting the restriction, I made the prologue analyzer a little smarter 
in differentiating valid prologue stack adjustments (decrementing the 
SP, setting the FP from the SP) from those that can only appear in 
epilogues (incrementing the SP, setting the SP from the FP).

Test results on nios2-elf look good.  OK to commit?

-Sandra

Comments

Yao Qi Nov. 11, 2014, 3:33 a.m. UTC | #1
Sandra Loosemore <sandra@codesourcery.com> writes:

Hi, Sandra,

> In this patch, all explicit matching of opcodes and masks in
> nios2_in_epilogue_p, nios2_analyze_prologue, and nios2_get_net_pc is
> eliminated in favor of invoking the disassembler (via
> nios2_find_opcode_hash) to do that part.  A new set of helper
> functions are introduced to extract instruction operands according to
> the format of the matched instruction opcode.  Future ISA extensions
> are likely to include multiple encodings of some logical operations,
> such as add or subtract, so this organization will allow those details
> to be consolidated in the new helper functions instead of handled
> inline at call sites for those functions.  Also, organizing the
> analysis by what the instructions being examined conceptually do
> instead of by their format and encoding makes it easier to understand.

Great, these helpers look very clear to me.

>
> This patch also fixes an outstanding bug in the code.  Formerly, there
> were assumptions that the prologue and epilogue could only include one
> stack adjustment each.  This used to be true of code emitted by GCC
> except for functions with stack frame too large to be addressed via a
> 16-bit offset.  A change made to GCC earlier this year (r208472) to
> correct an ABI conformance issue also means that many functions with
> frame pointers now have an additional stack pointer adjustment too.
> In lifting the restriction, I made the prologue analyzer a little
> smarter in differentiating valid prologue stack adjustments
> (decrementing the SP, setting the FP from the SP) from those that can
> only appear in epilogues (incrementing the SP, setting the SP from the
> FP).

These fixes should be in separate patches.  I'd like to see this patch
is split to a series which includes the following patches,

 1. add new helpers and rewrite existing functions with these new
 helpers,
 2. permit more than one stack adjustment instruction to appear in
 epilogue
 3. detect some additional prologue instruction patterns,

> diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c
> index 1b647ac..816b17b 100644
> --- a/gdb/nios2-tdep.c
> +++ b/gdb/nios2-tdep.c
> @@ -275,46 +275,398 @@ 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.  */

There should be an empty line between the end of comment and the function.

> +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)

Is there any reason you put these parameters in different lines?  We can
place them on the same line like:

static int
nios2_match_add (uint32_t insn, const struct nios2_opcode *op,
		 unsigned long mach, int *ra, int *rb, int *rc)

then the function can be shorter.

> +{
> +  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;
> +}
> +


> +
>  /* 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;
> +  /* Maximum number of possibly-epilogue instructions to check.
> +     Note that this number should not be too large, else we can
> +     potentially end up iterating through unmapped memory.  */
> +  int ninsns, max_insns = 5;
> +  unsigned int insn;
> +  const struct nios2_opcode *op = NULL;
> +  unsigned int uimm;
> +  int imm;
> +  int ra, rb, rc;
> +  enum branch_condition cond;
> +  CORE_ADDR pc;
>  
>    /* There has to be a previous instruction in the function.  */
> -  if (current_pc > start_pc)
> -    {
> +  if (current_pc <= start_pc)
> +    return 0;
>  
> -      /* 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);
> +  /* Find the previous instruction before current_pc.  */
> +  op = nios2_fetch_insn (gdbarch, current_pc - NIOS2_OPCODE_SIZE, &insn);
> +  if (op == NULL)
> +    return 0;
>  
> -      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;
> -	}
> +  /* Beginning with the previous instruction we just located, check whether
> +     we are in a sequence of at least one stack adjustment instruction.
> +     Possible instructions here include:
> +	 ADDI sp, sp, n
> +	 ADD sp, sp, rn
> +	 LDW sp, n(sp)  */
> +  for (ninsns = 0, pc = current_pc; ninsns < max_insns; ninsns++)
> +    {
> +      int ok = 0;

An empty line is needed between declaration and statement.

> +      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)
> +	break;
> +      /* Fetch the next insn.  */
> +      op = nios2_fetch_insn (gdbarch, pc, &insn);
> +      if (op == NULL)
> +	return 0;
> +      pc += op->size;
>      }
> +
> +  /* No stack adjustments found.  */
> +  if (ninsns == 0)
> +    return 0;
> +
> +  /* We found a whole lot of stack adjustments.  Be safe, tell GDB that
> +     the epilogue stack unwind is in progress even if we didn't see a
> +     return yet.  */
> +  if (ninsns == max_insns)
> +    return 1;

I am confused by the comments and code.  Infer from your code above that
GCC emits arbitrary number of sp-adjusting continuous instructions in
epilogue, is that true?

> +
> +  /* The next instruction following the stack adjustments must be a
> +     return, jump, or unconditional branch.  */
> +  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;
>  }
>  

Looks the epilogue detection isn't precise nor accurate.  Supposing we
have an epilogue like this below,

   1. ADDI sp, sp, n
   2. RET

if pc points at insn #1, nios2_in_epilogue_p returns true, which isn't
precise, because the stack frame isn't destroyed at the moment pc points
at insn #1.  gdbarch in_function_epilogue_p's name is misleading, and
better to be renamed to stack_frame_destroyed_p (it's on my todo list).

if pc points at insn #2, nios2_in_epilogue_p returns false, which isn't
accurate.

Probably, we need do the forward scan first, skipping arbitrary number of
sp-adjusting instructions until a return or jump, and then do a backward
scan to match a sp-adjusting instruction.  In this case, return true,
otherwise, return false.  Hopefully, this fixes some sw watchpoint
related test fails.

>  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;
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

Why do we change from byte_order_for_code to byte_order?

> +  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 == BFD_ENDIAN_BIG)
> +    return r1_breakpoint_be;
>    else
> -    return breakpoint_le;
> +    return r1_breakpoint_le;
>  }
>
Sandra Loosemore Nov. 24, 2014, 11:52 p.m. UTC | #2
On 11/10/2014 08:33 PM, Yao Qi wrote:

> These fixes should be in separate patches.  I'd like to see this patch
> is split to a series which includes the following patches,
>
>   1. add new helpers and rewrite existing functions with these new
>   helpers,
>   2. permit more than one stack adjustment instruction to appear in
>   epilogue
>   3. detect some additional prologue instruction patterns,

Hmmm, OK (although this required rewriting code for part 1 that is 
promptly going to get thrown away again with parts 2 and 3).

> There should be an empty line between the end of comment and the function.

Fixed throughout the patch.

>> +
>> +/* 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)
>
> Is there any reason you put these parameters in different lines?  We can
> place them on the same line like:
>
> static int
> nios2_match_add (uint32_t insn, const struct nios2_opcode *op,
> 		 unsigned long mach, int *ra, int *rb, int *rc)
>
> then the function can be shorter.

Fixed here and elsewhere.

> An empty line is needed between declaration and statement.

Fixed.

>> +  /* We found a whole lot of stack adjustments.  Be safe, tell GDB that
>> +     the epilogue stack unwind is in progress even if we didn't see a
>> +     return yet.  */
>> +  if (ninsns == max_insns)
>> +    return 1;
>
> I am confused by the comments and code.  Infer from your code above that
> GCC emits arbitrary number of sp-adjusting continuous instructions in
> epilogue, is that true?

No, GCC doesn't emit an arbitrary number of SP-adjusting instructions, 
but what should GDB do if it gets some code that looks like that?  I've 
rewritten the comment to make it more clear that this is a "shouldn't 
happen" situation.

> Looks the epilogue detection isn't precise nor accurate.  Supposing we
> have an epilogue like this below,
>
>     1. ADDI sp, sp, n
>     2. RET
>
> if pc points at insn #1, nios2_in_epilogue_p returns true, which isn't
> precise, because the stack frame isn't destroyed at the moment pc points
> at insn #1.  gdbarch in_function_epilogue_p's name is misleading, and
> better to be renamed to stack_frame_destroyed_p (it's on my todo list).
>
> if pc points at insn #2, nios2_in_epilogue_p returns false, which isn't
> accurate.

I think that you have gotten confused by the pc and insn variables being 
updated out of sync in the scanning loop.  I have rewritten the loop 
code and the comments to make it more obvious that scanning for stack 
adjustments starts at the instruction before current_pc.  It doesn't 
matter if there have been additional stack adjustments in the sequence 
of instructions before that -- we only need to see one to know that the 
stack teardown is already in progress at current_pc.

> Why do we change from byte_order_for_code to byte_order?

Leftover bits from some other changes that aren't ready to commit yet. 
I've put it back the way it was.

New patch set coming up shortly.

-Sandra
diff mbox

Patch

diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c
index 1b647ac..816b17b 100644
--- a/gdb/nios2-tdep.c
+++ b/gdb/nios2-tdep.c
@@ -275,46 +275,398 @@  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;
+  /* Maximum number of possibly-epilogue instructions to check.
+     Note that this number should not be too large, else we can
+     potentially end up iterating through unmapped memory.  */
+  int ninsns, max_insns = 5;
+  unsigned int insn;
+  const struct nios2_opcode *op = NULL;
+  unsigned int uimm;
+  int imm;
+  int ra, rb, rc;
+  enum branch_condition cond;
+  CORE_ADDR pc;
 
   /* There has to be a previous instruction in the function.  */
-  if (current_pc > start_pc)
-    {
+  if (current_pc <= start_pc)
+    return 0;
 
-      /* 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);
+  /* Find the previous instruction before current_pc.  */
+  op = nios2_fetch_insn (gdbarch, current_pc - NIOS2_OPCODE_SIZE, &insn);
+  if (op == NULL)
+    return 0;
 
-      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;
-	}
+  /* Beginning with the previous instruction we just located, check whether
+     we are in a sequence of at least one stack adjustment instruction.
+     Possible instructions here include:
+	 ADDI sp, sp, n
+	 ADD sp, sp, rn
+	 LDW sp, n(sp)  */
+  for (ninsns = 0, pc = current_pc; ninsns < max_insns; ninsns++)
+    {
+      int ok = 0;
+      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)
+	break;
+      /* Fetch the next insn.  */
+      op = nios2_fetch_insn (gdbarch, pc, &insn);
+      if (op == NULL)
+	return 0;
+      pc += op->size;
     }
+
+  /* No stack adjustments found.  */
+  if (ninsns == 0)
+    return 0;
+
+  /* We found a whole lot of stack adjustments.  Be safe, tell GDB that
+     the epilogue stack unwind is in progress even if we didn't see a
+     return yet.  */
+  if (ninsns == max_insns)
+    return 1;
+
+  /* The next instruction following the stack adjustments must be a
+     return, jump, or unconditional branch.  */
+  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 +689,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 +723,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 +742,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 +769,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 +783,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 +809,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)
@@ -512,6 +854,11 @@  nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
 	      cache->reg_saved[NIOS2_SP_REGNUM].addr = -4;
 	    }
 
+	  else if (rc == NIOS2_SP_REGNUM && ra == NIOS2_FP_REGNUM)
+	    /* This is setting SP from FP.  This only happens in the
+	       function epilogue.  */
+	    break;
+
 	  else if (rc != 0)
 	    {
 	      if (value[rb].reg == 0)
@@ -522,18 +869,22 @@  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)
+	  /* The add/move is only considered a prologue instruction
+	     if the destination is SP or FP.  */
+	  if (rc == NIOS2_SP_REGNUM || rc == NIOS2_FP_REGNUM)
+	    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 (rc == NIOS2_SP_REGNUM && rb == NIOS2_SP_REGNUM
+	      && value[rc].reg != 0)
+	    /* If we are decrementing the SP by a non-constant amount,
+	       this is alloca, not part of the prologue.  */
+	    break;
+	  else if (rc != 0)
 	    {
 	      if (value[rb].reg == 0)
 		value[rc].reg = value[ra].reg;
@@ -543,184 +894,155 @@  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);
-
-	  /* The first stack adjustment is part of the prologue.
-	     Any subsequent stack adjustments are either down to
-	     alloca or the epilogue so stop analysing when we hit
-	     them.  */
+	  /* ADDI    rb, ra, imm */
+
+	  /* A positive stack adjustment has to be part of the epilogue.  */
 	  if (rb == NIOS2_SP_REGNUM
-	      && (value[rb].offset != 0 || value[ra].reg != NIOS2_SP_REGNUM))
+	      && (imm > 0 || value[ra].reg != NIOS2_SP_REGNUM))
+	    break;
+
+	  /* Likewise restoring SP from FP.  */
+	  else if (rb == NIOS2_SP_REGNUM && ra == NIOS2_FP_REGNUM)
 	    break;
 
 	  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;
+	  /* The add is only considered a prologue instruction
+	     if the destination is SP or FP.  */
+	  if (rb == NIOS2_SP_REGNUM || rb == NIOS2_FP_REGNUM)
+	    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) */
-
-	  short immed16 = GET_IW_I_IMM16 (insn);
-	  int ra = GET_IW_I_A (insn);
-	  int rb = GET_IW_I_B (insn);
+	  /* STW rb, imm(ra) */
 
-	  /* 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)
+	    {
+	      /* 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)
 	    {
-	    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;
+	      /* 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 +1180,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 +1207,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;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  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 == BFD_ENDIAN_BIG)
+    return r1_breakpoint_be;
   else
-    return breakpoint_le;
+    return r1_breakpoint_le;
 }
 
 /* Implement the print_insn gdbarch method.  */
@@ -1256,15 +1575,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 +1585,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;
-
-    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;
+      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_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;
 }