diff options
author | Andrew Burgess <andrew.burgess@embecosm.com> | 2019-07-19 10:34:47 +0100 |
---|---|---|
committer | Andrew Burgess <andrew.burgess@embecosm.com> | 2019-07-19 21:00:22 +0100 |
commit | 01e175fe1b21950982642713513e442fc09614e6 (patch) | |
tree | 54950bd2fdf5fd046b12759f160160702cb22048 /gdb/riscv-tdep.c | |
parent | ec38ac465d632cbc7fbecffcaadb7c6ffc4b5f39 (diff) | |
download | gdb-01e175fe1b21950982642713513e442fc09614e6.zip gdb-01e175fe1b21950982642713513e442fc09614e6.tar.gz gdb-01e175fe1b21950982642713513e442fc09614e6.tar.bz2 |
gdb/riscv: Write 4-byte nop to dummy code region before inferior calls
When making inferior function calls GDB sets up a dummy code region on
the stack, and places a breakpoint within that region. If the random
stack contents appear to be a compressed instruction then GDB will
place a compressed breakpoint, which can cause problems if the target
doesn't support compressed instructions.
This commit prevents this issue by writing a 4-byte nop instruction to
the dummy region at the time the region is allocated. With this nop
instruction in place, when we come to insert the breakpoint then an
uncompressed breakpoint will be used.
This is similar to other targets, for example mips.
gdb/ChangeLog:
* riscv-tdep.c (riscv_push_dummy_code): Write a 4-byte nop
instruction to the dummy code region.
gdb/testsuite/ChangeLog:
* gdb.arch/riscv-bp-infcall.c: New file.
* gdb.arch/riscv-bp-infcall.exp: New file.
Diffstat (limited to 'gdb/riscv-tdep.c')
-rw-r--r-- | gdb/riscv-tdep.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 7f3a1f6..e4a66f1 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -1621,11 +1621,44 @@ riscv_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr, struct regcache *regcache) { + /* A nop instruction is 'add x0, x0, 0'. */ + static const gdb_byte nop_insn[] = { 0x13, 0x00, 0x00, 0x00 }; + /* Allocate space for a breakpoint, and keep the stack correctly - aligned. */ + aligned. The space allocated here must be at least big enough to + accommodate the NOP_INSN defined above. */ sp -= 16; *bp_addr = sp; *real_pc = funaddr; + + /* When we insert a breakpoint we select whether to use a compressed + breakpoint or not based on the existing contents of the memory. + + If the breakpoint is being placed onto the stack as part of setting up + for an inferior call from GDB, then the existing stack contents may + randomly appear to be a compressed instruction, causing GDB to insert + a compressed breakpoint. If this happens on a target that does not + support compressed instructions then this could cause problems. + + To prevent this issue we write an uncompressed nop onto the stack at + the location where the breakpoint will be inserted. In this way we + ensure that we always use an uncompressed breakpoint, which should + work on all targets. + + We call TARGET_WRITE_MEMORY here so that if the write fails we don't + throw an exception. Instead we ignore the error and move on. The + assumption is that either GDB will error later when actually trying to + insert a software breakpoint, or GDB will use hardware breakpoints and + there will be no need to write to memory later. */ + int status = target_write_memory (*bp_addr, nop_insn, sizeof (nop_insn)); + + if (riscv_debug_breakpoints || riscv_debug_infcall) + fprintf_unfiltered (gdb_stdlog, + "Writing %lld-byte nop instruction to %s: %s\n", + ((unsigned long long) sizeof (nop_insn)), + paddress (gdbarch, *bp_addr), + (status == 0 ? "success" : "failed")); + return sp; } |