xref: /freebsd/sys/cddl/dev/kinst/amd64/kinst_isa.c (revision 84d7fe4a6f647faa2c91cb254b155e88e68c798c)
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