[1/2] gdbarch software_single_step returns VEC (CORE_ADDR) *

Message ID 86egasrr2a.fsf@gmail.com
State New, archived
Headers

Commit Message

Yao Qi March 30, 2016, 2:14 p.m. UTC
  Pedro Alves <palves@redhat.com> writes:

> I think the problem is the ambiguity in arm_breakpoint_from_pc,
> and to the fact that we don't "normalize" breakpoint addresses
> before passing them down to target_insert_breakpoint. 

We don't pass address to target_insert_breakpoint, instead, we pass
bp_target_info.  If we do what you suggested, we need to set
"normalized" address into bl->target_info.reqstd_address.  This is the
only way to pass normalized address down to target_insert_breakpoint.
This means we propagate the ISA specific bits of address to breakpoint
system, I don't see anything harmful so far, but I feel risky to do so.

>
> Some callers start with an address coming from the user and want
> to consult symbol tables / mapping symbols.  Other caller really
> want to trust the thumb bit as set in the address.

Right.  If we want to fully trust on the bit of address, in some cases,
we need to consult symbols to normalize the address.  The question is
"in what cases do we do so?".  In my experimental patch, address is
normalized for breakpoints except single step breakpoint.

>
> Note that arm_breakpoint_from_pc uses arm_pc_is_thumb, which is
> what consults symbol tables / mapping symbols.
>
> I think the fix would to make arm_breakpoint_from_pc always trust
> that the address bit is already encoded correctly, and trust
> IS_THUMB_ADDR, similarly to how the gdbserver version does, in
> arm_breakpoint_kind_from_pc.

If so, we need to normalize addresses before calling
gdbarch_breakpoint_from_pc.  Moreover, we need to normalize address
before calling insert_single_step_breakpoint out side of
gdbarch_software_single_step.

>
> Then, we'd still need to consult the mapping symbols
> consultation, or IOW, do something based on arm_pc_is_thumb _before_
> target_insert_breakpoint is reached.  That is, call something like
> arm_pc_is_thumb and use the result to encode the thumb bit correctly in
> the address passed to target_insert_breakpoint.  IOW, "normalize" the
> target address, using some gdbarch method, _before_ that address is passed
> to the target routines in the first place.
>
> Along the way, several other functions would stop using arm_pc_is_thumb,
> but use IS_THUMB_ADDR directly.  E.g., arm_remote_breakpoint_from_pc.
>
> WDYT?
>

I wrote a patch as you suggested, and attach it below.  I am not very
happy on this one, but I am open to thoughts from you and others.

>
>> -# A return value of 1 means that the software_single_step breakpoints
>> -# were inserted; 0 means they were not.
>> -F:int:software_single_step:struct frame_info *frame:frame
>> +# Return a vector of addresses on which the software single step
>> +# breakpoints are inserted.  NULL means software single step is not used.
>
> s/are inserted/should be inserted/
>

I'll fix it.

