17aa38384SRui Paulo /*
27aa38384SRui Paulo * CDDL HEADER START
37aa38384SRui Paulo *
47aa38384SRui Paulo * The contents of this file are subject to the terms of the
57aa38384SRui Paulo * Common Development and Distribution License (the "License").
67aa38384SRui Paulo * You may not use this file except in compliance with the License.
77aa38384SRui Paulo *
87aa38384SRui Paulo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aa38384SRui Paulo * or http://www.opensolaris.org/os/licensing.
107aa38384SRui Paulo * See the License for the specific language governing permissions
117aa38384SRui Paulo * and limitations under the License.
127aa38384SRui Paulo *
137aa38384SRui Paulo * When distributing Covered Code, include this CDDL HEADER in each
147aa38384SRui Paulo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aa38384SRui Paulo * If applicable, add the following below this CDDL HEADER, with the
167aa38384SRui Paulo * fields enclosed by brackets "[]" replaced with your own identifying
177aa38384SRui Paulo * information: Portions Copyright [yyyy] [name of copyright owner]
187aa38384SRui Paulo *
197aa38384SRui Paulo * CDDL HEADER END
207aa38384SRui Paulo */
217aa38384SRui Paulo
227aa38384SRui Paulo /*
237aa38384SRui Paulo * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247aa38384SRui Paulo * Use is subject to license terms.
257aa38384SRui Paulo */
267aa38384SRui Paulo
27a98ff317SPedro F. Giffuni /*
28a98ff317SPedro F. Giffuni * Copyright (c) 2012 by Delphix. All rights reserved.
29a98ff317SPedro F. Giffuni */
30a98ff317SPedro F. Giffuni
317aa38384SRui Paulo #include <stdlib.h>
327aa38384SRui Paulo #include <assert.h>
337aa38384SRui Paulo #include <errno.h>
347aa38384SRui Paulo #include <string.h>
357aa38384SRui Paulo #include <libgen.h>
367aa38384SRui Paulo
377aa38384SRui Paulo #include <dt_impl.h>
387aa38384SRui Paulo #include <dt_pid.h>
397aa38384SRui Paulo
407aa38384SRui Paulo #include <dis_tables.h>
417aa38384SRui Paulo
42*907b59d7SMark Johnston #ifdef __FreeBSD__
43*907b59d7SMark Johnston #include <libproc.h>
440f2bd1e8SRui Paulo #include <libproc_compat.h>
450f2bd1e8SRui Paulo #endif
460f2bd1e8SRui Paulo
477aa38384SRui Paulo #define DT_POPL_EBP 0x5d
487aa38384SRui Paulo #define DT_RET 0xc3
497aa38384SRui Paulo #define DT_RET16 0xc2
507aa38384SRui Paulo #define DT_LEAVE 0xc9
517aa38384SRui Paulo #define DT_JMP32 0xe9
527aa38384SRui Paulo #define DT_JMP8 0xeb
537aa38384SRui Paulo #define DT_REP 0xf3
547aa38384SRui Paulo
557aa38384SRui Paulo #define DT_MOVL_EBP_ESP 0xe58b
567aa38384SRui Paulo
577aa38384SRui Paulo #define DT_ISJ32(op16) (((op16) & 0xfff0) == 0x0f80)
587aa38384SRui Paulo #define DT_ISJ8(op8) (((op8) & 0xf0) == 0x70)
597aa38384SRui Paulo
607aa38384SRui Paulo #define DT_MODRM_REG(modrm) (((modrm) >> 3) & 0x7)
617aa38384SRui Paulo
627aa38384SRui Paulo static int dt_instr_size(uchar_t *, dtrace_hdl_t *, pid_t, uintptr_t, char);
637aa38384SRui Paulo
647aa38384SRui Paulo /*ARGSUSED*/
657aa38384SRui Paulo int
dt_pid_create_entry_probe(struct ps_prochandle * P,dtrace_hdl_t * dtp,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp)667aa38384SRui Paulo dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
677aa38384SRui Paulo fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
687aa38384SRui Paulo {
697aa38384SRui Paulo ftp->ftps_type = DTFTP_ENTRY;
707aa38384SRui Paulo ftp->ftps_pc = (uintptr_t)symp->st_value;
717aa38384SRui Paulo ftp->ftps_size = (size_t)symp->st_size;
727aa38384SRui Paulo ftp->ftps_noffs = 1;
737aa38384SRui Paulo ftp->ftps_offs[0] = 0;
747aa38384SRui Paulo
757aa38384SRui Paulo if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
767aa38384SRui Paulo dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
777aa38384SRui Paulo strerror(errno));
787aa38384SRui Paulo return (dt_set_errno(dtp, errno));
797aa38384SRui Paulo }
807aa38384SRui Paulo
817aa38384SRui Paulo return (1);
827aa38384SRui Paulo }
837aa38384SRui Paulo
847aa38384SRui Paulo static int
dt_pid_has_jump_table(struct ps_prochandle * P,dtrace_hdl_t * dtp,uint8_t * text,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp)857aa38384SRui Paulo dt_pid_has_jump_table(struct ps_prochandle *P, dtrace_hdl_t *dtp,
867aa38384SRui Paulo uint8_t *text, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
877aa38384SRui Paulo {
887aa38384SRui Paulo ulong_t i;
897aa38384SRui Paulo int size;
90bc96366cSSteven Hartland #ifdef illumos
917aa38384SRui Paulo pid_t pid = Pstatus(P)->pr_pid;
927aa38384SRui Paulo char dmodel = Pstatus(P)->pr_dmodel;
930f2bd1e8SRui Paulo #else
940f2bd1e8SRui Paulo pid_t pid = proc_getpid(P);
95*907b59d7SMark Johnston char dmodel = proc_getmodel(P);
960f2bd1e8SRui Paulo #endif
977aa38384SRui Paulo
987aa38384SRui Paulo /*
997aa38384SRui Paulo * Take a pass through the function looking for a register-dependant
1007aa38384SRui Paulo * jmp instruction. This could be a jump table so we have to be
1017aa38384SRui Paulo * ultra conservative.
1027aa38384SRui Paulo */
1037aa38384SRui Paulo for (i = 0; i < ftp->ftps_size; i += size) {
1047aa38384SRui Paulo size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i,
1057aa38384SRui Paulo dmodel);
1067aa38384SRui Paulo
1077aa38384SRui Paulo /*
1087aa38384SRui Paulo * Assume the worst if we hit an illegal instruction.
1097aa38384SRui Paulo */
1107aa38384SRui Paulo if (size <= 0) {
1117aa38384SRui Paulo dt_dprintf("error at %#lx (assuming jump table)\n", i);
1127aa38384SRui Paulo return (1);
1137aa38384SRui Paulo }
1147aa38384SRui Paulo
1150f2bd1e8SRui Paulo #ifdef notyet
1167aa38384SRui Paulo /*
1177aa38384SRui Paulo * Register-dependant jmp instructions start with a 0xff byte
1187aa38384SRui Paulo * and have the modrm.reg field set to 4. They can have an
1197aa38384SRui Paulo * optional REX prefix on the 64-bit ISA.
1207aa38384SRui Paulo */
1217aa38384SRui Paulo if ((text[i] == 0xff && DT_MODRM_REG(text[i + 1]) == 4) ||
1227aa38384SRui Paulo (dmodel == PR_MODEL_LP64 && (text[i] & 0xf0) == 0x40 &&
1237aa38384SRui Paulo text[i + 1] == 0xff && DT_MODRM_REG(text[i + 2]) == 4)) {
1247aa38384SRui Paulo dt_dprintf("found a suspected jump table at %s:%lx\n",
1257aa38384SRui Paulo ftp->ftps_func, i);
1267aa38384SRui Paulo return (1);
1277aa38384SRui Paulo }
1280f2bd1e8SRui Paulo #endif
1297aa38384SRui Paulo }
1307aa38384SRui Paulo
1317aa38384SRui Paulo return (0);
1327aa38384SRui Paulo }
1337aa38384SRui Paulo
1347aa38384SRui Paulo /*ARGSUSED*/
1357aa38384SRui Paulo int
dt_pid_create_return_probe(struct ps_prochandle * P,dtrace_hdl_t * dtp,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp,uint64_t * stret)1367aa38384SRui Paulo dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
1377aa38384SRui Paulo fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
1387aa38384SRui Paulo {
1397aa38384SRui Paulo uint8_t *text;
1407aa38384SRui Paulo ulong_t i, end;
1417aa38384SRui Paulo int size;
142bc96366cSSteven Hartland #ifdef illumos
1437aa38384SRui Paulo pid_t pid = Pstatus(P)->pr_pid;
1447aa38384SRui Paulo char dmodel = Pstatus(P)->pr_dmodel;
1450f2bd1e8SRui Paulo #else
1460f2bd1e8SRui Paulo pid_t pid = proc_getpid(P);
147*907b59d7SMark Johnston char dmodel = proc_getmodel(P);
1480f2bd1e8SRui Paulo #endif
1497aa38384SRui Paulo
1507aa38384SRui Paulo /*
1517aa38384SRui Paulo * We allocate a few extra bytes at the end so we don't have to check
1527aa38384SRui Paulo * for overrunning the buffer.
1537aa38384SRui Paulo */
1547aa38384SRui Paulo if ((text = calloc(1, symp->st_size + 4)) == NULL) {
1557aa38384SRui Paulo dt_dprintf("mr sparkle: malloc() failed\n");
1567aa38384SRui Paulo return (DT_PROC_ERR);
1577aa38384SRui Paulo }
1587aa38384SRui Paulo
1597aa38384SRui Paulo if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
1607aa38384SRui Paulo dt_dprintf("mr sparkle: Pread() failed\n");
1617aa38384SRui Paulo free(text);
1627aa38384SRui Paulo return (DT_PROC_ERR);
1637aa38384SRui Paulo }
1647aa38384SRui Paulo
1657aa38384SRui Paulo ftp->ftps_type = DTFTP_RETURN;
1667aa38384SRui Paulo ftp->ftps_pc = (uintptr_t)symp->st_value;
1677aa38384SRui Paulo ftp->ftps_size = (size_t)symp->st_size;
1687aa38384SRui Paulo ftp->ftps_noffs = 0;
1697aa38384SRui Paulo
1707aa38384SRui Paulo /*
1717aa38384SRui Paulo * If there's a jump table in the function we're only willing to
1727aa38384SRui Paulo * instrument these specific (and equivalent) instruction sequences:
1737aa38384SRui Paulo * leave
1747aa38384SRui Paulo * [rep] ret
1757aa38384SRui Paulo * and
1767aa38384SRui Paulo * movl %ebp,%esp
1777aa38384SRui Paulo * popl %ebp
1787aa38384SRui Paulo * [rep] ret
1797aa38384SRui Paulo *
1807aa38384SRui Paulo * We do this to avoid accidentally interpreting jump table
1817aa38384SRui Paulo * offsets as actual instructions.
1827aa38384SRui Paulo */
1837aa38384SRui Paulo if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
1847aa38384SRui Paulo for (i = 0, end = ftp->ftps_size; i < end; i += size) {
1857aa38384SRui Paulo size = dt_instr_size(&text[i], dtp, pid,
1867aa38384SRui Paulo symp->st_value + i, dmodel);
1877aa38384SRui Paulo
1887aa38384SRui Paulo /* bail if we hit an invalid opcode */
1897aa38384SRui Paulo if (size <= 0)
1907aa38384SRui Paulo break;
1917aa38384SRui Paulo
1927aa38384SRui Paulo if (text[i] == DT_LEAVE && text[i + 1] == DT_RET) {
1937aa38384SRui Paulo dt_dprintf("leave/ret at %lx\n", i + 1);
1947aa38384SRui Paulo ftp->ftps_offs[ftp->ftps_noffs++] = i + 1;
1957aa38384SRui Paulo size = 2;
1967aa38384SRui Paulo } else if (text[i] == DT_LEAVE &&
1977aa38384SRui Paulo text[i + 1] == DT_REP && text[i + 2] == DT_RET) {
1987aa38384SRui Paulo dt_dprintf("leave/rep ret at %lx\n", i + 1);
1997aa38384SRui Paulo ftp->ftps_offs[ftp->ftps_noffs++] = i + 1;
2007aa38384SRui Paulo size = 3;
2017aa38384SRui Paulo } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP &&
2027aa38384SRui Paulo text[i + 2] == DT_POPL_EBP &&
2037aa38384SRui Paulo text[i + 3] == DT_RET) {
2047aa38384SRui Paulo dt_dprintf("movl/popl/ret at %lx\n", i + 3);
2057aa38384SRui Paulo ftp->ftps_offs[ftp->ftps_noffs++] = i + 3;
2067aa38384SRui Paulo size = 4;
2077aa38384SRui Paulo } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP &&
2087aa38384SRui Paulo text[i + 2] == DT_POPL_EBP &&
2097aa38384SRui Paulo text[i + 3] == DT_REP &&
2107aa38384SRui Paulo text[i + 4] == DT_RET) {
2117aa38384SRui Paulo dt_dprintf("movl/popl/rep ret at %lx\n", i + 3);
2127aa38384SRui Paulo ftp->ftps_offs[ftp->ftps_noffs++] = i + 3;
2137aa38384SRui Paulo size = 5;
2147aa38384SRui Paulo }
2157aa38384SRui Paulo }
2167aa38384SRui Paulo } else {
2177aa38384SRui Paulo for (i = 0, end = ftp->ftps_size; i < end; i += size) {
2187aa38384SRui Paulo size = dt_instr_size(&text[i], dtp, pid,
2197aa38384SRui Paulo symp->st_value + i, dmodel);
2207aa38384SRui Paulo
2217aa38384SRui Paulo /* bail if we hit an invalid opcode */
2227aa38384SRui Paulo if (size <= 0)
2237aa38384SRui Paulo break;
2247aa38384SRui Paulo
2257aa38384SRui Paulo /* ordinary ret */
2267aa38384SRui Paulo if (size == 1 && text[i] == DT_RET)
2277aa38384SRui Paulo goto is_ret;
2287aa38384SRui Paulo
2297aa38384SRui Paulo /* two-byte ret */
2307aa38384SRui Paulo if (size == 2 && text[i] == DT_REP &&
2317aa38384SRui Paulo text[i + 1] == DT_RET)
2327aa38384SRui Paulo goto is_ret;
2337aa38384SRui Paulo
2347aa38384SRui Paulo /* ret <imm16> */
2357aa38384SRui Paulo if (size == 3 && text[i] == DT_RET16)
2367aa38384SRui Paulo goto is_ret;
2377aa38384SRui Paulo
2387aa38384SRui Paulo /* two-byte ret <imm16> */
2397aa38384SRui Paulo if (size == 4 && text[i] == DT_REP &&
2407aa38384SRui Paulo text[i + 1] == DT_RET16)
2417aa38384SRui Paulo goto is_ret;
2427aa38384SRui Paulo
2437aa38384SRui Paulo /* 32-bit displacement jmp outside of the function */
2447aa38384SRui Paulo if (size == 5 && text[i] == DT_JMP32 && symp->st_size <=
2457aa38384SRui Paulo (uintptr_t)(i + size + *(int32_t *)&text[i + 1]))
2467aa38384SRui Paulo goto is_ret;
2477aa38384SRui Paulo
2487aa38384SRui Paulo /* 8-bit displacement jmp outside of the function */
2497aa38384SRui Paulo if (size == 2 && text[i] == DT_JMP8 && symp->st_size <=
2507aa38384SRui Paulo (uintptr_t)(i + size + *(int8_t *)&text[i + 1]))
2517aa38384SRui Paulo goto is_ret;
2527aa38384SRui Paulo
2537aa38384SRui Paulo /* 32-bit disp. conditional jmp outside of the func. */
2547aa38384SRui Paulo if (size == 6 && DT_ISJ32(*(uint16_t *)&text[i]) &&
2557aa38384SRui Paulo symp->st_size <=
2567aa38384SRui Paulo (uintptr_t)(i + size + *(int32_t *)&text[i + 2]))
2577aa38384SRui Paulo goto is_ret;
2587aa38384SRui Paulo
2597aa38384SRui Paulo /* 8-bit disp. conditional jmp outside of the func. */
2607aa38384SRui Paulo if (size == 2 && DT_ISJ8(text[i]) && symp->st_size <=
2617aa38384SRui Paulo (uintptr_t)(i + size + *(int8_t *)&text[i + 1]))
2627aa38384SRui Paulo goto is_ret;
2637aa38384SRui Paulo
2647aa38384SRui Paulo continue;
2657aa38384SRui Paulo is_ret:
2667aa38384SRui Paulo dt_dprintf("return at offset %lx\n", i);
2677aa38384SRui Paulo ftp->ftps_offs[ftp->ftps_noffs++] = i;
2687aa38384SRui Paulo }
2697aa38384SRui Paulo }
2707aa38384SRui Paulo
2717aa38384SRui Paulo free(text);
2727aa38384SRui Paulo if (ftp->ftps_noffs > 0) {
2737aa38384SRui Paulo if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
2747aa38384SRui Paulo dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
2757aa38384SRui Paulo strerror(errno));
2767aa38384SRui Paulo return (dt_set_errno(dtp, errno));
2777aa38384SRui Paulo }
2787aa38384SRui Paulo }
2797aa38384SRui Paulo
2807aa38384SRui Paulo return (ftp->ftps_noffs);
2817aa38384SRui Paulo }
2827aa38384SRui Paulo
2837aa38384SRui Paulo /*ARGSUSED*/
2847aa38384SRui Paulo int
dt_pid_create_offset_probe(struct ps_prochandle * P,dtrace_hdl_t * dtp,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp,ulong_t off)2857aa38384SRui Paulo dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
2867aa38384SRui Paulo fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
2877aa38384SRui Paulo {
2887aa38384SRui Paulo ftp->ftps_type = DTFTP_OFFSETS;
2897aa38384SRui Paulo ftp->ftps_pc = (uintptr_t)symp->st_value;
2907aa38384SRui Paulo ftp->ftps_size = (size_t)symp->st_size;
2917aa38384SRui Paulo ftp->ftps_noffs = 1;
2927aa38384SRui Paulo
2937aa38384SRui Paulo if (strcmp("-", ftp->ftps_func) == 0) {
2947aa38384SRui Paulo ftp->ftps_offs[0] = off;
2957aa38384SRui Paulo } else {
2967aa38384SRui Paulo uint8_t *text;
2977aa38384SRui Paulo ulong_t i;
2987aa38384SRui Paulo int size;
299bc96366cSSteven Hartland #ifdef illumos
3007aa38384SRui Paulo pid_t pid = Pstatus(P)->pr_pid;
3017aa38384SRui Paulo char dmodel = Pstatus(P)->pr_dmodel;
3020f2bd1e8SRui Paulo #else
3030f2bd1e8SRui Paulo pid_t pid = proc_getpid(P);
304*907b59d7SMark Johnston char dmodel = proc_getmodel(P);
3050f2bd1e8SRui Paulo #endif
3067aa38384SRui Paulo
3077aa38384SRui Paulo if ((text = malloc(symp->st_size)) == NULL) {
3087aa38384SRui Paulo dt_dprintf("mr sparkle: malloc() failed\n");
3097aa38384SRui Paulo return (DT_PROC_ERR);
3107aa38384SRui Paulo }
3117aa38384SRui Paulo
3127aa38384SRui Paulo if (Pread(P, text, symp->st_size, symp->st_value) !=
3137aa38384SRui Paulo symp->st_size) {
3147aa38384SRui Paulo dt_dprintf("mr sparkle: Pread() failed\n");
3157aa38384SRui Paulo free(text);
3167aa38384SRui Paulo return (DT_PROC_ERR);
3177aa38384SRui Paulo }
3187aa38384SRui Paulo
3197aa38384SRui Paulo /*
3207aa38384SRui Paulo * We can't instrument offsets in functions with jump tables
3217aa38384SRui Paulo * as we might interpret a jump table offset as an
3227aa38384SRui Paulo * instruction.
3237aa38384SRui Paulo */
3247aa38384SRui Paulo if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
3257aa38384SRui Paulo free(text);
3267aa38384SRui Paulo return (0);
3277aa38384SRui Paulo }
3287aa38384SRui Paulo
3297aa38384SRui Paulo for (i = 0; i < symp->st_size; i += size) {
3307aa38384SRui Paulo if (i == off) {
3317aa38384SRui Paulo ftp->ftps_offs[0] = i;
3327aa38384SRui Paulo break;
3337aa38384SRui Paulo }
3347aa38384SRui Paulo
3357aa38384SRui Paulo /*
3367aa38384SRui Paulo * If we've passed the desired offset without a
3377aa38384SRui Paulo * match, then the given offset must not lie on a
3387aa38384SRui Paulo * instruction boundary.
3397aa38384SRui Paulo */
3407aa38384SRui Paulo if (i > off) {
3417aa38384SRui Paulo free(text);
3427aa38384SRui Paulo return (DT_PROC_ALIGN);
3437aa38384SRui Paulo }
3447aa38384SRui Paulo
3457aa38384SRui Paulo size = dt_instr_size(&text[i], dtp, pid,
3467aa38384SRui Paulo symp->st_value + i, dmodel);
3477aa38384SRui Paulo
3487aa38384SRui Paulo /*
3497aa38384SRui Paulo * If we hit an invalid instruction, bail as if we
3507aa38384SRui Paulo * couldn't find the offset.
3517aa38384SRui Paulo */
3527aa38384SRui Paulo if (size <= 0) {
3537aa38384SRui Paulo free(text);
3547aa38384SRui Paulo return (DT_PROC_ALIGN);
3557aa38384SRui Paulo }
3567aa38384SRui Paulo }
3577aa38384SRui Paulo
3587aa38384SRui Paulo free(text);
3597aa38384SRui Paulo }
3607aa38384SRui Paulo
3617aa38384SRui Paulo if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
3627aa38384SRui Paulo dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
3637aa38384SRui Paulo strerror(errno));
3647aa38384SRui Paulo return (dt_set_errno(dtp, errno));
3657aa38384SRui Paulo }
3667aa38384SRui Paulo
3677aa38384SRui Paulo return (ftp->ftps_noffs);
3687aa38384SRui Paulo }
3697aa38384SRui Paulo
3707aa38384SRui Paulo /*ARGSUSED*/
3717aa38384SRui Paulo int
dt_pid_create_glob_offset_probes(struct ps_prochandle * P,dtrace_hdl_t * dtp,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp,const char * pattern)3727aa38384SRui Paulo dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
3737aa38384SRui Paulo fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
3747aa38384SRui Paulo {
3757aa38384SRui Paulo uint8_t *text;
3767aa38384SRui Paulo int size;
3777aa38384SRui Paulo ulong_t i, end = symp->st_size;
378bc96366cSSteven Hartland #ifdef illumos
3797aa38384SRui Paulo pid_t pid = Pstatus(P)->pr_pid;
3807aa38384SRui Paulo char dmodel = Pstatus(P)->pr_dmodel;
3810f2bd1e8SRui Paulo #else
3820f2bd1e8SRui Paulo pid_t pid = proc_getpid(P);
383*907b59d7SMark Johnston char dmodel = proc_getmodel(P);
3840f2bd1e8SRui Paulo #endif
3857aa38384SRui Paulo
3867aa38384SRui Paulo ftp->ftps_type = DTFTP_OFFSETS;
3877aa38384SRui Paulo ftp->ftps_pc = (uintptr_t)symp->st_value;
3887aa38384SRui Paulo ftp->ftps_size = (size_t)symp->st_size;
3897aa38384SRui Paulo ftp->ftps_noffs = 0;
3907aa38384SRui Paulo
3917aa38384SRui Paulo if ((text = malloc(symp->st_size)) == NULL) {
3927aa38384SRui Paulo dt_dprintf("mr sparkle: malloc() failed\n");
3937aa38384SRui Paulo return (DT_PROC_ERR);
3947aa38384SRui Paulo }
3957aa38384SRui Paulo
3967aa38384SRui Paulo if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
3977aa38384SRui Paulo dt_dprintf("mr sparkle: Pread() failed\n");
3987aa38384SRui Paulo free(text);
3997aa38384SRui Paulo return (DT_PROC_ERR);
4007aa38384SRui Paulo }
4017aa38384SRui Paulo
4027aa38384SRui Paulo /*
4037aa38384SRui Paulo * We can't instrument offsets in functions with jump tables as
4047aa38384SRui Paulo * we might interpret a jump table offset as an instruction.
4057aa38384SRui Paulo */
4067aa38384SRui Paulo if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
4077aa38384SRui Paulo free(text);
4087aa38384SRui Paulo return (0);
4097aa38384SRui Paulo }
4107aa38384SRui Paulo
4117aa38384SRui Paulo if (strcmp("*", pattern) == 0) {
4127aa38384SRui Paulo for (i = 0; i < end; i += size) {
4137aa38384SRui Paulo ftp->ftps_offs[ftp->ftps_noffs++] = i;
4147aa38384SRui Paulo
4157aa38384SRui Paulo size = dt_instr_size(&text[i], dtp, pid,
4167aa38384SRui Paulo symp->st_value + i, dmodel);
4177aa38384SRui Paulo
4187aa38384SRui Paulo /* bail if we hit an invalid opcode */
4197aa38384SRui Paulo if (size <= 0)
4207aa38384SRui Paulo break;
4217aa38384SRui Paulo }
4227aa38384SRui Paulo } else {
4237aa38384SRui Paulo char name[sizeof (i) * 2 + 1];
4247aa38384SRui Paulo
4257aa38384SRui Paulo for (i = 0; i < end; i += size) {
426bb15ca60SDimitry Andric (void) snprintf(name, sizeof (name), "%lx", i);
4277aa38384SRui Paulo if (gmatch(name, pattern))
4287aa38384SRui Paulo ftp->ftps_offs[ftp->ftps_noffs++] = i;
4297aa38384SRui Paulo
4307aa38384SRui Paulo size = dt_instr_size(&text[i], dtp, pid,
4317aa38384SRui Paulo symp->st_value + i, dmodel);
4327aa38384SRui Paulo
4337aa38384SRui Paulo /* bail if we hit an invalid opcode */
4347aa38384SRui Paulo if (size <= 0)
4357aa38384SRui Paulo break;
4367aa38384SRui Paulo }
4377aa38384SRui Paulo }
4387aa38384SRui Paulo
4397aa38384SRui Paulo free(text);
4407aa38384SRui Paulo if (ftp->ftps_noffs > 0) {
4417aa38384SRui Paulo if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
4427aa38384SRui Paulo dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
4437aa38384SRui Paulo strerror(errno));
4447aa38384SRui Paulo return (dt_set_errno(dtp, errno));
4457aa38384SRui Paulo }
4467aa38384SRui Paulo }
4477aa38384SRui Paulo
4487aa38384SRui Paulo return (ftp->ftps_noffs);
4497aa38384SRui Paulo }
4507aa38384SRui Paulo
4517aa38384SRui Paulo typedef struct dtrace_dis {
4527aa38384SRui Paulo uchar_t *instr;
4537aa38384SRui Paulo dtrace_hdl_t *dtp;
4547aa38384SRui Paulo pid_t pid;
4557aa38384SRui Paulo uintptr_t addr;
4567aa38384SRui Paulo } dtrace_dis_t;
4577aa38384SRui Paulo
4587aa38384SRui Paulo static int
dt_getbyte(void * data)4597aa38384SRui Paulo dt_getbyte(void *data)
4607aa38384SRui Paulo {
4617aa38384SRui Paulo dtrace_dis_t *dis = data;
4627aa38384SRui Paulo int ret = *dis->instr;
4637aa38384SRui Paulo
4647aa38384SRui Paulo if (ret == FASTTRAP_INSTR) {
4657aa38384SRui Paulo fasttrap_instr_query_t instr;
4667aa38384SRui Paulo
4677aa38384SRui Paulo instr.ftiq_pid = dis->pid;
4687aa38384SRui Paulo instr.ftiq_pc = dis->addr;
4697aa38384SRui Paulo
4707aa38384SRui Paulo /*
4717aa38384SRui Paulo * If we hit a byte that looks like the fasttrap provider's
4727aa38384SRui Paulo * trap instruction (which doubles as the breakpoint
4737aa38384SRui Paulo * instruction for debuggers) we need to query the kernel
4747aa38384SRui Paulo * for the real value. This may just be part of an immediate
4757aa38384SRui Paulo * value so there's no need to return an error if the
4767aa38384SRui Paulo * kernel doesn't know about this address.
4777aa38384SRui Paulo */
4787aa38384SRui Paulo if (ioctl(dis->dtp->dt_ftfd, FASTTRAPIOC_GETINSTR, &instr) == 0)
4797aa38384SRui Paulo ret = instr.ftiq_instr;
4807aa38384SRui Paulo }
4817aa38384SRui Paulo
4827aa38384SRui Paulo dis->addr++;
4837aa38384SRui Paulo dis->instr++;
4847aa38384SRui Paulo
4857aa38384SRui Paulo return (ret);
4867aa38384SRui Paulo }
4877aa38384SRui Paulo
4887aa38384SRui Paulo static int
dt_instr_size(uchar_t * instr,dtrace_hdl_t * dtp,pid_t pid,uintptr_t addr,char dmodel)4897aa38384SRui Paulo dt_instr_size(uchar_t *instr, dtrace_hdl_t *dtp, pid_t pid, uintptr_t addr,
4907aa38384SRui Paulo char dmodel)
4917aa38384SRui Paulo {
4927aa38384SRui Paulo dtrace_dis_t data;
4937aa38384SRui Paulo dis86_t x86dis;
4947aa38384SRui Paulo uint_t cpu_mode;
4957aa38384SRui Paulo
4967aa38384SRui Paulo data.instr = instr;
4977aa38384SRui Paulo data.dtp = dtp;
4987aa38384SRui Paulo data.pid = pid;
4997aa38384SRui Paulo data.addr = addr;
5007aa38384SRui Paulo
5017aa38384SRui Paulo x86dis.d86_data = &data;
5027aa38384SRui Paulo x86dis.d86_get_byte = dt_getbyte;
5037aa38384SRui Paulo x86dis.d86_check_func = NULL;
5047aa38384SRui Paulo
5057aa38384SRui Paulo cpu_mode = (dmodel == PR_MODEL_ILP32) ? SIZE32 : SIZE64;
5067aa38384SRui Paulo
5077aa38384SRui Paulo if (dtrace_disx86(&x86dis, cpu_mode) != 0)
5087aa38384SRui Paulo return (-1);
5097aa38384SRui Paulo
5107aa38384SRui Paulo /*
5117aa38384SRui Paulo * If the instruction was a single-byte breakpoint, there may be
5127aa38384SRui Paulo * another debugger attached to this process. The original instruction
5137aa38384SRui Paulo * can't be recovered so this must fail.
5147aa38384SRui Paulo */
515a98ff317SPedro F. Giffuni if (x86dis.d86_len == 1 &&
516a98ff317SPedro F. Giffuni (uchar_t)x86dis.d86_bytes[0] == FASTTRAP_INSTR)
5177aa38384SRui Paulo return (-1);
5187aa38384SRui Paulo
5197aa38384SRui Paulo return (x86dis.d86_len);
5207aa38384SRui Paulo }
521