aboutsummaryrefslogtreecommitdiff
path: root/gdb/breakpoint.c
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@codesourcery.com>2014-10-03 12:44:58 +0100
committerMaciej W. Rozycki <macro@codesourcery.com>2014-10-03 12:54:34 +0100
commit0d5ed1535229b7069757e04766f70a02fa60821c (patch)
tree8532eb4eaa97b8570e60bfd2170fd32ec7d5b757 /gdb/breakpoint.c
parent3e87153251d9a117182decbe57dd7d9d2a47c2b3 (diff)
downloadgdb-0d5ed1535229b7069757e04766f70a02fa60821c.zip
gdb-0d5ed1535229b7069757e04766f70a02fa60821c.tar.gz
gdb-0d5ed1535229b7069757e04766f70a02fa60821c.tar.bz2
Avoid software breakpoint's instruction shadow inconsistency
This change: commit b775012e845380ed4c7421a1b87caf7bfae39f5f Author: Luis Machado <luisgpm@br.ibm.com> Date: Fri Feb 24 15:10:59 2012 +0000 2012-02-24 Luis Machado <lgustavo@codesourcery.com> * remote.c (remote_supports_cond_breakpoints): New forward declaration. [...] changed the way breakpoints are inserted and removed such that `insert_bp_location' can now be called with the breakpoint being handled already in place, while previously the call was only ever made for breakpoints that have not been put in place. This in turn caused an issue for software breakpoints and targets for which a breakpoint's `placed_address' may not be the same as the original requested address. The issue is `insert_bp_location' overwrites the previously adjusted value in `placed_address' with the original address, that is only replaced back with the correct adjusted address later on when `gdbarch_breakpoint_from_pc' is called. Meanwhile there's a window where the value in `placed_address' does not correspond to data stored in `shadow_contents', leading to incorrect instruction bytes being supplied when `one_breakpoint_xfer_memory' is called to supply the instruction overlaid by the breakpoint. And this is exactly what happens on the MIPS target with software breakpoints placed in microMIPS code. In this case not only `placed_address' is not the original address because of the ISA bit, but `mips_breakpoint_from_pc' has to read the original instruction to determine which one of the two software breakpoint instruction encodings to choose as well. The 16-bit encoding is used to replace 16-bit instructions and similarly the 32-bit one is used with 32-bit instructions, to satisfy branch delay slot size requirements. The mismatch between `placed_address' and the address data in `shadow_contents' has been obtained from leads to the wrong encoding being used in some cases, which in the case of a 32-bit software breakpoint instruction replacing a 16-bit instruction causes corruption to the adjacent following instruction and leads the debug session astray if execution reaches there e.g. with a jump. To address this problem I made the change below, that adds a `reqstd_address' field to `struct bp_target_info' and leaves `placed_address' unchanged once it has been set. This ensures data in `shadow_contents' is always consistent with `placed_address'. This approach also has this good side effect that all the places that examine the breakpoint's address see a consistent value, either `reqstd_address' or `placed_address', as required. Currently some places see either the original or the adjusted address in `placed_address', depending on whether they have been called before `gdbarch_remote_breakpoint_from_pc' or afterwards. This is in particular true for subsequent calls to `gdbarch_remote_breakpoint_from_pc' itself, e.g. from `one_breakpoint_xfer_memory'. This is also important for places like `find_single_step_breakpoint' where a breakpoint's address is compared to the raw value of $pc. * breakpoint.h (bp_target_info): Add `reqstd_address' member, update comments. * breakpoint.c (one_breakpoint_xfer_memory): Use `reqstd_address' for the breakpoint's address. Don't preinitialize `placed_size'. (insert_bp_location): Set `reqstd_address' rather than `placed_address'. (bp_target_info_copy_insertion_state): Also copy `placed_address'. (bkpt_insert_location): Use `reqstd_address' for the breakpoint's address. (bkpt_remove_location): Likewise. (deprecated_insert_raw_breakpoint): Likewise. (deprecated_remove_raw_breakpoint): Likewise. (find_single_step_breakpoint): Likewise. * mem-break.c (default_memory_insert_breakpoint): Use `reqstd_address' for the breakpoint's address. Don't set `placed_address' or `placed_size' if breakpoint contents couldn't have been determined. * remote.c (remote_insert_breakpoint): Use `reqstd_address' for the breakpoint's address. (remote_insert_hw_breakpoint): Likewise. Don't set `placed_address' or `placed_size' if breakpoint couldn't have been set. * aarch64-linux-nat.c (aarch64_linux_insert_hw_breakpoint): Use `reqstd_address' for the breakpoint's address. * arm-linux-nat.c (arm_linux_hw_breakpoint_initialize): Likewise. * ia64-tdep.c (ia64_memory_insert_breakpoint): Likewise. * m32r-tdep.c (m32r_memory_insert_breakpoint): Likewise. * microblaze-linux-tdep.c (microblaze_linux_memory_remove_breakpoint): Likewise. * monitor.c (monitor_insert_breakpoint): Likewise. * nto-procfs.c (procfs_insert_breakpoint): Likewise. (procfs_insert_hw_breakpoint): Likewise. * ppc-linux-nat.c (ppc_linux_insert_hw_breakpoint): Likewise. * ppc-linux-tdep.c (ppc_linux_memory_remove_breakpoint): Likewise. * remote-m32r-sdi.c (m32r_insert_breakpoint): Likewise. * remote-mips.c (mips_insert_breakpoint): Likewise. * x86-nat.c (x86_insert_hw_breakpoint): Likewise.
Diffstat (limited to 'gdb/breakpoint.c')
-rw-r--r--gdb/breakpoint.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 7da88b0..e2170b4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1544,8 +1544,8 @@ one_breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
else
{
const unsigned char *bp;
- CORE_ADDR placed_address = target_info->placed_address;
- int placed_size = target_info->placed_size;
+ CORE_ADDR addr = target_info->reqstd_address;
+ int placed_size;
/* Update the shadow with what we want to write to memory. */
memcpy (target_info->shadow_contents + bptoffset,
@@ -1553,7 +1553,7 @@ one_breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
/* Determine appropriate breakpoint contents and size for this
address. */
- bp = gdbarch_breakpoint_from_pc (gdbarch, &placed_address, &placed_size);
+ bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &placed_size);
/* Update the final write buffer with this inserted
breakpoint's INSN. */
@@ -2601,7 +2601,7 @@ 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.placed_address = bl->address;
+ bl->target_info.reqstd_address = bl->address;
bl->target_info.placed_address_space = bl->pspace->aspace;
bl->target_info.length = bl->length;
@@ -2642,7 +2642,7 @@ insert_bp_location (struct bp_location *bl,
program, but it's not going to work anyway with current
gdb. */
struct mem_region *mr
- = lookup_mem_region (bl->target_info.placed_address);
+ = lookup_mem_region (bl->target_info.reqstd_address);
if (mr)
{
@@ -2722,7 +2722,7 @@ insert_bp_location (struct bp_location *bl,
bl->section);
/* Set a software (trap) breakpoint at the LMA. */
bl->overlay_target_info = bl->target_info;
- bl->overlay_target_info.placed_address = addr;
+ bl->overlay_target_info.reqstd_address = addr;
/* No overlay handling: just set the breakpoint. */
TRY_CATCH (e, RETURN_MASK_ALL)
@@ -13301,6 +13301,7 @@ bp_target_info_copy_insertion_state (struct bp_target_info *dest,
{
dest->shadow_len = src->shadow_len;
memcpy (dest->shadow_contents, src->shadow_contents, src->shadow_len);
+ dest->placed_address = src->placed_address;
dest->placed_size = src->placed_size;
}
@@ -13319,7 +13320,7 @@ bkpt_insert_location (struct bp_location *bl)
/* There is no need to insert a breakpoint if an unconditional
raw/sss breakpoint is already inserted at that location. */
sss_slot = find_single_step_breakpoint (bp_tgt->placed_address_space,
- bp_tgt->placed_address);
+ bp_tgt->reqstd_address);
if (sss_slot >= 0)
{
struct bp_target_info *sss_bp_tgt = single_step_breakpoints[sss_slot];
@@ -13341,7 +13342,7 @@ bkpt_remove_location (struct bp_location *bl)
{
struct bp_target_info *bp_tgt = &bl->target_info;
struct address_space *aspace = bp_tgt->placed_address_space;
- CORE_ADDR address = bp_tgt->placed_address;
+ CORE_ADDR address = bp_tgt->reqstd_address;
/* Only remove the breakpoint if there is no raw/sss breakpoint
still inserted at this location. Otherwise, we would be
@@ -15364,7 +15365,7 @@ deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch,
bp_tgt = XCNEW (struct bp_target_info);
bp_tgt->placed_address_space = aspace;
- bp_tgt->placed_address = pc;
+ bp_tgt->reqstd_address = pc;
/* If an unconditional non-raw breakpoint is already inserted at
that location, there's no need to insert another. However, with
@@ -15401,7 +15402,7 @@ deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp)
{
struct bp_target_info *bp_tgt = bp;
struct address_space *aspace = bp_tgt->placed_address_space;
- CORE_ADDR address = bp_tgt->placed_address;
+ CORE_ADDR address = bp_tgt->reqstd_address;
struct bp_location *bl;
int ret;
@@ -15543,7 +15544,7 @@ find_single_step_breakpoint (struct address_space *aspace,
struct bp_target_info *bp_tgt = single_step_breakpoints[i];
if (bp_tgt
&& breakpoint_address_match (bp_tgt->placed_address_space,
- bp_tgt->placed_address,
+ bp_tgt->reqstd_address,
aspace, pc))
return i;
}