>> +F:VEC (CORE_ADDR) *:software_single_step:struct frame_info *frame:frame
>> +
>> +m:void:insert_single_step_breakpoint:struct address_space *aspace, CORE_ADDR pc:aspace, pc::insert_single_step_breakpoint::0
>>   
>>   # Return non-zero if the processor is executing a delay slot and a
>>   # further single-step is needed before the instruction finishes.
>> diff --git a/gdb/infrun.c b/gdb/infrun.c
>> index 696105d..5dbcf7a 100644
>> --- a/gdb/infrun.c
>> +++ b/gdb/infrun.c
>> @@ -2248,11 +2248,28 @@ maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc)
>>     int hw_step = 1;
>>   
>>     if (execution_direction == EXEC_FORWARD
>> -      && gdbarch_software_single_step_p (gdbarch)
>> -      && gdbarch_software_single_step (gdbarch, get_current_frame ()))
>> +      && gdbarch_software_single_step_p (gdbarch))
>>       {
>> -      hw_step = 0;
>> +      struct frame_info *frame = get_current_frame ();
>> +      VEC (CORE_ADDR) * next_pcs;
>> +
>> +      next_pcs = gdbarch_software_single_step (gdbarch, frame);
>> +
>> +      if (next_pcs != NULL)
>> +	{
>> +	  int i;
>> +	  CORE_ADDR pc;
>> +	  struct address_space *aspace = get_frame_address_space (frame);
>> +
>> +	  hw_step = 0;
>> +
>> +	  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
>> +	    gdbarch_insert_single_step_breakpoint (gdbarch, aspace, pc);
>> +
>> +	  VEC_free (CORE_ADDR, next_pcs);
>> +	}
>
> This pattern of starting from a VEC of addresses, and a frame and
> calling gdbarch_insert_single_step_breakpoint on each address
> appears multiple times.  Can we put it in a convenience function?

Sure, I'll do.

>
> Though the other calls in record-full.c didn't go through
> gdbarch_insert_single_step_breakpoint -- why's that?

Oh, gdbarch_insert_single_step_breakpoint should be called.  I'll fix it.
  

Comments

Pedro Alves April 27, 2016, 3:19 p.m. UTC | #1
On 03/30/2016 03:14 PM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> I think the problem is the ambiguity in arm_breakpoint_from_pc,
>> and to the fact that we don't "normalize" breakpoint addresses
>> before passing them down to target_insert_breakpoint. 
> 
> We don't pass address to target_insert_breakpoint, instead, we pass
> bp_target_info. 

Yeah, well, we pass the address _in_ a bp_target_info, but we
pass the address.

> If we do what you suggested, we need to set
> "normalized" address into bl->target_info.reqstd_address.  This is the
> only way to pass normalized address down to target_insert_breakpoint.

Right.

> This means we propagate the ISA specific bits of address to breakpoint
> system, I don't see anything harmful so far, but I feel risky to do so.
> 
>>
>> Some callers start with an address coming from the user and want
>> to consult symbol tables / mapping symbols.  Other caller really
>> want to trust the thumb bit as set in the address.
> 
> Right.  If we want to fully trust on the bit of address, in some cases,
> we need to consult symbols to normalize the address.

Yeah.

> The question is
> "in what cases do we do so?".  In my experimental patch, address is
> normalized for breakpoints except single step breakpoint.
> 
>>
>> Note that arm_breakpoint_from_pc uses arm_pc_is_thumb, which is
>> what consults symbol tables / mapping symbols.
>>
>> I think the fix would to make arm_breakpoint_from_pc always trust
>> that the address bit is already encoded correctly, and trust
>> IS_THUMB_ADDR, similarly to how the gdbserver version does, in
>> arm_breakpoint_kind_from_pc.
> 
> If so, we need to normalize addresses before calling
> gdbarch_breakpoint_from_pc.  Moreover, we need to normalize address
> before calling insert_single_step_breakpoint out side of
> gdbarch_software_single_step.
> 
>>
>> Then, we'd still need to consult the mapping symbols
>> consultation, or IOW, do something based on arm_pc_is_thumb _before_
>> target_insert_breakpoint is reached.  That is, call something like
>> arm_pc_is_thumb and use the result to encode the thumb bit correctly in
>> the address passed to target_insert_breakpoint.  IOW, "normalize" the
>> target address, using some gdbarch method, _before_ that address is passed
>> to the target routines in the first place.
>>
>> Along the way, several other functions would stop using arm_pc_is_thumb,
>> but use IS_THUMB_ADDR directly.  E.g., arm_remote_breakpoint_from_pc.
>>
>> WDYT?

Another similar/related idea would be to go the gdbserver direction of
storing the breakpoint's "len/kind" in the breakpoint location, as a separate
field, instead of encoding it in the address:

  /* Return the breakpoint kind for this target based on PC.  The PCPTR is
     adjusted to the real memory location in case a flag (e.g., the Thumb bit on
     ARM) was present in the PC.  */
  int (*breakpoint_kind_from_pc) (CORE_ADDR *pcptr);

  /* Return the software breakpoint from KIND.  KIND can have target
     specific meaning like the Z0 kind parameter.
     SIZE is set to the software breakpoint's length in memory.  */
  const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size);


struct bp_target_info already has the "placed_size" field,
maybe we could reuse it, just like we started from the "len"
field on gdbserver, in 271652949894 (Support breakpoint kinds for 
software breakpoints in GDBServer).

In effect, this would move the gdbarch_remote_breakpoint_from_pc
calls to common code, just like it happened in gdbserver.

So when setting a single-step breakpoint, we'd get the "kind"
from the current mode, and when setting breakpoints from
user-input, we'd get it from the symbols tables / mapping symbols.

