Commit df3e0d1c authored by bibo,mao's avatar bibo,mao Committed by Tony Luck

[IA64] kprobe clears qp bits for special instructions

On IA64 there exists some special instructions which
always need to be executed regradless of qp bits, such
as com.crel.unc, tbit.trel.unc etc.
This patch clears qp bits when inserting kprobe trap code
and disables probepoint on slot 1 for these special
instructions.
Signed-off-by: default avatarbibo,mao <bibo.mao@intel.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 08ed38b6
...@@ -128,10 +128,46 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, ...@@ -128,10 +128,46 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
return; return;
} }
/*
* In this function we check to see if the instruction
* (qp) cmpx.crel.ctype p1,p2=r2,r3
* on which we are inserting kprobe is cmp instruction
* with ctype as unc.
*/
static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot,
uint major_opcode,
unsigned long kprobe_inst)
{
cmp_inst_t cmp_inst;
uint ctype_unc = 0;
if (!((bundle_encoding[template][slot] == I) ||
(bundle_encoding[template][slot] == M)))
goto out;
if (!((major_opcode == 0xC) || (major_opcode == 0xD) ||
(major_opcode == 0xE)))
goto out;
cmp_inst.l = kprobe_inst;
if ((cmp_inst.f.x2 == 0) || (cmp_inst.f.x2 == 1)) {
/* Integere compare - Register Register (A6 type)*/
if ((cmp_inst.f.tb == 0) && (cmp_inst.f.ta == 0)
&&(cmp_inst.f.c == 1))
ctype_unc = 1;
} else if ((cmp_inst.f.x2 == 2)||(cmp_inst.f.x2 == 3)) {
/* Integere compare - Immediate Register (A8 type)*/
if ((cmp_inst.f.ta == 0) &&(cmp_inst.f.c == 1))
ctype_unc = 1;
}
out:
return ctype_unc;
}
/* /*
* In this function we check to see if the instruction * In this function we check to see if the instruction
* on which we are inserting kprobe is supported. * on which we are inserting kprobe is supported.
* Returns 0 if supported * Returns qp value if supported
* Returns -EINVAL if unsupported * Returns -EINVAL if unsupported
*/ */
static int __kprobes unsupported_inst(uint template, uint slot, static int __kprobes unsupported_inst(uint template, uint slot,
...@@ -139,9 +175,21 @@ static int __kprobes unsupported_inst(uint template, uint slot, ...@@ -139,9 +175,21 @@ static int __kprobes unsupported_inst(uint template, uint slot,
unsigned long kprobe_inst, unsigned long kprobe_inst,
unsigned long addr) unsigned long addr)
{ {
if (bundle_encoding[template][slot] == I) { int qp;
switch (major_opcode) {
case 0x0: //I_UNIT_MISC_OPCODE: qp = kprobe_inst & 0x3f;
if (is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) {
if (slot == 1 && qp) {
printk(KERN_WARNING "Kprobes on cmp unc"
"instruction on slot 1 at <0x%lx>"
"is not supported\n", addr);
return -EINVAL;
}
qp = 0;
}
else if (bundle_encoding[template][slot] == I) {
if (major_opcode == 0) {
/* /*
* Check for Integer speculation instruction * Check for Integer speculation instruction
* - Bit 33-35 to be equal to 0x1 * - Bit 33-35 to be equal to 0x1
...@@ -152,7 +200,6 @@ static int __kprobes unsupported_inst(uint template, uint slot, ...@@ -152,7 +200,6 @@ static int __kprobes unsupported_inst(uint template, uint slot,
addr); addr);
return -EINVAL; return -EINVAL;
} }
/* /*
* IP relative mov instruction * IP relative mov instruction
* - Bit 27-35 to be equal to 0x30 * - Bit 27-35 to be equal to 0x30
...@@ -165,45 +212,69 @@ static int __kprobes unsupported_inst(uint template, uint slot, ...@@ -165,45 +212,69 @@ static int __kprobes unsupported_inst(uint template, uint slot,
} }
} }
else if ((major_opcode == 5) && !(kprobe_inst & (0xFUl << 33)) &&
(kprobe_inst & (0x1UL << 12))) {
/* test bit instructions, tbit,tnat,tf
* bit 33-36 to be equal to 0
* bit 12 to be equal to 1
*/
if (slot == 1 && qp) {
printk(KERN_WARNING "Kprobes on test bit"
"instruction on slot at <0x%lx>"
"is not supported\n", addr);
return -EINVAL;
} }
return 0; qp = 0;
} }
}
else if (bundle_encoding[template][slot] == B) {
/* if (major_opcode == 7) {
* In this function we check to see if the instruction /* IP-Relative Predict major code is 7 */
* (qp) cmpx.crel.ctype p1,p2=r2,r3 printk(KERN_WARNING "Kprobes on IP-Relative"
* on which we are inserting kprobe is cmp instruction "Predict is not supported\n");
* with ctype as unc. return -EINVAL;
}
else if (major_opcode == 2) {
/* Indirect Predict, major code is 2
* bit 27-32 to be equal to 10 or 11
*/ */
static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot, int x6=(kprobe_inst >> 27) & 0x3F;
uint major_opcode, if ((x6 == 0x10) || (x6 == 0x11)) {
unsigned long kprobe_inst) printk(KERN_WARNING "Kprobes on"
{ "Indirect Predict is not supported\n");
cmp_inst_t cmp_inst; return -EINVAL;
uint ctype_unc = 0; }
}
if (!((bundle_encoding[template][slot] == I) || }
(bundle_encoding[template][slot] == M))) /* kernel does not use float instruction, here for safety kprobe
goto out; * will judge whether it is fcmp/flass/float approximation instruction
*/
if (!((major_opcode == 0xC) || (major_opcode == 0xD) || else if (unlikely(bundle_encoding[template][slot] == F)) {
(major_opcode == 0xE))) if ((major_opcode == 4 || major_opcode == 5) &&
goto out; (kprobe_inst & (0x1 << 12))) {
/* fcmp/fclass unc instruction */
if (slot == 1 && qp) {
printk(KERN_WARNING "Kprobes on fcmp/fclass "
"instruction on slot at <0x%lx> "
"is not supported\n", addr);
return -EINVAL;
cmp_inst.l = kprobe_inst;
if ((cmp_inst.f.x2 == 0) || (cmp_inst.f.x2 == 1)) {
/* Integere compare - Register Register (A6 type)*/
if ((cmp_inst.f.tb == 0) && (cmp_inst.f.ta == 0)
&&(cmp_inst.f.c == 1))
ctype_unc = 1;
} else if ((cmp_inst.f.x2 == 2)||(cmp_inst.f.x2 == 3)) {
/* Integere compare - Immediate Register (A8 type)*/
if ((cmp_inst.f.ta == 0) &&(cmp_inst.f.c == 1))
ctype_unc = 1;
} }
out: qp = 0;
return ctype_unc; }
if ((major_opcode == 0 || major_opcode == 1) &&
(kprobe_inst & (0x1UL << 33))) {
/* float Approximation instruction */
if (slot == 1 && qp) {
printk(KERN_WARNING "Kprobes on float Approx "
"instr at <0x%lx> is not supported\n",
addr);
return -EINVAL;
}
qp = 0;
}
}
return qp;
} }
/* /*
...@@ -213,20 +284,17 @@ static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot, ...@@ -213,20 +284,17 @@ static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot,
static void __kprobes prepare_break_inst(uint template, uint slot, static void __kprobes prepare_break_inst(uint template, uint slot,
uint major_opcode, uint major_opcode,
unsigned long kprobe_inst, unsigned long kprobe_inst,
struct kprobe *p) struct kprobe *p,
int qp)
{ {
unsigned long break_inst = BREAK_INST; unsigned long break_inst = BREAK_INST;
bundle_t *bundle = &p->opcode.bundle; bundle_t *bundle = &p->opcode.bundle;
/* /*
* Copy the original kprobe_inst qualifying predicate(qp) * Copy the original kprobe_inst qualifying predicate(qp)
* to the break instruction iff !is_cmp_ctype_unc_inst * to the break instruction
* because for cmp instruction with ctype equal to unc,
* which is a special instruction always needs to be
* executed regradless of qp
*/ */
if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) break_inst |= qp;
break_inst |= (0x3f & kprobe_inst);
switch (slot) { switch (slot) {
case 0: case 0:
...@@ -422,6 +490,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -422,6 +490,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
unsigned long kprobe_inst=0; unsigned long kprobe_inst=0;
unsigned int slot = addr & 0xf, template, major_opcode = 0; unsigned int slot = addr & 0xf, template, major_opcode = 0;
bundle_t *bundle; bundle_t *bundle;
int qp;
bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle;
template = bundle->quad0.template; template = bundle->quad0.template;
...@@ -436,17 +505,17 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -436,17 +505,17 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
/* Get kprobe_inst and major_opcode from the bundle */ /* Get kprobe_inst and major_opcode from the bundle */
get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr)) qp = unsupported_inst(template, slot, major_opcode, kprobe_inst, addr);
if (qp < 0)
return -EINVAL; return -EINVAL;
p->ainsn.insn = get_insn_slot(); p->ainsn.insn = get_insn_slot();
if (!p->ainsn.insn) if (!p->ainsn.insn)
return -ENOMEM; return -ENOMEM;
memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t));
memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t));
prepare_break_inst(template, slot, major_opcode, kprobe_inst, p); prepare_break_inst(template, slot, major_opcode, kprobe_inst, p, qp);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment