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