This would probably be the cleanest, and would expose the most
sharing opportunities with gdbserver.

I think it'd avoid the encoding <-> decoding juggling to get
at the "kind" that we see in your patch.

> @@ -809,6 +810,7 @@ void
>  default_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
>  				   int *kindptr)
>  {
> +  *pcptr = gdbarch_addr_bits_encode  (gdbarch, *pcptr);
>    gdbarch_breakpoint_from_pc (gdbarch, pcptr, kindptr);
>  }

Would we need this one?  This is called from remote.c:remote_insert_breakpoint,
which already has the addr bit encoded in the PC.

Thanks,
Pedro Alves
  
Yao Qi April 29, 2016, 2:48 p.m. UTC | #2
Pedro Alves <palves@redhat.com> writes:

> Another similar/related idea would be to go the gdbserver direction of
> storing the breakpoint's "len/kind" in the breakpoint location, as a separate
> field, instead of encoding it in the address:
>
>   /* Return the breakpoint kind for this target based on PC.  The PCPTR is
>      adjusted to the real memory location in case a flag (e.g., the Thumb bit on
>      ARM) was present in the PC.  */
>   int (*breakpoint_kind_from_pc) (CORE_ADDR *pcptr);
>
>   /* Return the software breakpoint from KIND.  KIND can have target
>      specific meaning like the Z0 kind parameter.
>      SIZE is set to the software breakpoint's length in memory.  */
>   const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size);
>
>
> struct bp_target_info already has the "placed_size" field,
> maybe we could reuse it, just like we started from the "len"
> field on gdbserver, in 271652949894 (Support breakpoint kinds for 
> software breakpoints in GDBServer).

Yeah, I can give a try.

>
> In effect, this would move the gdbarch_remote_breakpoint_from_pc
> calls to common code, just like it happened in gdbserver.
>

gdbarch_remote_breakpoint_from_pc will be no longer needed, because
we've got "kind" field.  We can use it when sending Z packet.

> So when setting a single-step breakpoint, we'd get the "kind"
> from the current mode, and when setting breakpoints from
> user-input, we'd get it from the symbols tables / mapping symbols.

This means we need this to get the "kind" from the current mode,

  /* Return the breakpoint kind for this target based on the current
     processor state (e.g. the current instruction mode on ARM) and the
     PC.  The PCPTR is adjusted to the real memory location in case a flag
     (e.g., the Thumb bit on ARM) is present in the PC.  */
  int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr);

and also need to pass breakpoint location to to_insert_breakpoint to get
the type of breakpoint we are inserting, right?
  
Pedro Alves May 2, 2016, 10:21 a.m. UTC | #3
On 04/29/2016 03:48 PM, Yao Qi wrote:
> 
>> > So when setting a single-step breakpoint, we'd get the "kind"
>> > from the current mode, and when setting breakpoints from
>> > user-input, we'd get it from the symbols tables / mapping symbols.
> This means we need this to get the "kind" from the current mode,
> 
>   /* Return the breakpoint kind for this target based on the current
>      processor state (e.g. the current instruction mode on ARM) and the
>      PC.  The PCPTR is adjusted to the real memory location in case a flag
>      (e.g., the Thumb bit on ARM) is present in the PC.  */
>   int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr);

Hmm, not sure, maybe.  From the perspective of syncing design with
gdbserver, it makes sense.  On gdbserver, I think that's only used for advancing
past a permanent breakpoint.  On gdb side, we use
gdbarch_skip_permanent_breakpoint, which I think no arch overrides currently,
so it always ends up in default_skip_permanent_breakpoint -> gdbarch_breakpoint_from_pc.
(Looks like we could eliminate gdbarch_skip_permanent_breakpoint.)
We could also say we should keep gdb's permanent breakpoint skipping's
logic of determining which breakpoint instruction to skip in sync with
bp_loc_is_permanent -> program_breakpoint_here_p -> gdbarch_breakpoint_from_pc,
though in this case looking at the current mode doesn't make sense.

> 
> and also need to pass breakpoint location to to_insert_breakpoint to get
> the type of breakpoint we are inserting, right?

