From: "Maciej W. Rozycki" <macro@mips.com>
To: gdb-patches@sourceware.org
Cc: Chris Dearman <chris@mips.com>,
"Maciej W. Rozycki" <macro@linux-mips.org>
Subject: mips-tdep.c: Adjust breakpoints in branch delay slots
Date: Thu, 24 May 2007 18:08:00 -0000 [thread overview]
Message-ID: <Pine.LNX.4.61.0705241853450.21951@perivale.mips.com> (raw)
Hello,
This is a change that makes breakpoints requested in a branch or jump
delay slot be moved to the preceding instruction. This removes a
confusion that arises when such a breakpoint is hit and the resulting
message like this:
(gdb) break *0x00400670
Breakpoint 1 at 0x400670: file foo.c, line 12.
(gdb) run
Starting program: .../foo
Program received signal SIGTRAP, Trace/breakpoint trap.
main (argc=1, argv=0x7fd7c874) at foo.c:12
12 }
(gdb) x /2i $pc
0x40066c <main+12>: jr ra
0x400670 <main+16>: move v0,zero
This change has been tested natively for mips-unknown-linux-gnu and
remotely for mipsisa32-sde-elf, using mips-sim-sde32/-EB,
mips-sim-sde32/-mips16/-EB, mips-sim-sde32/-EL and
mips-sim-sde32/-mips16/-EL as the targets, with no regressions.
2007-05-24 Chris Dearman <chris@mips.com>
Maciej W. Rozycki <macro@mips.com>
* mips-tdep.c (mips32_instruction_has_delay_slot): New function.
(mips16_instruction_has_delay_slot): Likewise.
(mips_segment_boundary): Likewise.
(mips_adjust_breakpoint_address): Likewise.
(mips_gdbarch_init): Use mips_adjust_breakpoint_address.
OK to apply?
Maciej
12271-4
Index: binutils-quilt/src/gdb/mips-tdep.c
===================================================================
--- binutils-quilt.orig/src/gdb/mips-tdep.c 2007-05-23 17:50:36.000000000 +0100
+++ binutils-quilt/src/gdb/mips-tdep.c 2007-05-24 17:58:17.000000000 +0100
@@ -4817,6 +4817,186 @@
}
}
+/* Return non-zero if the ADDR instruction has a branch delay slot
+ (i.e. it is a jump or branch instruction). This function was based
+ on mips32_next_pc(). */
+
+static int
+mips32_instruction_has_delay_slot (CORE_ADDR addr)
+{
+ gdb_byte buf[MIPS_INSN32_SIZE];
+ int status;
+
+ status = read_memory_nobpt (addr, buf, MIPS_INSN32_SIZE);
+ return !status && mips32_next_pc (addr) != addr + 4;
+}
+
+static int
+mips16_instruction_has_delay_slot (CORE_ADDR addr, int mustbe32)
+{
+ gdb_byte buf[MIPS_INSN16_SIZE];
+ unsigned short inst;
+ int status;
+
+ status = read_memory_nobpt (addr, buf, MIPS_INSN16_SIZE);
+ if (status)
+ return 0;
+
+ inst = mips_fetch_instruction (addr);
+ if (!mustbe32)
+ return (inst & 0xf89f) == 0xe800; /* jr/jalr (16-bit instruction) */
+ return (inst & 0xf800) == 0x1800; /* jal/jalx (32-bit instruction) */
+}
+
+static CORE_ADDR
+mips_segment_boundary (CORE_ADDR bpaddr)
+{
+#ifdef BFD64
+ switch ((int)(bpaddr >> 62) & 0x3)
+ {
+ case 0x3: /* xkseg */
+ if (bpaddr == (bfd_signed_vma)(int)bpaddr)
+ return bpaddr & ~0x1fffffffLL; /* 32-bit compatibility segment */
+ break;
+ case 0x2: /* xkphys */
+ return bpaddr & 0xf800000000000000LL;
+ case 0x1: /* xksseg */
+ case 0x0: /* xkuseg/kuseg */
+ break;
+ }
+ return bpaddr & 0xc000000000000000LL;
+#else
+ if (bpaddr & (CORE_ADDR)0x80000000) /* kernel segment */
+ return bpaddr & ~(CORE_ADDR)0x1fffffff;
+ return 0x0000000; /* user segment */
+#endif
+}
+
+static CORE_ADDR
+mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
+{
+ CORE_ADDR prev_addr, next_addr;
+ CORE_ADDR boundary;
+
+ /* If a breakpoint is set on the instruction in a branch delay slot,
+ GDB gets confused. When the breakpoint is hit, the PC isn't on
+ the instruction in the branch delay slot, the PC will point to
+ the branch instruction. Since the PC doesn't match any known
+ breakpoints, GDB reports a trap exception.
+
+ There are two possible fixes for this problem.
+
+ 1) When the breakpoint gets hit, see if the BD bit is set in the
+ Cause register (which indicates the last exception occurred in a
+ branch delay slot). If the BD bit is set, fix the PC to point to
+ the instruction in the branch delay slot.
+
+ 2) When the user sets the breakpoint, don't allow him to set the
+ breakpoint on the instruction in the branch delay slot. Instead
+ move the breakpoint to the branch instruction (which will have
+ the same result).
+
+ The problem with the first solution is that if the user then
+ single-steps the processor, the branch instruction will get
+ skipped (since GDB thinks the PC is on the instruction in the
+ branch delay slot).
+
+ So, we'll use the second solution. To do this we need to know if
+ the instruction we're trying to set the breakpoint on is in the
+ branch delay slot. */
+
+ boundary = mips_segment_boundary (bpaddr);
+
+ if (!is_mips16_addr (bpaddr))
+ {
+ if (bpaddr == boundary)
+ return bpaddr;
+ /* If the previous instruction has a branch delay slot, we have
+ to move the breakpoint to the branch instruction. */
+ prev_addr = bpaddr - 4;
+ if (mips32_instruction_has_delay_slot (prev_addr))
+ {
+ bpaddr = prev_addr;
+ }
+ }
+ else
+ {
+ struct minimal_symbol *sym;
+ CORE_ADDR addr, jmpaddr;
+ int i;
+
+ /* The only MIPS16 instructions with delay slots are jal, jalr
+ and jr. An absolute jal is always 4 bytes long, so try for
+ that first, then try the 2 byte jalr/jal.
+ XXX We have to assume that bpaddr is not the second half of
+ an extended instruction. */
+
+ /* Make sure we don't scan back before the beginning of the
+ current function, since we may fetch constant data or MIPS32
+ insns that looks like a MIPS16 jump. Of course we might do
+ that anyway if the compiler has moved constants inline. :-( */
+ if (find_pc_partial_function (bpaddr, NULL, &addr, NULL)
+ && addr > boundary && addr < bpaddr)
+ boundary = addr & ~1;
+
+ jmpaddr = 0;
+ addr = bpaddr;
+ for (i = 1; i < 4; i++)
+ {
+ if ((addr & ~1) == boundary)
+ break;
+ addr -= 2;
+ if (i == 1 && mips16_instruction_has_delay_slot (addr, 0))
+ {
+ /* Looks like a jr/jalr at [target-1], but it could be
+ the second word of a previous jal, so record it and
+ check back one more. */
+ jmpaddr = addr;
+ }
+ else if (i > 1 && mips16_instruction_has_delay_slot (addr, 1))
+ {
+ if (i == 2)
+ /* Looks like a jal at [target-2], but it could also
+ be the second word of a previous jal, record it,
+ and check back one more. */
+ jmpaddr = addr;
+ else
+ /* Looks like a jal at [target-3], so any previously
+ recorded jal or jr must be wrong, because:
+
+ >-3: jal
+ -2: jal-ext (can't be jal)
+ -1: bdslot (can't be jr)
+ 0: target insn
+
+ Of course it could be another jal-ext which looks
+ like a jal, but in that case we'd have broken out
+ of this loop at [target-2]:
+
+ -4: jal
+ >-3: jal-ext
+ -2: bdslot (can't be jmp)
+ -1: jalr/jr
+ 0: target insn */
+ jmpaddr = 0;
+ }
+ else
+ {
+ /* Not a jump instruction: if we're at [target-1] this
+ could be the second word of a jal, so continue;
+ otherwise we're done. */
+ if (i > 1)
+ break;
+ }
+ }
+
+ if (jmpaddr)
+ bpaddr = jmpaddr;
+ }
+
+ return bpaddr;
+}
+
/* If PC is in a mips16 call or return stub, return the address of the target
PC, which is either the callee or the caller. There are several
cases which must be handled:
@@ -5514,6 +5694,8 @@
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, mips_breakpoint_from_pc);
+ set_gdbarch_adjust_breakpoint_address (gdbarch,
+ mips_adjust_breakpoint_address);
set_gdbarch_skip_prologue (gdbarch, mips_skip_prologue);
next reply other threads:[~2007-05-24 18:08 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-24 18:08 Maciej W. Rozycki [this message]
2007-05-24 18:21 ` Mark Kettenis
2007-05-24 18:31 ` Daniel Jacobowitz
[not found] ` <Pine.LNX.4.61.0705251217190.13913@perivale.mips.com>
2007-05-25 12:50 ` Maciej W. Rozycki
2007-05-25 13:16 ` Maciej W. Rozycki
[not found] ` <Pine.LNX.4.61.0705251318500.13913@perivale.mips.com>
2007-05-25 13:19 ` Daniel Jacobowitz
2007-06-15 14:38 ` Maciej W. Rozycki
2007-05-25 13:21 ` Maciej W. Rozycki
2007-05-25 13:26 ` Daniel Jacobowitz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Pine.LNX.4.61.0705241853450.21951@perivale.mips.com \
--to=macro@mips.com \
--cc=chris@mips.com \
--cc=gdb-patches@sourceware.org \
--cc=macro@linux-mips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox