1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1580 jwadams * Common Development and Distribution License (the "License"). 6 1580 jwadams * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8561 Scott * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <mdb/mdb_param.h> 27 0 stevel #include <mdb/mdb_modapi.h> 28 0 stevel #include <mdb/mdb_ks.h> 29 0 stevel #include <mdb/mdb_ctf.h> 30 0 stevel 31 0 stevel #include <sys/types.h> 32 0 stevel #include <sys/thread.h> 33 0 stevel #include <sys/session.h> 34 0 stevel #include <sys/user.h> 35 0 stevel #include <sys/proc.h> 36 0 stevel #include <sys/var.h> 37 0 stevel #include <sys/t_lock.h> 38 8048 Madhavan #include <sys/systm.h> 39 0 stevel #include <sys/callo.h> 40 0 stevel #include <sys/priocntl.h> 41 0 stevel #include <sys/class.h> 42 0 stevel #include <sys/regset.h> 43 0 stevel #include <sys/stack.h> 44 0 stevel #include <sys/cpuvar.h> 45 0 stevel #include <sys/vnode.h> 46 0 stevel #include <sys/vfs.h> 47 0 stevel #include <sys/flock_impl.h> 48 0 stevel #include <sys/kmem_impl.h> 49 0 stevel #include <sys/vmem_impl.h> 50 0 stevel #include <sys/kstat.h> 51 0 stevel #include <vm/seg_vn.h> 52 0 stevel #include <vm/anon.h> 53 0 stevel #include <vm/as.h> 54 0 stevel #include <vm/seg_map.h> 55 0 stevel #include <sys/dditypes.h> 56 0 stevel #include <sys/ddi_impldefs.h> 57 0 stevel #include <sys/sysmacros.h> 58 0 stevel #include <sys/sysconf.h> 59 0 stevel #include <sys/task.h> 60 0 stevel #include <sys/project.h> 61 0 stevel #include <sys/errorq_impl.h> 62 0 stevel #include <sys/cred_impl.h> 63 0 stevel #include <sys/zone.h> 64 0 stevel #include <sys/panic.h> 65 0 stevel #include <regex.h> 66 0 stevel #include <sys/port_impl.h> 67 0 stevel 68 789 ahrens #include "avl.h" 69 10696 David #include "bio.h" 70 10696 David #include "bitset.h" 71 6712 tomee #include "combined.h" 72 0 stevel #include "contract.h" 73 0 stevel #include "cpupart_mdb.h" 74 10696 David #include "ctxop.h" 75 10696 David #include "cyclic.h" 76 10696 David #include "damap.h" 77 0 stevel #include "devinfo.h" 78 10696 David #include "findstack.h" 79 10696 David #include "fm.h" 80 10696 David #include "group.h" 81 8561 Scott #include "irm.h" 82 10696 David #include "kgrep.h" 83 10696 David #include "kmem.h" 84 10696 David #include "ldi.h" 85 0 stevel #include "leaky.h" 86 0 stevel #include "lgrp.h" 87 0 stevel #include "list.h" 88 0 stevel #include "log.h" 89 10696 David #include "mdi.h" 90 10696 David #include "memory.h" 91 10696 David #include "mmd.h" 92 10696 David #include "modhash.h" 93 0 stevel #include "ndievents.h" 94 0 stevel #include "net.h" 95 3448 dh155122 #include "netstack.h" 96 0 stevel #include "nvpair.h" 97 10696 David #include "pg.h" 98 10696 David #include "rctl.h" 99 10696 David #include "sobj.h" 100 10696 David #include "streams.h" 101 10696 David #include "sysevent.h" 102 10889 Jonathan #include "taskq.h" 103 10696 David #include "thread.h" 104 0 stevel #include "tsd.h" 105 1676 jpk #include "tsol.h" 106 0 stevel #include "typegraph.h" 107 0 stevel #include "vfs.h" 108 0 stevel #include "zone.h" 109 10923 Evan #include "hotplug.h" 110 0 stevel 111 0 stevel /* 112 0 stevel * Surely this is defined somewhere... 113 0 stevel */ 114 0 stevel #define NINTR 16 115 4808 ek110237 116 4808 ek110237 #define KILOS 10 117 4808 ek110237 #define MEGS 20 118 4808 ek110237 #define GIGS 30 119 0 stevel 120 0 stevel #ifndef STACK_BIAS 121 0 stevel #define STACK_BIAS 0 122 0 stevel #endif 123 0 stevel 124 0 stevel static char 125 0 stevel pstat2ch(uchar_t state) 126 0 stevel { 127 0 stevel switch (state) { 128 0 stevel case SSLEEP: return ('S'); 129 0 stevel case SRUN: return ('R'); 130 0 stevel case SZOMB: return ('Z'); 131 0 stevel case SIDL: return ('I'); 132 0 stevel case SONPROC: return ('O'); 133 0 stevel case SSTOP: return ('T'); 134 3792 akolb case SWAIT: return ('W'); 135 0 stevel default: return ('?'); 136 0 stevel } 137 0 stevel } 138 0 stevel 139 0 stevel #define PS_PRTTHREADS 0x1 140 0 stevel #define PS_PRTLWPS 0x2 141 0 stevel #define PS_PSARGS 0x4 142 0 stevel #define PS_TASKS 0x8 143 0 stevel #define PS_PROJECTS 0x10 144 0 stevel #define PS_ZONES 0x20 145 0 stevel 146 0 stevel static int 147 0 stevel ps_threadprint(uintptr_t addr, const void *data, void *private) 148 0 stevel { 149 0 stevel const kthread_t *t = (const kthread_t *)data; 150 0 stevel uint_t prt_flags = *((uint_t *)private); 151 0 stevel 152 0 stevel static const mdb_bitmask_t t_state_bits[] = { 153 0 stevel { "TS_FREE", UINT_MAX, TS_FREE }, 154 0 stevel { "TS_SLEEP", TS_SLEEP, TS_SLEEP }, 155 0 stevel { "TS_RUN", TS_RUN, TS_RUN }, 156 0 stevel { "TS_ONPROC", TS_ONPROC, TS_ONPROC }, 157 0 stevel { "TS_ZOMB", TS_ZOMB, TS_ZOMB }, 158 0 stevel { "TS_STOPPED", TS_STOPPED, TS_STOPPED }, 159 3792 akolb { "TS_WAIT", TS_WAIT, TS_WAIT }, 160 0 stevel { NULL, 0, 0 } 161 0 stevel }; 162 0 stevel 163 0 stevel if (prt_flags & PS_PRTTHREADS) 164 0 stevel mdb_printf("\tT %?a <%b>\n", addr, t->t_state, t_state_bits); 165 0 stevel 166 0 stevel if (prt_flags & PS_PRTLWPS) 167 0 stevel mdb_printf("\tL %?a ID: %u\n", t->t_lwp, t->t_tid); 168 0 stevel 169 0 stevel return (WALK_NEXT); 170 0 stevel } 171 0 stevel 172 0 stevel int 173 0 stevel ps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 174 0 stevel { 175 0 stevel uint_t prt_flags = 0; 176 0 stevel proc_t pr; 177 0 stevel struct pid pid, pgid, sid; 178 0 stevel sess_t session; 179 0 stevel cred_t cred; 180 0 stevel task_t tk; 181 0 stevel kproject_t pj; 182 0 stevel zone_t zn; 183 0 stevel 184 0 stevel if (!(flags & DCMD_ADDRSPEC)) { 185 0 stevel if (mdb_walk_dcmd("proc", "ps", argc, argv) == -1) { 186 0 stevel mdb_warn("can't walk 'proc'"); 187 0 stevel return (DCMD_ERR); 188 0 stevel } 189 0 stevel return (DCMD_OK); 190 0 stevel } 191 0 stevel 192 0 stevel if (mdb_getopts(argc, argv, 193 0 stevel 'f', MDB_OPT_SETBITS, PS_PSARGS, &prt_flags, 194 0 stevel 'l', MDB_OPT_SETBITS, PS_PRTLWPS, &prt_flags, 195 0 stevel 'T', MDB_OPT_SETBITS, PS_TASKS, &prt_flags, 196 0 stevel 'P', MDB_OPT_SETBITS, PS_PROJECTS, &prt_flags, 197 0 stevel 'z', MDB_OPT_SETBITS, PS_ZONES, &prt_flags, 198 0 stevel 't', MDB_OPT_SETBITS, PS_PRTTHREADS, &prt_flags, NULL) != argc) 199 0 stevel return (DCMD_USAGE); 200 0 stevel 201 0 stevel if (DCMD_HDRSPEC(flags)) { 202 0 stevel mdb_printf("%<u>%1s %6s %6s %6s %6s ", 203 0 stevel "S", "PID", "PPID", "PGID", "SID"); 204 0 stevel if (prt_flags & PS_TASKS) 205 0 stevel mdb_printf("%5s ", "TASK"); 206 0 stevel if (prt_flags & PS_PROJECTS) 207 0 stevel mdb_printf("%5s ", "PROJ"); 208 0 stevel if (prt_flags & PS_ZONES) 209 0 stevel mdb_printf("%5s ", "ZONE"); 210 0 stevel mdb_printf("%6s %10s %?s %s%</u>\n", 211 0 stevel "UID", "FLAGS", "ADDR", "NAME"); 212 0 stevel } 213 0 stevel 214 0 stevel mdb_vread(&pr, sizeof (pr), addr); 215 0 stevel mdb_vread(&pid, sizeof (pid), (uintptr_t)pr.p_pidp); 216 0 stevel mdb_vread(&pgid, sizeof (pgid), (uintptr_t)pr.p_pgidp); 217 0 stevel mdb_vread(&cred, sizeof (cred), (uintptr_t)pr.p_cred); 218 0 stevel mdb_vread(&session, sizeof (session), (uintptr_t)pr.p_sessp); 219 0 stevel mdb_vread(&sid, sizeof (sid), (uintptr_t)session.s_sidp); 220 0 stevel if (prt_flags & (PS_TASKS | PS_PROJECTS)) 221 0 stevel mdb_vread(&tk, sizeof (tk), (uintptr_t)pr.p_task); 222 0 stevel if (prt_flags & PS_PROJECTS) 223 0 stevel mdb_vread(&pj, sizeof (pj), (uintptr_t)tk.tk_proj); 224 0 stevel if (prt_flags & PS_ZONES) 225 0 stevel mdb_vread(&zn, sizeof (zone_t), (uintptr_t)pr.p_zone); 226 0 stevel 227 0 stevel mdb_printf("%c %6d %6d %6d %6d ", 228 0 stevel pstat2ch(pr.p_stat), pid.pid_id, pr.p_ppid, pgid.pid_id, 229 0 stevel sid.pid_id); 230 0 stevel if (prt_flags & PS_TASKS) 231 0 stevel mdb_printf("%5d ", tk.tk_tkid); 232 0 stevel if (prt_flags & PS_PROJECTS) 233 0 stevel mdb_printf("%5d ", pj.kpj_id); 234 0 stevel if (prt_flags & PS_ZONES) 235 0 stevel mdb_printf("%5d ", zn.zone_id); 236 0 stevel mdb_printf("%6d 0x%08x %0?p %s\n", 237 0 stevel cred.cr_uid, pr.p_flag, addr, 238 0 stevel (prt_flags & PS_PSARGS) ? pr.p_user.u_psargs : pr.p_user.u_comm); 239 0 stevel 240 0 stevel if (prt_flags & ~PS_PSARGS) 241 0 stevel (void) mdb_pwalk("thread", ps_threadprint, &prt_flags, addr); 242 0 stevel 243 0 stevel return (DCMD_OK); 244 0 stevel } 245 0 stevel 246 0 stevel #define PG_NEWEST 0x0001 247 0 stevel #define PG_OLDEST 0x0002 248 0 stevel #define PG_PIPE_OUT 0x0004 249 1014 vb160487 #define PG_EXACT_MATCH 0x0008 250 0 stevel 251 0 stevel typedef struct pgrep_data { 252 0 stevel uint_t pg_flags; 253 0 stevel uint_t pg_psflags; 254 0 stevel uintptr_t pg_xaddr; 255 0 stevel hrtime_t pg_xstart; 256 0 stevel const char *pg_pat; 257 0 stevel #ifndef _KMDB 258 0 stevel regex_t pg_reg; 259 0 stevel #endif 260 0 stevel } pgrep_data_t; 261 0 stevel 262 0 stevel /*ARGSUSED*/ 263 0 stevel static int 264 0 stevel pgrep_cb(uintptr_t addr, const void *pdata, void *data) 265 0 stevel { 266 0 stevel const proc_t *prp = pdata; 267 0 stevel pgrep_data_t *pgp = data; 268 0 stevel #ifndef _KMDB 269 0 stevel regmatch_t pmatch; 270 0 stevel #endif 271 0 stevel 272 0 stevel /* 273 0 stevel * kmdb doesn't have access to the reg* functions, so we fall back 274 1014 vb160487 * to strstr/strcmp. 275 0 stevel */ 276 0 stevel #ifdef _KMDB 277 1014 vb160487 if ((pgp->pg_flags & PG_EXACT_MATCH) ? 278 1014 vb160487 (strcmp(prp->p_user.u_comm, pgp->pg_pat) != 0) : 279 1014 vb160487 (strstr(prp->p_user.u_comm, pgp->pg_pat) == NULL)) 280 0 stevel return (WALK_NEXT); 281 0 stevel #else 282 0 stevel if (regexec(&pgp->pg_reg, prp->p_user.u_comm, 1, &pmatch, 0) != 0) 283 1014 vb160487 return (WALK_NEXT); 284 1014 vb160487 285 1014 vb160487 if ((pgp->pg_flags & PG_EXACT_MATCH) && 286 1014 vb160487 (pmatch.rm_so != 0 || prp->p_user.u_comm[pmatch.rm_eo] != '\0')) 287 0 stevel return (WALK_NEXT); 288 0 stevel #endif 289 0 stevel 290 0 stevel if (pgp->pg_flags & (PG_NEWEST | PG_OLDEST)) { 291 0 stevel hrtime_t start; 292 0 stevel 293 0 stevel start = (hrtime_t)prp->p_user.u_start.tv_sec * NANOSEC + 294 0 stevel prp->p_user.u_start.tv_nsec; 295 0 stevel 296 0 stevel if (pgp->pg_flags & PG_NEWEST) { 297 0 stevel if (pgp->pg_xaddr == NULL || start > pgp->pg_xstart) { 298 0 stevel pgp->pg_xaddr = addr; 299 0 stevel pgp->pg_xstart = start; 300 0 stevel } 301 0 stevel } else { 302 0 stevel if (pgp->pg_xaddr == NULL || start < pgp->pg_xstart) { 303 0 stevel pgp->pg_xaddr = addr; 304 0 stevel pgp->pg_xstart = start; 305 0 stevel } 306 0 stevel } 307 0 stevel 308 0 stevel } else if (pgp->pg_flags & PG_PIPE_OUT) { 309 0 stevel mdb_printf("%p\n", addr); 310 0 stevel 311 0 stevel } else { 312 0 stevel if (mdb_call_dcmd("ps", addr, pgp->pg_psflags, 0, NULL) != 0) { 313 0 stevel mdb_warn("can't invoke 'ps'"); 314 0 stevel return (WALK_DONE); 315 0 stevel } 316 0 stevel pgp->pg_psflags &= ~DCMD_LOOPFIRST; 317 0 stevel } 318 0 stevel 319 0 stevel return (WALK_NEXT); 320 0 stevel } 321 0 stevel 322 0 stevel /*ARGSUSED*/ 323 0 stevel int 324 0 stevel pgrep(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 325 0 stevel { 326 0 stevel pgrep_data_t pg; 327 0 stevel int i; 328 0 stevel #ifndef _KMDB 329 0 stevel int err; 330 0 stevel #endif 331 0 stevel 332 0 stevel if (flags & DCMD_ADDRSPEC) 333 0 stevel return (DCMD_USAGE); 334 0 stevel 335 0 stevel pg.pg_flags = 0; 336 0 stevel pg.pg_xaddr = 0; 337 0 stevel 338 0 stevel i = mdb_getopts(argc, argv, 339 0 stevel 'n', MDB_OPT_SETBITS, PG_NEWEST, &pg.pg_flags, 340 0 stevel 'o', MDB_OPT_SETBITS, PG_OLDEST, &pg.pg_flags, 341 1014 vb160487 'x', MDB_OPT_SETBITS, PG_EXACT_MATCH, &pg.pg_flags, 342 0 stevel NULL); 343 0 stevel 344 0 stevel argc -= i; 345 0 stevel argv += i; 346 0 stevel 347 0 stevel if (argc != 1) 348 0 stevel return (DCMD_USAGE); 349 0 stevel 350 0 stevel /* 351 0 stevel * -n and -o are mutually exclusive. 352 0 stevel */ 353 0 stevel if ((pg.pg_flags & PG_NEWEST) && (pg.pg_flags & PG_OLDEST)) 354 0 stevel return (DCMD_USAGE); 355 0 stevel 356 0 stevel if (argv->a_type != MDB_TYPE_STRING) 357 0 stevel return (DCMD_USAGE); 358 0 stevel 359 0 stevel if (flags & DCMD_PIPE_OUT) 360 0 stevel pg.pg_flags |= PG_PIPE_OUT; 361 0 stevel 362 0 stevel pg.pg_pat = argv->a_un.a_str; 363 0 stevel if (DCMD_HDRSPEC(flags)) 364 0 stevel pg.pg_psflags = DCMD_ADDRSPEC | DCMD_LOOP | DCMD_LOOPFIRST; 365 0 stevel else 366 0 stevel pg.pg_psflags = DCMD_ADDRSPEC | DCMD_LOOP; 367 0 stevel 368 0 stevel #ifndef _KMDB 369 0 stevel if ((err = regcomp(&pg.pg_reg, pg.pg_pat, REG_EXTENDED)) != 0) { 370 0 stevel size_t nbytes; 371 0 stevel char *buf; 372 0 stevel 373 0 stevel nbytes = regerror(err, &pg.pg_reg, NULL, 0); 374 0 stevel buf = mdb_alloc(nbytes + 1, UM_SLEEP | UM_GC); 375 0 stevel (void) regerror(err, &pg.pg_reg, buf, nbytes); 376 0 stevel mdb_warn("%s\n", buf); 377 0 stevel 378 0 stevel return (DCMD_ERR); 379 0 stevel } 380 0 stevel #endif 381 0 stevel 382 0 stevel if (mdb_walk("proc", pgrep_cb, &pg) != 0) { 383 0 stevel mdb_warn("can't walk 'proc'"); 384 0 stevel return (DCMD_ERR); 385 0 stevel } 386 0 stevel 387 0 stevel if (pg.pg_xaddr != 0 && (pg.pg_flags & (PG_NEWEST | PG_OLDEST))) { 388 0 stevel if (pg.pg_flags & PG_PIPE_OUT) { 389 0 stevel mdb_printf("%p\n", pg.pg_xaddr); 390 0 stevel } else { 391 0 stevel if (mdb_call_dcmd("ps", pg.pg_xaddr, pg.pg_psflags, 392 0 stevel 0, NULL) != 0) { 393 0 stevel mdb_warn("can't invoke 'ps'"); 394 0 stevel return (DCMD_ERR); 395 0 stevel } 396 0 stevel } 397 0 stevel } 398 0 stevel 399 0 stevel return (DCMD_OK); 400 0 stevel } 401 0 stevel 402 0 stevel int 403 0 stevel task(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 404 0 stevel { 405 0 stevel task_t tk; 406 0 stevel kproject_t pj; 407 0 stevel 408 0 stevel if (!(flags & DCMD_ADDRSPEC)) { 409 0 stevel if (mdb_walk_dcmd("task_cache", "task", argc, argv) == -1) { 410 0 stevel mdb_warn("can't walk task_cache"); 411 0 stevel return (DCMD_ERR); 412 0 stevel } 413 0 stevel return (DCMD_OK); 414 0 stevel } 415 0 stevel if (DCMD_HDRSPEC(flags)) { 416 0 stevel mdb_printf("%<u>%?s %6s %6s %6s %6s %10s%</u>\n", 417 0 stevel "ADDR", "TASKID", "PROJID", "ZONEID", "REFCNT", "FLAGS"); 418 0 stevel } 419 0 stevel if (mdb_vread(&tk, sizeof (task_t), addr) == -1) { 420 0 stevel mdb_warn("can't read task_t structure at %p", addr); 421 0 stevel return (DCMD_ERR); 422 0 stevel } 423 0 stevel if (mdb_vread(&pj, sizeof (kproject_t), (uintptr_t)tk.tk_proj) == -1) { 424 0 stevel mdb_warn("can't read project_t structure at %p", addr); 425 0 stevel return (DCMD_ERR); 426 0 stevel } 427 0 stevel mdb_printf("%0?p %6d %6d %6d %6u 0x%08x\n", 428 0 stevel addr, tk.tk_tkid, pj.kpj_id, pj.kpj_zoneid, tk.tk_hold_count, 429 0 stevel tk.tk_flags); 430 0 stevel return (DCMD_OK); 431 0 stevel } 432 0 stevel 433 0 stevel int 434 0 stevel project(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 435 0 stevel { 436 0 stevel kproject_t pj; 437 0 stevel 438 0 stevel if (!(flags & DCMD_ADDRSPEC)) { 439 0 stevel if (mdb_walk_dcmd("projects", "project", argc, argv) == -1) { 440 0 stevel mdb_warn("can't walk projects"); 441 0 stevel return (DCMD_ERR); 442 0 stevel } 443 0 stevel return (DCMD_OK); 444 0 stevel } 445 0 stevel if (DCMD_HDRSPEC(flags)) { 446 0 stevel mdb_printf("%<u>%?s %6s %6s %6s%</u>\n", 447 0 stevel "ADDR", "PROJID", "ZONEID", "REFCNT"); 448 0 stevel } 449 0 stevel if (mdb_vread(&pj, sizeof (kproject_t), addr) == -1) { 450 0 stevel mdb_warn("can't read kproject_t structure at %p", addr); 451 0 stevel return (DCMD_ERR); 452 0 stevel } 453 0 stevel mdb_printf("%0?p %6d %6d %6u\n", addr, pj.kpj_id, pj.kpj_zoneid, 454 0 stevel pj.kpj_count); 455 0 stevel return (DCMD_OK); 456 0 stevel } 457 0 stevel 458 8048 Madhavan /* walk callouts themselves, either by list or id hash. */ 459 8048 Madhavan int 460 8048 Madhavan callout_walk_init(mdb_walk_state_t *wsp) 461 8048 Madhavan { 462 8048 Madhavan if (wsp->walk_addr == NULL) { 463 8048 Madhavan mdb_warn("callout doesn't support global walk"); 464 8048 Madhavan return (WALK_ERR); 465 8048 Madhavan } 466 8048 Madhavan wsp->walk_data = mdb_alloc(sizeof (callout_t), UM_SLEEP); 467 8048 Madhavan return (WALK_NEXT); 468 8048 Madhavan } 469 8048 Madhavan 470 8048 Madhavan #define CALLOUT_WALK_BYLIST 0 471 8048 Madhavan #define CALLOUT_WALK_BYID 1 472 8048 Madhavan 473 8048 Madhavan /* the walker arg switches between walking by list (0) and walking by id (1). */ 474 8048 Madhavan int 475 8048 Madhavan callout_walk_step(mdb_walk_state_t *wsp) 476 8048 Madhavan { 477 8048 Madhavan int retval; 478 8048 Madhavan 479 8048 Madhavan if (wsp->walk_addr == NULL) { 480 8048 Madhavan return (WALK_DONE); 481 8048 Madhavan } 482 8048 Madhavan if (mdb_vread(wsp->walk_data, sizeof (callout_t), 483 8048 Madhavan wsp->walk_addr) == -1) { 484 8048 Madhavan mdb_warn("failed to read callout at %p", wsp->walk_addr); 485 8048 Madhavan return (WALK_DONE); 486 8048 Madhavan } 487 8048 Madhavan retval = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 488 8048 Madhavan wsp->walk_cbdata); 489 8048 Madhavan 490 8048 Madhavan if ((ulong_t)wsp->walk_arg == CALLOUT_WALK_BYID) { 491 8048 Madhavan wsp->walk_addr = 492 8048 Madhavan (uintptr_t)(((callout_t *)wsp->walk_data)->c_idnext); 493 8048 Madhavan } else { 494 8048 Madhavan wsp->walk_addr = 495 8048 Madhavan (uintptr_t)(((callout_t *)wsp->walk_data)->c_clnext); 496 8048 Madhavan } 497 8048 Madhavan 498 8048 Madhavan return (retval); 499 8048 Madhavan } 500 8048 Madhavan 501 8048 Madhavan void 502 8048 Madhavan callout_walk_fini(mdb_walk_state_t *wsp) 503 8048 Madhavan { 504 8048 Madhavan mdb_free(wsp->walk_data, sizeof (callout_t)); 505 8048 Madhavan } 506 8048 Madhavan 507 8048 Madhavan /* 508 8048 Madhavan * walker for callout lists. This is different from hashes and callouts. 509 8048 Madhavan * Thankfully, it's also simpler. 510 8048 Madhavan */ 511 8048 Madhavan int 512 8048 Madhavan callout_list_walk_init(mdb_walk_state_t *wsp) 513 8048 Madhavan { 514 8048 Madhavan if (wsp->walk_addr == NULL) { 515 8048 Madhavan mdb_warn("callout list doesn't support global walk"); 516 8048 Madhavan return (WALK_ERR); 517 8048 Madhavan } 518 8048 Madhavan wsp->walk_data = mdb_alloc(sizeof (callout_list_t), UM_SLEEP); 519 8048 Madhavan return (WALK_NEXT); 520 8048 Madhavan } 521 8048 Madhavan 522 8048 Madhavan int 523 8048 Madhavan callout_list_walk_step(mdb_walk_state_t *wsp) 524 8048 Madhavan { 525 8048 Madhavan int retval; 526 8048 Madhavan 527 8048 Madhavan if (wsp->walk_addr == NULL) { 528 8048 Madhavan return (WALK_DONE); 529 8048 Madhavan } 530 8048 Madhavan if (mdb_vread(wsp->walk_data, sizeof (callout_list_t), 531 8048 Madhavan wsp->walk_addr) != sizeof (callout_list_t)) { 532 8048 Madhavan mdb_warn("failed to read callout_list at %p", wsp->walk_addr); 533 8048 Madhavan return (WALK_ERR); 534 8048 Madhavan } 535 8048 Madhavan retval = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 536 8048 Madhavan wsp->walk_cbdata); 537 8048 Madhavan 538 8048 Madhavan wsp->walk_addr = (uintptr_t) 539 8048 Madhavan (((callout_list_t *)wsp->walk_data)->cl_next); 540 8048 Madhavan 541 8048 Madhavan return (retval); 542 8048 Madhavan } 543 8048 Madhavan 544 8048 Madhavan void 545 8048 Madhavan callout_list_walk_fini(mdb_walk_state_t *wsp) 546 8048 Madhavan { 547 8048 Madhavan mdb_free(wsp->walk_data, sizeof (callout_list_t)); 548 8048 Madhavan } 549 8048 Madhavan 550 8048 Madhavan /* routines/structs to walk callout table(s) */ 551 8048 Madhavan typedef struct cot_data { 552 8048 Madhavan callout_table_t *ct0; 553 8048 Madhavan callout_table_t ct; 554 8048 Madhavan callout_hash_t cot_idhash[CALLOUT_BUCKETS]; 555 8048 Madhavan callout_hash_t cot_clhash[CALLOUT_BUCKETS]; 556 8048 Madhavan kstat_named_t ct_kstat_data[CALLOUT_NUM_STATS]; 557 8048 Madhavan int cotndx; 558 8048 Madhavan int cotsize; 559 8048 Madhavan } cot_data_t; 560 8048 Madhavan 561 8048 Madhavan int 562 8048 Madhavan callout_table_walk_init(mdb_walk_state_t *wsp) 563 8048 Madhavan { 564 8048 Madhavan int max_ncpus; 565 8048 Madhavan cot_data_t *cot_walk_data; 566 8048 Madhavan 567 8048 Madhavan cot_walk_data = mdb_alloc(sizeof (cot_data_t), UM_SLEEP); 568 8048 Madhavan 569 8048 Madhavan if (wsp->walk_addr == NULL) { 570 8048 Madhavan if (mdb_readvar(&cot_walk_data->ct0, "callout_table") == -1) { 571 8048 Madhavan mdb_warn("failed to read 'callout_table'"); 572 8048 Madhavan return (WALK_ERR); 573 8048 Madhavan } 574 8048 Madhavan if (mdb_readvar(&max_ncpus, "max_ncpus") == -1) { 575 8048 Madhavan mdb_warn("failed to get callout_table array size"); 576 8048 Madhavan return (WALK_ERR); 577 8048 Madhavan } 578 8048 Madhavan cot_walk_data->cotsize = CALLOUT_NTYPES * max_ncpus; 579 8048 Madhavan wsp->walk_addr = (uintptr_t)cot_walk_data->ct0; 580 8048 Madhavan } else { 581 8048 Madhavan /* not a global walk */ 582 8048 Madhavan cot_walk_data->cotsize = 1; 583 8048 Madhavan } 584 8048 Madhavan 585 8048 Madhavan cot_walk_data->cotndx = 0; 586 8048 Madhavan wsp->walk_data = cot_walk_data; 587 8048 Madhavan 588 8048 Madhavan return (WALK_NEXT); 589 8048 Madhavan } 590 8048 Madhavan 591 8048 Madhavan int 592 8048 Madhavan callout_table_walk_step(mdb_walk_state_t *wsp) 593 8048 Madhavan { 594 8048 Madhavan int retval; 595 8048 Madhavan cot_data_t *cotwd = (cot_data_t *)wsp->walk_data; 596 8048 Madhavan size_t size; 597 8048 Madhavan 598 8048 Madhavan if (cotwd->cotndx >= cotwd->cotsize) { 599 8048 Madhavan return (WALK_DONE); 600 8048 Madhavan } 601 8048 Madhavan if (mdb_vread(&(cotwd->ct), sizeof (callout_table_t), 602 8048 Madhavan wsp->walk_addr) != sizeof (callout_table_t)) { 603 8048 Madhavan mdb_warn("failed to read callout_table at %p", wsp->walk_addr); 604 8048 Madhavan return (WALK_ERR); 605 8048 Madhavan } 606 8048 Madhavan 607 8048 Madhavan size = sizeof (callout_hash_t) * CALLOUT_BUCKETS; 608 8048 Madhavan if (cotwd->ct.ct_idhash != NULL) { 609 8048 Madhavan if (mdb_vread(cotwd->cot_idhash, size, 610 8048 Madhavan (uintptr_t)(cotwd->ct.ct_idhash)) != size) { 611 8048 Madhavan mdb_warn("failed to read id_hash at %p", 612 8048 Madhavan cotwd->ct.ct_idhash); 613 8048 Madhavan return (WALK_ERR); 614 8048 Madhavan } 615 8048 Madhavan } 616 8048 Madhavan if (cotwd->ct.ct_clhash != NULL) { 617 8048 Madhavan if (mdb_vread(&(cotwd->cot_clhash), size, 618 8048 Madhavan (uintptr_t)cotwd->ct.ct_clhash) == -1) { 619 8048 Madhavan mdb_warn("failed to read cl_hash at %p", 620 8048 Madhavan cotwd->ct.ct_clhash); 621 8048 Madhavan return (WALK_ERR); 622 8048 Madhavan } 623 8048 Madhavan } 624 8048 Madhavan size = sizeof (kstat_named_t) * CALLOUT_NUM_STATS; 625 8048 Madhavan if (cotwd->ct.ct_kstat_data != NULL) { 626 8048 Madhavan if (mdb_vread(&(cotwd->ct_kstat_data), size, 627 8048 Madhavan (uintptr_t)cotwd->ct.ct_kstat_data) == -1) { 628 8048 Madhavan mdb_warn("failed to read kstats at %p", 629 8048 Madhavan cotwd->ct.ct_kstat_data); 630 8048 Madhavan return (WALK_ERR); 631 8048 Madhavan } 632 8048 Madhavan } 633 8048 Madhavan retval = wsp->walk_callback(wsp->walk_addr, (void *)cotwd, 634 8048 Madhavan wsp->walk_cbdata); 635 8048 Madhavan 636 8048 Madhavan cotwd->cotndx++; 637 8048 Madhavan if (cotwd->cotndx >= cotwd->cotsize) { 638 8048 Madhavan return (WALK_DONE); 639 8048 Madhavan } 640 8048 Madhavan wsp->walk_addr = (uintptr_t)((char *)wsp->walk_addr + 641 8048 Madhavan sizeof (callout_table_t)); 642 8048 Madhavan 643 8048 Madhavan return (retval); 644 8048 Madhavan } 645 8048 Madhavan 646 8048 Madhavan void 647 8048 Madhavan callout_table_walk_fini(mdb_walk_state_t *wsp) 648 8048 Madhavan { 649 8048 Madhavan mdb_free(wsp->walk_data, sizeof (cot_data_t)); 650 8048 Madhavan } 651 8048 Madhavan 652 8048 Madhavan static const char *co_typenames[] = { "R", "N" }; 653 8048 Madhavan 654 9039 Madhavan #define CO_PLAIN_ID(xid) ((xid) & CALLOUT_ID_MASK) 655 8048 Madhavan 656 8048 Madhavan #define TABLE_TO_SEQID(x) ((x) >> CALLOUT_TYPE_BITS) 657 8048 Madhavan 658 8048 Madhavan /* callout flags, in no particular order */ 659 8048 Madhavan #define COF_REAL 0x0000001 660 8048 Madhavan #define COF_NORM 0x0000002 661 8048 Madhavan #define COF_LONG 0x0000004 662 8048 Madhavan #define COF_SHORT 0x0000008 663 8048 Madhavan #define COF_EMPTY 0x0000010 664 8048 Madhavan #define COF_TIME 0x0000020 665 8048 Madhavan #define COF_BEFORE 0x0000040 666 8048 Madhavan #define COF_AFTER 0x0000080 667 8048 Madhavan #define COF_SEQID 0x0000100 668 8048 Madhavan #define COF_FUNC 0x0000200 669 8048 Madhavan #define COF_ADDR 0x0000400 670 8048 Madhavan #define COF_EXEC 0x0000800 671 8048 Madhavan #define COF_HIRES 0x0001000 672 9039 Madhavan #define COF_ABS 0x0002000 673 8048 Madhavan #define COF_TABLE 0x0004000 674 8048 Madhavan #define COF_BYIDH 0x0008000 675 8048 Madhavan #define COF_FREE 0x0010000 676 8048 Madhavan #define COF_LIST 0x0020000 677 8048 Madhavan #define COF_EXPREL 0x0040000 678 8048 Madhavan #define COF_HDR 0x0080000 679 8048 Madhavan #define COF_VERBOSE 0x0100000 680 8048 Madhavan #define COF_LONGLIST 0x0200000 681 8048 Madhavan #define COF_THDR 0x0400000 682 8048 Madhavan #define COF_LHDR 0x0800000 683 8048 Madhavan #define COF_CHDR 0x1000000 684 8048 Madhavan #define COF_PARAM 0x2000000 685 8048 Madhavan #define COF_DECODE 0x4000000 686 8048 Madhavan 687 8048 Madhavan /* show real and normal, short and long, expired and unexpired. */ 688 8048 Madhavan #define COF_DEFAULT (COF_REAL | COF_NORM | COF_LONG | COF_SHORT) 689 8048 Madhavan 690 9334 Madhavan #define COF_LIST_FLAGS \ 691 9334 Madhavan (CALLOUT_LIST_FLAG_HRESTIME | CALLOUT_LIST_FLAG_ABSOLUTE) 692 9334 Madhavan 693 8048 Madhavan /* private callout data for callback functions */ 694 8048 Madhavan typedef struct callout_data { 695 8048 Madhavan uint_t flags; /* COF_* */ 696 8048 Madhavan cpu_t *cpu; /* cpu pointer if given */ 697 8048 Madhavan int seqid; /* cpu seqid, or -1 */ 698 8048 Madhavan hrtime_t time; /* expiration time value */ 699 8048 Madhavan hrtime_t atime; /* expiration before value */ 700 8048 Madhavan hrtime_t btime; /* expiration after value */ 701 8048 Madhavan uintptr_t funcaddr; /* function address or NULL */ 702 8048 Madhavan uintptr_t param; /* parameter to function or NULL */ 703 8048 Madhavan hrtime_t now; /* current system time */ 704 8048 Madhavan int nsec_per_tick; /* for conversions */ 705 8048 Madhavan ulong_t ctbits; /* for decoding xid */ 706 8048 Madhavan callout_table_t *co_table; /* top of callout table array */ 707 8048 Madhavan int ndx; /* table index. */ 708 8048 Madhavan int bucket; /* which list/id bucket are we in */ 709 8048 Madhavan hrtime_t exp; /* expire time */ 710 9039 Madhavan int list_flags; /* copy of cl_flags */ 711 8048 Madhavan } callout_data_t; 712 8048 Madhavan 713 8048 Madhavan /* this callback does the actual callback itself (finally). */ 714 8048 Madhavan /*ARGSUSED*/ 715 8048 Madhavan static int 716 8048 Madhavan callouts_cb(uintptr_t addr, const void *data, void *priv) 717 8048 Madhavan { 718 8048 Madhavan callout_data_t *coargs = (callout_data_t *)priv; 719 8048 Madhavan callout_t *co = (callout_t *)data; 720 9334 Madhavan int tableid, list_flags; 721 8048 Madhavan callout_id_t coid; 722 8048 Madhavan 723 8048 Madhavan if ((coargs == NULL) || (co == NULL)) { 724 8048 Madhavan return (WALK_ERR); 725 8048 Madhavan } 726 8048 Madhavan 727 9334 Madhavan if ((coargs->flags & COF_FREE) && !(co->c_xid & CALLOUT_FREE)) { 728 9334 Madhavan /* 729 9334 Madhavan * The callout must have been reallocated. No point in 730 9334 Madhavan * walking any more. 731 9334 Madhavan */ 732 9334 Madhavan return (WALK_DONE); 733 9334 Madhavan } 734 9334 Madhavan if (!(coargs->flags & COF_FREE) && (co->c_xid & CALLOUT_FREE)) { 735 9334 Madhavan /* 736 9334 Madhavan * The callout must have been freed. No point in 737 9334 Madhavan * walking any more. 738 9334 Madhavan */ 739 9334 Madhavan return (WALK_DONE); 740 9334 Madhavan } 741 8048 Madhavan if ((coargs->flags & COF_FUNC) && 742 8048 Madhavan (coargs->funcaddr != (uintptr_t)co->c_func)) { 743 8048 Madhavan return (WALK_NEXT); 744 8048 Madhavan } 745 8048 Madhavan if ((coargs->flags & COF_PARAM) && 746 8048 Madhavan (coargs->param != (uintptr_t)co->c_arg)) { 747 8048 Madhavan return (WALK_NEXT); 748 8048 Madhavan } 749 8048 Madhavan if (!(coargs->flags & COF_LONG) && (co->c_xid & CALLOUT_LONGTERM)) { 750 8048 Madhavan return (WALK_NEXT); 751 8048 Madhavan } 752 8048 Madhavan if (!(coargs->flags & COF_SHORT) && !(co->c_xid & CALLOUT_LONGTERM)) { 753 8048 Madhavan return (WALK_NEXT); 754 8048 Madhavan } 755 8048 Madhavan if ((coargs->flags & COF_EXEC) && !(co->c_xid & CALLOUT_EXECUTING)) { 756 8048 Madhavan return (WALK_NEXT); 757 8048 Madhavan } 758 9334 Madhavan /* it is possible we don't have the exp time or flags */ 759 8048 Madhavan if (coargs->flags & COF_BYIDH) { 760 8048 Madhavan if (!(coargs->flags & COF_FREE)) { 761 8048 Madhavan /* we have to fetch the expire time ourselves. */ 762 8048 Madhavan if (mdb_vread(&coargs->exp, sizeof (hrtime_t), 763 8048 Madhavan (uintptr_t)co->c_list + offsetof(callout_list_t, 764 8048 Madhavan cl_expiration)) == -1) { 765 8048 Madhavan mdb_warn("failed to read expiration " 766 8048 Madhavan "time from %p", co->c_list); 767 8048 Madhavan coargs->exp = 0; 768 8048 Madhavan } 769 9039 Madhavan /* and flags. */ 770 9039 Madhavan if (mdb_vread(&coargs->list_flags, sizeof (int), 771 9039 Madhavan (uintptr_t)co->c_list + offsetof(callout_list_t, 772 9039 Madhavan cl_flags)) == -1) { 773 9039 Madhavan mdb_warn("failed to read list flags" 774 9039 Madhavan "from %p", co->c_list); 775 9039 Madhavan coargs->list_flags = 0; 776 9039 Madhavan } 777 8048 Madhavan } else { 778 8048 Madhavan /* free callouts can't use list pointer. */ 779 8048 Madhavan coargs->exp = 0; 780 9039 Madhavan coargs->list_flags = 0; 781 9039 Madhavan } 782 9039 Madhavan if (coargs->exp != 0) { 783 9039 Madhavan if ((coargs->flags & COF_TIME) && 784 9039 Madhavan (coargs->exp != coargs->time)) { 785 9039 Madhavan return (WALK_NEXT); 786 9039 Madhavan } 787 9039 Madhavan if ((coargs->flags & COF_BEFORE) && 788 9039 Madhavan (coargs->exp > coargs->btime)) { 789 9039 Madhavan return (WALK_NEXT); 790 9039 Madhavan } 791 9039 Madhavan if ((coargs->flags & COF_AFTER) && 792 9039 Madhavan (coargs->exp < coargs->atime)) { 793 9039 Madhavan return (WALK_NEXT); 794 9039 Madhavan } 795 9039 Madhavan } 796 9039 Madhavan /* tricky part, since both HIRES and ABS can be set */ 797 9334 Madhavan list_flags = coargs->list_flags; 798 9039 Madhavan if ((coargs->flags & COF_HIRES) && (coargs->flags & COF_ABS)) { 799 9039 Madhavan /* both flags are set, only skip "regular" ones */ 800 9334 Madhavan if (! (list_flags & COF_LIST_FLAGS)) { 801 9039 Madhavan return (WALK_NEXT); 802 9039 Madhavan } 803 9039 Madhavan } else { 804 9039 Madhavan /* individual flags, or no flags */ 805 9039 Madhavan if ((coargs->flags & COF_HIRES) && 806 9334 Madhavan !(list_flags & CALLOUT_LIST_FLAG_HRESTIME)) { 807 9039 Madhavan return (WALK_NEXT); 808 9039 Madhavan } 809 9039 Madhavan if ((coargs->flags & COF_ABS) && 810 9334 Madhavan !(list_flags & CALLOUT_LIST_FLAG_ABSOLUTE)) { 811 9039 Madhavan return (WALK_NEXT); 812 9039 Madhavan } 813 8048 Madhavan } 814 8048 Madhavan } 815 8048 Madhavan 816 8048 Madhavan #define callout_table_mask ((1 << coargs->ctbits) - 1) 817 8048 Madhavan tableid = CALLOUT_ID_TO_TABLE(co->c_xid); 818 8048 Madhavan #undef callout_table_mask 819 8048 Madhavan coid = CO_PLAIN_ID(co->c_xid); 820 8048 Madhavan 821 8048 Madhavan if ((coargs->flags & COF_CHDR) && !(coargs->flags & COF_ADDR)) { 822 8048 Madhavan /* 823 8048 Madhavan * We need to print the headers. If walking by id, then 824 8048 Madhavan * the list header isn't printed, so we must include 825 8048 Madhavan * that info here. 826 8048 Madhavan */ 827 8048 Madhavan if (!(coargs->flags & COF_VERBOSE)) { 828 8048 Madhavan mdb_printf("%<u>%3s %-1s %-14s %</u>", 829 8048 Madhavan "SEQ", "T", "EXP"); 830 8048 Madhavan } else if (coargs->flags & COF_BYIDH) { 831 8048 Madhavan mdb_printf("%<u>%-14s %</u>", "EXP"); 832 8048 Madhavan } 833 9039 Madhavan mdb_printf("%<u>%-4s %-?s %-20s%</u>", 834 9039 Madhavan "XHAL", "XID", "FUNC(ARG)"); 835 8048 Madhavan if (coargs->flags & COF_LONGLIST) { 836 8048 Madhavan mdb_printf("%<u> %-?s %-?s %-?s %-?s%</u>", 837 8048 Madhavan "PREVID", "NEXTID", "PREVL", "NEXTL"); 838 9039 Madhavan mdb_printf("%<u> %-?s %-4s %-?s%</u>", 839 9039 Madhavan "DONE", "UTOS", "THREAD"); 840 8048 Madhavan } 841 8048 Madhavan mdb_printf("\n"); 842 8048 Madhavan coargs->flags &= ~COF_CHDR; 843 8048 Madhavan coargs->flags |= (COF_THDR | COF_LHDR); 844 8048 Madhavan } 845 8048 Madhavan 846 8048 Madhavan if (!(coargs->flags & COF_ADDR)) { 847 8048 Madhavan if (!(coargs->flags & COF_VERBOSE)) { 848 8048 Madhavan mdb_printf("%-3d %1s %-14llx ", 849 8048 Madhavan TABLE_TO_SEQID(tableid), 850 8048 Madhavan co_typenames[tableid & CALLOUT_TYPE_MASK], 851 8048 Madhavan (coargs->flags & COF_EXPREL) ? 852 8048 Madhavan coargs->exp - coargs->now : coargs->exp); 853 8048 Madhavan } else if (coargs->flags & COF_BYIDH) { 854 8048 Madhavan mdb_printf("%-14x ", 855 8048 Madhavan (coargs->flags & COF_EXPREL) ? 856 8048 Madhavan coargs->exp - coargs->now : coargs->exp); 857 8048 Madhavan } 858 9334 Madhavan list_flags = coargs->list_flags; 859 9039 Madhavan mdb_printf("%1s%1s%1s%1s %-?llx %a(%p)", 860 8048 Madhavan (co->c_xid & CALLOUT_EXECUTING) ? "X" : " ", 861 9334 Madhavan (list_flags & CALLOUT_LIST_FLAG_HRESTIME) ? "H" : " ", 862 9334 Madhavan (list_flags & CALLOUT_LIST_FLAG_ABSOLUTE) ? "A" : " ", 863 8048 Madhavan (co->c_xid & CALLOUT_LONGTERM) ? "L" : " ", 864 8048 Madhavan (long long)coid, co->c_func, co->c_arg); 865 8048 Madhavan if (coargs->flags & COF_LONGLIST) { 866 8048 Madhavan mdb_printf(" %-?p %-?p %-?p %-?p", 867 8048 Madhavan co->c_idprev, co->c_idnext, co->c_clprev, 868 8048 Madhavan co->c_clnext); 869 9039 Madhavan mdb_printf(" %-?p %-4d %-0?p", 870 9039 Madhavan co->c_done, co->c_waiting, co->c_executor); 871 8048 Madhavan } 872 8048 Madhavan } else { 873 8048 Madhavan /* address only */ 874 8048 Madhavan mdb_printf("%-0p", addr); 875 8048 Madhavan } 876 8048 Madhavan mdb_printf("\n"); 877 8048 Madhavan return (WALK_NEXT); 878 8048 Madhavan } 879 8048 Madhavan 880 8048 Madhavan /* this callback is for callout list handling. idhash is done by callout_t_cb */ 881 8048 Madhavan /*ARGSUSED*/ 882 8048 Madhavan static int 883 8048 Madhavan callout_list_cb(uintptr_t addr, const void *data, void *priv) 884 8048 Madhavan { 885 8048 Madhavan callout_data_t *coargs = (callout_data_t *)priv; 886 8048 Madhavan callout_list_t *cl = (callout_list_t *)data; 887 8048 Madhavan callout_t *coptr; 888 9334 Madhavan int list_flags; 889 8048 Madhavan 890 8048 Madhavan if ((coargs == NULL) || (cl == NULL)) { 891 8048 Madhavan return (WALK_ERR); 892 8048 Madhavan } 893 8048 Madhavan 894 8048 Madhavan coargs->exp = cl->cl_expiration; 895 9039 Madhavan coargs->list_flags = cl->cl_flags; 896 9334 Madhavan if ((coargs->flags & COF_FREE) && 897 9334 Madhavan !(cl->cl_flags & CALLOUT_LIST_FLAG_FREE)) { 898 9334 Madhavan /* 899 9334 Madhavan * The callout list must have been reallocated. No point in 900 9334 Madhavan * walking any more. 901 9334 Madhavan */ 902 9334 Madhavan return (WALK_DONE); 903 9334 Madhavan } 904 9334 Madhavan if (!(coargs->flags & COF_FREE) && 905 9334 Madhavan (cl->cl_flags & CALLOUT_LIST_FLAG_FREE)) { 906 9334 Madhavan /* 907 9334 Madhavan * The callout list must have been freed. No point in 908 9334 Madhavan * walking any more. 909 9334 Madhavan */ 910 9334 Madhavan return (WALK_DONE); 911 9334 Madhavan } 912 8048 Madhavan if ((coargs->flags & COF_TIME) && 913 8048 Madhavan (cl->cl_expiration != coargs->time)) { 914 8048 Madhavan return (WALK_NEXT); 915 8048 Madhavan } 916 8048 Madhavan if ((coargs->flags & COF_BEFORE) && 917 8048 Madhavan (cl->cl_expiration > coargs->btime)) { 918 8048 Madhavan return (WALK_NEXT); 919 8048 Madhavan } 920 8048 Madhavan if ((coargs->flags & COF_AFTER) && 921 8048 Madhavan (cl->cl_expiration < coargs->atime)) { 922 8048 Madhavan return (WALK_NEXT); 923 8048 Madhavan } 924 8048 Madhavan if (!(coargs->flags & COF_EMPTY) && 925 8048 Madhavan (cl->cl_callouts.ch_head == NULL)) { 926 8048 Madhavan return (WALK_NEXT); 927 9039 Madhavan } 928 9039 Madhavan /* FOUR cases, each different, !A!B, !AB, A!B, AB */ 929 9039 Madhavan if ((coargs->flags & COF_HIRES) && (coargs->flags & COF_ABS)) { 930 9039 Madhavan /* both flags are set, only skip "regular" ones */ 931 9334 Madhavan if (! (cl->cl_flags & COF_LIST_FLAGS)) { 932 9039 Madhavan return (WALK_NEXT); 933 9039 Madhavan } 934 9039 Madhavan } else { 935 9039 Madhavan if ((coargs->flags & COF_HIRES) && 936 9334 Madhavan !(cl->cl_flags & CALLOUT_LIST_FLAG_HRESTIME)) { 937 9039 Madhavan return (WALK_NEXT); 938 9039 Madhavan } 939 9039 Madhavan if ((coargs->flags & COF_ABS) && 940 9334 Madhavan !(cl->cl_flags & CALLOUT_LIST_FLAG_ABSOLUTE)) { 941 9039 Madhavan return (WALK_NEXT); 942 9039 Madhavan } 943 8048 Madhavan } 944 8048 Madhavan 945 8048 Madhavan if ((coargs->flags & COF_LHDR) && !(coargs->flags & COF_ADDR) && 946 8048 Madhavan (coargs->flags & (COF_LIST | COF_VERBOSE))) { 947 8048 Madhavan if (!(coargs->flags & COF_VERBOSE)) { 948 8048 Madhavan /* don't be redundant again */ 949 8048 Madhavan mdb_printf("%<u>SEQ T %</u>"); 950 8048 Madhavan } 951 9039 Madhavan mdb_printf("%<u>EXP HA BUCKET " 952 9039 Madhavan "CALLOUTS %</u>"); 953 8048 Madhavan 954 8048 Madhavan if (coargs->flags & COF_LONGLIST) { 955 9039 Madhavan mdb_printf("%<u> %-?s %-?s%</u>", 956 9039 Madhavan "PREV", "NEXT"); 957 8048 Madhavan } 958 8048 Madhavan mdb_printf("\n"); 959 8048 Madhavan coargs->flags &= ~COF_LHDR; 960 8048 Madhavan coargs->flags |= (COF_THDR | COF_CHDR); 961 8048 Madhavan } 962 8048 Madhavan if (coargs->flags & (COF_LIST | COF_VERBOSE)) { 963 8048 Madhavan if (!(coargs->flags & COF_ADDR)) { 964 8048 Madhavan if (!(coargs->flags & COF_VERBOSE)) { 965 8048 Madhavan mdb_printf("%3d %1s ", 966 8048 Madhavan TABLE_TO_SEQID(coargs->ndx), 967 8048 Madhavan co_typenames[coargs->ndx & 968 8048 Madhavan CALLOUT_TYPE_MASK]); 969 8048 Madhavan } 970 8048 Madhavan 971 9334 Madhavan list_flags = coargs->list_flags; 972 9039 Madhavan mdb_printf("%-14llx %1s%1s %-6d %-0?p ", 973 8048 Madhavan (coargs->flags & COF_EXPREL) ? 974 8048 Madhavan coargs->exp - coargs->now : coargs->exp, 975 9334 Madhavan (list_flags & CALLOUT_LIST_FLAG_HRESTIME) ? 976 9039 Madhavan "H" : " ", 977 9334 Madhavan (list_flags & CALLOUT_LIST_FLAG_ABSOLUTE) ? 978 9039 Madhavan "A" : " ", 979 9039 Madhavan coargs->bucket, cl->cl_callouts.ch_head); 980 8048 Madhavan 981 8048 Madhavan if (coargs->flags & COF_LONGLIST) { 982 9039 Madhavan mdb_printf(" %-?p %-?p", 983 9039 Madhavan cl->cl_prev, cl->cl_next); 984 8048 Madhavan } 985 8048 Madhavan } else { 986 8048 Madhavan /* address only */ 987 8048 Madhavan mdb_printf("%-0p", addr); 988 8048 Madhavan } 989 8048 Madhavan mdb_printf("\n"); 990 8048 Madhavan if (coargs->flags & COF_LIST) { 991 8048 Madhavan return (WALK_NEXT); 992 8048 Madhavan } 993 8048 Madhavan } 994 8048 Madhavan /* yet another layer as we walk the actual callouts via list. */ 995 8048 Madhavan if (cl->cl_callouts.ch_head == NULL) { 996 8048 Madhavan return (WALK_NEXT); 997 8048 Madhavan } 998 8048 Madhavan /* free list structures do not have valid callouts off of them. */ 999 8048 Madhavan if (coargs->flags & COF_FREE) { 1000 8048 Madhavan return (WALK_NEXT); 1001 8048 Madhavan } 1002 8048 Madhavan coptr = (callout_t *)cl->cl_callouts.ch_head; 1003 8048 Madhavan 1004 8048 Madhavan if (coargs->flags & COF_VERBOSE) { 1005 8048 Madhavan mdb_inc_indent(4); 1006 8048 Madhavan } 1007 8048 Madhavan /* 1008 8048 Madhavan * walk callouts using yet another callback routine. 1009 8048 Madhavan * we use callouts_bytime because id hash is handled via 1010 8048 Madhavan * the callout_t_cb callback. 1011 8048 Madhavan */ 1012 8048 Madhavan if (mdb_pwalk("callouts_bytime", callouts_cb, coargs, 1013 8048 Madhavan (uintptr_t)coptr) == -1) { 1014 8048 Madhavan mdb_warn("cannot walk callouts at %p", coptr); 1015 8048 Madhavan return (WALK_ERR); 1016 8048 Madhavan } 1017 8048 Madhavan if (coargs->flags & COF_VERBOSE) { 1018 8048 Madhavan mdb_dec_indent(4); 1019 8048 Madhavan } 1020 8048 Madhavan 1021 8048 Madhavan return (WALK_NEXT); 1022 8048 Madhavan } 1023 8048 Madhavan 1024 8048 Madhavan /* this callback handles the details of callout table walking. */ 1025 8048 Madhavan static int 1026 8048 Madhavan callout_t_cb(uintptr_t addr, const void *data, void *priv) 1027 8048 Madhavan { 1028 8048 Madhavan callout_data_t *coargs = (callout_data_t *)priv; 1029 8048 Madhavan cot_data_t *cotwd = (cot_data_t *)data; 1030 8048 Madhavan callout_table_t *ct = &(cotwd->ct); 1031 8048 Madhavan int index, seqid, cotype; 1032 8048 Madhavan int i; 1033 8048 Madhavan callout_list_t *clptr; 1034 8048 Madhavan callout_t *coptr; 1035 8048 Madhavan 1036 8048 Madhavan if ((coargs == NULL) || (ct == NULL) || (coargs->co_table == NULL)) { 1037 8048 Madhavan return (WALK_ERR); 1038 8048 Madhavan } 1039 8048 Madhavan 1040 8048 Madhavan index = ((char *)addr - (char *)coargs->co_table) / 1041 8048 Madhavan sizeof (callout_table_t); 1042 8048 Madhavan cotype = index & CALLOUT_TYPE_MASK; 1043 8048 Madhavan seqid = TABLE_TO_SEQID(index); 1044 8048 Madhavan 1045 8048 Madhavan if ((coargs->flags & COF_SEQID) && (coargs->seqid != seqid)) { 1046 8048 Madhavan return (WALK_NEXT); 1047 8048 Madhavan } 1048 8048 Madhavan 1049 8048 Madhavan if (!(coargs->flags & COF_REAL) && (cotype == CALLOUT_REALTIME)) { 1050 8048 Madhavan return (WALK_NEXT); 1051 8048 Madhavan } 1052 8048 Madhavan 1053 8048 Madhavan if (!(coargs->flags & COF_NORM) && (cotype == CALLOUT_NORMAL)) { 1054 8048 Madhavan return (WALK_NEXT); 1055 8048 Madhavan } 1056 8048 Madhavan 1057 8048 Madhavan if (!(coargs->flags & COF_EMPTY) && ( 1058 8048 Madhavan (ct->ct_heap == NULL) || (ct->ct_cyclic == NULL))) { 1059 8048 Madhavan return (WALK_NEXT); 1060 8048 Madhavan } 1061 8048 Madhavan 1062 8048 Madhavan if ((coargs->flags & COF_THDR) && !(coargs->flags & COF_ADDR) && 1063 8048 Madhavan (coargs->flags & (COF_TABLE | COF_VERBOSE))) { 1064 8048 Madhavan /* print table hdr */ 1065 8048 Madhavan mdb_printf("%<u>%-3s %-1s %-?s %-?s %-?s %-?s%</u>", 1066 8048 Madhavan "SEQ", "T", "FREE", "LFREE", "CYCLIC", "HEAP"); 1067 8048 Madhavan coargs->flags &= ~COF_THDR; 1068 8048 Madhavan coargs->flags |= (COF_LHDR | COF_CHDR); 1069 8048 Madhavan if (coargs->flags & COF_LONGLIST) { 1070 8048 Madhavan /* more info! */ 1071 8048 Madhavan mdb_printf("%<u> %-T%-7s %-7s %-?s %-?s" 1072 8048 Madhavan " %-?s %-?s %-?s%</u>", 1073 8048 Madhavan "HEAPNUM", "HEAPMAX", "TASKQ", "EXPQ", 1074 8048 Madhavan "PEND", "FREE", "LOCK"); 1075 8048 Madhavan } 1076 8048 Madhavan mdb_printf("\n"); 1077 8048 Madhavan } 1078 8048 Madhavan if (coargs->flags & (COF_TABLE | COF_VERBOSE)) { 1079 8048 Madhavan if (!(coargs->flags & COF_ADDR)) { 1080 8048 Madhavan mdb_printf("%-3d %-1s %-0?p %-0?p %-0?p %-?p", 1081 8048 Madhavan seqid, co_typenames[cotype], 1082 8048 Madhavan ct->ct_free, ct->ct_lfree, ct->ct_cyclic, 1083 8048 Madhavan ct->ct_heap); 1084 8048 Madhavan if (coargs->flags & COF_LONGLIST) { 1085 8048 Madhavan /* more info! */ 1086 8048 Madhavan mdb_printf(" %-7d %-7d %-?p %-?p" 1087 8048 Madhavan " %-?lld %-?lld %-?p", 1088 8048 Madhavan ct->ct_heap_num, ct->ct_heap_max, 1089 8048 Madhavan ct->ct_taskq, ct->ct_expired.ch_head, 1090 8048 Madhavan cotwd->ct_timeouts_pending, 1091 8048 Madhavan cotwd->ct_allocations - 1092 8048 Madhavan cotwd->ct_timeouts_pending, 1093 8048 Madhavan ct->ct_mutex); 1094 8048 Madhavan } 1095 8048 Madhavan } else { 1096 8048 Madhavan /* address only */ 1097 8048 Madhavan mdb_printf("%-0?p", addr); 1098 8048 Madhavan } 1099 8048 Madhavan mdb_printf("\n"); 1100 8048 Madhavan if (coargs->flags & COF_TABLE) { 1101 8048 Madhavan return (WALK_NEXT); 1102 8048 Madhavan } 1103 8048 Madhavan } 1104 8048 Madhavan 1105 8048 Madhavan coargs->ndx = index; 1106 8048 Madhavan if (coargs->flags & COF_VERBOSE) { 1107 8048 Madhavan mdb_inc_indent(4); 1108 8048 Madhavan } 1109 8048 Madhavan /* keep digging. */ 1110 8048 Madhavan if (!(coargs->flags & COF_BYIDH)) { 1111 8048 Madhavan /* walk the list hash table */ 1112 8048 Madhavan if (coargs->flags & COF_FREE) { 1113 8048 Madhavan clptr = ct->ct_lfree; 1114 8048 Madhavan coargs->bucket = 0; 1115 8048 Madhavan if (clptr == NULL) { 1116 8048 Madhavan return (WALK_NEXT); 1117 8048 Madhavan } 1118 8048 Madhavan if (mdb_pwalk("callout_list", callout_list_cb, coargs, 1119 8048 Madhavan (uintptr_t)clptr) == -1) { 1120 8048 Madhavan mdb_warn("cannot walk callout free list at %p", 1121 8048 Madhavan clptr); 1122 8048 Madhavan return (WALK_ERR); 1123 8048 Madhavan } 1124 8048 Madhavan } else { 1125 8048 Madhavan /* first print the expired list. */ 1126 8048 Madhavan clptr = (callout_list_t *)ct->ct_expired.ch_head; 1127 8048 Madhavan if (clptr != NULL) { 1128 8048 Madhavan coargs->bucket = -1; 1129 8048 Madhavan if (mdb_pwalk("callout_list", callout_list_cb, 1130 8048 Madhavan coargs, (uintptr_t)clptr) == -1) { 1131 8048 Madhavan mdb_warn("cannot walk callout_list" 1132 8048 Madhavan " at %p", clptr); 1133 8048 Madhavan return (WALK_ERR); 1134 8048 Madhavan } 1135 8048 Madhavan } 1136 8048 Madhavan for (i = 0; i < CALLOUT_BUCKETS; i++) { 1137 8048 Madhavan if (ct->ct_clhash == NULL) { 1138 8048 Madhavan /* nothing to do */ 1139 8048 Madhavan break; 1140 8048 Madhavan } 1141 8048 Madhavan if (cotwd->cot_clhash[i].ch_head == NULL) { 1142 8048 Madhavan continue; 1143 8048 Madhavan } 1144 8048 Madhavan clptr = (callout_list_t *) 1145 8048 Madhavan cotwd->cot_clhash[i].ch_head; 1146 8048 Madhavan coargs->bucket = i; 1147 8048 Madhavan /* walk list with callback routine. */ 1148 8048 Madhavan if (mdb_pwalk("callout_list", callout_list_cb, 1149 8048 Madhavan coargs, (uintptr_t)clptr) == -1) { 1150 8048 Madhavan mdb_warn("cannot walk callout_list" 1151 8048 Madhavan " at %p", clptr); 1152 8048 Madhavan return (WALK_ERR); 1153 8048 Madhavan } 1154 8048 Madhavan } 1155 8048 Madhavan } 1156 8048 Madhavan } else { 1157 8048 Madhavan /* walk the id hash table. */ 1158 8048 Madhavan if (coargs->flags & COF_FREE) { 1159 8048 Madhavan coptr = ct->ct_free; 1160 8048 Madhavan coargs->bucket = 0; 1161 8048 Madhavan if (coptr == NULL) { 1162 8048 Madhavan return (WALK_NEXT); 1163 8048 Madhavan } 1164 8048 Madhavan if (mdb_pwalk("callouts_byid", callouts_cb, coargs, 1165 8048 Madhavan (uintptr_t)coptr) == -1) { 1166 8048 Madhavan mdb_warn("cannot walk callout id free list" 1167 8048 Madhavan " at %p", coptr); 1168 8048 Madhavan return (WALK_ERR); 1169 8048 Madhavan } 1170 8048 Madhavan } else { 1171 8048 Madhavan for (i = 0; i < CALLOUT_BUCKETS; i++) { 1172 8048 Madhavan if (ct->ct_idhash == NULL) { 1173 8048 Madhavan break; 1174 8048 Madhavan } 1175 8048 Madhavan coptr = (callout_t *) 1176 8048 Madhavan cotwd->cot_idhash[i].ch_head; 1177 8048 Madhavan if (coptr == NULL) { 1178 8048 Madhavan continue; 1179 8048 Madhavan } 1180 8048 Madhavan coargs->bucket = i; 1181 8048 Madhavan 1182 8048 Madhavan /* 1183 8048 Madhavan * walk callouts directly by id. For id 1184 8048 Madhavan * chain, the callout list is just a header, 1185 8048 Madhavan * so there's no need to walk it. 1186 8048 Madhavan */ 1187 8048 Madhavan if (mdb_pwalk("callouts_byid", callouts_cb, 1188 8048 Madhavan coargs, (uintptr_t)coptr) == -1) { 1189 8048 Madhavan mdb_warn("cannot walk callouts at %p", 1190 8048 Madhavan coptr); 1191 8048 Madhavan return (WALK_ERR); 1192 8048 Madhavan } 1193 8048 Madhavan } 1194 8048 Madhavan } 1195 8048 Madhavan } 1196 8048 Madhavan if (coargs->flags & COF_VERBOSE) { 1197 8048 Madhavan mdb_dec_indent(4); 1198 8048 Madhavan } 1199 8048 Madhavan return (WALK_NEXT); 1200 8048 Madhavan } 1201 8048 Madhavan 1202 8048 Madhavan /* 1203 8048 Madhavan * initialize some common info for both callout dcmds. 1204 8048 Madhavan */ 1205 8048 Madhavan int 1206 8048 Madhavan callout_common_init(callout_data_t *coargs) 1207 8048 Madhavan { 1208 8048 Madhavan /* we need a couple of things */ 1209 8048 Madhavan if (mdb_readvar(&(coargs->co_table), "callout_table") == -1) { 1210 8048 Madhavan mdb_warn("failed to read 'callout_table'"); 1211 8048 Madhavan return (DCMD_ERR); 1212 8048 Madhavan } 1213 8048 Madhavan /* need to get now in nsecs. Approximate with hrtime vars */ 1214 8048 Madhavan if (mdb_readsym(&(coargs->now), sizeof (hrtime_t), "hrtime_last") != 1215 8048 Madhavan sizeof (hrtime_t)) { 1216 8048 Madhavan if (mdb_readsym(&(coargs->now), sizeof (hrtime_t), 1217 8048 Madhavan "hrtime_base") != sizeof (hrtime_t)) { 1218 8048 Madhavan mdb_warn("Could not determine current system time"); 1219 8048 Madhavan return (DCMD_ERR); 1220 8048 Madhavan } 1221 8048 Madhavan } 1222 8048 Madhavan 1223 8048 Madhavan if (mdb_readvar(&(coargs->ctbits), "callout_table_bits") == -1) { 1224 8048 Madhavan mdb_warn("failed to read 'callout_table_bits'"); 1225 8048 Madhavan return (DCMD_ERR); 1226 8048 Madhavan } 1227 8048 Madhavan if (mdb_readvar(&(coargs->nsec_per_tick), "nsec_per_tick") == -1) { 1228 8048 Madhavan mdb_warn("failed to read 'nsec_per_tick'"); 1229 8048 Madhavan return (DCMD_ERR); 1230 8048 Madhavan } 1231 8048 Madhavan return (DCMD_OK); 1232 8048 Madhavan } 1233 8048 Madhavan 1234 8048 Madhavan /* 1235 8048 Madhavan * dcmd to print callouts. Optional addr limits to specific table. 1236 8048 Madhavan * Parses lots of options that get passed to callbacks for walkers. 1237 8048 Madhavan * Has it's own help function. 1238 8048 Madhavan */ 1239 0 stevel /*ARGSUSED*/ 1240 0 stevel int 1241 0 stevel callout(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1242 0 stevel { 1243 8048 Madhavan callout_data_t coargs; 1244 8048 Madhavan /* getopts doesn't help much with stuff like this */ 1245 8048 Madhavan boolean_t Sflag, Cflag, tflag, aflag, bflag, dflag, kflag; 1246 8048 Madhavan char *funcname = NULL; 1247 8048 Madhavan char *paramstr = NULL; 1248 8048 Madhavan uintptr_t Stmp, Ctmp; /* for getopt. */ 1249 8048 Madhavan int retval; 1250 8048 Madhavan 1251 8048 Madhavan coargs.flags = COF_DEFAULT; 1252 8048 Madhavan Sflag = Cflag = tflag = bflag = aflag = dflag = kflag = FALSE; 1253 8048 Madhavan coargs.seqid = -1; 1254 8048 Madhavan 1255 8048 Madhavan if (mdb_getopts(argc, argv, 1256 8048 Madhavan 'r', MDB_OPT_CLRBITS, COF_NORM, &coargs.flags, 1257 8048 Madhavan 'n', MDB_OPT_CLRBITS, COF_REAL, &coargs.flags, 1258 8048 Madhavan 'l', MDB_OPT_CLRBITS, COF_SHORT, &coargs.flags, 1259 8048 Madhavan 's', MDB_OPT_CLRBITS, COF_LONG, &coargs.flags, 1260 8048 Madhavan 'x', MDB_OPT_SETBITS, COF_EXEC, &coargs.flags, 1261 8048 Madhavan 'h', MDB_OPT_SETBITS, COF_HIRES, &coargs.flags, 1262 9039 Madhavan 'B', MDB_OPT_SETBITS, COF_ABS, &coargs.flags, 1263 8048 Madhavan 'E', MDB_OPT_SETBITS, COF_EMPTY, &coargs.flags, 1264 8048 Madhavan 'd', MDB_OPT_SETBITS, 1, &dflag, 1265 8048 Madhavan 'C', MDB_OPT_UINTPTR_SET, &Cflag, &Ctmp, 1266 8048 Madhavan 'S', MDB_OPT_UINTPTR_SET, &Sflag, &Stmp, 1267 8048 Madhavan 't', MDB_OPT_UINTPTR_SET, &tflag, (uintptr_t *)&coargs.time, 1268 8048 Madhavan 'a', MDB_OPT_UINTPTR_SET, &aflag, (uintptr_t *)&coargs.atime, 1269 8048 Madhavan 'b', MDB_OPT_UINTPTR_SET, &bflag, (uintptr_t *)&coargs.btime, 1270 8048 Madhavan 'k', MDB_OPT_SETBITS, 1, &kflag, 1271 8048 Madhavan 'f', MDB_OPT_STR, &funcname, 1272 8048 Madhavan 'p', MDB_OPT_STR, ¶mstr, 1273 8048 Madhavan 'T', MDB_OPT_SETBITS, COF_TABLE, &coargs.flags, 1274 8048 Madhavan 'D', MDB_OPT_SETBITS, COF_EXPREL, &coargs.flags, 1275 8048 Madhavan 'L', MDB_OPT_SETBITS, COF_LIST, &coargs.flags, 1276 8048 Madhavan 'V', MDB_OPT_SETBITS, COF_VERBOSE, &coargs.flags, 1277 8048 Madhavan 'v', MDB_OPT_SETBITS, COF_LONGLIST, &coargs.flags, 1278 8048 Madhavan 'i', MDB_OPT_SETBITS, COF_BYIDH, &coargs.flags, 1279 8048 Madhavan 'F', MDB_OPT_SETBITS, COF_FREE, &coargs.flags, 1280 8048 Madhavan 'A', MDB_OPT_SETBITS, COF_ADDR, &coargs.flags, 1281 8048 Madhavan NULL) != argc) { 1282 8048 Madhavan return (DCMD_USAGE); 1283 8048 Madhavan } 1284 8048 Madhavan 1285 8048 Madhavan /* initialize from kernel variables */ 1286 8048 Madhavan if ((retval = callout_common_init(&coargs)) != DCMD_OK) { 1287 8048 Madhavan return (retval); 1288 8048 Madhavan } 1289 8048 Madhavan 1290 8048 Madhavan /* do some option post-processing */ 1291 8048 Madhavan if (kflag) { 1292 8048 Madhavan coargs.time *= coargs.nsec_per_tick; 1293 8048 Madhavan coargs.atime *= coargs.nsec_per_tick; 1294 8048 Madhavan coargs.btime *= coargs.nsec_per_tick; 1295 8048 Madhavan } 1296 8048 Madhavan 1297 8048 Madhavan if (dflag) { 1298 8048 Madhavan coargs.time += coargs.now; 1299 8048 Madhavan coargs.atime += coargs.now; 1300 8048 Madhavan coargs.btime += coargs.now; 1301 8048 Madhavan } 1302 8048 Madhavan if (Sflag) { 1303 8048 Madhavan if (flags & DCMD_ADDRSPEC) { 1304 8048 Madhavan mdb_printf("-S option conflicts with explicit" 1305 8048 Madhavan " address\n"); 1306 8048 Madhavan return (DCMD_USAGE); 1307 8048 Madhavan } 1308 8048 Madhavan coargs.flags |= COF_SEQID; 1309 8048 Madhavan coargs.seqid = (int)Stmp; 1310 8048 Madhavan } 1311 8048 Madhavan if (Cflag) { 1312 8048 Madhavan if (flags & DCMD_ADDRSPEC) { 1313 8048 Madhavan mdb_printf("-C option conflicts with explicit" 1314 8048 Madhavan " address\n"); 1315 8048 Madhavan return (DCMD_USAGE); 1316 8048 Madhavan } 1317 8048 Madhavan if (coargs.flags & COF_SEQID) { 1318 8048 Madhavan mdb_printf("-C and -S are mutually exclusive\n"); 1319 8048 Madhavan return (DCMD_USAGE); 1320 8048 Madhavan } 1321 8048 Madhavan coargs.cpu = (cpu_t *)Ctmp; 1322 8048 Madhavan if (mdb_vread(&coargs.seqid, sizeof (processorid_t), 1323 8048 Madhavan (uintptr_t)&(coargs.cpu->cpu_seqid)) == -1) { 1324 8048 Madhavan mdb_warn("failed to read cpu_t at %p", Ctmp); 1325 8048 Madhavan return (DCMD_ERR); 1326 8048 Madhavan } 1327 8048 Madhavan coargs.flags |= COF_SEQID; 1328 8048 Madhavan } 1329 8048 Madhavan /* avoid null outputs. */ 1330 8048 Madhavan if (!(coargs.flags & (COF_REAL | COF_NORM))) { 1331 8048 Madhavan coargs.flags |= COF_REAL | COF_NORM; 1332 8048 Madhavan } 1333 8048 Madhavan if (!(coargs.flags & (COF_LONG | COF_SHORT))) { 1334 8048 Madhavan coargs.flags |= COF_LONG | COF_SHORT; 1335 8048 Madhavan } 1336 8048 Madhavan if (tflag) { 1337 8048 Madhavan if (aflag || bflag) { 1338 8048 Madhavan mdb_printf("-t and -a|b are mutually exclusive\n"); 1339 8048 Madhavan return (DCMD_USAGE); 1340 8048 Madhavan } 1341 8048 Madhavan coargs.flags |= COF_TIME; 1342 8048 Madhavan } 1343 8048 Madhavan if (aflag) { 1344 8048 Madhavan coargs.flags |= COF_AFTER; 1345 8048 Madhavan } 1346 8048 Madhavan if (bflag) { 1347 8048 Madhavan coargs.flags |= COF_BEFORE; 1348 8048 Madhavan } 1349 8048 Madhavan if ((aflag && bflag) && (coargs.btime <= coargs.atime)) { 1350 8048 Madhavan mdb_printf("value for -a must be earlier than the value" 1351 8048 Madhavan " for -b.\n"); 1352 8048 Madhavan return (DCMD_USAGE); 1353 8048 Madhavan } 1354 8048 Madhavan 1355 8048 Madhavan if (funcname != NULL) { 1356 8048 Madhavan GElf_Sym sym; 1357 8048 Madhavan 1358 8048 Madhavan if (mdb_lookup_by_name(funcname, &sym) != 0) { 1359 8048 Madhavan coargs.funcaddr = mdb_strtoull(funcname); 1360 8048 Madhavan } else { 1361 8048 Madhavan coargs.funcaddr = sym.st_value; 1362 8048 Madhavan } 1363 8048 Madhavan coargs.flags |= COF_FUNC; 1364 8048 Madhavan } 1365 8048 Madhavan 1366 8048 Madhavan if (paramstr != NULL) { 1367 8048 Madhavan GElf_Sym sym; 1368 8048 Madhavan 1369 8048 Madhavan if (mdb_lookup_by_name(paramstr, &sym) != 0) { 1370 8048 Madhavan coargs.param = mdb_strtoull(paramstr); 1371 8048 Madhavan } else { 1372 8048 Madhavan coargs.param = sym.st_value; 1373 8048 Madhavan } 1374 8048 Madhavan coargs.flags |= COF_PARAM; 1375 8048 Madhavan } 1376 8048 Madhavan 1377 8048 Madhavan if (!(flags & DCMD_ADDRSPEC)) { 1378 8048 Madhavan /* don't pass "dot" if no addr. */ 1379 8048 Madhavan addr = NULL; 1380 8048 Madhavan } 1381 8048 Madhavan if (addr != NULL) { 1382 8048 Madhavan /* 1383 8048 Madhavan * a callout table was specified. Ignore -r|n option 1384 8048 Madhavan * to avoid null output. 1385 8048 Madhavan */ 1386 8048 Madhavan coargs.flags |= (COF_REAL | COF_NORM); 1387 8048 Madhavan } 1388 8048 Madhavan 1389 8048 Madhavan if (DCMD_HDRSPEC(flags) || (coargs.flags & COF_VERBOSE)) { 1390 8048 Madhavan coargs.flags |= COF_THDR | COF_LHDR | COF_CHDR; 1391 8048 Madhavan } 1392 8048 Madhavan if (coargs.flags & COF_FREE) { 1393 8048 Madhavan coargs.flags |= COF_EMPTY; 1394 8048 Madhavan /* -F = free callouts, -FL = free lists */ 1395 8048 Madhavan if (!(coargs.flags & COF_LIST)) { 1396 8048 Madhavan coargs.flags |= COF_BYIDH; 1397 8048 Madhavan } 1398 8048 Madhavan } 1399 8048 Madhavan 1400 8048 Madhavan /* walk table, using specialized callback routine. */ 1401 8048 Madhavan if (mdb_pwalk("callout_table", callout_t_cb, &coargs, addr) == -1) { 1402 8048 Madhavan mdb_warn("cannot walk callout_table"); 1403 8048 Madhavan return (DCMD_ERR); 1404 8048 Madhavan } 1405 8048 Madhavan return (DCMD_OK); 1406 8048 Madhavan } 1407 8048 Madhavan 1408 8048 Madhavan 1409 8048 Madhavan /* 1410 8048 Madhavan * Given an extended callout id, dump its information. 1411 8048 Madhavan */ 1412 8048 Madhavan /*ARGSUSED*/ 1413 8048 Madhavan int 1414 8048 Madhavan calloutid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1415 8048 Madhavan { 1416 8048 Madhavan callout_data_t coargs; 1417 8048 Madhavan callout_table_t *ctptr; 1418 8048 Madhavan callout_table_t ct; 1419 8048 Madhavan callout_id_t coid; 1420 8048 Madhavan callout_t *coptr; 1421 8048 Madhavan int tableid; 1422 8048 Madhavan callout_id_t xid; 1423 8048 Madhavan ulong_t idhash; 1424 8048 Madhavan int i, retval; 1425 8048 Madhavan const mdb_arg_t *arg; 1426 8048 Madhavan size_t size; 1427 8048 Madhavan callout_hash_t cot_idhash[CALLOUT_BUCKETS]; 1428 8048 Madhavan 1429 8048 Madhavan coargs.flags = COF_DEFAULT | COF_BYIDH; 1430 8048 Madhavan i = mdb_getopts(argc, argv, 1431 8048 Madhavan 'd', MDB_OPT_SETBITS, COF_DECODE, &coargs.flags, 1432 8048 Madhavan 'v', MDB_OPT_SETBITS, COF_LONGLIST, &coargs.flags, 1433 8048 Madhavan NULL); 1434 8048 Madhavan argc -= i; 1435 8048 Madhavan argv += i; 1436 8048 Madhavan 1437 8048 Madhavan if (argc != 1) { 1438 8048 Madhavan return (DCMD_USAGE); 1439 8048 Madhavan } 1440 8048 Madhavan arg = &argv[0]; 1441 8048 Madhavan 1442 8048 Madhavan if (arg->a_type == MDB_TYPE_IMMEDIATE) { 1443 8048 Madhavan xid = arg->a_un.a_val; 1444 8048 Madhavan } else { 1445 8048 Madhavan xid = (callout_id_t)mdb_strtoull(arg->a_un.a_str); 1446 8048 Madhavan } 1447 8048 Madhavan 1448 8048 Madhavan if (DCMD_HDRSPEC(flags)) { 1449 8048 Madhavan coargs.flags |= COF_CHDR; 1450 8048 Madhavan } 1451 8048 Madhavan 1452 8048 Madhavan 1453 8048 Madhavan /* initialize from kernel variables */ 1454 8048 Madhavan if ((retval = callout_common_init(&coargs)) != DCMD_OK) { 1455 8048 Madhavan return (retval); 1456 8048 Madhavan } 1457 8048 Madhavan 1458 8048 Madhavan /* we must massage the environment so that the macros will play nice */ 1459 8048 Madhavan #define callout_table_mask ((1 << coargs.ctbits) - 1) 1460 8048 Madhavan #define callout_table_bits coargs.ctbits 1461 8048 Madhavan #define nsec_per_tick coargs.nsec_per_tick 1462 8048 Madhavan tableid = CALLOUT_ID_TO_TABLE(xid); 1463 8048 Madhavan idhash = CALLOUT_IDHASH(xid); 1464 8048 Madhavan #undef callouts_table_bits 1465 8048 Madhavan #undef callout_table_mask 1466 8048 Madhavan #undef nsec_per_tick 1467 8048 Madhavan coid = CO_PLAIN_ID(xid); 1468 8048 Madhavan 1469 8048 Madhavan if (flags & DCMD_ADDRSPEC) { 1470 8048 Madhavan mdb_printf("calloutid does not accept explicit address.\n"); 1471 8048 Madhavan return (DCMD_USAGE); 1472 8048 Madhavan } 1473 8048 Madhavan 1474 8048 Madhavan if (coargs.flags & COF_DECODE) { 1475 8048 Madhavan if (DCMD_HDRSPEC(flags)) { 1476 9039 Madhavan mdb_printf("%<u>%3s %1s %2s %-?s %-6s %</u>\n", 1477 9039 Madhavan "SEQ", "T", "XL", "XID", "IDHASH"); 1478 9039 Madhavan } 1479 9039 Madhavan mdb_printf("%-3d %1s %1s%1s %-?llx %-6d\n", 1480 8048 Madhavan TABLE_TO_SEQID(tableid), 1481 8048 Madhavan co_typenames[tableid & CALLOUT_TYPE_MASK], 1482 8048 Madhavan (xid & CALLOUT_EXECUTING) ? "X" : " ", 1483 8048 Madhavan (xid & CALLOUT_LONGTERM) ? "L" : " ", 1484 8048 Madhavan (long long)coid, idhash); 1485 8048 Madhavan return (DCMD_OK); 1486 8048 Madhavan } 1487 8048 Madhavan 1488 8048 Madhavan /* get our table. Note this relies on the types being correct */ 1489 8048 Madhavan ctptr = coargs.co_table + tableid; 1490 8048 Madhavan if (mdb_vread(&ct, sizeof (callout_table_t), (uintptr_t)ctptr) == -1) { 1491 8048 Madhavan mdb_warn("failed to read callout_table at %p", ctptr); 1492 8048 Madhavan return (DCMD_ERR); 1493 8048 Madhavan } 1494 8048 Madhavan size = sizeof (callout_hash_t) * CALLOUT_BUCKETS; 1495 8048 Madhavan if (ct.ct_idhash != NULL) { 1496 8048 Madhavan if (mdb_vread(&(cot_idhash), size, 1497 8048 Madhavan (uintptr_t)ct.ct_idhash) == -1) { 1498 8048 Madhavan mdb_warn("failed to read id_hash at %p", 1499 8048 Madhavan ct.ct_idhash); 1500 8048 Madhavan return (WALK_ERR); 1501 8048 Madhavan } 1502 8048 Madhavan } 1503 8048 Madhavan 1504 8048 Madhavan /* callout at beginning of hash chain */ 1505 8048 Madhavan if (ct.ct_idhash == NULL) { 1506 8048 Madhavan mdb_printf("id hash chain for this xid is empty\n"); 1507 8048 Madhavan return (DCMD_ERR); 1508 8048 Madhavan } 1509 8048 Madhavan coptr = (callout_t *)cot_idhash[idhash].ch_head; 1510 8048 Madhavan if (coptr == NULL) { 1511 8048 Madhavan mdb_printf("id hash chain for this xid is empty\n"); 1512 8048 Madhavan return (DCMD_ERR); 1513 8048 Madhavan } 1514 8048 Madhavan 1515 8048 Madhavan coargs.ndx = tableid; 1516 8048 Madhavan coargs.bucket = idhash; 1517 8048 Madhavan 1518 8048 Madhavan /* use the walker, luke */ 1519 8048 Madhavan if (mdb_pwalk("callouts_byid", callouts_cb, &coargs, 1520 8048 Madhavan (uintptr_t)coptr) == -1) { 1521 8048 Madhavan mdb_warn("cannot walk callouts at %p", coptr); 1522 8048 Madhavan return (WALK_ERR); 1523 8048 Madhavan } 1524 8048 Madhavan 1525 8048 Madhavan return (DCMD_OK); 1526 8048 Madhavan } 1527 8048 Madhavan 1528 8048 Madhavan void 1529 8048 Madhavan callout_help(void) 1530 8048 Madhavan { 1531 8048 Madhavan mdb_printf("callout: display callouts.\n" 1532 8048 Madhavan "Given a callout table address, display callouts from table.\n" 1533 8048 Madhavan "Without an address, display callouts from all tables.\n" 1534 8048 Madhavan "options:\n" 1535 8048 Madhavan " -r|n : limit display to (r)ealtime or (n)ormal type callouts\n" 1536 8048 Madhavan " -s|l : limit display to (s)hort-term ids or (l)ong-term ids\n" 1537 8048 Madhavan " -x : limit display to callouts which are executing\n" 1538 8048 Madhavan " -h : limit display to callouts based on hrestime\n" 1539 9039 Madhavan " -B : limit display to callouts based on absolute time\n" 1540 8048 Madhavan " -t|a|b nsec: limit display to callouts that expire a(t) time," 1541 8048 Madhavan " (a)fter time,\n or (b)efore time. Use -a and -b together " 1542 8048 Madhavan " to specify a range.\n For \"now\", use -d[t|a|b] 0.\n" 1543 8048 Madhavan " -d : interpret time option to -t|a|b as delta from current time\n" 1544 8048 Madhavan " -k : use ticks instead of nanoseconds as arguments to" 1545 8048 Madhavan " -t|a|b. Note that\n ticks are less accurate and may not" 1546 8048 Madhavan " match other tick times (ie: lbolt).\n" 1547 8048 Madhavan " -D : display exiration time as delta from current time\n" 1548 8048 Madhavan " -S seqid : limit display to callouts for this cpu sequence id\n" 1549 8048 Madhavan " -C addr : limit display to callouts for this cpu pointer\n" 1550 8048 Madhavan " -f name|addr : limit display to callouts with this function\n" 1551 8048 Madhavan " -p name|addr : limit display to callouts functions with this" 1552 8048 Madhavan " parameter\n" 1553 8048 Madhavan " -T : display the callout table itself, instead of callouts\n" 1554 8048 Madhavan " -L : display callout lists instead of callouts\n" 1555 8048 Madhavan " -E : with -T or L, display empty data structures.\n" 1556 8048 Madhavan " -i : traverse callouts by id hash instead of list hash\n" 1557 8048 Madhavan " -F : walk free callout list (free list with -i) instead\n" 1558 8048 Madhavan " -v : display more info for each item\n" 1559 8048 Madhavan " -V : show details of each level of info as it is traversed\n" 1560 8048 Madhavan " -A : show only addresses. Useful for pipelines.\n"); 1561 8048 Madhavan } 1562 8048 Madhavan 1563 8048 Madhavan void 1564 8048 Madhavan calloutid_help(void) 1565 8048 Madhavan { 1566 8048 Madhavan mdb_printf("calloutid: display callout by id.\n" 1567 8048 Madhavan "Given an extended callout id, display the callout infomation.\n" 1568 8048 Madhavan "options:\n" 1569 8048 Madhavan " -d : do not dereference callout, just decode the id.\n" 1570 8048 Madhavan " -v : verbose display more info about the callout\n"); 1571 0 stevel } 1572 0 stevel 1573 0 stevel /*ARGSUSED*/ 1574 0 stevel int 1575 0 stevel class(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1576 0 stevel { 1577 0 stevel long num_classes, i; 1578 0 stevel sclass_t *class_tbl; 1579 0 stevel GElf_Sym g_sclass; 1580 0 stevel char class_name[PC_CLNMSZ]; 1581 0 stevel size_t tbl_size; 1582 0 stevel 1583 0 stevel if (mdb_lookup_by_name("sclass", &g_sclass) == -1) { 1584 0 stevel mdb_warn("failed to find symbol sclass\n"); 1585 0 stevel return (DCMD_ERR); 1586 0 stevel } 1587 0 stevel 1588 0 stevel tbl_size = (size_t)g_sclass.st_size; 1589 0 stevel num_classes = tbl_size / (sizeof (sclass_t)); 1590 0 stevel class_tbl = mdb_alloc(tbl_size, UM_SLEEP | UM_GC); 1591 0 stevel 1592 0 stevel if (mdb_readsym(class_tbl, tbl_size, "sclass") == -1) { 1593 0 stevel mdb_warn("failed to read sclass"); 1594 0 stevel return (DCMD_ERR); 1595 0 stevel } 1596 0 stevel 1597 0 stevel mdb_printf("%<u>%4s %-10s %-24s %-24s%</u>\n", "SLOT", "NAME", 1598 0 stevel "INIT FCN", "CLASS FCN"); 1599 0 stevel 1600 0 stevel for (i = 0; i < num_classes; i++) { 1601 0 stevel if (mdb_vread(class_name, sizeof (class_name), 1602 0 stevel (uintptr_t)class_tbl[i].cl_name) == -1) 1603 0 stevel (void) strcpy(class_name, "???"); 1604 0 stevel 1605 0 stevel mdb_printf("%4ld %-10s %-24a %-24a\n", i, class_name, 1606 0 stevel class_tbl[i].cl_init, class_tbl[i].cl_funcs); 1607 0 stevel } 1608 0 stevel 1609 0 stevel return (DCMD_OK); 1610 0 stevel } 1611 0 stevel 1612 0 stevel #define FSNAMELEN 32 /* Max len of FS name we read from vnodeops */ 1613 0 stevel 1614 0 stevel int 1615 0 stevel vnode2path(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1616 0 stevel { 1617 0 stevel uintptr_t rootdir; 1618 0 stevel vnode_t vn; 1619 0 stevel char buf[MAXPATHLEN]; 1620 0 stevel 1621 0 stevel uint_t opt_F = FALSE; 1622 0 stevel 1623 0 stevel if (mdb_getopts(argc, argv, 1624 0 stevel 'F', MDB_OPT_SETBITS, TRUE, &opt_F, NULL) != argc) 1625 0 stevel return (DCMD_USAGE); 1626 0 stevel 1627 0 stevel if (!(flags & DCMD_ADDRSPEC)) { 1628 0 stevel mdb_warn("expected explicit vnode_t address before ::\n"); 1629 0 stevel return (DCMD_USAGE); 1630 0 stevel } 1631 0 stevel 1632 0 stevel if (mdb_readvar(&rootdir, "rootdir") == -1) { 1633 0 stevel mdb_warn("failed to read rootdir"); 1634 0 stevel return (DCMD_ERR); 1635 0 stevel } 1636 0 stevel 1637 0 stevel if (mdb_vnode2path(addr, buf, sizeof (buf)) == -1) 1638 0 stevel return (DCMD_ERR); 1639 0 stevel 1640 0 stevel if (*buf == '\0') { 1641 0 stevel mdb_printf("??\n"); 1642 0 stevel return (DCMD_OK); 1643 0 stevel } 1644 0 stevel 1645 0 stevel mdb_printf("%s", buf); 1646 0 stevel if (opt_F && buf[strlen(buf)-1] != '/' && 1647 0 stevel mdb_vread(&vn, sizeof (vn), addr) == sizeof (vn)) 1648 0 stevel mdb_printf("%c", mdb_vtype2chr(vn.v_type, 0)); 1649 0 stevel mdb_printf("\n"); 1650 0 stevel 1651 0 stevel return (DCMD_OK); 1652 0 stevel } 1653 0 stevel 1654 0 stevel int 1655 0 stevel ld_walk_init(mdb_walk_state_t *wsp) 1656 0 stevel { 1657 0 stevel wsp->walk_data = (void *)wsp->walk_addr; 1658 0 stevel return (WALK_NEXT); 1659 0 stevel } 1660 0 stevel 1661 0 stevel int 1662 0 stevel ld_walk_step(mdb_walk_state_t *wsp) 1663 0 stevel { 1664 0 stevel int status; 1665 0 stevel lock_descriptor_t ld; 1666 0 stevel 1667 0 stevel if (mdb_vread(&ld, sizeof (lock_descriptor_t), wsp->walk_addr) == -1) { 1668 0 stevel mdb_warn("couldn't read lock_descriptor_t at %p\n", 1669 0 stevel wsp->walk_addr); 1670 0 stevel return (WALK_ERR); 1671 0 stevel } 1672 0 stevel 1673 0 stevel status = wsp->walk_callback(wsp->walk_addr, &ld, wsp->walk_cbdata); 1674 0 stevel if (status == WALK_ERR) 1675 0 stevel return (WALK_ERR); 1676 0 stevel 1677 0 stevel wsp->walk_addr = (uintptr_t)ld.l_next; 1678 0 stevel if (wsp->walk_addr == (uintptr_t)wsp->walk_data) 1679 0 stevel return (WALK_DONE); 1680 0 stevel 1681 0 stevel return (status); 1682 0 stevel } 1683 0 stevel 1684 0 stevel int 1685 0 stevel lg_walk_init(mdb_walk_state_t *wsp) 1686 0 stevel { 1687 0 stevel GElf_Sym sym; 1688 0 stevel 1689 0 stevel if (mdb_lookup_by_name("lock_graph", &sym) == -1) { 1690 0 stevel mdb_warn("failed to find symbol 'lock_graph'\n"); 1691 0 stevel return (WALK_ERR); 1692 0 stevel } 1693 0 stevel 1694 0 stevel wsp->walk_addr = (uintptr_t)sym.st_value; 1695 436 dmick wsp->walk_data = (void *)(uintptr_t)(sym.st_value + sym.st_size); 1696 0 stevel 1697 0 stevel return (WALK_NEXT); 1698 0 stevel } 1699 0 stevel 1700 0 stevel typedef struct lg_walk_data { 1701 0 stevel uintptr_t startaddr; 1702 0 stevel mdb_walk_cb_t callback; 1703 0 stevel void *data; 1704 0 stevel } lg_walk_data_t; 1705 0 stevel 1706 0 stevel /* 1707 0 stevel * We can't use ::walk lock_descriptor directly, because the head of each graph 1708 0 stevel * is really a dummy lock. Rather than trying to dynamically determine if this 1709 0 stevel * is a dummy node or not, we just filter out the initial element of the 1710 0 stevel * list. 1711 0 stevel */ 1712 0 stevel static int 1713 0 stevel lg_walk_cb(uintptr_t addr, const void *data, void *priv) 1714 0 stevel { 1715 0 stevel lg_walk_data_t *lw = priv; 1716 0 stevel 1717 0 stevel if (addr != lw->startaddr) 1718 0 stevel return (lw->callback(addr, data, lw->data)); 1719 0 stevel 1720 0 stevel return (WALK_NEXT); 1721 0 stevel } 1722 0 stevel 1723 0 stevel int 1724 0 stevel lg_walk_step(mdb_walk_state_t *wsp) 1725 0 stevel { 1726 0 stevel graph_t *graph; 1727 0 stevel lg_walk_data_t lw; 1728 0 stevel 1729 0 stevel if (wsp->walk_addr >= (uintptr_t)wsp->walk_data) 1730 0 stevel return (WALK_DONE); 1731 0 stevel 1732 0 stevel if (mdb_vread(&graph, sizeof (graph), wsp->walk_addr) == -1) { 1733 0 stevel mdb_warn("failed to read graph_t at %p", wsp->walk_addr); 1734 0 stevel return (WALK_ERR); 1735 0 stevel } 1736 0 stevel 1737 0 stevel wsp->walk_addr += sizeof (graph); 1738 0 stevel 1739 0 stevel if (graph == NULL) 1740 0 stevel return (WALK_NEXT); 1741 0 stevel 1742 0 stevel lw.callback = wsp->walk_callback; 1743 0 stevel lw.data = wsp->walk_cbdata; 1744 0 stevel 1745 0 stevel lw.startaddr = (uintptr_t)&(graph->active_locks); 1746 0 stevel if (mdb_pwalk("lock_descriptor", lg_walk_cb, &lw, lw.startaddr)) { 1747 0 stevel mdb_warn("couldn't walk lock_descriptor at %p\n", lw.startaddr); 1748 0 stevel return (WALK_ERR); 1749 0 stevel } 1750 0 stevel 1751 0 stevel lw.startaddr = (uintptr_t)&(graph->sleeping_locks); 1752 0 stevel if (mdb_pwalk("lock_descriptor", lg_walk_cb, &lw, lw.startaddr)) { 1753 0 stevel mdb_warn("couldn't walk lock_descriptor at %p\n", lw.startaddr); 1754 0 stevel return (WALK_ERR); 1755 0 stevel } 1756 0 stevel 1757 0 stevel return (WALK_NEXT); 1758 0 stevel } 1759 0 stevel 1760 0 stevel /* 1761 0 stevel * The space available for the path corresponding to the locked vnode depends 1762 0 stevel * on whether we are printing 32- or 64-bit addresses. 1763 0 stevel */ 1764 0 stevel #ifdef _LP64 1765 0 stevel #define LM_VNPATHLEN 20 1766 0 stevel #else 1767 0 stevel #define LM_VNPATHLEN 30 1768 0 stevel #endif 1769 0 stevel 1770 0 stevel /*ARGSUSED*/ 1771 0 stevel static int 1772 0 stevel lminfo_cb(uintptr_t addr, const void *data, void *priv) 1773 0 stevel { 1774 0 stevel const lock_descriptor_t *ld = data; 1775 0 stevel char buf[LM_VNPATHLEN]; 1776 0 stevel proc_t p; 1777 0 stevel 1778 0 stevel mdb_printf("%-?p %2s %04x %6d %-16s %-?p ", 1779 0 stevel addr, ld->l_type == F_RDLCK ? "RD" : 1780 0 stevel ld->l_type == F_WRLCK ? "WR" : "??", 1781 0 stevel ld->l_state, ld->l_flock.l_pid, 1782 0 stevel ld->l_flock.l_pid == 0 ? "<kernel>" : 1783 0 stevel mdb_pid2proc(ld->l_flock.l_pid, &p) == NULL ? 1784 0 stevel "<defunct>" : p.p_user.u_comm, 1785 0 stevel ld->l_vnode); 1786 0 stevel 1787 0 stevel mdb_vnode2path((uintptr_t)ld->l_vnode, buf, 1788 0 stevel sizeof (buf)); 1789 0 stevel mdb_printf("%s\n", buf); 1790 0 stevel 1791 0 stevel return (WALK_NEXT); 1792 0 stevel } 1793 0 stevel 1794 0 stevel /*ARGSUSED*/ 1795 0 stevel int 1796 0 stevel lminfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1797 0 stevel { 1798 0 stevel if (DCMD_HDRSPEC(flags)) 1799 0 stevel mdb_printf("%<u>%-?s %2s %4s %6s %-16s %-?s %s%</u>\n", 1800 0 stevel "ADDR", "TP", "FLAG", "PID", "COMM", "VNODE", "PATH"); 1801 0 stevel 1802 0 stevel return (mdb_pwalk("lock_graph", lminfo_cb, NULL, NULL)); 1803 0 stevel } 1804 0 stevel 1805 0 stevel /*ARGSUSED*/ 1806 0 stevel int 1807 0 stevel seg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1808 0 stevel { 1809 0 stevel struct seg s; 1810 0 stevel 1811 0 stevel if (argc != 0) 1812 0 stevel return (DCMD_USAGE); 1813 0 stevel 1814 0 stevel if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 1815 0 stevel mdb_printf("%<u>%?s %?s %?s %?s %s%</u>\n", 1816 0 stevel "SEG", "BASE", "SIZE", "DATA", "OPS"); 1817 0 stevel } 1818 0 stevel 1819 0 stevel if (mdb_vread(&s, sizeof (s), addr) == -1) { 1820 0 stevel mdb_warn("failed to read seg at %p", addr); 1821 0 stevel return (DCMD_ERR); 1822 0 stevel } 1823 0 stevel 1824 0 stevel mdb_printf("%?p %?p %?lx %?p %a\n", 1825 0 stevel addr, s.s_base, s.s_size, s.s_data, s.s_ops); 1826 0 stevel 1827 0 stevel return (DCMD_OK); 1828 0 stevel } 1829 0 stevel 1830 0 stevel /*ARGSUSED*/ 1831 0 stevel static int 1832 0 stevel pmap_walk_anon(uintptr_t addr, const struct anon *anon, int *nres) 1833 0 stevel { 1834 0 stevel uintptr_t pp = 1835 0 stevel mdb_vnode2page((uintptr_t)anon->an_vp, (uintptr_t)anon->an_off); 1836 0 stevel 1837 0 stevel if (pp != NULL) 1838 0 stevel (*nres)++; 1839 0 stevel 1840 0 stevel return (WALK_NEXT); 1841 0 stevel } 1842 0 stevel 1843 0 stevel static int 1844 0 stevel pmap_walk_seg(uintptr_t addr, const struct seg *seg, uintptr_t segvn) 1845 0 stevel { 1846 0 stevel 1847 0 stevel mdb_printf("%0?p %0?p %7dk", addr, seg->s_base, seg->s_size / 1024); 1848 0 stevel 1849 0 stevel if (segvn == (uintptr_t)seg->s_ops) { 1850 0 stevel struct segvn_data svn; 1851 0 stevel int nres = 0; 1852 0 stevel 1853 0 stevel (void) mdb_vread(&svn, sizeof (svn), (uintptr_t)seg->s_data); 1854 0 stevel 1855 0 stevel if (svn.amp == NULL) { 1856 0 stevel mdb_printf(" %8s", ""); 1857 0 stevel goto drive_on; 1858 0 stevel } 1859 0 stevel 1860 0 stevel /* 1861 0 stevel * We've got an amp for this segment; walk through 1862 0 stevel * the amp, and determine mappings. 1863 0 stevel */ 1864 0 stevel if (mdb_pwalk("anon", (mdb_walk_cb_t)pmap_walk_anon, 1865 0 stevel &nres, (uintptr_t)svn.amp) == -1) 1866 0 stevel mdb_warn("failed to walk anon (amp=%p)", svn.amp); 1867 0 stevel 1868 0 stevel mdb_printf(" %7dk", (nres * PAGESIZE) / 1024); 1869 0 stevel drive_on: 1870 0 stevel 1871 0 stevel if (svn.vp != NULL) { 1872 0 stevel char buf[29]; 1873 0 stevel 1874 0 stevel mdb_vnode2path((uintptr_t)svn.vp, buf, sizeof (buf)); 1875 0 stevel mdb_printf(" %s", buf); 1876 0 stevel } else 1877 0 stevel mdb_printf(" [ anon ]"); 1878 0 stevel } 1879 0 stevel 1880 0 stevel mdb_printf("\n"); 1881 0 stevel return (WALK_NEXT); 1882 0 stevel } 1883 0 stevel 1884 0 stevel static int 1885 0 stevel pmap_walk_seg_quick(uintptr_t addr, const struct seg *seg, uintptr_t segvn) 1886 0 stevel { 1887 0 stevel mdb_printf("%0?p %0?p %7dk", addr, seg->s_base, seg->s_size / 1024); 1888 0 stevel 1889 0 stevel if (segvn == (uintptr_t)seg->s_ops) { 1890 0 stevel struct segvn_data svn; 1891 0 stevel 1892 0 stevel (void) mdb_vread(&svn, sizeof (svn), (uintptr_t)seg->s_data); 1893 0 stevel 1894 0 stevel if (svn.vp != NULL) { 1895 0 stevel mdb_printf(" %0?p", svn.vp); 1896 0 stevel } else { 1897 0 stevel mdb_printf(" [ anon ]"); 1898 0 stevel } 1899 0 stevel } 1900 0 stevel 1901 0 stevel mdb_printf("\n"); 1902 0 stevel return (WALK_NEXT); 1903 0 stevel } 1904 0 stevel 1905 0 stevel /*ARGSUSED*/ 1906 0 stevel int 1907 0 stevel pmap(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1908 0 stevel { 1909 0 stevel uintptr_t segvn; 1910 0 stevel proc_t proc; 1911 0 stevel uint_t quick = FALSE; 1912 0 stevel mdb_walk_cb_t cb = (mdb_walk_cb_t)pmap_walk_seg; 1913 0 stevel 1914 0 stevel GElf_Sym sym; 1915 0 stevel 1916 0 stevel if (!(flags & DCMD_ADDRSPEC)) 1917 0 stevel return (DCMD_USAGE); 1918 0 stevel 1919 0 stevel if (mdb_getopts(argc, argv, 1920 0 stevel 'q', MDB_OPT_SETBITS, TRUE, &quick, NULL) != argc) 1921 0 stevel return (DCMD_USAGE); 1922 0 stevel 1923 0 stevel if (mdb_vread(&proc, sizeof (proc), addr) == -1) { 1924 0 stevel mdb_warn("failed to read proc at %p", addr); 1925 0 stevel return (DCMD_ERR); 1926 0 stevel } 1927 0 stevel 1928 0 stevel if (mdb_lookup_by_name("segvn_ops", &sym) == 0) 1929 0 stevel segvn = (uintptr_t)sym.st_value; 1930 0 stevel else 1931 0 stevel segvn = NULL; 1932 0 stevel 1933 0 stevel mdb_printf("%?s %?s %8s ", "SEG", "BASE", "SIZE"); 1934 0 stevel 1935 0 stevel if (quick) { 1936 0 stevel mdb_printf("VNODE\n"); 1937 0 stevel cb = (mdb_walk_cb_t)pmap_walk_seg_quick; 1938 0 stevel } else { 1939 0 stevel mdb_printf("%8s %s\n", "RES", "PATH"); 1940 0 stevel } 1941 0 stevel 1942 0 stevel if (mdb_pwalk("seg", cb, (void *)segvn, (uintptr_t)proc.p_as) == -1) { 1943 0 stevel mdb_warn("failed to walk segments of as %p", proc.p_as); 1944 0 stevel return (DCMD_ERR); 1945 0 stevel } 1946 0 stevel 1947 0 stevel return (DCMD_OK); 1948 0 stevel } 1949 0 stevel 1950 0 stevel typedef struct anon_walk_data { 1951 0 stevel uintptr_t *aw_levone; 1952 0 stevel uintptr_t *aw_levtwo; 1953 0 stevel int aw_nlevone; 1954 0 stevel int aw_levone_ndx; 1955 0 stevel int aw_levtwo_ndx; 1956 0 stevel struct anon_map aw_amp; 1957 0 stevel struct anon_hdr aw_ahp; 1958 0 stevel } anon_walk_data_t; 1959 0 stevel 1960 0 stevel int 1961 0 stevel anon_walk_init(mdb_walk_state_t *wsp) 1962 0 stevel { 1963 0 stevel anon_walk_data_t *aw; 1964 0 stevel 1965 0 stevel if (wsp->walk_addr == NULL) { 1966 0 stevel mdb_warn("anon walk doesn't support global walks\n"); 1967 0 stevel return (WALK_ERR); 1968 0 stevel } 1969 0 stevel 1970 0 stevel aw = mdb_alloc(sizeof (anon_walk_data_t), UM_SLEEP); 1971 0 stevel 1972 0 stevel if (mdb_vread(&aw->aw_amp, sizeof (aw->aw_amp), wsp->walk_addr) == -1) { 1973 0 stevel mdb_warn("failed to read anon map at %p", wsp->walk_addr); 1974 0 stevel mdb_free(aw, sizeof (anon_walk_data_t)); 1975 0 stevel return (WALK_ERR); 1976 0 stevel } 1977 0 stevel 1978 0 stevel if (mdb_vread(&aw->aw_ahp, sizeof (aw->aw_ahp), 1979 0 stevel (uintptr_t)(aw->aw_amp.ahp)) == -1) { 1980 0 stevel mdb_warn("failed to read anon hdr ptr at %p", aw->aw_amp.ahp); 1981 0 stevel mdb_free(aw, sizeof (anon_walk_data_t)); 1982 0 stevel return (WALK_ERR); 1983 0 stevel } 1984 0 stevel 1985 0 stevel if (aw->aw_ahp.size <= ANON_CHUNK_SIZE || 1986 0 stevel (aw->aw_ahp.flags & ANON_ALLOC_FORCE)) { 1987 0 stevel aw->aw_nlevone = aw->aw_ahp.size; 1988 0 stevel aw->aw_levtwo = NULL; 1989 0 stevel } else { 1990 0 stevel aw->aw_nlevone = 1991 0 stevel (aw->aw_ahp.size + ANON_CHUNK_OFF) >> ANON_CHUNK_SHIFT; 1992 0 stevel aw->aw_levtwo = 1993 0 stevel mdb_zalloc(ANON_CHUNK_SIZE * sizeof (uintptr_t), UM_SLEEP); 1994 0 stevel } 1995 0 stevel 1996 0 stevel aw->aw_levone = 1997 0 stevel mdb_alloc(aw->aw_nlevone * sizeof (uintptr_t), UM_SLEEP); 1998 0 stevel 1999 0 stevel aw->aw_levone_ndx = 0; 2000 0 stevel aw->aw_levtwo_ndx = 0; 2001 0 stevel 2002 0 stevel mdb_vread(aw->aw_levone, aw->aw_nlevone * sizeof (uintptr_t), 2003 0 stevel (uintptr_t)aw->aw_ahp.array_chunk); 2004 0 stevel 2005 0 stevel if (aw->aw_levtwo != NULL) { 2006 0 stevel while (aw->aw_levone[aw->aw_levone_ndx] == NULL) { 2007 0 stevel aw->aw_levone_ndx++; 2008 0 stevel if (aw->aw_levone_ndx == aw->aw_nlevone) { 2009 0 stevel mdb_warn("corrupt anon; couldn't" 2010 0 stevel "find ptr to lev two map"); 2011 0 stevel goto out; 2012 0 stevel } 2013 0 stevel } 2014 0 stevel 2015 0 stevel mdb_vread(aw->aw_levtwo, ANON_CHUNK_SIZE * sizeof (uintptr_t), 2016 0 stevel aw->aw_levone[aw->aw_levone_ndx]); 2017 0 stevel } 2018 0 stevel 2019 0 stevel out: 2020 0 stevel wsp->walk_data = aw; 2021 0 stevel return (0); 2022 0 stevel } 2023 0 stevel 2024 0 stevel int 2025 0 stevel anon_walk_step(mdb_walk_state_t *wsp) 2026 0 stevel { 2027 0 stevel int status; 2028 0 stevel anon_walk_data_t *aw = (anon_walk_data_t *)wsp->walk_data; 2029 0 stevel struct anon anon; 2030 0 stevel uintptr_t anonptr; 2031 0 stevel 2032 0 stevel again: 2033 0 stevel /* 2034 0 stevel * Once we've walked through level one, we're done. 2035 0 stevel */ 2036 0 stevel if (aw->aw_levone_ndx == aw->aw_nlevone) 2037 0 stevel return (WALK_DONE); 2038 0 stevel 2039 0 stevel if (aw->aw_levtwo == NULL) { 2040 0 stevel anonptr = aw->aw_levone[aw->aw_levone_ndx]; 2041 0 stevel aw->aw_levone_ndx++; 2042 0 stevel } else { 2043 0 stevel anonptr = aw->aw_levtwo[aw->aw_levtwo_ndx]; 2044 0 stevel aw->aw_levtwo_ndx++; 2045 0 stevel 2046 0 stevel if (aw->aw_levtwo_ndx == ANON_CHUNK_SIZE) { 2047 0 stevel aw->aw_levtwo_ndx = 0; 2048 0 stevel 2049 0 stevel do { 2050 0 stevel aw->aw_levone_ndx++; 2051 0 stevel 2052 0 stevel if (aw->aw_levone_ndx == aw->aw_nlevone) 2053 0 stevel return (WALK_DONE); 2054 0 stevel } while (aw->aw_levone[aw->aw_levone_ndx] == NULL); 2055 0 stevel 2056 0 stevel mdb_vread(aw->aw_levtwo, ANON_CHUNK_SIZE * 2057 0 stevel sizeof (uintptr_t), 2058 0 stevel aw->aw_levone[aw->aw_levone_ndx]); 2059 0 stevel } 2060 0 stevel } 2061 0 stevel 2062 0 stevel if (anonptr != NULL) { 2063 0 stevel mdb_vread(&anon, sizeof (anon), anonptr); 2064 0 stevel status = wsp->walk_callback(anonptr, &anon, wsp->walk_cbdata); 2065 0 stevel } else 2066 0 stevel goto again; 2067 0 stevel 2068 0 stevel return (status); 2069 0 stevel } 2070 0 stevel 2071 0 stevel void 2072 0 stevel anon_walk_fini(mdb_walk_state_t *wsp) 2073 0 stevel { 2074 0 stevel anon_walk_data_t *aw = (anon_walk_data_t *)wsp->walk_data; 2075 0 stevel 2076 0 stevel if (aw->aw_levtwo != NULL) 2077 0 stevel mdb_free(aw->aw_levtwo, ANON_CHUNK_SIZE * sizeof (uintptr_t)); 2078 0 stevel 2079 0 stevel mdb_free(aw->aw_levone, aw->aw_nlevone * sizeof (uintptr_t)); 2080 0 stevel mdb_free(aw, sizeof (anon_walk_data_t)); 2081 0 stevel } 2082 0 stevel 2083 0 stevel /*ARGSUSED*/ 2084 0 stevel int 2085 0 stevel whereopen_fwalk(uintptr_t addr, struct file *f, uintptr_t *target) 2086 0 stevel { 2087 0 stevel if ((uintptr_t)f->f_vnode == *target) { 2088 0 stevel mdb_printf("file %p\n", addr); 2089 0 stevel *target = NULL; 2090 0 stevel } 2091 0 stevel 2092 0 stevel return (WALK_NEXT); 2093 0 stevel } 2094 0 stevel 2095 0 stevel /*ARGSUSED*/ 2096 0 stevel int 2097 0 stevel whereopen_pwalk(uintptr_t addr, void *ignored, uintptr_t *target) 2098 0 stevel { 2099 0 stevel uintptr_t t = *target; 2100 0 stevel 2101 0 stevel if (mdb_pwalk("file", (mdb_walk_cb_t)whereopen_fwalk, &t, addr) == -1) { 2102 0 stevel mdb_warn("couldn't file walk proc %p", addr); 2103 0 stevel return (WALK_ERR); 2104 0 stevel } 2105 0 stevel 2106 0 stevel if (t == NULL) 2107 0 stevel mdb_printf("%p\n", addr); 2108 0 stevel 2109 0 stevel return (WALK_NEXT); 2110 0 stevel } 2111 0 stevel 2112 0 stevel /*ARGSUSED*/ 2113 0 stevel int 2114 0 stevel whereopen(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2115 0 stevel { 2116 0 stevel uintptr_t target = addr; 2117 0 stevel 2118 0 stevel if (!(flags & DCMD_ADDRSPEC) || addr == NULL) 2119 0 stevel return (DCMD_USAGE); 2120 0 stevel 2121 0 stevel if (mdb_walk("proc", (mdb_walk_cb_t)whereopen_pwalk, &target) == -1) { 2122 0 stevel mdb_warn("can't proc walk"); 2123 0 stevel return (DCMD_ERR); 2124 0 stevel } 2125 0 stevel 2126 0 stevel return (DCMD_OK); 2127 0 stevel } 2128 0 stevel 2129 0 stevel typedef struct datafmt { 2130 0 stevel char *hdr1; 2131 0 stevel char *hdr2; 2132 0 stevel char *dashes; 2133 0 stevel char *fmt; 2134 0 stevel } datafmt_t; 2135 0 stevel 2136 0 stevel static datafmt_t kmemfmt[] = { 2137 0 stevel { "cache ", "name ", 2138 0 stevel "-------------------------", "%-25s " }, 2139 0 stevel { " buf", " size", "------", "%6u " }, 2140 0 stevel { " buf", "in use", "------", "%6u " }, 2141 0 stevel { " buf", " total", "------", "%6u " }, 2142 4808 ek110237 { " memory", " in use", "----------", "%9u%c " }, 2143 0 stevel { " alloc", " succeed", "---------", "%9u " }, 2144 0 stevel { "alloc", " fail", "-----", "%5u " }, 2145 0 stevel { NULL, NULL, NULL, NULL } 2146 0 stevel }; 2147 0 stevel 2148 0 stevel static datafmt_t vmemfmt[] = { 2149 0 stevel { "vmem ", "name ", 2150 0 stevel "-------------------------", "%-*s " }, 2151 4808 ek110237 { " memory", " in use", "----------", "%9llu%c " }, 2152 4808 ek110237 { " memory", " total", "-----------", "%10llu%c " }, 2153 4808 ek110237 { " memory", " import", "----------", "%9llu%c " }, 2154 0 stevel { " alloc", " succeed", "---------", "%9llu " }, 2155 0 stevel { "alloc", " fail", "-----", "%5llu " }, 2156 0 stevel { NULL, NULL, NULL, NULL } 2157 0 stevel }; 2158 0 stevel 2159 0 stevel /*ARGSUSED*/ 2160 0 stevel static int 2161 0 stevel kmastat_cpu_avail(uintptr_t addr, const kmem_cpu_cache_t *ccp, int *avail) 2162 0 stevel { 2163 11178 Dave short rounds, prounds; 2164 11178 Dave 2165 11178 Dave if (KMEM_DUMPCC(ccp)) { 2166 11178 Dave rounds = ccp->cc_dump_rounds; 2167 11178 Dave prounds = ccp->cc_dump_prounds; 2168 11178 Dave } else { 2169 11178 Dave rounds = ccp->cc_rounds; 2170 11178 Dave prounds = ccp->cc_prounds; 2171 11178 Dave } 2172 11178 Dave if (rounds > 0) 2173 11178 Dave *avail += rounds; 2174 11178 Dave if (prounds > 0) 2175 11178 Dave *avail += prounds; 2176 0 stevel 2177 0 stevel return (WALK_NEXT); 2178 0 stevel } 2179 0 stevel 2180 0 stevel /*ARGSUSED*/ 2181 0 stevel static int 2182 0 stevel kmastat_cpu_alloc(uintptr_t addr, const kmem_cpu_cache_t *ccp, int *alloc) 2183 0 stevel { 2184 0 stevel *alloc += ccp->cc_alloc; 2185 0 stevel 2186 0 stevel return (WALK_NEXT); 2187 0 stevel } 2188 0 stevel 2189 0 stevel /*ARGSUSED*/ 2190 0 stevel static int 2191 0 stevel kmastat_slab_avail(uintptr_t addr, const kmem_slab_t *sp, int *avail) 2192 0 stevel { 2193 0 stevel *avail += sp->slab_chunks - sp->slab_refcnt; 2194 0 stevel 2195 0 stevel return (WALK_NEXT); 2196 0 stevel } 2197 0 stevel 2198 0 stevel typedef struct kmastat_vmem { 2199 0 stevel uintptr_t kv_addr; 2200 0 stevel struct kmastat_vmem *kv_next; 2201 0 stevel int kv_meminuse; 2202 0 stevel int kv_alloc; 2203 0 stevel int kv_fail; 2204 0 stevel } kmastat_vmem_t; 2205 0 stevel 2206 3095 ek110237 typedef struct kmastat_args { 2207 3095 ek110237 kmastat_vmem_t **ka_kvpp; 2208 3095 ek110237 uint_t ka_shift; 2209 3095 ek110237 } kmastat_args_t; 2210 3095 ek110237 2211 0 stevel static int 2212 3095 ek110237 kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_args_t *kap) 2213 0 stevel { 2214 11185 Sean kmastat_vmem_t **kvpp = kap->ka_kvpp; 2215 0 stevel kmastat_vmem_t *kv; 2216 0 stevel datafmt_t *dfp = kmemfmt; 2217 0 stevel int magsize; 2218 0 stevel 2219 0 stevel int avail, alloc, total; 2220 0 stevel size_t meminuse = (cp->cache_slab_create - cp->cache_slab_destroy) * 2221 0 stevel cp->cache_slabsize; 2222 0 stevel 2223 0 stevel mdb_walk_cb_t cpu_avail = (mdb_walk_cb_t)kmastat_cpu_avail; 2224 0 stevel mdb_walk_cb_t cpu_alloc = (mdb_walk_cb_t)kmastat_cpu_alloc; 2225 0 stevel mdb_walk_cb_t slab_avail = (mdb_walk_cb_t)kmastat_slab_avail; 2226 0 stevel 2227 0 stevel magsize = kmem_get_magsize(cp); 2228 0 stevel 2229 0 stevel alloc = cp->cache_slab_alloc + cp->cache_full.ml_alloc; 2230 0 stevel avail = cp->cache_full.ml_total * magsize; 2231 0 stevel total = cp->cache_buftotal; 2232 0 stevel 2233 0 stevel (void) mdb_pwalk("kmem_cpu_cache", cpu_alloc, &alloc, addr); 2234 0 stevel (void) mdb_pwalk("kmem_cpu_cache", cpu_avail, &avail, addr); 2235 0 stevel (void) mdb_pwalk("kmem_slab_partial", slab_avail, &avail, addr); 2236 0 stevel 2237 11185 Sean for (kv = *kvpp; kv != NULL; kv = kv->kv_next) { 2238 0 stevel if (kv->kv_addr == (uintptr_t)cp->cache_arena) 2239 0 stevel goto out; 2240 0 stevel } 2241 0 stevel 2242 0 stevel kv = mdb_zalloc(sizeof (kmastat_vmem_t), UM_SLEEP | UM_GC); 2243 11185 Sean kv->kv_next = *kvpp; 2244 0 stevel kv->kv_addr = (uintptr_t)cp->cache_arena; 2245 11185 Sean *kvpp = kv; 2246 0 stevel out: 2247 0 stevel kv->kv_meminuse += meminuse; 2248 0 stevel kv->kv_alloc += alloc; 2249 0 stevel kv->kv_fail += cp->cache_alloc_fail; 2250 0 stevel 2251 0 stevel mdb_printf((dfp++)->fmt, cp->cache_name); 2252 0 stevel mdb_printf((dfp++)->fmt, cp->cache_bufsize); 2253 0 stevel mdb_printf((dfp++)->fmt, total - avail); 2254 0 stevel mdb_printf((dfp++)->fmt, total); 2255 4808 ek110237 mdb_printf((dfp++)->fmt, meminuse >> kap->ka_shift, 2256 4808 ek110237 kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' : 2257 4808 ek110237 kap->ka_shift == KILOS ? 'K' : 'B'); 2258 0 stevel mdb_printf((dfp++)->fmt, alloc); 2259 0 stevel mdb_printf((dfp++)->fmt, cp->cache_alloc_fail); 2260 0 stevel mdb_printf("\n"); 2261 0 stevel 2262 0 stevel return (WALK_NEXT); 2263 0 stevel } 2264 0 stevel 2265 0 stevel static int 2266 3095 ek110237 kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap) 2267 0 stevel { 2268 3095 ek110237 kmastat_vmem_t *kv = *kap->ka_kvpp; 2269 0 stevel size_t len; 2270 0 stevel 2271 0 stevel while (kv != NULL && kv->kv_addr != addr) 2272 0 stevel kv = kv->kv_next; 2273 0 stevel 2274 0 stevel if (kv == NULL || kv->kv_alloc == 0) 2275 0 stevel return (WALK_NEXT); 2276 0 stevel 2277 0 stevel len = MIN(17, strlen(v->vm_name)); 2278 0 stevel 2279 4808 ek110237 mdb_printf("Total [%s]%*s %6s %6s %6s %9u%c %9u %5u\n", v->vm_name, 2280 0 stevel 17 - len, "", "", "", "", 2281 4808 ek110237 kv->kv_meminuse >> kap->ka_shift, 2282 4808 ek110237 kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' : 2283 4808 ek110237 kap->ka_shift == KILOS ? 'K' : 'B', kv->kv_alloc, kv->kv_fail); 2284 0 stevel 2285 0 stevel return (WALK_NEXT); 2286 0 stevel } 2287 0 stevel 2288 0 stevel /*ARGSUSED*/ 2289 0 stevel static int 2290 3095 ek110237 kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp) 2291 0 stevel { 2292 0 stevel datafmt_t *dfp = vmemfmt; 2293 0 stevel const vmem_kstat_t *vkp = &v->vm_kstat; 2294 0 stevel uintptr_t paddr; 2295 0 stevel vmem_t parent; 2296 0 stevel int ident = 0; 2297 0 stevel 2298 0 stevel for (paddr = (uintptr_t)v->vm_source; paddr != NULL; ident += 4) { 2299 0 stevel if (mdb_vread(&parent, sizeof (parent), paddr) == -1) { 2300 0 stevel mdb_warn("couldn't trace %p's ancestry", addr); 2301 0 stevel ident = 0; 2302 0 stevel break; 2303 0 stevel } 2304 0 stevel paddr = (uintptr_t)parent.vm_source; 2305 0 stevel } 2306 0 stevel 2307 0 stevel mdb_printf("%*s", ident, ""); 2308 0 stevel mdb_printf((dfp++)->fmt, 25 - ident, v->vm_name); 2309 4808 ek110237 mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64 >> *shiftp, 2310 4808 ek110237 *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' : 2311 4808 ek110237 *shiftp == KILOS ? 'K' : 'B'); 2312 4808 ek110237 mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64 >> *shiftp, 2313 4808 ek110237 *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' : 2314 4808 ek110237 *shiftp == KILOS ? 'K' : 'B'); 2315 4808 ek110237 mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64 >> *shiftp, 2316 4808 ek110237 *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' : 2317 4808 ek110237 *shiftp == KILOS ? 'K' : 'B'); 2318 0 stevel mdb_printf((dfp++)->fmt, vkp->vk_alloc.value.ui64); 2319 0 stevel mdb_printf((dfp++)->fmt, vkp->vk_fail.value.ui64); 2320 0 stevel 2321 0 stevel mdb_printf("\n"); 2322 0 stevel 2323 0 stevel return (WALK_NEXT); 2324 0 stevel } 2325 0 stevel 2326 0 stevel /*ARGSUSED*/ 2327 0 stevel int 2328 0 stevel kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2329 0 stevel { 2330 0 stevel kmastat_vmem_t *kv = NULL; 2331 0 stevel datafmt_t *dfp; 2332 3095 ek110237 kmastat_args_t ka; 2333 0 stevel 2334 3095 ek110237 ka.ka_shift = 0; 2335 3095 ek110237 if (mdb_getopts(argc, argv, 2336 4808 ek110237 'k', MDB_OPT_SETBITS, KILOS, &ka.ka_shift, 2337 4808 ek110237 'm', MDB_OPT_SETBITS, MEGS, &ka.ka_shift, 2338 4808 ek110237 'g', MDB_OPT_SETBITS, GIGS, &ka.ka_shift, NULL) != argc) 2339 0 stevel return (DCMD_USAGE); 2340 0 stevel 2341 0 stevel for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) 2342 0 stevel mdb_printf("%s ", dfp->hdr1); 2343 0 stevel mdb_printf("\n"); 2344 0 stevel 2345 0 stevel for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) 2346 0 stevel mdb_printf("%s ", dfp->hdr2); 2347 0 stevel mdb_printf("\n"); 2348 0 stevel 2349 0 stevel for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) 2350 0 stevel mdb_printf("%s ", dfp->dashes); 2351 0 stevel mdb_printf("\n"); 2352 0 stevel 2353 3095 ek110237 ka.ka_kvpp = &kv; 2354 3095 ek110237 if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &ka) == -1) { 2355 0 stevel mdb_warn("can't walk 'kmem_cache'"); 2356 0 stevel return (DCMD_ERR); 2357 0 stevel } 2358 0 stevel 2359 0 stevel for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) 2360 0 stevel mdb_printf("%s ", dfp->dashes); 2361 0 stevel mdb_printf("\n"); 2362 0 stevel 2363 3095 ek110237 if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, &ka) == -1) { 2364 0 stevel mdb_warn("can't walk 'vmem'"); 2365 0 stevel return (DCMD_ERR); 2366 0 stevel } 2367 0 stevel 2368 0 stevel for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) 2369 0 stevel mdb_printf("%s ", dfp->dashes); 2370 0 stevel mdb_printf("\n"); 2371 0 stevel 2372 0 stevel mdb_printf("\n"); 2373 0 stevel 2374 0 stevel for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++) 2375 0 stevel mdb_printf("%s ", dfp->hdr1); 2376 0 stevel mdb_printf("\n"); 2377 0 stevel 2378 0 stevel for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++) 2379 0 stevel mdb_printf("%s ", dfp->hdr2); 2380 0 stevel mdb_printf("\n"); 2381 0 stevel 2382 0 stevel for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++) 2383 0 stevel mdb_printf("%s ", dfp->dashes); 2384 0 stevel mdb_printf("\n"); 2385 0 stevel 2386 3095 ek110237 if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, &ka.ka_shift) == -1) { 2387 0 stevel mdb_warn("can't walk 'vmem'"); 2388 0 stevel return (DCMD_ERR); 2389 0 stevel } 2390 0 stevel 2391 0 stevel for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++) 2392 0 stevel mdb_printf("%s ", dfp->dashes); 2393 0 stevel mdb_printf("\n"); 2394 0 stevel return (DCMD_OK); 2395 0 stevel } 2396 0 stevel 2397 0 stevel /* 2398 0 stevel * Our ::kgrep callback scans the entire kernel VA space (kas). kas is made 2399 0 stevel * up of a set of 'struct seg's. We could just scan each seg en masse, but 2400 0 stevel * unfortunately, a few of the segs are both large and sparse, so we could 2401 0 stevel * spend quite a bit of time scanning VAs which have no backing pages. 2402 0 stevel * 2403 0 stevel * So for the few very sparse segs, we skip the segment itself, and scan 2404 0 stevel * the allocated vmem_segs in the vmem arena which manages that part of kas. 2405 0 stevel * Currently, we do this for: 2406 0 stevel * 2407 0 stevel * SEG VMEM ARENA 2408 0 stevel * kvseg heap_arena 2409 0 stevel * kvseg32 heap32_arena 2410 0 stevel * kvseg_core heap_core_arena 2411 0 stevel * 2412 0 stevel * In addition, we skip the segkpm segment in its entirety, since it is very 2413 0 stevel * sparse, and contains no new kernel data. 2414 0 stevel */ 2415 0 stevel typedef struct kgrep_walk_data { 2416 0 stevel kgrep_cb_func *kg_cb; 2417 0 stevel void *kg_cbdata; 2418 0 stevel uintptr_t kg_kvseg; 2419 0 stevel uintptr_t kg_kvseg32; 2420 0 stevel uintptr_t kg_kvseg_core; 2421 0 stevel uintptr_t kg_segkpm; 2422 5 eg155566 uintptr_t kg_heap_lp_base; 2423 5 eg155566 uintptr_t kg_heap_lp_end; 2424 0 stevel } kgrep_walk_data_t; 2425 0 stevel 2426 0 stevel static int 2427 0 stevel kgrep_walk_seg(uintptr_t addr, const struct seg *seg, kgrep_walk_data_t *kg) 2428 0 stevel { 2429 0 stevel uintptr_t base = (uintptr_t)seg->s_base; 2430 0 stevel 2431 0 stevel if (addr == kg->kg_kvseg || addr == kg->kg_kvseg32 || 2432 0 stevel addr == kg->kg_kvseg_core) 2433 0 stevel return (WALK_NEXT); 2434 0 stevel 2435 0 stevel if ((uintptr_t)seg->s_ops == kg->kg_segkpm) 2436 0 stevel return (WALK_NEXT); 2437 0 stevel 2438 0 stevel return (kg->kg_cb(base, base + seg->s_size, kg->kg_cbdata)); 2439 0 stevel } 2440 0 stevel 2441 0 stevel /*ARGSUSED*/ 2442 0 stevel static int 2443 0 stevel kgrep_walk_vseg(uintptr_t addr, const vmem_seg_t *seg, kgrep_walk_data_t *kg) 2444 0 stevel { 2445 5 eg155566 /* 2446 5 eg155566 * skip large page heap address range - it is scanned by walking 2447 5 eg155566 * allocated vmem_segs in the heap_lp_arena 2448 5 eg155566 */ 2449 5 eg155566 if (seg->vs_start == kg->kg_heap_lp_base && 2450 5 eg155566 seg->vs_end == kg->kg_heap_lp_end) 2451 5 eg155566 return (WALK_NEXT); 2452 5 eg155566 2453 5 eg155566 return (kg->kg_cb(seg->vs_start, seg->vs_end, kg->kg_cbdata)); 2454 5 eg155566 } 2455 5 eg155566 2456 5 eg155566 /*ARGSUSED*/ 2457 5 eg155566 static int 2458 5 eg155566 kgrep_xwalk_vseg(uintptr_t addr, const vmem_seg_t *seg, kgrep_walk_data_t *kg) 2459 5 eg155566 { 2460 0 stevel return (kg->kg_cb(seg->vs_start, seg->vs_end, kg->kg_cbdata)); 2461 0 stevel } 2462 0 stevel 2463 0 stevel static int 2464 0 stevel kgrep_walk_vmem(uintptr_t addr, const vmem_t *vmem, kgrep_walk_data_t *kg) 2465 0 stevel { 2466 5 eg155566 mdb_walk_cb_t walk_vseg = (mdb_walk_cb_t)kgrep_walk_vseg; 2467 5 eg155566 2468 0 stevel if (strcmp(vmem->vm_name, "heap") != 0 && 2469 0 stevel strcmp(vmem->vm_name, "heap32") != 0 && 2470 5 eg155566 strcmp(vmem->vm_name, "heap_core") != 0 && 2471 5 eg155566 strcmp(vmem->vm_name, "heap_lp") != 0) 2472 0 stevel return (WALK_NEXT); 2473 0 stevel 2474 5 eg155566 if (strcmp(vmem->vm_name, "heap_lp") == 0) 2475 5 eg155566 walk_vseg = (mdb_walk_cb_t)kgrep_xwalk_vseg; 2476 5 eg155566 2477 5 eg155566 if (mdb_pwalk("vmem_alloc", walk_vseg, kg, addr) == -1) { 2478 0 stevel mdb_warn("couldn't walk vmem_alloc for vmem %p", addr); 2479 0 stevel return (WALK_ERR); 2480 0 stevel } 2481 0 stevel 2482 0 stevel return (WALK_NEXT); 2483 0 stevel } 2484 0 stevel 2485 0 stevel int 2486 0 stevel kgrep_subr(kgrep_cb_func *cb, void *cbdata) 2487 0 stevel { 2488 0 stevel GElf_Sym kas, kvseg, kvseg32, kvseg_core, segkpm; 2489 0 stevel kgrep_walk_data_t kg; 2490 0 stevel 2491 0 stevel if (mdb_get_state() == MDB_STATE_RUNNING) { 2492 0 stevel mdb_warn("kgrep can only be run on a system " 2493 0 stevel "dump or under kmdb; see dumpadm(1M)\n"); 2494 0 stevel return (DCMD_ERR); 2495 0 stevel } 2496 0 stevel 2497 0 stevel if (mdb_lookup_by_name("kas", &kas) == -1) { 2498 0 stevel mdb_warn("failed to locate 'kas' symbol\n"); 2499 0 stevel return (DCMD_ERR); 2500 0 stevel } 2501 0 stevel 2502 0 stevel if (mdb_lookup_by_name("kvseg", &kvseg) == -1) { 2503 0 stevel mdb_warn("failed to locate 'kvseg' symbol\n"); 2504 0 stevel return (DCMD_ERR); 2505 0 stevel } 2506 0 stevel 2507 0 stevel if (mdb_lookup_by_name("kvseg32", &kvseg32) == -1) { 2508 0 stevel mdb_warn("failed to locate 'kvseg32' symbol\n"); 2509 0 stevel return (DCMD_ERR); 2510 0 stevel } 2511 0 stevel 2512 0 stevel if (mdb_lookup_by_name("kvseg_core", &kvseg_core) == -1) { 2513 0 stevel mdb_warn("failed to locate 'kvseg_core' symbol\n"); 2514 0 stevel return (DCMD_ERR); 2515 0 stevel } 2516 0 stevel 2517 0 stevel if (mdb_lookup_by_name("segkpm_ops", &segkpm) == -1) { 2518 0 stevel mdb_warn("failed to locate 'segkpm_ops' symbol\n"); 2519 5 eg155566 return (DCMD_ERR); 2520 5 eg155566 } 2521 5 eg155566 2522 5 eg155566 if (mdb_readvar(&kg.kg_heap_lp_base, "heap_lp_base") == -1) { 2523 5 eg155566 mdb_warn("failed to read 'heap_lp_base'\n"); 2524 5 eg155566 return (DCMD_ERR); 2525 5 eg155566 } 2526 5 eg155566 2527 5 eg155566 if (mdb_readvar(&kg.kg_heap_lp_end, "heap_lp_end") == -1) { 2528 5 eg155566 mdb_warn("failed to read 'heap_lp_end'\n"); 2529 0 stevel return (DCMD_ERR); 2530 0 stevel } 2531 0 stevel 2532 0 stevel kg.kg_cb = cb; 2533 0 stevel kg.kg_cbdata = cbdata; 2534 0 stevel kg.kg_kvseg = (uintptr_t)kvseg.st_value; 2535 0 stevel kg.kg_kvseg32 = (uintptr_t)kvseg32.st_value; 2536 0 stevel kg.kg_kvseg_core = (uintptr_t)kvseg_core.st_value; 2537 0 stevel kg.kg_segkpm = (uintptr_t)segkpm.st_value; 2538 0 stevel 2539 0 stevel if (mdb_pwalk("seg", (mdb_walk_cb_t)kgrep_walk_seg, 2540 0 stevel &kg, kas.st_value) == -1) { 2541 0 stevel mdb_warn("failed to walk kas segments"); 2542 0 stevel return (DCMD_ERR); 2543 0 stevel } 2544 0 stevel 2545 0 stevel if (mdb_walk("vmem", (mdb_walk_cb_t)kgrep_walk_vmem, &kg) == -1) { 2546 0 stevel mdb_warn("failed to walk heap/heap32 vmem arenas"); 2547 0 stevel return (DCMD_ERR); 2548 0 stevel } 2549 0 stevel 2550 0 stevel return (DCMD_OK); 2551 0 stevel } 2552 0 stevel 2553 0 stevel size_t 2554 0 stevel kgrep_subr_pagesize(void) 2555 0 stevel { 2556 0 stevel return (PAGESIZE); 2557 0 stevel } 2558 0 stevel 2559 0 stevel typedef struct file_walk_data { 2560 0 stevel struct uf_entry *fw_flist; 2561 0 stevel int fw_flistsz; 2562 0 stevel int fw_ndx; 2563 0 stevel int fw_nofiles; 2564 0 stevel } file_walk_data_t; 2565 0 stevel 2566 0 stevel int 2567 0 stevel file_walk_init(mdb_walk_state_t *wsp) 2568 0 stevel { 2569 0 stevel file_walk_data_t *fw; 2570 0 stevel proc_t p; 2571 0 stevel 2572 0 stevel if (wsp->walk_addr == NULL) { 2573 0 stevel mdb_warn("file walk doesn't support global walks\n"); 2574 0 stevel return (WALK_ERR); 2575 0 stevel } 2576 0 stevel 2577 0 stevel fw = mdb_alloc(sizeof (file_walk_data_t), UM_SLEEP); 2578 0 stevel 2579 0 stevel if (mdb_vread(&p, sizeof (p), wsp->walk_addr) == -1) { 2580 0 stevel mdb_free(fw, sizeof (file_walk_data_t)); 2581 0 stevel mdb_warn("failed to read proc structure at %p", wsp->walk_addr); 2582 0 stevel return (WALK_ERR); 2583 0 stevel } 2584 0 stevel 2585 0 stevel if (p.p_user.u_finfo.fi_nfiles == 0) { 2586 0 stevel mdb_free(fw, sizeof (file_walk_data_t)); 2587 0 stevel return (WALK_DONE); 2588 0 stevel } 2589 0 stevel 2590 0 stevel fw->fw_nofiles = p.p_user.u_finfo.fi_nfiles; 2591 0 stevel fw->fw_flistsz = sizeof (struct uf_entry) * fw->fw_nofiles; 2592 0 stevel fw->fw_flist = mdb_alloc(fw->fw_flistsz, UM_SLEEP); 2593 0 stevel 2594 0 stevel if (mdb_vread(fw->fw_flist, fw->fw_flistsz, 2595 0 stevel (uintptr_t)p.p_user.u_finfo.fi_list) == -1) { 2596 0 stevel mdb_warn("failed to read file array at %p", 2597 0 stevel p.p_user.u_finfo.fi_list); 2598 0 stevel mdb_free(fw->fw_flist, fw->fw_flistsz); 2599 0 stevel mdb_free(fw, sizeof (file_walk_data_t)); 2600 0 stevel return (WALK_ERR); 2601 0 stevel } 2602 0 stevel 2603 0 stevel fw->fw_ndx = 0; 2604 0 stevel wsp->walk_data = fw; 2605 0 stevel 2606 0 stevel return (WALK_NEXT); 2607 0 stevel } 2608 0 stevel 2609 0 stevel int 2610 0 stevel file_walk_step(mdb_walk_state_t *wsp) 2611 0 stevel { 2612 0 stevel file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data; 2613 0 stevel struct file file; 2614 0 stevel uintptr_t fp; 2615 0 stevel 2616 0 stevel again: 2617 0 stevel if (fw->fw_ndx == fw->fw_nofiles) 2618 0 stevel return (WALK_DONE); 2619 0 stevel 2620 0 stevel if ((fp = (uintptr_t)fw->fw_flist[fw->fw_ndx++].uf_file) == NULL) 2621 0 stevel goto again; 2622 0 stevel 2623 0 stevel (void) mdb_vread(&file, sizeof (file), (uintptr_t)fp); 2624 0 stevel return (wsp->walk_callback(fp, &file, wsp->walk_cbdata)); 2625 0 stevel } 2626 0 stevel 2627 0 stevel int 2628 0 stevel allfile_walk_step(mdb_walk_state_t *wsp) 2629 0 stevel { 2630 0 stevel file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data; 2631 0 stevel struct file file; 2632 0 stevel uintptr_t fp; 2633 0 stevel 2634 0 stevel if (fw->fw_ndx == fw->fw_nofiles) 2635 0 stevel return (WALK_DONE); 2636 0 stevel 2637 0 stevel if ((fp = (uintptr_t)fw->fw_flist[fw->fw_ndx++].uf_file) != NULL) 2638 0 stevel (void) mdb_vread(&file, sizeof (file), (uintptr_t)fp); 2639 0 stevel else 2640 0 stevel bzero(&file, sizeof (file)); 2641 0 stevel 2642 0 stevel return (wsp->walk_callback(fp, &file, wsp->walk_cbdata)); 2643 0 stevel } 2644 0 stevel 2645 0 stevel void 2646 0 stevel file_walk_fini(mdb_walk_state_t *wsp) 2647 0 stevel { 2648 0 stevel file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data; 2649 0 stevel 2650 0 stevel mdb_free(fw->fw_flist, fw->fw_flistsz); 2651 0 stevel mdb_free(fw, sizeof (file_walk_data_t)); 2652 0 stevel } 2653 0 stevel 2654 0 stevel int 2655 0 stevel port_walk_init(mdb_walk_state_t *wsp) 2656 0 stevel { 2657 0 stevel if (wsp->walk_addr == NULL) { 2658 0 stevel mdb_warn("port walk doesn't support global walks\n"); 2659 0 stevel return (WALK_ERR); 2660 0 stevel } 2661 0 stevel 2662 0 stevel if (mdb_layered_walk("file", wsp) == -1) { 2663 0 stevel mdb_warn("couldn't walk 'file'"); 2664 0 stevel return (WALK_ERR); 2665 0 stevel } 2666 0 stevel return (WALK_NEXT); 2667 0 stevel } 2668 0 stevel 2669 0 stevel int 2670 0 stevel port_walk_step(mdb_walk_state_t *wsp) 2671 0 stevel { 2672 0 stevel struct vnode vn; 2673 0 stevel uintptr_t vp; 2674 0 stevel uintptr_t pp; 2675 0 stevel struct port port; 2676 0 stevel 2677 0 stevel vp = (uintptr_t)((struct file *)wsp->walk_layer)->f_vnode; 2678 0 stevel if (mdb_vread(&vn, sizeof (vn), vp) == -1) { 2679 0 stevel mdb_warn("failed to read vnode_t at %p", vp); 2680 0 stevel return (WALK_ERR); 2681 0 stevel } 2682 0 stevel if (vn.v_type != VPORT) 2683 0 stevel return (WALK_NEXT); 2684 0 stevel 2685 0 stevel pp = (uintptr_t)vn.v_data; 2686 0 stevel if (mdb_vread(&port, sizeof (port), pp) == -1) { 2687 0 stevel mdb_warn("failed to read port_t at %p", pp); 2688 0 stevel return (WALK_ERR); 2689 0 stevel } 2690 0 stevel return (wsp->walk_callback(pp, &port, wsp->walk_cbdata)); 2691 0 stevel } 2692 0 stevel 2693 0 stevel typedef struct portev_walk_data { 2694 0 stevel list_node_t *pev_node; 2695 0 stevel list_node_t *pev_last; 2696 0 stevel size_t pev_offset; 2697 0 stevel } portev_walk_data_t; 2698 0 stevel 2699 0 stevel int 2700 0 stevel portev_walk_init(mdb_walk_state_t *wsp) 2701 0 stevel { 2702 0 stevel portev_walk_data_t *pevd; 2703 0 stevel struct port port; 2704 0 stevel struct vnode vn; 2705 0 stevel struct list *list; 2706 0 stevel uintptr_t vp; 2707 0 stevel 2708 0 stevel if (wsp->walk_addr == NULL) { 2709 0 stevel mdb_warn("portev walk doesn't support global walks\n"); 2710 0 stevel return (WALK_ERR); 2711 0 stevel } 2712 0 stevel 2713 0 stevel pevd = mdb_alloc(sizeof (portev_walk_data_t), UM_SLEEP); 2714 0 stevel 2715 0 stevel if (mdb_vread(&port, sizeof (port), wsp->walk_addr) == -1) { 2716 0 stevel mdb_free(pevd, sizeof (portev_walk_data_t)); 2717 0 stevel mdb_warn("failed to read port structure at %p", wsp->walk_addr); 2718 0 stevel return (WALK_ERR); 2719 0 stevel } 2720 0 stevel 2721 0 stevel vp = (uintptr_t)port.port_vnode; 2722 0 stevel if (mdb_vread(&vn, sizeof (vn), vp) == -1) { 2723 0 stevel mdb_free(pevd, sizeof (portev_walk_data_t)); 2724 0 stevel mdb_warn("failed to read vnode_t at %p", vp); 2725 0 stevel return (WALK_ERR); 2726 0 stevel } 2727 0 stevel 2728 0 stevel if (vn.v_type != VPORT) { 2729 0 stevel mdb_free(pevd, sizeof (portev_walk_data_t)); 2730 0 stevel mdb_warn("input address (%p) does not point to an event port", 2731 0 stevel wsp->walk_addr); 2732 0 stevel return (WALK_ERR); 2733 0 stevel } 2734 0 stevel 2735 0 stevel if (port.port_queue.portq_nent == 0) { 2736 0 stevel mdb_free(pevd, sizeof (portev_walk_data_t)); 2737 0 stevel return (WALK_DONE); 2738 0 stevel } 2739 0 stevel list = &port.port_queue.portq_list; 2740 0 stevel pevd->pev_offset = list->list_offset; 2741 0 stevel pevd->pev_last = list->list_head.list_prev; 2742 0 stevel pevd->pev_node = list->list_head.list_next; 2743 0 stevel wsp->walk_data = pevd; 2744 0 stevel return (WALK_NEXT); 2745 0 stevel } 2746 0 stevel 2747 0 stevel int 2748 0 stevel portev_walk_step(mdb_walk_state_t *wsp) 2749 0 stevel { 2750 0 stevel portev_walk_data_t *pevd; 2751 0 stevel struct port_kevent ev; 2752 0 stevel uintptr_t evp; 2753 0 stevel 2754 0 stevel pevd = (portev_walk_data_t *)wsp->walk_data; 2755 0 stevel 2756 0 stevel if (pevd->pev_last == NULL) 2757 0 stevel return (WALK_DONE); 2758 0 stevel if (pevd->pev_node == pevd->pev_last) 2759 0 stevel pevd->pev_last = NULL; /* last round */ 2760 0 stevel 2761 0 stevel evp = ((uintptr_t)(((char *)pevd->pev_node) - pevd->pev_offset)); 2762 0 stevel if (mdb_vread(&ev, sizeof (ev), evp) == -1) { 2763 0 stevel mdb_warn("failed to read port_kevent at %p", evp); 2764 0 stevel return (WALK_DONE); 2765 0 stevel } 2766 0 stevel pevd->pev_node = ev.portkev_node.list_next; 2767 0 stevel return (wsp->walk_callback(evp, &ev, wsp->walk_cbdata)); 2768 0 stevel } 2769 0 stevel 2770 0 stevel void 2771 0 stevel portev_walk_fini(mdb_walk_state_t *wsp) 2772 0 stevel { 2773 0 stevel portev_walk_data_t *pevd = (portev_walk_data_t *)wsp->walk_data; 2774 0 stevel 2775 0 stevel if (pevd != NULL) 2776 0 stevel mdb_free(pevd, sizeof (portev_walk_data_t)); 2777 0 stevel } 2778 0 stevel 2779 0 stevel typedef struct proc_walk_data { 2780 0 stevel uintptr_t *pw_stack; 2781 0 stevel int pw_depth; 2782 0 stevel int pw_max; 2783 0 stevel } proc_walk_data_t; 2784 0 stevel 2785 0 stevel int 2786 0 stevel proc_walk_init(mdb_walk_state_t *wsp) 2787 0 stevel { 2788 0 stevel GElf_Sym sym; 2789 0 stevel proc_walk_data_t *pw; 2790 0 stevel 2791 0 stevel if (wsp->walk_addr == NULL) { 2792 0 stevel if (mdb_lookup_by_name("p0", &sym) == -1) { 2793 0 stevel mdb_warn("failed to read 'practive'"); 2794 0 stevel return (WALK_ERR); 2795 0 stevel } 2796 0 stevel wsp->walk_addr = (uintptr_t)sym.st_value; 2797 0 stevel } 2798 0 stevel 2799 0 stevel pw = mdb_zalloc(sizeof (proc_walk_data_t), UM_SLEEP); 2800 0 stevel 2801 0 stevel if (mdb_readvar(&pw->pw_max, "nproc") == -1) { 2802 0 stevel mdb_warn("failed to read 'nproc'"); 2803 0 stevel mdb_free(pw, sizeof (pw)); 2804 0 stevel return (WALK_ERR); 2805 0 stevel } 2806 0 stevel 2807 0 stevel pw->pw_stack = mdb_alloc(pw->pw_max * sizeof (uintptr_t), UM_SLEEP); 2808 0 stevel wsp->walk_data = pw; 2809 0 stevel 2810 0 stevel return (WALK_NEXT); 2811 0 stevel } 2812 0 stevel 2813 0 stevel int 2814 0 stevel proc_walk_step(mdb_walk_state_t *wsp) 2815 0 stevel { 2816 0 stevel proc_walk_data_t *pw = wsp->walk_data; 2817 0 stevel uintptr_t addr = wsp->walk_addr; 2818 0 stevel uintptr_t cld, sib; 2819 0 stevel 2820 0 stevel int status; 2821 0 stevel proc_t pr; 2822 0 stevel 2823 0 stevel if (mdb_vread(&pr, sizeof (proc_t), addr) == -1) { 2824 0 stevel mdb_warn("failed to read proc at %p", addr); 2825 0 stevel return (WALK_DONE); 2826 0 stevel } 2827 0 stevel 2828 0 stevel cld = (uintptr_t)pr.p_child; 2829 0 stevel sib = (uintptr_t)pr.p_sibling; 2830 0 stevel 2831 0 stevel if (pw->pw_depth > 0 && addr == pw->pw_stack[pw->pw_depth - 1]) { 2832 0 stevel pw->pw_depth--; 2833 0 stevel goto sib; 2834 0 stevel } 2835 0 stevel 2836 0 stevel status = wsp->walk_callback(addr, &pr, wsp->walk_cbdata); 2837 0 stevel 2838 0 stevel if (status != WALK_NEXT) 2839 0 stevel return (status); 2840 0 stevel 2841 0 stevel if ((wsp->walk_addr = cld) != NULL) { 2842 0 stevel if (mdb_vread(&pr, sizeof (proc_t), cld) == -1) { 2843 0 stevel mdb_warn("proc %p has invalid p_child %p; skipping\n", 2844 0 stevel addr, cld); 2845 0 stevel goto sib; 2846 0 stevel } 2847 0 stevel 2848 0 stevel pw->pw_stack[pw->pw_depth++] = addr; 2849 0 stevel 2850 0 stevel if (pw->pw_depth == pw->pw_max) { 2851 0 stevel mdb_warn("depth %d exceeds max depth; try again\n", 2852 0 stevel pw->pw_depth); 2853 0 stevel return (WALK_DONE); 2854 0 stevel } 2855 0 stevel return (WALK_NEXT); 2856 0 stevel } 2857 0 stevel 2858 0 stevel sib: 2859 0 stevel /* 2860 0 stevel * We know that p0 has no siblings, and if another starting proc 2861 0 stevel * was given, we don't want to walk its siblings anyway. 2862 0 stevel */ 2863 0 stevel if (pw->pw_depth == 0) 2864 0 stevel return (WALK_DONE); 2865 0 stevel 2866 0 stevel if (sib != NULL && mdb_vread(&pr, sizeof (proc_t), sib) == -1) { 2867 0 stevel mdb_warn("proc %p has invalid p_sibling %p; skipping\n", 2868 0 stevel addr, sib); 2869 0 stevel sib = NULL; 2870 0 stevel } 2871 0 stevel 2872 0 stevel if ((wsp->walk_addr = sib) == NULL) { 2873 0 stevel if (pw->pw_depth > 0) { 2874 0 stevel wsp->walk_addr = pw->pw_stack[pw->pw_depth - 1]; 2875 0 stevel return (WALK_NEXT); 2876 0 stevel } 2877 0 stevel return (WALK_DONE); 2878 0 stevel } 2879 0 stevel 2880 0 stevel return (WALK_NEXT); 2881 0 stevel } 2882 0 stevel 2883 0 stevel void 2884 0 stevel proc_walk_fini(mdb_walk_state_t *wsp) 2885 0 stevel { 2886 0 stevel proc_walk_data_t *pw = wsp->walk_data; 2887 0 stevel 2888 0 stevel mdb_free(pw->pw_stack, pw->pw_max * sizeof (uintptr_t)); 2889 0 stevel mdb_free(pw, sizeof (proc_walk_data_t)); 2890 0 stevel } 2891 0 stevel 2892 0 stevel int 2893 0 stevel task_walk_init(mdb_walk_state_t *wsp) 2894 0 stevel { 2895 0 stevel task_t task; 2896 0 stevel 2897 0 stevel if (mdb_vread(&task, sizeof (task_t), wsp->walk_addr) == -1) { 2898 0 stevel mdb_warn("failed to read task at %p", wsp->walk_addr); 2899 0 stevel return (WALK_ERR); 2900 0 stevel } 2901 0 stevel wsp->walk_addr = (uintptr_t)task.tk_memb_list; 2902 0 stevel wsp->walk_data = task.tk_memb_list; 2903 0 stevel return (WALK_NEXT); 2904 0 stevel } 2905 0 stevel 2906 0 stevel int 2907 0 stevel task_walk_step(mdb_walk_state_t *wsp) 2908 0 stevel { 2909 0 stevel proc_t proc; 2910 0 stevel int status; 2911 0 stevel 2912 0 stevel if (mdb_vread(&proc, sizeof (proc_t), wsp->walk_addr) == -1) { 2913 0 stevel mdb_warn("failed to read proc at %p", wsp->walk_addr); 2914 0 stevel return (WALK_DONE); 2915 0 stevel } 2916 0 stevel 2917 0 stevel status = wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata); 2918 0 stevel 2919 0 stevel if (proc.p_tasknext == wsp->walk_data) 2920 0 stevel return (WALK_DONE); 2921 0 stevel 2922 0 stevel wsp->walk_addr = (uintptr_t)proc.p_tasknext; 2923 0 stevel return (status); 2924 0 stevel } 2925 0 stevel 2926 0 stevel int 2927 0 stevel project_walk_init(mdb_walk_state_t *wsp) 2928 0 stevel { 2929 0 stevel if (wsp->walk_addr == NULL) { 2930 0 stevel if (mdb_readvar(&wsp->walk_addr, "proj0p") == -1) { 2931 0 stevel mdb_warn("failed to read 'proj0p'"); 2932 0 stevel return (WALK_ERR); 2933 0 stevel } 2934 0 stevel } 2935 0 stevel wsp->walk_data = (void *)wsp->walk_addr; 2936 0 stevel return (WALK_NEXT); 2937 0 stevel } 2938 0 stevel 2939 0 stevel int 2940 0 stevel project_walk_step(mdb_walk_state_t *wsp) 2941 0 stevel { 2942 0 stevel uintptr_t addr = wsp->