[v3,08/10] Support software single step on ARM in GDBServer.

Message ID 1448287968-12907-9-git-send-email-antoine.tremblay@ericsson.com
State New, archived
Headers

Commit Message

Antoine Tremblay Nov. 23, 2015, 2:12 p.m. UTC
  In this v3:

 * The common arm_get_next_pcs call has been refactored the same way like
so : VEC (CORE_ADDR) *arm_get_next_pcs (struct arm_get_next_pcs *ctx,
CORE_ADDR pc);

 * Use ctor functions to construct gdb|gdbserver_get_next_pcs context.

 * Some style fixes.

---

This patch teaches GDBserver how to software single step on ARM
linux by sharing code with GDB.

The arm_get_next_pcs function in GDB is now shared with GDBServer.  So that
GDBServer can use the function to return the possible addresses of the next PC.

A proper shared context was also needed so that we could share the code, this
context is described as this data structure (expressed as a class
hierarchy):

  struct arch_get_next_pcs
    struct arch_(gdb|gdbserver)_get_next_pcs

Where arch can by replaced by arm for this patch. This structure should be
flexible enough to accomodate any arch that would need a get_next_pcs
context.

Limitations :

GDBServer can't step over a sigreturn or rt_sigreturn syscall since this would
require the DWARF information to identify the caller PC. This situation
only prints a warning for the moment.

Testing :

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/ChangeLog:
	* Makefile.in: Add arm-get-next-pcs.c/o to all arm targets.
	* aarch32-linux-nat.c: Include arch/arm-get-next-pcs.h.
	* arch/arm-get-next-pcs.c: New file.
	* arch/arm-get-next-pcs.h: New file.
	* arm-linux-nat.c: Include arch/arm.h and arch/arm-get-next-pcs.h
	* arm-linux-tdep.c: (arm_linux_software_single_step): Adjust for
	arm_get_next_pcs implementation.
	* arm-tdep.c (submask): Move macro to arm-get-next-pcs.h.
	(bit): Likewise.
	(bits): Likewise.
	(sbits): Likewise.
	(BranchDest): Likewise.
	(thumb_instruction_changes_pc): Move to arm-get-next-pcs.c
	(thumb2_instruction_changes_pc): Likewise.
	(arm_instruction_changes_pc): Likewise.
	(thumb_advance_itstate): Likewise.
	(thumb_get_next_pc_raw): Likewise.
	(arm_get_next_pc_raw): Likewise.
	(arm_get_next_pc): Likewise.
	(thumb_deal_with_atomic_sequence_raw): Likewise.
	(arm_deal_with_atomic_sequence_raw): Likewise.
	(arm_deal_with_atomic_sequence): Likewise.
	(arm_get_next_pcs_read_memory_unsigned_integer): New function.
	(arm_get_next_pcs_addr_bits_remove): Likewise.
	(arm_get_next_pcs_collect_register_unsigned): Likewise.
	(arm_get_next_pcs_syscall_next_pc): Likewise.
	(arm_software_single_step): Adjust for arm_get_next_pcs
	implementation.
	(arm_gdb_get_next_pcs_ctor): New function.
	* arm-tdep.h (arm_get_next_pcs_read_memory_unsigned_integer):
	New declaration.
	(arm_get_next_pcs_addr_bits_remove): Likewise.
	(arm_get_next_pcs_collect_register_unsigned): Likewise.
	(arm_get_next_pcs_syscall_next_pc): Likewise.
	(arm_software_single_step): Likewise.
	(arm_deal_with_atomic_sequence: Remove declaration.
	(arm_software_single_step): Likewise.
	(struct arm_gdb_get_next_pcs): New struct.
	(arm_gdb_get_next_pcs_ctor) New function declaration.
	* arm-wince-tdep.c: Include arch/arm-get-next-pcs.h.
	* armbsd-tdep.c: Likewise.
	* armnbsd-tdep.c: Likewise.
	* armobsd-tdep.c: Likewise.
	* configure.tgt: Add arm-get-next-pcs.o to all arm targets.
	* common/gdb_vecs.h: Add CORE_ADDR vector definition.
	* symtab.h: Move CORE_ADDR vector definition to gdb_vecs.h.

gdb/gdbserver/ChangeLog:
	* Makefile.in : Add arm-get-next-pcs.c/o.
	* configure.srv: Add arm-get-next-pcs.o to needed arm targets.
	* linux-arm-low.c (get_next_pcs_addr_bits_remove): New function.
	(get_next_pcs_collect_register_unsigned): Likewise.
	(get_next_pcs_read_memory_unsigned_integer): Likewise.
	(get_next_pcs_syscall_next_pc): Likewise.
	(arm_gdbserver_get_next_pcs): Likewise.
	(struct linux_target_ops) <arm_gdbserver_get_next_pcs>:
	Initialize.
	(struct arm_gdbserver_get_next_pcs): New struct.
	(arm_gdbserver_get_next_pcs_ctor): New function.
	* linux-low.h: Move CORE_ADDR vector definition to gdb_vecs.h.
	* server.h: Include gdb_vecs.h.
---
 gdb/Makefile.in               |   12 +-
 gdb/aarch32-linux-nat.c       |    1 +
 gdb/arch/arm-get-next-pcs.c   | 1234 +++++++++++++++++++++++++++++++++
 gdb/arch/arm-get-next-pcs.h   |   98 +++
 gdb/arm-linux-nat.c           |    2 +
 gdb/arm-linux-tdep.c          |   53 +-
 gdb/arm-tdep.c                | 1507 ++++++-----------------------------------
 gdb/arm-tdep.h                |   46 +-
 gdb/arm-wince-tdep.c          |    1 +
 gdb/armbsd-tdep.c             |    1 +
 gdb/armnbsd-tdep.c            |    1 +
 gdb/armobsd-tdep.c            |    1 +
 gdb/common/gdb_vecs.h         |    2 +
 gdb/configure.tgt             |   19 +-
 gdb/gdbserver/Makefile.in     |    5 +-
 gdb/gdbserver/configure.srv   |    1 +
 gdb/gdbserver/linux-arm-low.c |  168 ++++-
 gdb/gdbserver/linux-low.h     |    2 -
 gdb/gdbserver/server.h        |    1 +
 gdb/symtab.h                  |    2 -
 20 files changed, 1833 insertions(+), 1324 deletions(-)
 create mode 100644 gdb/arch/arm-get-next-pcs.c
 create mode 100644 gdb/arch/arm-get-next-pcs.h
  

Comments

Pedro Alves Nov. 26, 2015, 10:49 a.m. UTC | #1
On 11/23/2015 02:12 PM, Antoine Tremblay wrote:
> In this v3:
> 
>  * The common arm_get_next_pcs call has been refactored the same way like
> so : VEC (CORE_ADDR) *arm_get_next_pcs (struct arm_get_next_pcs *ctx,
> CORE_ADDR pc);
> 
>  * Use ctor functions to construct gdb|gdbserver_get_next_pcs context.
> 
>  * Some style fixes.
> 
> ---
> 
> This patch teaches GDBserver how to software single step on ARM
> linux by sharing code with GDB.
> 
> The arm_get_next_pcs function in GDB is now shared with GDBServer.  So that
> GDBServer can use the function to return the possible addresses of the next PC.
> 
> A proper shared context was also needed so that we could share the code, this
> context is described as this data structure (expressed as a class
> hierarchy):
> 
>   struct arch_get_next_pcs
>     struct arch_(gdb|gdbserver)_get_next_pcs
> 
> Where arch can by replaced by arm for this patch. This structure should be
> flexible enough to accomodate any arch that would need a get_next_pcs
> context.

(accommodate)

> 
> Limitations :
> 
> GDBServer can't step over a sigreturn or rt_sigreturn syscall since this would
> require the DWARF information to identify the caller PC. This situation
> only prints a warning for the moment.

I wonder whether this ends up being a regression?  E.g., if you
put a breakpoint with a condition that evals false, on top of such an
instruction?

I wonder whether this ends up being a regression, or whether it only trigger
on new features, like tracepoints?  I'm thinking that it may be a
regression for the case of a conditional breakpoint with a conditional
evaluated on the target?

Other than the warning, what happens?  Does gdbserver lose control of
the inferior?

> +  /* Insert a breakpoint right after the end of the atomic sequence.  */
> +  breaks[0] = loc;
> +
> +  /* Check for duplicated breakpoints.  Check also for a breakpoint
> +     placed (branch instruction's destination) anywhere in sequence.  */
> +  if (last_breakpoint
> +      && (breaks[1] == breaks[0]
> +	  || (breaks[1] >= pc && breaks[1] < loc)))
> +    last_breakpoint = 0;
> +
> +  /* Adds the breakpoints to the list to be inserted.  */
> +  for (index = 0; index <= last_breakpoint; index++)
> +    {
> +      VEC_safe_push (CORE_ADDR, *next_pcs, MAKE_THUMB_ADDR (breaks[index]));
> +    }

No braces.

> +
> +  return 1;
> +}
> +



> +  else if (itstate & 0x0f)
> +    {
> +      /* We are in a conditional block.  Check the condition.  */
> +      int cond = itstate >> 4;
> +
> +      if (! condition_true (cond, status))
> +	/* Advance to the next instruction.  All the 32-bit
> +	   instructions share a common prefix.  */
> +	VEC_safe_push (CORE_ADDR, *next_pcs,
> +		       MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1)));

Here there should be braces around the comment and the VEC call.

> +
> +      return *next_pcs;
> +
> +      /* Otherwise, handle the instruction normally.  */
> +    }


> @@ -912,27 +922,44 @@ arm_linux_software_single_step (struct frame_info *frame)
>  {
>    struct gdbarch *gdbarch = get_frame_arch (frame);
>    struct address_space *aspace = get_frame_address_space (frame);
> -  CORE_ADDR next_pc;
> -
> -  if (arm_deal_with_atomic_sequence (frame))
> -    return 1;
> +  struct arm_gdb_get_next_pcs next_pcs_ctx;
> +  CORE_ADDR pc;
> +  int i;
> +  VEC (CORE_ADDR) *next_pcs = NULL;
>  
>    /* If the target does have hardware single step, GDB doesn't have
>       to bother software single step.  */
>    if (target_can_do_single_step () == 1)
>      return 0;
>  
> -  next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
> +  arm_gdb_get_next_pcs_ctor (&next_pcs_ctx,
> +			     &arm_linux_get_next_pcs_ops,
> +			     gdbarch_byte_order (gdbarch),
> +			     gdbarch_byte_order_for_code (gdbarch),
> +			     arm_frame_is_thumb (frame),
> +			     arm_apcs_32,
> +			     gdbarch_tdep (gdbarch)->thumb2_breakpoint,
> +			     frame,
> +			     gdbarch);
>  
> -  /* The Linux kernel offers some user-mode helpers in a high page.  We can
> -     not read this page (as of 2.6.23), and even if we could then we couldn't
> -     set breakpoints in it, and even if we could then the atomic operations
> -     would fail when interrupted.  They are all called as functions and return
> -     to the address in LR, so step to there instead.  */
> -  if (next_pc > 0xffff0000)
> -    next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
> +  next_pcs = arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs_ctx,
> +			       get_frame_pc (frame));
> +
> +  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
> +    {
> +      /* The Linux kernel offers some user-mode helpers in a high page.  We can
> +	 not read this page (as of 2.6.23), and even if we could then we
> +	 couldn't set breakpoints in it, and even if we could then the atomic
> +	 operations would fail when interrupted.  They are all called as
> +	 functions and return to the address in LR, so step to there
> +	 instead.  */
> +      if (pc > 0xffff0000)
> +	pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
> +
> +      arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
> +    }
>  
> -  arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
> +  VEC_free (CORE_ADDR, next_pcs);

This would be better freed with a cleanup:

    VEC (CORE_ADDR) *next_pcs = NULL;
    old_chain = make_cleanup (VEC_cleanup (CORE_ADDR), next_pcs);

    ...

    do_cleanups (old_chain);

>  
>    return 1;
>  }


>        /* There's a lot of code before this instruction.  Start with an
>  	 optimistic search; it's easy to recognize halfwords that can
> @@ -7291,6 +6106,116 @@ thumb2_copy_block_xfer (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
>    return 0;
>  }
>  
> +/* Initialize arm_gdb_get_next_pcs_stor.  */

/* Initialize arm_gdb_get_next_pcs.  */


> +void
> +arm_gdb_get_next_pcs_ctor (struct arm_gdb_get_next_pcs *self,
> +			   struct arm_get_next_pcs_ops *ops,
> +			   int byte_order,



> +/* 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 instructions
> +   and breakpoint them.  */
> +
> +int
> +arm_software_single_step (struct frame_info *frame)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  struct address_space *aspace = get_frame_address_space (frame);
> +  struct arm_gdb_get_next_pcs next_pcs_ctx;
> +  CORE_ADDR pc;
> +  int i;
> +  VEC (CORE_ADDR) *next_pcs = NULL;
> +
> +  arm_gdb_get_next_pcs_ctor (&next_pcs_ctx,
> +			     &arm_get_next_pcs_ops,
> +			     gdbarch_byte_order (gdbarch),
> +			     gdbarch_byte_order_for_code (gdbarch),
> +			     arm_frame_is_thumb (frame),
> +			     arm_apcs_32,
> +			     gdbarch_tdep (gdbarch)->thumb2_breakpoint,
> +			     frame,
> +			     gdbarch);
> +
> +  next_pcs = arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs,

This is wrong.  Should be  "(struct arm_get_next_pcs *) &next_pcs_ctx" instead.

I think this shows that it'd be good to run the series against the
testsuite on native ARM.

You could avoid these wrong casts by writting "&next_pcs_ctx.base" instead.

> +			       get_frame_pc (frame));
> +
> +  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
> +    {
> +      arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
> +    }

No braces.

> +
> +  VEC_free (CORE_ADDR, next_pcs);

Use a cleanup instead.

> +
> +  return 1;
> +}
> +
>  /* Cleanup/copy SVC (SWI) instructions.  These two functions are overridden
>     for Linux, where some SVC instructions must be treated specially.  */
>  
> diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
> index 9b8447b..f3a13a4 100644
> --- a/gdb/arm-tdep.h
> +++ b/gdb/arm-tdep.h
> @@ -23,6 +23,9 @@
>  struct gdbarch;
>  struct regset;
>  struct address_space;
> +struct get_next_pcs;
> +struct arm_get_next_pcs;
> +struct gdb_get_next_pcs;
>  
>  #include "arch/arm.h"
>  
> @@ -221,6 +224,17 @@ struct displaced_step_closure
>  		   struct displaced_step_closure *);
>  };
>  
> +/* Context for a get_next_pcs call on ARM in GDB.  */
> +struct arm_gdb_get_next_pcs
> +{
> +  /* Common context for gdb/gdbserver.  */
> +  struct arm_get_next_pcs base;
> +  /* Frame information.  */
> +  struct frame_info *frame;
> +  /* Architecture dependent information.  */
> +  struct gdbarch *gdbarch;
> +};
> +
>  /* Values for the WRITE_PC argument to displaced_write_reg.  If the register
>     write may write to the PC, specifies the way the CPSR T bit, etc. is
>     modified by the instruction.  */
> @@ -250,11 +264,37 @@ extern void
>  		       ULONGEST val, enum pc_write_style write_pc);
>  
>  CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
> -CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);
> +
> +ULONGEST arm_get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr,
> +							int len,
> +							int byte_order);
> +
> +void arm_gdb_get_next_pcs_ctor (struct arm_gdb_get_next_pcs *self,
> +				struct arm_get_next_pcs_ops *ops,
> +				int byte_order,
> +				int byte_order_for_code,
> +				int is_thumb,
> +				int arm_apcs_32,
> +				const gdb_byte *arm_thumb2_breakpoint,
> +				struct frame_info *frame,
> +				struct gdbarch *gdbarch);
> +
> +CORE_ADDR
> +arm_get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self,

See extension.h for how to indent these long declarations.  The function
name should not be at column 0.

> +				   CORE_ADDR val);
> +
> +ULONGEST
> +arm_get_next_pcs_collect_register_unsigned (struct arm_get_next_pcs *self,
> +					    int n);
> +
> +CORE_ADDR
> +arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc);
> +
> +int arm_software_single_step (struct frame_info *frame);
> +


> +
>  /* These are in <asm/elf.h> in current kernels.  */
>  #define HWCAP_VFP       64
>  #define HWCAP_IWMMXT    512
> @@ -146,6 +156,29 @@ static int arm_regmap[] = {
>    64
>  };
>  
> +/* Forward declarations needed for get_next_pcs ops.  */
> +static ULONGEST
> +get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr,
> +					   int len,
> +					   int byte_order);
> +
> +static ULONGEST
> +get_next_pcs_collect_register_unsigned (struct arm_get_next_pcs *self, int n);
> +
> +static CORE_ADDR
> +get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, CORE_ADDR val);
> +
> +static CORE_ADDR
> +get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc);
> +

Ditto.


Thanks,
Pedro Alves
  
Yao Qi Nov. 26, 2015, 12:48 p.m. UTC | #2
Antoine Tremblay <antoine.tremblay@ericsson.com> writes:

> Limitations :
>
> GDBServer can't step over a sigreturn or rt_sigreturn syscall since this would
> require the DWARF information to identify the caller PC. This situation
> only prints a warning for the moment.

They are using frame not DWARF to identify the PC, however, it is not
necessary.  When GDB or GDBserver is doing software single step, it must
be in the inner-most frame, so we can get the caller PC by examining the
stack at a certain offset from SP (from regcache), like what are doing in
arm_linux_sigreturn_init and arm_linux_rt_sigreturn_init, rather than
replying frame unwinding.  See my comments to arm_get_next_pcs_syscall_next_pc.

> +
> +/* Wrapper over syscall_next_pc for use in get_next_pcs.  */
> +
> +CORE_ADDR
> +arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc)
> +{
> +  struct arm_gdb_get_next_pcs *next_pcs = (struct arm_gdb_get_next_pcs *) self;
> +  struct gdbarch_tdep *tdep;
> +
> +  tdep = gdbarch_tdep (next_pcs->gdbarch);
> +  if (tdep->syscall_next_pc != NULL)
> +    return tdep->syscall_next_pc (next_pcs->frame);
> +
> +  return 0;
> +}
> +


> +/* When PC is at a syscall instruction, return the PC of the next
> +   instruction to be executed.  */
> +static CORE_ADDR
> +get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc)
> +{
> +  CORE_ADDR return_addr = 0;
> +  int is_thumb = self->is_thumb;
> +  ULONGEST svc_number = 0;
> +
> +  if (is_thumb)
> +    {
> +      svc_number = self->ops->collect_register_unsigned (self, 7);
> +      return_addr = pc + 2;
> +    }
> +  else
> +    {
> +      unsigned long this_instr = self->ops->read_memory_unsigned_integer
> +	((CORE_ADDR) pc, 4, self->byte_order_for_code);
> +
> +      unsigned long svc_operand = (0x00ffffff & this_instr);
> +      if (svc_operand)  /* OABI.  */
> +	{
> +	  svc_number = svc_operand - 0x900000;
> +	}
> +      else /* EABI.  */
> +	{
> +	  svc_number = self->ops->collect_register_unsigned (self, 7);
> +	}
> +
> +      return_addr = pc + 4;
> +    }
> +
> +  /* Is this a sigreturn or rt_sigreturn syscall?
> +     If so it is currently not handeled.  */
> +  if (svc_number == 119 || svc_number == 173)
> +    {
> +      if (debug_threads)
> +	debug_printf ("Unhandled sigreturn or rt_sigreturn syscall\n");

We can still compute the caller pc by examining stack.

> +    }
> +
> +  /* Addresses for calling Thumb functions have the bit 0 set.  */
> +  if (is_thumb)
> +    return_addr = MAKE_THUMB_ADDR (return_addr);
> +
> +  return return_addr;
> +}
>  

This leads me thinking more about current software single step code in
GDB.  In GDB side, we are using frame to access registers, while in
GDBserver, we are using regcache.  Why don't we use regcache in both
sides? so that the "struct arm_get_next_pcs_ops" can be simplified, for
example, field collect_register_unsigned may be no longer necessary.

In fact, software_single_step used to have regcache argument, added by
https://sourceware.org/ml/gdb-patches/2007-04/msg00218.html but we
changed to argument frame
https://sourceware.org/ml/gdb-patches/2007-04/msg00218.html  IMO, it is
better to use regcache than frame.  We have two options,

 #1, switch from frame apis to regcache apis to access registers in arm
  software single step.  We can get regcache by get_current_regcache ().
 #2, change argument of gdbarch method software_single_step from frame
  to regcache, which means all its implementations need update, and
  switch to regcache apis to access registers.

#2 is the right way to go in long term, and we really need to improve
software_single_step.  Let me what do you think.
  
Antoine Tremblay Nov. 26, 2015, 1:35 p.m. UTC | #3
On 11/26/2015 05:49 AM, Pedro Alves wrote:
> On 11/23/2015 02:12 PM, Antoine Tremblay wrote:
>> In this v3:
>>
>>   * The common arm_get_next_pcs call has been refactored the same way like
>> so : VEC (CORE_ADDR) *arm_get_next_pcs (struct arm_get_next_pcs *ctx,
>> CORE_ADDR pc);
>>
>>   * Use ctor functions to construct gdb|gdbserver_get_next_pcs context.
>>
>>   * Some style fixes.
>>
>> ---
>>
>> This patch teaches GDBserver how to software single step on ARM
>> linux by sharing code with GDB.
>>
>> The arm_get_next_pcs function in GDB is now shared with GDBServer.  So that
>> GDBServer can use the function to return the possible addresses of the next PC.
>>
>> A proper shared context was also needed so that we could share the code, this
>> context is described as this data structure (expressed as a class
>> hierarchy):
>>
>>    struct arch_get_next_pcs
>>      struct arch_(gdb|gdbserver)_get_next_pcs
>>
>> Where arch can by replaced by arm for this patch. This structure should be
>> flexible enough to accomodate any arch that would need a get_next_pcs
>> context.
>
> (accommodate)
>
Fixed.

>>
>> Limitations :
>>
>> GDBServer can't step over a sigreturn or rt_sigreturn syscall since this would
>> require the DWARF information to identify the caller PC. This situation
>> only prints a warning for the moment.
>
> I wonder whether this ends up being a regression?  E.g., if you
> put a breakpoint with a condition that evals false, on top of such an
> instruction?

Yes I think it could, I'll see if I can reproduce that.

>
> I wonder whether this ends up being a regression, or whether it only trigger
> on new features, like tracepoints?

That was my initial assessment but I think it could be a regression indeed.

  I'm thinking that it may be a
> regression for the case of a conditional breakpoint with a conditional
> evaluated on the target?
>
> Other than the warning, what happens?  Does gdbserver lose control of
> the inferior?
>

It will lose control, Yao has suggested a solution, I will look into it.


>> +  /* Insert a breakpoint right after the end of the atomic sequence.  */
>> +  breaks[0] = loc;
>> +
>> +  /* Check for duplicated breakpoints.  Check also for a breakpoint
>> +     placed (branch instruction's destination) anywhere in sequence.  */
>> +  if (last_breakpoint
>> +      && (breaks[1] == breaks[0]
>> +	  || (breaks[1] >= pc && breaks[1] < loc)))
>> +    last_breakpoint = 0;
>> +
>> +  /* Adds the breakpoints to the list to be inserted.  */
>> +  for (index = 0; index <= last_breakpoint; index++)
>> +    {
>> +      VEC_safe_push (CORE_ADDR, *next_pcs, MAKE_THUMB_ADDR (breaks[index]));
>> +    }
>
> No braces.
>
Fixed. and in the other place in the file too.

>> +
>> +  return 1;
>> +}
>> +
>
>
>
>> +  else if (itstate & 0x0f)
>> +    {
>> +      /* We are in a conditional block.  Check the condition.  */
>> +      int cond = itstate >> 4;
>> +
>> +      if (! condition_true (cond, status))
>> +	/* Advance to the next instruction.  All the 32-bit
>> +	   instructions share a common prefix.  */
>> +	VEC_safe_push (CORE_ADDR, *next_pcs,
>> +		       MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1)));
>
> Here there should be braces around the comment and the VEC call.
>

Ok.

>> +
>> +      return *next_pcs;
>> +
>> +      /* Otherwise, handle the instruction normally.  */
>> +    }
>
>
>> @@ -912,27 +922,44 @@ arm_linux_software_single_step (struct frame_info *frame)
>>   {
>>     struct gdbarch *gdbarch = get_frame_arch (frame);
>>     struct address_space *aspace = get_frame_address_space (frame);
>> -  CORE_ADDR next_pc;
>> -
>> -  if (arm_deal_with_atomic_sequence (frame))
>> -    return 1;
>> +  struct arm_gdb_get_next_pcs next_pcs_ctx;
>> +  CORE_ADDR pc;
>> +  int i;
>> +  VEC (CORE_ADDR) *next_pcs = NULL;
>>
>>     /* If the target does have hardware single step, GDB doesn't have
>>        to bother software single step.  */
>>     if (target_can_do_single_step () == 1)
>>       return 0;
>>
>> -  next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
>> +  arm_gdb_get_next_pcs_ctor (&next_pcs_ctx,
>> +			     &arm_linux_get_next_pcs_ops,
>> +			     gdbarch_byte_order (gdbarch),
>> +			     gdbarch_byte_order_for_code (gdbarch),
>> +			     arm_frame_is_thumb (frame),
>> +			     arm_apcs_32,
>> +			     gdbarch_tdep (gdbarch)->thumb2_breakpoint,
>> +			     frame,
>> +			     gdbarch);
>>
>> -  /* The Linux kernel offers some user-mode helpers in a high page.  We can
>> -     not read this page (as of 2.6.23), and even if we could then we couldn't
>> -     set breakpoints in it, and even if we could then the atomic operations
>> -     would fail when interrupted.  They are all called as functions and return
>> -     to the address in LR, so step to there instead.  */
>> -  if (next_pc > 0xffff0000)
>> -    next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
>> +  next_pcs = arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs_ctx,
>> +			       get_frame_pc (frame));
>> +
>> +  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
>> +    {
>> +      /* The Linux kernel offers some user-mode helpers in a high page.  We can
>> +	 not read this page (as of 2.6.23), and even if we could then we
>> +	 couldn't set breakpoints in it, and even if we could then the atomic
>> +	 operations would fail when interrupted.  They are all called as
>> +	 functions and return to the address in LR, so step to there
>> +	 instead.  */
>> +      if (pc > 0xffff0000)
>> +	pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
>> +
>> +      arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
>> +    }
>>
>> -  arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
>> +  VEC_free (CORE_ADDR, next_pcs);
>
> This would be better freed with a cleanup:
>
>      VEC (CORE_ADDR) *next_pcs = NULL;
>      old_chain = make_cleanup (VEC_cleanup (CORE_ADDR), next_pcs);
>
>      ...
>
>      do_cleanups (old_chain);
>
>>
>>     return 1;
>>   }
>

Ok fixed other occurrences too.

>
>>         /* There's a lot of code before this instruction.  Start with an
>>   	 optimistic search; it's easy to recognize halfwords that can
>> @@ -7291,6 +6106,116 @@ thumb2_copy_block_xfer (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
>>     return 0;
>>   }
>>
>> +/* Initialize arm_gdb_get_next_pcs_stor.  */
>
> /* Initialize arm_gdb_get_next_pcs.  */
>
>
Done.

>> +void
>> +arm_gdb_get_next_pcs_ctor (struct arm_gdb_get_next_pcs *self,
>> +			   struct arm_get_next_pcs_ops *ops,
>> +			   int byte_order,
>
>
>
>> +/* 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 instructions
>> +   and breakpoint them.  */
>> +
>> +int
>> +arm_software_single_step (struct frame_info *frame)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>> +  struct address_space *aspace = get_frame_address_space (frame);
>> +  struct arm_gdb_get_next_pcs next_pcs_ctx;
>> +  CORE_ADDR pc;
>> +  int i;
>> +  VEC (CORE_ADDR) *next_pcs = NULL;
>> +
>> +  arm_gdb_get_next_pcs_ctor (&next_pcs_ctx,
>> +			     &arm_get_next_pcs_ops,
>> +			     gdbarch_byte_order (gdbarch),
>> +			     gdbarch_byte_order_for_code (gdbarch),
>> +			     arm_frame_is_thumb (frame),
>> +			     arm_apcs_32,
>> +			     gdbarch_tdep (gdbarch)->thumb2_breakpoint,
>> +			     frame,
>> +			     gdbarch);
>> +
>> +  next_pcs = arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs,
>
> This is wrong.  Should be  "(struct arm_get_next_pcs *) &next_pcs_ctx" instead.
>
Wow :( Indeed thx.

> I think this shows that it'd be good to run the series against the
> testsuite on native ARM.

I do run that all the time but on linux, it turns out I made the 
misstake in arm-tdep.c but not in arm-linux-tdep.c so it did not show up 
in my tests.

Thanks for seeing it!

>
> You could avoid these wrong casts by writting "&next_pcs_ctx.base" instead.
>
Indeed fixing like so all occurrences.

>> +			       get_frame_pc (frame));
>> +
>> +  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
>> +    {
>> +      arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
>> +    }
>
> No braces.
>
Fixed.

>> +
>> +  VEC_free (CORE_ADDR, next_pcs);
>
> Use a cleanup instead.

Fixed.
>
>> +
>> +  return 1;
>> +}
>> +
>>   /* Cleanup/copy SVC (SWI) instructions.  These two functions are overridden
>>      for Linux, where some SVC instructions must be treated specially.  */
>>
>> diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
>> index 9b8447b..f3a13a4 100644
>> --- a/gdb/arm-tdep.h
>> +++ b/gdb/arm-tdep.h
>> @@ -23,6 +23,9 @@
>>   struct gdbarch;
>>   struct regset;
>>   struct address_space;
>> +struct get_next_pcs;
>> +struct arm_get_next_pcs;
>> +struct gdb_get_next_pcs;
>>
>>   #include "arch/arm.h"
>>
>> @@ -221,6 +224,17 @@ struct displaced_step_closure
>>   		   struct displaced_step_closure *);
>>   };
>>
>> +/* Context for a get_next_pcs call on ARM in GDB.  */
>> +struct arm_gdb_get_next_pcs
>> +{
>> +  /* Common context for gdb/gdbserver.  */
>> +  struct arm_get_next_pcs base;
>> +  /* Frame information.  */
>> +  struct frame_info *frame;
>> +  /* Architecture dependent information.  */
>> +  struct gdbarch *gdbarch;
>> +};
>> +
>>   /* Values for the WRITE_PC argument to displaced_write_reg.  If the register
>>      write may write to the PC, specifies the way the CPSR T bit, etc. is
>>      modified by the instruction.  */
>> @@ -250,11 +264,37 @@ extern void
>>   		       ULONGEST val, enum pc_write_style write_pc);
>>
>>   CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
>> -CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);
>> +
>> +ULONGEST arm_get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr,
>> +							int len,
>> +							int byte_order);
>> +
>> +void arm_gdb_get_next_pcs_ctor (struct arm_gdb_get_next_pcs *self,
>> +				struct arm_get_next_pcs_ops *ops,
>> +				int byte_order,
>> +				int byte_order_for_code,
>> +				int is_thumb,
>> +				int arm_apcs_32,
>> +				const gdb_byte *arm_thumb2_breakpoint,
>> +				struct frame_info *frame,
>> +				struct gdbarch *gdbarch);
>> +
>> +CORE_ADDR
>> +arm_get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self,
>
> See extension.h for how to indent these long declarations.  The function
> name should not be at column 0.
>

Ok, thanks for the example.

>> +				   CORE_ADDR val);
>> +
>> +ULONGEST
>> +arm_get_next_pcs_collect_register_unsigned (struct arm_get_next_pcs *self,
>> +					    int n);
>> +
>> +CORE_ADDR
>> +arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc);
>> +
>> +int arm_software_single_step (struct frame_info *frame);
>> +
>
>
>> +
>>   /* These are in <asm/elf.h> in current kernels.  */
>>   #define HWCAP_VFP       64
>>   #define HWCAP_IWMMXT    512
>> @@ -146,6 +156,29 @@ static int arm_regmap[] = {
>>     64
>>   };
>>
>> +/* Forward declarations needed for get_next_pcs ops.  */
>> +static ULONGEST
>> +get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr,
>> +					   int len,
>> +					   int byte_order);
>> +
>> +static ULONGEST
>> +get_next_pcs_collect_register_unsigned (struct arm_get_next_pcs *self, int n);
>> +
>> +static CORE_ADDR
>> +get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, CORE_ADDR val);
>> +
>> +static CORE_ADDR
>> +get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc);
>> +
>
> Ditto.
>
Done.

Note I also used a cleanup now in 
install_software_single_step_breakpoint and removed the braces in the for.

Thank you,
Antoine
  
Antoine Tremblay Nov. 26, 2015, 3:11 p.m. UTC | #4
On 11/26/2015 07:48 AM, Yao Qi wrote:
> Antoine Tremblay <antoine.tremblay@ericsson.com> writes:
>
>> Limitations :
>>
>> GDBServer can't step over a sigreturn or rt_sigreturn syscall since this would
>> require the DWARF information to identify the caller PC. This situation
>> only prints a warning for the moment.
>
> They are using frame not DWARF to identify the PC, however, it is not
> necessary.  When GDB or GDBserver is doing software single step, it must
> be in the inner-most frame, so we can get the caller PC by examining the
> stack at a certain offset from SP (from regcache), like what are doing in
> arm_linux_sigreturn_init and arm_linux_rt_sigreturn_init, rather than
> replying frame unwinding.  See my comments to arm_get_next_pcs_syscall_next_pc.
>

Humm and frame can use the dwarf unwinder can it not ? frame is still 
very confusing to me.

But I'm glad it's not the only option, I'll examine the stack and fix it.

>> +
>> +/* Wrapper over syscall_next_pc for use in get_next_pcs.  */
>> +
>> +CORE_ADDR
>> +arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc)
>> +{
>> +  struct arm_gdb_get_next_pcs *next_pcs = (struct arm_gdb_get_next_pcs *) self;
>> +  struct gdbarch_tdep *tdep;
>> +
>> +  tdep = gdbarch_tdep (next_pcs->gdbarch);
>> +  if (tdep->syscall_next_pc != NULL)
>> +    return tdep->syscall_next_pc (next_pcs->frame);
>> +
>> +  return 0;
>> +}
>> +
>
>
>> +/* When PC is at a syscall instruction, return the PC of the next
>> +   instruction to be executed.  */
>> +static CORE_ADDR
>> +get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc)
>> +{
>> +  CORE_ADDR return_addr = 0;
>> +  int is_thumb = self->is_thumb;
>> +  ULONGEST svc_number = 0;
>> +
>> +  if (is_thumb)
>> +    {
>> +      svc_number = self->ops->collect_register_unsigned (self, 7);
>> +      return_addr = pc + 2;
>> +    }
>> +  else
>> +    {
>> +      unsigned long this_instr = self->ops->read_memory_unsigned_integer
>> +	((CORE_ADDR) pc, 4, self->byte_order_for_code);
>> +
>> +      unsigned long svc_operand = (0x00ffffff & this_instr);
>> +      if (svc_operand)  /* OABI.  */
>> +	{
>> +	  svc_number = svc_operand - 0x900000;
>> +	}
>> +      else /* EABI.  */
>> +	{
>> +	  svc_number = self->ops->collect_register_unsigned (self, 7);
>> +	}
>> +
>> +      return_addr = pc + 4;
>> +    }
>> +
>> +  /* Is this a sigreturn or rt_sigreturn syscall?
>> +     If so it is currently not handeled.  */
>> +  if (svc_number == 119 || svc_number == 173)
>> +    {
>> +      if (debug_threads)
>> +	debug_printf ("Unhandled sigreturn or rt_sigreturn syscall\n");
>
> We can still compute the caller pc by examining stack.
>
>> +    }
>> +
>> +  /* Addresses for calling Thumb functions have the bit 0 set.  */
>> +  if (is_thumb)
>> +    return_addr = MAKE_THUMB_ADDR (return_addr);
>> +
>> +  return return_addr;
>> +}
>>
>
> This leads me thinking more about current software single step code in
> GDB.  In GDB side, we are using frame to access registers, while in
> GDBserver, we are using regcache.  Why don't we use regcache in both
> sides? so that the "struct arm_get_next_pcs_ops" can be simplified, for
> example, field collect_register_unsigned may be no longer necessary.
>
> In fact, software_single_step used to have regcache argument, added by
> https://sourceware.org/ml/gdb-patches/2007-04/msg00218.html but we
> changed to argument frame
> https://sourceware.org/ml/gdb-patches/2007-04/msg00218.html

This is the same link as the previous one...

  IMO, it is
> better to use regcache than frame.  We have two options,
>
>   #1, switch from frame apis to regcache apis to access registers in arm
>    software single step.  We can get regcache by get_current_regcache ().
>   #2, change argument of gdbarch method software_single_step from frame
>    to regcache, which means all its implementations need update, and
>    switch to regcache apis to access registers.
>
> #2 is the right way to go in long term, and we really need to improve
> software_single_step.  Let me what do you think.
>

Looking at the impacts of #2, I do not feel comfortable including these 
changes in this patch set. I feel they would require a patch set of 
their own.

However #1 seems like something possible I would start by this option if 
that's fine with you ?

Also, I can still do the refactoring before this patch but it will 
require more work since I'll have to diff the functions moved etc.. do 
you feel it's required to do so or the refactoring could be done after 
this patch ?


Thank you,
Antoine
  
Yao Qi Nov. 26, 2015, 4:03 p.m. UTC | #5
On 26/11/15 15:11, Antoine Tremblay wrote:
> This is the same link as the previous one...
>

Oops, sorry, https://sourceware.org/ml/gdb-patches/2007-06/msg00087.html


>   IMO, it is
>> better to use regcache than frame.  We have two options,
>>
>>   #1, switch from frame apis to regcache apis to access registers in arm
>>    software single step.  We can get regcache by get_current_regcache ().
>>   #2, change argument of gdbarch method software_single_step from frame
>>    to regcache, which means all its implementations need update, and
>>    switch to regcache apis to access registers.
>>
>> #2 is the right way to go in long term, and we really need to improve
>> software_single_step.  Let me what do you think.
>>
>
> Looking at the impacts of #2, I do not feel comfortable including these
> changes in this patch set. I feel they would require a patch set of
> their own.
>
> However #1 seems like something possible I would start by this option if
> that's fine with you ?

Yes.

>
> Also, I can still do the refactoring before this patch but it will
> require more work since I'll have to diff the functions moved etc.. do
> you feel it's required to do so or the refactoring could be done after
> this patch ?

I prefer doing the refactor first, and separately, because after this
refactor, your patch #8 will be simplified a lot.  In this series, we
want to share the code on arm software single step, however, registers
are accessed through frame in GDB side, while through regcache in
GDBserver.  In order to share code, we should unify them as much as we
can, that is, access registers through regcache as well in GDB side.
Then, we can move the code from arm-tdep.c to arch/ directory, to 
support software single step in GDBserver.
  
Antoine Tremblay Nov. 26, 2015, 4:07 p.m. UTC | #6
On 11/26/2015 11:03 AM, Yao Qi wrote:
>
>
> On 26/11/15 15:11, Antoine Tremblay wrote:
>> This is the same link as the previous one...
>>
>
> Oops, sorry, https://sourceware.org/ml/gdb-patches/2007-06/msg00087.html
>
Thanks

