1210198Srpaulo/* 2210198Srpaulo * CDDL HEADER START 3210198Srpaulo * 4210198Srpaulo * The contents of this file are subject to the terms of the 5210198Srpaulo * Common Development and Distribution License (the "License"). 6210198Srpaulo * You may not use this file except in compliance with the License. 7210198Srpaulo * 8210198Srpaulo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9210198Srpaulo * or http://www.opensolaris.org/os/licensing. 10210198Srpaulo * See the License for the specific language governing permissions 11210198Srpaulo * and limitations under the License. 12210198Srpaulo * 13210198Srpaulo * When distributing Covered Code, include this CDDL HEADER in each 14210198Srpaulo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15210198Srpaulo * If applicable, add the following below this CDDL HEADER, with the 16210198Srpaulo * fields enclosed by brackets "[]" replaced with your own identifying 17210198Srpaulo * information: Portions Copyright [yyyy] [name of copyright owner] 18210198Srpaulo * 19210198Srpaulo * CDDL HEADER END 20210198Srpaulo */ 21210198Srpaulo 22210198Srpaulo/* 23210198Srpaulo * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24210198Srpaulo * Use is subject to license terms. 25210198Srpaulo */ 26210198Srpaulo 27253725Spfg/* 28253725Spfg * Copyright (c) 2012 by Delphix. All rights reserved. 29253725Spfg */ 30253725Spfg 31210198Srpaulo#include <stdlib.h> 32210198Srpaulo#include <assert.h> 33210198Srpaulo#include <errno.h> 34210198Srpaulo#include <string.h> 35210198Srpaulo#include <libgen.h> 36210198Srpaulo 37210198Srpaulo#include <dt_impl.h> 38210198Srpaulo#include <dt_pid.h> 39210198Srpaulo 40210198Srpaulo#include <dis_tables.h> 41210198Srpaulo 42211554Srpaulo#if !defined(sun) 43211554Srpaulo#define PR_MODEL_ILP32 1 44211554Srpaulo#define PR_MODEL_LP64 2 45211554Srpaulo#include <libproc_compat.h> 46211554Srpaulo#endif 47211554Srpaulo 48210198Srpaulo#define DT_POPL_EBP 0x5d 49210198Srpaulo#define DT_RET 0xc3 50210198Srpaulo#define DT_RET16 0xc2 51210198Srpaulo#define DT_LEAVE 0xc9 52210198Srpaulo#define DT_JMP32 0xe9 53210198Srpaulo#define DT_JMP8 0xeb 54210198Srpaulo#define DT_REP 0xf3 55210198Srpaulo 56210198Srpaulo#define DT_MOVL_EBP_ESP 0xe58b 57210198Srpaulo 58210198Srpaulo#define DT_ISJ32(op16) (((op16) & 0xfff0) == 0x0f80) 59210198Srpaulo#define DT_ISJ8(op8) (((op8) & 0xf0) == 0x70) 60210198Srpaulo 61210198Srpaulo#define DT_MODRM_REG(modrm) (((modrm) >> 3) & 0x7) 62210198Srpaulo 63210198Srpaulostatic int dt_instr_size(uchar_t *, dtrace_hdl_t *, pid_t, uintptr_t, char); 64210198Srpaulo 65210198Srpaulo/*ARGSUSED*/ 66210198Srpauloint 67210198Srpaulodt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 68210198Srpaulo fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) 69210198Srpaulo{ 70210198Srpaulo ftp->ftps_type = DTFTP_ENTRY; 71210198Srpaulo ftp->ftps_pc = (uintptr_t)symp->st_value; 72210198Srpaulo ftp->ftps_size = (size_t)symp->st_size; 73210198Srpaulo ftp->ftps_noffs = 1; 74210198Srpaulo ftp->ftps_offs[0] = 0; 75210198Srpaulo 76210198Srpaulo if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 77210198Srpaulo dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 78210198Srpaulo strerror(errno)); 79210198Srpaulo return (dt_set_errno(dtp, errno)); 80210198Srpaulo } 81210198Srpaulo 82210198Srpaulo return (1); 83210198Srpaulo} 84210198Srpaulo 85210198Srpaulostatic int 86210198Srpaulodt_pid_has_jump_table(struct ps_prochandle *P, dtrace_hdl_t *dtp, 87210198Srpaulo uint8_t *text, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) 88210198Srpaulo{ 89210198Srpaulo ulong_t i; 90210198Srpaulo int size; 91211554Srpaulo#if defined(sun) 92210198Srpaulo pid_t pid = Pstatus(P)->pr_pid; 93210198Srpaulo char dmodel = Pstatus(P)->pr_dmodel; 94211554Srpaulo#else 95211554Srpaulo pid_t pid = proc_getpid(P); 96211554Srpaulo#if __i386__ 97211554Srpaulo char dmodel = PR_MODEL_ILP32; 98211554Srpaulo#elif __amd64__ 99211554Srpaulo char dmodel = PR_MODEL_LP64; 100211554Srpaulo#endif 101211554Srpaulo#endif 102210198Srpaulo 103210198Srpaulo /* 104210198Srpaulo * Take a pass through the function looking for a register-dependant 105210198Srpaulo * jmp instruction. This could be a jump table so we have to be 106210198Srpaulo * ultra conservative. 107210198Srpaulo */ 108210198Srpaulo for (i = 0; i < ftp->ftps_size; i += size) { 109210198Srpaulo size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, 110210198Srpaulo dmodel); 111210198Srpaulo 112210198Srpaulo /* 113210198Srpaulo * Assume the worst if we hit an illegal instruction. 114210198Srpaulo */ 115210198Srpaulo if (size <= 0) { 116210198Srpaulo dt_dprintf("error at %#lx (assuming jump table)\n", i); 117210198Srpaulo return (1); 118210198Srpaulo } 119210198Srpaulo 120211554Srpaulo#ifdef notyet 121210198Srpaulo /* 122210198Srpaulo * Register-dependant jmp instructions start with a 0xff byte 123210198Srpaulo * and have the modrm.reg field set to 4. They can have an 124210198Srpaulo * optional REX prefix on the 64-bit ISA. 125210198Srpaulo */ 126210198Srpaulo if ((text[i] == 0xff && DT_MODRM_REG(text[i + 1]) == 4) || 127210198Srpaulo (dmodel == PR_MODEL_LP64 && (text[i] & 0xf0) == 0x40 && 128210198Srpaulo text[i + 1] == 0xff && DT_MODRM_REG(text[i + 2]) == 4)) { 129210198Srpaulo dt_dprintf("found a suspected jump table at %s:%lx\n", 130210198Srpaulo ftp->ftps_func, i); 131210198Srpaulo return (1); 132210198Srpaulo } 133211554Srpaulo#endif 134210198Srpaulo } 135210198Srpaulo 136210198Srpaulo return (0); 137210198Srpaulo} 138210198Srpaulo 139210198Srpaulo/*ARGSUSED*/ 140210198Srpauloint 141210198Srpaulodt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 142210198Srpaulo fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) 143210198Srpaulo{ 144210198Srpaulo uint8_t *text; 145210198Srpaulo ulong_t i, end; 146210198Srpaulo int size; 147211554Srpaulo#if defined(sun) 148210198Srpaulo pid_t pid = Pstatus(P)->pr_pid; 149210198Srpaulo char dmodel = Pstatus(P)->pr_dmodel; 150211554Srpaulo#else 151211554Srpaulo pid_t pid = proc_getpid(P); 152211554Srpaulo#if __i386__ 153211554Srpaulo char dmodel = PR_MODEL_ILP32; 154211554Srpaulo#elif __amd64__ 155211554Srpaulo char dmodel = PR_MODEL_LP64; 156211554Srpaulo#endif 157211554Srpaulo#endif 158210198Srpaulo 159210198Srpaulo /* 160210198Srpaulo * We allocate a few extra bytes at the end so we don't have to check 161210198Srpaulo * for overrunning the buffer. 162210198Srpaulo */ 163210198Srpaulo if ((text = calloc(1, symp->st_size + 4)) == NULL) { 164210198Srpaulo dt_dprintf("mr sparkle: malloc() failed\n"); 165210198Srpaulo return (DT_PROC_ERR); 166210198Srpaulo } 167210198Srpaulo 168210198Srpaulo if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { 169210198Srpaulo dt_dprintf("mr sparkle: Pread() failed\n"); 170210198Srpaulo free(text); 171210198Srpaulo return (DT_PROC_ERR); 172210198Srpaulo } 173210198Srpaulo 174210198Srpaulo ftp->ftps_type = DTFTP_RETURN; 175210198Srpaulo ftp->ftps_pc = (uintptr_t)symp->st_value; 176210198Srpaulo ftp->ftps_size = (size_t)symp->st_size; 177210198Srpaulo ftp->ftps_noffs = 0; 178210198Srpaulo 179210198Srpaulo /* 180210198Srpaulo * If there's a jump table in the function we're only willing to 181210198Srpaulo * instrument these specific (and equivalent) instruction sequences: 182210198Srpaulo * leave 183210198Srpaulo * [rep] ret 184210198Srpaulo * and 185210198Srpaulo * movl %ebp,%esp 186210198Srpaulo * popl %ebp 187210198Srpaulo * [rep] ret 188210198Srpaulo * 189210198Srpaulo * We do this to avoid accidentally interpreting jump table 190210198Srpaulo * offsets as actual instructions. 191210198Srpaulo */ 192210198Srpaulo if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { 193210198Srpaulo for (i = 0, end = ftp->ftps_size; i < end; i += size) { 194210198Srpaulo size = dt_instr_size(&text[i], dtp, pid, 195210198Srpaulo symp->st_value + i, dmodel); 196210198Srpaulo 197210198Srpaulo /* bail if we hit an invalid opcode */ 198210198Srpaulo if (size <= 0) 199210198Srpaulo break; 200210198Srpaulo 201210198Srpaulo if (text[i] == DT_LEAVE && text[i + 1] == DT_RET) { 202210198Srpaulo dt_dprintf("leave/ret at %lx\n", i + 1); 203210198Srpaulo ftp->ftps_offs[ftp->ftps_noffs++] = i + 1; 204210198Srpaulo size = 2; 205210198Srpaulo } else if (text[i] == DT_LEAVE && 206210198Srpaulo text[i + 1] == DT_REP && text[i + 2] == DT_RET) { 207210198Srpaulo dt_dprintf("leave/rep ret at %lx\n", i + 1); 208210198Srpaulo ftp->ftps_offs[ftp->ftps_noffs++] = i + 1; 209210198Srpaulo size = 3; 210210198Srpaulo } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP && 211210198Srpaulo text[i + 2] == DT_POPL_EBP && 212210198Srpaulo text[i + 3] == DT_RET) { 213210198Srpaulo dt_dprintf("movl/popl/ret at %lx\n", i + 3); 214210198Srpaulo ftp->ftps_offs[ftp->ftps_noffs++] = i + 3; 215210198Srpaulo size = 4; 216210198Srpaulo } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP && 217210198Srpaulo text[i + 2] == DT_POPL_EBP && 218210198Srpaulo text[i + 3] == DT_REP && 219210198Srpaulo text[i + 4] == DT_RET) { 220210198Srpaulo dt_dprintf("movl/popl/rep ret at %lx\n", i + 3); 221210198Srpaulo ftp->ftps_offs[ftp->ftps_noffs++] = i + 3; 222210198Srpaulo size = 5; 223210198Srpaulo } 224210198Srpaulo } 225210198Srpaulo } else { 226210198Srpaulo for (i = 0, end = ftp->ftps_size; i < end; i += size) { 227210198Srpaulo size = dt_instr_size(&text[i], dtp, pid, 228210198Srpaulo symp->st_value + i, dmodel); 229210198Srpaulo 230210198Srpaulo /* bail if we hit an invalid opcode */ 231210198Srpaulo if (size <= 0) 232210198Srpaulo break; 233210198Srpaulo 234210198Srpaulo /* ordinary ret */ 235210198Srpaulo if (size == 1 && text[i] == DT_RET) 236210198Srpaulo goto is_ret; 237210198Srpaulo 238210198Srpaulo /* two-byte ret */ 239210198Srpaulo if (size == 2 && text[i] == DT_REP && 240210198Srpaulo text[i + 1] == DT_RET) 241210198Srpaulo goto is_ret; 242210198Srpaulo 243210198Srpaulo /* ret <imm16> */ 244210198Srpaulo if (size == 3 && text[i] == DT_RET16) 245210198Srpaulo goto is_ret; 246210198Srpaulo 247210198Srpaulo /* two-byte ret <imm16> */ 248210198Srpaulo if (size == 4 && text[i] == DT_REP && 249210198Srpaulo text[i + 1] == DT_RET16) 250210198Srpaulo goto is_ret; 251210198Srpaulo 252210198Srpaulo /* 32-bit displacement jmp outside of the function */ 253210198Srpaulo if (size == 5 && text[i] == DT_JMP32 && symp->st_size <= 254210198Srpaulo (uintptr_t)(i + size + *(int32_t *)&text[i + 1])) 255210198Srpaulo goto is_ret; 256210198Srpaulo 257210198Srpaulo /* 8-bit displacement jmp outside of the function */ 258210198Srpaulo if (size == 2 && text[i] == DT_JMP8 && symp->st_size <= 259210198Srpaulo (uintptr_t)(i + size + *(int8_t *)&text[i + 1])) 260210198Srpaulo goto is_ret; 261210198Srpaulo 262210198Srpaulo /* 32-bit disp. conditional jmp outside of the func. */ 263210198Srpaulo if (size == 6 && DT_ISJ32(*(uint16_t *)&text[i]) && 264210198Srpaulo symp->st_size <= 265210198Srpaulo (uintptr_t)(i + size + *(int32_t *)&text[i + 2])) 266210198Srpaulo goto is_ret; 267210198Srpaulo 268210198Srpaulo /* 8-bit disp. conditional jmp outside of the func. */ 269210198Srpaulo if (size == 2 && DT_ISJ8(text[i]) && symp->st_size <= 270210198Srpaulo (uintptr_t)(i + size + *(int8_t *)&text[i + 1])) 271210198Srpaulo goto is_ret; 272210198Srpaulo 273210198Srpaulo continue; 274210198Srpaulois_ret: 275210198Srpaulo dt_dprintf("return at offset %lx\n", i); 276210198Srpaulo ftp->ftps_offs[ftp->ftps_noffs++] = i; 277210198Srpaulo } 278210198Srpaulo } 279210198Srpaulo 280210198Srpaulo free(text); 281210198Srpaulo if (ftp->ftps_noffs > 0) { 282210198Srpaulo if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 283210198Srpaulo dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 284210198Srpaulo strerror(errno)); 285210198Srpaulo return (dt_set_errno(dtp, errno)); 286210198Srpaulo } 287210198Srpaulo } 288210198Srpaulo 289210198Srpaulo return (ftp->ftps_noffs); 290210198Srpaulo} 291210198Srpaulo 292210198Srpaulo/*ARGSUSED*/ 293210198Srpauloint 294210198Srpaulodt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 295210198Srpaulo fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off) 296210198Srpaulo{ 297210198Srpaulo ftp->ftps_type = DTFTP_OFFSETS; 298210198Srpaulo ftp->ftps_pc = (uintptr_t)symp->st_value; 299210198Srpaulo ftp->ftps_size = (size_t)symp->st_size; 300210198Srpaulo ftp->ftps_noffs = 1; 301210198Srpaulo 302210198Srpaulo if (strcmp("-", ftp->ftps_func) == 0) { 303210198Srpaulo ftp->ftps_offs[0] = off; 304210198Srpaulo } else { 305210198Srpaulo uint8_t *text; 306210198Srpaulo ulong_t i; 307210198Srpaulo int size; 308211554Srpaulo#if defined(sun) 309210198Srpaulo pid_t pid = Pstatus(P)->pr_pid; 310210198Srpaulo char dmodel = Pstatus(P)->pr_dmodel; 311211554Srpaulo#else 312211554Srpaulo pid_t pid = proc_getpid(P); 313211554Srpaulo#if __i386__ 314211554Srpaulo char dmodel = PR_MODEL_ILP32; 315211554Srpaulo#elif __amd64__ 316211554Srpaulo char dmodel = PR_MODEL_LP64; 317211554Srpaulo#endif 318211554Srpaulo#endif 319210198Srpaulo 320210198Srpaulo if ((text = malloc(symp->st_size)) == NULL) { 321210198Srpaulo dt_dprintf("mr sparkle: malloc() failed\n"); 322210198Srpaulo return (DT_PROC_ERR); 323210198Srpaulo } 324210198Srpaulo 325210198Srpaulo if (Pread(P, text, symp->st_size, symp->st_value) != 326210198Srpaulo symp->st_size) { 327210198Srpaulo dt_dprintf("mr sparkle: Pread() failed\n"); 328210198Srpaulo free(text); 329210198Srpaulo return (DT_PROC_ERR); 330210198Srpaulo } 331210198Srpaulo 332210198Srpaulo /* 333210198Srpaulo * We can't instrument offsets in functions with jump tables 334210198Srpaulo * as we might interpret a jump table offset as an 335210198Srpaulo * instruction. 336210198Srpaulo */ 337210198Srpaulo if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { 338210198Srpaulo free(text); 339210198Srpaulo return (0); 340210198Srpaulo } 341210198Srpaulo 342210198Srpaulo for (i = 0; i < symp->st_size; i += size) { 343210198Srpaulo if (i == off) { 344210198Srpaulo ftp->ftps_offs[0] = i; 345210198Srpaulo break; 346210198Srpaulo } 347210198Srpaulo 348210198Srpaulo /* 349210198Srpaulo * If we've passed the desired offset without a 350210198Srpaulo * match, then the given offset must not lie on a 351210198Srpaulo * instruction boundary. 352210198Srpaulo */ 353210198Srpaulo if (i > off) { 354210198Srpaulo free(text); 355210198Srpaulo return (DT_PROC_ALIGN); 356210198Srpaulo } 357210198Srpaulo 358210198Srpaulo size = dt_instr_size(&text[i], dtp, pid, 359210198Srpaulo symp->st_value + i, dmodel); 360210198Srpaulo 361210198Srpaulo /* 362210198Srpaulo * If we hit an invalid instruction, bail as if we 363210198Srpaulo * couldn't find the offset. 364210198Srpaulo */ 365210198Srpaulo if (size <= 0) { 366210198Srpaulo free(text); 367210198Srpaulo return (DT_PROC_ALIGN); 368210198Srpaulo } 369210198Srpaulo } 370210198Srpaulo 371210198Srpaulo free(text); 372210198Srpaulo } 373210198Srpaulo 374210198Srpaulo if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 375210198Srpaulo dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 376210198Srpaulo strerror(errno)); 377210198Srpaulo return (dt_set_errno(dtp, errno)); 378210198Srpaulo } 379210198Srpaulo 380210198Srpaulo return (ftp->ftps_noffs); 381210198Srpaulo} 382210198Srpaulo 383210198Srpaulo/*ARGSUSED*/ 384210198Srpauloint 385210198Srpaulodt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, 386210198Srpaulo fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) 387210198Srpaulo{ 388210198Srpaulo uint8_t *text; 389210198Srpaulo int size; 390210198Srpaulo ulong_t i, end = symp->st_size; 391211554Srpaulo#if defined(sun) 392210198Srpaulo pid_t pid = Pstatus(P)->pr_pid; 393210198Srpaulo char dmodel = Pstatus(P)->pr_dmodel; 394211554Srpaulo#else 395211554Srpaulo pid_t pid = proc_getpid(P); 396211554Srpaulo#if __i386__ 397211554Srpaulo char dmodel = PR_MODEL_ILP32; 398211554Srpaulo#elif __amd64__ 399211554Srpaulo char dmodel = PR_MODEL_LP64; 400211554Srpaulo#endif 401211554Srpaulo#endif 402210198Srpaulo 403210198Srpaulo ftp->ftps_type = DTFTP_OFFSETS; 404210198Srpaulo ftp->ftps_pc = (uintptr_t)symp->st_value; 405210198Srpaulo ftp->ftps_size = (size_t)symp->st_size; 406210198Srpaulo ftp->ftps_noffs = 0; 407210198Srpaulo 408210198Srpaulo if ((text = malloc(symp->st_size)) == NULL) { 409210198Srpaulo dt_dprintf("mr sparkle: malloc() failed\n"); 410210198Srpaulo return (DT_PROC_ERR); 411210198Srpaulo } 412210198Srpaulo 413210198Srpaulo if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { 414210198Srpaulo dt_dprintf("mr sparkle: Pread() failed\n"); 415210198Srpaulo free(text); 416210198Srpaulo return (DT_PROC_ERR); 417210198Srpaulo } 418210198Srpaulo 419210198Srpaulo /* 420210198Srpaulo * We can't instrument offsets in functions with jump tables as 421210198Srpaulo * we might interpret a jump table offset as an instruction. 422210198Srpaulo */ 423210198Srpaulo if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { 424210198Srpaulo free(text); 425210198Srpaulo return (0); 426210198Srpaulo } 427210198Srpaulo 428210198Srpaulo if (strcmp("*", pattern) == 0) { 429210198Srpaulo for (i = 0; i < end; i += size) { 430210198Srpaulo ftp->ftps_offs[ftp->ftps_noffs++] = i; 431210198Srpaulo 432210198Srpaulo size = dt_instr_size(&text[i], dtp, pid, 433210198Srpaulo symp->st_value + i, dmodel); 434210198Srpaulo 435210198Srpaulo /* bail if we hit an invalid opcode */ 436210198Srpaulo if (size <= 0) 437210198Srpaulo break; 438210198Srpaulo } 439210198Srpaulo } else { 440210198Srpaulo char name[sizeof (i) * 2 + 1]; 441210198Srpaulo 442210198Srpaulo for (i = 0; i < end; i += size) { 443228548Sdim (void) snprintf(name, sizeof (name), "%lx", i); 444210198Srpaulo if (gmatch(name, pattern)) 445210198Srpaulo ftp->ftps_offs[ftp->ftps_noffs++] = i; 446210198Srpaulo 447210198Srpaulo size = dt_instr_size(&text[i], dtp, pid, 448210198Srpaulo symp->st_value + i, dmodel); 449210198Srpaulo 450210198Srpaulo /* bail if we hit an invalid opcode */ 451210198Srpaulo if (size <= 0) 452210198Srpaulo break; 453210198Srpaulo } 454210198Srpaulo } 455210198Srpaulo 456210198Srpaulo free(text); 457210198Srpaulo if (ftp->ftps_noffs > 0) { 458210198Srpaulo if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 459210198Srpaulo dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 460210198Srpaulo strerror(errno)); 461210198Srpaulo return (dt_set_errno(dtp, errno)); 462210198Srpaulo } 463210198Srpaulo } 464210198Srpaulo 465210198Srpaulo return (ftp->ftps_noffs); 466210198Srpaulo} 467210198Srpaulo 468210198Srpaulotypedef struct dtrace_dis { 469210198Srpaulo uchar_t *instr; 470210198Srpaulo dtrace_hdl_t *dtp; 471210198Srpaulo pid_t pid; 472210198Srpaulo uintptr_t addr; 473210198Srpaulo} dtrace_dis_t; 474210198Srpaulo 475210198Srpaulostatic int 476210198Srpaulodt_getbyte(void *data) 477210198Srpaulo{ 478210198Srpaulo dtrace_dis_t *dis = data; 479210198Srpaulo int ret = *dis->instr; 480210198Srpaulo 481210198Srpaulo if (ret == FASTTRAP_INSTR) { 482210198Srpaulo fasttrap_instr_query_t instr; 483210198Srpaulo 484210198Srpaulo instr.ftiq_pid = dis->pid; 485210198Srpaulo instr.ftiq_pc = dis->addr; 486210198Srpaulo 487210198Srpaulo /* 488210198Srpaulo * If we hit a byte that looks like the fasttrap provider's 489210198Srpaulo * trap instruction (which doubles as the breakpoint 490210198Srpaulo * instruction for debuggers) we need to query the kernel 491210198Srpaulo * for the real value. This may just be part of an immediate 492210198Srpaulo * value so there's no need to return an error if the 493210198Srpaulo * kernel doesn't know about this address. 494210198Srpaulo */ 495210198Srpaulo if (ioctl(dis->dtp->dt_ftfd, FASTTRAPIOC_GETINSTR, &instr) == 0) 496210198Srpaulo ret = instr.ftiq_instr; 497210198Srpaulo } 498210198Srpaulo 499210198Srpaulo dis->addr++; 500210198Srpaulo dis->instr++; 501210198Srpaulo 502210198Srpaulo return (ret); 503210198Srpaulo} 504210198Srpaulo 505210198Srpaulostatic int 506210198Srpaulodt_instr_size(uchar_t *instr, dtrace_hdl_t *dtp, pid_t pid, uintptr_t addr, 507210198Srpaulo char dmodel) 508210198Srpaulo{ 509210198Srpaulo dtrace_dis_t data; 510210198Srpaulo dis86_t x86dis; 511210198Srpaulo uint_t cpu_mode; 512210198Srpaulo 513210198Srpaulo data.instr = instr; 514210198Srpaulo data.dtp = dtp; 515210198Srpaulo data.pid = pid; 516210198Srpaulo data.addr = addr; 517210198Srpaulo 518210198Srpaulo x86dis.d86_data = &data; 519210198Srpaulo x86dis.d86_get_byte = dt_getbyte; 520210198Srpaulo x86dis.d86_check_func = NULL; 521210198Srpaulo 522210198Srpaulo cpu_mode = (dmodel == PR_MODEL_ILP32) ? SIZE32 : SIZE64; 523210198Srpaulo 524210198Srpaulo if (dtrace_disx86(&x86dis, cpu_mode) != 0) 525210198Srpaulo return (-1); 526210198Srpaulo 527210198Srpaulo /* 528210198Srpaulo * If the instruction was a single-byte breakpoint, there may be 529210198Srpaulo * another debugger attached to this process. The original instruction 530210198Srpaulo * can't be recovered so this must fail. 531210198Srpaulo */ 532253725Spfg if (x86dis.d86_len == 1 && 533253725Spfg (uchar_t)x86dis.d86_bytes[0] == FASTTRAP_INSTR) 534210198Srpaulo return (-1); 535210198Srpaulo 536210198Srpaulo return (x86dis.d86_len); 537210198Srpaulo} 538