I was thinking we'd have all we need in bp_target_info->placed_size,
but of course I may be missing something.

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index c3d7802..bd185da 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -85,6 +85,7 @@  displaced_step_at_entry_point (struct gdbarch *gdbarch)
   /* Inferior calls also use the entry point as a breakpoint location.
      We don't want displaced stepping to interfere with those
      breakpoints, so leave space.  */
+  addr = gdbarch_addr_bits_encode (gdbarch, addr);
   gdbarch_breakpoint_from_pc (gdbarch, &addr, &bp_len);
   addr += bp_len * 2;
 
@@ -809,6 +810,7 @@  void
 default_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
 				   int *kindptr)
 {
+  *pcptr = gdbarch_addr_bits_encode  (gdbarch, *pcptr);
   gdbarch_breakpoint_from_pc (gdbarch, pcptr, kindptr);
 }
 
@@ -853,6 +855,7 @@  default_skip_permanent_breakpoint (struct regcache *regcache)
   const gdb_byte *bp_insn;
   int bp_len;
 
+  current_pc = gdbarch_addr_bits_encode (gdbarch, current_pc);
   bp_insn = gdbarch_breakpoint_from_pc (gdbarch, &current_pc, &bp_len);
   current_pc += bp_len;
   regcache_write_pc (regcache, current_pc);
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 9b68315..89e1ec7 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -952,7 +952,7 @@  arm_linux_software_single_step (struct frame_info *frame)
   next_pcs = arm_get_next_pcs (&next_pcs_ctx);
 
   for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
-    arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
+    insert_single_step_breakpoint (gdbarch, aspace, pc);
 
   do_cleanups (old_chain);
 
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index ad69834..74a94ed 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -143,13 +143,6 @@  static const char *const arm_mode_strings[] =
 static const char *arm_fallback_mode_string = "auto";
 static const char *arm_force_mode_string = "auto";
 
-/* Internal override of the execution mode.  -1 means no override,
-   0 means override to ARM mode, 1 means override to Thumb mode.
-   The effect is the same as if arm_force_mode has been set by the
-   user (except the internal override has precedence over a user's
-   arm_force_mode override).  */
-static int arm_override_mode = -1;
-
 /* Number of different reg name sets (options).  */
 static int num_disassembly_options;
 
@@ -422,10 +415,6 @@  arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
   if (IS_THUMB_ADDR (memaddr))
     return 1;
 
-  /* Respect internal mode override if active.  */
-  if (arm_override_mode != -1)
-    return arm_override_mode;
-
   /* If the user wants to override the symbol table, let him.  */
   if (strcmp (arm_force_mode_string, "arm") == 0)
     return 0;
@@ -480,6 +469,17 @@  arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
     return (val & 0x03fffffc);
 }
 
+/* Implement the addr_bits_encode gdbarch method.  */
+
+static CORE_ADDR
+arm_addr_bits_encode (struct gdbarch *gdbarch, CORE_ADDR val)
+{
+  if (arm_pc_is_thumb (gdbarch, val))
+    return MAKE_THUMB_ADDR (val);
+  else
+    return UNMAKE_THUMB_ADDR (val);
+}
+
 /* Return 1 if PC is the start of a compiler helper function which
    can be safely ignored during prologue skipping.  IS_THUMB is true
    if the function is known to be a Thumb function due to the way it
@@ -4085,26 +4085,6 @@  convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
 			       &d, dbl);
 }
 
-/* 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);
-}
-
 /* 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.  */
@@ -6178,7 +6158,7 @@  arm_software_single_step (struct frame_info *frame)
   next_pcs = arm_get_next_pcs (&next_pcs_ctx);
 
   for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
-    arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
+    insert_single_step_breakpoint (gdbarch, aspace, pc);
 
   do_cleanups (old_chain);
 
@@ -7699,7 +7679,7 @@  arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
 
