1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * explicitly define DTRACE_ERRDEBUG to pull in definition of dtrace_errhash_t 31 * explicitly define _STDARG_H to avoid stdarg.h/varargs.h u/k defn conflict 32 */ 33 #define DTRACE_ERRDEBUG 34 #define _STDARG_H 35 36 #include <mdb/mdb_param.h> 37 #include <mdb/mdb_modapi.h> 38 #include <mdb/mdb_ks.h> 39 #include <sys/dtrace_impl.h> 40 #include <sys/vmem_impl.h> 41 #include <sys/ddi_impldefs.h> 42 #include <sys/sysmacros.h> 43 #include <sys/kobj.h> 44 #include <dtrace.h> 45 #include <alloca.h> 46 #include <ctype.h> 47 #include <errno.h> 48 #include <math.h> 49 50 #ifdef _LP64 51 #define DIFO_ADDRWIDTH 11 52 #else 53 #define DIFO_ADDRWIDTH 8 54 #endif 55 56 int dof_sec(uintptr_t, uint_t, int, const mdb_arg_t *); 57 58 /*ARGSUSED*/ 59 static void 60 dis_log(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 61 { 62 mdb_printf("%-4s %%r%u, %%r%u, %%r%u", name, 63 DIF_INSTR_R1(instr), DIF_INSTR_R2(instr), DIF_INSTR_RD(instr)); 64 } 65 66 /*ARGSUSED*/ 67 static void 68 dis_branch(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 69 { 70 mdb_printf("%-4s %u", name, DIF_INSTR_LABEL(instr)); 71 } 72 73 /*ARGSUSED*/ 74 static void 75 dis_load(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 76 { 77 mdb_printf("%-4s [%%r%u], %%r%u", name, 78 DIF_INSTR_R1(instr), DIF_INSTR_RD(instr)); 79 } 80 81 /*ARGSUSED*/ 82 static void 83 dis_store(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 84 { 85 mdb_printf("%-4s %%r%u, [%%r%u]", name, 86 DIF_INSTR_R1(instr), DIF_INSTR_RD(instr)); 87 } 88 89 /*ARGSUSED*/ 90 static void 91 dis_str(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 92 { 93 mdb_printf("%s", name); 94 } 95 96 /*ARGSUSED*/ 97 static void 98 dis_r1rd(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 99 { 100 mdb_printf("%-4s %%r%u, %%r%u", name, 101 DIF_INSTR_R1(instr), DIF_INSTR_RD(instr)); 102 } 103 104 /*ARGSUSED*/ 105 static void 106 dis_cmp(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 107 { 108 mdb_printf("%-4s %%r%u, %%r%u", name, 109 DIF_INSTR_R1(instr), DIF_INSTR_R2(instr)); 110 } 111 112 /*ARGSUSED*/ 113 static void 114 dis_tst(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 115 { 116 mdb_printf("%-4s %%r%u", name, DIF_INSTR_R1(instr)); 117 } 118 119 static const char * 120 dis_varname(const dtrace_difo_t *dp, uint_t id, uint_t scope) 121 { 122 dtrace_difv_t *dvp; 123 size_t varsize; 124 caddr_t addr = NULL, str; 125 uint_t i; 126 127 if (dp == NULL) 128 return (NULL); 129 130 varsize = sizeof (dtrace_difv_t) * dp->dtdo_varlen; 131 dvp = mdb_alloc(varsize, UM_SLEEP); 132 133 if (mdb_vread(dvp, varsize, (uintptr_t)dp->dtdo_vartab) == -1) { 134 mdb_free(dvp, varsize); 135 return ("<unreadable>"); 136 } 137 138 for (i = 0; i < dp->dtdo_varlen; i++) { 139 if (dvp[i].dtdv_id == id && dvp[i].dtdv_scope == scope) { 140 if (dvp[i].dtdv_name < dp->dtdo_strlen) 141 addr = dp->dtdo_strtab + dvp[i].dtdv_name; 142 break; 143 } 144 } 145 146 mdb_free(dvp, varsize); 147 148 if (addr == NULL) 149 return (NULL); 150 151 str = mdb_zalloc(dp->dtdo_strlen + 1, UM_SLEEP | UM_GC); 152 153 for (i = 0; i == 0 || str[i - 1] != '\0'; i++, addr++) { 154 if (mdb_vread(&str[i], sizeof (char), (uintptr_t)addr) == -1) 155 return ("<unreadable>"); 156 } 157 158 return (str); 159 } 160 161 static uint_t 162 dis_scope(const char *name) 163 { 164 switch (name[2]) { 165 case 'l': return (DIFV_SCOPE_LOCAL); 166 case 't': return (DIFV_SCOPE_THREAD); 167 case 'g': return (DIFV_SCOPE_GLOBAL); 168 default: return (-1u); 169 } 170 } 171 172 static void 173 dis_lda(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 174 { 175 uint_t var = DIF_INSTR_R1(instr); 176 const char *vname; 177 178 mdb_printf("%-4s DIF_VAR(%x), %%r%u, %%r%u", name, 179 var, DIF_INSTR_R2(instr), DIF_INSTR_RD(instr)); 180 181 if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL) 182 mdb_printf("\t\t! %s", vname); 183 } 184 185 static void 186 dis_ldv(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 187 { 188 uint_t var = DIF_INSTR_VAR(instr); 189 const char *vname; 190 191 mdb_printf("%-4s DIF_VAR(%x), %%r%u", name, var, DIF_INSTR_RD(instr)); 192 193 if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL) 194 mdb_printf("\t\t! %s", vname); 195 } 196 197 static void 198 dis_stv(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 199 { 200 uint_t var = DIF_INSTR_VAR(instr); 201 const char *vname; 202 203 mdb_printf("%-4s %%r%u, DIF_VAR(%x)", name, DIF_INSTR_RS(instr), var); 204 205 if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL) 206 mdb_printf("\t\t! %s", vname); 207 } 208 209 static void 210 dis_setx(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 211 { 212 uint_t intptr = DIF_INSTR_INTEGER(instr); 213 214 mdb_printf("%-4s DIF_INTEGER[%u], %%r%u", name, 215 intptr, DIF_INSTR_RD(instr)); 216 217 if (dp != NULL && intptr < dp->dtdo_intlen) { 218 uint64_t *ip = mdb_alloc(dp->dtdo_intlen * 219 sizeof (uint64_t), UM_SLEEP | UM_GC); 220 221 if (mdb_vread(ip, dp->dtdo_intlen * sizeof (uint64_t), 222 (uintptr_t)dp->dtdo_inttab) == -1) 223 mdb_warn("failed to read data at %p", dp->dtdo_inttab); 224 else 225 mdb_printf("\t\t! 0x%llx", ip[intptr]); 226 } 227 } 228 229 static void 230 dis_sets(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 231 { 232 uint_t strptr = DIF_INSTR_STRING(instr); 233 234 mdb_printf("%-4s DIF_STRING[%u], %%r%u", name, 235 strptr, DIF_INSTR_RD(instr)); 236 237 if (dp != NULL && strptr < dp->dtdo_strlen) { 238 char *str = mdb_alloc(dp->dtdo_strlen, UM_SLEEP | UM_GC); 239 240 if (mdb_vread(str, dp->dtdo_strlen, 241 (uintptr_t)dp->dtdo_strtab) == -1) 242 mdb_warn("failed to read data at %p", dp->dtdo_strtab); 243 else 244 mdb_printf("\t\t! \"%s\"", str + strptr); 245 } 246 } 247 248 /*ARGSUSED*/ 249 static void 250 dis_ret(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 251 { 252 mdb_printf("%-4s %%r%u", name, DIF_INSTR_RD(instr)); 253 } 254 255 /*ARGSUSED*/ 256 static void 257 dis_call(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 258 { 259 static struct { 260 const char *name; 261 int subr; 262 } snames[] = { 263 { "rand", DIF_SUBR_RAND }, 264 { "mutex_owned", DIF_SUBR_MUTEX_OWNED }, 265 { "mutex_owner", DIF_SUBR_MUTEX_OWNER }, 266 { "mutex_type_adaptive", DIF_SUBR_MUTEX_TYPE_ADAPTIVE }, 267 { "mutex_type_spin", DIF_SUBR_MUTEX_TYPE_SPIN }, 268 { "rw_read_held", DIF_SUBR_RW_READ_HELD }, 269 { "rw_write_held", DIF_SUBR_RW_WRITE_HELD }, 270 { "rw_iswriter", DIF_SUBR_RW_ISWRITER }, 271 { "copyin", DIF_SUBR_COPYIN }, 272 { "copyinstr", DIF_SUBR_COPYINSTR }, 273 { "speculation", DIF_SUBR_SPECULATION }, 274 { "progenyof", DIF_SUBR_PROGENYOF }, 275 { "strlen", DIF_SUBR_STRLEN }, 276 { "copyout", DIF_SUBR_COPYOUT }, 277 { "copyoutstr", DIF_SUBR_COPYOUTSTR }, 278 { "alloca", DIF_SUBR_ALLOCA }, 279 { "bcopy", DIF_SUBR_BCOPY }, 280 { "copyinto", DIF_SUBR_COPYINTO }, 281 { "msgdsize", DIF_SUBR_MSGDSIZE }, 282 { "msgsize", DIF_SUBR_MSGSIZE }, 283 { "getmajor", DIF_SUBR_GETMAJOR }, 284 { "getminor", DIF_SUBR_GETMINOR }, 285 { "ddi_pathname", DIF_SUBR_DDI_PATHNAME }, 286 { "strjoin", DIF_SUBR_STRJOIN }, 287 { "lltostr", DIF_SUBR_LLTOSTR }, 288 { "basename", DIF_SUBR_BASENAME }, 289 { "dirname", DIF_SUBR_DIRNAME }, 290 { "cleanpath", DIF_SUBR_CLEANPATH }, 291 { "strchr", DIF_SUBR_STRCHR }, 292 { "strrchr", DIF_SUBR_STRRCHR }, 293 { "strstr", DIF_SUBR_STRSTR }, 294 { "strtok", DIF_SUBR_STRTOK }, 295 { "substr", DIF_SUBR_SUBSTR }, 296 { "index", DIF_SUBR_INDEX }, 297 { "rindex", DIF_SUBR_RINDEX }, 298 { NULL, 0 } 299 }; 300 301 uint_t subr = DIF_INSTR_SUBR(instr), i; 302 303 mdb_printf("%-4s DIF_SUBR(%u), %%r%u", name, subr, DIF_INSTR_RD(instr)); 304 305 for (i = 0; snames[i].name != NULL; i++) { 306 if (subr == snames[i].subr) { 307 mdb_printf("\t\t! %s", snames[i].name); 308 return; 309 } 310 } 311 } 312 313 /*ARGSUSED*/ 314 static void 315 dis_pushts(const dtrace_difo_t *dp, const char *name, dif_instr_t instr) 316 { 317 static const char *const tnames[] = { "TYPE_CTF", "TYPE_STRING" }; 318 uint_t type = DIF_INSTR_TYPE(instr); 319 320 mdb_printf("%-4s DIF_TYPE(%u), %%r%u, %%r%u", 321 name, type, DIF_INSTR_R2(instr), DIF_INSTR_RS(instr)); 322 323 if (type < sizeof (tnames) / sizeof (tnames[0])) 324 mdb_printf("\t! %s", tnames[type]); 325 } 326 327 static char * 328 dis_typestr(const dtrace_diftype_t *t, char *buf, size_t len) 329 { 330 char kind[8]; 331 332 switch (t->dtdt_kind) { 333 case DIF_TYPE_CTF: 334 (void) strcpy(kind, "D type"); 335 break; 336 case DIF_TYPE_STRING: 337 (void) strcpy(kind, "string"); 338 break; 339 default: 340 (void) mdb_snprintf(kind, sizeof (kind), "0x%x", t->dtdt_kind); 341 } 342 343 if (t->dtdt_flags & DIF_TF_BYREF) { 344 (void) mdb_snprintf(buf, len, 345 "%s by ref (size %lu)", 346 kind, (ulong_t)t->dtdt_size); 347 } else { 348 (void) mdb_snprintf(buf, len, "%s (size %lu)", 349 kind, (ulong_t)t->dtdt_size); 350 } 351 352 return (buf); 353 } 354 355 static int 356 dis(uintptr_t addr, dtrace_difo_t *dp) 357 { 358 static const struct opent { 359 const char *op_name; 360 void (*op_func)(const dtrace_difo_t *, 361 const char *, dif_instr_t); 362 } optab[] = { 363 { "(illegal opcode)", dis_str }, 364 { "or", dis_log }, /* DIF_OP_OR */ 365 { "xor", dis_log }, /* DIF_OP_XOR */ 366 { "and", dis_log }, /* DIF_OP_AND */ 367 { "sll", dis_log }, /* DIF_OP_SLL */ 368 { "srl", dis_log }, /* DIF_OP_SRL */ 369 { "sub", dis_log }, /* DIF_OP_SUB */ 370 { "add", dis_log }, /* DIF_OP_ADD */ 371 { "mul", dis_log }, /* DIF_OP_MUL */ 372 { "sdiv", dis_log }, /* DIF_OP_SDIV */ 373 { "udiv", dis_log }, /* DIF_OP_UDIV */ 374 { "srem", dis_log }, /* DIF_OP_SREM */ 375 { "urem", dis_log }, /* DIF_OP_UREM */ 376 { "not", dis_r1rd }, /* DIF_OP_NOT */ 377 { "mov", dis_r1rd }, /* DIF_OP_MOV */ 378 { "cmp", dis_cmp }, /* DIF_OP_CMP */ 379 { "tst", dis_tst }, /* DIF_OP_TST */ 380 { "ba", dis_branch }, /* DIF_OP_BA */ 381 { "be", dis_branch }, /* DIF_OP_BE */ 382 { "bne", dis_branch }, /* DIF_OP_BNE */ 383 { "bg", dis_branch }, /* DIF_OP_BG */ 384 { "bgu", dis_branch }, /* DIF_OP_BGU */ 385 { "bge", dis_branch }, /* DIF_OP_BGE */ 386 { "bgeu", dis_branch }, /* DIF_OP_BGEU */ 387 { "bl", dis_branch }, /* DIF_OP_BL */ 388 { "blu", dis_branch }, /* DIF_OP_BLU */ 389 { "ble", dis_branch }, /* DIF_OP_BLE */ 390 { "bleu", dis_branch }, /* DIF_OP_BLEU */ 391 { "ldsb", dis_load }, /* DIF_OP_LDSB */ 392 { "ldsh", dis_load }, /* DIF_OP_LDSH */ 393 { "ldsw", dis_load }, /* DIF_OP_LDSW */ 394 { "ldub", dis_load }, /* DIF_OP_LDUB */ 395 { "lduh", dis_load }, /* DIF_OP_LDUH */ 396 { "lduw", dis_load }, /* DIF_OP_LDUW */ 397 { "ldx", dis_load }, /* DIF_OP_LDX */ 398 { "ret", dis_ret }, /* DIF_OP_RET */ 399 { "nop", dis_str }, /* DIF_OP_NOP */ 400 { "setx", dis_setx }, /* DIF_OP_SETX */ 401 { "sets", dis_sets }, /* DIF_OP_SETS */ 402 { "scmp", dis_cmp }, /* DIF_OP_SCMP */ 403 { "ldga", dis_lda }, /* DIF_OP_LDGA */ 404 { "ldgs", dis_ldv }, /* DIF_OP_LDGS */ 405 { "stgs", dis_stv }, /* DIF_OP_STGS */ 406 { "ldta", dis_lda }, /* DIF_OP_LDTA */ 407 { "ldts", dis_ldv }, /* DIF_OP_LDTS */ 408 { "stts", dis_stv }, /* DIF_OP_STTS */ 409 { "sra", dis_log }, /* DIF_OP_SRA */ 410 { "call", dis_call }, /* DIF_OP_CALL */ 411 { "pushtr", dis_pushts }, /* DIF_OP_PUSHTR */ 412 { "pushtv", dis_pushts }, /* DIF_OP_PUSHTV */ 413 { "popts", dis_str }, /* DIF_OP_POPTS */ 414 { "flushts", dis_str }, /* DIF_OP_FLUSHTS */ 415 { "ldgaa", dis_ldv }, /* DIF_OP_LDGAA */ 416 { "ldtaa", dis_ldv }, /* DIF_OP_LDTAA */ 417 { "stgaa", dis_stv }, /* DIF_OP_STGAA */ 418 { "sttaa", dis_stv }, /* DIF_OP_STTAA */ 419 { "ldls", dis_ldv }, /* DIF_OP_LDLS */ 420 { "stls", dis_stv }, /* DIF_OP_STLS */ 421 { "allocs", dis_r1rd }, /* DIF_OP_ALLOCS */ 422 { "copys", dis_log }, /* DIF_OP_COPYS */ 423 { "stb", dis_store }, /* DIF_OP_STB */ 424 { "sth", dis_store }, /* DIF_OP_STH */ 425 { "stw", dis_store }, /* DIF_OP_STW */ 426 { "stx", dis_store }, /* DIF_OP_STX */ 427 { "uldsb", dis_load }, /* DIF_OP_ULDSB */ 428 { "uldsh", dis_load }, /* DIF_OP_ULDSH */ 429 { "uldsw", dis_load }, /* DIF_OP_ULDSW */ 430 { "uldub", dis_load }, /* DIF_OP_ULDUB */ 431 { "ulduh", dis_load }, /* DIF_OP_ULDUH */ 432 { "ulduw", dis_load }, /* DIF_OP_ULDUW */ 433 { "uldx", dis_load }, /* DIF_OP_ULDX */ 434 { "rldsb", dis_load }, /* DIF_OP_RLDSB */ 435 { "rldsh", dis_load }, /* DIF_OP_RLDSH */ 436 { "rldsw", dis_load }, /* DIF_OP_RLDSW */ 437 { "rldub", dis_load }, /* DIF_OP_RLDUB */ 438 { "rlduh", dis_load }, /* DIF_OP_RLDUH */ 439 { "rlduw", dis_load }, /* DIF_OP_RLDUW */ 440 { "rldx", dis_load }, /* DIF_OP_RLDX */ 441 }; 442 443 dif_instr_t instr, opcode; 444 const struct opent *op; 445 446 if (mdb_vread(&instr, sizeof (dif_instr_t), addr) == -1) { 447 mdb_warn("failed to read DIF instruction at %p", addr); 448 return (DCMD_ERR); 449 } 450 451 opcode = DIF_INSTR_OP(instr); 452 453 if (opcode >= sizeof (optab) / sizeof (optab[0])) 454 opcode = 0; /* force invalid opcode message */ 455 456 op = &optab[opcode]; 457 mdb_printf("%0*p %08x ", DIFO_ADDRWIDTH, addr, instr); 458 op->op_func(dp, op->op_name, instr); 459 mdb_printf("\n"); 460 mdb_set_dot(addr + sizeof (dif_instr_t)); 461 462 return (DCMD_OK); 463 } 464 465 /*ARGSUSED*/ 466 int 467 difo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 468 { 469 dtrace_difo_t difo, *dp = &difo; 470 uintptr_t instr, limit; 471 dtrace_difv_t *dvp; 472 size_t varsize; 473 ulong_t i; 474 char type[64]; 475 char *str; 476 477 if (!(flags & DCMD_ADDRSPEC)) 478 return (DCMD_USAGE); 479 480 if (mdb_vread(dp, sizeof (dtrace_difo_t), addr) == -1) { 481 mdb_warn("couldn't read dtrace_difo_t at %p", addr); 482 return (DCMD_ERR); 483 } 484 485 mdb_printf("%<u>DIF Object 0x%p%</u> (refcnt=%d)\n\n", 486 addr, dp->dtdo_refcnt); 487 mdb_printf("%<b>%-*s %-8s %s%</b>\n", DIFO_ADDRWIDTH, "ADDR", 488 "OPCODE", "INSTRUCTION"); 489 490 mdb_set_dot((uintmax_t)(uintptr_t)dp->dtdo_buf); 491 limit = (uintptr_t)dp->dtdo_buf + dp->dtdo_len * sizeof (dif_instr_t); 492 493 while ((instr = mdb_get_dot()) < limit) 494 dis(instr, dp); 495 496 if (dp->dtdo_varlen != 0) { 497 mdb_printf("\n%<b>%-16s %-4s %-3s %-3s %-4s %s%</b>\n", 498 "NAME", "ID", "KND", "SCP", "FLAG", "TYPE"); 499 } 500 501 varsize = sizeof (dtrace_difv_t) * dp->dtdo_varlen; 502 dvp = mdb_alloc(varsize, UM_SLEEP | UM_GC); 503 504 if (mdb_vread(dvp, varsize, (uintptr_t)dp->dtdo_vartab) == -1) { 505 mdb_warn("couldn't read dtdo_vartab"); 506 return (DCMD_ERR); 507 } 508 509 str = mdb_alloc(dp->dtdo_strlen, UM_SLEEP | UM_GC); 510 511 if (mdb_vread(str, dp->dtdo_strlen, (uintptr_t)dp->dtdo_strtab) == -1) { 512 mdb_warn("couldn't read dtdo_strtab"); 513 return (DCMD_ERR); 514 } 515 516 for (i = 0; i < dp->dtdo_varlen; i++) { 517 dtrace_difv_t *v = &dvp[i]; 518 char kind[4], scope[4], flags[16] = { 0 }; 519 520 switch (v->dtdv_kind) { 521 case DIFV_KIND_ARRAY: 522 (void) strcpy(kind, "arr"); 523 break; 524 case DIFV_KIND_SCALAR: 525 (void) strcpy(kind, "scl"); 526 break; 527 default: 528 (void) mdb_snprintf(kind, sizeof (kind), 529 "%u", v->dtdv_kind); 530 } 531 532 switch (v->dtdv_scope) { 533 case DIFV_SCOPE_GLOBAL: 534 (void) strcpy(scope, "glb"); 535 break; 536 case DIFV_SCOPE_THREAD: 537 (void) strcpy(scope, "tls"); 538 break; 539 case DIFV_SCOPE_LOCAL: 540 (void) strcpy(scope, "loc"); 541 break; 542 default: 543 (void) mdb_snprintf(scope, sizeof (scope), 544 "%u", v->dtdv_scope); 545 } 546 547 if (v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)) { 548 (void) mdb_snprintf(flags, sizeof (flags), "/0x%x", 549 v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)); 550 } 551 552 if (v->dtdv_flags & DIFV_F_REF) 553 (void) strcat(flags, "/r"); 554 if (v->dtdv_flags & DIFV_F_MOD) 555 (void) strcat(flags, "/w"); 556 557 mdb_printf("%-16s %-4x %-3s %-3s %-4s %s\n", 558 &str[v->dtdv_name], 559 v->dtdv_id, kind, scope, flags + 1, 560 dis_typestr(&v->dtdv_type, type, sizeof (type))); 561 } 562 563 mdb_printf("\n%<b>RETURN%</b>\n%s\n\n", 564 dis_typestr(&dp->dtdo_rtype, type, sizeof (type))); 565 566 return (DCMD_OK); 567 } 568 569 /*ARGSUSED*/ 570 int 571 difinstr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 572 { 573 if (!(flags & DCMD_ADDRSPEC)) 574 return (DCMD_USAGE); 575 576 return (dis(addr, NULL)); 577 } 578 579 /*ARGSUSED*/ 580 int 581 id2probe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 582 { 583 uintptr_t probe = NULL; 584 uintptr_t probes; 585 586 if (!(flags & DCMD_ADDRSPEC)) 587 return (DCMD_USAGE); 588 589 if (addr == DTRACE_IDNONE || addr > UINT32_MAX) 590 goto out; 591 592 if (mdb_readvar(&probes, "dtrace_probes") == -1) { 593 mdb_warn("failed to read 'dtrace_probes'"); 594 return (DCMD_ERR); 595 } 596 597 probes += (addr - 1) * sizeof (dtrace_probe_t *); 598 599 if (mdb_vread(&probe, sizeof (uintptr_t), probes) == -1) { 600 mdb_warn("failed to read dtrace_probes[%d]", addr - 1); 601 return (DCMD_ERR); 602 } 603 604 out: 605 mdb_printf("%p\n", probe); 606 return (DCMD_OK); 607 } 608 609 /*ARGSUSED*/ 610 int 611 dof_hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 612 { 613 dof_hdr_t h; 614 615 if (argc != 0) 616 return (DCMD_USAGE); 617 618 if (!(flags & DCMD_ADDRSPEC)) 619 addr = 0; /* assume base of file in file target */ 620 621 if (mdb_vread(&h, sizeof (h), addr) != sizeof (h)) { 622 mdb_warn("failed to read header at %p", addr); 623 return (DCMD_ERR); 624 } 625 626 mdb_printf("dofh_ident.id_magic = 0x%x, %c, %c, %c\n", 627 h.dofh_ident[DOF_ID_MAG0], h.dofh_ident[DOF_ID_MAG1], 628 h.dofh_ident[DOF_ID_MAG2], h.dofh_ident[DOF_ID_MAG3]); 629 630 switch (h.dofh_ident[DOF_ID_MODEL]) { 631 case DOF_MODEL_ILP32: 632 mdb_printf("dofh_ident.id_model = ILP32\n"); 633 break; 634 case DOF_MODEL_LP64: 635 mdb_printf("dofh_ident.id_model = LP64\n"); 636 break; 637 default: 638 mdb_printf("dofh_ident.id_model = 0x%x\n", 639 h.dofh_ident[DOF_ID_MODEL]); 640 } 641 642 switch (h.dofh_ident[DOF_ID_ENCODING]) { 643 case DOF_ENCODE_LSB: 644 mdb_printf("dofh_ident.id_encoding = LSB\n"); 645 break; 646 case DOF_ENCODE_MSB: 647 mdb_printf("dofh_ident.id_encoding = MSB\n"); 648 break; 649 default: 650 mdb_printf("dofh_ident.id_encoding = 0x%x\n", 651 h.dofh_ident[DOF_ID_ENCODING]); 652 } 653 654 mdb_printf("dofh_ident.id_version = %u\n", 655 h.dofh_ident[DOF_ID_VERSION]); 656 mdb_printf("dofh_ident.id_difvers = %u\n", 657 h.dofh_ident[DOF_ID_DIFVERS]); 658 mdb_printf("dofh_ident.id_difireg = %u\n", 659 h.dofh_ident[DOF_ID_DIFIREG]); 660 mdb_printf("dofh_ident.id_diftreg = %u\n", 661 h.dofh_ident[DOF_ID_DIFTREG]); 662 663 mdb_printf("dofh_flags = 0x%x\n", h.dofh_flags); 664 mdb_printf("dofh_hdrsize = %u\n", h.dofh_hdrsize); 665 mdb_printf("dofh_secsize = %u\n", h.dofh_secsize); 666 mdb_printf("dofh_secnum = %u\n", h.dofh_secnum); 667 mdb_printf("dofh_secoff = %llu\n", h.dofh_secoff); 668 mdb_printf("dofh_loadsz = %llu\n", h.dofh_loadsz); 669 mdb_printf("dofh_filesz = %llu\n", h.dofh_filesz); 670 671 return (DCMD_OK); 672 } 673 674 /*ARGSUSED*/ 675 static int 676 dof_sec_walk(uintptr_t addr, void *ignored, int *sec) 677 { 678 mdb_printf("%3d ", (*sec)++); 679 (void) dof_sec(addr, DCMD_ADDRSPEC | DCMD_LOOP, 0, NULL); 680 return (WALK_NEXT); 681 } 682 683 static const char * 684 dof_sec_typename(uint32_t type) 685 { 686 static const char *const types[] = { 687 "none", "comments", "source", "ecbdesc", "probedesc", "actdesc", 688 "difohdr", "dif", "strtab", "vartab", "reltab", "typtab", 689 "urelhdr", "krelhdr", "optdesc", "provider", "probes", 690 "prargs", "proffs", "inttab", "utsname" 691 }; 692 static char buf[32]; 693 694 if (type < sizeof (types) / sizeof (types[0])) 695 return (types[type]); 696 697 mdb_snprintf(buf, sizeof (buf), "%u", type); 698 return (buf); 699 } 700 701 /*ARGSUSED*/ 702 int 703 dof_sec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 704 { 705 dof_sec_t s; 706 707 if (!(flags & DCMD_ADDRSPEC)) 708 mdb_printf("%<u>%-3s ", "NDX"); 709 710 if (!(flags & DCMD_ADDRSPEC) || DCMD_HDRSPEC(flags)) { 711 mdb_printf("%<u>%?s %-10s %-5s %-5s %-5s %-6s %-5s%</u>\n", 712 "ADDR", "TYPE", "ALIGN", "FLAGS", "ENTSZ", "OFFSET", 713 "SIZE"); 714 } 715 716 if (!(flags & DCMD_ADDRSPEC)) { 717 int sec = 0; 718 719 if (mdb_walk("dof_sec", 720 (mdb_walk_cb_t)dof_sec_walk, &sec) == -1) { 721 mdb_warn("failed to walk dof_sec"); 722 return (DCMD_ERR); 723 } 724 return (DCMD_OK); 725 } 726 727 if (argc != 0) 728 return (DCMD_USAGE); 729 730 if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) { 731 mdb_warn("failed to read section header at %p", addr); 732 return (DCMD_ERR); 733 } 734 735 mdb_printf("%?p ", addr); 736 mdb_printf("%-10s ", dof_sec_typename(s.dofs_type)); 737 738 mdb_printf("%-5u %-#5x %-#5x %-6llx %-#5llx\n", s.dofs_align, 739 s.dofs_flags, s.dofs_entsize, s.dofs_offset, s.dofs_size); 740 741 return (DCMD_OK); 742 } 743 744 int 745 dof_sec_walk_init(mdb_walk_state_t *wsp) 746 { 747 dof_hdr_t h, *hp; 748 size_t size; 749 750 if (mdb_vread(&h, sizeof (h), wsp->walk_addr) != sizeof (h)) { 751 mdb_warn("failed to read DOF header at %p", wsp->walk_addr); 752 return (WALK_ERR); 753 } 754 755 size = sizeof (dof_hdr_t) + sizeof (dof_sec_t) * h.dofh_secnum; 756 hp = mdb_alloc(size, UM_SLEEP); 757 758 if (mdb_vread(hp, size, wsp->walk_addr) != size) { 759 mdb_warn("failed to read DOF sections at %p", wsp->walk_addr); 760 mdb_free(hp, size); 761 return (WALK_ERR); 762 } 763 764 wsp->walk_arg = (void *)0; 765 wsp->walk_data = hp; 766 767 return (WALK_NEXT); 768 } 769 770 int 771 dof_sec_walk_step(mdb_walk_state_t *wsp) 772 { 773 uint_t i = (uintptr_t)wsp->walk_arg; 774 size_t off = sizeof (dof_hdr_t) + sizeof (dof_sec_t) * i; 775 dof_hdr_t *hp = wsp->walk_data; 776 dof_sec_t *sp = (dof_sec_t *)((uintptr_t)hp + off); 777 778 if (i >= hp->dofh_secnum) 779 return (WALK_DONE); 780 781 wsp->walk_arg = (void *)(uintptr_t)(i + 1); 782 return (wsp->walk_callback(wsp->walk_addr + off, sp, wsp->walk_cbdata)); 783 } 784 785 void 786 dof_sec_walk_fini(mdb_walk_state_t *wsp) 787 { 788 dof_hdr_t *hp = wsp->walk_data; 789 mdb_free(hp, sizeof (dof_hdr_t) + sizeof (dof_sec_t) * hp->dofh_secnum); 790 } 791 792 /*ARGSUSED*/ 793 int 794 dof_ecbdesc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 795 { 796 dof_ecbdesc_t e; 797 798 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 799 return (DCMD_USAGE); 800 801 if (mdb_vread(&e, sizeof (e), addr) != sizeof (e)) { 802 mdb_warn("failed to read ecbdesc at %p", addr); 803 return (DCMD_ERR); 804 } 805 806 mdb_printf("dofe_probes = %d\n", e.dofe_probes); 807 mdb_printf("dofe_actions = %d\n", e.dofe_actions); 808 mdb_printf("dofe_pred = %d\n", e.dofe_pred); 809 mdb_printf("dofe_uarg = 0x%llx\n", e.dofe_uarg); 810 811 return (DCMD_OK); 812 } 813 814 /*ARGSUSED*/ 815 int 816 dof_probedesc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 817 { 818 dof_probedesc_t p; 819 820 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 821 return (DCMD_USAGE); 822 823 if (mdb_vread(&p, sizeof (p), addr) != sizeof (p)) { 824 mdb_warn("failed to read probedesc at %p", addr); 825 return (DCMD_ERR); 826 } 827 828 mdb_printf("dofp_strtab = %d\n", p.dofp_strtab); 829 mdb_printf("dofp_provider = %u\n", p.dofp_provider); 830 mdb_printf("dofp_mod = %u\n", p.dofp_mod); 831 mdb_printf("dofp_func = %u\n", p.dofp_func); 832 mdb_printf("dofp_name = %u\n", p.dofp_name); 833 mdb_printf("dofp_id = %u\n", p.dofp_id); 834 835 return (DCMD_OK); 836 } 837 838 /*ARGSUSED*/ 839 int 840 dof_actdesc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 841 { 842 dof_actdesc_t a; 843 844 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 845 return (DCMD_USAGE); 846 847 if (mdb_vread(&a, sizeof (a), addr) != sizeof (a)) { 848 mdb_warn("failed to read actdesc at %p", addr); 849 return (DCMD_ERR); 850 } 851 852 mdb_printf("dofa_difo = %d\n", a.dofa_difo); 853 mdb_printf("dofa_strtab = %d\n", a.dofa_strtab); 854 mdb_printf("dofa_kind = %u\n", a.dofa_kind); 855 mdb_printf("dofa_ntuple = %u\n", a.dofa_ntuple); 856 mdb_printf("dofa_arg = 0x%llx\n", a.dofa_arg); 857 mdb_printf("dofa_uarg = 0x%llx\n", a.dofa_uarg); 858 859 return (DCMD_OK); 860 } 861 862 /*ARGSUSED*/ 863 int 864 dof_relohdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 865 { 866 dof_relohdr_t r; 867 868 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 869 return (DCMD_USAGE); 870 871 if (mdb_vread(&r, sizeof (r), addr) != sizeof (r)) { 872 mdb_warn("failed to read relohdr at %p", addr); 873 return (DCMD_ERR); 874 } 875 876 mdb_printf("dofr_strtab = %d\n", r.dofr_strtab); 877 mdb_printf("dofr_relsec = %d\n", r.dofr_relsec); 878 mdb_printf("dofr_tgtsec = %d\n", r.dofr_tgtsec); 879 880 return (DCMD_OK); 881 } 882 883 /*ARGSUSED*/ 884 int 885 dof_relodesc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 886 { 887 dof_relodesc_t r; 888 889 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 890 return (DCMD_USAGE); 891 892 if (mdb_vread(&r, sizeof (r), addr) != sizeof (r)) { 893 mdb_warn("failed to read relodesc at %p", addr); 894 return (DCMD_ERR); 895 } 896 897 mdb_printf("dofr_name = %u\n", r.dofr_name); 898 mdb_printf("dofr_type = %u\n", r.dofr_type); 899 mdb_printf("dofr_offset = 0x%llx\n", r.dofr_offset); 900 mdb_printf("dofr_data = 0x%llx\n", r.dofr_data); 901 902 return (DCMD_OK); 903 } 904 905 void 906 dtrace_help(void) 907 { 908 909 mdb_printf("Given a dtrace_state_t structure that represents a " 910 "DTrace consumer, prints\n" 911 "dtrace(1M)-like output for in-kernel DTrace data. (The " 912 "dtrace_state_t\n" 913 "structures for all DTrace consumers may be obtained by running " 914 "the \n" 915 "::dtrace_state dcmd.) When data is present on multiple CPUs, " 916 "data are\n" 917 "presented in CPU order, with records within each CPU ordered " 918 "oldest to \n" 919 "youngest. Options:\n\n" 920 "-c cpu Only provide output for specified CPU.\n"); 921 } 922 923 static int 924 dtracemdb_eprobe(dtrace_state_t *state, dtrace_eprobedesc_t *epd) 925 { 926 dtrace_epid_t epid = epd->dtepd_epid; 927 dtrace_probe_t probe; 928 dtrace_ecb_t ecb; 929 uintptr_t addr, paddr, ap; 930 dtrace_action_t act; 931 int nactions, nrecs; 932 933 addr = (uintptr_t)state->dts_ecbs + 934 (epid - 1) * sizeof (dtrace_ecb_t *); 935 936 if (mdb_vread(&addr, sizeof (addr), addr) == -1) { 937 mdb_warn("failed to read ecb for epid %d", epid); 938 return (-1); 939 } 940 941 if (addr == NULL) { 942 mdb_warn("epid %d doesn't match an ecb\n", epid); 943 return (-1); 944 } 945 946 if (mdb_vread(&ecb, sizeof (ecb), addr) == -1) { 947 mdb_warn("failed to read ecb at %p", addr); 948 return (-1); 949 } 950 951 paddr = (uintptr_t)ecb.dte_probe; 952 953 if (mdb_vread(&probe, sizeof (probe), paddr) == -1) { 954 mdb_warn("failed to read probe for ecb %p", addr); 955 return (-1); 956 } 957 958 /* 959 * This is a little painful: in order to find the number of actions, 960 * we need to first walk through them. 961 */ 962 for (ap = (uintptr_t)ecb.dte_action, nactions = 0; ap != NULL; ) { 963 if (mdb_vread(&act, sizeof (act), ap) == -1) { 964 mdb_warn("failed to read action %p on ecb %p", 965 ap, addr); 966 return (-1); 967 } 968 969 if (!DTRACEACT_ISAGG(act.dta_kind) && !act.dta_intuple) 970 nactions++; 971 972 ap = (uintptr_t)act.dta_next; 973 } 974 975 nrecs = epd->dtepd_nrecs; 976 epd->dtepd_nrecs = nactions; 977 epd->dtepd_probeid = probe.dtpr_id; 978 epd->dtepd_uarg = ecb.dte_uarg; 979 epd->dtepd_size = ecb.dte_size; 980 981 for (ap = (uintptr_t)ecb.dte_action, nactions = 0; ap != NULL; ) { 982 if (mdb_vread(&act, sizeof (act), ap) == -1) { 983 mdb_warn("failed to read action %p on ecb %p", 984 ap, addr); 985 return (-1); 986 } 987 988 if (!DTRACEACT_ISAGG(act.dta_kind) && !act.dta_intuple) { 989 if (nrecs-- == 0) 990 break; 991 992 epd->dtepd_rec[nactions++] = act.dta_rec; 993 } 994 995 ap = (uintptr_t)act.dta_next; 996 } 997 998 return (0); 999 } 1000 1001 /*ARGSUSED*/ 1002 static int 1003 dtracemdb_probe(dtrace_state_t *state, dtrace_probedesc_t *pd) 1004 { 1005 uintptr_t base, addr, paddr, praddr; 1006 int nprobes, i; 1007 dtrace_probe_t probe; 1008 dtrace_provider_t prov; 1009 1010 if (pd->dtpd_id == DTRACE_IDNONE) 1011 pd->dtpd_id++; 1012 1013 if (mdb_readvar(&base, "dtrace_probes") == -1) { 1014 mdb_warn("failed to read 'dtrace_probes'"); 1015 return (-1); 1016 } 1017 1018 if (mdb_readvar(&nprobes, "dtrace_nprobes") == -1) { 1019 mdb_warn("failed to read 'dtrace_nprobes'"); 1020 return (-1); 1021 } 1022 1023 for (i = pd->dtpd_id; i <= nprobes; i++) { 1024 addr = base + (i - 1) * sizeof (dtrace_probe_t *); 1025 1026 if (mdb_vread(&paddr, sizeof (paddr), addr) == -1) { 1027 mdb_warn("couldn't read probe pointer at %p", addr); 1028 return (-1); 1029 } 1030 1031 if (paddr != NULL) 1032 break; 1033 } 1034 1035 if (paddr == NULL) { 1036 errno = ESRCH; 1037 return (-1); 1038 } 1039 1040 if (mdb_vread(&probe, sizeof (probe), paddr) == -1) { 1041 mdb_warn("couldn't read probe at %p", paddr); 1042 return (-1); 1043 } 1044 1045 pd->dtpd_id = probe.dtpr_id; 1046 1047 if (mdb_vread(pd->dtpd_name, DTRACE_NAMELEN, 1048 (uintptr_t)probe.dtpr_name) == -1) { 1049 mdb_warn("failed to read probe name for probe %p", paddr); 1050 return (-1); 1051 } 1052 1053 if (mdb_vread(pd->dtpd_func, DTRACE_FUNCNAMELEN, 1054 (uintptr_t)probe.dtpr_func) == -1) { 1055 mdb_warn("failed to read function name for probe %p", paddr); 1056 return (-1); 1057 } 1058 1059 if (mdb_vread(pd->dtpd_mod, DTRACE_MODNAMELEN, 1060 (uintptr_t)probe.dtpr_mod) == -1) { 1061 mdb_warn("failed to read module name for probe %p", paddr); 1062 return (-1); 1063 } 1064 1065 praddr = (uintptr_t)probe.dtpr_provider; 1066 1067 if (mdb_vread(&prov, sizeof (prov), praddr) == -1) { 1068 mdb_warn("failed to read provider for probe %p", paddr); 1069 return (-1); 1070 } 1071 1072 if (mdb_vread(pd->dtpd_provider, DTRACE_PROVNAMELEN, 1073 (uintptr_t)prov.dtpv_name) == -1) { 1074 mdb_warn("failed to read provider name for probe %p", paddr); 1075 return (-1); 1076 } 1077 1078 return (0); 1079 } 1080 1081 /*ARGSUSED*/ 1082 static int 1083 dtracemdb_aggdesc(dtrace_state_t *state, dtrace_aggdesc_t *agd) 1084 { 1085 dtrace_aggid_t aggid = agd->dtagd_id; 1086 dtrace_aggregation_t agg; 1087 dtrace_ecb_t ecb; 1088 uintptr_t addr, eaddr, ap, last; 1089 dtrace_action_t act; 1090 dtrace_recdesc_t *lrec; 1091 int nactions, nrecs; 1092 1093 addr = (uintptr_t)state->dts_aggregations + 1094 (aggid - 1) * sizeof (dtrace_aggregation_t *); 1095 1096 if (mdb_vread(&addr, sizeof (addr), addr) == -1) { 1097 mdb_warn("failed to read aggregation for aggid %d", aggid); 1098 return (-1); 1099 } 1100 1101 if (addr == NULL) { 1102 mdb_warn("aggid %d doesn't match an aggregation\n", aggid); 1103 return (-1); 1104 } 1105 1106 if (mdb_vread(&agg, sizeof (agg), addr) == -1) { 1107 mdb_warn("failed to read aggregation at %p", addr); 1108 return (-1); 1109 } 1110 1111 eaddr = (uintptr_t)agg.dtag_ecb; 1112 1113 if (mdb_vread(&ecb, sizeof (ecb), eaddr) == -1) { 1114 mdb_warn("failed to read ecb for aggregation %p", addr); 1115 return (-1); 1116 } 1117 1118 last = (uintptr_t)addr + offsetof(dtrace_aggregation_t, dtag_action); 1119 1120 /* 1121 * This is a little painful: in order to find the number of actions, 1122 * we need to first walk through them. 1123 */ 1124 ap = (uintptr_t)agg.dtag_first; 1125 nactions = 0; 1126 1127 for (;;) { 1128 if (mdb_vread(&act, sizeof (act), ap) == -1) { 1129 mdb_warn("failed to read action %p on aggregation %p", 1130 ap, addr); 1131 return (-1); 1132 } 1133 1134 nactions++; 1135 1136 if (ap == last) 1137 break; 1138 1139 ap = (uintptr_t)act.dta_next; 1140 } 1141 1142 lrec = &act.dta_rec; 1143 agd->dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - agg.dtag_base; 1144 1145 nrecs = agd->dtagd_nrecs; 1146 agd->dtagd_nrecs = nactions; 1147 agd->dtagd_epid = ecb.dte_epid; 1148 1149 ap = (uintptr_t)agg.dtag_first; 1150 nactions = 0; 1151 1152 for (;;) { 1153 dtrace_recdesc_t rec; 1154 1155 if (mdb_vread(&act, sizeof (act), ap) == -1) { 1156 mdb_warn("failed to read action %p on aggregation %p", 1157 ap, addr); 1158 return (-1); 1159 } 1160 1161 if (nrecs-- == 0) 1162 break; 1163 1164 rec = act.dta_rec; 1165 rec.dtrd_offset -= agg.dtag_base; 1166 rec.dtrd_uarg = 0; 1167 agd->dtagd_rec[nactions++] = rec; 1168 1169 if (ap == last) 1170 break; 1171 1172 ap = (uintptr_t)act.dta_next; 1173 } 1174 1175 return (0); 1176 } 1177 1178 static int 1179 dtracemdb_bufsnap(dtrace_buffer_t *which, dtrace_bufdesc_t *desc) 1180 { 1181 uintptr_t addr; 1182 size_t bufsize; 1183 dtrace_buffer_t buf; 1184 caddr_t data = desc->dtbd_data; 1185 processorid_t max_cpuid, cpu = desc->dtbd_cpu; 1186 1187 if (mdb_readvar(&max_cpuid, "max_cpuid") == -1) { 1188 mdb_warn("failed to read 'max_cpuid'"); 1189 errno = EIO; 1190 return (-1); 1191 } 1192 1193 if (cpu < 0 || cpu > max_cpuid) { 1194 errno = EINVAL; 1195 return (-1); 1196 } 1197 1198 addr = (uintptr_t)which + cpu * sizeof (dtrace_buffer_t); 1199 1200 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 1201 mdb_warn("failed to read buffer description at %p", addr); 1202 errno = EIO; 1203 return (-1); 1204 } 1205 1206 if (buf.dtb_tomax == NULL) { 1207 errno = ENOENT; 1208 return (-1); 1209 } 1210 1211 if (buf.dtb_flags & DTRACEBUF_WRAPPED) { 1212 bufsize = buf.dtb_size; 1213 } else { 1214 bufsize = buf.dtb_offset; 1215 } 1216 1217 if (mdb_vread(data, bufsize, (uintptr_t)buf.dtb_tomax) == -1) { 1218 mdb_warn("couldn't read buffer for CPU %d", cpu); 1219 errno = EIO; 1220 return (-1); 1221 } 1222 1223 if (buf.dtb_offset > buf.dtb_size) { 1224 mdb_warn("buffer for CPU %d has corrupt offset\n", cpu); 1225 errno = EIO; 1226 return (-1); 1227 } 1228 1229 if (buf.dtb_flags & DTRACEBUF_WRAPPED) { 1230 if (buf.dtb_xamot_offset > buf.dtb_size) { 1231 mdb_warn("ringbuffer for CPU %d has corrupt " 1232 "wrapped offset\n", cpu); 1233 errno = EIO; 1234 return (-1); 1235 } 1236 1237 /* 1238 * If the ring buffer has wrapped, it needs to be polished. 1239 * See the comment in dtrace_buffer_polish() for details. 1240 */ 1241 if (buf.dtb_offset < buf.dtb_xamot_offset) { 1242 bzero(data + buf.dtb_offset, 1243 buf.dtb_xamot_offset - buf.dtb_offset); 1244 } 1245 1246 if (buf.dtb_offset > buf.dtb_xamot_offset) { 1247 bzero(data + buf.dtb_offset, 1248 buf.dtb_size - buf.dtb_offset); 1249 bzero(data, buf.dtb_xamot_offset); 1250 } 1251 1252 desc->dtbd_oldest = buf.dtb_xamot_offset; 1253 } else { 1254 desc->dtbd_oldest = 0; 1255 } 1256 1257 desc->dtbd_size = bufsize; 1258 desc->dtbd_drops = buf.dtb_drops; 1259 desc->dtbd_errors = buf.dtb_errors; 1260 1261 return (0); 1262 } 1263 1264 /* 1265 * This is essentially identical to its cousin in the kernel. 1266 */ 1267 static dof_hdr_t * 1268 dtracemdb_dof_create(dtrace_state_t *state) 1269 { 1270 dof_hdr_t *dof; 1271 dof_sec_t *sec; 1272 dof_optdesc_t *opt; 1273 int i, len = sizeof (dof_hdr_t) + 1274 roundup(sizeof (dof_sec_t), sizeof (uint64_t)) + 1275 sizeof (dof_optdesc_t) * DTRACEOPT_MAX; 1276 1277 dof = mdb_zalloc(len, UM_SLEEP); 1278 dof->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; 1279 dof->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; 1280 dof->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; 1281 dof->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; 1282 1283 dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; 1284 dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; 1285 dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION_1; 1286 dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION; 1287 dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS; 1288 dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS; 1289 1290 dof->dofh_flags = 0; 1291 dof->dofh_hdrsize = sizeof (dof_hdr_t); 1292 dof->dofh_secsize = sizeof (dof_sec_t); 1293 dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */ 1294 dof->dofh_secoff = sizeof (dof_hdr_t); 1295 dof->dofh_loadsz = len; 1296 dof->dofh_filesz = len; 1297 dof->dofh_pad = 0; 1298 1299 /* 1300 * Fill in the option section header... 1301 */ 1302 sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t)); 1303 sec->dofs_type = DOF_SECT_OPTDESC; 1304 sec->dofs_align = sizeof (uint64_t); 1305 sec->dofs_flags = DOF_SECF_LOAD; 1306 sec->dofs_entsize = sizeof (dof_optdesc_t); 1307 1308 opt = (dof_optdesc_t *)((uintptr_t)sec + 1309 roundup(sizeof (dof_sec_t), sizeof (uint64_t))); 1310 1311 sec->dofs_offset = (uintptr_t)opt - (uintptr_t)dof; 1312 sec->dofs_size = sizeof (dof_optdesc_t) * DTRACEOPT_MAX; 1313 1314 for (i = 0; i < DTRACEOPT_MAX; i++) { 1315 opt[i].dofo_option = i; 1316 opt[i].dofo_strtab = DOF_SECIDX_NONE; 1317 opt[i].dofo_value = state->dts_options[i]; 1318 } 1319 1320 return (dof); 1321 } 1322 1323 static int 1324 dtracemdb_format(dtrace_state_t *state, dtrace_fmtdesc_t *desc) 1325 { 1326 uintptr_t addr, faddr; 1327 char c; 1328 int len = 0; 1329 1330 if (desc->dtfd_format == 0 || desc->dtfd_format > state->dts_nformats) { 1331 errno = EINVAL; 1332 return (-1); 1333 } 1334 1335 faddr = (uintptr_t)state->dts_formats + 1336 (desc->dtfd_format - 1) * sizeof (char *); 1337 1338 if (mdb_vread(&addr, sizeof (addr), faddr) == -1) { 1339 mdb_warn("failed to read format string pointer at %p", faddr); 1340 return (-1); 1341 } 1342 1343 do { 1344 if (mdb_vread(&c, sizeof (c), addr + len++) == -1) { 1345 mdb_warn("failed to read format string at %p", addr); 1346 return (-1); 1347 } 1348 } while (c != '\0'); 1349 1350 if (len > desc->dtfd_length) { 1351 desc->dtfd_length = len; 1352 return (0); 1353 } 1354 1355 if (mdb_vread(desc->dtfd_string, len, addr) == -1) { 1356 mdb_warn("failed to reread format string at %p", addr); 1357 return (-1); 1358 } 1359 1360 return (0); 1361 } 1362 1363 static int 1364 dtracemdb_status(dtrace_state_t *state, dtrace_status_t *status) 1365 { 1366 dtrace_dstate_t *dstate; 1367 int i, j; 1368 uint64_t nerrs; 1369 uintptr_t addr; 1370 int ncpu; 1371 1372 if (mdb_readvar(&ncpu, "_ncpu") == -1) { 1373 mdb_warn("failed to read '_ncpu'"); 1374 return (DCMD_ERR); 1375 } 1376 1377 bzero(status, sizeof (dtrace_status_t)); 1378 1379 if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) { 1380 errno = ENOENT; 1381 return (-1); 1382 } 1383 1384 /* 1385 * For the MDB backend, we never set dtst_exiting or dtst_filled. This 1386 * is by design: we don't want the library to try to stop tracing, 1387 * because it doesn't particularly mean anything. 1388 */ 1389 nerrs = state->dts_errors; 1390 dstate = &state->dts_vstate.dtvs_dynvars; 1391 1392 for (i = 0; i < ncpu; i++) { 1393 dtrace_dstate_percpu_t dcpu; 1394 dtrace_buffer_t buf; 1395 1396 addr = (uintptr_t)&dstate->dtds_percpu[i]; 1397 1398 if (mdb_vread(&dcpu, sizeof (dcpu), addr) == -1) { 1399 mdb_warn("failed to read per-CPU dstate at %p", addr); 1400 return (-1); 1401 } 1402 1403 status->dtst_dyndrops += dcpu.dtdsc_drops; 1404 status->dtst_dyndrops_dirty += dcpu.dtdsc_dirty_drops; 1405 status->dtst_dyndrops_rinsing += dcpu.dtdsc_rinsing_drops; 1406 1407 addr = (uintptr_t)&state->dts_buffer[i]; 1408 1409 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 1410 mdb_warn("failed to read per-CPU buffer at %p", addr); 1411 return (-1); 1412 } 1413 1414 nerrs += buf.dtb_errors; 1415 1416 for (j = 0; j < state->dts_nspeculations; j++) { 1417 dtrace_speculation_t spec; 1418 1419 addr = (uintptr_t)&state->dts_speculations[j]; 1420 1421 if (mdb_vread(&spec, sizeof (spec), addr) == -1) { 1422 mdb_warn("failed to read " 1423 "speculation at %p", addr); 1424 return (-1); 1425 } 1426 1427 addr = (uintptr_t)&spec.dtsp_buffer[i]; 1428 1429 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 1430 mdb_warn("failed to read " 1431 "speculative buffer at %p", addr); 1432 return (-1); 1433 } 1434 1435 status->dtst_specdrops += buf.dtb_xamot_drops; 1436 } 1437 } 1438 1439 status->dtst_specdrops_busy = state->dts_speculations_busy; 1440 status->dtst_specdrops_unavail = state->dts_speculations_unavail; 1441 status->dtst_errors = nerrs; 1442 1443 return (0); 1444 } 1445 1446 typedef struct dtracemdb_data { 1447 dtrace_state_t *dtmd_state; 1448 char *dtmd_symstr; 1449 char *dtmd_modstr; 1450 uintptr_t dtmd_addr; 1451 } dtracemdb_data_t; 1452 1453 static int 1454 dtracemdb_ioctl(void *varg, int cmd, void *arg) 1455 { 1456 dtracemdb_data_t *data = varg; 1457 dtrace_state_t *state = data->dtmd_state; 1458 1459 switch (cmd) { 1460 case DTRACEIOC_CONF: { 1461 dtrace_conf_t *conf = arg; 1462 1463 bzero(conf, sizeof (conf)); 1464 conf->dtc_difversion = DIF_VERSION; 1465 conf->dtc_difintregs = DIF_DIR_NREGS; 1466 conf->dtc_diftupregs = DIF_DTR_NREGS; 1467 conf->dtc_ctfmodel = CTF_MODEL_NATIVE; 1468 1469 return (0); 1470 } 1471 1472 case DTRACEIOC_DOFGET: { 1473 dof_hdr_t *hdr = arg, *dof; 1474 1475 dof = dtracemdb_dof_create(state); 1476 bcopy(dof, hdr, MIN(hdr->dofh_loadsz, dof->dofh_loadsz)); 1477 mdb_free(dof, dof->dofh_loadsz); 1478 1479 return (0); 1480 } 1481 1482 case DTRACEIOC_BUFSNAP: 1483 return (dtracemdb_bufsnap(state->dts_buffer, arg)); 1484 1485 case DTRACEIOC_AGGSNAP: 1486 return (dtracemdb_bufsnap(state->dts_aggbuffer, arg)); 1487 1488 case DTRACEIOC_AGGDESC: 1489 return (dtracemdb_aggdesc(state, arg)); 1490 1491 case DTRACEIOC_EPROBE: 1492 return (dtracemdb_eprobe(state, arg)); 1493 1494 case DTRACEIOC_PROBES: 1495 return (dtracemdb_probe(state, arg)); 1496 1497 case DTRACEIOC_FORMAT: 1498 return (dtracemdb_format(state, arg)); 1499 1500 case DTRACEIOC_STATUS: 1501 return (dtracemdb_status(state, arg)); 1502 1503 case DTRACEIOC_GO: 1504 *(processorid_t *)arg = -1; 1505 return (0); 1506 1507 case DTRACEIOC_ENABLE: 1508 errno = ENOTTY; /* see dt_open.c:dtrace_go() */ 1509 return (-1); 1510 1511 case DTRACEIOC_PROVIDER: 1512 case DTRACEIOC_PROBEMATCH: 1513 errno = ESRCH; 1514 return (-1); 1515 1516 default: 1517 mdb_warn("unexpected ioctl 0x%x (%s)\n", cmd, 1518 cmd == DTRACEIOC_PROVIDER ? "DTRACEIOC_PROVIDER" : 1519 cmd == DTRACEIOC_PROBES ? "DTRACEIOC_PROBES" : 1520 cmd == DTRACEIOC_BUFSNAP ? "DTRACEIOC_BUFSNAP" : 1521 cmd == DTRACEIOC_PROBEMATCH ? "DTRACEIOC_PROBEMATCH" : 1522 cmd == DTRACEIOC_ENABLE ? "DTRACEIOC_ENABLE" : 1523 cmd == DTRACEIOC_AGGSNAP ? "DTRACEIOC_AGGSNAP" : 1524 cmd == DTRACEIOC_EPROBE ? "DTRACEIOC_EPROBE" : 1525 cmd == DTRACEIOC_PROBEARG ? "DTRACEIOC_PROBEARG" : 1526 cmd == DTRACEIOC_CONF ? "DTRACEIOC_CONF" : 1527 cmd == DTRACEIOC_STATUS ? "DTRACEIOC_STATUS" : 1528 cmd == DTRACEIOC_GO ? "DTRACEIOC_GO" : 1529 cmd == DTRACEIOC_STOP ? "DTRACEIOC_STOP" : 1530 cmd == DTRACEIOC_AGGDESC ? "DTRACEIOC_AGGDESC" : 1531 cmd == DTRACEIOC_FORMAT ? "DTRACEIOC_FORMAT" : 1532 cmd == DTRACEIOC_DOFGET ? "DTRACEIOC_DOFGET" : 1533 cmd == DTRACEIOC_REPLICATE ? "DTRACEIOC_REPLICATE" : 1534 "???"); 1535 errno = ENXIO; 1536 return (-1); 1537 } 1538 } 1539 1540 static int 1541 dtracemdb_modctl(uintptr_t addr, const struct modctl *m, dtracemdb_data_t *data) 1542 { 1543 struct module mod; 1544 1545 if (m->mod_mp == NULL) 1546 return (WALK_NEXT); 1547 1548 if (mdb_vread(&mod, sizeof (mod), (uintptr_t)m->mod_mp) == -1) { 1549 mdb_warn("couldn't read modctl %p's module", addr); 1550 return (WALK_NEXT); 1551 } 1552 1553 if ((uintptr_t)mod.text > data->dtmd_addr) 1554 return (WALK_NEXT); 1555 1556 if ((uintptr_t)mod.text + mod.text_size <= data->dtmd_addr) 1557 return (WALK_NEXT); 1558 1559 if (mdb_readstr(data->dtmd_modstr, MDB_SYM_NAMLEN, 1560 (uintptr_t)m->mod_modname) == -1) 1561 return (WALK_ERR); 1562 1563 return (WALK_DONE); 1564 } 1565 1566 static int 1567 dtracemdb_lookup_by_addr(void *varg, GElf_Addr addr, GElf_Sym *symp, 1568 dtrace_syminfo_t *sip) 1569 { 1570 dtracemdb_data_t *data = varg; 1571 1572 if (data->dtmd_symstr == NULL) { 1573 data->dtmd_symstr = mdb_zalloc(MDB_SYM_NAMLEN, 1574 UM_SLEEP | UM_GC); 1575 } 1576 1577 if (data->dtmd_modstr == NULL) { 1578 data->dtmd_modstr = mdb_zalloc(MDB_SYM_NAMLEN, 1579 UM_SLEEP | UM_GC); 1580 } 1581 1582 if (symp != NULL) { 1583 if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY, data->dtmd_symstr, 1584 MDB_SYM_NAMLEN, symp) == -1) 1585 return (-1); 1586 } 1587 1588 if (sip != NULL) { 1589 data->dtmd_addr = addr; 1590 1591 (void) strcpy(data->dtmd_modstr, "???"); 1592 1593 if (mdb_walk("modctl", 1594 (mdb_walk_cb_t)dtracemdb_modctl, varg) == -1) { 1595 mdb_warn("couldn't walk 'modctl'"); 1596 return (-1); 1597 } 1598 1599 sip->dts_object = data->dtmd_modstr; 1600 sip->dts_id = 0; 1601 sip->dts_name = symp != NULL ? data->dtmd_symstr : NULL; 1602 } 1603 1604 return (0); 1605 } 1606 1607 /*ARGSUSED*/ 1608 static int 1609 dtracemdb_stat(void *varg, processorid_t cpu) 1610 { 1611 GElf_Sym sym; 1612 cpu_t c; 1613 uintptr_t caddr, addr; 1614 1615 if (mdb_lookup_by_name("cpu", &sym) == -1) { 1616 mdb_warn("failed to find symbol for 'cpu'"); 1617 return (-1); 1618 } 1619 1620 if (cpu * sizeof (uintptr_t) > sym.st_size) 1621 return (-1); 1622 1623 addr = (uintptr_t)sym.st_value + cpu * sizeof (uintptr_t); 1624 1625 if (mdb_vread(&caddr, sizeof (caddr), addr) == -1) { 1626 mdb_warn("failed to read cpu[%d]", cpu); 1627 return (-1); 1628 } 1629 1630 if (caddr == NULL) 1631 return (-1); 1632 1633 if (mdb_vread(&c, sizeof (c), caddr) == -1) { 1634 mdb_warn("failed to read cpu at %p", caddr); 1635 return (-1); 1636 } 1637 1638 if (c.cpu_flags & CPU_POWEROFF) { 1639 return (P_POWEROFF); 1640 } else if (c.cpu_flags & CPU_SPARE) { 1641 return (P_SPARE); 1642 } else if (c.cpu_flags & CPU_FAULTED) { 1643 return (P_FAULTED); 1644 } else if ((c.cpu_flags & (CPU_READY | CPU_OFFLINE)) != CPU_READY) { 1645 return (P_OFFLINE); 1646 } else if (c.cpu_flags & CPU_ENABLE) { 1647 return (P_ONLINE); 1648 } else { 1649 return (P_NOINTR); 1650 } 1651 } 1652 1653 /*ARGSUSED*/ 1654 static long 1655 dtracemdb_sysconf(void *varg, int name) 1656 { 1657 int max_ncpus; 1658 processorid_t max_cpuid; 1659 1660 switch (name) { 1661 case _SC_CPUID_MAX: 1662 if (mdb_readvar(&max_cpuid, "max_cpuid") == -1) { 1663 mdb_warn("failed to read 'max_cpuid'"); 1664 return (-1); 1665 } 1666 1667 return (max_cpuid); 1668 1669 case _SC_NPROCESSORS_MAX: 1670 if (mdb_readvar(&max_ncpus, "max_ncpus") == -1) { 1671 mdb_warn("failed to read 'max_ncpus'"); 1672 return (-1); 1673 } 1674 1675 return (max_ncpus); 1676 1677 default: 1678 mdb_warn("unexpected sysconf code %d\n", name); 1679 return (-1); 1680 } 1681 } 1682 1683 const dtrace_vector_t dtrace_mdbops = { 1684 dtracemdb_ioctl, 1685 dtracemdb_lookup_by_addr, 1686 dtracemdb_stat, 1687 dtracemdb_sysconf 1688 }; 1689 1690 typedef struct dtrace_dcmddata { 1691 dtrace_hdl_t *dtdd_dtp; 1692 int dtdd_cpu; 1693 int dtdd_quiet; 1694 int dtdd_flowindent; 1695 int dtdd_heading; 1696 } dtrace_dcmddata_t; 1697 1698 /*ARGSUSED*/ 1699 static int 1700 dtrace_dcmdrec(const dtrace_probedata_t *data, 1701 const dtrace_recdesc_t *rec, void *arg) 1702 { 1703 dtrace_dcmddata_t *dd = arg; 1704 1705 if (rec == NULL) { 1706 /* 1707 * We have processed the final record; output the newline if 1708 * we're not in quiet mode. 1709 */ 1710 if (!dd->dtdd_quiet) 1711 mdb_printf("\n"); 1712 1713 return (DTRACE_CONSUME_NEXT); 1714 } 1715 1716 return (DTRACE_CONSUME_THIS); 1717 } 1718 1719 /*ARGSUSED*/ 1720 static int 1721 dtrace_dcmdprobe(const dtrace_probedata_t *data, void *arg) 1722 { 1723 dtrace_probedesc_t *pd = data->dtpda_pdesc; 1724 processorid_t cpu = data->dtpda_cpu; 1725 dtrace_dcmddata_t *dd = arg; 1726 char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2]; 1727 1728 if (dd->dtdd_cpu != -1UL && dd->dtdd_cpu != cpu) 1729 return (DTRACE_CONSUME_NEXT); 1730 1731 if (dd->dtdd_heading == 0) { 1732 if (!dd->dtdd_flowindent) { 1733 if (!dd->dtdd_quiet) { 1734 mdb_printf("%3s %6s %32s\n", 1735 "CPU", "ID", "FUNCTION:NAME"); 1736 } 1737 } else { 1738 mdb_printf("%3s %-41s\n", "CPU", "FUNCTION"); 1739 } 1740 dd->dtdd_heading = 1; 1741 } 1742 1743 if (!dd->dtdd_flowindent) { 1744 if (!dd->dtdd_quiet) { 1745 (void) mdb_snprintf(name, sizeof (name), "%s:%s", 1746 pd->dtpd_func, pd->dtpd_name); 1747 1748 mdb_printf("%3d %6d %32s ", cpu, pd->dtpd_id, name); 1749 } 1750 } else { 1751 int indent = data->dtpda_indent; 1752 1753 if (data->dtpda_flow == DTRACEFLOW_NONE) { 1754 (void) mdb_snprintf(name, sizeof (name), "%*s%s%s:%s", 1755 indent, "", data->dtpda_prefix, pd->dtpd_func, 1756 pd->dtpd_name); 1757 } else { 1758 (void) mdb_snprintf(name, sizeof (name), "%*s%s%s", 1759 indent, "", data->dtpda_prefix, pd->dtpd_func); 1760 } 1761 1762 mdb_printf("%3d %-41s ", cpu, name); 1763 } 1764 1765 return (DTRACE_CONSUME_THIS); 1766 } 1767 1768 /*ARGSUSED*/ 1769 static int 1770 dtrace_dcmderr(dtrace_errdata_t *data, void *arg) 1771 { 1772 mdb_warn(data->dteda_msg); 1773 return (DTRACE_HANDLE_OK); 1774 } 1775 1776 /*ARGSUSED*/ 1777 static int 1778 dtrace_dcmddrop(dtrace_dropdata_t *data, void *arg) 1779 { 1780 mdb_warn(data->dtdda_msg); 1781 return (DTRACE_HANDLE_OK); 1782 } 1783 1784 /*ARGSUSED*/ 1785 static int 1786 dtrace_dcmdbuffered(dtrace_bufdata_t *bufdata, void *arg) 1787 { 1788 mdb_printf("%s", bufdata->dtbda_buffered); 1789 return (DTRACE_HANDLE_OK); 1790 } 1791 1792 /*ARGSUSED*/ 1793 int 1794 dtrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1795 { 1796 dtrace_state_t state; 1797 dtrace_hdl_t *dtp; 1798 int ncpu, err; 1799 uintptr_t c = -1UL; 1800 dtrace_dcmddata_t dd; 1801 dtrace_optval_t val; 1802 dtracemdb_data_t md; 1803 int rval = DCMD_ERR; 1804 1805 if (!(flags & DCMD_ADDRSPEC)) 1806 return (DCMD_USAGE); 1807 1808 if (mdb_getopts(argc, argv, 'c', MDB_OPT_UINTPTR, &c, NULL) != argc) 1809 return (DCMD_USAGE); 1810 1811 if (mdb_readvar(&ncpu, "_ncpu") == -1) { 1812 mdb_warn("failed to read '_ncpu'"); 1813 return (DCMD_ERR); 1814 } 1815 1816 if (mdb_vread(&state, sizeof (state), addr) == -1) { 1817 mdb_warn("couldn't read dtrace_state_t at %p", addr); 1818 return (DCMD_ERR); 1819 } 1820 1821 bzero(&md, sizeof (md)); 1822 md.dtmd_state = &state; 1823 1824 if ((dtp = dtrace_vopen(DTRACE_VERSION, DTRACE_O_NOSYS, &err, 1825 &dtrace_mdbops, &md)) == NULL) { 1826 mdb_warn("failed to initialize dtrace: %s\n", 1827 dtrace_errmsg(NULL, err)); 1828 return (DCMD_ERR); 1829 } 1830 1831 if (dtrace_go(dtp) != 0) { 1832 mdb_warn("failed to initialize dtrace: %s\n", 1833 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1834 goto err; 1835 } 1836 1837 bzero(&dd, sizeof (dd)); 1838 dd.dtdd_dtp = dtp; 1839 dd.dtdd_cpu = c; 1840 1841 if (dtrace_getopt(dtp, "flowindent", &val) == -1) { 1842 mdb_warn("couldn't get 'flowindent' option: %s\n", 1843 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1844 goto err; 1845 } 1846 1847 dd.dtdd_flowindent = (val != DTRACEOPT_UNSET); 1848 1849 if (dtrace_getopt(dtp, "quiet", &val) == -1) { 1850 mdb_warn("couldn't get 'quiet' option: %s\n", 1851 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1852 goto err; 1853 } 1854 1855 dd.dtdd_quiet = (val != DTRACEOPT_UNSET); 1856 1857 if (dtrace_handle_err(dtp, dtrace_dcmderr, NULL) == -1) { 1858 mdb_warn("couldn't add err handler: %s\n", 1859 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1860 goto err; 1861 } 1862 1863 if (dtrace_handle_drop(dtp, dtrace_dcmddrop, NULL) == -1) { 1864 mdb_warn("couldn't add drop handler: %s\n", 1865 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1866 goto err; 1867 } 1868 1869 if (dtrace_handle_buffered(dtp, dtrace_dcmdbuffered, NULL) == -1) { 1870 mdb_warn("couldn't add buffered handler: %s\n", 1871 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1872 goto err; 1873 } 1874 1875 if (dtrace_status(dtp) == -1) { 1876 mdb_warn("couldn't get status: %s\n", 1877 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1878 goto err; 1879 } 1880 1881 if (dtrace_aggregate_snap(dtp) == -1) { 1882 mdb_warn("couldn't snapshot aggregation: %s\n", 1883 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1884 goto err; 1885 } 1886 1887 if (dtrace_consume(dtp, NULL, 1888 dtrace_dcmdprobe, dtrace_dcmdrec, &dd) == -1) { 1889 mdb_warn("couldn't consume DTrace buffers: %s\n", 1890 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1891 } 1892 1893 if (dtrace_aggregate_print(dtp, NULL, NULL) == -1) { 1894 mdb_warn("couldn't print aggregation: %s\n", 1895 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1896 goto err; 1897 } 1898 1899 rval = DCMD_OK; 1900 err: 1901 dtrace_close(dtp); 1902 return (rval); 1903 } 1904 1905 static int 1906 dtrace_errhash_cmp(const void *l, const void *r) 1907 { 1908 uintptr_t lhs = *((uintptr_t *)l); 1909 uintptr_t rhs = *((uintptr_t *)r); 1910 dtrace_errhash_t lerr, rerr; 1911 char lmsg[256], rmsg[256]; 1912 1913 (void) mdb_vread(&lerr, sizeof (lerr), lhs); 1914 (void) mdb_vread(&rerr, sizeof (rerr), rhs); 1915 1916 if (lerr.dter_msg == NULL) 1917 return (-1); 1918 1919 if (rerr.dter_msg == NULL) 1920 return (1); 1921 1922 (void) mdb_readstr(lmsg, sizeof (lmsg), (uintptr_t)lerr.dter_msg); 1923 (void) mdb_readstr(rmsg, sizeof (rmsg), (uintptr_t)rerr.dter_msg); 1924 1925 return (strcmp(lmsg, rmsg)); 1926 } 1927 1928 int 1929 dtrace_errhash_init(mdb_walk_state_t *wsp) 1930 { 1931 GElf_Sym sym; 1932 uintptr_t *hash, addr; 1933 int i; 1934 1935 if (wsp->walk_addr != NULL) { 1936 mdb_warn("dtrace_errhash walk only supports global walks\n"); 1937 return (WALK_ERR); 1938 } 1939 1940 if (mdb_lookup_by_name("dtrace_errhash", &sym) == -1) { 1941 mdb_warn("couldn't find 'dtrace_errhash' (non-DEBUG kernel?)"); 1942 return (WALK_ERR); 1943 } 1944 1945 addr = (uintptr_t)sym.st_value; 1946 hash = mdb_alloc(DTRACE_ERRHASHSZ * sizeof (uintptr_t), 1947 UM_SLEEP | UM_GC); 1948 1949 for (i = 0; i < DTRACE_ERRHASHSZ; i++) 1950 hash[i] = addr + i * sizeof (dtrace_errhash_t); 1951 1952 qsort(hash, DTRACE_ERRHASHSZ, sizeof (uintptr_t), dtrace_errhash_cmp); 1953 1954 wsp->walk_addr = 0; 1955 wsp->walk_data = hash; 1956 1957 return (WALK_NEXT); 1958 } 1959 1960 int 1961 dtrace_errhash_step(mdb_walk_state_t *wsp) 1962 { 1963 int ndx = (int)wsp->walk_addr; 1964 uintptr_t *hash = wsp->walk_data; 1965 dtrace_errhash_t err; 1966 uintptr_t addr; 1967 1968 if (ndx >= DTRACE_ERRHASHSZ) 1969 return (WALK_DONE); 1970 1971 wsp->walk_addr = ndx + 1; 1972 addr = hash[ndx]; 1973 1974 if (mdb_vread(&err, sizeof (err), addr) == -1) { 1975 mdb_warn("failed to read dtrace_errhash_t at %p", addr); 1976 return (WALK_DONE); 1977 } 1978 1979 if (err.dter_msg == NULL) 1980 return (WALK_NEXT); 1981 1982 return (wsp->walk_callback(addr, &err, wsp->walk_cbdata)); 1983 } 1984 1985 /*ARGSUSED*/ 1986 int 1987 dtrace_errhash(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1988 { 1989 dtrace_errhash_t err; 1990 char msg[256]; 1991 1992 if (!(flags & DCMD_ADDRSPEC)) { 1993 if (mdb_walk_dcmd("dtrace_errhash", "dtrace_errhash", 1994 argc, argv) == -1) { 1995 mdb_warn("can't walk 'dtrace_errhash'"); 1996 return (DCMD_ERR); 1997 } 1998 1999 return (DCMD_OK); 2000 } 2001 2002 if (DCMD_HDRSPEC(flags)) 2003 mdb_printf("%8s %s\n", "COUNT", "ERROR"); 2004 2005 if (mdb_vread(&err, sizeof (err), addr) == -1) { 2006 mdb_warn("failed to read dtrace_errhash_t at %p", addr); 2007 return (DCMD_ERR); 2008 } 2009 2010 addr = (uintptr_t)err.dter_msg; 2011 2012 if (mdb_readstr(msg, sizeof (msg), addr) == -1) { 2013 mdb_warn("failed to read error msg at %p", addr); 2014 return (DCMD_ERR); 2015 } 2016 2017 mdb_printf("%8d %s", err.dter_count, msg); 2018 2019 /* 2020 * Some error messages include a newline -- only print the newline 2021 * if the message doesn't have one. 2022 */ 2023 if (msg[strlen(msg) - 1] != '\n') 2024 mdb_printf("\n"); 2025 2026 return (DCMD_OK); 2027 } 2028 2029 int 2030 dtrace_helptrace_init(mdb_walk_state_t *wsp) 2031 { 2032 uint32_t next; 2033 int enabled; 2034 2035 if (wsp->walk_addr != NULL) { 2036 mdb_warn("dtrace_helptrace only supports global walks\n"); 2037 return (WALK_ERR); 2038 } 2039 2040 if (mdb_readvar(&enabled, "dtrace_helptrace_enabled") == -1) { 2041 mdb_warn("couldn't read 'dtrace_helptrace_enabled'"); 2042 return (WALK_ERR); 2043 } 2044 2045 if (!enabled) { 2046 mdb_warn("helper tracing is not enabled\n"); 2047 return (WALK_ERR); 2048 } 2049 2050 if (mdb_readvar(&next, "dtrace_helptrace_next") == -1) { 2051 mdb_warn("couldn't read 'dtrace_helptrace_next'"); 2052 return (WALK_ERR); 2053 } 2054 2055 wsp->walk_addr = next; 2056 2057 return (WALK_NEXT); 2058 } 2059 2060 int 2061 dtrace_helptrace_step(mdb_walk_state_t *wsp) 2062 { 2063 uint32_t next, size, nlocals, bufsize; 2064 uintptr_t buffer, addr; 2065 dtrace_helptrace_t *ht; 2066 int rval; 2067 2068 if (mdb_readvar(&next, "dtrace_helptrace_next") == -1) { 2069 mdb_warn("couldn't read 'dtrace_helptrace_next'"); 2070 return (WALK_ERR); 2071 } 2072 2073 if (mdb_readvar(&bufsize, "dtrace_helptrace_bufsize") == -1) { 2074 mdb_warn("couldn't read 'dtrace_helptrace_bufsize'"); 2075 return (WALK_ERR); 2076 } 2077 2078 if (mdb_readvar(&buffer, "dtrace_helptrace_buffer") == -1) { 2079 mdb_warn("couldn't read 'dtrace_helptrace_buffer'"); 2080 return (WALK_ERR); 2081 } 2082 2083 if (mdb_readvar(&nlocals, "dtrace_helptrace_nlocals") == -1) { 2084 mdb_warn("couldn't read 'dtrace_helptrace_nlocals'"); 2085 return (WALK_ERR); 2086 } 2087 2088 size = sizeof (dtrace_helptrace_t) + 2089 nlocals * sizeof (uint64_t) - sizeof (uint64_t); 2090 2091 if (wsp->walk_addr + size > bufsize) { 2092 if (next == 0) 2093 return (WALK_DONE); 2094 2095 wsp->walk_addr = 0; 2096 } 2097 2098 addr = buffer + wsp->walk_addr; 2099 ht = alloca(size); 2100 2101 if (mdb_vread(ht, size, addr) == -1) { 2102 mdb_warn("couldn't read entry at %p", addr); 2103 return (WALK_ERR); 2104 } 2105 2106 if (ht->dtht_helper != NULL) { 2107 rval = wsp->walk_callback(addr, ht, wsp->walk_cbdata); 2108 2109 if (rval != WALK_NEXT) 2110 return (rval); 2111 } 2112 2113 if (wsp->walk_addr < next && wsp->walk_addr + size >= next) 2114 return (WALK_DONE); 2115 2116 wsp->walk_addr += size; 2117 return (WALK_NEXT); 2118 } 2119 2120 int 2121 dtrace_helptrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2122 { 2123 dtrace_helptrace_t help; 2124 dtrace_helper_action_t helper; 2125 char where[30]; 2126 uint_t opt_v = FALSE; 2127 uintptr_t haddr; 2128 2129 if (!(flags & DCMD_ADDRSPEC)) { 2130 if (mdb_walk_dcmd("dtrace_helptrace", "dtrace_helptrace", 2131 argc, argv) == -1) { 2132 mdb_warn("can't walk 'dtrace_helptrace'"); 2133 return (DCMD_ERR); 2134 } 2135 2136 return (DCMD_OK); 2137 } 2138 2139 if (mdb_getopts(argc, argv, 'v', 2140 MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) 2141 return (DCMD_USAGE); 2142 2143 if (DCMD_HDRSPEC(flags)) { 2144 mdb_printf(" %?s %?s %12s %s\n", 2145 "ADDR", "HELPER", "WHERE", "DIFO"); 2146 } 2147 2148 if (mdb_vread(&help, sizeof (help), addr) == -1) { 2149 mdb_warn("failed to read dtrace_helptrace_t at %p", addr); 2150 return (DCMD_ERR); 2151 } 2152 2153 switch (help.dtht_where) { 2154 case 0: 2155 (void) mdb_snprintf(where, sizeof (where), "predicate"); 2156 break; 2157 2158 case DTRACE_HELPTRACE_NEXT: 2159 (void) mdb_snprintf(where, sizeof (where), "next"); 2160 break; 2161 2162 case DTRACE_HELPTRACE_DONE: 2163 (void) mdb_snprintf(where, sizeof (where), "done"); 2164 break; 2165 2166 case DTRACE_HELPTRACE_ERR: 2167 (void) mdb_snprintf(where, sizeof (where), "err"); 2168 break; 2169 2170 default: 2171 (void) mdb_snprintf(where, sizeof (where), 2172 "action #%d", help.dtht_where); 2173 break; 2174 } 2175 2176 mdb_printf(" %?p %?p %12s ", addr, help.dtht_helper, where); 2177 2178 haddr = (uintptr_t)help.dtht_helper; 2179 2180 if (mdb_vread(&helper, sizeof (helper), haddr) == -1) { 2181 /* 2182 * We're not going to warn in this case -- we're just not going 2183 * to print anything exciting. 2184 */ 2185 mdb_printf("???\n"); 2186 } else { 2187 switch (help.dtht_where) { 2188 case 0: 2189 mdb_printf("%p\n", helper.dthp_predicate); 2190 break; 2191 2192 case DTRACE_HELPTRACE_NEXT: 2193 case DTRACE_HELPTRACE_DONE: 2194 case DTRACE_HELPTRACE_ERR: 2195 mdb_printf("-\n"); 2196 break; 2197 2198 default: 2199 haddr = (uintptr_t)helper.dthp_actions + 2200 (help.dtht_where - 1) * sizeof (uintptr_t); 2201 2202 if (mdb_vread(&haddr, sizeof (haddr), haddr) == -1) { 2203 mdb_printf("???\n"); 2204 } else { 2205 mdb_printf("%p\n", haddr); 2206 } 2207 } 2208 } 2209 2210 if (opt_v) { 2211 int i; 2212 2213 mdb_printf("%?s|\n%?s+--> %?s %4s %s\n", "", "", 2214 "ADDR", "NDX", "VALUE"); 2215 addr += sizeof (help) - sizeof (uint64_t); 2216 2217 for (i = 0; i < help.dtht_nlocals; i++) { 2218 uint64_t val; 2219 2220 if (mdb_vread(&val, sizeof (val), addr) == -1) { 2221 mdb_warn("couldn't read local at %p", addr); 2222 continue; 2223 } 2224 2225 mdb_printf("%?s %?p %4d %p\n", "", addr, i, val); 2226 addr += sizeof (uint64_t); 2227 } 2228 2229 mdb_printf("\n"); 2230 } 2231 2232 return (DCMD_OK); 2233 } 2234 2235 /*ARGSUSED*/ 2236 static int 2237 dtrace_state_walk(uintptr_t addr, const vmem_seg_t *seg, minor_t *highest) 2238 { 2239 if (seg->vs_end > *highest) 2240 *highest = seg->vs_end; 2241 2242 return (WALK_NEXT); 2243 } 2244 2245 typedef struct dtrace_state_walk { 2246 uintptr_t dtsw_softstate; 2247 minor_t dtsw_max; 2248 minor_t dtsw_current; 2249 } dtrace_state_walk_t; 2250 2251 int 2252 dtrace_state_init(mdb_walk_state_t *wsp) 2253 { 2254 uintptr_t dtrace_minor; 2255 minor_t max = 0; 2256 dtrace_state_walk_t *dw; 2257 2258 if (wsp->walk_addr != NULL) { 2259 mdb_warn("dtrace_state only supports global walks\n"); 2260 return (WALK_ERR); 2261 } 2262 2263 /* 2264 * Find the dtrace_minor vmem arena and walk it to get the maximum 2265 * minor number. 2266 */ 2267 if (mdb_readvar(&dtrace_minor, "dtrace_minor") == -1) { 2268 mdb_warn("failed to read 'dtrace_minor'"); 2269 return (WALK_ERR); 2270 } 2271 2272 if (mdb_pwalk("vmem_alloc", (mdb_walk_cb_t)dtrace_state_walk, 2273 &max, dtrace_minor) == -1) { 2274 mdb_warn("couldn't walk 'vmem_alloc'"); 2275 return (WALK_ERR); 2276 } 2277 2278 dw = mdb_zalloc(sizeof (dtrace_state_walk_t), UM_SLEEP | UM_GC); 2279 dw->dtsw_current = 0; 2280 dw->dtsw_max = max; 2281 2282 if (mdb_readvar(&dw->dtsw_softstate, "dtrace_softstate") == -1) { 2283 mdb_warn("failed to read 'dtrace_softstate'"); 2284 return (DCMD_ERR); 2285 } 2286 2287 wsp->walk_data = dw; 2288 2289 return (WALK_NEXT); 2290 } 2291 2292 int 2293 dtrace_state_step(mdb_walk_state_t *wsp) 2294 { 2295 dtrace_state_walk_t *dw = wsp->walk_data; 2296 uintptr_t statep; 2297 dtrace_state_t state; 2298 int rval; 2299 2300 while (mdb_get_soft_state_byaddr(dw->dtsw_softstate, dw->dtsw_current, 2301 &statep, NULL, 0) == -1) { 2302 if (dw->dtsw_current >= dw->dtsw_max) 2303 return (WALK_DONE); 2304 2305 dw->dtsw_current++; 2306 } 2307 2308 if (mdb_vread(&state, sizeof (state), statep) == -1) { 2309 mdb_warn("couldn't read dtrace_state_t at %p", statep); 2310 return (WALK_NEXT); 2311 } 2312 2313 rval = wsp->walk_callback(statep, &state, wsp->walk_cbdata); 2314 dw->dtsw_current++; 2315 2316 return (rval); 2317 } 2318 2319 typedef struct dtrace_state_data { 2320 int dtsd_major; 2321 uintptr_t dtsd_proc; 2322 uintptr_t dtsd_softstate; 2323 uintptr_t dtsd_state; 2324 } dtrace_state_data_t; 2325 2326 static int 2327 dtrace_state_file(uintptr_t addr, struct file *f, dtrace_state_data_t *data) 2328 { 2329 vnode_t vnode; 2330 proc_t proc; 2331 minor_t minor; 2332 uintptr_t statep; 2333 2334 if (mdb_vread(&vnode, sizeof (vnode), (uintptr_t)f->f_vnode) == -1) { 2335 mdb_warn("couldn't read vnode at %p", (uintptr_t)f->f_vnode); 2336 return (WALK_NEXT); 2337 } 2338 2339 if (getmajor(vnode.v_rdev) != data->dtsd_major) 2340 return (WALK_NEXT); 2341 2342 minor = getminor(vnode.v_rdev); 2343 2344 if (mdb_vread(&proc, sizeof (proc), data->dtsd_proc) == -1) { 2345 mdb_warn("failed to read proc at %p", data->dtsd_proc); 2346 return (WALK_NEXT); 2347 } 2348 2349 if (mdb_get_soft_state_byaddr(data->dtsd_softstate, minor, 2350 &statep, NULL, 0) == -1) { 2351 mdb_warn("failed to read softstate for minor %d", minor); 2352 return (WALK_NEXT); 2353 } 2354 2355 if (statep != data->dtsd_state) 2356 return (WALK_NEXT); 2357 2358 mdb_printf("%?p %5d %?p %-*s %?p\n", statep, minor, 2359 data->dtsd_proc, MAXCOMLEN, proc.p_user.u_comm, addr); 2360 2361 return (WALK_NEXT); 2362 } 2363 2364 /*ARGSUSED*/ 2365 static int 2366 dtrace_state_proc(uintptr_t addr, void *ignored, dtrace_state_data_t *data) 2367 { 2368 data->dtsd_proc = addr; 2369 2370 if (mdb_pwalk("file", 2371 (mdb_walk_cb_t)dtrace_state_file, data, addr) == -1) { 2372 mdb_warn("couldn't walk 'file' for proc %p", addr); 2373 return (WALK_ERR); 2374 } 2375 2376 return (WALK_NEXT); 2377 } 2378 2379 void 2380 dtrace_state_help(void) 2381 { 2382 mdb_printf("Given a dtrace_state_t structure, displays all " 2383 /*CSTYLED*/ 2384 "consumers, or \"<anonymous>\"\nif the consumer is anonymous. If " 2385 "no state structure is provided, iterates\nover all state " 2386 "structures.\n\n" 2387 "Addresses in ADDR column may be provided to ::dtrace to obtain\n" 2388 "dtrace(1M)-like output for in-kernel DTrace data.\n"); 2389 } 2390 2391 int 2392 dtrace_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2393 { 2394 uintptr_t devi; 2395 struct dev_info info; 2396 dtrace_state_data_t data; 2397 dtrace_anon_t anon; 2398 dtrace_state_t state; 2399 2400 if (!(flags & DCMD_ADDRSPEC)) { 2401 if (mdb_walk_dcmd("dtrace_state", 2402 "dtrace_state", argc, argv) == -1) { 2403 mdb_warn("can't walk dtrace_state"); 2404 return (DCMD_ERR); 2405 } 2406 return (DCMD_OK); 2407 } 2408 2409 if (DCMD_HDRSPEC(flags)) { 2410 mdb_printf("%?s %5s %?s %-*s %?s\n", "ADDR", "MINOR", "PROC", 2411 MAXCOMLEN, "NAME", "FILE"); 2412 } 2413 2414 /* 2415 * First determine if this is anonymous state. 2416 */ 2417 if (mdb_readvar(&anon, "dtrace_anon") == -1) { 2418 mdb_warn("failed to read 'dtrace_anon'"); 2419 return (DCMD_ERR); 2420 } 2421 2422 if ((uintptr_t)anon.dta_state == addr) { 2423 if (mdb_vread(&state, sizeof (state), addr) == -1) { 2424 mdb_warn("failed to read anon at %p", addr); 2425 return (DCMD_ERR); 2426 } 2427 2428 mdb_printf("%?p %5d %?s %-*s %?s\n", addr, 2429 getminor(state.dts_dev), "-", MAXCOMLEN, 2430 "<anonymous>", "-"); 2431 2432 return (DCMD_OK); 2433 } 2434 2435 if (mdb_readvar(&devi, "dtrace_devi") == -1) { 2436 mdb_warn("failed to read 'dtrace_devi'"); 2437 return (DCMD_ERR); 2438 } 2439 2440 if (mdb_vread(&info, sizeof (struct dev_info), devi) == -1) { 2441 mdb_warn("failed to read 'dev_info'"); 2442 return (DCMD_ERR); 2443 } 2444 2445 data.dtsd_major = info.devi_major; 2446 2447 if (mdb_readvar(&data.dtsd_softstate, "dtrace_softstate") == -1) { 2448 mdb_warn("failed to read 'dtrace_softstate'"); 2449 return (DCMD_ERR); 2450 } 2451 2452 data.dtsd_state = addr; 2453 2454 /* 2455 * Walk through all processes and all open files looking for this 2456 * state. It must be open somewhere... 2457 */ 2458 if (mdb_walk("proc", (mdb_walk_cb_t)dtrace_state_proc, &data) == -1) { 2459 mdb_warn("couldn't walk 'proc'"); 2460 return (DCMD_ERR); 2461 } 2462 2463 return (DCMD_OK); 2464 } 2465 2466 typedef struct dtrace_aggkey_data { 2467 uintptr_t *dtakd_hash; 2468 uintptr_t dtakd_hashsize; 2469 uintptr_t dtakd_next; 2470 uintptr_t dtakd_ndx; 2471 } dtrace_aggkey_data_t; 2472 2473 int 2474 dtrace_aggkey_init(mdb_walk_state_t *wsp) 2475 { 2476 dtrace_buffer_t buf; 2477 uintptr_t addr; 2478 dtrace_aggbuffer_t agb; 2479 dtrace_aggkey_data_t *data; 2480 size_t hsize; 2481 2482 if ((addr = wsp->walk_addr) == NULL) { 2483 mdb_warn("dtrace_aggkey walk needs aggregation buffer\n"); 2484 return (WALK_ERR); 2485 } 2486 2487 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 2488 mdb_warn("failed to read aggregation buffer at %p", addr); 2489 return (WALK_ERR); 2490 } 2491 2492 addr = (uintptr_t)buf.dtb_tomax + 2493 buf.dtb_size - sizeof (dtrace_aggbuffer_t); 2494 2495 if (mdb_vread(&agb, sizeof (agb), addr) == -1) { 2496 mdb_warn("failed to read dtrace_aggbuffer_t at %p", addr); 2497 return (WALK_ERR); 2498 } 2499 2500 data = mdb_zalloc(sizeof (dtrace_aggkey_data_t), UM_SLEEP); 2501 2502 data->dtakd_hashsize = agb.dtagb_hashsize; 2503 hsize = agb.dtagb_hashsize * sizeof (dtrace_aggkey_t *); 2504 data->dtakd_hash = mdb_alloc(hsize, UM_SLEEP); 2505 2506 if (mdb_vread(data->dtakd_hash, hsize, 2507 (uintptr_t)agb.dtagb_hash) == -1) { 2508 mdb_warn("failed to read hash at %p", 2509 (uintptr_t)agb.dtagb_hash); 2510 mdb_free(data->dtakd_hash, hsize); 2511 mdb_free(data, sizeof (dtrace_aggkey_data_t)); 2512 return (WALK_ERR); 2513 } 2514 2515 wsp->walk_data = data; 2516 return (WALK_NEXT); 2517 } 2518 2519 int 2520 dtrace_aggkey_step(mdb_walk_state_t *wsp) 2521 { 2522 dtrace_aggkey_data_t *data = wsp->walk_data; 2523 dtrace_aggkey_t key; 2524 uintptr_t addr; 2525 2526 while ((addr = data->dtakd_next) == NULL) { 2527 if (data->dtakd_ndx == data->dtakd_hashsize) 2528 return (WALK_DONE); 2529 2530 data->dtakd_next = data->dtakd_hash[data->dtakd_ndx++]; 2531 } 2532 2533 if (mdb_vread(&key, sizeof (key), addr) == -1) { 2534 mdb_warn("failed to read dtrace_aggkey_t at %p", addr); 2535 return (WALK_ERR); 2536 } 2537 2538 data->dtakd_next = (uintptr_t)key.dtak_next; 2539 2540 return (wsp->walk_callback(addr, &key, wsp->walk_cbdata)); 2541 } 2542 2543 void 2544 dtrace_aggkey_fini(mdb_walk_state_t *wsp) 2545 { 2546 dtrace_aggkey_data_t *data = wsp->walk_data; 2547 size_t hsize; 2548 2549 hsize = data->dtakd_hashsize * sizeof (dtrace_aggkey_t *); 2550 mdb_free(data->dtakd_hash, hsize); 2551 mdb_free(data, sizeof (dtrace_aggkey_data_t)); 2552 } 2553 2554 typedef struct dtrace_dynvar_data { 2555 dtrace_dynhash_t *dtdvd_hash; 2556 uintptr_t dtdvd_hashsize; 2557 uintptr_t dtdvd_next; 2558 uintptr_t dtdvd_ndx; 2559 } dtrace_dynvar_data_t; 2560 2561 int 2562 dtrace_dynvar_init(mdb_walk_state_t *wsp) 2563 { 2564 uintptr_t addr; 2565 dtrace_dstate_t dstate; 2566 dtrace_dynvar_data_t *data; 2567 size_t hsize; 2568 2569 if ((addr = wsp->walk_addr) == NULL) { 2570 mdb_warn("dtrace_dynvar walk needs dtrace_dstate_t\n"); 2571 return (WALK_ERR); 2572 } 2573 2574 if (mdb_vread(&dstate, sizeof (dstate), addr) == -1) { 2575 mdb_warn("failed to read dynamic state at %p", addr); 2576 return (WALK_ERR); 2577 } 2578 2579 data = mdb_zalloc(sizeof (dtrace_dynvar_data_t), UM_SLEEP); 2580 2581 data->dtdvd_hashsize = dstate.dtds_hashsize; 2582 hsize = dstate.dtds_hashsize * sizeof (dtrace_dynhash_t); 2583 data->dtdvd_hash = mdb_alloc(hsize, UM_SLEEP); 2584 2585 if (mdb_vread(data->dtdvd_hash, hsize, 2586 (uintptr_t)dstate.dtds_hash) == -1) { 2587 mdb_warn("failed to read hash at %p", 2588 (uintptr_t)dstate.dtds_hash); 2589 mdb_free(data->dtdvd_hash, hsize); 2590 mdb_free(data, sizeof (dtrace_dynvar_data_t)); 2591 return (WALK_ERR); 2592 } 2593 2594 wsp->walk_data = data; 2595 return (WALK_NEXT); 2596 } 2597 2598 int 2599 dtrace_dynvar_step(mdb_walk_state_t *wsp) 2600 { 2601 dtrace_dynvar_data_t *data = wsp->walk_data; 2602 dtrace_dynvar_t dynvar, *dvar; 2603 size_t dvarsize; 2604 uintptr_t addr; 2605 int nkeys; 2606 2607 while ((addr = data->dtdvd_next) == NULL) { 2608 if (data->dtdvd_ndx == data->dtdvd_hashsize) 2609 return (WALK_DONE); 2610 2611 data->dtdvd_next = 2612 (uintptr_t)data->dtdvd_hash[data->dtdvd_ndx++].dtdh_chain; 2613 } 2614 2615 if (mdb_vread(&dynvar, sizeof (dynvar), addr) == -1) { 2616 mdb_warn("failed to read dtrace_dynvar_t at %p", addr); 2617 return (WALK_ERR); 2618 } 2619 2620 /* 2621 * Now we need to allocate the correct size. 2622 */ 2623 nkeys = dynvar.dtdv_tuple.dtt_nkeys; 2624 dvarsize = (uintptr_t)&dynvar.dtdv_tuple.dtt_key[nkeys] - 2625 (uintptr_t)&dynvar; 2626 2627 dvar = alloca(dvarsize); 2628 2629 if (mdb_vread(dvar, dvarsize, addr) == -1) { 2630 mdb_warn("failed to read dtrace_dynvar_t at %p", addr); 2631 return (WALK_ERR); 2632 } 2633 2634 data->dtdvd_next = (uintptr_t)dynvar.dtdv_next; 2635 2636 return (wsp->walk_callback(addr, dvar, wsp->walk_cbdata)); 2637 } 2638 2639 void 2640 dtrace_dynvar_fini(mdb_walk_state_t *wsp) 2641 { 2642 dtrace_dynvar_data_t *data = wsp->walk_data; 2643 size_t hsize; 2644 2645 hsize = data->dtdvd_hashsize * sizeof (dtrace_dynvar_t *); 2646 mdb_free(data->dtdvd_hash, hsize); 2647 mdb_free(data, sizeof (dtrace_dynvar_data_t)); 2648 } 2649 2650 typedef struct dtrace_hashstat_data { 2651 size_t *dthsd_counts; 2652 size_t dthsd_hashsize; 2653 char *dthsd_data; 2654 size_t dthsd_size; 2655 int dthsd_header; 2656 } dtrace_hashstat_data_t; 2657 2658 typedef void (*dtrace_hashstat_func_t)(dtrace_hashstat_data_t *); 2659 2660 static void 2661 dtrace_hashstat_additive(dtrace_hashstat_data_t *data) 2662 { 2663 int i; 2664 int hval = 0; 2665 2666 for (i = 0; i < data->dthsd_size; i++) 2667 hval += data->dthsd_data[i]; 2668 2669 data->dthsd_counts[hval % data->dthsd_hashsize]++; 2670 } 2671 2672 static void 2673 dtrace_hashstat_shifty(dtrace_hashstat_data_t *data) 2674 { 2675 uint64_t hval = 0; 2676 int i; 2677 2678 if (data->dthsd_size < sizeof (uint64_t)) { 2679 dtrace_hashstat_additive(data); 2680 return; 2681 } 2682 2683 for (i = 0; i < data->dthsd_size; i += sizeof (uint64_t)) { 2684 /* LINTED - alignment */ 2685 uint64_t val = *((uint64_t *)&data->dthsd_data[i]); 2686 2687 hval += (val & ((1 << NBBY) - 1)) + 2688 ((val >> NBBY) & ((1 << NBBY) - 1)) + 2689 ((val >> (NBBY << 1)) & ((1 << NBBY) - 1)) + 2690 ((val >> (NBBY << 2)) & ((1 << NBBY) - 1)) + 2691 (val & USHRT_MAX) + (val >> (NBBY << 1) & USHRT_MAX); 2692 } 2693 2694 data->dthsd_counts[hval % data->dthsd_hashsize]++; 2695 } 2696 2697 static void 2698 dtrace_hashstat_knuth(dtrace_hashstat_data_t *data) 2699 { 2700 int i; 2701 int hval = data->dthsd_size; 2702 2703 for (i = 0; i < data->dthsd_size; i++) 2704 hval = (hval << 4) ^ (hval >> 28) ^ data->dthsd_data[i]; 2705 2706 data->dthsd_counts[hval % data->dthsd_hashsize]++; 2707 } 2708 2709 static void 2710 dtrace_hashstat_oneatatime(dtrace_hashstat_data_t *data) 2711 { 2712 int i; 2713 uint32_t hval = 0; 2714 2715 for (i = 0; i < data->dthsd_size; i++) { 2716 hval += data->dthsd_data[i]; 2717 hval += (hval << 10); 2718 hval ^= (hval >> 6); 2719 } 2720 2721 hval += (hval << 3); 2722 hval ^= (hval >> 11); 2723 hval += (hval << 15); 2724 2725 data->dthsd_counts[hval % data->dthsd_hashsize]++; 2726 } 2727 2728 static void 2729 dtrace_hashstat_fnv(dtrace_hashstat_data_t *data) 2730 { 2731 static const uint32_t prime = 0x01000193; 2732 uint32_t hval = 0; 2733 int i; 2734 2735 for (i = 0; i < data->dthsd_size; i++) { 2736 hval *= prime; 2737 hval ^= data->dthsd_data[i]; 2738 } 2739 2740 data->dthsd_counts[hval % data->dthsd_hashsize]++; 2741 } 2742 2743 static void 2744 dtrace_hashstat_stats(char *name, dtrace_hashstat_data_t *data) 2745 { 2746 size_t nz = 0, i; 2747 int longest = 0; 2748 size_t ttl = 0; 2749 double sum = 0.0; 2750 double avg; 2751 uint_t util, stddev; 2752 2753 if (!data->dthsd_header) { 2754 mdb_printf("%15s %11s %11s %11s %11s %11s\n", "NAME", 2755 "HASHSIZE", "%UTIL", "LONGEST", "AVERAGE", "STDDEV"); 2756 data->dthsd_header = 1; 2757 } 2758 2759 for (i = 0; i < data->dthsd_hashsize; i++) { 2760 if (data->dthsd_counts[i] != 0) { 2761 nz++; 2762 2763 if (data->dthsd_counts[i] > longest) 2764 longest = data->dthsd_counts[i]; 2765 2766 ttl += data->dthsd_counts[i]; 2767 } 2768 } 2769 2770 if (nz == 0) { 2771 mdb_printf("%15s %11d %11s %11s %11s %11s\n", name, 2772 data->dthsd_hashsize, "-", "-", "-", "-"); 2773 return; 2774 } 2775 2776 avg = (double)ttl / (double)nz; 2777 2778 for (i = 0; i < data->dthsd_hashsize; i++) { 2779 double delta = (double)data->dthsd_counts[i] - avg; 2780 2781 if (data->dthsd_counts[i] == 0) 2782 continue; 2783 2784 sum += delta * delta; 2785 } 2786 2787 util = (nz * 1000) / data->dthsd_hashsize; 2788 stddev = (uint_t)sqrt(sum / (double)nz) * 10; 2789 2790 mdb_printf("%15s %11d %9u.%1u %11d %11d %9u.%1u\n", name, 2791 data->dthsd_hashsize, util / 10, util % 10, longest, ttl / nz, 2792 stddev / 10, stddev % 10); 2793 } 2794 2795 static struct dtrace_hashstat { 2796 char *dths_name; 2797 dtrace_hashstat_func_t dths_func; 2798 } _dtrace_hashstat[] = { 2799 { "<actual>", NULL }, 2800 { "additive", dtrace_hashstat_additive }, 2801 { "shifty", dtrace_hashstat_shifty }, 2802 { "knuth", dtrace_hashstat_knuth }, 2803 { "one-at-a-time", dtrace_hashstat_oneatatime }, 2804 { "fnv", dtrace_hashstat_fnv }, 2805 { NULL, 0 } 2806 }; 2807 2808 typedef struct dtrace_aggstat_data { 2809 dtrace_hashstat_data_t dtagsd_hash; 2810 dtrace_hashstat_func_t dtagsd_func; 2811 } dtrace_aggstat_data_t; 2812 2813 static int 2814 dtrace_aggstat_walk(uintptr_t addr, dtrace_aggkey_t *key, 2815 dtrace_aggstat_data_t *data) 2816 { 2817 dtrace_hashstat_data_t *hdata = &data->dtagsd_hash; 2818 size_t size; 2819 2820 if (data->dtagsd_func == NULL) { 2821 size_t bucket = key->dtak_hashval % hdata->dthsd_hashsize; 2822 2823 hdata->dthsd_counts[bucket]++; 2824 return (WALK_NEXT); 2825 } 2826 2827 /* 2828 * We need to read the data. 2829 */ 2830 size = key->dtak_size - sizeof (dtrace_aggid_t); 2831 addr = (uintptr_t)key->dtak_data + sizeof (dtrace_aggid_t); 2832 hdata->dthsd_data = alloca(size); 2833 hdata->dthsd_size = size; 2834 2835 if (mdb_vread(hdata->dthsd_data, size, addr) == -1) { 2836 mdb_warn("couldn't read data at %p", addr); 2837 return (WALK_ERR); 2838 } 2839 2840 data->dtagsd_func(hdata); 2841 2842 return (WALK_NEXT); 2843 } 2844 2845 /*ARGSUSED*/ 2846 int 2847 dtrace_aggstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2848 { 2849 dtrace_buffer_t buf; 2850 uintptr_t aaddr; 2851 dtrace_aggbuffer_t agb; 2852 size_t hsize, i, actual, prime, evenpow; 2853 dtrace_aggstat_data_t data; 2854 dtrace_hashstat_data_t *hdata = &data.dtagsd_hash; 2855 2856 bzero(&data, sizeof (data)); 2857 2858 if (!(flags & DCMD_ADDRSPEC)) 2859 return (DCMD_USAGE); 2860 2861 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 2862 mdb_warn("failed to read aggregation buffer at %p", addr); 2863 return (DCMD_ERR); 2864 } 2865 2866 aaddr = (uintptr_t)buf.dtb_tomax + 2867 buf.dtb_size - sizeof (dtrace_aggbuffer_t); 2868 2869 if (mdb_vread(&agb, sizeof (agb), aaddr) == -1) { 2870 mdb_warn("failed to read dtrace_aggbuffer_t at %p", aaddr); 2871 return (DCMD_ERR); 2872 } 2873 2874 hsize = (actual = agb.dtagb_hashsize) * sizeof (size_t); 2875 hdata->dthsd_counts = mdb_alloc(hsize, UM_SLEEP | UM_GC); 2876 2877 /* 2878 * Now pick the largest prime smaller than the hash size. (If the 2879 * existing size is prime, we'll pick a smaller prime just for the 2880 * hell of it.) 2881 */ 2882 for (prime = agb.dtagb_hashsize - 1; prime > 7; prime--) { 2883 size_t limit = prime / 7; 2884 2885 for (i = 2; i < limit; i++) { 2886 if ((prime % i) == 0) 2887 break; 2888 } 2889 2890 if (i == limit) 2891 break; 2892 } 2893 2894 /* 2895 * And now we want to pick the largest power of two smaller than the 2896 * hashsize. 2897 */ 2898 for (i = 0; (1 << i) < agb.dtagb_hashsize; i++) 2899 continue; 2900 2901 evenpow = (1 << (i - 1)); 2902 2903 for (i = 0; _dtrace_hashstat[i].dths_name != NULL; i++) { 2904 data.dtagsd_func = _dtrace_hashstat[i].dths_func; 2905 2906 hdata->dthsd_hashsize = actual; 2907 hsize = hdata->dthsd_hashsize * sizeof (size_t); 2908 bzero(hdata->dthsd_counts, hsize); 2909 2910 if (mdb_pwalk("dtrace_aggkey", 2911 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) { 2912 mdb_warn("failed to walk dtrace_aggkey at %p", addr); 2913 return (DCMD_ERR); 2914 } 2915 2916 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 2917 2918 /* 2919 * If we were just printing the actual value, we won't try 2920 * any of the sizing experiments. 2921 */ 2922 if (data.dtagsd_func == NULL) 2923 continue; 2924 2925 hdata->dthsd_hashsize = prime; 2926 hsize = hdata->dthsd_hashsize * sizeof (size_t); 2927 bzero(hdata->dthsd_counts, hsize); 2928 2929 if (mdb_pwalk("dtrace_aggkey", 2930 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) { 2931 mdb_warn("failed to walk dtrace_aggkey at %p", addr); 2932 return (DCMD_ERR); 2933 } 2934 2935 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 2936 2937 hdata->dthsd_hashsize = evenpow; 2938 hsize = hdata->dthsd_hashsize * sizeof (size_t); 2939 bzero(hdata->dthsd_counts, hsize); 2940 2941 if (mdb_pwalk("dtrace_aggkey", 2942 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) { 2943 mdb_warn("failed to walk dtrace_aggkey at %p", addr); 2944 return (DCMD_ERR); 2945 } 2946 2947 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 2948 } 2949 2950 return (DCMD_OK); 2951 } 2952 2953 /*ARGSUSED*/ 2954 static int 2955 dtrace_dynstat_walk(uintptr_t addr, dtrace_dynvar_t *dynvar, 2956 dtrace_aggstat_data_t *data) 2957 { 2958 dtrace_hashstat_data_t *hdata = &data->dtagsd_hash; 2959 dtrace_tuple_t *tuple = &dynvar->dtdv_tuple; 2960 dtrace_key_t *key = tuple->dtt_key; 2961 size_t size = 0, offs = 0; 2962 int i, nkeys = tuple->dtt_nkeys; 2963 char *buf; 2964 2965 if (data->dtagsd_func == NULL) { 2966 size_t bucket = dynvar->dtdv_hashval % hdata->dthsd_hashsize; 2967 2968 hdata->dthsd_counts[bucket]++; 2969 return (WALK_NEXT); 2970 } 2971 2972 /* 2973 * We want to hand the hashing algorithm a contiguous buffer. First 2974 * run through the tuple and determine the size. 2975 */ 2976 for (i = 0; i < nkeys; i++) { 2977 if (key[i].dttk_size == 0) { 2978 size += sizeof (uint64_t); 2979 } else { 2980 size += key[i].dttk_size; 2981 } 2982 } 2983 2984 buf = alloca(size); 2985 2986 /* 2987 * Now go back through the tuple and copy the data into the buffer. 2988 */ 2989 for (i = 0; i < nkeys; i++) { 2990 if (key[i].dttk_size == 0) { 2991 bcopy(&key[i].dttk_value, &buf[offs], 2992 sizeof (uint64_t)); 2993 offs += sizeof (uint64_t); 2994 } else { 2995 if (mdb_vread(&buf[offs], key[i].dttk_size, 2996 key[i].dttk_value) == -1) { 2997 mdb_warn("couldn't read tuple data at %p", 2998 key[i].dttk_value); 2999 return (WALK_ERR); 3000 } 3001 3002 offs += key[i].dttk_size; 3003 } 3004 } 3005 3006 hdata->dthsd_data = buf; 3007 hdata->dthsd_size = size; 3008 3009 data->dtagsd_func(hdata); 3010 3011 return (WALK_NEXT); 3012 } 3013 3014 /*ARGSUSED*/ 3015 int 3016 dtrace_dynstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3017 { 3018 dtrace_dstate_t dstate; 3019 size_t hsize, i, actual, prime; 3020 dtrace_aggstat_data_t data; 3021 dtrace_hashstat_data_t *hdata = &data.dtagsd_hash; 3022 3023 bzero(&data, sizeof (data)); 3024 3025 if (!(flags & DCMD_ADDRSPEC)) 3026 return (DCMD_USAGE); 3027 3028 if (mdb_vread(&dstate, sizeof (dstate), addr) == -1) { 3029 mdb_warn("failed to read dynamic variable state at %p", addr); 3030 return (DCMD_ERR); 3031 } 3032 3033 hsize = (actual = dstate.dtds_hashsize) * sizeof (size_t); 3034 hdata->dthsd_counts = mdb_alloc(hsize, UM_SLEEP | UM_GC); 3035 3036 /* 3037 * Now pick the largest prime smaller than the hash size. (If the 3038 * existing size is prime, we'll pick a smaller prime just for the 3039 * hell of it.) 3040 */ 3041 for (prime = dstate.dtds_hashsize - 1; prime > 7; prime--) { 3042 size_t limit = prime / 7; 3043 3044 for (i = 2; i < limit; i++) { 3045 if ((prime % i) == 0) 3046 break; 3047 } 3048 3049 if (i == limit) 3050 break; 3051 } 3052 3053 for (i = 0; _dtrace_hashstat[i].dths_name != NULL; i++) { 3054 data.dtagsd_func = _dtrace_hashstat[i].dths_func; 3055 3056 hdata->dthsd_hashsize = actual; 3057 hsize = hdata->dthsd_hashsize * sizeof (size_t); 3058 bzero(hdata->dthsd_counts, hsize); 3059 3060 if (mdb_pwalk("dtrace_dynvar", 3061 (mdb_walk_cb_t)dtrace_dynstat_walk, &data, addr) == -1) { 3062 mdb_warn("failed to walk dtrace_dynvar at %p", addr); 3063 return (DCMD_ERR); 3064 } 3065 3066 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 3067 3068 /* 3069 * If we were just printing the actual value, we won't try 3070 * any of the sizing experiments. 3071 */ 3072 if (data.dtagsd_func == NULL) 3073 continue; 3074 3075 hdata->dthsd_hashsize = prime; 3076 hsize = hdata->dthsd_hashsize * sizeof (size_t); 3077 bzero(hdata->dthsd_counts, hsize); 3078 3079 if (mdb_pwalk("dtrace_dynvar", 3080 (mdb_walk_cb_t)dtrace_dynstat_walk, &data, addr) == -1) { 3081 mdb_warn("failed to walk dtrace_aggkey at %p", addr); 3082 return (DCMD_ERR); 3083 } 3084 3085 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 3086 } 3087 3088 return (DCMD_OK); 3089 } 3090 3091 static int 3092 dof_sect_strtab(uintptr_t addr, dof_sec_t *sec) 3093 { 3094 char *strtab; 3095 size_t sz, i; 3096 3097 sz = (size_t)sec->dofs_size; 3098 strtab = mdb_alloc(sz, UM_SLEEP | UM_GC); 3099 if (mdb_vread(strtab, sz, addr + sec->dofs_offset) != sz) { 3100 mdb_warn("failed to read string table"); 3101 return (1); 3102 } 3103 3104 mdb_printf("size = %lx\n", sz); 3105 3106 for (i = 0; i < sz; i++) { 3107 if (strtab[i] == '\0') 3108 mdb_printf("\\0"); 3109 else 3110 mdb_printf("%c", strtab[i]); 3111 } 3112 3113 mdb_printf("\n"); 3114 3115 return (0); 3116 } 3117 3118 static int 3119 dof_sect_provider(uintptr_t addr, dof_sec_t *sec, dof_sec_t *dofs) 3120 { 3121 dof_provider_t pv; 3122 dof_probe_t *pb; 3123 char *strtab; 3124 uint32_t *offs; 3125 uint8_t *args = NULL; 3126 size_t sz; 3127 int i, j; 3128 dof_stridx_t narg, xarg; 3129 3130 if (mdb_vread(&pv, sizeof (dof_provider_t), 3131 addr + sec->dofs_offset) != sizeof (dof_provider_t)) { 3132 mdb_warn("failed to read DOF provider"); 3133 return (-1); 3134 } 3135 3136 sz = dofs[pv.dofpv_strtab].dofs_size; 3137 strtab = mdb_alloc(sz, UM_SLEEP | UM_GC); 3138 if (mdb_vread(strtab, sz, addr + 3139 dofs[pv.dofpv_strtab].dofs_offset) != sz) { 3140 mdb_warn("failed to read string table"); 3141 return (-1); 3142 } 3143 3144 mdb_printf("%lx provider %s {\n", (ulong_t)(addr + sec->dofs_offset), 3145 strtab + pv.dofpv_name); 3146 3147 sz = dofs[pv.dofpv_prargs].dofs_size; 3148 if (sz != 0) { 3149 args = mdb_alloc(sz, UM_SLEEP | UM_GC); 3150 if (mdb_vread(args, sz, addr + 3151 dofs[pv.dofpv_prargs].dofs_offset) != sz) { 3152 mdb_warn("failed to read args"); 3153 return (-1); 3154 } 3155 } 3156 3157 sz = dofs[pv.dofpv_proffs].dofs_size; 3158 offs = mdb_alloc(sz, UM_SLEEP | UM_GC); 3159 if (mdb_vread(offs, sz, addr + dofs[pv.dofpv_proffs].dofs_offset) 3160 != sz) { 3161 mdb_warn("failed to read offs"); 3162 return (-1); 3163 } 3164 3165 sz = dofs[pv.dofpv_probes].dofs_size; 3166 pb = mdb_alloc(sz, UM_SLEEP | UM_GC); 3167 if (mdb_vread(pb, sz, addr + dofs[pv.dofpv_probes].dofs_offset) != sz) { 3168 mdb_warn("failed to read probes"); 3169 return (-1); 3170 } 3171 3172 (void) mdb_inc_indent(2); 3173 3174 for (i = 0; i < sz / dofs[pv.dofpv_probes].dofs_entsize; i++) { 3175 mdb_printf("%lx probe %s:%s {\n", (ulong_t)(addr + 3176 dofs[pv.dofpv_probes].dofs_offset + 3177 i * dofs[pv.dofpv_probes].dofs_entsize), 3178 strtab + pb[i].dofpr_func, 3179 strtab + pb[i].dofpr_name); 3180 3181 (void) mdb_inc_indent(2); 3182 mdb_printf("addr: %p\n", (ulong_t)pb[i].dofpr_addr); 3183 mdb_printf("offs: "); 3184 for (j = 0; j < pb[i].dofpr_noffs; j++) { 3185 mdb_printf("%s %x", "," + (j == 0), 3186 offs[pb[i].dofpr_offidx + j]); 3187 } 3188 mdb_printf("\n"); 3189 3190 mdb_printf("nargs:"); 3191 narg = pb[i].dofpr_nargv; 3192 for (j = 0; j < pb[i].dofpr_nargc; j++) { 3193 mdb_printf("%s %s", "," + (j == 0), strtab + narg); 3194 narg += strlen(strtab + narg) + 1; 3195 } 3196 mdb_printf("\n"); 3197 mdb_printf("xargs:"); 3198 xarg = pb[i].dofpr_xargv; 3199 for (j = 0; j < pb[i].dofpr_xargc; j++) { 3200 mdb_printf("%s %s", "," + (j == 0), strtab + xarg); 3201 xarg += strlen(strtab + xarg) + 1; 3202 } 3203 mdb_printf("\n"); 3204 mdb_printf("map: "); 3205 for (j = 0; j < pb[i].dofpr_xargc; j++) { 3206 mdb_printf("%s %d->%d", "," + (j == 0), 3207 args[pb[i].dofpr_argidx + j], j); 3208 } 3209 3210 (void) mdb_dec_indent(2); 3211 mdb_printf("\n}\n"); 3212 } 3213 3214 (void) mdb_dec_indent(2); 3215 mdb_printf("}\n"); 3216 3217 return (0); 3218 } 3219 3220 static int 3221 dof_sect_prargs(uintptr_t addr, dof_sec_t *sec) 3222 { 3223 int i; 3224 uint8_t arg; 3225 3226 for (i = 0; i < sec->dofs_size; i++) { 3227 if (mdb_vread(&arg, sizeof (arg), 3228 addr + sec->dofs_offset + i) != sizeof (arg)) { 3229 mdb_warn("failed to read argument"); 3230 return (1); 3231 } 3232 3233 mdb_printf("%d ", arg); 3234 3235 if (i % 20 == 19) 3236 mdb_printf("\n"); 3237 } 3238 3239 mdb_printf("\n"); 3240 3241 return (0); 3242 } 3243 3244 /*ARGSUSED*/ 3245 static int 3246 dofdump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3247 { 3248 dof_hdr_t dofh; 3249 dof_sec_t *dofs; 3250 int i; 3251 3252 if (mdb_vread(&dofh, sizeof (dof_hdr_t), addr) != sizeof (dof_hdr_t)) { 3253 mdb_warn("failed to read DOF header"); 3254 return (DCMD_ERR); 3255 } 3256 3257 dofs = mdb_alloc(sizeof (dof_sec_t) * dofh.dofh_secnum, 3258 UM_SLEEP | UM_GC); 3259 3260 for (i = 0; i < dofh.dofh_secnum; i++) { 3261 if (mdb_vread(&dofs[i], sizeof (dof_sec_t), dofh.dofh_secoff + 3262 addr + i * dofh.dofh_secsize) != sizeof (dof_sec_t)) { 3263 mdb_warn("failed to read DOF sections"); 3264 return (DCMD_ERR); 3265 } 3266 } 3267 3268 for (i = 0; i < dofh.dofh_secnum; i++) { 3269 mdb_printf("%lx Section %d: %s\n", (ulong_t)(dofh.dofh_secoff + 3270 addr + i * dofh.dofh_secsize), i, 3271 dof_sec_typename(dofs[i].dofs_type)); 3272 3273 (void) mdb_inc_indent(2); 3274 switch (dofs[i].dofs_type) { 3275 case DOF_SECT_PROVIDER: 3276 (void) dof_sect_provider(addr, &dofs[i], dofs); 3277 break; 3278 case DOF_SECT_STRTAB: 3279 (void) dof_sect_strtab(addr, &dofs[i]); 3280 break; 3281 case DOF_SECT_PRARGS: 3282 (void) dof_sect_prargs(addr, &dofs[i]); 3283 break; 3284 } 3285 (void) mdb_dec_indent(2); 3286 3287 mdb_printf("\n"); 3288 } 3289 3290 return (DCMD_OK); 3291 } 3292 3293 static const mdb_dcmd_t dcmds[] = { 3294 { "id2probe", ":", "translate a dtrace_id_t to a dtrace_probe_t", 3295 id2probe }, 3296 { "difinstr", ":", "disassemble a DIF instruction", difinstr }, 3297 { "difo", ":", "print a DIF object", difo }, 3298 { "dof_hdr", "?", "print a DOF header", dof_hdr }, 3299 { "dof_sec", ":", "print a DOF section header", dof_sec }, 3300 { "dof_ecbdesc", ":", "print a DOF ecbdesc", dof_ecbdesc }, 3301 { "dof_probedesc", ":", "print a DOF probedesc", dof_probedesc }, 3302 { "dof_actdesc", ":", "print a DOF actdesc", dof_actdesc }, 3303 { "dof_relohdr", ":", "print a DOF relocation header", dof_relohdr }, 3304 { "dof_relodesc", ":", "print a DOF relodesc", dof_relodesc }, 3305 { "dofdump", ":", "dump DOF", dofdump }, 3306 { "dtrace", ":[-c cpu]", "print dtrace(1M)-like output", 3307 dtrace, dtrace_help }, 3308 { "dtrace_errhash", ":", "print DTrace error hash", dtrace_errhash }, 3309 { "dtrace_helptrace", ":", "print DTrace helper trace", 3310 dtrace_helptrace }, 3311 { "dtrace_state", ":", "print active DTrace consumers", dtrace_state, 3312 dtrace_state_help }, 3313 { "dtrace_aggstat", ":", 3314 "print DTrace aggregation hash statistics", dtrace_aggstat }, 3315 { "dtrace_dynstat", ":", 3316 "print DTrace dynamic variable hash statistics", dtrace_dynstat }, 3317 { NULL } 3318 }; 3319 3320 static const mdb_walker_t walkers[] = { 3321 { "dof_sec", "walk DOF section header table given header address", 3322 dof_sec_walk_init, dof_sec_walk_step, dof_sec_walk_fini }, 3323 { "dtrace_errhash", "walk hash of DTrace error messasges", 3324 dtrace_errhash_init, dtrace_errhash_step }, 3325 { "dtrace_helptrace", "walk DTrace helper trace entries", 3326 dtrace_helptrace_init, dtrace_helptrace_step }, 3327 { "dtrace_state", "walk DTrace per-consumer softstate", 3328 dtrace_state_init, dtrace_state_step }, 3329 { "dtrace_aggkey", "walk DTrace aggregation keys", 3330 dtrace_aggkey_init, dtrace_aggkey_step, dtrace_aggkey_fini }, 3331 { "dtrace_dynvar", "walk DTrace dynamic variables", 3332 dtrace_dynvar_init, dtrace_dynvar_step, dtrace_dynvar_fini }, 3333 { NULL } 3334 }; 3335 3336 static const mdb_modinfo_t modinfo = { 3337 MDB_API_VERSION, dcmds, walkers 3338 }; 3339 3340 const mdb_modinfo_t * 3341 _mdb_init(void) 3342 { 3343 return (&modinfo); 3344 } 3345