>
>>   IMO, it is
>>> better to use regcache than frame.  We have two options,
>>>
>>>   #1, switch from frame apis to regcache apis to access registers in arm
>>>    software single step.  We can get regcache by get_current_regcache
>>> ().
>>>   #2, change argument of gdbarch method software_single_step from frame
>>>    to regcache, which means all its implementations need update, and
>>>    switch to regcache apis to access registers.
>>>
>>> #2 is the right way to go in long term, and we really need to improve
>>> software_single_step.  Let me what do you think.
>>>
>>
>> Looking at the impacts of #2, I do not feel comfortable including these
>> changes in this patch set. I feel they would require a patch set of
>> their own.
>>
>> However #1 seems like something possible I would start by this option if
>> that's fine with you ?
>
> Yes.
>
>>
>> Also, I can still do the refactoring before this patch but it will
>> require more work since I'll have to diff the functions moved etc.. do
>> you feel it's required to do so or the refactoring could be done after
>> this patch ?
>
> I prefer doing the refactor first, and separately, because after this
> refactor, your patch #8 will be simplified a lot.  In this series, we
> want to share the code on arm software single step, however, registers
> are accessed through frame in GDB side, while through regcache in
> GDBserver.  In order to share code, we should unify them as much as we
> can, that is, access registers through regcache as well in GDB side.
> Then, we can move the code from arm-tdep.c to arch/ directory, to
> support software single step in GDBserver.
>

Yes ok I'll do it this way then.
  
Antoine Tremblay Nov. 27, 2015, 1:45 p.m. UTC | #7
On 11/26/2015 11:07 AM, Antoine Tremblay wrote:
>
>
> On 11/26/2015 11:03 AM, Yao Qi wrote:
>>
>>
>> On 26/11/15 15:11, Antoine Tremblay wrote:
>>> This is the same link as the previous one...
>>>
>>
>> Oops, sorry, https://sourceware.org/ml/gdb-patches/2007-06/msg00087.html
>>
> Thanks
>
>>
>>>   IMO, it is
>>>> better to use regcache than frame.  We have two options,
>>>>
>>>>   #1, switch from frame apis to regcache apis to access registers in
>>>> arm
>>>>    software single step.  We can get regcache by get_current_regcache
>>>> ().
>>

About this one, as we thought it would simplify the 
collect_register_unsigned field.

It's unfortunate but it won't because GDB's collect_registers_unsigned 
reads the registers and then calls extract_register_unsigned (in the 
same call).

This function uses bfd enums for byte ordering and I can't use that in 
GDBServer as discussed previously.

So I will not be able to directly share GDB's 
collect_registers_unsigned, thus either collect_register_unsigned will 
be replaced by 2 calls, one shared that fetches the register, and then a 
call that extracts the integer as a different operation on GDB and 
GDBserver or I will end up with the same collect_register_unsigned field 
only it will be using regcache on GDBServer's side now.

And I don't think it's good to have it in 2 calls, so I will have the 
same collect_register_unsigned_field...

Thus this refactoring would not simplify the patch and IMHO would create 
some inconsistency why are we using regcache in some place for no 
apparent gain while all the rest uses frame.

In light of this, I plan to keep it as is unless there's an objection ?

Regards,
Antoine
  
Yao Qi Nov. 27, 2015, 3:15 p.m. UTC | #8
On 27/11/15 13:45, Antoine Tremblay wrote:
>
> And I don't think it's good to have it in 2 calls, so I will have the
> same collect_register_unsigned_field...

If so, let us keep collect_register_unsigned field.
>
> Thus this refactoring would not simplify the patch and IMHO would create
> some inconsistency why are we using regcache in some place for no
> apparent gain while all the rest uses frame.

That is what I want to avoid...  for the software single step routines
in two sides (GDB and GDBserver), I don't want to see that regcache is
used in one side while frame is used in the other side.  regcache should
be used in both sides.

>
> In light of this, I plan to keep it as is unless there's an objection ?

Sorry, I don't like the patch as is.  I plan to change gdbarch method
software_single_step to something like this,

F:VEC (CORE_ADDR) *:software_single_step:struct regcache *regcache:regcache

it returns a set of address on which GDB can insert software single step
breakpoint.
  
Antoine Tremblay Nov. 27, 2015, 3:35 p.m. UTC | #9
On 11/27/2015 10:15 AM, Yao Qi wrote:
> On 27/11/15 13:45, Antoine Tremblay wrote:
>>
>> And I don't think it's good to have it in 2 calls, so I will have the
>> same collect_register_unsigned_field...
>
> If so, let us keep collect_register_unsigned field.
>>
>> Thus this refactoring would not simplify the patch and IMHO would create
>> some inconsistency why are we using regcache in some place for no
>> apparent gain while all the rest uses frame.
>
> That is what I want to avoid...  for the software single step routines
> in two sides (GDB and GDBserver), I don't want to see that regcache is
> used in one side while frame is used in the other side.  regcache should
> be used in both sides.
>
>>
>> In light of this, I plan to keep it as is unless there's an objection ?
>
> Sorry, I don't like the patch as is.  I plan to change gdbarch method
> software_single_step to something like this,
>
> F:VEC (CORE_ADDR) *:software_single_step:struct regcache *regcache:regcache
>
> it returns a set of address on which GDB can insert software single step
> breakpoint.
>

Alright as long as it's understood that the fields will stay, I'll do it 
like this.

Thanks,
Antoine
  

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 14ad405..670b4eb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -657,7 +657,8 @@  ALL_64_TARGET_OBS = \
 
 # All other target-dependent objects files (used with --enable-targets=all).
 ALL_TARGET_OBS = \
-	armbsd-tdep.o arm.o arm-linux-tdep.o arm-symbian-tdep.o \
+	armbsd-tdep.o arm.o arm-linux-tdep.o \
+	arm-get-next-pcs.o arm-symbian-tdep.o \
 	armnbsd-tdep.o armobsd-tdep.o \
 	arm-tdep.o arm-wince-tdep.o \
 	avr-tdep.o \
@@ -1660,8 +1661,9 @@  ALLDEPFILES = \
 	amd64-dicos-tdep.c \
 	amd64-linux-nat.c amd64-linux-tdep.c \
 	amd64-sol2-tdep.c \
-	arm.c \
-	arm-linux-nat.c arm-linux-tdep.c arm-symbian-tdep.c arm-tdep.c \
+	arm.c arm-get-next-pcs.c \
+	arm-linux-nat.c arm-linux-tdep.c \
+	arm-symbian-tdep.c arm-tdep.c \
 	armnbsd-nat.c armbsd-tdep.c armnbsd-tdep.c armobsd-tdep.c \
 	avr-tdep.c \
 	bfin-linux-tdep.c bfin-tdep.c \
@@ -2286,6 +2288,10 @@  arm.o: ${srcdir}/arch/arm.c
 	$(COMPILE) $(srcdir)/arch/arm.c
 	$(POSTCOMPILE)
 
+arm-get-next-pcs.o: ${srcdir}/arch/arm-get-next-pcs.c
+	$(COMPILE) $(srcdir)/arch/arm-get-next-pcs.c
+	$(POSTCOMPILE)
+
 # gdb/nat/ dependencies
 #
 # Need to explicitly specify the compile rule as make will do nothing
diff --git a/gdb/aarch32-linux-nat.c b/gdb/aarch32-linux-nat.c
index 3147399..9d1f696 100644
--- a/gdb/aarch32-linux-nat.c
+++ b/gdb/aarch32-linux-nat.c
@@ -18,6 +18,7 @@ 
 #include "defs.h"
 
 #include "regcache.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
 
