4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2012 by Delphix. All rights reserved.
40 #include <dis_tables.h>
42 #define DT_POPL_EBP 0x5d
50 #define DT_MOVL_EBP_ESP 0xe58b
52 #define DT_ISJ32(op16) (((op16) & 0xfff0) == 0x0f80)
53 #define DT_ISJ8(op8) (((op8) & 0xf0) == 0x70)
55 #define DT_MODRM_REG(modrm) (((modrm) >> 3) & 0x7)
57 static int dt_instr_size(uchar_t
*, dtrace_hdl_t
*, pid_t
, uintptr_t, char);
61 dt_pid_create_entry_probe(struct ps_prochandle
*P
, dtrace_hdl_t
*dtp
,
62 fasttrap_probe_spec_t
*ftp
, const GElf_Sym
*symp
)
64 ftp
->ftps_type
= DTFTP_ENTRY
;
65 ftp
->ftps_pc
= (uintptr_t)symp
->st_value
;
66 ftp
->ftps_size
= (size_t)symp
->st_size
;
68 ftp
->ftps_offs
[0] = 0;
70 if (ioctl(dtp
->dt_ftfd
, FASTTRAPIOC_MAKEPROBE
, ftp
) != 0) {
71 dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
73 return (dt_set_errno(dtp
, errno
));
80 dt_pid_has_jump_table(struct ps_prochandle
*P
, dtrace_hdl_t
*dtp
,
81 uint8_t *text
, fasttrap_probe_spec_t
*ftp
, const GElf_Sym
*symp
)
85 pid_t pid
= Pstatus(P
)->pr_pid
;
86 char dmodel
= Pstatus(P
)->pr_dmodel
;
89 * Take a pass through the function looking for a register-dependant
90 * jmp instruction. This could be a jump table so we have to be
93 for (i
= 0; i
< ftp
->ftps_size
; i
+= size
) {
94 size
= dt_instr_size(&text
[i
], dtp
, pid
, symp
->st_value
+ i
,
98 * Assume the worst if we hit an illegal instruction.
101 dt_dprintf("error at %#lx (assuming jump table)\n", i
);
106 * Register-dependant jmp instructions start with a 0xff byte
107 * and have the modrm.reg field set to 4. They can have an
108 * optional REX prefix on the 64-bit ISA.
110 if ((text
[i
] == 0xff && DT_MODRM_REG(text
[i
+ 1]) == 4) ||
111 (dmodel
== PR_MODEL_LP64
&& (text
[i
] & 0xf0) == 0x40 &&
112 text
[i
+ 1] == 0xff && DT_MODRM_REG(text
[i
+ 2]) == 4)) {
113 dt_dprintf("found a suspected jump table at %s:%lx\n",
124 dt_pid_create_return_probe(struct ps_prochandle
*P
, dtrace_hdl_t
*dtp
,
125 fasttrap_probe_spec_t
*ftp
, const GElf_Sym
*symp
, uint64_t *stret
)
130 pid_t pid
= Pstatus(P
)->pr_pid
;
131 char dmodel
= Pstatus(P
)->pr_dmodel
;
134 * We allocate a few extra bytes at the end so we don't have to check
135 * for overrunning the buffer.
137 if ((text
= calloc(1, symp
->st_size
+ 4)) == NULL
) {
138 dt_dprintf("mr sparkle: malloc() failed\n");
139 return (DT_PROC_ERR
);
142 if (Pread(P
, text
, symp
->st_size
, symp
->st_value
) != symp
->st_size
) {
143 dt_dprintf("mr sparkle: Pread() failed\n");
145 return (DT_PROC_ERR
);
148 ftp
->ftps_type
= DTFTP_RETURN
;
149 ftp
->ftps_pc
= (uintptr_t)symp
->st_value
;
150 ftp
->ftps_size
= (size_t)symp
->st_size
;
154 * If there's a jump table in the function we're only willing to
155 * instrument these specific (and equivalent) instruction sequences:
163 * We do this to avoid accidentally interpreting jump table
164 * offsets as actual instructions.
166 if (dt_pid_has_jump_table(P
, dtp
, text
, ftp
, symp
)) {
167 for (i
= 0, end
= ftp
->ftps_size
; i
< end
; i
+= size
) {
168 size
= dt_instr_size(&text
[i
], dtp
, pid
,
169 symp
->st_value
+ i
, dmodel
);
171 /* bail if we hit an invalid opcode */
175 if (text
[i
] == DT_LEAVE
&& text
[i
+ 1] == DT_RET
) {
176 dt_dprintf("leave/ret at %lx\n", i
+ 1);
177 ftp
->ftps_offs
[ftp
->ftps_noffs
++] = i
+ 1;
179 } else if (text
[i
] == DT_LEAVE
&&
180 text
[i
+ 1] == DT_REP
&& text
[i
+ 2] == DT_RET
) {
181 dt_dprintf("leave/rep ret at %lx\n", i
+ 1);
182 ftp
->ftps_offs
[ftp
->ftps_noffs
++] = i
+ 1;
184 } else if (*(uint16_t *)&text
[i
] == DT_MOVL_EBP_ESP
&&
185 text
[i
+ 2] == DT_POPL_EBP
&&
186 text
[i
+ 3] == DT_RET
) {
187 dt_dprintf("movl/popl/ret at %lx\n", i
+ 3);
188 ftp
->ftps_offs
[ftp
->ftps_noffs
++] = i
+ 3;
190 } else if (*(uint16_t *)&text
[i
] == DT_MOVL_EBP_ESP
&&
191 text
[i
+ 2] == DT_POPL_EBP
&&
192 text
[i
+ 3] == DT_REP
&&
193 text
[i
+ 4] == DT_RET
) {
194 dt_dprintf("movl/popl/rep ret at %lx\n", i
+ 3);
195 ftp
->ftps_offs
[ftp
->ftps_noffs
++] = i
+ 3;
200 for (i
= 0, end
= ftp
->ftps_size
; i
< end
; i
+= size
) {
201 size
= dt_instr_size(&text
[i
], dtp
, pid
,
202 symp
->st_value
+ i
, dmodel
);
204 /* bail if we hit an invalid opcode */
209 if (size
== 1 && text
[i
] == DT_RET
)
213 if (size
== 2 && text
[i
] == DT_REP
&&
214 text
[i
+ 1] == DT_RET
)
218 if (size
== 3 && text
[i
] == DT_RET16
)
221 /* two-byte ret <imm16> */
222 if (size
== 4 && text
[i
] == DT_REP
&&
223 text
[i
+ 1] == DT_RET16
)
226 /* 32-bit displacement jmp outside of the function */
227 if (size
== 5 && text
[i
] == DT_JMP32
&& symp
->st_size
<=
228 (uintptr_t)(i
+ size
+ *(int32_t *)&text
[i
+ 1]))
231 /* 8-bit displacement jmp outside of the function */
232 if (size
== 2 && text
[i
] == DT_JMP8
&& symp
->st_size
<=
233 (uintptr_t)(i
+ size
+ *(int8_t *)&text
[i
+ 1]))
236 /* 32-bit disp. conditional jmp outside of the func. */
237 if (size
== 6 && DT_ISJ32(*(uint16_t *)&text
[i
]) &&
239 (uintptr_t)(i
+ size
+ *(int32_t *)&text
[i
+ 2]))
242 /* 8-bit disp. conditional jmp outside of the func. */
243 if (size
== 2 && DT_ISJ8(text
[i
]) && symp
->st_size
<=
244 (uintptr_t)(i
+ size
+ *(int8_t *)&text
[i
+ 1]))
249 dt_dprintf("return at offset %lx\n", i
);
250 ftp
->ftps_offs
[ftp
->ftps_noffs
++] = i
;
255 if (ftp
->ftps_noffs
> 0) {
256 if (ioctl(dtp
->dt_ftfd
, FASTTRAPIOC_MAKEPROBE
, ftp
) != 0) {
257 dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
259 return (dt_set_errno(dtp
, errno
));
263 return (ftp
->ftps_noffs
);
268 dt_pid_create_offset_probe(struct ps_prochandle
*P
, dtrace_hdl_t
*dtp
,
269 fasttrap_probe_spec_t
*ftp
, const GElf_Sym
*symp
, ulong_t off
)
271 ftp
->ftps_type
= DTFTP_OFFSETS
;
272 ftp
->ftps_pc
= (uintptr_t)symp
->st_value
;
273 ftp
->ftps_size
= (size_t)symp
->st_size
;
276 if (strcmp("-", ftp
->ftps_func
) == 0) {
277 ftp
->ftps_offs
[0] = off
;
282 pid_t pid
= Pstatus(P
)->pr_pid
;
283 char dmodel
= Pstatus(P
)->pr_dmodel
;
285 if ((text
= malloc(symp
->st_size
)) == NULL
) {
286 dt_dprintf("mr sparkle: malloc() failed\n");
287 return (DT_PROC_ERR
);
290 if (Pread(P
, text
, symp
->st_size
, symp
->st_value
) !=
292 dt_dprintf("mr sparkle: Pread() failed\n");
294 return (DT_PROC_ERR
);
298 * We can't instrument offsets in functions with jump tables
299 * as we might interpret a jump table offset as an
302 if (dt_pid_has_jump_table(P
, dtp
, text
, ftp
, symp
)) {
307 for (i
= 0; i
< symp
->st_size
; i
+= size
) {
309 ftp
->ftps_offs
[0] = i
;
314 * If we've passed the desired offset without a
315 * match, then the given offset must not lie on a
316 * instruction boundary.
320 return (DT_PROC_ALIGN
);
323 size
= dt_instr_size(&text
[i
], dtp
, pid
,
324 symp
->st_value
+ i
, dmodel
);
327 * If we hit an invalid instruction, bail as if we
328 * couldn't find the offset.
332 return (DT_PROC_ALIGN
);
339 if (ioctl(dtp
->dt_ftfd
, FASTTRAPIOC_MAKEPROBE
, ftp
) != 0) {
340 dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
342 return (dt_set_errno(dtp
, errno
));
345 return (ftp
->ftps_noffs
);
350 dt_pid_create_glob_offset_probes(struct ps_prochandle
*P
, dtrace_hdl_t
*dtp
,
351 fasttrap_probe_spec_t
*ftp
, const GElf_Sym
*symp
, const char *pattern
)
355 ulong_t i
, end
= symp
->st_size
;
356 pid_t pid
= Pstatus(P
)->pr_pid
;
357 char dmodel
= Pstatus(P
)->pr_dmodel
;
359 ftp
->ftps_type
= DTFTP_OFFSETS
;
360 ftp
->ftps_pc
= (uintptr_t)symp
->st_value
;
361 ftp
->ftps_size
= (size_t)symp
->st_size
;
364 if ((text
= malloc(symp
->st_size
)) == NULL
) {
365 dt_dprintf("mr sparkle: malloc() failed\n");
366 return (DT_PROC_ERR
);
369 if (Pread(P
, text
, symp
->st_size
, symp
->st_value
) != symp
->st_size
) {
370 dt_dprintf("mr sparkle: Pread() failed\n");
372 return (DT_PROC_ERR
);
376 * We can't instrument offsets in functions with jump tables as
377 * we might interpret a jump table offset as an instruction.
379 if (dt_pid_has_jump_table(P
, dtp
, text
, ftp
, symp
)) {
384 if (strcmp("*", pattern
) == 0) {
385 for (i
= 0; i
< end
; i
+= size
) {
386 ftp
->ftps_offs
[ftp
->ftps_noffs
++] = i
;
388 size
= dt_instr_size(&text
[i
], dtp
, pid
,
389 symp
->st_value
+ i
, dmodel
);
391 /* bail if we hit an invalid opcode */
396 char name
[sizeof (i
) * 2 + 1];
398 for (i
= 0; i
< end
; i
+= size
) {
399 (void) snprintf(name
, sizeof (name
), "%x", i
);
400 if (gmatch(name
, pattern
))
401 ftp
->ftps_offs
[ftp
->ftps_noffs
++] = i
;
403 size
= dt_instr_size(&text
[i
], dtp
, pid
,
404 symp
->st_value
+ i
, dmodel
);
406 /* bail if we hit an invalid opcode */
413 if (ftp
->ftps_noffs
> 0) {
414 if (ioctl(dtp
->dt_ftfd
, FASTTRAPIOC_MAKEPROBE
, ftp
) != 0) {
415 dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
417 return (dt_set_errno(dtp
, errno
));
421 return (ftp
->ftps_noffs
);
424 typedef struct dtrace_dis
{
432 dt_getbyte(void *data
)
434 dtrace_dis_t
*dis
= data
;
435 int ret
= *dis
->instr
;
437 if (ret
== FASTTRAP_INSTR
) {
438 fasttrap_instr_query_t instr
;
440 instr
.ftiq_pid
= dis
->pid
;
441 instr
.ftiq_pc
= dis
->addr
;
444 * If we hit a byte that looks like the fasttrap provider's
445 * trap instruction (which doubles as the breakpoint
446 * instruction for debuggers) we need to query the kernel
447 * for the real value. This may just be part of an immediate
448 * value so there's no need to return an error if the
449 * kernel doesn't know about this address.
451 if (ioctl(dis
->dtp
->dt_ftfd
, FASTTRAPIOC_GETINSTR
, &instr
) == 0)
452 ret
= instr
.ftiq_instr
;
462 dt_instr_size(uchar_t
*instr
, dtrace_hdl_t
*dtp
, pid_t pid
, uintptr_t addr
,
474 x86dis
.d86_data
= &data
;
475 x86dis
.d86_get_byte
= dt_getbyte
;
476 x86dis
.d86_check_func
= NULL
;
478 cpu_mode
= (dmodel
== PR_MODEL_ILP32
) ? SIZE32
: SIZE64
;
480 if (dtrace_disx86(&x86dis
, cpu_mode
) != 0)
484 * If the instruction was a single-byte breakpoint, there may be
485 * another debugger attached to this process. The original instruction
486 * can't be recovered so this must fail.
488 if (x86dis
.d86_len
== 1 &&
489 (uchar_t
)x86dis
.d86_bytes
[0] == FASTTRAP_INSTR
)
492 return (x86dis
.d86_len
);