-  if (arm_pc_is_thumb (gdbarch, *pcptr))
+  if (IS_THUMB_ADDR (*pcptr))
     {
       *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
 
@@ -7734,9 +7714,11 @@  static void
 arm_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
 			       int *kindptr)
 {
+  CORE_ADDR pc = *pcptr;
+
   arm_breakpoint_from_pc (gdbarch, pcptr, kindptr);
 
-  if (arm_pc_is_thumb (gdbarch, *pcptr) && *kindptr == 4)
+  if (IS_THUMB_ADDR (pc) && *kindptr == 4)
     /* The documented magic value for a 32-bit Thumb-2 breakpoint, so
        that this is not confused with a 32-bit ARM breakpoint.  */
     *kindptr = 3;
@@ -9214,6 +9196,7 @@  arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Address manipulation.  */
   set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
+  set_gdbarch_addr_bits_encode (gdbarch, arm_addr_bits_encode);
 
   /* Advance PC across function entry code.  */
   set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index e5d13bb..2eecfed 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -259,8 +259,6 @@  CORE_ADDR arm_get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self,
 
 int arm_get_next_pcs_is_thumb (struct arm_get_next_pcs *self);
 
-void arm_insert_single_step_breakpoint (struct gdbarch *,
-					struct address_space *, CORE_ADDR);
 int arm_software_single_step (struct frame_info *);
 int arm_is_thumb (struct regcache *regcache);
 int arm_frame_is_thumb (struct frame_info *frame);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f99a7ab..6da8339 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2602,6 +2602,8 @@  build_target_command_list (struct bp_location *bl)
     bl->target_info.persist = 1;
 }
 
+static int breakpoint_address_is_meaningful (struct breakpoint *bpt);
+
 /* Insert a low-level "breakpoint" of some type.  BL is the breakpoint
    location.  Any error messages are printed to TMP_ERROR_STREAM; and
    DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
@@ -2632,7 +2634,19 @@  insert_bp_location (struct bp_location *bl,
      we have a breakpoint inserted at that address and thus
      read the breakpoint instead of returning the data saved in
      the breakpoint location's shadow contents.  */
-  bl->target_info.reqstd_address = bl->address;
+  if (bl->owner->type == bp_single_step
+      || !breakpoint_address_is_meaningful (bl->owner))
+    bl->target_info.reqstd_address = bl->address;
+  else
+    {
+      /* Encode ISA specific bits into reqstd_address for breakpoints
+	 except single step breakpoint, because the target address of
+	 single step breakpoint has already encoded with ISA specific
+	 bits.  */
+      bl->target_info.reqstd_address = gdbarch_addr_bits_encode (bl->gdbarch,
+								 bl->address);
+    }
+
   bl->target_info.placed_address_space = bl->pspace->aspace;
   bl->target_info.length = bl->length;
 
@@ -9084,7 +9098,7 @@  program_breakpoint_here_p (struct gdbarch *gdbarch, CORE_ADDR address)
   struct cleanup *cleanup;
   int retval = 0;
 
-  addr = address;
+  addr = gdbarch_addr_bits_encode (gdbarch, address);
   bpoint = gdbarch_breakpoint_from_pc (gdbarch, &addr, &len);
 
   /* Software breakpoints unsupported?  */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index bd0b48c..52aedb0 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -244,6 +244,7 @@  struct gdbarch
   int frame_red_zone_size;
   gdbarch_convert_from_func_ptr_addr_ftype *convert_from_func_ptr_addr;
   gdbarch_addr_bits_remove_ftype *addr_bits_remove;
+  gdbarch_addr_bits_encode_ftype *addr_bits_encode;
   gdbarch_software_single_step_ftype *software_single_step;
   gdbarch_single_step_through_delay_ftype *single_step_through_delay;
   gdbarch_print_insn_ftype *print_insn;
@@ -404,6 +405,7 @@  gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
   gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity;
   gdbarch->addr_bits_remove = core_addr_identity;
+  gdbarch->addr_bits_encode = core_addr_identity;
   gdbarch->skip_trampoline_code = generic_skip_trampoline_code;
   gdbarch->skip_solib_resolver = generic_skip_solib_resolver;
   gdbarch->in_solib_return_trampoline = generic_in_solib_return_trampoline;
@@ -590,6 +592,7 @@  verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of stabs_argument_has_addr, invalid_p == 0 */
   /* Skip verify of convert_from_func_ptr_addr, invalid_p == 0 */
   /* Skip verify of addr_bits_remove, invalid_p == 0 */
+  /* Skip verify of addr_bits_encode, invalid_p == 0 */
   /* Skip verify of software_single_step, has predicate.  */
   /* Skip verify of single_step_through_delay, has predicate.  */
   if (gdbarch->print_insn == 0)
@@ -708,6 +711,9 @@  gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: addr_bit = %s\n",
                       plongest (gdbarch->addr_bit));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: addr_bits_encode = <%s>\n",
