summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/ia64/kernel/kprobes.c43
-rw-r--r--include/asm-ia64/kprobes.h17
2 files changed, 58 insertions, 2 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 5d5344681555..51bc08bd0466 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -120,6 +120,41 @@ static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode
}
/*
+ * 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 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 override the bundle with
* the break instruction at the given slot.
*/
@@ -131,9 +166,13 @@ static void prepare_break_inst(uint template, uint slot, uint major_opcode,
/*
* Copy the original kprobe_inst qualifying predicate(qp)
- * to the break instruction
+ * to the break instruction iff !is_cmp_ctype_unc_inst
+ * because for cmp instruction with ctype equal to unc,
+ * which is a special instruction always needs to be
+ * executed regradless of qp
*/
- break_inst |= (0x3f & kprobe_inst);
+ if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst))
+ break_inst |= (0x3f & kprobe_inst);
switch (slot) {
case 0:
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index cec4d9958307..7b700035e36d 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -30,6 +30,23 @@
#define BREAK_INST (long)(__IA64_BREAK_KPROBE << 6)
+typedef union cmp_inst {
+ struct {
+ unsigned long long qp : 6;
+ unsigned long long p1 : 6;
+ unsigned long long c : 1;
+ unsigned long long r2 : 7;
+ unsigned long long r3 : 7;
+ unsigned long long p2 : 6;
+ unsigned long long ta : 1;
+ unsigned long long x2 : 2;
+ unsigned long long tb : 1;
+ unsigned long long opcode : 4;
+ unsigned long long reserved : 23;
+ }f;
+ unsigned long long l;
+} cmp_inst_t;
+
struct kprobe;
typedef struct _bundle {