diff --git a/gdb/arch/arm-get-next-pcs.c b/gdb/arch/arm-get-next-pcs.c
new file mode 100644
index 0000000..58586c4
--- /dev/null
+++ b/gdb/arch/arm-get-next-pcs.c
@@ -0,0 +1,1234 @@ 
+/* Common code for ARM software single stepping support.
+
+   Copyright (C) 1988-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "gdb_vecs.h"
+#include "arm.h"
+#include "arm-get-next-pcs.h"
+
+/* See arm-get-next-pcs.h.  */
+
+void
+arm_get_next_pcs_ctor (struct arm_get_next_pcs *self,
+		       struct arm_get_next_pcs_ops *ops,
+		       int byte_order,
+		       int byte_order_for_code,
+		       int is_thumb,
+		       int arm_apcs_32,
+		       const gdb_byte *arm_thumb2_breakpoint)
+{
+  self->ops = ops;
+  self->byte_order = byte_order;
+  self->byte_order_for_code = byte_order_for_code;
+  self->is_thumb = is_thumb;
+  self->arm_apcs_32 = arm_apcs_32;
+  self->arm_thumb2_breakpoint = arm_thumb2_breakpoint;
+}
+
+/* Advance the state of the IT block and return that state.  */
+
+static int
+thumb_advance_itstate (unsigned int itstate)
+{
+  /* Preserve IT[7:5], the first three bits of the condition.  Shift
+     the upcoming condition flags left by one bit.  */
+  itstate = (itstate & 0xe0) | ((itstate << 1) & 0x1f);
+
+  /* If we have finished the IT block, clear the state.  */
+  if ((itstate & 0x0f) == 0)
+    itstate = 0;
+
+  return itstate;
+}
+
+/* See arm-get-next-pcs.h.  */
+
+int
+arm_instruction_changes_pc (uint32_t this_instr)
+{
+  if (bits (this_instr, 28, 31) == INST_NV)
+    /* Unconditional instructions.  */
+    switch (bits (this_instr, 24, 27))
+      {
+      case 0xa:
+      case 0xb:
+	/* Branch with Link and change to Thumb.  */
+	return 1;
+      case 0xc:
+      case 0xd:
+      case 0xe:
+	/* Coprocessor register transfer.  */
+        if (bits (this_instr, 12, 15) == 15)
+	  error (_("Invalid update to pc in instruction"));
+	return 0;
+      default:
+	return 0;
+      }
+  else
+    switch (bits (this_instr, 25, 27))
+      {
+      case 0x0:
+	if (bits (this_instr, 23, 24) == 2 && bit (this_instr, 20) == 0)
+	  {
+	    /* Multiplies and extra load/stores.  */
+	    if (bit (this_instr, 4) == 1 && bit (this_instr, 7) == 1)
+	      /* Neither multiplies nor extension load/stores are allowed
+		 to modify PC.  */
+	      return 0;
+
+	    /* Otherwise, miscellaneous instructions.  */
+
+	    /* BX <reg>, BXJ <reg>, BLX <reg> */
+	    if (bits (this_instr, 4, 27) == 0x12fff1
+		|| bits (this_instr, 4, 27) == 0x12fff2
+		|| bits (this_instr, 4, 27) == 0x12fff3)
+	      return 1;
+
+	    /* Other miscellaneous instructions are unpredictable if they
+	       modify PC.  */
+	    return 0;
+	  }
+	/* Data processing instruction.  Fall through.  */
+
+      case 0x1:
+	if (bits (this_instr, 12, 15) == 15)
+	  return 1;
+	else
+	  return 0;
+
+      case 0x2:
+      case 0x3:
+	/* Media instructions and architecturally undefined instructions.  */
+	if (bits (this_instr, 25, 27) == 3 && bit (this_instr, 4) == 1)
+	  return 0;
+
+	/* Stores.  */
+	if (bit (this_instr, 20) == 0)
+	  return 0;
+
+	/* Loads.  */
+	if (bits (this_instr, 12, 15) == ARM_PC_REGNUM)
+	  return 1;
+	else
+	  return 0;
+
+      case 0x4:
+	/* Load/store multiple.  */
+	if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1)
+	  return 1;
+	else
+	  return 0;
+
+      case 0x5:
+	/* Branch and branch with link.  */
+	return 1;
+
+      case 0x6:
+      case 0x7:
+	/* Coprocessor transfers or SWIs can not affect PC.  */
+	return 0;
+
+      default:
+	internal_error (__FILE__, __LINE__, _("bad value in switch"));
+      }
+}
+
+/* See arm-get-next-pcs.h.  */
+
+int
+thumb_instruction_changes_pc (unsigned short inst)
+{
+  if ((inst & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
+    return 1;
+
+  if ((inst & 0xf000) == 0xd000)	/* conditional branch */
+    return 1;
+
+  if ((inst & 0xf800) == 0xe000)	/* unconditional branch */
+    return 1;
+
+  if ((inst & 0xff00) == 0x4700)	/* bx REG, blx REG */
+    return 1;
+
+  if ((inst & 0xff87) == 0x4687)	/* mov pc, REG */
+    return 1;
+
+  if ((inst & 0xf500) == 0xb100)	/* CBNZ or CBZ.  */
+    return 1;
+
+  return 0;
+}
+
+
+/* See arm-get-next-pcs.h.  */
+
+int
+thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2)
+{
+  if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
+    {
+      /* Branches and miscellaneous control instructions.  */
+
+      if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
+	{
+	  /* B, BL, BLX.  */
+	  return 1;
+	}
+      else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
+	{
+	  /* SUBS PC, LR, #imm8.  */
+	  return 1;
+	}
+      else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
+	{
+	  /* Conditional branch.  */
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  if ((inst1 & 0xfe50) == 0xe810)
+    {
+      /* Load multiple or RFE.  */
+
+      if (bit (inst1, 7) && !bit (inst1, 8))
+	{
+	  /* LDMIA or POP */
+	  if (bit (inst2, 15))
+	    return 1;
+	}
+      else if (!bit (inst1, 7) && bit (inst1, 8))
+	{
+	  /* LDMDB */
+	  if (bit (inst2, 15))
+	    return 1;
+	}
+      else if (bit (inst1, 7) && bit (inst1, 8))
+	{
+	  /* RFEIA */
+	  return 1;
+	}
+      else if (!bit (inst1, 7) && !bit (inst1, 8))
+	{
+	  /* RFEDB */
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
+    {
+      /* MOV PC or MOVS PC.  */
+      return 1;
+    }
+
+  if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
+    {
+      /* LDR PC.  */
+      if (bits (inst1, 0, 3) == 15)
+	return 1;
+      if (bit (inst1, 7))
+	return 1;
+      if (bit (inst2, 11))
+	return 1;
+      if ((inst2 & 0x0fc0) == 0x0000)
+	return 1;
+
+      return 0;
+    }
+
+  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+    {
+      /* TBB.  */
+      return 1;
+    }
+
+  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
+    {
+      /* TBH.  */
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Checks for an atomic sequence of instructions beginning with a LDREX{,B,H,D}
+   instruction and ending with a STREX{,B,H,D} instruction.  If such a sequence
+   is found, attempt to step through it.  The end of the sequence address is
+   added to the next_pcs list.  */
+
+static int
+thumb_deal_with_atomic_sequence_raw (struct arm_get_next_pcs *self,
+				     CORE_ADDR pc,
+				     VEC (CORE_ADDR) **next_pcs)
+{
+  int byte_order_for_code = self->byte_order_for_code;
+  CORE_ADDR breaks[2] = {-1, -1};
+  CORE_ADDR loc = pc;
+  unsigned short insn1, insn2;
+  int insn_count;
+  int index;
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
+  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+  ULONGEST status, itstate;
+
+  /* We currently do not support atomic sequences within an IT block.  */
+  status = self->ops->collect_register_unsigned (self, ARM_PS_REGNUM);
+
+  itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
+  if (itstate & 0x0f)
+    return 0;
+
+  /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.  */
+  insn1 = self->ops->read_memory_unsigned_integer (loc, 2, byte_order_for_code);
+
+  loc += 2;
+  if (thumb_insn_size (insn1) != 4)
+    return 0;
+
+  insn2 = self->ops->read_memory_unsigned_integer (loc, 2, byte_order_for_code);
+
+  loc += 2;
+  if (!((insn1 & 0xfff0) == 0xe850
+        || ((insn1 & 0xfff0) == 0xe8d0 && (insn2 & 0x00c0) == 0x0040)))
+    return 0;
+
+  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
+     instructions.  */
+  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+    {
+      insn1
+	= self->ops->read_memory_unsigned_integer (loc, 2,byte_order_for_code);
+      loc += 2;
+
+      if (thumb_insn_size (insn1) != 4)
+	{
+	  /* Assume that there is at most one conditional branch in the
+	     atomic sequence.  If a conditional branch is found, put a
+	     breakpoint in its destination address.  */
+	  if ((insn1 & 0xf000) == 0xd000 && bits (insn1, 8, 11) != 0x0f)
+	    {
+	      if (last_breakpoint > 0)
+		return 0; /* More than one conditional branch found,
+			     fallback to the standard code.  */
+
+	      breaks[1] = loc + 2 + (sbits (insn1, 0, 7) << 1);
+	      last_breakpoint++;
+	    }
+
+	  /* We do not support atomic sequences that use any *other*
+	     instructions but conditional branches to change the PC.
+	     Fall back to standard code to avoid losing control of
+	     execution.  */
+	  else if (thumb_instruction_changes_pc (insn1))
+	    return 0;
+	}
+      else
+	{
+	  insn2 = self->ops->read_memory_unsigned_integer
+	    (loc, 2, byte_order_for_code);
+
+	  loc += 2;
+
+	  /* Assume that there is at most one conditional branch in the
+	     atomic sequence.  If a conditional branch is found, put a
+	     breakpoint in its destination address.  */
+	  if ((insn1 & 0xf800) == 0xf000
+	      && (insn2 & 0xd000) == 0x8000
+	      && (insn1 & 0x0380) != 0x0380)
+	    {
+	      int sign, j1, j2, imm1, imm2;
+	      unsigned int offset;
+
+	      sign = sbits (insn1, 10, 10);
+	      imm1 = bits (insn1, 0, 5);
+	      imm2 = bits (insn2, 0, 10);
+	      j1 = bit (insn2, 13);
+	      j2 = bit (insn2, 11);
+
+	      offset = (sign << 20) + (j2 << 19) + (j1 << 18);
+	      offset += (imm1 << 12) + (imm2 << 1);
+
+	      if (last_breakpoint > 0)
+		return 0; /* More than one conditional branch found,
+			     fallback to the standard code.  */
+
+	      breaks[1] = loc + offset;
+	      last_breakpoint++;
+	    }
+
+	  /* We do not support atomic sequences that use any *other*
+	     instructions but conditional branches to change the PC.
+	     Fall back to standard code to avoid losing control of
+	     execution.  */
+	  else if (thumb2_instruction_changes_pc (insn1, insn2))
+	    return 0;
+
+	  /* If we find a strex{,b,h,d}, we're done.  */
+	  if ((insn1 & 0xfff0) == 0xe840
+	      || ((insn1 & 0xfff0) == 0xe8c0 && (insn2 & 0x00c0) == 0x0040))
+	    break;
+	}
+    }
+
+  /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence.  */
+  if (insn_count == atomic_sequence_length)
+    return 0;
+
+  /* Insert a breakpoint right after the end of the atomic sequence.  */
+  breaks[0] = loc;
+
+  /* Check for duplicated breakpoints.  Check also for a breakpoint
+     placed (branch instruction's destination) anywhere in sequence.  */
+  if (last_breakpoint
+      && (breaks[1] == breaks[0]
+	  || (breaks[1] >= pc && breaks[1] < loc)))
+    last_breakpoint = 0;
+
+  /* Adds the breakpoints to the list to be inserted.  */
+  for (index = 0; index <= last_breakpoint; index++)
+    {
+      VEC_safe_push (CORE_ADDR, *next_pcs, MAKE_THUMB_ADDR (breaks[index]));
+    }
+
+  return 1;
+}
+
+/* Checks for an atomic sequence of instructions beginning with a LDREX{,B,H,D}
+   instruction and ending with a STREX{,B,H,D} instruction.  If such a sequence
+   is found, attempt to step through it.  The end of the sequence address is
+   added to the next_pcs list.  */
+
+static int
+arm_deal_with_atomic_sequence_raw (struct arm_get_next_pcs *self,
+				   CORE_ADDR pc,
+				   VEC (CORE_ADDR) **next_pcs)
+{
+  int byte_order_for_code = self->byte_order_for_code;
+  CORE_ADDR breaks[2] = {-1, -1};
+  CORE_ADDR loc = pc;
+  unsigned int insn;
+  int insn_count;
+  int index;
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
+  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+
+  /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.
+     Note that we do not currently support conditionally executed atomic
+     instructions.  */
+  insn = self->ops->read_memory_unsigned_integer (loc, 4, byte_order_for_code);
+
+  loc += 4;
+  if ((insn & 0xff9000f0) != 0xe1900090)
+    return 0;
+
+  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
+     instructions.  */
+  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+    {
+      insn = self->ops->read_memory_unsigned_integer
+	(loc, 4, byte_order_for_code);
+
+      loc += 4;
+
+      /* Assume that there is at most one conditional branch in the atomic
+         sequence.  If a conditional branch is found, put a breakpoint in
+         its destination address.  */
+      if (bits (insn, 24, 27) == 0xa)
+	{
+          if (last_breakpoint > 0)
+            return 0; /* More than one conditional branch found, fallback
+                         to the standard single-step code.  */
+
+	  breaks[1] = BranchDest (loc - 4, insn);
+	  last_breakpoint++;
+        }
+
+      /* We do not support atomic sequences that use any *other* instructions
+         but conditional branches to change the PC.  Fall back to standard
+	 code to avoid losing control of execution.  */
+      else if (arm_instruction_changes_pc (insn))
+	return 0;
+
+      /* If we find a strex{,b,h,d}, we're done.  */
+      if ((insn & 0xff9000f0) == 0xe1800090)
+	break;
+    }
+
+  /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence.  */
+  if (insn_count == atomic_sequence_length)
+    return 0;
+
+  /* Insert a breakpoint right after the end of the atomic sequence.  */
+  breaks[0] = loc;
+
+  /* Check for duplicated breakpoints.  Check also for a breakpoint
+     placed (branch instruction's destination) anywhere in sequence.  */
+  if (last_breakpoint
+      && (breaks[1] == breaks[0]
+	  || (breaks[1] >= pc && breaks[1] < loc)))
+    last_breakpoint = 0;
+
+  /* Adds the breakpoints to the list to be inserted.  */
+  for (index = 0; index <= last_breakpoint; index++)
+    {
+      VEC_safe_push (CORE_ADDR, *next_pcs, breaks[index]);
+    }
+
+  return 1;
+}
+
+/* See arm-get-next-pcs.h.  */
+
+VEC (CORE_ADDR) *
+arm_get_next_pcs (struct arm_get_next_pcs *self, CORE_ADDR pc)
+{
+  VEC (CORE_ADDR) *next_pcs = NULL;
+
+  if (self->is_thumb)
+    {
+      if (!thumb_deal_with_atomic_sequence_raw (self, pc, &next_pcs))
+	return thumb_get_next_pcs_raw (self, pc, &next_pcs);
+    }
+  else
+    {
+      if (!arm_deal_with_atomic_sequence_raw (self, pc, &next_pcs))
+	return arm_get_next_pcs_raw (self, pc, &next_pcs);
+    }
+
+  return next_pcs;
+}
+
+/* Decode shifted register value.  */
+
+static unsigned long
+shifted_reg_val (struct arm_get_next_pcs* self, unsigned long inst,
+		 int carry, unsigned long pc_val, unsigned long status_reg)
+{
+  unsigned long res, shift;
+  int rm = bits (inst, 0, 3);
+  unsigned long shifttype = bits (inst, 5, 6);
+
+  if (bit (inst, 4))
+    {
+      int rs = bits (inst, 8, 11);
+      shift = (rs == 15
+	       ? pc_val + 8
+	       : self->ops->collect_register_unsigned (self, rs)) & 0xFF;
+    }
+  else
+    shift = bits (inst, 7, 11);
+
+  res = (rm == ARM_PC_REGNUM
+	 ? (pc_val + (bit (inst, 4) ? 12 : 8))
+	 : self->ops->collect_register_unsigned (self, rm));
+
+  switch (shifttype)
+    {
+    case 0:			/* LSL */
+      res = shift >= 32 ? 0 : res << shift;
+      break;
+
+    case 1:			/* LSR */
+      res = shift >= 32 ? 0 : res >> shift;
+      break;
+
+    case 2:			/* ASR */
+      if (shift >= 32)
+	shift = 31;
+      res = ((res & 0x80000000L)
+	     ? ~((~res) >> shift) : res >> shift);
+      break;
+
+    case 3:			/* ROR/RRX */
+      shift &= 31;
+      if (shift == 0)
+	res = (res >> 1) | (carry ? 0x80000000L : 0);
+      else
+	res = (res >> shift) | (res << (32 - shift));
+      break;
+    }
+
+  return res & 0xffffffff;
+}
+
+/* See arm-get-next-pcs.h.  */
+
+VEC (CORE_ADDR) *
+thumb_get_next_pcs_raw (struct arm_get_next_pcs *self,
+			CORE_ADDR pc,
+			VEC (CORE_ADDR) **next_pcs)
+{
+  int byte_order = self->byte_order;
+  int byte_order_for_code = self->byte_order_for_code;
+  unsigned long pc_val = ((unsigned long) pc) + 4;	/* PC after prefetch */
+  unsigned short inst1;
+  CORE_ADDR nextpc = pc + 2;		/* Default is next instruction.  */
+  unsigned long offset;
+  ULONGEST status, itstate;
+
+  nextpc = MAKE_THUMB_ADDR (nextpc);
+  pc_val = MAKE_THUMB_ADDR (pc_val);
+
+  inst1 = self->ops->read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+
+  /* Thumb-2 conditional execution support.  There are eight bits in
+     the CPSR which describe conditional execution state.  Once
+     reconstructed (they're in a funny order), the low five bits
+     describe the low bit of the condition for each instruction and
+     how many instructions remain.  The high three bits describe the
+     base condition.  One of the low four bits will be set if an IT
+     block is active.  These bits read as zero on earlier
+     processors.  */
+  status = self->ops->collect_register_unsigned (self, ARM_PS_REGNUM);
+
+  itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
+
+  /* If-Then handling.  On GNU/Linux, where this routine is used, we
+     use an undefined instruction as a breakpoint.  Unlike BKPT, IT
+     can disable execution of the undefined instruction.  So we might
+     miss the breakpoint if we set it on a skipped conditional
+     instruction.  Because conditional instructions can change the
+     flags, affecting the execution of further instructions, we may
+     need to set two breakpoints.  */
+
+  if (self->arm_thumb2_breakpoint != NULL)
+    {
+      if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
+	{
+	  /* An IT instruction.  Because this instruction does not
+	     modify the flags, we can accurately predict the next
+	     executed instruction.  */
+	  itstate = inst1 & 0x00ff;
+	  pc += thumb_insn_size (inst1);
+
+	  while (itstate != 0 && ! condition_true (itstate >> 4, status))
+	    {
+	      inst1 = self->ops->read_memory_unsigned_integer
+		(pc, 2,byte_order_for_code);
+	      pc += thumb_insn_size (inst1);
+	      itstate = thumb_advance_itstate (itstate);
+	    }
+
+	  VEC_safe_push (CORE_ADDR, *next_pcs, MAKE_THUMB_ADDR (pc));
+	  return *next_pcs;
+	}
+      else if (itstate != 0)
+	{
+	  /* We are in a conditional block.  Check the condition.  */
+	  if (! condition_true (itstate >> 4, status))
+	    {
+	      /* Advance to the next executed instruction.  */
+	      pc += thumb_insn_size (inst1);
+	      itstate = thumb_advance_itstate (itstate);
+
+	      while (itstate != 0 && ! condition_true (itstate >> 4, status))
+		{
+		  inst1 = self->ops->read_memory_unsigned_integer
+		    (pc, 2, byte_order_for_code);
+
+		  pc += thumb_insn_size (inst1);
+		  itstate = thumb_advance_itstate (itstate);
+		}
+
+	      VEC_safe_push (CORE_ADDR, *next_pcs, MAKE_THUMB_ADDR (pc));
+	      return *next_pcs;
+	    }
+	  else if ((itstate & 0x0f) == 0x08)
+	    {
+	      /* This is the last instruction of the conditional
+		 block, and it is executed.  We can handle it normally
+		 because the following instruction is not conditional,
+		 and we must handle it normally because it is
+		 permitted to branch.  Fall through.  */
+	    }
+	  else
+	    {
+	      int cond_negated;
+
+	      /* There are conditional instructions after this one.
+		 If this instruction modifies the flags, then we can
+		 not predict what the next executed instruction will
+		 be.  Fortunately, this instruction is architecturally
+		 forbidden to branch; we know it will fall through.
+		 Start by skipping past it.  */
+	      pc += thumb_insn_size (inst1);
+	      itstate = thumb_advance_itstate (itstate);
+
+	      /* Set a breakpoint on the following instruction.  */
+	      gdb_assert ((itstate & 0x0f) != 0);
+	      VEC_safe_push (CORE_ADDR, *next_pcs, MAKE_THUMB_ADDR (pc));
+
+	      cond_negated = (itstate >> 4) & 1;
+
+	      /* Skip all following instructions with the same
+		 condition.  If there is a later instruction in the IT
+		 block with the opposite condition, set the other
+		 breakpoint there.  If not, then set a breakpoint on
+		 the instruction after the IT block.  */
+	      do
+		{
+		  inst1 = self->ops->read_memory_unsigned_integer
+		    (pc, 2, byte_order_for_code);
+
+		  pc += thumb_insn_size (inst1);
+		  itstate = thumb_advance_itstate (itstate);
+		}
+	      while (itstate != 0 && ((itstate >> 4) & 1) == cond_negated);
+
+	      VEC_safe_push (CORE_ADDR, *next_pcs, MAKE_THUMB_ADDR (pc));
+
+	      return *next_pcs;
+	    }
+	}
+    }
+  else if (itstate & 0x0f)
+    {
+      /* We are in a conditional block.  Check the condition.  */
+      int cond = itstate >> 4;
+
+      if (! condition_true (cond, status))
+	/* Advance to the next instruction.  All the 32-bit
+	   instructions share a common prefix.  */
+	VEC_safe_push (CORE_ADDR, *next_pcs,
+		       MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1)));
+
+      return *next_pcs;
+
+      /* Otherwise, handle the instruction normally.  */
+    }
+
+  if ((inst1 & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
+    {
+      CORE_ADDR sp;
+
+      /* Fetch the saved PC from the stack.  It's stored above
+         all of the other registers.  */
+      offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
+
+      sp = self->ops->collect_register_unsigned (self, ARM_SP_REGNUM);
+
+      nextpc = self->ops->read_memory_unsigned_integer
+	(sp + offset, 4, byte_order);
+    }
+  else if ((inst1 & 0xf000) == 0xd000)	/* conditional branch */
+    {
+      unsigned long cond = bits (inst1, 8, 11);
+      if (cond == 0x0f)  /* 0x0f = SWI */
+	{
+	  nextpc = self->ops->syscall_next_pc (self, pc);
+	}
+      else if (cond != 0x0f && condition_true (cond, status))
+	nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
+    }
+  else if ((inst1 & 0xf800) == 0xe000)	/* unconditional branch */
+    {
+      nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
+    }
+  else if (thumb_insn_size (inst1) == 4) /* 32-bit instruction */
+    {
+      unsigned short inst2;
+      inst2 = self->ops->read_memory_unsigned_integer
+	(pc + 2, 2, byte_order_for_code);
+
+      /* Default to the next instruction.  */
+      nextpc = pc + 4;
+      nextpc = MAKE_THUMB_ADDR (nextpc);
+
+      if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
+	{
+	  /* Branches and miscellaneous control instructions.  */
+
+	  if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
+	    {
+	      /* B, BL, BLX.  */
+	      int j1, j2, imm1, imm2;
+
+	      imm1 = sbits (inst1, 0, 10);
+	      imm2 = bits (inst2, 0, 10);
+	      j1 = bit (inst2, 13);
+	      j2 = bit (inst2, 11);
+
+	      offset = ((imm1 << 12) + (imm2 << 1));
+	      offset ^= ((!j2) << 22) | ((!j1) << 23);
+
+	      nextpc = pc_val + offset;
+	      /* For BLX make sure to clear the low bits.  */
+	      if (bit (inst2, 12) == 0)
+		nextpc = nextpc & 0xfffffffc;
+	    }
+	  else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
+	    {
+	      /* SUBS PC, LR, #imm8.  */
+	      nextpc
+		= self->ops->collect_register_unsigned (self, ARM_LR_REGNUM);
+	      nextpc -= inst2 & 0x00ff;
+	    }
+	  else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
+	    {
+	      /* Conditional branch.  */
+	      if (condition_true (bits (inst1, 6, 9), status))
+		{
+		  int sign, j1, j2, imm1, imm2;
+
+		  sign = sbits (inst1, 10, 10);
+		  imm1 = bits (inst1, 0, 5);
+		  imm2 = bits (inst2, 0, 10);
+		  j1 = bit (inst2, 13);
+		  j2 = bit (inst2, 11);
+
+		  offset = (sign << 20) + (j2 << 19) + (j1 << 18);
+		  offset += (imm1 << 12) + (imm2 << 1);
+
+		  nextpc = pc_val + offset;
+		}
+	    }
+	}
+      else if ((inst1 & 0xfe50) == 0xe810)
+	{
+	  /* Load multiple or RFE.  */
+	  int rn, offset, load_pc = 1;
+
+	  rn = bits (inst1, 0, 3);
+	  if (bit (inst1, 7) && !bit (inst1, 8))
+	    {
+	      /* LDMIA or POP */
+	      if (!bit (inst2, 15))
+		load_pc = 0;
+	      offset = bitcount (inst2) * 4 - 4;
+	    }
+	  else if (!bit (inst1, 7) && bit (inst1, 8))
+	    {
+	      /* LDMDB */
+	      if (!bit (inst2, 15))
+		load_pc = 0;
+	      offset = -4;
+	    }
+	  else if (bit (inst1, 7) && bit (inst1, 8))
+	    {
+	      /* RFEIA */
+	      offset = 0;
+	    }
+	  else if (!bit (inst1, 7) && !bit (inst1, 8))
+	    {
+	      /* RFEDB */
+	      offset = -8;
+	    }
+	  else
+	    load_pc = 0;
+
+	  if (load_pc)
+	    {
+	      CORE_ADDR addr = self->ops->collect_register_unsigned (self, rn);
+	      nextpc = self->ops->read_memory_unsigned_integer
+		(addr + offset, 4, byte_order);
+	    }
+	}
+      else if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
+	{
+	  /* MOV PC or MOVS PC.  */
+	  nextpc
+	    = self->ops->collect_register_unsigned (self, bits (inst2, 0, 3));
+	  nextpc = MAKE_THUMB_ADDR (nextpc);
+	}
+      else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
+	{
+	  /* LDR PC.  */
+	  CORE_ADDR base;
+	  int rn, load_pc = 1;
+
+	  rn = bits (inst1, 0, 3);
+	  base = self->ops->collect_register_unsigned (self, rn);
+	  if (rn == ARM_PC_REGNUM)
+	    {
+	      base = (base + 4) & ~(CORE_ADDR) 0x3;
+	      if (bit (inst1, 7))
+		base += bits (inst2, 0, 11);
+	      else
+		base -= bits (inst2, 0, 11);
+	    }
+	  else if (bit (inst1, 7))
+	    base += bits (inst2, 0, 11);
+	  else if (bit (inst2, 11))
+	    {
+	      if (bit (inst2, 10))
+		{
+		  if (bit (inst2, 9))
+		    base += bits (inst2, 0, 7);
+		  else
+		    base -= bits (inst2, 0, 7);
+		}
+	    }
+	  else if ((inst2 & 0x0fc0) == 0x0000)
+	    {
+	      int shift = bits (inst2, 4, 5), rm = bits (inst2, 0, 3);
+	      base += self->ops->collect_register_unsigned (self, rm) << shift;
+	    }
+	  else
+	    /* Reserved.  */
+	    load_pc = 0;
+
+	  if (load_pc)
+	    nextpc
+	      = self->ops->read_memory_unsigned_integer (base, 4, byte_order);
+	}
+      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+	{
+	  /* TBB.  */
+	  CORE_ADDR tbl_reg, table, offset, length;
+
+	  tbl_reg = bits (inst1, 0, 3);
+	  if (tbl_reg == 0x0f)
+	    table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
+	  else
+	    table = self->ops->collect_register_unsigned (self, tbl_reg);
+
+	  offset
+	    = self->ops->collect_register_unsigned (self, bits (inst2, 0, 3));
+	  length = 2 * self->ops->read_memory_unsigned_integer
+	    (table + offset, 1, byte_order);
+	  nextpc = pc_val + length;
+	}
+      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
+	{
+	  /* TBH.  */
+	  CORE_ADDR tbl_reg, table, offset, length;
+
+	  tbl_reg = bits (inst1, 0, 3);
+	  if (tbl_reg == 0x0f)
+	    table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
+	  else
+	    table = self->ops->collect_register_unsigned (self, tbl_reg);
+
+	  offset = 2 * self->ops->collect_register_unsigned
+	    (self, bits (inst2, 0, 3));
+	  length = 2 * self->ops->read_memory_unsigned_integer
+	    (table + offset, 2, byte_order);
+	  nextpc = pc_val + length;
+	}
+    }
+  else if ((inst1 & 0xff00) == 0x4700)	/* bx REG, blx REG */
+    {
+      if (bits (inst1, 3, 6) == 0x0f)
+	nextpc = UNMAKE_THUMB_ADDR (pc_val);
+      else
+	nextpc
+	  = self->ops->collect_register_unsigned (self, bits (inst1, 3, 6));
+    }
+  else if ((inst1 & 0xff87) == 0x4687)	/* mov pc, REG */
+    {
+      if (bits (inst1, 3, 6) == 0x0f)
+	nextpc = pc_val;
+      else
+	nextpc
+	  = self->ops->collect_register_unsigned (self, bits (inst1, 3, 6));
+
+      nextpc = MAKE_THUMB_ADDR (nextpc);
+    }
+  else if ((inst1 & 0xf500) == 0xb100)
+    {
+      /* CBNZ or CBZ.  */
+      int imm = (bit (inst1, 9) << 6) + (bits (inst1, 3, 7) << 1);
+      ULONGEST reg
+	= self->ops->collect_register_unsigned (self, bits (inst1, 0, 2));
+
+      if (bit (inst1, 11) && reg != 0)
+	nextpc = pc_val + imm;
+      else if (!bit (inst1, 11) && reg == 0)
+	nextpc = pc_val + imm;
+    }
+
+  VEC_safe_push (CORE_ADDR, *next_pcs, nextpc);
+
+  return *next_pcs;
+}
+
+/* Get the raw next possible addresses.  PC in next_pcs is the current program
+   counter, which is assumed to be executing in ARM mode.
+
+   The values returned have the execution state of the next instruction
+   encoded in it.  Use IS_THUMB_ADDR () to see whether the instruction is
+   in Thumb-State, and gdbarch_addr_bits_remove () to get the plain memory
+   address in GDB and arm_addr_bits_remove in GDBServer.  */
+
+VEC (CORE_ADDR) *
+arm_get_next_pcs_raw (struct arm_get_next_pcs *self,
+		      CORE_ADDR pc,
+		      VEC (CORE_ADDR) **next_pcs)
+{
+  int byte_order = self->byte_order;
+  unsigned long pc_val;
+  unsigned long this_instr = 0;
+  unsigned long status;
+  CORE_ADDR nextpc;
+
+  pc_val = (unsigned long) pc;
+  this_instr = self->ops->read_memory_unsigned_integer (pc, 4, byte_order);
+
+  status = self->ops->collect_register_unsigned (self, ARM_PS_REGNUM);
+
+  nextpc = (CORE_ADDR) (pc_val + 4);	/* Default case */
+
+  if (bits (this_instr, 28, 31) == INST_NV)
+    switch (bits (this_instr, 24, 27))
+      {
+      case 0xa:
+      case 0xb:
+	{
+	  /* Branch with Link and change to Thumb.  */
+	  nextpc = BranchDest (pc, this_instr);
+	  nextpc |= bit (this_instr, 24) << 1;
+	  nextpc = MAKE_THUMB_ADDR (nextpc);
+	  break;
+	}
+      case 0xc:
+      case 0xd:
+      case 0xe:
+	/* Coprocessor register transfer.  */
+        if (bits (this_instr, 12, 15) == 15)
+	  error (_("Invalid update to pc in instruction"));
+	break;
+      }
+  else if (condition_true (bits (this_instr, 28, 31), status))
+    {
+      switch (bits (this_instr, 24, 27))
+	{
+	case 0x0:
+	case 0x1:			/* data processing */
+	case 0x2:
+	case 0x3:
+	  {
+	    unsigned long operand1, operand2, result = 0;
+	    unsigned long rn;
+	    int c;
+
+	    if (bits (this_instr, 12, 15) != 15)
+	      break;
+
+	    if (bits (this_instr, 22, 25) == 0
+		&& bits (this_instr, 4, 7) == 9)	/* multiply */
+	      error (_("Invalid update to pc in instruction"));
+
+	    /* BX <reg>, BLX <reg> */
+	    if (bits (this_instr, 4, 27) == 0x12fff1
+		|| bits (this_instr, 4, 27) == 0x12fff3)
+	      {
+		rn = bits (this_instr, 0, 3);
+		nextpc = ((rn == ARM_PC_REGNUM)
+			  ? (pc_val + 8)
+			  : self->ops->collect_register_unsigned (self, rn));
+
+		VEC_safe_push (CORE_ADDR, *next_pcs, nextpc);
+		return *next_pcs;
+	      }
+
+	    /* Multiply into PC.  */
+	    c = (status & FLAG_C) ? 1 : 0;
+	    rn = bits (this_instr, 16, 19);
+	    operand1 = ((rn == ARM_PC_REGNUM)
+			? (pc_val + 8)
+			: self->ops->collect_register_unsigned (self, rn));
+
+	    if (bit (this_instr, 25))
+	      {
+		unsigned long immval = bits (this_instr, 0, 7);
+		unsigned long rotate = 2 * bits (this_instr, 8, 11);
+		operand2 = ((immval >> rotate) | (immval << (32 - rotate)))
+		  & 0xffffffff;
+	      }
+	    else		/* operand 2 is a shifted register.  */
+	      operand2 = shifted_reg_val (self, this_instr, c,
+					  pc_val, status);
+
+	    switch (bits (this_instr, 21, 24))
+	      {
+	      case 0x0:	/*and */
+		result = operand1 & operand2;
+		break;
+
+	      case 0x1:	/*eor */
+		result = operand1 ^ operand2;
+		break;
+
+	      case 0x2:	/*sub */
+		result = operand1 - operand2;
+		break;
+
+	      case 0x3:	/*rsb */
+		result = operand2 - operand1;
+		break;
+
+	      case 0x4:	/*add */
+		result = operand1 + operand2;
+		break;
+
+	      case 0x5:	/*adc */
+		result = operand1 + operand2 + c;
+		break;
+
+	      case 0x6:	/*sbc */
+		result = operand1 - operand2 + c;
+		break;
+
+	      case 0x7:	/*rsc */
+		result = operand2 - operand1 + c;
+		break;
+
+	      case 0x8:
+	      case 0x9:
+	      case 0xa:
+	      case 0xb:	/* tst, teq, cmp, cmn */
+		result = (unsigned long) nextpc;
+		break;
+
+	      case 0xc:	/*orr */
+		result = operand1 | operand2;
+		break;
+
+	      case 0xd:	/*mov */
+		/* Always step into a function.  */
+		result = operand2;
+		break;
+
+	      case 0xe:	/*bic */
+		result = operand1 & ~operand2;
+		break;
+
+	      case 0xf:	/*mvn */
+		result = ~operand2;
+		break;
+	      }
+
+            /* In 26-bit APCS the bottom two bits of the result are
+	       ignored, and we always end up in ARM state.  */
+	    if (!self->arm_apcs_32)
+	      nextpc = self->ops->addr_bits_remove (self, result);
+	      else
+	      nextpc = result;
+	    break;
+	  }
+
+	case 0x4:
+	case 0x5:		/* data transfer */
+	case 0x6:
+	case 0x7:
+	  if (bits (this_instr, 25, 27) == 0x3 && bit (this_instr, 4) == 1)
+	    {
+	      /* Media instructions and architecturally undefined
+		 instructions.  */
+	      break;
+	    }
+	  if (bit (this_instr, 20))
+	    {
+	      /* load */
+	      if (bits (this_instr, 12, 15) == 15)
+		{
+		  /* rd == pc */
+		  unsigned long rn;
+		  unsigned long base;
+
+		  if (bit (this_instr, 22))
+		    error (_("Invalid update to pc in instruction"));
+
+		  /* byte write to PC */
+		  rn = bits (this_instr, 16, 19);
+		  base = ((rn == ARM_PC_REGNUM)
+			  ? (pc_val + 8)
+			  : self->ops->collect_register_unsigned (self, rn));
+
+		  if (bit (this_instr, 24))
+		    {
+		      /* pre-indexed */
+		      int c = (status & FLAG_C) ? 1 : 0;
+		      unsigned long offset =
+		      (bit (this_instr, 25)
+		       ? shifted_reg_val (self, this_instr, c,
+					  pc_val, status)
+		       : bits (this_instr, 0, 11));
+
+		      if (bit (this_instr, 23))
+			base += offset;
+		      else
+			base -= offset;
+		    }
+		  nextpc =
+		    (CORE_ADDR) self->ops->read_memory_unsigned_integer
+		    ((CORE_ADDR) base, 4, byte_order);
+		}
+	    }
+	  break;
+
+	case 0x8:
+	case 0x9:		/* block transfer */
+	  if (bit (this_instr, 20))
+	    {
+	      /* LDM */
+	      if (bit (this_instr, 15))
+		{
+		  /* loading pc */
+		  int offset = 0;
+		  unsigned long rn_val
+		    = self->ops->collect_register_unsigned
+		    (self, bits (this_instr, 16, 19));
+
+		  if (bit (this_instr, 23))
+		    {
+		      /* up */
+		      unsigned long reglist = bits (this_instr, 0, 14);
+		      offset = bitcount (reglist) * 4;
+		      if (bit (this_instr, 24))		/* pre */
+			offset += 4;
+		    }
+		  else if (bit (this_instr, 24))
+		    offset = -4;
+
+		  nextpc = (CORE_ADDR) self->ops->read_memory_unsigned_integer
+		    ((CORE_ADDR) (rn_val + offset), 4, byte_order);
+		}
+	    }
+	  break;
+
+	case 0xb:		/* branch & link */
+	case 0xa:		/* branch */
+	  {
+	    nextpc = BranchDest (pc, this_instr);
+	    break;
+	  }
+
+	case 0xc:
+	case 0xd:
+	case 0xe:		/* coproc ops */
+	  break;
+	case 0xf:		/* SWI */
+	  {
+	    nextpc = self->ops->syscall_next_pc (self, pc);
+	  }
+	  break;
+
+	default:
+	  error (_("Bad bit-field extraction\n"));
+	  return *next_pcs;
+	}
+    }
+
+  VEC_safe_push (CORE_ADDR, *next_pcs, nextpc);
+  return *next_pcs;
+}
diff --git a/gdb/arch/arm-get-next-pcs.h b/gdb/arch/arm-get-next-pcs.h
new file mode 100644
index 0000000..8e58bf8
--- /dev/null
+++ b/gdb/arch/arm-get-next-pcs.h
@@ -0,0 +1,98 @@ 
+/* Common code for ARM software single stepping support.
+
+   Copyright (C) 1988-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef ARM_GET_NEXT_PCS_H
+#define ARM_GET_NEXT_PCS_H 1
+
+/* Support routines for instruction parsing.  */
+#define submask(x) ((1L << ((x) + 1)) - 1)
+#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
+#define bit(obj,st) (((obj) >> (st)) & 1)
+#define sbits(obj,st,fn) \
+  ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
+#define BranchDest(addr,instr) \
+  ((CORE_ADDR) (((unsigned long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
+
+
+/* Forward declaration.  */
+struct arm_get_next_pcs;
+
+/* get_next_pcs operations.  */
+struct arm_get_next_pcs_ops
+{
+  ULONGEST (*read_memory_unsigned_integer) (CORE_ADDR memaddr,
+					    int len,
+					    int byte_order);
+  ULONGEST (*collect_register_unsigned) (struct arm_get_next_pcs *self, int n);
+  CORE_ADDR (*syscall_next_pc) (struct arm_get_next_pcs *self, CORE_ADDR pc);
+  CORE_ADDR (*addr_bits_remove) (struct arm_get_next_pcs *self, CORE_ADDR val);
+};
+
+/* Context for a get_next_pcs call on ARM.  */
+struct arm_get_next_pcs
+{
+  /* Operations implementations.  */
+  struct arm_get_next_pcs_ops *ops;
+  /* Byte order for data.  */
+  int byte_order;
+  /* Byte order for code.  */
+  int byte_order_for_code;
+  /* Is the pc in thumb mode.  */
+  int is_thumb;
+  /* Use 32bit or 26 bit pc.  */
+  int arm_apcs_32;
+  /* Thumb2 breakpoint instruction.  */
+  const gdb_byte *arm_thumb2_breakpoint;
+};
+
+/* Initialize arm_get_next_pcs.  */
+void arm_get_next_pcs_ctor (struct arm_get_next_pcs *self,
+			    struct arm_get_next_pcs_ops *ops,
+			    int byte_order,
+			    int byte_order_for_code,
+			    int is_thumb,
+			    int arm_apcs_32,
+			    const gdb_byte *arm_thumb2_breakpoint);
+
+/* Find the next possible PCs after the current instruction executes.  */
+VEC (CORE_ADDR) *arm_get_next_pcs (struct arm_get_next_pcs *self,
+				   CORE_ADDR pc);
+
+/* Find the next possible PCs for thumb mode.  */
+VEC (CORE_ADDR) *thumb_get_next_pcs_raw (struct arm_get_next_pcs *self,
+					 CORE_ADDR pc,
+					 VEC (CORE_ADDR) **next_pcs);
+
+/* Find the next possible PCs for arm mode.  */
+VEC (CORE_ADDR) *arm_get_next_pcs_raw (struct arm_get_next_pcs *self,
+				       CORE_ADDR pc,
+				       VEC (CORE_ADDR) **next_pcs);
+
+/* Return 1 if THIS_INSTR might change control flow, 0 otherwise.  */
+int arm_instruction_changes_pc (uint32_t this_instr);
+
+/* Return 1 if the 16-bit Thumb instruction INST might change
+   control flow, 0 otherwise.  */
+int thumb_instruction_changes_pc (unsigned short inst);
+
+/* Return 1 if the 32-bit Thumb instruction in INST1 and INST2
+   might change control flow, 0 otherwise.  */
+int thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2);
+
+#endif /* ARM_GET_NEXT_PCS_H */
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index 63fdae1..695d3e5 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -27,6 +27,8 @@ 
 #include "observer.h"
 #include "gdbthread.h"
 
+#include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
 #include "aarch32-linux-nat.h"
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 73e1271..d8d67b3 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -35,6 +35,8 @@ 
 #include "auxv.h"
 #include "xml-syscall.h"
 
+#include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
 #include "linux-tdep.h"
@@ -257,6 +259,14 @@  static const gdb_byte arm_linux_thumb2_le_breakpoint[] = { 0xf0, 0xf7, 0x00, 0xa
 #define ARM_LDR_PC_SP_12		0xe49df00c
 #define ARM_LDR_PC_SP_4			0xe49df004
 
+/* Operation function pointers for get_next_pcs.  */
+static struct arm_get_next_pcs_ops arm_linux_get_next_pcs_ops = {
+  arm_get_next_pcs_read_memory_unsigned_integer,
+  arm_get_next_pcs_collect_register_unsigned,
+  arm_get_next_pcs_syscall_next_pc,
+  arm_get_next_pcs_addr_bits_remove
+};
+
 static void
 arm_linux_sigtramp_cache (struct frame_info *this_frame,
 			  struct trad_frame_cache *this_cache,
@@ -912,27 +922,44 @@  arm_linux_software_single_step (struct frame_info *frame)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct address_space *aspace = get_frame_address_space (frame);
-  CORE_ADDR next_pc;
-
-  if (arm_deal_with_atomic_sequence (frame))
-    return 1;
+  struct arm_gdb_get_next_pcs next_pcs_ctx;
+  CORE_ADDR pc;
+  int i;
+  VEC (CORE_ADDR) *next_pcs = NULL;
 
   /* If the target does have hardware single step, GDB doesn't have
      to bother software single step.  */
   if (target_can_do_single_step () == 1)
     return 0;
 
-  next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
+  arm_gdb_get_next_pcs_ctor (&next_pcs_ctx,
+			     &arm_linux_get_next_pcs_ops,
+			     gdbarch_byte_order (gdbarch),
+			     gdbarch_byte_order_for_code (gdbarch),
+			     arm_frame_is_thumb (frame),
+			     arm_apcs_32,
+			     gdbarch_tdep (gdbarch)->thumb2_breakpoint,
+			     frame,
+			     gdbarch);
 
-  /* The Linux kernel offers some user-mode helpers in a high page.  We can
-     not read this page (as of 2.6.23), and even if we could then we couldn't
-     set breakpoints in it, and even if we could then the atomic operations
-     would fail when interrupted.  They are all called as functions and return
-     to the address in LR, so step to there instead.  */
-  if (next_pc > 0xffff0000)
-    next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+  next_pcs = arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs_ctx,
+			       get_frame_pc (frame));
+
+  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
+    {
+      /* The Linux kernel offers some user-mode helpers in a high page.  We can
+	 not read this page (as of 2.6.23), and even if we could then we
+	 couldn't set breakpoints in it, and even if we could then the atomic
+	 operations would fail when interrupted.  They are all called as
+	 functions and return to the address in LR, so step to there
+	 instead.  */
+      if (pc > 0xffff0000)
+	pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+
+      arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
+    }
 
-  arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
+  VEC_free (CORE_ADDR, next_pcs);
 
   return 1;
 }
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index c361f62..373f628 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -46,6 +46,7 @@ 
 #include "observer.h"
 
 #include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
 
@@ -236,6 +237,14 @@  static void arm_neon_quad_write (struct gdbarch *gdbarch,
 				 struct regcache *regcache,
 				 int regnum, const gdb_byte *buf);
 
+/* get_next_pcs operations.  */
+static struct arm_get_next_pcs_ops arm_get_next_pcs_ops = {
+  arm_get_next_pcs_read_memory_unsigned_integer,
+  arm_get_next_pcs_collect_register_unsigned,
+  arm_get_next_pcs_syscall_next_pc,
+  arm_get_next_pcs_addr_bits_remove
+};
+
 struct arm_prologue_cache
 {
   /* The stack pointer at the time this frame was created; i.e. the
@@ -507,15 +516,6 @@  skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb)
   return 0;
 }
 
-/* Support routines for instruction parsing.  */
-#define submask(x) ((1L << ((x) + 1)) - 1)
-#define bit(obj,st) (((obj) >> (st)) & 1)
-#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
-#define sbits(obj,st,fn) \
-  ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
-#define BranchDest(addr,instr) \
-  ((CORE_ADDR) (((unsigned long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
-
 /* Extract the immediate from instruction movw/movt of encoding T.  INSN1 is
    the first 16-bit of instruction, and INSN2 is the second 16-bit of
    instruction.  */
@@ -555,128 +555,6 @@  thumb_expand_immediate (unsigned int imm)
   return (0x80 | (imm & 0x7f)) << (32 - count);
 }
 
-/* Return 1 if the 16-bit Thumb instruction INST might change
-   control flow, 0 otherwise.  */
-
-static int
-thumb_instruction_changes_pc (unsigned short inst)
-{
-  if ((inst & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
-    return 1;
-
-  if ((inst & 0xf000) == 0xd000)	/* conditional branch */
-    return 1;
-
-  if ((inst & 0xf800) == 0xe000)	/* unconditional branch */
-    return 1;
-
-  if ((inst & 0xff00) == 0x4700)	/* bx REG, blx REG */
-    return 1;
-
-  if ((inst & 0xff87) == 0x4687)	/* mov pc, REG */
-    return 1;
-
-  if ((inst & 0xf500) == 0xb100)	/* CBNZ or CBZ.  */
-    return 1;
-
-  return 0;
-}
-
-/* Return 1 if the 32-bit Thumb instruction in INST1 and INST2
-   might change control flow, 0 otherwise.  */
-
-static int
-thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2)
-{
-  if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
-    {
-      /* Branches and miscellaneous control instructions.  */
-
-      if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
-	{
-	  /* B, BL, BLX.  */
-	  return 1;
-	}
-      else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
-	{
-	  /* SUBS PC, LR, #imm8.  */
-	  return 1;
-	}
-      else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
-	{
-	  /* Conditional branch.  */
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  if ((inst1 & 0xfe50) == 0xe810)
-    {
-      /* Load multiple or RFE.  */
-
-      if (bit (inst1, 7) && !bit (inst1, 8))
-	{
-	  /* LDMIA or POP */
-	  if (bit (inst2, 15))
-	    return 1;
-	}
-      else if (!bit (inst1, 7) && bit (inst1, 8))
-	{
-	  /* LDMDB */
-	  if (bit (inst2, 15))
-	    return 1;
-	}
-      else if (bit (inst1, 7) && bit (inst1, 8))
-	{
-	  /* RFEIA */
-	  return 1;
-	}
-      else if (!bit (inst1, 7) && !bit (inst1, 8))
-	{
-	  /* RFEDB */
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
-    {
-      /* MOV PC or MOVS PC.  */
-      return 1;
-    }
-
-  if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
-    {
-      /* LDR PC.  */
-      if (bits (inst1, 0, 3) == 15)
-	return 1;
-      if (bit (inst1, 7))
-	return 1;
-      if (bit (inst2, 11))
-	return 1;
-      if ((inst2 & 0x0fc0) == 0x0000)
-	return 1;	
-
-      return 0;
-    }
-
-  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
-    {
-      /* TBB.  */
-      return 1;
-    }
-
-  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
-    {
-      /* TBH.  */
-      return 1;
-    }
-
-  return 0;
-}
-
 /* Return 1 if the 16-bit Thumb instruction INSN restores SP in
    epilogue, 0 otherwise.  */
 
@@ -1504,98 +1382,6 @@  thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
   thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
 }
 
-/* Return 1 if THIS_INSTR might change control flow, 0 otherwise.  */
-
-static int
-arm_instruction_changes_pc (uint32_t this_instr)
-{
-  if (bits (this_instr, 28, 31) == INST_NV)
-    /* Unconditional instructions.  */
-    switch (bits (this_instr, 24, 27))
-      {
-      case 0xa:
-      case 0xb:
-	/* Branch with Link and change to Thumb.  */
-	return 1;
-      case 0xc:
-      case 0xd:
-      case 0xe:
-	/* Coprocessor register transfer.  */
-        if (bits (this_instr, 12, 15) == 15)
-	  error (_("Invalid update to pc in instruction"));
-	return 0;
-      default:
-	return 0;
-      }
-  else
-    switch (bits (this_instr, 25, 27))
-      {
-      case 0x0:
-	if (bits (this_instr, 23, 24) == 2 && bit (this_instr, 20) == 0)
-	  {
-	    /* Multiplies and extra load/stores.  */
-	    if (bit (this_instr, 4) == 1 && bit (this_instr, 7) == 1)
-	      /* Neither multiplies nor extension load/stores are allowed
-		 to modify PC.  */
-	      return 0;
-
-	    /* Otherwise, miscellaneous instructions.  */
-
-	    /* BX <reg>, BXJ <reg>, BLX <reg> */
-	    if (bits (this_instr, 4, 27) == 0x12fff1
-		|| bits (this_instr, 4, 27) == 0x12fff2
-		|| bits (this_instr, 4, 27) == 0x12fff3)
-	      return 1;
-
-	    /* Other miscellaneous instructions are unpredictable if they
-	       modify PC.  */
-	    return 0;
-	  }
-	/* Data processing instruction.  Fall through.  */
-
-      case 0x1:
-	if (bits (this_instr, 12, 15) == 15)
-	  return 1;
-	else
-	  return 0;
-
-      case 0x2:
-      case 0x3:
-	/* Media instructions and architecturally undefined instructions.  */
-	if (bits (this_instr, 25, 27) == 3 && bit (this_instr, 4) == 1)
-	  return 0;
-
-	/* Stores.  */
-	if (bit (this_instr, 20) == 0)
-	  return 0;
-
-	/* Loads.  */
-	if (bits (this_instr, 12, 15) == ARM_PC_REGNUM)
-	  return 1;
-	else
-	  return 0;
-
-      case 0x4:
-	/* Load/store multiple.  */
-	if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1)
-	  return 1;
-	else
-	  return 0;
-
-      case 0x5:
-	/* Branch and branch with link.  */
-	return 1;
-
-      case 0x6:
-      case 0x7:
-	/* Coprocessor transfers or SWIs can not affect PC.  */
-	return 0;
-
-      default:
-	internal_error (__FILE__, __LINE__, _("bad value in switch"));
-      }
-}
-
 /* Return 1 if the ARM instruction INSN restores SP in epilogue, 0
    otherwise.  */
 
@@ -4290,1102 +4076,131 @@  convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
 			       &d, dbl);
 }
 
-static unsigned long
-shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
-		 unsigned long pc_val, unsigned long status_reg)
+/* 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)
 {
-  unsigned long res, shift;
-  int rm = bits (inst, 0, 3);
-  unsigned long shifttype = bits (inst, 5, 6);
+  struct cleanup *old_chain
+    = make_cleanup_restore_integer (&arm_override_mode);
 
-  if (bit (inst, 4))
-    {
-      int rs = bits (inst, 8, 11);
-      shift = (rs == 15 ? pc_val + 8
-			: get_frame_register_unsigned (frame, rs)) & 0xFF;
-    }
-  else
-    shift = bits (inst, 7, 11);
+  arm_override_mode = IS_THUMB_ADDR (pc);
+  pc = gdbarch_addr_bits_remove (gdbarch, pc);
 
-  res = (rm == ARM_PC_REGNUM
-	 ? (pc_val + (bit (inst, 4) ? 12 : 8))
-	 : get_frame_register_unsigned (frame, rm));
+  insert_single_step_breakpoint (gdbarch, aspace, pc);
 
-  switch (shifttype)
-    {
-    case 0:			/* LSL */
-      res = shift >= 32 ? 0 : res << shift;
-      break;
+  do_cleanups (old_chain);
+}
 
-    case 1:			/* LSR */
-      res = shift >= 32 ? 0 : res >> shift;
-      break;
+/* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand
+   the buffer to be NEW_LEN bytes ending at ENDADDR.  Return
+   NULL if an error occurs.  BUF is freed.  */
 
-    case 2:			/* ASR */
-      if (shift >= 32)
-	shift = 31;
-      res = ((res & 0x80000000L)
-	     ? ~((~res) >> shift) : res >> shift);
-      break;
+static gdb_byte *
+extend_buffer_earlier (gdb_byte *buf, CORE_ADDR endaddr,
+		       int old_len, int new_len)
+{
+  gdb_byte *new_buf;
+  int bytes_to_read = new_len - old_len;
 
-    case 3:			/* ROR/RRX */
-      shift &= 31;
-      if (shift == 0)
-	res = (res >> 1) | (carry ? 0x80000000L : 0);
-      else
-	res = (res >> shift) | (res << (32 - shift));
-      break;
+  new_buf = (gdb_byte *) xmalloc (new_len);
+  memcpy (new_buf + bytes_to_read, buf, old_len);
+  xfree (buf);
+  if (target_read_memory (endaddr - new_len, new_buf, bytes_to_read) != 0)
+    {
+      xfree (new_buf);
+      return NULL;
     }
-
-  return res & 0xffffffff;
+  return new_buf;
 }
 
-static int
-thumb_advance_itstate (unsigned int itstate)
-{
-  /* Preserve IT[7:5], the first three bits of the condition.  Shift
-     the upcoming condition flags left by one bit.  */
-  itstate = (itstate & 0xe0) | ((itstate << 1) & 0x1f);
-
-  /* If we have finished the IT block, clear the state.  */
-  if ((itstate & 0x0f) == 0)
-    itstate = 0;
-
-  return itstate;
-}
+/* An IT block is at most the 2-byte IT instruction followed by
+   four 4-byte instructions.  The furthest back we must search to
+   find an IT block that affects the current instruction is thus
+   2 + 3 * 4 == 14 bytes.  */
+#define MAX_IT_BLOCK_PREFIX 14
 
-/* Find the next PC after the current instruction executes.  In some
-   cases we can not statically determine the answer (see the IT state
-   handling in this function); in that case, a breakpoint may be
-   inserted in addition to the returned PC, which will be used to set
-   another breakpoint by our caller.  */
+/* Use a quick scan if there are more than this many bytes of
+   code.  */
+#define IT_SCAN_THRESHOLD 32
 
+/* Adjust a breakpoint's address to move breakpoints out of IT blocks.
+   A breakpoint in an IT block may not be hit, depending on the
+   condition flags.  */
 static CORE_ADDR
-thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
+arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  struct address_space *aspace = get_frame_address_space (frame);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  unsigned long pc_val = ((unsigned long) pc) + 4;	/* PC after prefetch */
-  unsigned short inst1;
-  CORE_ADDR nextpc = pc + 2;		/* Default is next instruction.  */
-  unsigned long offset;
-  ULONGEST status, itstate;
-
-  nextpc = MAKE_THUMB_ADDR (nextpc);
-  pc_val = MAKE_THUMB_ADDR (pc_val);
-
-  inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
-
-  /* Thumb-2 conditional execution support.  There are eight bits in
-     the CPSR which describe conditional execution state.  Once
-     reconstructed (they're in a funny order), the low five bits
-     describe the low bit of the condition for each instruction and
-     how many instructions remain.  The high three bits describe the
-     base condition.  One of the low four bits will be set if an IT
-     block is active.  These bits read as zero on earlier
-     processors.  */
-  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
-  itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
-
-  /* If-Then handling.  On GNU/Linux, where this routine is used, we
-     use an undefined instruction as a breakpoint.  Unlike BKPT, IT
-     can disable execution of the undefined instruction.  So we might
-     miss the breakpoint if we set it on a skipped conditional
-     instruction.  Because conditional instructions can change the
-     flags, affecting the execution of further instructions, we may
-     need to set two breakpoints.  */
-
-  if (gdbarch_tdep (gdbarch)->thumb2_breakpoint != NULL)
-    {
-      if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
-	{
-	  /* An IT instruction.  Because this instruction does not
-	     modify the flags, we can accurately predict the next
-	     executed instruction.  */
-	  itstate = inst1 & 0x00ff;
-	  pc += thumb_insn_size (inst1);
-
-	  while (itstate != 0 && ! condition_true (itstate >> 4, status))
-	    {
-	      inst1 = read_memory_unsigned_integer (pc, 2,
-						    byte_order_for_code);
-	      pc += thumb_insn_size (inst1);
-	      itstate = thumb_advance_itstate (itstate);
-	    }
-
-	  return MAKE_THUMB_ADDR (pc);
-	}
-      else if (itstate != 0)
-	{
-	  /* We are in a conditional block.  Check the condition.  */
-	  if (! condition_true (itstate >> 4, status))
-	    {
-	      /* Advance to the next executed instruction.  */
-	      pc += thumb_insn_size (inst1);
-	      itstate = thumb_advance_itstate (itstate);
+  gdb_byte *buf;
+  char map_type;
+  CORE_ADDR boundary, func_start;
+  int buf_len;
+  enum bfd_endian order = gdbarch_byte_order_for_code (gdbarch);
+  int i, any, last_it, last_it_count;
 
-	      while (itstate != 0 && ! condition_true (itstate >> 4, status))
-		{
-		  inst1 = read_memory_unsigned_integer (pc, 2, 
-							byte_order_for_code);
-		  pc += thumb_insn_size (inst1);
-		  itstate = thumb_advance_itstate (itstate);
-		}
+  /* If we are using BKPT breakpoints, none of this is necessary.  */
+  if (gdbarch_tdep (gdbarch)->thumb2_breakpoint == NULL)
+    return bpaddr;
 
-	      return MAKE_THUMB_ADDR (pc);
-	    }
-	  else if ((itstate & 0x0f) == 0x08)
-	    {
-	      /* This is the last instruction of the conditional
-		 block, and it is executed.  We can handle it normally
-		 because the following instruction is not conditional,
-		 and we must handle it normally because it is
-		 permitted to branch.  Fall through.  */
-	    }
-	  else
-	    {
-	      int cond_negated;
-
-	      /* There are conditional instructions after this one.
-		 If this instruction modifies the flags, then we can
-		 not predict what the next executed instruction will
-		 be.  Fortunately, this instruction is architecturally
-		 forbidden to branch; we know it will fall through.
-		 Start by skipping past it.  */
-	      pc += thumb_insn_size (inst1);
-	      itstate = thumb_advance_itstate (itstate);
-
-	      /* Set a breakpoint on the following instruction.  */
-	      gdb_assert ((itstate & 0x0f) != 0);
-	      arm_insert_single_step_breakpoint (gdbarch, aspace,
-						 MAKE_THUMB_ADDR (pc));
-	      cond_negated = (itstate >> 4) & 1;
-
-	      /* Skip all following instructions with the same
-		 condition.  If there is a later instruction in the IT
-		 block with the opposite condition, set the other
-		 breakpoint there.  If not, then set a breakpoint on
-		 the instruction after the IT block.  */
-	      do
-		{
-		  inst1 = read_memory_unsigned_integer (pc, 2,
-							byte_order_for_code);
-		  pc += thumb_insn_size (inst1);
-		  itstate = thumb_advance_itstate (itstate);
-		}
-	      while (itstate != 0 && ((itstate >> 4) & 1) == cond_negated);
+  /* ARM mode does not have this problem.  */
+  if (!arm_pc_is_thumb (gdbarch, bpaddr))
+    return bpaddr;
 
-	      return MAKE_THUMB_ADDR (pc);
-	    }
-	}
-    }
-  else if (itstate & 0x0f)
-    {
-      /* We are in a conditional block.  Check the condition.  */
-      int cond = itstate >> 4;
+  /* We are setting a breakpoint in Thumb code that could potentially
+     contain an IT block.  The first step is to find how much Thumb
+     code there is; we do not need to read outside of known Thumb
+     sequences.  */
+  map_type = arm_find_mapping_symbol (bpaddr, &boundary);
+  if (map_type == 0)
+    /* Thumb-2 code must have mapping symbols to have a chance.  */
+    return bpaddr;
 
-      if (! condition_true (cond, status))
-	/* Advance to the next instruction.  All the 32-bit
-	   instructions share a common prefix.  */
-	return MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1));
+  bpaddr = gdbarch_addr_bits_remove (gdbarch, bpaddr);
 
-      /* Otherwise, handle the instruction normally.  */
-    }
+  if (find_pc_partial_function (bpaddr, NULL, &func_start, NULL)
+      && func_start > boundary)
+    boundary = func_start;
 
-  if ((inst1 & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
-    {
-      CORE_ADDR sp;
+  /* Search for a candidate IT instruction.  We have to do some fancy
+     footwork to distinguish a real IT instruction from the second
+     half of a 32-bit instruction, but there is no need for that if
+     there's no candidate.  */
+  buf_len = min (bpaddr - boundary, MAX_IT_BLOCK_PREFIX);
+  if (buf_len == 0)
+    /* No room for an IT instruction.  */
+    return bpaddr;
 
-      /* Fetch the saved PC from the stack.  It's stored above
-         all of the other registers.  */
-      offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
-      sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
-      nextpc = read_memory_unsigned_integer (sp + offset, 4, byte_order);
-    }
-  else if ((inst1 & 0xf000) == 0xd000)	/* conditional branch */
+  buf = (gdb_byte *) xmalloc (buf_len);
+  if (target_read_memory (bpaddr - buf_len, buf, buf_len) != 0)
+    return bpaddr;
+  any = 0;
+  for (i = 0; i < buf_len; i += 2)
     {
-      unsigned long cond = bits (inst1, 8, 11);
-      if (cond == 0x0f)  /* 0x0f = SWI */
+      unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
+      if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
 	{
-	  struct gdbarch_tdep *tdep;
-	  tdep = gdbarch_tdep (gdbarch);
-
-	  if (tdep->syscall_next_pc != NULL)
-	    nextpc = tdep->syscall_next_pc (frame);
-
+	  any = 1;
+	  break;
 	}
-      else if (cond != 0x0f && condition_true (cond, status))
-	nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
     }
-  else if ((inst1 & 0xf800) == 0xe000)	/* unconditional branch */
+  if (any == 0)
     {
-      nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
+      xfree (buf);
+      return bpaddr;
     }
-  else if (thumb_insn_size (inst1) == 4) /* 32-bit instruction */
+
+  /* OK, the code bytes before this instruction contain at least one
+     halfword which resembles an IT instruction.  We know that it's
+     Thumb code, but there are still two possibilities.  Either the
+     halfword really is an IT instruction, or it is the second half of
+     a 32-bit Thumb instruction.  The only way we can tell is to
+     scan forwards from a known instruction boundary.  */
+  if (bpaddr - boundary > IT_SCAN_THRESHOLD)
     {
-      unsigned short inst2;
-      inst2 = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code);
-
-      /* Default to the next instruction.  */
-      nextpc = pc + 4;
-      nextpc = MAKE_THUMB_ADDR (nextpc);
-
-      if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
-	{
-	  /* Branches and miscellaneous control instructions.  */
-
-	  if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
-	    {
-	      /* B, BL, BLX.  */
-	      int j1, j2, imm1, imm2;
-
-	      imm1 = sbits (inst1, 0, 10);
-	      imm2 = bits (inst2, 0, 10);
-	      j1 = bit (inst2, 13);
-	      j2 = bit (inst2, 11);
-
-	      offset = ((imm1 << 12) + (imm2 << 1));
-	      offset ^= ((!j2) << 22) | ((!j1) << 23);
-
-	      nextpc = pc_val + offset;
-	      /* For BLX make sure to clear the low bits.  */
-	      if (bit (inst2, 12) == 0)
-		nextpc = nextpc & 0xfffffffc;
-	    }
-	  else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
-	    {
-	      /* SUBS PC, LR, #imm8.  */
-	      nextpc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
-	      nextpc -= inst2 & 0x00ff;
-	    }
-	  else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
-	    {
-	      /* Conditional branch.  */
-	      if (condition_true (bits (inst1, 6, 9), status))
-		{
-		  int sign, j1, j2, imm1, imm2;
-
-		  sign = sbits (inst1, 10, 10);
-		  imm1 = bits (inst1, 0, 5);
-		  imm2 = bits (inst2, 0, 10);
-		  j1 = bit (inst2, 13);
-		  j2 = bit (inst2, 11);
-
-		  offset = (sign << 20) + (j2 << 19) + (j1 << 18);
-		  offset += (imm1 << 12) + (imm2 << 1);
-
-		  nextpc = pc_val + offset;
-		}
-	    }
-	}
-      else if ((inst1 & 0xfe50) == 0xe810)
-	{
-	  /* Load multiple or RFE.  */
-	  int rn, offset, load_pc = 1;
-
-	  rn = bits (inst1, 0, 3);
-	  if (bit (inst1, 7) && !bit (inst1, 8))
-	    {
-	      /* LDMIA or POP */
-	      if (!bit (inst2, 15))
-		load_pc = 0;
-	      offset = bitcount (inst2) * 4 - 4;
-	    }
-	  else if (!bit (inst1, 7) && bit (inst1, 8))
-	    {
-	      /* LDMDB */
-	      if (!bit (inst2, 15))
-		load_pc = 0;
-	      offset = -4;
-	    }
-	  else if (bit (inst1, 7) && bit (inst1, 8))
-	    {
-	      /* RFEIA */
-	      offset = 0;
-	    }
-	  else if (!bit (inst1, 7) && !bit (inst1, 8))
-	    {
-	      /* RFEDB */
-	      offset = -8;
-	    }
-	  else
-	    load_pc = 0;
-
-	  if (load_pc)
-	    {
-	      CORE_ADDR addr = get_frame_register_unsigned (frame, rn);
-	      nextpc = get_frame_memory_unsigned (frame, addr + offset, 4);
-	    }
-	}
-      else if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
-	{
-	  /* MOV PC or MOVS PC.  */
-	  nextpc = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
-	  nextpc = MAKE_THUMB_ADDR (nextpc);
-	}
-      else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
-	{
-	  /* LDR PC.  */
-	  CORE_ADDR base;
-	  int rn, load_pc = 1;
-
-	  rn = bits (inst1, 0, 3);
-	  base = get_frame_register_unsigned (frame, rn);
-	  if (rn == ARM_PC_REGNUM)
-	    {
-	      base = (base + 4) & ~(CORE_ADDR) 0x3;
-	      if (bit (inst1, 7))
-		base += bits (inst2, 0, 11);
-	      else
-		base -= bits (inst2, 0, 11);
-	    }
-	  else if (bit (inst1, 7))
-	    base += bits (inst2, 0, 11);
-	  else if (bit (inst2, 11))
-	    {
-	      if (bit (inst2, 10))
-		{
-		  if (bit (inst2, 9))
-		    base += bits (inst2, 0, 7);
-		  else
-		    base -= bits (inst2, 0, 7);
-		}
-	    }
-	  else if ((inst2 & 0x0fc0) == 0x0000)
-	    {
-	      int shift = bits (inst2, 4, 5), rm = bits (inst2, 0, 3);
-	      base += get_frame_register_unsigned (frame, rm) << shift;
-	    }
-	  else
-	    /* Reserved.  */
-	    load_pc = 0;
-
-	  if (load_pc)
-	    nextpc = get_frame_memory_unsigned (frame, base, 4);
-	}
-      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
-	{
-	  /* TBB.  */
-	  CORE_ADDR tbl_reg, table, offset, length;
-
-	  tbl_reg = bits (inst1, 0, 3);
-	  if (tbl_reg == 0x0f)
-	    table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
-	  else
-	    table = get_frame_register_unsigned (frame, tbl_reg);
-
-	  offset = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
-	  length = 2 * get_frame_memory_unsigned (frame, table + offset, 1);
-	  nextpc = pc_val + length;
-	}
-      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
-	{
-	  /* TBH.  */
-	  CORE_ADDR tbl_reg, table, offset, length;
-
-	  tbl_reg = bits (inst1, 0, 3);
-	  if (tbl_reg == 0x0f)
-	    table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
-	  else
-	    table = get_frame_register_unsigned (frame, tbl_reg);
-
-	  offset = 2 * get_frame_register_unsigned (frame, bits (inst2, 0, 3));
-	  length = 2 * get_frame_memory_unsigned (frame, table + offset, 2);
-	  nextpc = pc_val + length;
-	}
-    }
-  else if ((inst1 & 0xff00) == 0x4700)	/* bx REG, blx REG */
-    {
-      if (bits (inst1, 3, 6) == 0x0f)
-	nextpc = UNMAKE_THUMB_ADDR (pc_val);
-      else
-	nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
-    }
-  else if ((inst1 & 0xff87) == 0x4687)	/* mov pc, REG */
-    {
-      if (bits (inst1, 3, 6) == 0x0f)
-	nextpc = pc_val;
-      else
-	nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
-
-      nextpc = MAKE_THUMB_ADDR (nextpc);
-    }
-  else if ((inst1 & 0xf500) == 0xb100)
-    {
-      /* CBNZ or CBZ.  */
-      int imm = (bit (inst1, 9) << 6) + (bits (inst1, 3, 7) << 1);
-      ULONGEST reg = get_frame_register_unsigned (frame, bits (inst1, 0, 2));
-
-      if (bit (inst1, 11) && reg != 0)
-	nextpc = pc_val + imm;
-      else if (!bit (inst1, 11) && reg == 0)
-	nextpc = pc_val + imm;
-    }
-  return nextpc;
-}
-
-/* Get the raw next address.  PC is the current program counter, in 
-   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
-   in Thumb-State, and gdbarch_addr_bits_remove () to get the plain memory
-   address.  */
-
-static CORE_ADDR
-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);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  unsigned long pc_val;
-  unsigned long this_instr;
-  unsigned long status;
-  CORE_ADDR nextpc;
-
-  pc_val = (unsigned long) pc;
-  this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
-
-  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
-  nextpc = (CORE_ADDR) (pc_val + 4);	/* Default case */
-
-  if (bits (this_instr, 28, 31) == INST_NV)
-    switch (bits (this_instr, 24, 27))
-      {
-      case 0xa:
-      case 0xb:
-	{
-	  /* Branch with Link and change to Thumb.  */
-	  nextpc = BranchDest (pc, this_instr);
-	  nextpc |= bit (this_instr, 24) << 1;
-	  nextpc = MAKE_THUMB_ADDR (nextpc);
-	  break;
-	}
-      case 0xc:
-      case 0xd:
-      case 0xe:
-	/* Coprocessor register transfer.  */
-        if (bits (this_instr, 12, 15) == 15)
-	  error (_("Invalid update to pc in instruction"));
-	break;
-      }
-  else if (condition_true (bits (this_instr, 28, 31), status))
-    {
-      switch (bits (this_instr, 24, 27))
-	{
-	case 0x0:
-	case 0x1:			/* data processing */
-	case 0x2:
-	case 0x3:
-	  {
-	    unsigned long operand1, operand2, result = 0;
-	    unsigned long rn;
-	    int c;
-
-	    if (bits (this_instr, 12, 15) != 15)
-	      break;
-
-	    if (bits (this_instr, 22, 25) == 0
-		&& bits (this_instr, 4, 7) == 9)	/* multiply */
-	      error (_("Invalid update to pc in instruction"));
-
-	    /* BX <reg>, BLX <reg> */
-	    if (bits (this_instr, 4, 27) == 0x12fff1
-		|| bits (this_instr, 4, 27) == 0x12fff3)
-	      {
-		rn = bits (this_instr, 0, 3);
-		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 == ARM_PC_REGNUM)
-			? (pc_val + 8)
-			: get_frame_register_unsigned (frame, rn));
-
-	    if (bit (this_instr, 25))
-	      {
-		unsigned long immval = bits (this_instr, 0, 7);
-		unsigned long rotate = 2 * bits (this_instr, 8, 11);
-		operand2 = ((immval >> rotate) | (immval << (32 - rotate)))
-		  & 0xffffffff;
-	      }
-	    else		/* operand 2 is a shifted register.  */
-	      operand2 = shifted_reg_val (frame, this_instr, c,
-					  pc_val, status);
-
-	    switch (bits (this_instr, 21, 24))
-	      {
-	      case 0x0:	/*and */
-		result = operand1 & operand2;
-		break;
-
-	      case 0x1:	/*eor */
-		result = operand1 ^ operand2;
-		break;
-
-	      case 0x2:	/*sub */
-		result = operand1 - operand2;
-		break;
-
-	      case 0x3:	/*rsb */
-		result = operand2 - operand1;
-		break;
-
-	      case 0x4:	/*add */
-		result = operand1 + operand2;
-		break;
-
-	      case 0x5:	/*adc */
-		result = operand1 + operand2 + c;
-		break;
-
-	      case 0x6:	/*sbc */
-		result = operand1 - operand2 + c;
-		break;
-
-	      case 0x7:	/*rsc */
-		result = operand2 - operand1 + c;
-		break;
-
-	      case 0x8:
-	      case 0x9:
-	      case 0xa:
-	      case 0xb:	/* tst, teq, cmp, cmn */
-		result = (unsigned long) nextpc;
-		break;
-
-	      case 0xc:	/*orr */
-		result = operand1 | operand2;
-		break;
-
-	      case 0xd:	/*mov */
-		/* Always step into a function.  */
-		result = operand2;
-		break;
-
-	      case 0xe:	/*bic */
-		result = operand1 & ~operand2;
-		break;
-
-	      case 0xf:	/*mvn */
-		result = ~operand2;
-		break;
-	      }
-
-            /* In 26-bit APCS the bottom two bits of the result are 
-	       ignored, and we always end up in ARM state.  */
-	    if (!arm_apcs_32)
-	      nextpc = arm_addr_bits_remove (gdbarch, result);
-	    else
-	      nextpc = result;
-
-	    break;
-	  }
-
-	case 0x4:
-	case 0x5:		/* data transfer */
-	case 0x6:
-	case 0x7:
-	  if (bits (this_instr, 25, 27) == 0x3 && bit (this_instr, 4) == 1)
-	    {
-	      /* Media instructions and architecturally undefined
-		 instructions.  */
-	      break;
-	    }
-
-	  if (bit (this_instr, 20))
-	    {
-	      /* load */
-	      if (bits (this_instr, 12, 15) == 15)
-		{
-		  /* rd == pc */
-		  unsigned long rn;
-		  unsigned long base;
-
-		  if (bit (this_instr, 22))
-		    error (_("Invalid update to pc in instruction"));
-
-		  /* byte write to PC */
-		  rn = bits (this_instr, 16, 19);
-		  base = ((rn == ARM_PC_REGNUM)
-			  ? (pc_val + 8)
-			  : get_frame_register_unsigned (frame, rn));
-
-		  if (bit (this_instr, 24))
-		    {
-		      /* pre-indexed */
-		      int c = (status & FLAG_C) ? 1 : 0;
-		      unsigned long offset =
-		      (bit (this_instr, 25)
-		       ? shifted_reg_val (frame, this_instr, c, pc_val, status)
-		       : bits (this_instr, 0, 11));
-
-		      if (bit (this_instr, 23))
-			base += offset;
-		      else
-			base -= offset;
-		    }
-		  nextpc =
-		    (CORE_ADDR) read_memory_unsigned_integer ((CORE_ADDR) base,
-							      4, byte_order);
-		}
-	    }
-	  break;
-
-	case 0x8:
-	case 0x9:		/* block transfer */
-	  if (bit (this_instr, 20))
-	    {
-	      /* LDM */
-	      if (bit (this_instr, 15))
-		{
-		  /* loading pc */
-		  int offset = 0;
-		  unsigned long rn_val
-		    = get_frame_register_unsigned (frame,
-						   bits (this_instr, 16, 19));
-
-		  if (bit (this_instr, 23))
-		    {
-		      /* up */
-		      unsigned long reglist = bits (this_instr, 0, 14);
-		      offset = bitcount (reglist) * 4;
-		      if (bit (this_instr, 24))		/* pre */
-			offset += 4;
-		    }
-		  else if (bit (this_instr, 24))
-		    offset = -4;
-
-		  nextpc =
-		    (CORE_ADDR) read_memory_unsigned_integer ((CORE_ADDR)
-							      (rn_val + offset),
-							      4, byte_order);
-		}
-	    }
-	  break;
-
-	case 0xb:		/* branch & link */
-	case 0xa:		/* branch */
-	  {
-	    nextpc = BranchDest (pc, this_instr);
-	    break;
-	  }
-
-	case 0xc:
-	case 0xd:
-	case 0xe:		/* coproc ops */
-	  break;
-	case 0xf:		/* SWI */
-	  {
-	    struct gdbarch_tdep *tdep;
-	    tdep = gdbarch_tdep (gdbarch);
-
-	    if (tdep->syscall_next_pc != NULL)
-	      nextpc = tdep->syscall_next_pc (frame);
-
-	  }
-	  break;
-
-	default:
-	  fprintf_filtered (gdb_stderr, _("Bad bit-field extraction\n"));
-	  return (pc);
-	}
-    }
-
-  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)
-{
-  CORE_ADDR nextpc;
-
-  if (arm_frame_is_thumb (frame))
-    nextpc = thumb_get_next_pc_raw (frame, pc);
-  else
-    nextpc = arm_get_next_pc_raw (frame, pc);
-
-  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);
-}
-
-/* Checks for an atomic sequence of instructions beginning with a LDREX{,B,H,D}
-   instruction and ending with a STREX{,B,H,D} instruction.  If such a sequence
-   is found, attempt to step through it.  A breakpoint is placed at the end of
-   the sequence.  */
-
-static int
-thumb_deal_with_atomic_sequence_raw (struct frame_info *frame)
-{
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  struct address_space *aspace = get_frame_address_space (frame);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  CORE_ADDR pc = get_frame_pc (frame);
-  CORE_ADDR breaks[2] = {-1, -1};
-  CORE_ADDR loc = pc;
-  unsigned short insn1, insn2;
-  int insn_count;
-  int index;
-  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
-  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
-  ULONGEST status, itstate;
-
-  /* We currently do not support atomic sequences within an IT block.  */
-  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
-  itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
-  if (itstate & 0x0f)
-    return 0;
-
-  /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.  */
-  insn1 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
-  loc += 2;
-  if (thumb_insn_size (insn1) != 4)
-    return 0;
-
-  insn2 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
-  loc += 2;
-  if (!((insn1 & 0xfff0) == 0xe850
-        || ((insn1 & 0xfff0) == 0xe8d0 && (insn2 & 0x00c0) == 0x0040)))
-    return 0;
-
-  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
-     instructions.  */
-  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
-    {
-      insn1 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
-      loc += 2;
-
-      if (thumb_insn_size (insn1) != 4)
-	{
-	  /* Assume that there is at most one conditional branch in the
-	     atomic sequence.  If a conditional branch is found, put a
-	     breakpoint in its destination address.  */
-	  if ((insn1 & 0xf000) == 0xd000 && bits (insn1, 8, 11) != 0x0f)
-	    {
-	      if (last_breakpoint > 0)
-		return 0; /* More than one conditional branch found,
-			     fallback to the standard code.  */
-
-	      breaks[1] = loc + 2 + (sbits (insn1, 0, 7) << 1);
-	      last_breakpoint++;
-	    }
-
-	  /* We do not support atomic sequences that use any *other*
-	     instructions but conditional branches to change the PC.
-	     Fall back to standard code to avoid losing control of
-	     execution.  */
-	  else if (thumb_instruction_changes_pc (insn1))
-	    return 0;
-	}
-      else
-	{
-	  insn2 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
-	  loc += 2;
-
-	  /* Assume that there is at most one conditional branch in the
-	     atomic sequence.  If a conditional branch is found, put a
-	     breakpoint in its destination address.  */
-	  if ((insn1 & 0xf800) == 0xf000
-	      && (insn2 & 0xd000) == 0x8000
-	      && (insn1 & 0x0380) != 0x0380)
-	    {
-	      int sign, j1, j2, imm1, imm2;
-	      unsigned int offset;
-
-	      sign = sbits (insn1, 10, 10);
-	      imm1 = bits (insn1, 0, 5);
-	      imm2 = bits (insn2, 0, 10);
-	      j1 = bit (insn2, 13);
-	      j2 = bit (insn2, 11);
-
-	      offset = (sign << 20) + (j2 << 19) + (j1 << 18);
-	      offset += (imm1 << 12) + (imm2 << 1);
-
-	      if (last_breakpoint > 0)
-		return 0; /* More than one conditional branch found,
-			     fallback to the standard code.  */
-
-	      breaks[1] = loc + offset;
-	      last_breakpoint++;
-	    }
-
-	  /* We do not support atomic sequences that use any *other*
-	     instructions but conditional branches to change the PC.
-	     Fall back to standard code to avoid losing control of
-	     execution.  */
-	  else if (thumb2_instruction_changes_pc (insn1, insn2))
-	    return 0;
-
-	  /* If we find a strex{,b,h,d}, we're done.  */
-	  if ((insn1 & 0xfff0) == 0xe840
-	      || ((insn1 & 0xfff0) == 0xe8c0 && (insn2 & 0x00c0) == 0x0040))
-	    break;
-	}
-    }
-
-  /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence.  */
-  if (insn_count == atomic_sequence_length)
-    return 0;
-
-  /* Insert a breakpoint right after the end of the atomic sequence.  */
-  breaks[0] = loc;
-
-  /* Check for duplicated breakpoints.  Check also for a breakpoint
-     placed (branch instruction's destination) anywhere in sequence.  */
-  if (last_breakpoint
-      && (breaks[1] == breaks[0]
-	  || (breaks[1] >= pc && breaks[1] < loc)))
-    last_breakpoint = 0;
-
-  /* Effectively inserts the breakpoints.  */
-  for (index = 0; index <= last_breakpoint; index++)
-    arm_insert_single_step_breakpoint (gdbarch, aspace,
-				       MAKE_THUMB_ADDR (breaks[index]));
-
-  return 1;
-}
-
-static int
-arm_deal_with_atomic_sequence_raw (struct frame_info *frame)
-{
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  struct address_space *aspace = get_frame_address_space (frame);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  CORE_ADDR pc = get_frame_pc (frame);
-  CORE_ADDR breaks[2] = {-1, -1};
-  CORE_ADDR loc = pc;
-  unsigned int insn;
-  int insn_count;
-  int index;
-  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
-  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
-
-  /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.
-     Note that we do not currently support conditionally executed atomic
-     instructions.  */
-  insn = read_memory_unsigned_integer (loc, 4, byte_order_for_code);
-  loc += 4;
-  if ((insn & 0xff9000f0) != 0xe1900090)
-    return 0;
-
-  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
-     instructions.  */
-  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
-    {
-      insn = read_memory_unsigned_integer (loc, 4, byte_order_for_code);
-      loc += 4;
-
-      /* Assume that there is at most one conditional branch in the atomic
-         sequence.  If a conditional branch is found, put a breakpoint in
-         its destination address.  */
-      if (bits (insn, 24, 27) == 0xa)
-	{
-          if (last_breakpoint > 0)
-            return 0; /* More than one conditional branch found, fallback
-                         to the standard single-step code.  */
-
-	  breaks[1] = BranchDest (loc - 4, insn);
-	  last_breakpoint++;
-        }
-
-      /* We do not support atomic sequences that use any *other* instructions
-         but conditional branches to change the PC.  Fall back to standard
-	 code to avoid losing control of execution.  */
-      else if (arm_instruction_changes_pc (insn))
-	return 0;
-
-      /* If we find a strex{,b,h,d}, we're done.  */
-      if ((insn & 0xff9000f0) == 0xe1800090)
-	break;
-    }
-
-  /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence.  */
-  if (insn_count == atomic_sequence_length)
-    return 0;
-
-  /* Insert a breakpoint right after the end of the atomic sequence.  */
-  breaks[0] = loc;
-
-  /* Check for duplicated breakpoints.  Check also for a breakpoint
-     placed (branch instruction's destination) anywhere in sequence.  */
-  if (last_breakpoint
-      && (breaks[1] == breaks[0]
-	  || (breaks[1] >= pc && breaks[1] < loc)))
-    last_breakpoint = 0;
-
-  /* Effectively inserts the breakpoints.  */
-  for (index = 0; index <= last_breakpoint; index++)
-    arm_insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
-
-  return 1;
-}
-
-int
-arm_deal_with_atomic_sequence (struct frame_info *frame)
-{
-  if (arm_frame_is_thumb (frame))
-    return thumb_deal_with_atomic_sequence_raw (frame);
-  else
-    return arm_deal_with_atomic_sequence_raw (frame);
-}
-
-/* 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
-   and breakpoint it.  */
-
-int
-arm_software_single_step (struct frame_info *frame)
-{
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  struct address_space *aspace = get_frame_address_space (frame);
-  CORE_ADDR next_pc;
-
-  if (arm_deal_with_atomic_sequence (frame))
-    return 1;
-
-  next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
-  arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
-
-  return 1;
-}
-
-/* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand
-   the buffer to be NEW_LEN bytes ending at ENDADDR.  Return
-   NULL if an error occurs.  BUF is freed.  */
-
-static gdb_byte *
-extend_buffer_earlier (gdb_byte *buf, CORE_ADDR endaddr,
-		       int old_len, int new_len)
-{
-  gdb_byte *new_buf;
-  int bytes_to_read = new_len - old_len;
-
-  new_buf = (gdb_byte *) xmalloc (new_len);
-  memcpy (new_buf + bytes_to_read, buf, old_len);
-  xfree (buf);
-  if (target_read_memory (endaddr - new_len, new_buf, bytes_to_read) != 0)
-    {
-      xfree (new_buf);
-      return NULL;
-    }
-  return new_buf;
-}
-
-/* An IT block is at most the 2-byte IT instruction followed by
-   four 4-byte instructions.  The furthest back we must search to
-   find an IT block that affects the current instruction is thus
-   2 + 3 * 4 == 14 bytes.  */
-#define MAX_IT_BLOCK_PREFIX 14
-
-/* Use a quick scan if there are more than this many bytes of
-   code.  */
-#define IT_SCAN_THRESHOLD 32
-
-/* Adjust a breakpoint's address to move breakpoints out of IT blocks.
-   A breakpoint in an IT block may not be hit, depending on the
-   condition flags.  */
-static CORE_ADDR
-arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
-{
-  gdb_byte *buf;
-  char map_type;
-  CORE_ADDR boundary, func_start;
-  int buf_len;
-  enum bfd_endian order = gdbarch_byte_order_for_code (gdbarch);
-  int i, any, last_it, last_it_count;
-
-  /* If we are using BKPT breakpoints, none of this is necessary.  */
-  if (gdbarch_tdep (gdbarch)->thumb2_breakpoint == NULL)
-    return bpaddr;
-
-  /* ARM mode does not have this problem.  */
-  if (!arm_pc_is_thumb (gdbarch, bpaddr))
-    return bpaddr;
-
-  /* We are setting a breakpoint in Thumb code that could potentially
-     contain an IT block.  The first step is to find how much Thumb
-     code there is; we do not need to read outside of known Thumb
-     sequences.  */
-  map_type = arm_find_mapping_symbol (bpaddr, &boundary);
-  if (map_type == 0)
-    /* Thumb-2 code must have mapping symbols to have a chance.  */
-    return bpaddr;
-
-  bpaddr = gdbarch_addr_bits_remove (gdbarch, bpaddr);
-
-  if (find_pc_partial_function (bpaddr, NULL, &func_start, NULL)
-      && func_start > boundary)
-    boundary = func_start;
-
-  /* Search for a candidate IT instruction.  We have to do some fancy
-     footwork to distinguish a real IT instruction from the second
-     half of a 32-bit instruction, but there is no need for that if
-     there's no candidate.  */
-  buf_len = min (bpaddr - boundary, MAX_IT_BLOCK_PREFIX);
-  if (buf_len == 0)
-    /* No room for an IT instruction.  */
-    return bpaddr;
-
-  buf = (gdb_byte *) xmalloc (buf_len);
-  if (target_read_memory (bpaddr - buf_len, buf, buf_len) != 0)
-    return bpaddr;
-  any = 0;
-  for (i = 0; i < buf_len; i += 2)
-    {
-      unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
-      if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
-	{
-	  any = 1;
-	  break;
-	}
-    }
-  if (any == 0)
-    {
-      xfree (buf);
-      return bpaddr;
-    }
-
-  /* OK, the code bytes before this instruction contain at least one
-     halfword which resembles an IT instruction.  We know that it's
-     Thumb code, but there are still two possibilities.  Either the
-     halfword really is an IT instruction, or it is the second half of
-     a 32-bit Thumb instruction.  The only way we can tell is to
-     scan forwards from a known instruction boundary.  */
-  if (bpaddr - boundary > IT_SCAN_THRESHOLD)
-    {
-      int definite;
+      int definite;
 
       /* There's a lot of code before this instruction.  Start with an
 	 optimistic search; it's easy to recognize halfwords that can
@@ -7291,6 +6106,116 @@  thumb2_copy_block_xfer (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
   return 0;
 }
 
+/* Initialize arm_gdb_get_next_pcs_stor.  */
+void
+arm_gdb_get_next_pcs_ctor (struct arm_gdb_get_next_pcs *self,
+			   struct arm_get_next_pcs_ops *ops,
+			   int byte_order,
+			   int byte_order_for_code,
+			   int is_thumb,
+			   int arm_apcs_32,
+			   const gdb_byte *arm_thumb2_breakpoint,
+			   struct frame_info *frame,
+			   struct gdbarch *gdbarch)
+{
+  arm_get_next_pcs_ctor ((struct arm_get_next_pcs *) self,
+			 ops,
+			 byte_order,
+			 byte_order_for_code,
+			 is_thumb,
+			 arm_apcs_32,
+			 arm_thumb2_breakpoint);
+
+  self->frame = frame;
+  self->gdbarch = gdbarch;
+}
+
+/* Wrapper over read_memory_unsigned_integer for use in arm_get_next_pcs.
+ This is used to avoid a dependency on BFD's bfd_endian enum.  */
+
+ULONGEST
+arm_get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, int len,
+					       int byte_order)
+{
+  return read_memory_unsigned_integer (memaddr, len, byte_order);
+}
+
+/* Wrapper over gdbarch_addr_bits_remove for use in arm_get_next_pcs.  */
+
+CORE_ADDR
+arm_get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *arm_next_pcs,
+				   CORE_ADDR val)
+{
+  struct arm_gdb_get_next_pcs *next_pcs
+    = (struct arm_gdb_get_next_pcs *) arm_next_pcs;
+
+  return gdbarch_addr_bits_remove (next_pcs->gdbarch, val);
+}
+
+/* Wrapper over gdbarch_addr_bits_remove for use in arm_get_next_pcs.  */
+
+ULONGEST
+arm_get_next_pcs_collect_register_unsigned (struct arm_get_next_pcs *self,
+					    int n)
+{
+  struct arm_gdb_get_next_pcs *next_pcs = (struct arm_gdb_get_next_pcs *) self;
+
+  return get_frame_register_unsigned (next_pcs->frame, n);
+}
+
+/* Wrapper over syscall_next_pc for use in get_next_pcs.  */
+
+CORE_ADDR
+arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc)
+{
+  struct arm_gdb_get_next_pcs *next_pcs = (struct arm_gdb_get_next_pcs *) self;
+  struct gdbarch_tdep *tdep;
+
+  tdep = gdbarch_tdep (next_pcs->gdbarch);
+  if (tdep->syscall_next_pc != NULL)
+    return tdep->syscall_next_pc (next_pcs->frame);
+
+  return 0;
+}
+
+/* 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 instructions
+   and breakpoint them.  */
+
+int
+arm_software_single_step (struct frame_info *frame)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct address_space *aspace = get_frame_address_space (frame);
+  struct arm_gdb_get_next_pcs next_pcs_ctx;
+  CORE_ADDR pc;
+  int i;
+  VEC (CORE_ADDR) *next_pcs = NULL;
+
+  arm_gdb_get_next_pcs_ctor (&next_pcs_ctx,
+			     &arm_get_next_pcs_ops,
+			     gdbarch_byte_order (gdbarch),
+			     gdbarch_byte_order_for_code (gdbarch),
+			     arm_frame_is_thumb (frame),
+			     arm_apcs_32,
+			     gdbarch_tdep (gdbarch)->thumb2_breakpoint,
+			     frame,
+			     gdbarch);
+
+  next_pcs = arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs,
+			       get_frame_pc (frame));
+
+  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
+    {
+      arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
+    }
+
+  VEC_free (CORE_ADDR, next_pcs);
+
+  return 1;
+}
+
 /* Cleanup/copy SVC (SWI) instructions.  These two functions are overridden
    for Linux, where some SVC instructions must be treated specially.  */
 
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 9b8447b..f3a13a4 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -23,6 +23,9 @@ 
 struct gdbarch;
 struct regset;
 struct address_space;
+struct get_next_pcs;
+struct arm_get_next_pcs;
+struct gdb_get_next_pcs;
 
 #include "arch/arm.h"
 
@@ -221,6 +224,17 @@  struct displaced_step_closure
 		   struct displaced_step_closure *);
 };
 
+/* Context for a get_next_pcs call on ARM in GDB.  */
+struct arm_gdb_get_next_pcs
+{
+  /* Common context for gdb/gdbserver.  */
+  struct arm_get_next_pcs base;
+  /* Frame information.  */
+  struct frame_info *frame;
+  /* Architecture dependent information.  */
+  struct gdbarch *gdbarch;
+};
+
 /* Values for the WRITE_PC argument to displaced_write_reg.  If the register
    write may write to the PC, specifies the way the CPSR T bit, etc. is
    modified by the instruction.  */
@@ -250,11 +264,37 @@  extern void
 		       ULONGEST val, enum pc_write_style write_pc);
 
 CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
-CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);
+
+ULONGEST arm_get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr,
+							int len,
+							int byte_order);
+
+void arm_gdb_get_next_pcs_ctor (struct arm_gdb_get_next_pcs *self,
+				struct arm_get_next_pcs_ops *ops,
+				int byte_order,
+				int byte_order_for_code,
+				int is_thumb,
+				int arm_apcs_32,
+				const gdb_byte *arm_thumb2_breakpoint,
+				struct frame_info *frame,
+				struct gdbarch *gdbarch);
+
+CORE_ADDR
+arm_get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self,
+				   CORE_ADDR val);
+
+ULONGEST
+arm_get_next_pcs_collect_register_unsigned (struct arm_get_next_pcs *self,
+					    int n);
+
+CORE_ADDR
+arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc);
+
+int arm_software_single_step (struct frame_info *frame);
+
 void arm_insert_single_step_breakpoint (struct gdbarch *,
 					struct address_space *, CORE_ADDR);
-int arm_deal_with_atomic_sequence (struct frame_info *);
-int arm_software_single_step (struct frame_info *);
+
 int arm_frame_is_thumb (struct frame_info *frame);
 
 extern struct displaced_step_closure *
diff --git a/gdb/arm-wince-tdep.c b/gdb/arm-wince-tdep.c
index 3abd89d..d3add93 100644
--- a/gdb/arm-wince-tdep.c
+++ b/gdb/arm-wince-tdep.c
@@ -25,6 +25,7 @@ 
 #include "frame.h"
 
 #include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "windows-tdep.h"
 
diff --git a/gdb/armbsd-tdep.c b/gdb/armbsd-tdep.c
index 1b9bad7..b19048e 100644
--- a/gdb/armbsd-tdep.c
+++ b/gdb/armbsd-tdep.c
@@ -22,6 +22,7 @@ 
 #include "regcache.h"
 #include "regset.h"
 
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 
 /* Core file support.  */
diff --git a/gdb/armnbsd-tdep.c b/gdb/armnbsd-tdep.c
index 14eceaa..c67b226 100644
--- a/gdb/armnbsd-tdep.c
+++ b/gdb/armnbsd-tdep.c
@@ -21,6 +21,7 @@ 
 #include "osabi.h"
 
 #include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "solib-svr4.h"
 
