1 1.1 christos /* 2 1.1 christos * CDDL HEADER START 3 1.1 christos * 4 1.1 christos * The contents of this file are subject to the terms of the 5 1.1 christos * Common Development and Distribution License (the "License"). 6 1.1 christos * You may not use this file except in compliance with the License. 7 1.1 christos * 8 1.1 christos * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 1.1 christos * or http://www.opensolaris.org/os/licensing. 10 1.1 christos * See the License for the specific language governing permissions 11 1.1 christos * and limitations under the License. 12 1.1 christos * 13 1.1 christos * When distributing Covered Code, include this CDDL HEADER in each 14 1.1 christos * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 1.1 christos * If applicable, add the following below this CDDL HEADER, with the 16 1.1 christos * fields enclosed by brackets "[]" replaced with your own identifying 17 1.1 christos * information: Portions Copyright [yyyy] [name of copyright owner] 18 1.1 christos * 19 1.1 christos * CDDL HEADER END 20 1.1 christos */ 21 1.1 christos 22 1.1 christos /* 23 1.1 christos * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 1.1 christos * Use is subject to license terms. 25 1.1 christos */ 26 1.1 christos 27 1.1 christos /* 28 1.1 christos * Copyright (c) 2012 by Delphix. All rights reserved. 29 1.1 christos */ 30 1.1 christos 31 1.1 christos #include <stdlib.h> 32 1.1 christos #include <assert.h> 33 1.1 christos #include <errno.h> 34 1.1 christos #include <string.h> 35 1.1 christos #include <libgen.h> 36 1.1 christos #include <sys/ioctl.h> 37 1.1 christos 38 1.1 christos #include <dt_impl.h> 39 1.1 christos #include <dt_pid.h> 40 1.1 christos 41 1.1 christos #include <dis_tables.h> 42 1.1 christos 43 1.2 chs #if defined(__FreeBSD__) || defined(__NetBSD__) 44 1.2 chs #include <libproc.h> 45 1.1 christos #include <libproc_compat.h> 46 1.1 christos #endif 47 1.1 christos 48 1.1 christos #define DT_POPL_EBP 0x5d 49 1.1 christos #define DT_RET 0xc3 50 1.1 christos #define DT_RET16 0xc2 51 1.1 christos #define DT_LEAVE 0xc9 52 1.1 christos #define DT_JMP32 0xe9 53 1.1 christos #define DT_JMP8 0xeb 54 1.1 christos #define DT_REP 0xf3 55 1.1 christos 56 1.1 christos #define DT_MOVL_EBP_ESP 0xe58b 57 1.1 christos 58 1.1 christos #define DT_ISJ32(op16) (((op16) & 0xfff0) == 0x0f80) 59 1.1 christos #define DT_ISJ8(op8) (((op8) & 0xf0) == 0x70) 60 1.1 christos 61 1.1 christos #define DT_MODRM_REG(modrm) (((modrm) >> 3) & 0x7) 62 1.1 christos 63 1.1 christos static int dt_instr_size(uchar_t *, dtrace_hdl_t *, pid_t, uintptr_t, char); 64 1.1 christos 65 1.1 christos /*ARGSUSED*/ 66 1.1 christos int 67 1.1 christos dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 68 1.1 christos fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) 69 1.1 christos { 70 1.1 christos ftp->ftps_type = DTFTP_ENTRY; 71 1.1 christos ftp->ftps_pc = (uintptr_t)symp->st_value; 72 1.1 christos ftp->ftps_size = (size_t)symp->st_size; 73 1.1 christos ftp->ftps_noffs = 1; 74 1.1 christos ftp->ftps_offs[0] = 0; 75 1.1 christos 76 1.1 christos if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 77 1.1 christos dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 78 1.1 christos strerror(errno)); 79 1.1 christos return (dt_set_errno(dtp, errno)); 80 1.1 christos } 81 1.1 christos 82 1.1 christos return (1); 83 1.1 christos } 84 1.1 christos 85 1.1 christos static int 86 1.1 christos dt_pid_has_jump_table(struct ps_prochandle *P, dtrace_hdl_t *dtp, 87 1.1 christos uint8_t *text, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) 88 1.1 christos { 89 1.1 christos ulong_t i; 90 1.1 christos int size; 91 1.1 christos #ifdef illumos 92 1.1 christos pid_t pid = Pstatus(P)->pr_pid; 93 1.1 christos char dmodel = Pstatus(P)->pr_dmodel; 94 1.1 christos #else 95 1.1 christos pid_t pid = proc_getpid(P); 96 1.2 chs char dmodel = proc_getmodel(P); 97 1.1 christos #endif 98 1.1 christos 99 1.1 christos /* 100 1.1 christos * Take a pass through the function looking for a register-dependant 101 1.1 christos * jmp instruction. This could be a jump table so we have to be 102 1.1 christos * ultra conservative. 103 1.1 christos */ 104 1.1 christos for (i = 0; i < ftp->ftps_size; i += size) { 105 1.1 christos size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, 106 1.1 christos dmodel); 107 1.1 christos 108 1.1 christos /* 109 1.1 christos * Assume the worst if we hit an illegal instruction. 110 1.1 christos */ 111 1.1 christos if (size <= 0) { 112 1.1 christos dt_dprintf("error at %#lx (assuming jump table)\n", i); 113 1.1 christos return (1); 114 1.1 christos } 115 1.1 christos 116 1.1 christos #ifdef notyet 117 1.1 christos /* 118 1.1 christos * Register-dependant jmp instructions start with a 0xff byte 119 1.1 christos * and have the modrm.reg field set to 4. They can have an 120 1.1 christos * optional REX prefix on the 64-bit ISA. 121 1.1 christos */ 122 1.1 christos if ((text[i] == 0xff && DT_MODRM_REG(text[i + 1]) == 4) || 123 1.1 christos (dmodel == PR_MODEL_LP64 && (text[i] & 0xf0) == 0x40 && 124 1.1 christos text[i + 1] == 0xff && DT_MODRM_REG(text[i + 2]) == 4)) { 125 1.1 christos dt_dprintf("found a suspected jump table at %s:%lx\n", 126 1.1 christos ftp->ftps_func, i); 127 1.1 christos return (1); 128 1.1 christos } 129 1.1 christos #endif 130 1.1 christos } 131 1.1 christos 132 1.1 christos return (0); 133 1.1 christos } 134 1.1 christos 135 1.1 christos /*ARGSUSED*/ 136 1.1 christos int 137 1.1 christos dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 138 1.1 christos fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) 139 1.1 christos { 140 1.1 christos uint8_t *text; 141 1.1 christos ulong_t i, end; 142 1.1 christos int size; 143 1.1 christos #ifdef illumos 144 1.1 christos pid_t pid = Pstatus(P)->pr_pid; 145 1.1 christos char dmodel = Pstatus(P)->pr_dmodel; 146 1.1 christos #else 147 1.1 christos pid_t pid = proc_getpid(P); 148 1.2 chs char dmodel = proc_getmodel(P); 149 1.1 christos #endif 150 1.1 christos 151 1.1 christos /* 152 1.1 christos * We allocate a few extra bytes at the end so we don't have to check 153 1.1 christos * for overrunning the buffer. 154 1.1 christos */ 155 1.1 christos if ((text = calloc(1, symp->st_size + 4)) == NULL) { 156 1.1 christos dt_dprintf("mr sparkle: malloc() failed\n"); 157 1.1 christos return (DT_PROC_ERR); 158 1.1 christos } 159 1.1 christos 160 1.1 christos if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { 161 1.1 christos dt_dprintf("mr sparkle: Pread() failed\n"); 162 1.1 christos free(text); 163 1.1 christos return (DT_PROC_ERR); 164 1.1 christos } 165 1.1 christos 166 1.1 christos ftp->ftps_type = DTFTP_RETURN; 167 1.1 christos ftp->ftps_pc = (uintptr_t)symp->st_value; 168 1.1 christos ftp->ftps_size = (size_t)symp->st_size; 169 1.1 christos ftp->ftps_noffs = 0; 170 1.1 christos 171 1.1 christos /* 172 1.1 christos * If there's a jump table in the function we're only willing to 173 1.1 christos * instrument these specific (and equivalent) instruction sequences: 174 1.1 christos * leave 175 1.1 christos * [rep] ret 176 1.1 christos * and 177 1.1 christos * movl %ebp,%esp 178 1.1 christos * popl %ebp 179 1.1 christos * [rep] ret 180 1.1 christos * 181 1.1 christos * We do this to avoid accidentally interpreting jump table 182 1.1 christos * offsets as actual instructions. 183 1.1 christos */ 184 1.1 christos if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { 185 1.1 christos for (i = 0, end = ftp->ftps_size; i < end; i += size) { 186 1.1 christos size = dt_instr_size(&text[i], dtp, pid, 187 1.1 christos symp->st_value + i, dmodel); 188 1.1 christos 189 1.1 christos /* bail if we hit an invalid opcode */ 190 1.1 christos if (size <= 0) 191 1.1 christos break; 192 1.1 christos 193 1.1 christos if (text[i] == DT_LEAVE && text[i + 1] == DT_RET) { 194 1.1 christos dt_dprintf("leave/ret at %lx\n", i + 1); 195 1.1 christos ftp->ftps_offs[ftp->ftps_noffs++] = i + 1; 196 1.1 christos size = 2; 197 1.1 christos } else if (text[i] == DT_LEAVE && 198 1.1 christos text[i + 1] == DT_REP && text[i + 2] == DT_RET) { 199 1.1 christos dt_dprintf("leave/rep ret at %lx\n", i + 1); 200 1.1 christos ftp->ftps_offs[ftp->ftps_noffs++] = i + 1; 201 1.1 christos size = 3; 202 1.1 christos } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP && 203 1.1 christos text[i + 2] == DT_POPL_EBP && 204 1.1 christos text[i + 3] == DT_RET) { 205 1.1 christos dt_dprintf("movl/popl/ret at %lx\n", i + 3); 206 1.1 christos ftp->ftps_offs[ftp->ftps_noffs++] = i + 3; 207 1.1 christos size = 4; 208 1.1 christos } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP && 209 1.1 christos text[i + 2] == DT_POPL_EBP && 210 1.1 christos text[i + 3] == DT_REP && 211 1.1 christos text[i + 4] == DT_RET) { 212 1.1 christos dt_dprintf("movl/popl/rep ret at %lx\n", i + 3); 213 1.1 christos ftp->ftps_offs[ftp->ftps_noffs++] = i + 3; 214 1.1 christos size = 5; 215 1.1 christos } 216 1.1 christos } 217 1.1 christos } else { 218 1.1 christos for (i = 0, end = ftp->ftps_size; i < end; i += size) { 219 1.1 christos size = dt_instr_size(&text[i], dtp, pid, 220 1.1 christos symp->st_value + i, dmodel); 221 1.1 christos 222 1.1 christos /* bail if we hit an invalid opcode */ 223 1.1 christos if (size <= 0) 224 1.1 christos break; 225 1.1 christos 226 1.1 christos /* ordinary ret */ 227 1.1 christos if (size == 1 && text[i] == DT_RET) 228 1.1 christos goto is_ret; 229 1.1 christos 230 1.1 christos /* two-byte ret */ 231 1.1 christos if (size == 2 && text[i] == DT_REP && 232 1.1 christos text[i + 1] == DT_RET) 233 1.1 christos goto is_ret; 234 1.1 christos 235 1.1 christos /* ret <imm16> */ 236 1.1 christos if (size == 3 && text[i] == DT_RET16) 237 1.1 christos goto is_ret; 238 1.1 christos 239 1.1 christos /* two-byte ret <imm16> */ 240 1.1 christos if (size == 4 && text[i] == DT_REP && 241 1.1 christos text[i + 1] == DT_RET16) 242 1.1 christos goto is_ret; 243 1.1 christos 244 1.1 christos /* 32-bit displacement jmp outside of the function */ 245 1.1 christos if (size == 5 && text[i] == DT_JMP32 && symp->st_size <= 246 1.1 christos (uintptr_t)(i + size + *(int32_t *)&text[i + 1])) 247 1.1 christos goto is_ret; 248 1.1 christos 249 1.1 christos /* 8-bit displacement jmp outside of the function */ 250 1.1 christos if (size == 2 && text[i] == DT_JMP8 && symp->st_size <= 251 1.1 christos (uintptr_t)(i + size + *(int8_t *)&text[i + 1])) 252 1.1 christos goto is_ret; 253 1.1 christos 254 1.1 christos /* 32-bit disp. conditional jmp outside of the func. */ 255 1.1 christos if (size == 6 && DT_ISJ32(*(uint16_t *)&text[i]) && 256 1.1 christos symp->st_size <= 257 1.1 christos (uintptr_t)(i + size + *(int32_t *)&text[i + 2])) 258 1.1 christos goto is_ret; 259 1.1 christos 260 1.1 christos /* 8-bit disp. conditional jmp outside of the func. */ 261 1.1 christos if (size == 2 && DT_ISJ8(text[i]) && symp->st_size <= 262 1.1 christos (uintptr_t)(i + size + *(int8_t *)&text[i + 1])) 263 1.1 christos goto is_ret; 264 1.1 christos 265 1.1 christos continue; 266 1.1 christos is_ret: 267 1.1 christos dt_dprintf("return at offset %lx\n", i); 268 1.1 christos ftp->ftps_offs[ftp->ftps_noffs++] = i; 269 1.1 christos } 270 1.1 christos } 271 1.1 christos 272 1.1 christos free(text); 273 1.1 christos if (ftp->ftps_noffs > 0) { 274 1.1 christos if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 275 1.1 christos dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 276 1.1 christos strerror(errno)); 277 1.1 christos return (dt_set_errno(dtp, errno)); 278 1.1 christos } 279 1.1 christos } 280 1.1 christos 281 1.1 christos return (ftp->ftps_noffs); 282 1.1 christos } 283 1.1 christos 284 1.1 christos /*ARGSUSED*/ 285 1.1 christos int 286 1.1 christos dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 287 1.1 christos fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off) 288 1.1 christos { 289 1.1 christos ftp->ftps_type = DTFTP_OFFSETS; 290 1.1 christos ftp->ftps_pc = (uintptr_t)symp->st_value; 291 1.1 christos ftp->ftps_size = (size_t)symp->st_size; 292 1.1 christos ftp->ftps_noffs = 1; 293 1.1 christos 294 1.1 christos if (strcmp("-", ftp->ftps_func) == 0) { 295 1.1 christos ftp->ftps_offs[0] = off; 296 1.1 christos } else { 297 1.1 christos uint8_t *text; 298 1.1 christos ulong_t i; 299 1.1 christos int size; 300 1.1 christos #ifdef illumos 301 1.1 christos pid_t pid = Pstatus(P)->pr_pid; 302 1.1 christos char dmodel = Pstatus(P)->pr_dmodel; 303 1.1 christos #else 304 1.1 christos pid_t pid = proc_getpid(P); 305 1.2 chs char dmodel = proc_getmodel(P); 306 1.1 christos #endif 307 1.1 christos 308 1.1 christos if ((text = malloc(symp->st_size)) == NULL) { 309 1.1 christos dt_dprintf("mr sparkle: malloc() failed\n"); 310 1.1 christos return (DT_PROC_ERR); 311 1.1 christos } 312 1.1 christos 313 1.1 christos if (Pread(P, text, symp->st_size, symp->st_value) != 314 1.1 christos symp->st_size) { 315 1.1 christos dt_dprintf("mr sparkle: Pread() failed\n"); 316 1.1 christos free(text); 317 1.1 christos return (DT_PROC_ERR); 318 1.1 christos } 319 1.1 christos 320 1.1 christos /* 321 1.1 christos * We can't instrument offsets in functions with jump tables 322 1.1 christos * as we might interpret a jump table offset as an 323 1.1 christos * instruction. 324 1.1 christos */ 325 1.1 christos if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { 326 1.1 christos free(text); 327 1.1 christos return (0); 328 1.1 christos } 329 1.1 christos 330 1.1 christos for (i = 0; i < symp->st_size; i += size) { 331 1.1 christos if (i == off) { 332 1.1 christos ftp->ftps_offs[0] = i; 333 1.1 christos break; 334 1.1 christos } 335 1.1 christos 336 1.1 christos /* 337 1.1 christos * If we've passed the desired offset without a 338 1.1 christos * match, then the given offset must not lie on a 339 1.1 christos * instruction boundary. 340 1.1 christos */ 341 1.1 christos if (i > off) { 342 1.1 christos free(text); 343 1.1 christos return (DT_PROC_ALIGN); 344 1.1 christos } 345 1.1 christos 346 1.1 christos size = dt_instr_size(&text[i], dtp, pid, 347 1.1 christos symp->st_value + i, dmodel); 348 1.1 christos 349 1.1 christos /* 350 1.1 christos * If we hit an invalid instruction, bail as if we 351 1.1 christos * couldn't find the offset. 352 1.1 christos */ 353 1.1 christos if (size <= 0) { 354 1.1 christos free(text); 355 1.1 christos return (DT_PROC_ALIGN); 356 1.1 christos } 357 1.1 christos } 358 1.1 christos 359 1.1 christos free(text); 360 1.1 christos } 361 1.1 christos 362 1.1 christos if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 363 1.1 christos dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 364 1.1 christos strerror(errno)); 365 1.1 christos return (dt_set_errno(dtp, errno)); 366 1.1 christos } 367 1.1 christos 368 1.1 christos return (ftp->ftps_noffs); 369 1.1 christos } 370 1.1 christos 371 1.1 christos /*ARGSUSED*/ 372 1.1 christos int 373 1.1 christos dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, 374 1.1 christos fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) 375 1.1 christos { 376 1.1 christos uint8_t *text; 377 1.1 christos int size; 378 1.1 christos ulong_t i, end = symp->st_size; 379 1.1 christos #ifdef illumos 380 1.1 christos pid_t pid = Pstatus(P)->pr_pid; 381 1.1 christos char dmodel = Pstatus(P)->pr_dmodel; 382 1.1 christos #else 383 1.1 christos pid_t pid = proc_getpid(P); 384 1.2 chs char dmodel = proc_getmodel(P); 385 1.1 christos #endif 386 1.1 christos 387 1.1 christos ftp->ftps_type = DTFTP_OFFSETS; 388 1.1 christos ftp->ftps_pc = (uintptr_t)symp->st_value; 389 1.1 christos ftp->ftps_size = (size_t)symp->st_size; 390 1.1 christos ftp->ftps_noffs = 0; 391 1.1 christos 392 1.1 christos if ((text = malloc(symp->st_size)) == NULL) { 393 1.1 christos dt_dprintf("mr sparkle: malloc() failed\n"); 394 1.1 christos return (DT_PROC_ERR); 395 1.1 christos } 396 1.1 christos 397 1.1 christos if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { 398 1.1 christos dt_dprintf("mr sparkle: Pread() failed\n"); 399 1.1 christos free(text); 400 1.1 christos return (DT_PROC_ERR); 401 1.1 christos } 402 1.1 christos 403 1.1 christos /* 404 1.1 christos * We can't instrument offsets in functions with jump tables as 405 1.1 christos * we might interpret a jump table offset as an instruction. 406 1.1 christos */ 407 1.1 christos if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { 408 1.1 christos free(text); 409 1.1 christos return (0); 410 1.1 christos } 411 1.1 christos 412 1.1 christos if (strcmp("*", pattern) == 0) { 413 1.1 christos for (i = 0; i < end; i += size) { 414 1.1 christos ftp->ftps_offs[ftp->ftps_noffs++] = i; 415 1.1 christos 416 1.1 christos size = dt_instr_size(&text[i], dtp, pid, 417 1.1 christos symp->st_value + i, dmodel); 418 1.1 christos 419 1.1 christos /* bail if we hit an invalid opcode */ 420 1.1 christos if (size <= 0) 421 1.1 christos break; 422 1.1 christos } 423 1.1 christos } else { 424 1.1 christos char name[sizeof (i) * 2 + 1]; 425 1.1 christos 426 1.1 christos for (i = 0; i < end; i += size) { 427 1.1 christos (void) snprintf(name, sizeof (name), "%lx", i); 428 1.1 christos if (gmatch(name, pattern)) 429 1.1 christos ftp->ftps_offs[ftp->ftps_noffs++] = i; 430 1.1 christos 431 1.1 christos size = dt_instr_size(&text[i], dtp, pid, 432 1.1 christos symp->st_value + i, dmodel); 433 1.1 christos 434 1.1 christos /* bail if we hit an invalid opcode */ 435 1.1 christos if (size <= 0) 436 1.1 christos break; 437 1.1 christos } 438 1.1 christos } 439 1.1 christos 440 1.1 christos free(text); 441 1.1 christos if (ftp->ftps_noffs > 0) { 442 1.1 christos if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 443 1.1 christos dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 444 1.1 christos strerror(errno)); 445 1.1 christos return (dt_set_errno(dtp, errno)); 446 1.1 christos } 447 1.1 christos } 448 1.1 christos 449 1.1 christos return (ftp->ftps_noffs); 450 1.1 christos } 451 1.1 christos 452 1.1 christos typedef struct dtrace_dis { 453 1.1 christos uchar_t *instr; 454 1.1 christos dtrace_hdl_t *dtp; 455 1.1 christos pid_t pid; 456 1.1 christos uintptr_t addr; 457 1.1 christos } dtrace_dis_t; 458 1.1 christos 459 1.1 christos static int 460 1.1 christos dt_getbyte(void *data) 461 1.1 christos { 462 1.1 christos dtrace_dis_t *dis = data; 463 1.1 christos int ret = *dis->instr; 464 1.1 christos 465 1.1 christos if (ret == FASTTRAP_INSTR) { 466 1.1 christos fasttrap_instr_query_t instr; 467 1.1 christos 468 1.1 christos instr.ftiq_pid = dis->pid; 469 1.1 christos instr.ftiq_pc = dis->addr; 470 1.1 christos 471 1.1 christos /* 472 1.1 christos * If we hit a byte that looks like the fasttrap provider's 473 1.1 christos * trap instruction (which doubles as the breakpoint 474 1.1 christos * instruction for debuggers) we need to query the kernel 475 1.1 christos * for the real value. This may just be part of an immediate 476 1.1 christos * value so there's no need to return an error if the 477 1.1 christos * kernel doesn't know about this address. 478 1.1 christos */ 479 1.1 christos if (ioctl(dis->dtp->dt_ftfd, FASTTRAPIOC_GETINSTR, &instr) == 0) 480 1.1 christos ret = instr.ftiq_instr; 481 1.1 christos } 482 1.1 christos 483 1.1 christos dis->addr++; 484 1.1 christos dis->instr++; 485 1.1 christos 486 1.1 christos return (ret); 487 1.1 christos } 488 1.1 christos 489 1.1 christos static int 490 1.1 christos dt_instr_size(uchar_t *instr, dtrace_hdl_t *dtp, pid_t pid, uintptr_t addr, 491 1.1 christos char dmodel) 492 1.1 christos { 493 1.1 christos dtrace_dis_t data; 494 1.1 christos dis86_t x86dis; 495 1.1 christos uint_t cpu_mode; 496 1.1 christos 497 1.1 christos data.instr = instr; 498 1.1 christos data.dtp = dtp; 499 1.1 christos data.pid = pid; 500 1.1 christos data.addr = addr; 501 1.1 christos 502 1.1 christos x86dis.d86_data = &data; 503 1.1 christos x86dis.d86_get_byte = dt_getbyte; 504 1.1 christos x86dis.d86_check_func = NULL; 505 1.1 christos 506 1.1 christos cpu_mode = (dmodel == PR_MODEL_ILP32) ? SIZE32 : SIZE64; 507 1.1 christos 508 1.1 christos if (dtrace_disx86(&x86dis, cpu_mode) != 0) 509 1.1 christos return (-1); 510 1.1 christos 511 1.1 christos /* 512 1.1 christos * If the instruction was a single-byte breakpoint, there may be 513 1.1 christos * another debugger attached to this process. The original instruction 514 1.1 christos * can't be recovered so this must fail. 515 1.1 christos */ 516 1.1 christos if (x86dis.d86_len == 1 && 517 1.1 christos (uchar_t)x86dis.d86_bytes[0] == FASTTRAP_INSTR) 518 1.1 christos return (-1); 519 1.1 christos 520 1.1 christos return (x86dis.d86_len); 521 1.1 christos } 522