summaryrefslogtreecommitdiffstats
path: root/sys/ia64
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2005-06-27 23:51:38 +0000
committermarcel <marcel@FreeBSD.org>2005-06-27 23:51:38 +0000
commitb3e8712f74c37e27ed01c96a59f0f2d5929de749 (patch)
treea481a8bb2d80a92735e0f5f1d085789a325d2d20 /sys/ia64
parentd34460ded950b94a296cb35469967768067ff7de (diff)
downloadFreeBSD-src-b3e8712f74c37e27ed01c96a59f0f2d5929de749.zip
FreeBSD-src-b3e8712f74c37e27ed01c96a59f0f2d5929de749.tar.gz
Handle B-unit break instructions. The break.b is unique in that the
immediate is not saved by the architecture. Any of the break.{mifx} instructions have their immediate saved in cr.iim on interruption. Consequently, when we handle the break interrupt, we end up with a break value of 0 when it was a break.b. The immediate is important because it distinguishes between different uses of the break and which are defined by the runtime specification. The bottomline is that when the GNU debugger replaces a B-unit instruction with a break instruction in the inferior, we would not send the process a SIGTRAP when we encounter it, because the value is not one we recognize as a debugger breakpoint. This change adds logic to decode the bundle in which the break instruction lives whenever the break value is 0. The assumption being that it's a break.b and we fetch the immediate directly out of the instruction. If the break instruction was not a break.b, but any of break.{mifx} with an immediate of 0, we would be doing unnecessary work. But since a break 0 is invalid, this is not a problem and it will still result in a SIGILL being sent to the process. Approved by: re (scottl)
Diffstat (limited to 'sys/ia64')
-rw-r--r--sys/ia64/ia64/trap.c51
1 files changed, 50 insertions, 1 deletions
diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c
index b8ff02f..86dc147 100644
--- a/sys/ia64/ia64/trap.c
+++ b/sys/ia64/ia64/trap.c
@@ -72,6 +72,8 @@ __FBSDID("$FreeBSD$");
#include <sys/ktrace.h>
#endif
+#include <ia64/disasm/disasm.h>
+
static int print_usertrap = 0;
SYSCTL_INT(_machdep, OID_AUTO, print_usertrap,
CTLFLAG_RW, &print_usertrap, 0, "");
@@ -281,6 +283,39 @@ printtrap(int vector, struct trapframe *tf, int isfatal, int user)
printf("\n");
}
+/*
+ * We got a trap caused by a break instruction and the immediate was 0.
+ * This indicates that we may have a break.b with some non-zero immediate.
+ * The break.b doesn't cause the immediate to be put in cr.iim. Hence,
+ * we need to disassemble the bundle and return the immediate found there.
+ * This may be a 0 value anyway. Return 0 for any error condition. This
+ * will result in a SIGILL, which is pretty much the best thing to do.
+ */
+static uint64_t
+trap_decode_break(struct trapframe *tf)
+{
+ struct asm_bundle bundle;
+ struct asm_inst *inst;
+ int slot;
+
+ if (!asm_decode(tf->tf_special.iip, &bundle))
+ return (0);
+
+ slot = ((tf->tf_special.psr & IA64_PSR_RI) == IA64_PSR_RI_0) ? 0 :
+ ((tf->tf_special.psr & IA64_PSR_RI) == IA64_PSR_RI_1) ? 1 : 2;
+ inst = bundle.b_inst + slot;
+
+ /*
+ * Sanity checking: It must be a break instruction and the operand
+ * that has the break value must be an immediate.
+ */
+ if (inst->i_op != ASM_OP_BREAK ||
+ inst->i_oper[1].o_type != ASM_OPER_IMM)
+ return (0);
+
+ return (inst->i_oper[1].o_value);
+}
+
void
trap_panic(int vector, struct trapframe *tf)
{
@@ -414,8 +449,22 @@ trap(int vector, struct trapframe *tf)
case IA64_VEC_BREAK:
if (user) {
- /* XXX we don't decode break.b */
ucode = (int)tf->tf_special.ifa & 0x1FFFFF;
+ if (ucode == 0) {
+ /*
+ * A break.b doesn't cause the immediate to be
+ * stored in cr.iim (and saved in the TF in
+ * tf_special.ifa). We need to decode the
+ * instruction to find out what the immediate
+ * was. Note that if the break instruction
+ * didn't happen to be a break.b, but any
+ * other break with an immediate of 0, we
+ * will do unnecessary work to get the value
+ * we already had. Not an issue, because a
+ * break 0 is invalid.
+ */
+ ucode = trap_decode_break(tf);
+ }
if (ucode < 0x80000) {
/* Software interrupts. */
switch (ucode) {
OpenPOWER on IntegriCloud