diff --git a/gdb/armobsd-tdep.c b/gdb/armobsd-tdep.c
index 58bcc5d..883c63f 100644
--- a/gdb/armobsd-tdep.c
+++ b/gdb/armobsd-tdep.c
@@ -23,6 +23,7 @@ 
 #include "tramp-frame.h"
 
 #include "obsd-tdep.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "solib-svr4.h"
 
diff --git a/gdb/common/gdb_vecs.h b/gdb/common/gdb_vecs.h
index b3f56f8..a08d416 100644
--- a/gdb/common/gdb_vecs.h
+++ b/gdb/common/gdb_vecs.h
@@ -31,6 +31,8 @@  DEF_VEC_P (const_char_ptr);
 
 DEF_VEC_I (int);
 
+DEF_VEC_I (CORE_ADDR);
+
 extern void free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec);
 
 extern struct cleanup *
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index dfbb4d1..eb56e7e 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -44,7 +44,7 @@  aarch64*-*-elf)
 aarch64*-*-linux*)
 	# Target: AArch64 linux
 	gdb_target_obs="aarch64-tdep.o aarch64-linux-tdep.o aarch64-insn.o \
-			arm.o arm-tdep.o arm-linux-tdep.o \
+			arm.o arm-get-next-pcs.o arm-tdep.o arm-linux-tdep.o \
 			glibc-tdep.o linux-tdep.o solib-svr4.o \
 			symfile-mem.o linux-record.o"
 	build_gdbserver=yes
