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 2004 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 * MDB developer support module. This module is loaded automatically when the 31 * proc target is initialized and the target is mdb itself. In the future, we 32 * should document these facilities in the answerbook to aid module developers. 33 */ 34 35 /* 36 * The mere inclusion of sys/utsname.h causes _uname() and uname() to be 37 * defined on Intel, along with an external reference to _nuname(). Since we 38 * don't actually use uname (or utsname, for that matter) in this dmod, we'll 39 * prevent its inclusion. 40 */ 41 #define _SYS_UTSNAME_H 42 struct utsname; 43 44 #define _MDB 45 #include <mdb/mdb_modapi.h> 46 #include <mdb/mdb_frame.h> 47 #include <mdb/mdb_io_impl.h> 48 #include <mdb/mdb_target_impl.h> 49 #include <kmdb/kmdb_wr_impl.h> 50 #include <mdb/mdb.h> 51 52 static const mdb_t * 53 get_mdb(void) 54 { 55 static mdb_t m; 56 57 if (mdb_readvar(&m, "mdb") == -1) 58 mdb_warn("failed to read mdb_t state"); 59 60 return (&m); 61 } 62 63 static int 64 cmd_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 65 { 66 const char sep[] = 67 "-----------------------------------------------------------------"; 68 69 if (flags & DCMD_ADDRSPEC) { 70 char buf[MDB_NV_NAMELEN + 1]; 71 uintptr_t sp, pc; 72 mdb_idcmd_t idc; 73 mdb_frame_t f; 74 mdb_cmd_t c; 75 mdb_arg_t *ap; 76 size_t i; 77 78 if (mdb_vread(&f, sizeof (f), addr) == -1) { 79 mdb_warn("failed to read frame at %p", addr); 80 return (DCMD_ERR); 81 } 82 83 bzero(&c, sizeof (mdb_cmd_t)); 84 85 if (mdb_vread(&c, sizeof (c), (uintptr_t)f.f_cp) < 0 || 86 mdb_vread(&idc, sizeof (idc), (uintptr_t)c.c_dcmd) < 0 || 87 mdb_readstr(buf, sizeof (buf), (uintptr_t)idc.idc_name) < 1) 88 (void) strcpy(buf, "?"); 89 90 mdb_printf("+>\tframe <%u> %p (%s", f.f_id, addr, buf); 91 ap = mdb_alloc(c.c_argv.a_nelems * sizeof (mdb_arg_t), UM_GC); 92 93 if (ap != NULL && mdb_vread(ap, c.c_argv.a_nelems * 94 sizeof (mdb_arg_t), (uintptr_t)c.c_argv.a_data) > 0) { 95 for (i = 0; i < c.c_argv.a_nelems; i++) { 96 switch (ap[i].a_type) { 97 case MDB_TYPE_STRING: 98 if (mdb_readstr(buf, sizeof (buf), 99 (uintptr_t)ap[i].a_un.a_str) > 0) 100 mdb_printf(" %s", buf); 101 else 102 mdb_printf(" <str=%a>", 103 ap[i].a_un.a_str); 104 break; 105 case MDB_TYPE_IMMEDIATE: 106 mdb_printf(" $[ 0x%llx ]", 107 ap[i].a_un.a_val); 108 break; 109 case MDB_TYPE_CHAR: 110 mdb_printf(" '%c'", ap[i].a_un.a_char); 111 break; 112 default: 113 mdb_printf(" <type=%d>", ap[i].a_type); 114 } 115 } 116 } 117 118 mdb_printf(")\n\tf_list = %-?p\tf_cmds = %p\n", 119 addr + OFFSETOF(mdb_frame_t, f_list), 120 addr + OFFSETOF(mdb_frame_t, f_cmds)); 121 mdb_printf("\tf_istk = %-?p\tf_ostk = %p\n", 122 addr + OFFSETOF(mdb_frame_t, f_istk), 123 addr + OFFSETOF(mdb_frame_t, f_ostk)); 124 mdb_printf("\tf_wcbs = %-?p\tf_mblks = %p\n", 125 f.f_wcbs, f.f_mblks); 126 mdb_printf("\tf_pcmd = %-?p\tf_pcb = %p\n", 127 f.f_pcmd, addr + OFFSETOF(mdb_frame_t, f_pcb)); 128 mdb_printf("\tf_cp = %-?p\t\tf_flags = 0x%x\n\n", 129 f.f_cp, f.f_flags); 130 131 #if defined(__sparc) 132 sp = ((uintptr_t *)f.f_pcb)[1]; 133 pc = ((uintptr_t *)f.f_pcb)[2]; 134 #elif defined(__amd64) 135 sp = ((uintptr_t *)f.f_pcb)[5]; 136 pc = ((uintptr_t *)f.f_pcb)[7]; 137 #elif defined(__i386) 138 sp = ((uintptr_t *)f.f_pcb)[3]; 139 pc = ((uintptr_t *)f.f_pcb)[5]; 140 #else 141 #error Unknown ISA 142 #endif 143 if (pc != 0) 144 mdb_printf(" [ %0?lr %a() ]\n", sp, pc); 145 146 mdb_set_dot(sp); 147 mdb_inc_indent(8); 148 mdb_eval("<.$C0"); 149 mdb_dec_indent(8); 150 mdb_printf("%s\n", sep); 151 152 } else { 153 mdb_printf("%s\n", sep); 154 (void) mdb_walk_dcmd("mdb_frame", "mdb_stack", argc, argv); 155 } 156 157 return (DCMD_OK); 158 } 159 160 static int 161 cmd_frame(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 162 { 163 if ((flags & DCMD_ADDRSPEC) && argc == 0) 164 return (cmd_stack(addr, flags, argc, argv)); 165 166 return (DCMD_USAGE); 167 } 168 169 /*ARGSUSED*/ 170 static int 171 cmd_iob(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 172 { 173 mdb_iob_t iob; 174 mdb_io_t io; 175 176 if (!(flags & DCMD_ADDRSPEC) || argc != 0) 177 return (DCMD_USAGE); 178 179 if (DCMD_HDRSPEC(flags)) { 180 mdb_printf("%?s %6s %6s %?s %s\n", 181 "IOB", "NBYTES", "FLAGS", "IOP", "OPS"); 182 } 183 184 if (mdb_vread(&iob, sizeof (iob), addr) == -1 || 185 mdb_vread(&io, sizeof (io), (uintptr_t)iob.iob_iop) == -1) { 186 mdb_warn("failed to read iob at %p", addr); 187 return (DCMD_ERR); 188 } 189 190 mdb_printf("%?p %6lu %6x %?p %a\n", addr, (ulong_t)iob.iob_nbytes, 191 iob.iob_flags, iob.iob_iop, io.io_ops); 192 193 return (DCMD_OK); 194 } 195 196 /*ARGSUSED*/ 197 static int 198 cmd_in(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 199 { 200 mdb_printf("%p\n", get_mdb()->m_in); 201 return (DCMD_OK); 202 } 203 204 /*ARGSUSED*/ 205 static int 206 cmd_out(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 207 { 208 mdb_printf("%p\n", get_mdb()->m_out); 209 return (DCMD_OK); 210 } 211 212 /*ARGSUSED*/ 213 static int 214 cmd_err(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 215 { 216 mdb_printf("%p\n", get_mdb()->m_err); 217 return (DCMD_OK); 218 } 219 220 /*ARGSUSED*/ 221 static int 222 cmd_target(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 223 { 224 mdb_tgt_t t; 225 226 if (argc != 0) 227 return (DCMD_USAGE); 228 229 if (!(flags & DCMD_ADDRSPEC)) 230 addr = (uintptr_t)get_mdb()->m_target; 231 232 if (mdb_vread(&t, sizeof (t), addr) != sizeof (t)) { 233 mdb_warn("failed to read target at %p", addr); 234 return (DCMD_ERR); 235 } 236 237 mdb_printf("+>\ttarget %p (%a)\n", addr, t.t_ops); 238 239 mdb_printf("\tt_active = %-?p\tt_idle = %p\n", 240 addr + OFFSETOF(mdb_tgt_t, t_active), 241 addr + OFFSETOF(mdb_tgt_t, t_idle)); 242 mdb_printf("\tt_xdlist = %-?p\tt_module = %a\n", 243 addr + OFFSETOF(mdb_tgt_t, t_xdlist), t.t_module); 244 mdb_printf("\tt_pshandle = %-?p\tt_data = %p\n", 245 t.t_pshandle, t.t_data); 246 mdb_printf("\tt_status = %-?p\tt_matched = %p\n", 247 addr + OFFSETOF(mdb_tgt_t, t_status), t.t_matched); 248 mdb_printf("\tt_flags = %-?x\tt_vecnt = 0t%u\n", t.t_flags, t.t_vecnt); 249 mdb_printf("\tt_vepos = %-?d\tt_veneg = %d\n\n", t.t_vepos, t.t_veneg); 250 251 return (DCMD_OK); 252 } 253 254 /*ARGSUSED*/ 255 static int 256 cmd_sespec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 257 { 258 mdb_sespec_t se; 259 260 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 261 return (DCMD_USAGE); 262 263 if (mdb_vread(&se, sizeof (se), addr) != sizeof (se)) { 264 mdb_warn("failed to read sespec at %p", addr); 265 return (DCMD_ERR); 266 } 267 268 mdb_printf("+>\tsespec %p (%a)\n", addr, se.se_ops); 269 270 mdb_printf("\tse_selist = %-?p\tse_velist = %p\n", 271 addr + OFFSETOF(mdb_sespec_t, se_selist), 272 addr + OFFSETOF(mdb_sespec_t, se_velist)); 273 274 mdb_printf("\tse_data = %-?p\tse_refs = %u\n", 275 se.se_data, se.se_refs); 276 mdb_printf("\tse_state = %-?d\tse_errno = %d\n\n", 277 se.se_state, se.se_errno); 278 279 return (DCMD_OK); 280 } 281 282 /*ARGSUSED*/ 283 static int 284 cmd_vespec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 285 { 286 mdb_vespec_t ve; 287 288 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 289 return (DCMD_USAGE); 290 291 if (mdb_vread(&ve, sizeof (ve), addr) != sizeof (ve)) { 292 mdb_warn("failed to read vespec at %p", addr); 293 return (DCMD_ERR); 294 } 295 296 mdb_printf("+>\tvespec %p (id %d)\n", addr, ve.ve_id); 297 mdb_printf("\tve_list = %-?p\tve_flags = 0x%x\n", 298 addr + OFFSETOF(mdb_vespec_t, ve_list), ve.ve_flags); 299 mdb_printf("\tve_se = %-?p\tve_refs = %u\n", ve.ve_se, ve.ve_refs); 300 mdb_printf("\tve_hits = %-?u\tve_lim = %u\n", ve.ve_hits, ve.ve_limit); 301 mdb_printf("\tve_data = %-?p\tve_callback = %a\n", 302 ve.ve_data, ve.ve_callback); 303 mdb_printf("\tve_args = %-?p\tve_dtor = %a\n\n", 304 ve.ve_args, ve.ve_dtor); 305 306 return (DCMD_OK); 307 } 308 309 /*ARGSUSED*/ 310 static int 311 cmd_wr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 312 { 313 char path[MAXPATHLEN]; 314 kmdb_wr_t wn; 315 char dir; 316 317 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 318 return (DCMD_USAGE); 319 320 if (mdb_vread(&wn, sizeof (wn), addr) != sizeof (wn)) { 321 mdb_warn("failed to read wr node at %p", addr); 322 return (DCMD_ERR); 323 } 324 325 if (DCMD_HDRSPEC(flags)) { 326 mdb_printf("%-9s %3s %?s %s\n", 327 "COMMAND", "ERR", "MODCTL", "NAME"); 328 } 329 330 dir = "><"[WR_ISACK(&wn) != 0]; 331 switch (WR_TASK(&wn)) { 332 case WNTASK_DMOD_LOAD: { 333 kmdb_wr_load_t dlr; 334 335 if (mdb_vread(&dlr, sizeof (dlr), addr) != sizeof (dlr)) { 336 mdb_warn("failed to read kmdb_wr_load_t at %p", addr); 337 return (DCMD_ERR); 338 } 339 340 if (mdb_readstr(path, sizeof (path), 341 (uintptr_t)dlr.dlr_fname) < 0) { 342 mdb_warn("failed to read path name at %p", 343 dlr.dlr_fname); 344 *path = '\0'; 345 } 346 347 mdb_printf("%cload %3d %?p %s\n", dir, dlr.dlr_errno, 348 dlr.dlr_modctl, path); 349 break; 350 } 351 352 case WNTASK_DMOD_LOAD_ALL: 353 mdb_printf("%cload all %3d\n", dir, wn.wn_errno); 354 break; 355 356 case WNTASK_DMOD_UNLOAD: { 357 kmdb_wr_unload_t dur; 358 359 if (mdb_vread(&dur, sizeof (dur), addr) != sizeof (dur)) { 360 mdb_warn("failed to read kmdb_wr_unload_t at %p", addr); 361 return (DCMD_ERR); 362 } 363 364 if (mdb_readstr(path, sizeof (path), 365 (uintptr_t)dur.dur_modname) < 0) { 366 mdb_warn("failed to read module name at %p", 367 dur.dur_modname); 368 *path = '\0'; 369 } 370 371 mdb_printf("%cunload %3d %?p %s\n", dir, dur.dur_errno, 372 dur.dur_modctl, path); 373 break; 374 } 375 376 case WNTASK_DMOD_PATH_CHANGE: { 377 kmdb_wr_path_t dpth; 378 uintptr_t pathp; 379 int first = 1; 380 381 if (mdb_vread(&dpth, sizeof (dpth), addr) != sizeof (dpth)) { 382 mdb_warn("failed to read kmdb_wr_path_t at %p", addr); 383 return (DCMD_ERR); 384 } 385 386 mdb_printf("%cpath chg %3d ", dir, dpth.dpth_errno); 387 for (;;) { 388 if (mdb_vread(&pathp, sizeof (pathp), 389 (uintptr_t)dpth.dpth_path) != sizeof (pathp)) { 390 mdb_warn("failed to read path pointer at %p", 391 dpth.dpth_path); 392 break; 393 } 394 395 dpth.dpth_path++; 396 397 if (pathp == NULL) 398 break; 399 400 if (mdb_readstr(path, sizeof (path), pathp) < 0) { 401 mdb_warn("failed to read path at %p", pathp); 402 *path = '\0'; 403 } 404 405 mdb_printf("%s%s", (first ? "" : "\n "), 406 path); 407 first = 0; 408 } 409 mdb_printf("\n"); 410 break; 411 } 412 413 default: 414 mdb_warn("unknown task type %d\n", wn.wn_task); 415 return (DCMD_ERR); 416 } 417 418 return (DCMD_OK); 419 } 420 421 static int 422 iob_stack_walk_init(mdb_walk_state_t *wsp) 423 { 424 mdb_iob_stack_t stk; 425 426 if (mdb_vread(&stk, sizeof (stk), wsp->walk_addr) == -1) { 427 mdb_warn("failed to read iob_stack at %p", wsp->walk_addr); 428 return (WALK_ERR); 429 } 430 431 wsp->walk_addr = (uintptr_t)stk.stk_top; 432 return (WALK_NEXT); 433 } 434 435 static int 436 iob_stack_walk_step(mdb_walk_state_t *wsp) 437 { 438 uintptr_t addr = wsp->walk_addr; 439 mdb_iob_t iob; 440 441 if (addr == NULL) 442 return (WALK_DONE); 443 444 if (mdb_vread(&iob, sizeof (iob), addr) == -1) { 445 mdb_warn("failed to read iob at %p", addr); 446 return (WALK_ERR); 447 } 448 449 wsp->walk_addr = (uintptr_t)iob.iob_next; 450 return (wsp->walk_callback(addr, &iob, wsp->walk_cbdata)); 451 } 452 453 static int 454 frame_walk_init(mdb_walk_state_t *wsp) 455 { 456 if (wsp->walk_addr == NULL) 457 wsp->walk_addr = (uintptr_t)get_mdb()->m_flist.ml_prev; 458 459 return (WALK_NEXT); 460 } 461 462 static int 463 frame_walk_step(mdb_walk_state_t *wsp) 464 { 465 uintptr_t addr = wsp->walk_addr; 466 mdb_frame_t f; 467 468 if (addr == NULL) 469 return (WALK_DONE); 470 471 if (mdb_vread(&f, sizeof (f), addr) == -1) { 472 mdb_warn("failed to read frame at %p", addr); 473 return (WALK_ERR); 474 } 475 476 wsp->walk_addr = (uintptr_t)f.f_list.ml_prev; 477 return (wsp->walk_callback(addr, &f, wsp->walk_cbdata)); 478 } 479 480 static int 481 target_walk_init(mdb_walk_state_t *wsp) 482 { 483 if (wsp->walk_addr == NULL) 484 wsp->walk_addr = (uintptr_t)get_mdb()->m_target; 485 486 return (WALK_NEXT); 487 } 488 489 static int 490 target_walk_step(mdb_walk_state_t *wsp) 491 { 492 uintptr_t addr = wsp->walk_addr; 493 mdb_tgt_t t; 494 495 if (addr == NULL) 496 return (WALK_DONE); 497 498 if (mdb_vread(&t, sizeof (t), addr) == -1) { 499 mdb_warn("failed to read target at %p", addr); 500 return (WALK_ERR); 501 } 502 503 wsp->walk_addr = (uintptr_t)t.t_tgtlist.ml_next; 504 return (wsp->walk_callback(addr, &t, wsp->walk_cbdata)); 505 } 506 507 static int 508 sespec_walk_step(mdb_walk_state_t *wsp) 509 { 510 uintptr_t addr = wsp->walk_addr; 511 mdb_sespec_t s; 512 513 if (addr == NULL) 514 return (WALK_DONE); 515 516 if (mdb_vread(&s, sizeof (s), addr) == -1) { 517 mdb_warn("failed to read sespec at %p", addr); 518 return (WALK_ERR); 519 } 520 521 wsp->walk_addr = (uintptr_t)s.se_selist.ml_next; 522 return (wsp->walk_callback(addr, &s, wsp->walk_cbdata)); 523 } 524 525 static int 526 vespec_walk_step(mdb_walk_state_t *wsp) 527 { 528 uintptr_t addr = wsp->walk_addr; 529 mdb_vespec_t v; 530 531 if (addr == NULL) 532 return (WALK_DONE); 533 534 if (mdb_vread(&v, sizeof (v), addr) == -1) { 535 mdb_warn("failed to read vespec at %p", addr); 536 return (WALK_ERR); 537 } 538 539 wsp->walk_addr = (uintptr_t)v.ve_list.ml_next; 540 return (wsp->walk_callback(addr, &v, wsp->walk_cbdata)); 541 } 542 543 static int 544 se_matched_walk_step(mdb_walk_state_t *wsp) 545 { 546 uintptr_t addr = wsp->walk_addr; 547 mdb_sespec_t s; 548 549 if (addr == NULL) 550 return (WALK_DONE); 551 552 if (mdb_vread(&s, sizeof (s), addr) == -1) { 553 mdb_warn("failed to read sespec at %p", addr); 554 return (WALK_ERR); 555 } 556 557 wsp->walk_addr = (uintptr_t)s.se_matched; 558 return (wsp->walk_callback(addr, &s, wsp->walk_cbdata)); 559 } 560 561 static const mdb_dcmd_t dcmds[] = { 562 { "mdb_stack", "?", "print debugger stack", cmd_stack }, 563 { "mdb_frame", ":", "print debugger frame", cmd_frame }, 564 { "mdb_iob", ":", "print i/o buffer information", cmd_iob }, 565 { "mdb_in", NULL, "print stdin iob", cmd_in }, 566 { "mdb_out", NULL, "print stdout iob", cmd_out }, 567 { "mdb_err", NULL, "print stderr iob", cmd_err }, 568 { "mdb_tgt", "?", "print current target", cmd_target }, 569 { "mdb_sespec", ":", "print software event specifier", cmd_sespec }, 570 { "mdb_vespec", ":", "print virtual event specifier", cmd_vespec }, 571 { "kmdb_wr", NULL, "print a work queue entry", cmd_wr }, 572 { NULL } 573 }; 574 575 static const mdb_walker_t walkers[] = { 576 { "mdb_frame", "iterate over mdb_frame stack", 577 frame_walk_init, frame_walk_step, NULL }, 578 { "mdb_iob_stack", "iterate over mdb_iob_stack elements", 579 iob_stack_walk_init, iob_stack_walk_step, NULL }, 580 { "mdb_tgt", "iterate over active targets", 581 target_walk_init, target_walk_step, NULL }, 582 { "mdb_sespec", "iterate over software event specifiers", 583 NULL, sespec_walk_step, NULL }, 584 { "mdb_vespec", "iterate over virtual event specifiers", 585 NULL, vespec_walk_step, NULL }, 586 { "se_matched", "iterate over matched software event specifiers", 587 NULL, se_matched_walk_step, NULL }, 588 { NULL } 589 }; 590 591 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 592 593 const mdb_modinfo_t * 594 _mdb_init(void) 595 { 596 char buf[256]; 597 uintptr_t addr; 598 int rcount; 599 GElf_Sym sym; 600 601 if (mdb_lookup_by_name("mdb", &sym) == -1) { 602 mdb_warn("failed to read mdb state structure"); 603 return (NULL); 604 } 605 606 if (sym.st_size != sizeof (mdb_t)) { 607 mdb_printf("mdb: WARNING: mdb_ds may not match mdb " 608 "implementation (mdb_t mismatch)\n"); 609 } 610 611 if (mdb_readvar(&addr, "_mdb_abort_str") != -1 && addr != NULL && 612 mdb_readstr(buf, sizeof (buf), addr) > 0) 613 mdb_printf("mdb: debugger failed with error: %s\n", buf); 614 615 if (mdb_readvar(&rcount, "_mdb_abort_rcount") != -1 && rcount != 0) 616 mdb_printf("mdb: WARNING: resume executed %d times\n", rcount); 617 618 return (&modinfo); 619 } 620