+                      host_address_to_string (gdbarch->addr_bits_encode));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: addr_bits_remove = <%s>\n",
                       host_address_to_string (gdbarch->addr_bits_remove));
   fprintf_unfiltered (file,
@@ -3059,6 +3065,23 @@  set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch,
   gdbarch->addr_bits_remove = addr_bits_remove;
 }
 
+CORE_ADDR
+gdbarch_addr_bits_encode (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->addr_bits_encode != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_addr_bits_encode called\n");
+  return gdbarch->addr_bits_encode (gdbarch, addr);
+}
+
+void
+set_gdbarch_addr_bits_encode (struct gdbarch *gdbarch,
+                              gdbarch_addr_bits_encode_ftype addr_bits_encode)
+{
+  gdbarch->addr_bits_encode = addr_bits_encode;
+}
+
 int
 gdbarch_software_single_step_p (struct gdbarch *gdbarch)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 252fc4b..cba7bb0 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -642,6 +642,12 @@  typedef CORE_ADDR (gdbarch_addr_bits_remove_ftype) (struct gdbarch *gdbarch, COR
 extern CORE_ADDR gdbarch_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr);
 extern void set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch, gdbarch_addr_bits_remove_ftype *addr_bits_remove);
 
+/* Encode the ISA specific bits into address. */
+
+typedef CORE_ADDR (gdbarch_addr_bits_encode_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern CORE_ADDR gdbarch_addr_bits_encode (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_addr_bits_encode (struct gdbarch *gdbarch, gdbarch_addr_bits_encode_ftype *addr_bits_encode);
+
 /* FIXME/cagney/2001-01-18: This should be split in two.  A target method that
    indicates if the target needs software single step.  An ISA method to
    implement it.
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 37f59b7..8c937b3 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -601,6 +601,9 @@  m:CORE_ADDR:convert_from_func_ptr_addr:CORE_ADDR addr, struct target_ops *targ:a
 # possible it should be in TARGET_READ_PC instead).
 m:CORE_ADDR:addr_bits_remove:CORE_ADDR addr:addr::core_addr_identity::0
 
+# Encode the ISA specific bits into address.
+m:CORE_ADDR:addr_bits_encode:CORE_ADDR addr:addr::core_addr_identity::0
+
 # FIXME/cagney/2001-01-18: This should be split in two.  A target method that
 # indicates if the target needs software single step.  An ISA method to
 # implement it.
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 77cd931..4809457 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -897,7 +897,7 @@  call_function_by_hand_dummy (struct value *function,
 	   If software breakpoints are unsupported for this target we
 	   leave the user visible memory content uninitialized.  */
 
-	bp_addr_as_address = bp_addr;
+	bp_addr_as_address = gdbarch_addr_bits_encode (gdbarch, bp_addr);
 	bp_bytes = gdbarch_breakpoint_from_pc (gdbarch, &bp_addr_as_address,
 					       &bp_size);
 	if (bp_bytes != NULL)
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 696105d..feee63d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2525,6 +2525,7 @@  resume (enum gdb_signal sig)
 		 don't want this thread to step further from PC
 		 (overstep).  */
 	      gdb_assert (!step_over_info_valid_p ());
+	      pc = gdbarch_addr_bits_encode (gdbarch, pc);
 	      insert_single_step_breakpoint (gdbarch, aspace, pc);
 	      insert_breakpoints ();
 
@@ -7217,6 +7218,7 @@  keep_going_stepped_thread (struct thread_info *tp)
       clear_step_over_info ();
       tp->control.trap_expected = 0;
 
+      stop_pc = gdbarch_addr_bits_encode (gdbarch, stop_pc);
       insert_single_step_breakpoint (get_frame_arch (frame),
 				     get_frame_address_space (frame),
 				     stop_pc);
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index f197aa7..94faedd 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -2437,6 +2437,7 @@  linux_displaced_step_location (struct gdbarch *gdbarch)
   /* Inferior calls also use the entry point as a breakpoint location.
      We don't want displaced stepping to interfere with those
      breakpoints, so leave space.  */
+  addr = gdbarch_addr_bits_encode (gdbarch, addr);
   gdbarch_breakpoint_from_pc (gdbarch, &addr, &bp_len);
   addr += bp_len * 2;