@@ -84,31 +84,34 @@  am33_2.0*-*-linux*)
 
 arm*-wince-pe | arm*-*-mingw32ce*)
 	# Target: ARM based machine running Windows CE (win32)
-	gdb_target_obs="arm.o arm-tdep.o arm-wince-tdep.o windows-tdep.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o arm-wince-tdep.o \
+			windows-tdep.o"
 	build_gdbserver=yes
 	;;
 arm*-*-linux*)
 	# Target: ARM based machine running GNU/Linux
-	gdb_target_obs="arm.o arm-tdep.o arm-linux-tdep.o glibc-tdep.o \
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o \
+                        arm-linux-tdep.o glibc-tdep.o \
 			solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o"
 	build_gdbserver=yes
 	;;
 arm*-*-netbsd* | arm*-*-knetbsd*-gnu)
 	# Target: NetBSD/arm
-	gdb_target_obs="arm.o arm-tdep.o armnbsd-tdep.o solib-svr4.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o armnbsd-tdep.o \
+			solib-svr4.o"
 	;;
 arm*-*-openbsd*)
 	# Target: OpenBSD/arm
-	gdb_target_obs="arm.o arm-tdep.o armbsd-tdep.o armobsd-tdep.o \
-			obsd-tdep.o solib-svr4.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o armbsd-tdep.o \
+			armobsd-tdep.o obsd-tdep.o solib-svr4.o"
 	;;
 arm*-*-symbianelf*)
 	# Target: SymbianOS/arm
