[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: bibo,mao <bibo.mao@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>

authored by bibo,mao and committed by Tony Luck df3e0d1c 08ed38b6

+122 -53
+122 -53
arch/ia64/kernel/kprobes.c
··· 130 131 /* 132 * In this function we check to see if the instruction 133 - * on which we are inserting kprobe is supported. 134 - * Returns 0 if supported 135 - * Returns -EINVAL if unsupported 136 - */ 137 - static int __kprobes unsupported_inst(uint template, uint slot, 138 - uint major_opcode, 139 - unsigned long kprobe_inst, 140 - unsigned long addr) 141 - { 142 - if (bundle_encoding[template][slot] == I) { 143 - switch (major_opcode) { 144 - case 0x0: //I_UNIT_MISC_OPCODE: 145 - /* 146 - * Check for Integer speculation instruction 147 - * - Bit 33-35 to be equal to 0x1 148 - */ 149 - if (((kprobe_inst >> 33) & 0x7) == 1) { 150 - printk(KERN_WARNING 151 - "Kprobes on speculation inst at <0x%lx> not supported\n", 152 - addr); 153 - return -EINVAL; 154 - } 155 - 156 - /* 157 - * IP relative mov instruction 158 - * - Bit 27-35 to be equal to 0x30 159 - */ 160 - if (((kprobe_inst >> 27) & 0x1FF) == 0x30) { 161 - printk(KERN_WARNING 162 - "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n", 163 - addr); 164 - return -EINVAL; 165 - 166 - } 167 - } 168 - } 169 - return 0; 170 - } 171 - 172 - 173 - /* 174 - * In this function we check to see if the instruction 175 * (qp) cmpx.crel.ctype p1,p2=r2,r3 176 * on which we are inserting kprobe is cmp instruction 177 * with ctype as unc. ··· 165 } 166 167 /* 168 * In this function we override the bundle with 169 * the break instruction at the given slot. 170 */ 171 static void __kprobes prepare_break_inst(uint template, uint slot, 172 uint major_opcode, 173 unsigned long kprobe_inst, 174 - struct kprobe *p) 175 { 176 unsigned long break_inst = BREAK_INST; 177 bundle_t *bundle = &p->opcode.bundle; 178 179 /* 180 * Copy the original kprobe_inst qualifying predicate(qp) 181 - * to the break instruction iff !is_cmp_ctype_unc_inst 182 - * because for cmp instruction with ctype equal to unc, 183 - * which is a special instruction always needs to be 184 - * executed regradless of qp 185 */ 186 - if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) 187 - break_inst |= (0x3f & kprobe_inst); 188 189 switch (slot) { 190 case 0: ··· 490 unsigned long kprobe_inst=0; 491 unsigned int slot = addr & 0xf, template, major_opcode = 0; 492 bundle_t *bundle; 493 494 bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; 495 template = bundle->quad0.template; ··· 505 /* Get kprobe_inst and major_opcode from the bundle */ 506 get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); 507 508 - if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr)) 509 - return -EINVAL; 510 - 511 512 p->ainsn.insn = get_insn_slot(); 513 if (!p->ainsn.insn) ··· 515 memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); 516 memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); 517 518 - prepare_break_inst(template, slot, major_opcode, kprobe_inst, p); 519 520 return 0; 521 }
··· 130 131 /* 132 * In this function we check to see if the instruction 133 * (qp) cmpx.crel.ctype p1,p2=r2,r3 134 * on which we are inserting kprobe is cmp instruction 135 * with ctype as unc. ··· 207 } 208 209 /* 210 + * In this function we check to see if the instruction 211 + * on which we are inserting kprobe is supported. 212 + * Returns qp value if supported 213 + * Returns -EINVAL if unsupported 214 + */ 215 + static int __kprobes unsupported_inst(uint template, uint slot, 216 + uint major_opcode, 217 + unsigned long kprobe_inst, 218 + unsigned long addr) 219 + { 220 + int qp; 221 + 222 + qp = kprobe_inst & 0x3f; 223 + if (is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) { 224 + if (slot == 1 && qp) { 225 + printk(KERN_WARNING "Kprobes on cmp unc" 226 + "instruction on slot 1 at <0x%lx>" 227 + "is not supported\n", addr); 228 + return -EINVAL; 229 + 230 + } 231 + qp = 0; 232 + } 233 + else if (bundle_encoding[template][slot] == I) { 234 + if (major_opcode == 0) { 235 + /* 236 + * Check for Integer speculation instruction 237 + * - Bit 33-35 to be equal to 0x1 238 + */ 239 + if (((kprobe_inst >> 33) & 0x7) == 1) { 240 + printk(KERN_WARNING 241 + "Kprobes on speculation inst at <0x%lx> not supported\n", 242 + addr); 243 + return -EINVAL; 244 + } 245 + /* 246 + * IP relative mov instruction 247 + * - Bit 27-35 to be equal to 0x30 248 + */ 249 + if (((kprobe_inst >> 27) & 0x1FF) == 0x30) { 250 + printk(KERN_WARNING 251 + "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n", 252 + addr); 253 + return -EINVAL; 254 + 255 + } 256 + } 257 + else if ((major_opcode == 5) && !(kprobe_inst & (0xFUl << 33)) && 258 + (kprobe_inst & (0x1UL << 12))) { 259 + /* test bit instructions, tbit,tnat,tf 260 + * bit 33-36 to be equal to 0 261 + * bit 12 to be equal to 1 262 + */ 263 + if (slot == 1 && qp) { 264 + printk(KERN_WARNING "Kprobes on test bit" 265 + "instruction on slot at <0x%lx>" 266 + "is not supported\n", addr); 267 + return -EINVAL; 268 + } 269 + qp = 0; 270 + } 271 + } 272 + else if (bundle_encoding[template][slot] == B) { 273 + if (major_opcode == 7) { 274 + /* IP-Relative Predict major code is 7 */ 275 + printk(KERN_WARNING "Kprobes on IP-Relative" 276 + "Predict is not supported\n"); 277 + return -EINVAL; 278 + } 279 + else if (major_opcode == 2) { 280 + /* Indirect Predict, major code is 2 281 + * bit 27-32 to be equal to 10 or 11 282 + */ 283 + int x6=(kprobe_inst >> 27) & 0x3F; 284 + if ((x6 == 0x10) || (x6 == 0x11)) { 285 + printk(KERN_WARNING "Kprobes on" 286 + "Indirect Predict is not supported\n"); 287 + return -EINVAL; 288 + } 289 + } 290 + } 291 + /* kernel does not use float instruction, here for safety kprobe 292 + * will judge whether it is fcmp/flass/float approximation instruction 293 + */ 294 + else if (unlikely(bundle_encoding[template][slot] == F)) { 295 + if ((major_opcode == 4 || major_opcode == 5) && 296 + (kprobe_inst & (0x1 << 12))) { 297 + /* fcmp/fclass unc instruction */ 298 + if (slot == 1 && qp) { 299 + printk(KERN_WARNING "Kprobes on fcmp/fclass " 300 + "instruction on slot at <0x%lx> " 301 + "is not supported\n", addr); 302 + return -EINVAL; 303 + 304 + } 305 + qp = 0; 306 + } 307 + if ((major_opcode == 0 || major_opcode == 1) && 308 + (kprobe_inst & (0x1UL << 33))) { 309 + /* float Approximation instruction */ 310 + if (slot == 1 && qp) { 311 + printk(KERN_WARNING "Kprobes on float Approx " 312 + "instr at <0x%lx> is not supported\n", 313 + addr); 314 + return -EINVAL; 315 + } 316 + qp = 0; 317 + } 318 + } 319 + return qp; 320 + } 321 + 322 + /* 323 * In this function we override the bundle with 324 * the break instruction at the given slot. 325 */ 326 static void __kprobes prepare_break_inst(uint template, uint slot, 327 uint major_opcode, 328 unsigned long kprobe_inst, 329 + struct kprobe *p, 330 + int qp) 331 { 332 unsigned long break_inst = BREAK_INST; 333 bundle_t *bundle = &p->opcode.bundle; 334 335 /* 336 * Copy the original kprobe_inst qualifying predicate(qp) 337 + * to the break instruction 338 */ 339 + break_inst |= qp; 340 341 switch (slot) { 342 case 0: ··· 422 unsigned long kprobe_inst=0; 423 unsigned int slot = addr & 0xf, template, major_opcode = 0; 424 bundle_t *bundle; 425 + int qp; 426 427 bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; 428 template = bundle->quad0.template; ··· 436 /* Get kprobe_inst and major_opcode from the bundle */ 437 get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); 438 439 + qp = unsupported_inst(template, slot, major_opcode, kprobe_inst, addr); 440 + if (qp < 0) 441 + return -EINVAL; 442 443 p->ainsn.insn = get_insn_slot(); 444 if (!p->ainsn.insn) ··· 446 memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); 447 memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); 448 449 + prepare_break_inst(template, slot, major_opcode, kprobe_inst, p, qp); 450 451 return 0; 452 }