/* * Figure out which fixups arch_uprobe_post_xol() will need to perform, and * annotate arch_uprobe->fixups accordingly. To start with, * arch_uprobe->fixups is either zero or it reflects rip-related fixups. */ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) { bool fix_ip = true, fix_call = false; /* defaults */ int reg; insn_get_opcode(insn); /* should be a nop */ switch (OPCODE1(insn)) { case 0x9d: /* popf */ auprobe->fixups |= UPROBE_FIX_SETF; break; case 0xc3: /* ret/lret */ case 0xcb: case 0xc2: case 0xca: /* ip is correct */ fix_ip = false; break; case 0xe8: /* call relative - Fix return addr */ fix_call = true; break; case 0x9a: /* call absolute - Fix return addr, not ip */ fix_call = true; fix_ip = false; break; case 0xff: insn_get_modrm(insn); reg = MODRM_REG(insn); if (reg == 2 || reg == 3) { /* call or lcall, indirect */ /* Fix return addr; ip is correct. */ fix_call = true; fix_ip = false; } else if (reg == 4 || reg == 5) { /* jmp or ljmp, indirect */ /* ip is correct. */ fix_ip = false; } break; case 0xea: /* jmp absolute -- ip is correct */ fix_ip = false; break; default: break; } if (fix_ip) auprobe->fixups |= UPROBE_FIX_IP; if (fix_call) auprobe->fixups |= UPROBE_FIX_CALL; }
static int validate_insn_64bits(struct arch_uprobe *auprobe, struct insn *insn) { insn_init(insn, auprobe->insn, true); /* Skip good instruction prefixes; reject "bad" ones. */ insn_get_opcode(insn); if (is_prefix_bad(insn)) return -ENOTSUPP; if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_64)) return 0; if (insn->opcode.nbytes == 2) { if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) return 0; } return -ENOTSUPP; }