-	gdb_target_obs="arm.o arm-tdep.o arm-symbian-tdep.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o arm-symbian-tdep.o"
 	;;
 arm*-*-*)
 	# Target: ARM embedded system
-	gdb_target_obs="arm.o arm-tdep.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o"
 	gdb_sim=../sim/arm/libsim.a
 	;;
 
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index f18243b..22034fe 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -181,7 +181,7 @@  SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/common-exceptions.c $(srcdir)/symbol.c \
 	$(srcdir)/common/btrace-common.c \
 	$(srcdir)/common/fileio.c $(srcdir)/nat/linux-namespaces.c \
-	$(srcdir)/arch/arm.c
+	$(srcdir)/arch/arm.c $(srcdir)/arch/arm-get-next-pcs.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -589,6 +589,9 @@  fileio.o: ../common/fileio.c
 arm.o: ../arch/arm.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+arm-get-next-pcs.o: ../arch/arm-get-next-pcs.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 
 # Native object files rules from ../nat
 
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index e854110..838dedd 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -71,6 +71,7 @@  case "${target}" in
 			srv_tgtobj="$srv_linux_obj linux-arm-low.o"
 			srv_tgtobj="$srv_tgtobj linux-aarch32-low.o"
 			srv_tgtobj="${srv_tgtobj} arm.o"
+			srv_tgtobj="${srv_tgtobj} arm-get-next-pcs.o"
 			srv_xmlfiles="arm-with-iwmmxt.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml"
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 78a4c8f..bb2a1b8 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -31,6 +31,7 @@ 
 #include <signal.h>
 
 #include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 
 /* Defined in auto-generated files.  */
 void init_registers_arm (void);
@@ -126,6 +127,15 @@  struct arch_lwp_info
   CORE_ADDR stopped_data_address;
 };
 
+/* Context for a get_next_pcs call on ARM in GDBServer.  */
+struct arm_gdbserver_get_next_pcs
+{
+  /* Common context for gdb/gdbserver.  */
+  struct arm_get_next_pcs base;
+  /* The cache for registry values.  */
+  struct regcache *regcache;
+};
+
 /* These are in <asm/elf.h> in current kernels.  */
 #define HWCAP_VFP       64
 #define HWCAP_IWMMXT    512
@@ -146,6 +156,29 @@  static int arm_regmap[] = {
   64
 };
 
+/* Forward declarations needed for get_next_pcs ops.  */
+static ULONGEST
+get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr,
+					   int len,
+					   int byte_order);
+
+static ULONGEST
+get_next_pcs_collect_register_unsigned (struct arm_get_next_pcs *self, int n);
+
+static CORE_ADDR
+get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, CORE_ADDR val);
+
+static CORE_ADDR
+get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc);
+
+/* get_next_pcs operations.  */
+static struct arm_get_next_pcs_ops get_next_pcs_ops = {
+  get_next_pcs_read_memory_unsigned_integer,
+  get_next_pcs_collect_register_unsigned,
+  get_next_pcs_syscall_next_pc,
+  get_next_pcs_addr_bits_remove
+};
+
 static int
 arm_cannot_store_register (int regno)
 {
@@ -208,6 +241,13 @@  arm_fill_vfpregset (struct regcache *regcache, void *buf)
   arm_fill_vfpregset_num (regcache, buf, num);
 }
 
+/* Wrapper of UNMAKE_THUMB_ADDR for get_next_pcs.  */
+static CORE_ADDR
+get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, CORE_ADDR val)
+{
+  return UNMAKE_THUMB_ADDR (val);
+}
+
 static void
 arm_store_vfpregset (struct regcache *regcache, const void *buf)
 {
@@ -317,6 +357,39 @@  arm_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Wrapper of collect_register for get_next_pcs.  */
+
+static ULONGEST
+get_next_pcs_collect_register_unsigned (struct arm_get_next_pcs *self, int n)
+{
+  struct arm_gdbserver_get_next_pcs *next_pcs
+    = (struct arm_gdbserver_get_next_pcs *) self;
+  ULONGEST res = 0;
+  int size = register_size (next_pcs->regcache->tdesc, n);
+
+  if (size > (int) sizeof (ULONGEST))
+    error (_("That operation is not available on integers of more than"
+	     "%d bytes."),
+	   (int) sizeof (ULONGEST));
+
+  collect_register (next_pcs->regcache, n, &res);
+  return res;
+}
+
+/* Read memory from the inferiror.
+   BYTE_ORDER is ignored and there to keep compatiblity with GDB's
+   read_memory_unsigned_integer. */
+static ULONGEST
+get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr,
+					   int len,
+					   int byte_order)
+{
+  ULONGEST res;
+
+  (*the_target->read_memory) (memaddr, (unsigned char *) &res, len);
+  return res;
+}
+
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -801,6 +874,52 @@  arm_prepare_to_resume (struct lwp_info *lwp)
       }
 }
 
+/* When PC is at a syscall instruction, return the PC of the next
+   instruction to be executed.  */
+static CORE_ADDR
+get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self, CORE_ADDR pc)
+{
+  CORE_ADDR return_addr = 0;
+  int is_thumb = self->is_thumb;
+  ULONGEST svc_number = 0;
+
+  if (is_thumb)
+    {
+      svc_number = self->ops->collect_register_unsigned (self, 7);
+      return_addr = pc + 2;
+    }
+  else
+    {
+      unsigned long this_instr = self->ops->read_memory_unsigned_integer
+	((CORE_ADDR) pc, 4, self->byte_order_for_code);
+
+      unsigned long svc_operand = (0x00ffffff & this_instr);
+      if (svc_operand)  /* OABI.  */
+	{
+	  svc_number = svc_operand - 0x900000;
+	}
+      else /* EABI.  */
+	{
+	  svc_number = self->ops->collect_register_unsigned (self, 7);
+	}
+
+      return_addr = pc + 4;
+    }
+
+  /* Is this a sigreturn or rt_sigreturn syscall?
+     If so it is currently not handeled.  */
+  if (svc_number == 119 || svc_number == 173)
+    {
+      if (debug_threads)
+	debug_printf ("Unhandled sigreturn or rt_sigreturn syscall\n");
+    }
+
+  /* Addresses for calling Thumb functions have the bit 0 set.  */
+  if (is_thumb)
+    return_addr = MAKE_THUMB_ADDR (return_addr);
+
+  return return_addr;
+}
 
 static int
 arm_get_hwcap (unsigned long *valp)
@@ -890,6 +1009,53 @@  arm_arch_setup (void)
     have_ptrace_getregset = 0;
 }
 
+/* Initialize arm_gdbserver_get_next_pcs.  */
+
+static void
+arm_gdbserver_get_next_pcs_ctor (struct arm_gdbserver_get_next_pcs *self,
+				 struct arm_get_next_pcs_ops *ops,
+				 int byte_order,
+				 int byte_order_for_code,
+				 int is_thumb,
+				 int arm_apcs_32,
+				 const gdb_byte *arm_thumb2_breakpoint,
+				 struct regcache *regcache)
+{
+  arm_get_next_pcs_ctor ((struct arm_get_next_pcs *) self,
+			 ops,
+			 byte_order,
+			 byte_order_for_code,
+			 is_thumb,
+			 arm_apcs_32,
+			 arm_thumb2_breakpoint);
+
+  self->regcache = regcache;
+}
+
+/* Fetch the next possible PCs after the current instruction executes.  */
+
+static VEC (CORE_ADDR) *
+arm_gdbserver_get_next_pcs (CORE_ADDR pc, struct regcache *regcache)
+{
+  struct arm_gdbserver_get_next_pcs next_pcs_ctx;
+  VEC (CORE_ADDR) *next_pcs = NULL;
+
+  arm_gdbserver_get_next_pcs_ctor (&next_pcs_ctx,
+				   &get_next_pcs_ops,
+				   /* Byte order is ignored assumed as host.  */
+				   0,
+				   0,
+				   arm_is_thumb_mode (),
+				   /* 32-bit apcs supported only.  */
+				   1,
+				   (const gdb_byte *) &thumb2_breakpoint,
+				   regcache);
+
+  next_pcs = arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs_ctx, pc);
+
+  return next_pcs;
+}
+
 /* Support for hardware single step.  */
 
 static int
@@ -1032,7 +1198,7 @@  struct linux_target_ops the_low_target = {
   arm_set_pc,
   arm_breakpoint_kind_from_pc,
   arm_sw_breakpoint_from_kind,
-  NULL, /* get_next_pcs */
+  arm_gdbserver_get_next_pcs,
   0,
   arm_breakpoint_at,
   arm_supports_z_point_type,
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index ee8d88f..d36acfe 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -124,8 +124,6 @@  struct process_info_private
 
 struct lwp_info;
 
-DEF_VEC_I (CORE_ADDR);
-
 struct linux_target_ops
 {
   /* Architecture-specific setup.  */
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 96ad4fa..9a4189f 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -123,6 +123,7 @@  extern void discard_queued_stop_replies (ptid_t ptid);
 
 #include "utils.h"
 #include "debug.h"
+#include "gdb_vecs.h"
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 37c8c93..b522726 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1613,8 +1613,6 @@  void iterate_over_symtabs (const char *name,
 					    void *data),
 			   void *data);
 
-DEF_VEC_I (CORE_ADDR);
-
 VEC (CORE_ADDR) *find_pcs_for_symtab_line (struct symtab *symtab, int line,
 					   struct linetable_entry **best_entry);