1f0bc4ed1SChristos Margiolis /* 2f0bc4ed1SChristos Margiolis * SPDX-License-Identifier: CDDL 1.0 3f0bc4ed1SChristos Margiolis * 4f0bc4ed1SChristos Margiolis * Copyright 2022 Christos Margiolis <christos@FreeBSD.org> 5f0bc4ed1SChristos Margiolis * Copyright 2022 Mark Johnston <markj@FreeBSD.org> 6f0bc4ed1SChristos Margiolis */ 7f0bc4ed1SChristos Margiolis 8f0bc4ed1SChristos Margiolis #include <sys/param.h> 9*84d7fe4aSMark Johnston #include <sys/pcpu.h> 10f0bc4ed1SChristos Margiolis 11f0bc4ed1SChristos Margiolis #include <machine/cpufunc.h> 12f0bc4ed1SChristos Margiolis #include <machine/md_var.h> 13f0bc4ed1SChristos Margiolis 14f0bc4ed1SChristos Margiolis #include <sys/dtrace.h> 15f0bc4ed1SChristos Margiolis #include <cddl/dev/dtrace/dtrace_cddl.h> 16f0bc4ed1SChristos Margiolis #include <dis_tables.h> 17f0bc4ed1SChristos Margiolis 18f0bc4ed1SChristos Margiolis #include "kinst.h" 19f0bc4ed1SChristos Margiolis 20f0bc4ed1SChristos Margiolis #define KINST_PUSHL_RBP 0x55 21f0bc4ed1SChristos Margiolis #define KINST_STI 0xfb 22f0bc4ed1SChristos Margiolis #define KINST_POPF 0x9d 23f0bc4ed1SChristos Margiolis 24f0bc4ed1SChristos Margiolis #define KINST_MODRM_MOD(b) (((b) & 0xc0) >> 6) 25f0bc4ed1SChristos Margiolis #define KINST_MODRM_REG(b) (((b) & 0x38) >> 3) 26f0bc4ed1SChristos Margiolis #define KINST_MODRM_RM(b) ((b) & 0x07) 27f0bc4ed1SChristos Margiolis 28f0bc4ed1SChristos Margiolis #define KINST_SIB_SCALE(s) (((s) & 0xc0) >> 6) 29f0bc4ed1SChristos Margiolis #define KINST_SIB_INDEX(s) (((s) & 0x38) >> 3) 30f0bc4ed1SChristos Margiolis #define KINST_SIB_BASE(s) (((s) & 0x07) >> 0) 31f0bc4ed1SChristos Margiolis 32f0bc4ed1SChristos Margiolis #define KINST_REX_W(r) (((r) & 0x08) >> 3) 33f0bc4ed1SChristos Margiolis #define KINST_REX_R(r) (((r) & 0x04) >> 2) 34f0bc4ed1SChristos Margiolis #define KINST_REX_X(r) (((r) & 0x02) >> 1) 35f0bc4ed1SChristos Margiolis #define KINST_REX_B(r) (((r) & 0x01) >> 0) 36f0bc4ed1SChristos Margiolis 37f0bc4ed1SChristos Margiolis #define KINST_F_CALL 0x0001 /* instruction is a "call" */ 38f0bc4ed1SChristos Margiolis #define KINST_F_DIRECT_CALL 0x0002 /* instruction is a direct call */ 39f0bc4ed1SChristos Margiolis #define KINST_F_RIPREL 0x0004 /* instruction is position-dependent */ 40f0bc4ed1SChristos Margiolis #define KINST_F_JMP 0x0008 /* instruction is a %rip-relative jmp */ 41f0bc4ed1SChristos Margiolis #define KINST_F_MOD_DIRECT 0x0010 /* operand is not a memory address */ 42f0bc4ed1SChristos Margiolis 43f0bc4ed1SChristos Margiolis /* 44*84d7fe4aSMark Johnston * Per-CPU trampolines used when the interrupted thread is executing with 45*84d7fe4aSMark Johnston * interrupts disabled. If an interrupt is raised while executing a trampoline, 46*84d7fe4aSMark Johnston * the interrupt thread cannot safely overwrite its trampoline if it hits a 47*84d7fe4aSMark Johnston * kinst probe while executing the interrupt handler. 48*84d7fe4aSMark Johnston */ 49*84d7fe4aSMark Johnston DPCPU_DEFINE_STATIC(uint8_t *, intr_tramp); 50*84d7fe4aSMark Johnston 51*84d7fe4aSMark Johnston /* 52f0bc4ed1SChristos Margiolis * Map ModR/M register bits to a trapframe offset. 53f0bc4ed1SChristos Margiolis */ 54f0bc4ed1SChristos Margiolis static int 55f0bc4ed1SChristos Margiolis kinst_regoff(int reg) 56f0bc4ed1SChristos Margiolis { 57f0bc4ed1SChristos Margiolis #define _MATCH_REG(i, reg) \ 58f0bc4ed1SChristos Margiolis case i: \ 59f0bc4ed1SChristos Margiolis return (offsetof(struct trapframe, tf_ ## reg) / \ 60f0bc4ed1SChristos Margiolis sizeof(register_t)) 61f0bc4ed1SChristos Margiolis switch (reg) { 62f0bc4ed1SChristos Margiolis _MATCH_REG( 0, rax); 63f0bc4ed1SChristos Margiolis _MATCH_REG( 1, rcx); 64f0bc4ed1SChristos Margiolis _MATCH_REG( 2, rdx); 65f0bc4ed1SChristos Margiolis _MATCH_REG( 3, rbx); 66f0bc4ed1SChristos Margiolis _MATCH_REG( 4, rsp); /* SIB when mod != 3 */ 67f0bc4ed1SChristos Margiolis _MATCH_REG( 5, rbp); 68f0bc4ed1SChristos Margiolis _MATCH_REG( 6, rsi); 69f0bc4ed1SChristos Margiolis _MATCH_REG( 7, rdi); 70f0bc4ed1SChristos Margiolis _MATCH_REG( 8, r8); /* REX.R is set */ 71f0bc4ed1SChristos Margiolis _MATCH_REG( 9, r9); 72f0bc4ed1SChristos Margiolis _MATCH_REG(10, r10); 73f0bc4ed1SChristos Margiolis _MATCH_REG(11, r11); 74f0bc4ed1SChristos Margiolis _MATCH_REG(12, r12); 75f0bc4ed1SChristos Margiolis _MATCH_REG(13, r13); 76f0bc4ed1SChristos Margiolis _MATCH_REG(14, r14); 77f0bc4ed1SChristos Margiolis _MATCH_REG(15, r15); 78f0bc4ed1SChristos Margiolis } 79f0bc4ed1SChristos Margiolis #undef _MATCH_REG 80f0bc4ed1SChristos Margiolis panic("%s: unhandled register index %d", __func__, reg); 81f0bc4ed1SChristos Margiolis } 82f0bc4ed1SChristos Margiolis 83f0bc4ed1SChristos Margiolis /* 84f0bc4ed1SChristos Margiolis * Obtain the specified register's value. 85f0bc4ed1SChristos Margiolis */ 86f0bc4ed1SChristos Margiolis static uint64_t 87f0bc4ed1SChristos Margiolis kinst_regval(struct trapframe *frame, int reg) 88f0bc4ed1SChristos Margiolis { 89f0bc4ed1SChristos Margiolis if (reg == -1) 90f0bc4ed1SChristos Margiolis return (0); 91f0bc4ed1SChristos Margiolis return (((register_t *)frame)[kinst_regoff(reg)]); 92f0bc4ed1SChristos Margiolis } 93f0bc4ed1SChristos Margiolis 94f0bc4ed1SChristos Margiolis static uint32_t 95f0bc4ed1SChristos Margiolis kinst_riprel_disp(struct kinst_probe *kp, void *dst) 96f0bc4ed1SChristos Margiolis { 97f0bc4ed1SChristos Margiolis return ((uint32_t)((intptr_t)kp->kp_patchpoint + kp->kp_md.disp - 98f0bc4ed1SChristos Margiolis (intptr_t)dst)); 99f0bc4ed1SChristos Margiolis } 100f0bc4ed1SChristos Margiolis 101f0bc4ed1SChristos Margiolis static void 102f0bc4ed1SChristos Margiolis kinst_trampoline_populate(struct kinst_probe *kp, uint8_t *tramp) 103f0bc4ed1SChristos Margiolis { 104f0bc4ed1SChristos Margiolis uint8_t *instr; 105f0bc4ed1SChristos Margiolis uint32_t disp; 106f0bc4ed1SChristos Margiolis int ilen; 107f0bc4ed1SChristos Margiolis 108f0bc4ed1SChristos Margiolis ilen = kp->kp_md.tinstlen; 109f0bc4ed1SChristos Margiolis 110f0bc4ed1SChristos Margiolis memcpy(tramp, kp->kp_md.template, ilen); 111f0bc4ed1SChristos Margiolis if ((kp->kp_md.flags & KINST_F_RIPREL) != 0) { 112f0bc4ed1SChristos Margiolis disp = kinst_riprel_disp(kp, tramp); 113f0bc4ed1SChristos Margiolis memcpy(&tramp[kp->kp_md.dispoff], &disp, sizeof(uint32_t)); 114f0bc4ed1SChristos Margiolis } 115f0bc4ed1SChristos Margiolis 116f0bc4ed1SChristos Margiolis /* 117f0bc4ed1SChristos Margiolis * The following position-independent jmp takes us back to the 118f0bc4ed1SChristos Margiolis * original code. It is encoded as "jmp *0(%rip)" (six bytes), 119f0bc4ed1SChristos Margiolis * followed by the absolute address of the instruction following 120f0bc4ed1SChristos Margiolis * the one that was traced (eight bytes). 121f0bc4ed1SChristos Margiolis */ 122f0bc4ed1SChristos Margiolis tramp[ilen + 0] = 0xff; 123f0bc4ed1SChristos Margiolis tramp[ilen + 1] = 0x25; 124f0bc4ed1SChristos Margiolis tramp[ilen + 2] = 0x00; 125f0bc4ed1SChristos Margiolis tramp[ilen + 3] = 0x00; 126f0bc4ed1SChristos Margiolis tramp[ilen + 4] = 0x00; 127f0bc4ed1SChristos Margiolis tramp[ilen + 5] = 0x00; 128f0bc4ed1SChristos Margiolis instr = kp->kp_patchpoint + kp->kp_md.instlen; 129f0bc4ed1SChristos Margiolis memcpy(&tramp[ilen + 6], &instr, sizeof(uintptr_t)); 130f0bc4ed1SChristos Margiolis } 131f0bc4ed1SChristos Margiolis 132f0bc4ed1SChristos Margiolis int 133f0bc4ed1SChristos Margiolis kinst_invop(uintptr_t addr, struct trapframe *frame, uintptr_t scratch) 134f0bc4ed1SChristos Margiolis { 135f0bc4ed1SChristos Margiolis solaris_cpu_t *cpu; 136f0bc4ed1SChristos Margiolis uintptr_t *stack, retaddr; 137f0bc4ed1SChristos Margiolis struct kinst_probe *kp; 138f0bc4ed1SChristos Margiolis struct kinst_probe_md *kpmd; 139f0bc4ed1SChristos Margiolis uint8_t *tramp; 140f0bc4ed1SChristos Margiolis 141f0bc4ed1SChristos Margiolis stack = (uintptr_t *)frame->tf_rsp; 142f0bc4ed1SChristos Margiolis cpu = &solaris_cpu[curcpu]; 143f0bc4ed1SChristos Margiolis 144f0bc4ed1SChristos Margiolis LIST_FOREACH(kp, KINST_GETPROBE(addr), kp_hashnext) { 145f0bc4ed1SChristos Margiolis if ((uintptr_t)kp->kp_patchpoint == addr) 146f0bc4ed1SChristos Margiolis break; 147f0bc4ed1SChristos Margiolis } 148f0bc4ed1SChristos Margiolis if (kp == NULL) 149f0bc4ed1SChristos Margiolis return (0); 150f0bc4ed1SChristos Margiolis 1510e69c959SMark Johnston /* 1520e69c959SMark Johnston * Report the address of the breakpoint for the benefit of consumers 1530e69c959SMark Johnston * fetching register values with regs[]. 1540e69c959SMark Johnston */ 1550e69c959SMark Johnston frame->tf_rip--; 1560e69c959SMark Johnston 157f0bc4ed1SChristos Margiolis DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 158f0bc4ed1SChristos Margiolis cpu->cpu_dtrace_caller = stack[0]; 159f0bc4ed1SChristos Margiolis DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); 160f0bc4ed1SChristos Margiolis dtrace_probe(kp->kp_id, 0, 0, 0, 0, 0); 161f0bc4ed1SChristos Margiolis cpu->cpu_dtrace_caller = 0; 162f0bc4ed1SChristos Margiolis 163f0bc4ed1SChristos Margiolis kpmd = &kp->kp_md; 164f0bc4ed1SChristos Margiolis if ((kpmd->flags & KINST_F_CALL) != 0) { 165f0bc4ed1SChristos Margiolis /* 166f0bc4ed1SChristos Margiolis * dtrace_invop_start() reserves space on the stack to 167f0bc4ed1SChristos Margiolis * store the return address of the call instruction. 168f0bc4ed1SChristos Margiolis */ 169f0bc4ed1SChristos Margiolis retaddr = (uintptr_t)(kp->kp_patchpoint + kpmd->instlen); 170f0bc4ed1SChristos Margiolis *(uintptr_t *)scratch = retaddr; 171f0bc4ed1SChristos Margiolis 172f0bc4ed1SChristos Margiolis if ((kpmd->flags & KINST_F_DIRECT_CALL) != 0) { 173f0bc4ed1SChristos Margiolis frame->tf_rip = (uintptr_t)(kp->kp_patchpoint + 174f0bc4ed1SChristos Margiolis kpmd->disp + kpmd->instlen); 175f0bc4ed1SChristos Margiolis } else { 176f0bc4ed1SChristos Margiolis register_t rval; 177f0bc4ed1SChristos Margiolis 178f0bc4ed1SChristos Margiolis if (kpmd->reg1 == -1 && kpmd->reg2 == -1) { 179f0bc4ed1SChristos Margiolis /* rip-relative */ 1800e69c959SMark Johnston rval = frame->tf_rip + kpmd->instlen; 181f0bc4ed1SChristos Margiolis } else { 182f0bc4ed1SChristos Margiolis /* indirect */ 183f0bc4ed1SChristos Margiolis rval = kinst_regval(frame, kpmd->reg1) + 184f0bc4ed1SChristos Margiolis (kinst_regval(frame, kpmd->reg2) << 185f0bc4ed1SChristos Margiolis kpmd->scale); 186f0bc4ed1SChristos Margiolis } 187f0bc4ed1SChristos Margiolis 188f0bc4ed1SChristos Margiolis if ((kpmd->flags & KINST_F_MOD_DIRECT) != 0) { 189f0bc4ed1SChristos Margiolis frame->tf_rip = rval + kpmd->disp; 190f0bc4ed1SChristos Margiolis } else { 191f0bc4ed1SChristos Margiolis frame->tf_rip = 192f0bc4ed1SChristos Margiolis *(uintptr_t *)(rval + kpmd->disp); 193f0bc4ed1SChristos Margiolis } 194f0bc4ed1SChristos Margiolis } 195f0bc4ed1SChristos Margiolis return (DTRACE_INVOP_CALL); 196f0bc4ed1SChristos Margiolis } else { 197*84d7fe4aSMark Johnston if ((frame->tf_rflags & PSL_I) == 0) 198*84d7fe4aSMark Johnston tramp = DPCPU_GET(intr_tramp); 199*84d7fe4aSMark Johnston else 200f0bc4ed1SChristos Margiolis tramp = curthread->t_kinst; 201f0bc4ed1SChristos Margiolis if (tramp == NULL) { 202f0bc4ed1SChristos Margiolis /* 203f0bc4ed1SChristos Margiolis * A trampoline allocation failed, so this probe is 204f0bc4ed1SChristos Margiolis * effectively disabled. Restore the original 205f0bc4ed1SChristos Margiolis * instruction. 206f0bc4ed1SChristos Margiolis * 207f0bc4ed1SChristos Margiolis * We can't safely print anything here, but the 208f0bc4ed1SChristos Margiolis * trampoline allocator should have left a breadcrumb in 209f0bc4ed1SChristos Margiolis * the dmesg. 210f0bc4ed1SChristos Margiolis */ 211f0bc4ed1SChristos Margiolis kinst_patch_tracepoint(kp, kp->kp_savedval); 212f0bc4ed1SChristos Margiolis frame->tf_rip = (register_t)kp->kp_patchpoint; 213f0bc4ed1SChristos Margiolis } else { 214f0bc4ed1SChristos Margiolis kinst_trampoline_populate(kp, tramp); 215f0bc4ed1SChristos Margiolis frame->tf_rip = (register_t)tramp; 216f0bc4ed1SChristos Margiolis } 217f0bc4ed1SChristos Margiolis return (DTRACE_INVOP_NOP); 218f0bc4ed1SChristos Margiolis } 219f0bc4ed1SChristos Margiolis } 220f0bc4ed1SChristos Margiolis 221f0bc4ed1SChristos Margiolis void 222f0bc4ed1SChristos Margiolis kinst_patch_tracepoint(struct kinst_probe *kp, kinst_patchval_t val) 223f0bc4ed1SChristos Margiolis { 224f0bc4ed1SChristos Margiolis register_t reg; 225f0bc4ed1SChristos Margiolis int oldwp; 226f0bc4ed1SChristos Margiolis 227f0bc4ed1SChristos Margiolis reg = intr_disable(); 228f0bc4ed1SChristos Margiolis oldwp = disable_wp(); 229f0bc4ed1SChristos Margiolis *kp->kp_patchpoint = val; 230f0bc4ed1SChristos Margiolis restore_wp(oldwp); 231f0bc4ed1SChristos Margiolis intr_restore(reg); 232f0bc4ed1SChristos Margiolis } 233f0bc4ed1SChristos Margiolis 234f0bc4ed1SChristos Margiolis static void 235f0bc4ed1SChristos Margiolis kinst_set_disp8(struct kinst_probe *kp, uint8_t byte) 236f0bc4ed1SChristos Margiolis { 237f0bc4ed1SChristos Margiolis kp->kp_md.disp = (int64_t)(int8_t)byte; 238f0bc4ed1SChristos Margiolis } 239f0bc4ed1SChristos Margiolis 240f0bc4ed1SChristos Margiolis static void 241f0bc4ed1SChristos Margiolis kinst_set_disp32(struct kinst_probe *kp, uint8_t *bytes) 242f0bc4ed1SChristos Margiolis { 243f0bc4ed1SChristos Margiolis int32_t disp32; 244f0bc4ed1SChristos Margiolis 245f0bc4ed1SChristos Margiolis memcpy(&disp32, bytes, sizeof(disp32)); 246f0bc4ed1SChristos Margiolis kp->kp_md.disp = (int64_t)disp32; 247f0bc4ed1SChristos Margiolis } 248f0bc4ed1SChristos Margiolis 249f0bc4ed1SChristos Margiolis static int 250f0bc4ed1SChristos Margiolis kinst_dis_get_byte(void *p) 251f0bc4ed1SChristos Margiolis { 252f0bc4ed1SChristos Margiolis int ret; 253f0bc4ed1SChristos Margiolis uint8_t **instr = p; 254f0bc4ed1SChristos Margiolis 255f0bc4ed1SChristos Margiolis ret = **instr; 256f0bc4ed1SChristos Margiolis (*instr)++; 257f0bc4ed1SChristos Margiolis 258f0bc4ed1SChristos Margiolis return (ret); 259f0bc4ed1SChristos Margiolis } 260f0bc4ed1SChristos Margiolis 261f0bc4ed1SChristos Margiolis /* 262f0bc4ed1SChristos Margiolis * Set up all of the state needed to faithfully execute a probed instruction. 263f0bc4ed1SChristos Margiolis * 264f0bc4ed1SChristos Margiolis * In the simple case, we copy the instruction unmodified to a per-thread 265f0bc4ed1SChristos Margiolis * trampoline, wherein it is followed by a jump back to the original code. 266f0bc4ed1SChristos Margiolis * - Instructions can have %rip as an operand: 267f0bc4ed1SChristos Margiolis * - with %rip-relative addressing encoded in ModR/M, or 268f0bc4ed1SChristos Margiolis * - implicitly as a part of the instruction definition (jmp, call). 269f0bc4ed1SChristos Margiolis * - Call instructions (which may be %rip-relative) need to push the correct 270f0bc4ed1SChristos Margiolis * return address onto the stack. 271f0bc4ed1SChristos Margiolis * 272f0bc4ed1SChristos Margiolis * Call instructions are simple enough to be emulated in software, so we simply 273f0bc4ed1SChristos Margiolis * do not use the trampoline mechanism in that case. kinst_invop() will compute 274f0bc4ed1SChristos Margiolis * the branch target using the address info computed here (register operands and 275f0bc4ed1SChristos Margiolis * displacement). 276f0bc4ed1SChristos Margiolis * 277f0bc4ed1SChristos Margiolis * %rip-relative operands encoded using the ModR/M byte always use a 32-bit 278f0bc4ed1SChristos Margiolis * displacement; when populating the trampoline the displacement is adjusted to 279f0bc4ed1SChristos Margiolis * be relative to the trampoline address. Trampolines are always allocated 280f0bc4ed1SChristos Margiolis * above KERNBASE for this reason. 281f0bc4ed1SChristos Margiolis * 282f0bc4ed1SChristos Margiolis * For other %rip-relative operands (just jumps) we take the same approach. 283f0bc4ed1SChristos Margiolis * Instructions which specify an 8-bit displacement must be rewritten to use a 284f0bc4ed1SChristos Margiolis * 32-bit displacement. 285f0bc4ed1SChristos Margiolis */ 286f0bc4ed1SChristos Margiolis static int 287f0bc4ed1SChristos Margiolis kinst_instr_dissect(struct kinst_probe *kp, uint8_t **instr) 288f0bc4ed1SChristos Margiolis { 289f0bc4ed1SChristos Margiolis struct kinst_probe_md *kpmd; 290f0bc4ed1SChristos Margiolis dis86_t d86; 291f0bc4ed1SChristos Margiolis uint8_t *bytes, modrm, rex; 292f0bc4ed1SChristos Margiolis int dispoff, i, ilen, opcidx; 293f0bc4ed1SChristos Margiolis 294f0bc4ed1SChristos Margiolis kpmd = &kp->kp_md; 295f0bc4ed1SChristos Margiolis 296f0bc4ed1SChristos Margiolis d86.d86_data = instr; 297f0bc4ed1SChristos Margiolis d86.d86_get_byte = kinst_dis_get_byte; 298f0bc4ed1SChristos Margiolis d86.d86_check_func = NULL; 299f0bc4ed1SChristos Margiolis if (dtrace_disx86(&d86, SIZE64) != 0) { 300f0bc4ed1SChristos Margiolis KINST_LOG("failed to disassemble instruction at: %p", *instr); 301f0bc4ed1SChristos Margiolis return (EINVAL); 302f0bc4ed1SChristos Margiolis } 303f0bc4ed1SChristos Margiolis bytes = d86.d86_bytes; 304f0bc4ed1SChristos Margiolis kpmd->instlen = kpmd->tinstlen = d86.d86_len; 305f0bc4ed1SChristos Margiolis 306f0bc4ed1SChristos Margiolis /* 307f0bc4ed1SChristos Margiolis * Skip over prefixes, save REX. 308f0bc4ed1SChristos Margiolis */ 309f0bc4ed1SChristos Margiolis rex = 0; 310f0bc4ed1SChristos Margiolis for (i = 0; i < kpmd->instlen; i++) { 311f0bc4ed1SChristos Margiolis switch (bytes[i]) { 312f0bc4ed1SChristos Margiolis case 0xf0 ... 0xf3: 313f0bc4ed1SChristos Margiolis /* group 1 */ 314f0bc4ed1SChristos Margiolis continue; 315f0bc4ed1SChristos Margiolis case 0x26: 316f0bc4ed1SChristos Margiolis case 0x2e: 317f0bc4ed1SChristos Margiolis case 0x36: 318f0bc4ed1SChristos Margiolis case 0x3e: 319f0bc4ed1SChristos Margiolis case 0x64: 320f0bc4ed1SChristos Margiolis case 0x65: 321f0bc4ed1SChristos Margiolis /* group 2 */ 322f0bc4ed1SChristos Margiolis continue; 323f0bc4ed1SChristos Margiolis case 0x66: 324f0bc4ed1SChristos Margiolis /* group 3 */ 325f0bc4ed1SChristos Margiolis continue; 326f0bc4ed1SChristos Margiolis case 0x67: 327f0bc4ed1SChristos Margiolis /* group 4 */ 328f0bc4ed1SChristos Margiolis continue; 329f0bc4ed1SChristos Margiolis case 0x40 ... 0x4f: 330f0bc4ed1SChristos Margiolis /* REX */ 331f0bc4ed1SChristos Margiolis rex = bytes[i]; 332f0bc4ed1SChristos Margiolis continue; 333f0bc4ed1SChristos Margiolis } 334f0bc4ed1SChristos Margiolis break; 335f0bc4ed1SChristos Margiolis } 336f0bc4ed1SChristos Margiolis KASSERT(i < kpmd->instlen, 337f0bc4ed1SChristos Margiolis ("%s: failed to disassemble instruction at %p", __func__, bytes)); 338f0bc4ed1SChristos Margiolis opcidx = i; 339f0bc4ed1SChristos Margiolis 340f0bc4ed1SChristos Margiolis /* 341f0bc4ed1SChristos Margiolis * Identify instructions of interest by opcode: calls and jumps. 342f0bc4ed1SChristos Margiolis * Extract displacements. 343f0bc4ed1SChristos Margiolis */ 344f0bc4ed1SChristos Margiolis dispoff = -1; 345f0bc4ed1SChristos Margiolis switch (bytes[opcidx]) { 346f0bc4ed1SChristos Margiolis case 0x0f: 347f0bc4ed1SChristos Margiolis switch (bytes[opcidx + 1]) { 348f0bc4ed1SChristos Margiolis case 0x80 ... 0x8f: 349f0bc4ed1SChristos Margiolis /* conditional jmp near */ 350f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_JMP | KINST_F_RIPREL; 351f0bc4ed1SChristos Margiolis dispoff = opcidx + 2; 352f0bc4ed1SChristos Margiolis kinst_set_disp32(kp, &bytes[dispoff]); 353f0bc4ed1SChristos Margiolis break; 354f0bc4ed1SChristos Margiolis } 355f0bc4ed1SChristos Margiolis break; 356f0bc4ed1SChristos Margiolis case 0xe3: 357f0bc4ed1SChristos Margiolis /* 358f0bc4ed1SChristos Margiolis * There is no straightforward way to translate this instruction 359f0bc4ed1SChristos Margiolis * to use a 32-bit displacement. Fortunately, it is rarely 360f0bc4ed1SChristos Margiolis * used. 361f0bc4ed1SChristos Margiolis */ 362f0bc4ed1SChristos Margiolis return (EINVAL); 363f0bc4ed1SChristos Margiolis case 0x70 ... 0x7f: 364f0bc4ed1SChristos Margiolis /* conditional jmp short */ 365f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_JMP | KINST_F_RIPREL; 366f0bc4ed1SChristos Margiolis dispoff = opcidx + 1; 367f0bc4ed1SChristos Margiolis kinst_set_disp8(kp, bytes[dispoff]); 368f0bc4ed1SChristos Margiolis break; 369f0bc4ed1SChristos Margiolis case 0xe9: 370f0bc4ed1SChristos Margiolis /* unconditional jmp near */ 371f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_JMP | KINST_F_RIPREL; 372f0bc4ed1SChristos Margiolis dispoff = opcidx + 1; 373f0bc4ed1SChristos Margiolis kinst_set_disp32(kp, &bytes[dispoff]); 374f0bc4ed1SChristos Margiolis break; 375f0bc4ed1SChristos Margiolis case 0xeb: 376f0bc4ed1SChristos Margiolis /* unconditional jmp short */ 377f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_JMP | KINST_F_RIPREL; 378f0bc4ed1SChristos Margiolis dispoff = opcidx + 1; 379f0bc4ed1SChristos Margiolis kinst_set_disp8(kp, bytes[dispoff]); 380f0bc4ed1SChristos Margiolis break; 381f0bc4ed1SChristos Margiolis case 0xe8: 382f0bc4ed1SChristos Margiolis case 0x9a: 383f0bc4ed1SChristos Margiolis /* direct call */ 384f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_CALL | KINST_F_DIRECT_CALL; 385f0bc4ed1SChristos Margiolis dispoff = opcidx + 1; 386f0bc4ed1SChristos Margiolis kinst_set_disp32(kp, &bytes[dispoff]); 387f0bc4ed1SChristos Margiolis break; 388f0bc4ed1SChristos Margiolis case 0xff: 389f0bc4ed1SChristos Margiolis KASSERT(d86.d86_got_modrm, 390f0bc4ed1SChristos Margiolis ("no ModR/M byte for instr at %p", *instr - kpmd->instlen)); 391f0bc4ed1SChristos Margiolis switch (KINST_MODRM_REG(bytes[d86.d86_rmindex])) { 392f0bc4ed1SChristos Margiolis case 0x02: 393f0bc4ed1SChristos Margiolis case 0x03: 394f0bc4ed1SChristos Margiolis /* indirect call */ 395f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_CALL; 396f0bc4ed1SChristos Margiolis break; 397f0bc4ed1SChristos Margiolis case 0x04: 398f0bc4ed1SChristos Margiolis case 0x05: 399f0bc4ed1SChristos Margiolis /* indirect jump */ 400f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_JMP; 401f0bc4ed1SChristos Margiolis break; 402f0bc4ed1SChristos Margiolis } 403f0bc4ed1SChristos Margiolis } 404f0bc4ed1SChristos Margiolis 405f0bc4ed1SChristos Margiolis /* 406f0bc4ed1SChristos Margiolis * If there's a ModR/M byte, we need to check it to see if the operand 407f0bc4ed1SChristos Margiolis * is %rip-relative, and rewrite the displacement if so. If not, we 408f0bc4ed1SChristos Margiolis * might still have to extract operand info if this is a call 409f0bc4ed1SChristos Margiolis * instruction. 410f0bc4ed1SChristos Margiolis */ 411f0bc4ed1SChristos Margiolis if (d86.d86_got_modrm) { 412f0bc4ed1SChristos Margiolis uint8_t mod, rm, sib; 413f0bc4ed1SChristos Margiolis 414f0bc4ed1SChristos Margiolis kpmd->reg1 = kpmd->reg2 = -1; 415f0bc4ed1SChristos Margiolis 416f0bc4ed1SChristos Margiolis modrm = bytes[d86.d86_rmindex]; 417f0bc4ed1SChristos Margiolis mod = KINST_MODRM_MOD(modrm); 418f0bc4ed1SChristos Margiolis rm = KINST_MODRM_RM(modrm); 419f0bc4ed1SChristos Margiolis if (mod == 0 && rm == 5) { 420f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_RIPREL; 421f0bc4ed1SChristos Margiolis dispoff = d86.d86_rmindex + 1; 422f0bc4ed1SChristos Margiolis kinst_set_disp32(kp, &bytes[dispoff]); 423f0bc4ed1SChristos Margiolis } else if ((kpmd->flags & KINST_F_CALL) != 0) { 424f0bc4ed1SChristos Margiolis bool havesib; 425f0bc4ed1SChristos Margiolis 426f0bc4ed1SChristos Margiolis havesib = (mod != 3 && rm == 4); 427f0bc4ed1SChristos Margiolis dispoff = d86.d86_rmindex + (havesib ? 2 : 1); 428f0bc4ed1SChristos Margiolis if (mod == 1) 429f0bc4ed1SChristos Margiolis kinst_set_disp8(kp, bytes[dispoff]); 430f0bc4ed1SChristos Margiolis else if (mod == 2) 431f0bc4ed1SChristos Margiolis kinst_set_disp32(kp, &bytes[dispoff]); 432f0bc4ed1SChristos Margiolis else if (mod == 3) 433f0bc4ed1SChristos Margiolis kpmd->flags |= KINST_F_MOD_DIRECT; 434f0bc4ed1SChristos Margiolis 435f0bc4ed1SChristos Margiolis if (havesib) { 436f0bc4ed1SChristos Margiolis sib = bytes[d86.d86_rmindex + 1]; 437f0bc4ed1SChristos Margiolis if (KINST_SIB_BASE(sib) != 5) { 438f0bc4ed1SChristos Margiolis kpmd->reg1 = KINST_SIB_BASE(sib) | 439f0bc4ed1SChristos Margiolis (KINST_REX_B(rex) << 3); 440f0bc4ed1SChristos Margiolis } 441f0bc4ed1SChristos Margiolis kpmd->scale = KINST_SIB_SCALE(sib); 442f0bc4ed1SChristos Margiolis kpmd->reg2 = KINST_SIB_INDEX(sib) | 443f0bc4ed1SChristos Margiolis (KINST_REX_X(rex) << 3); 444f0bc4ed1SChristos Margiolis } else { 445f0bc4ed1SChristos Margiolis kpmd->reg1 = rm | (KINST_REX_B(rex) << 3); 446f0bc4ed1SChristos Margiolis } 447f0bc4ed1SChristos Margiolis } 448f0bc4ed1SChristos Margiolis } 449f0bc4ed1SChristos Margiolis 450f0bc4ed1SChristos Margiolis /* 451f0bc4ed1SChristos Margiolis * Calls are emulated in software; once operands are decoded we have 452f0bc4ed1SChristos Margiolis * nothing else to do. 453f0bc4ed1SChristos Margiolis */ 454f0bc4ed1SChristos Margiolis if ((kpmd->flags & KINST_F_CALL) != 0) 455f0bc4ed1SChristos Margiolis return (0); 456f0bc4ed1SChristos Margiolis 457f0bc4ed1SChristos Margiolis /* 458f0bc4ed1SChristos Margiolis * Allocate and populate an instruction trampoline template. 459f0bc4ed1SChristos Margiolis * 460f0bc4ed1SChristos Margiolis * Position-independent instructions can simply be copied, but 461f0bc4ed1SChristos Margiolis * position-dependent instructions require some surgery: jump 462f0bc4ed1SChristos Margiolis * instructions with an 8-bit displacement need to be converted to use a 463f0bc4ed1SChristos Margiolis * 32-bit displacement, and the adjusted displacement needs to be 464f0bc4ed1SChristos Margiolis * computed. 465f0bc4ed1SChristos Margiolis */ 466f0bc4ed1SChristos Margiolis ilen = kpmd->instlen; 467f0bc4ed1SChristos Margiolis if ((kpmd->flags & KINST_F_RIPREL) != 0) { 468f0bc4ed1SChristos Margiolis if ((kpmd->flags & KINST_F_JMP) == 0 || 469f0bc4ed1SChristos Margiolis bytes[opcidx] == 0x0f || 470f0bc4ed1SChristos Margiolis bytes[opcidx] == 0xe9 || 471f0bc4ed1SChristos Margiolis bytes[opcidx] == 0xff) { 472f0bc4ed1SChristos Margiolis memcpy(kpmd->template, bytes, dispoff); 473f0bc4ed1SChristos Margiolis memcpy(&kpmd->template[dispoff + 4], 474f0bc4ed1SChristos Margiolis &bytes[dispoff + 4], ilen - (dispoff + 4)); 475f0bc4ed1SChristos Margiolis kpmd->dispoff = dispoff; 476f0bc4ed1SChristos Margiolis } else if (bytes[opcidx] == 0xeb) { 477f0bc4ed1SChristos Margiolis memcpy(kpmd->template, bytes, opcidx); 478f0bc4ed1SChristos Margiolis kpmd->template[opcidx] = 0xe9; 479f0bc4ed1SChristos Margiolis kpmd->dispoff = opcidx + 1; 480f0bc4ed1SChristos Margiolis 481f0bc4ed1SChristos Margiolis /* Instruction length changes from 2 to 5. */ 482f0bc4ed1SChristos Margiolis kpmd->tinstlen = 5; 483f0bc4ed1SChristos Margiolis kpmd->disp -= 3; 484f0bc4ed1SChristos Margiolis } else if (bytes[opcidx] >= 0x70 && bytes[opcidx] <= 0x7f) { 485f0bc4ed1SChristos Margiolis memcpy(kpmd->template, bytes, opcidx); 486f0bc4ed1SChristos Margiolis kpmd->template[opcidx] = 0x0f; 487f0bc4ed1SChristos Margiolis kpmd->template[opcidx + 1] = bytes[opcidx] + 0x10; 488f0bc4ed1SChristos Margiolis kpmd->dispoff = opcidx + 2; 489f0bc4ed1SChristos Margiolis 490f0bc4ed1SChristos Margiolis /* Instruction length changes from 2 to 6. */ 491f0bc4ed1SChristos Margiolis kpmd->tinstlen = 6; 492f0bc4ed1SChristos Margiolis kpmd->disp -= 4; 493f0bc4ed1SChristos Margiolis } else { 494f0bc4ed1SChristos Margiolis panic("unhandled opcode %#x", bytes[opcidx]); 495f0bc4ed1SChristos Margiolis } 496f0bc4ed1SChristos Margiolis } else { 497f0bc4ed1SChristos Margiolis memcpy(kpmd->template, bytes, ilen); 498f0bc4ed1SChristos Margiolis } 499f0bc4ed1SChristos Margiolis 500f0bc4ed1SChristos Margiolis return (0); 501f0bc4ed1SChristos Margiolis } 502f0bc4ed1SChristos Margiolis 503f0bc4ed1SChristos Margiolis int 504f0bc4ed1SChristos Margiolis kinst_make_probe(linker_file_t lf, int symindx, linker_symval_t *symval, 505f0bc4ed1SChristos Margiolis void *opaque) 506f0bc4ed1SChristos Margiolis { 507f0bc4ed1SChristos Margiolis struct kinst_probe *kp; 508f0bc4ed1SChristos Margiolis dtrace_kinst_probedesc_t *pd; 509f0bc4ed1SChristos Margiolis const char *func; 510*84d7fe4aSMark Johnston int error, instrsize, n, off; 511f0bc4ed1SChristos Margiolis uint8_t *instr, *limit; 512f0bc4ed1SChristos Margiolis 513f0bc4ed1SChristos Margiolis pd = opaque; 514f0bc4ed1SChristos Margiolis func = symval->name; 515f0bc4ed1SChristos Margiolis if (strcmp(func, pd->kpd_func) != 0 || strcmp(func, "trap_check") == 0) 516f0bc4ed1SChristos Margiolis return (0); 517f0bc4ed1SChristos Margiolis 518f0bc4ed1SChristos Margiolis instr = (uint8_t *)symval->value; 519f0bc4ed1SChristos Margiolis limit = (uint8_t *)symval->value + symval->size; 520f0bc4ed1SChristos Margiolis if (instr >= limit) 521f0bc4ed1SChristos Margiolis return (0); 522f0bc4ed1SChristos Margiolis 523f0bc4ed1SChristos Margiolis /* 524f0bc4ed1SChristos Margiolis * Ignore functions not beginning with the usual function prologue. 525*84d7fe4aSMark Johnston * These might correspond to exception handlers with which we should not 526*84d7fe4aSMark Johnston * meddle. This does however exclude functions which can be safely 527*84d7fe4aSMark Johnston * traced, such as cpu_switch(). 528f0bc4ed1SChristos Margiolis */ 529f0bc4ed1SChristos Margiolis if (*instr != KINST_PUSHL_RBP) 530f0bc4ed1SChristos Margiolis return (0); 531f0bc4ed1SChristos Margiolis 532f0bc4ed1SChristos Margiolis n = 0; 533f0bc4ed1SChristos Margiolis while (instr < limit) { 534*84d7fe4aSMark Johnston instrsize = dtrace_instr_size(instr); 535f0bc4ed1SChristos Margiolis off = (int)(instr - (uint8_t *)symval->value); 536f0bc4ed1SChristos Margiolis if (pd->kpd_off != -1 && off != pd->kpd_off) { 537*84d7fe4aSMark Johnston instr += instrsize; 538*84d7fe4aSMark Johnston continue; 539*84d7fe4aSMark Johnston } 540*84d7fe4aSMark Johnston 541*84d7fe4aSMark Johnston /* 542*84d7fe4aSMark Johnston * Check for instructions which may enable interrupts. Such 543*84d7fe4aSMark Johnston * instructions are tricky to trace since it is unclear whether 544*84d7fe4aSMark Johnston * to use the per-thread or per-CPU trampolines. Since they are 545*84d7fe4aSMark Johnston * rare, we don't bother to implement special handling for them. 546*84d7fe4aSMark Johnston * 547*84d7fe4aSMark Johnston * If the caller specified an offset, return an error, otherwise 548*84d7fe4aSMark Johnston * silently ignore the instruction so that it remains possible 549*84d7fe4aSMark Johnston * to enable all instructions in a function. 550*84d7fe4aSMark Johnston */ 551*84d7fe4aSMark Johnston if (instrsize == 1 && 552*84d7fe4aSMark Johnston (instr[0] == KINST_POPF || instr[0] == KINST_STI)) { 553*84d7fe4aSMark Johnston if (pd->kpd_off != -1) 554*84d7fe4aSMark Johnston return (EINVAL); 555*84d7fe4aSMark Johnston instr += instrsize; 556f0bc4ed1SChristos Margiolis continue; 557f0bc4ed1SChristos Margiolis } 558f0bc4ed1SChristos Margiolis 559f0bc4ed1SChristos Margiolis /* 560f0bc4ed1SChristos Margiolis * Prevent separate dtrace(1) instances from creating copies of 561f0bc4ed1SChristos Margiolis * the same probe. 562f0bc4ed1SChristos Margiolis */ 563f0bc4ed1SChristos Margiolis LIST_FOREACH(kp, KINST_GETPROBE(instr), kp_hashnext) { 564f0bc4ed1SChristos Margiolis if (strcmp(kp->kp_func, func) == 0 && 565f0bc4ed1SChristos Margiolis strtol(kp->kp_name, NULL, 10) == off) 566f0bc4ed1SChristos Margiolis return (0); 567f0bc4ed1SChristos Margiolis } 568f0bc4ed1SChristos Margiolis if (++n > KINST_PROBETAB_MAX) { 569f0bc4ed1SChristos Margiolis KINST_LOG("probe list full: %d entries", n); 570f0bc4ed1SChristos Margiolis return (ENOMEM); 571f0bc4ed1SChristos Margiolis } 572f0bc4ed1SChristos Margiolis kp = malloc(sizeof(struct kinst_probe), M_KINST, 573f0bc4ed1SChristos Margiolis M_WAITOK | M_ZERO); 574f0bc4ed1SChristos Margiolis kp->kp_func = func; 575f0bc4ed1SChristos Margiolis snprintf(kp->kp_name, sizeof(kp->kp_name), "%d", off); 576f0bc4ed1SChristos Margiolis kp->kp_savedval = *instr; 577f0bc4ed1SChristos Margiolis kp->kp_patchval = KINST_PATCHVAL; 578f0bc4ed1SChristos Margiolis kp->kp_patchpoint = instr; 579f0bc4ed1SChristos Margiolis 580f0bc4ed1SChristos Margiolis error = kinst_instr_dissect(kp, &instr); 581f0bc4ed1SChristos Margiolis if (error != 0) 582f0bc4ed1SChristos Margiolis return (error); 583f0bc4ed1SChristos Margiolis 584f0bc4ed1SChristos Margiolis kinst_probe_create(kp, lf); 585f0bc4ed1SChristos Margiolis } 586f0bc4ed1SChristos Margiolis 587f0bc4ed1SChristos Margiolis return (0); 588f0bc4ed1SChristos Margiolis } 589*84d7fe4aSMark Johnston 590*84d7fe4aSMark Johnston int 591*84d7fe4aSMark Johnston kinst_md_init(void) 592*84d7fe4aSMark Johnston { 593*84d7fe4aSMark Johnston uint8_t *tramp; 594*84d7fe4aSMark Johnston int cpu; 595*84d7fe4aSMark Johnston 596*84d7fe4aSMark Johnston CPU_FOREACH(cpu) { 597*84d7fe4aSMark Johnston tramp = kinst_trampoline_alloc(M_WAITOK); 598*84d7fe4aSMark Johnston if (tramp == NULL) 599*84d7fe4aSMark Johnston return (ENOMEM); 600*84d7fe4aSMark Johnston DPCPU_ID_SET(cpu, intr_tramp, tramp); 601*84d7fe4aSMark Johnston } 602*84d7fe4aSMark Johnston 603*84d7fe4aSMark Johnston return (0); 604*84d7fe4aSMark Johnston } 605*84d7fe4aSMark Johnston 606*84d7fe4aSMark Johnston void 607*84d7fe4aSMark Johnston kinst_md_deinit(void) 608*84d7fe4aSMark Johnston { 609*84d7fe4aSMark Johnston uint8_t *tramp; 610*84d7fe4aSMark Johnston int cpu; 611*84d7fe4aSMark Johnston 612*84d7fe4aSMark Johnston CPU_FOREACH(cpu) { 613*84d7fe4aSMark Johnston tramp = DPCPU_ID_GET(cpu, intr_tramp); 614*84d7fe4aSMark Johnston if (tramp != NULL) { 615*84d7fe4aSMark Johnston kinst_trampoline_dealloc(DPCPU_ID_GET(cpu, intr_tramp)); 616*84d7fe4aSMark Johnston DPCPU_ID_SET(cpu, intr_tramp, NULL); 617*84d7fe4aSMark Johnston } 618*84d7fe4aSMark Johnston } 619*84d7fe4aSMark Johnston } 620