diff options
author | marcel <marcel@FreeBSD.org> | 2005-06-27 23:51:38 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2005-06-27 23:51:38 +0000 |
commit | b3e8712f74c37e27ed01c96a59f0f2d5929de749 (patch) | |
tree | a481a8bb2d80a92735e0f5f1d085789a325d2d20 /sys/ia64 | |
parent | d34460ded950b94a296cb35469967768067ff7de (diff) | |
download | FreeBSD-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.c | 51 |
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) { |