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 2116 anish * Common Development and Distribution License (the "License"). 6 2116 anish * 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 9073 Cathy * 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 /* 27 0 stevel * Mdb kernel support module. This module is loaded automatically when the 28 0 stevel * kvm target is initialized. Any global functions declared here are exported 29 0 stevel * for the resolution of symbols in subsequently loaded modules. 30 0 stevel * 31 0 stevel * WARNING: Do not assume that static variables in mdb_ks will be initialized 32 0 stevel * to zero. 33 0 stevel */ 34 0 stevel 35 0 stevel 36 0 stevel #include <mdb/mdb_target.h> 37 0 stevel #include <mdb/mdb_param.h> 38 0 stevel #include <mdb/mdb_modapi.h> 39 0 stevel #include <mdb/mdb_ks.h> 40 0 stevel 41 0 stevel #include <sys/types.h> 42 0 stevel #include <sys/procfs.h> 43 0 stevel #include <sys/proc.h> 44 0 stevel #include <sys/dnlc.h> 45 0 stevel #include <sys/autoconf.h> 46 0 stevel #include <sys/machelf.h> 47 0 stevel #include <sys/modctl.h> 48 0 stevel #include <sys/hwconf.h> 49 0 stevel #include <sys/kobj.h> 50 0 stevel #include <sys/fs/autofs.h> 51 0 stevel #include <sys/ddi_impldefs.h> 52 0 stevel #include <sys/refstr_impl.h> 53 1234 johnlev #include <sys/cpuvar.h> 54 2546 carlsonj #include <sys/dlpi.h> 55 11066 rafael #include <sys/clock_impl.h> 56 0 stevel #include <errno.h> 57 0 stevel 58 0 stevel #include <vm/seg_vn.h> 59 0 stevel #include <vm/page.h> 60 0 stevel 61 0 stevel #define MDB_PATH_NELEM 256 /* Maximum path components */ 62 0 stevel 63 0 stevel typedef struct mdb_path { 64 0 stevel size_t mdp_nelem; /* Number of components */ 65 0 stevel uint_t mdp_complete; /* Path completely resolved? */ 66 0 stevel uintptr_t mdp_vnode[MDB_PATH_NELEM]; /* Array of vnode_t addresses */ 67 0 stevel char *mdp_name[MDB_PATH_NELEM]; /* Array of name components */ 68 0 stevel } mdb_path_t; 69 0 stevel 70 0 stevel static int mdb_autonode2path(uintptr_t, mdb_path_t *); 71 0 stevel static int mdb_sprintpath(char *, size_t, mdb_path_t *); 72 0 stevel 73 0 stevel /* 74 0 stevel * Kernel parameters from <sys/param.h> which we keep in-core: 75 0 stevel */ 76 0 stevel unsigned long _mdb_ks_pagesize; 77 0 stevel unsigned int _mdb_ks_pageshift; 78 0 stevel unsigned long _mdb_ks_pageoffset; 79 0 stevel unsigned long long _mdb_ks_pagemask; 80 0 stevel unsigned long _mdb_ks_mmu_pagesize; 81 0 stevel unsigned int _mdb_ks_mmu_pageshift; 82 0 stevel unsigned long _mdb_ks_mmu_pageoffset; 83 0 stevel unsigned long _mdb_ks_mmu_pagemask; 84 0 stevel uintptr_t _mdb_ks_kernelbase; 85 0 stevel uintptr_t _mdb_ks_userlimit; 86 0 stevel uintptr_t _mdb_ks_userlimit32; 87 0 stevel uintptr_t _mdb_ks_argsbase; 88 0 stevel unsigned long _mdb_ks_msg_bsize; 89 0 stevel unsigned long _mdb_ks_defaultstksz; 90 0 stevel int _mdb_ks_ncpu; 91 0 stevel 92 0 stevel /* 93 0 stevel * In-core copy of DNLC information: 94 0 stevel */ 95 0 stevel #define MDB_DNLC_HSIZE 1024 96 0 stevel #define MDB_DNLC_HASH(vp) (((uintptr_t)(vp) >> 3) & (MDB_DNLC_HSIZE - 1)) 97 0 stevel #define MDB_DNLC_NCACHE_SZ(ncp) (sizeof (ncache_t) + (ncp)->namlen) 98 0 stevel #define MDB_DNLC_MAX_RETRY 4 99 0 stevel 100 0 stevel 101 0 stevel static ncache_t **dnlc_hash; /* mdbs hash array of dnlc entries */ 102 0 stevel 103 0 stevel /* 104 0 stevel * This will be the location of the vnodeops pointer for "autofs_vnodeops" 105 0 stevel * The pointer still needs to be read with mdb_vread() to get the location 106 0 stevel * of the vnodeops structure for autofs. 107 0 stevel */ 108 0 stevel static struct vnodeops *autofs_vnops_ptr; 109 0 stevel 110 0 stevel /* 111 0 stevel * STREAMS queue registrations: 112 0 stevel */ 113 0 stevel typedef struct mdb_qinfo { 114 0 stevel const mdb_qops_t *qi_ops; /* Address of ops vector */ 115 0 stevel uintptr_t qi_addr; /* Address of qinit structure (key) */ 116 0 stevel struct mdb_qinfo *qi_next; /* Next qinfo in list */ 117 0 stevel } mdb_qinfo_t; 118 0 stevel 119 0 stevel static mdb_qinfo_t *qi_head; /* Head of qinfo chain */ 120 0 stevel 121 0 stevel /* 122 0 stevel * Device naming callback structure: 123 0 stevel */ 124 0 stevel typedef struct nm_query { 125 0 stevel const char *nm_name; /* Device driver name [in/out] */ 126 0 stevel major_t nm_major; /* Device major number [in/out] */ 127 0 stevel ushort_t nm_found; /* Did we find a match? [out] */ 128 0 stevel } nm_query_t; 129 0 stevel 130 0 stevel /* 131 0 stevel * Address-to-modctl callback structure: 132 0 stevel */ 133 0 stevel typedef struct a2m_query { 134 0 stevel uintptr_t a2m_addr; /* Virtual address [in] */ 135 0 stevel uintptr_t a2m_where; /* Modctl address [out] */ 136 0 stevel } a2m_query_t; 137 0 stevel 138 0 stevel /* 139 0 stevel * Segment-to-mdb_map callback structure: 140 0 stevel */ 141 0 stevel typedef struct { 142 0 stevel struct seg_ops *asm_segvn_ops; /* Address of segvn ops [in] */ 143 0 stevel void (*asm_callback)(const struct mdb_map *, void *); /* Callb [in] */ 144 0 stevel void *asm_cbdata; /* Callback data [in] */ 145 0 stevel } asmap_arg_t; 146 0 stevel 147 0 stevel static void 148 0 stevel dnlc_free(void) 149 0 stevel { 150 0 stevel ncache_t *ncp, *next; 151 0 stevel int i; 152 0 stevel 153 0 stevel if (dnlc_hash == NULL) { 154 0 stevel return; 155 0 stevel } 156 0 stevel 157 0 stevel /* 158 0 stevel * Free up current dnlc entries 159 0 stevel */ 160 0 stevel for (i = 0; i < MDB_DNLC_HSIZE; i++) { 161 0 stevel for (ncp = dnlc_hash[i]; ncp; ncp = next) { 162 0 stevel next = ncp->hash_next; 163 0 stevel mdb_free(ncp, MDB_DNLC_NCACHE_SZ(ncp)); 164 0 stevel } 165 0 stevel } 166 0 stevel mdb_free(dnlc_hash, MDB_DNLC_HSIZE * sizeof (ncache_t *)); 167 0 stevel dnlc_hash = NULL; 168 0 stevel } 169 0 stevel 170 0 stevel char bad_dnlc[] = "inconsistent dnlc chain: %d, ncache va: %p" 171 0 stevel " - continuing with the rest\n"; 172 0 stevel 173 0 stevel static int 174 0 stevel dnlc_load(void) 175 0 stevel { 176 0 stevel int i; /* hash index */ 177 0 stevel int retry_cnt = 0; 178 0 stevel int skip_bad_chains = 0; 179 0 stevel int nc_hashsz; /* kernel hash array size */ 180 0 stevel uintptr_t nc_hash_addr; /* kernel va of ncache hash array */ 181 0 stevel uintptr_t head; /* kernel va of head of hash chain */ 182 0 stevel 183 0 stevel /* 184 0 stevel * If we've already cached the DNLC and we're looking at a dump, 185 0 stevel * our cache is good forever, so don't bother re-loading. 186 0 stevel */ 187 0 stevel if (dnlc_hash && mdb_prop_postmortem) { 188 0 stevel return (0); 189 0 stevel } 190 0 stevel 191 0 stevel /* 192 0 stevel * For a core dump, retries wont help. 193 0 stevel * Just print and skip any bad chains. 194 0 stevel */ 195 0 stevel if (mdb_prop_postmortem) { 196 0 stevel skip_bad_chains = 1; 197 0 stevel } 198 0 stevel retry: 199 0 stevel if (retry_cnt++ >= MDB_DNLC_MAX_RETRY) { 200 0 stevel /* 201 0 stevel * Give up retrying the rapidly changing dnlc. 202 0 stevel * Just print and skip any bad chains 203 0 stevel */ 204 0 stevel skip_bad_chains = 1; 205 0 stevel } 206 0 stevel 207 0 stevel dnlc_free(); /* Free up the mdb hashed dnlc - if any */ 208 0 stevel 209 0 stevel /* 210 0 stevel * Although nc_hashsz and the location of nc_hash doesn't currently 211 0 stevel * change, it may do in the future with a more dynamic dnlc. 212 0 stevel * So always read these values afresh. 213 0 stevel */ 214 0 stevel if (mdb_readvar(&nc_hashsz, "nc_hashsz") == -1) { 215 0 stevel mdb_warn("failed to read nc_hashsz"); 216 0 stevel return (-1); 217 0 stevel } 218 0 stevel if (mdb_readvar(&nc_hash_addr, "nc_hash") == -1) { 219 0 stevel mdb_warn("failed to read nc_hash"); 220 0 stevel return (-1); 221 0 stevel } 222 0 stevel 223 0 stevel /* 224 0 stevel * Allocate the mdb dnlc hash array 225 0 stevel */ 226 0 stevel dnlc_hash = mdb_zalloc(MDB_DNLC_HSIZE * sizeof (ncache_t *), UM_SLEEP); 227 0 stevel 228 0 stevel /* for each kernel hash chain */ 229 0 stevel for (i = 0, head = nc_hash_addr; i < nc_hashsz; 230 0 stevel i++, head += sizeof (nc_hash_t)) { 231 0 stevel nc_hash_t nch; /* kernel hash chain header */ 232 0 stevel ncache_t *ncp; /* name cache pointer */ 233 0 stevel int hash; /* mdb hash value */ 234 0 stevel uintptr_t nc_va; /* kernel va of next ncache */ 235 0 stevel uintptr_t ncprev_va; /* kernel va of previous ncache */ 236 0 stevel int khash; /* kernel dnlc hash value */ 237 0 stevel uchar_t namelen; /* name length */ 238 0 stevel ncache_t nc; /* name cache entry */ 239 0 stevel int nc_size; /* size of a name cache entry */ 240 0 stevel 241 0 stevel /* 242 0 stevel * We read each element of the nc_hash array individually 243 0 stevel * just before we process the entries in its chain. This is 244 0 stevel * because the chain can change so rapidly on a running system. 245 0 stevel */ 246 0 stevel if (mdb_vread(&nch, sizeof (nc_hash_t), head) == -1) { 247 0 stevel mdb_warn("failed to read nc_hash chain header %d", i); 248 0 stevel dnlc_free(); 249 0 stevel return (-1); 250 0 stevel } 251 0 stevel 252 0 stevel ncprev_va = head; 253 0 stevel nc_va = (uintptr_t)(nch.hash_next); 254 0 stevel /* for each entry in the chain */ 255 0 stevel while (nc_va != head) { 256 0 stevel /* 257 0 stevel * The size of the ncache entries varies 258 0 stevel * because the name is appended to the structure. 259 0 stevel * So we read in the structure then re-read 260 0 stevel * for the structure plus name. 261 0 stevel */ 262 0 stevel if (mdb_vread(&nc, sizeof (ncache_t), nc_va) == -1) { 263 0 stevel if (skip_bad_chains) { 264 0 stevel mdb_warn(bad_dnlc, i, nc_va); 265 0 stevel break; 266 0 stevel } 267 0 stevel goto retry; 268 0 stevel } 269 0 stevel nc_size = MDB_DNLC_NCACHE_SZ(&nc); 270 0 stevel ncp = mdb_alloc(nc_size, UM_SLEEP); 271 0 stevel if (mdb_vread(ncp, nc_size - 1, nc_va) == -1) { 272 0 stevel mdb_free(ncp, nc_size); 273 0 stevel if (skip_bad_chains) { 274 0 stevel mdb_warn(bad_dnlc, i, nc_va); 275 0 stevel break; 276 0 stevel } 277 0 stevel goto retry; 278 0 stevel } 279 0 stevel 280 0 stevel /* 281 0 stevel * Check for chain consistency 282 0 stevel */ 283 0 stevel if ((uintptr_t)ncp->hash_prev != ncprev_va) { 284 0 stevel mdb_free(ncp, nc_size); 285 0 stevel if (skip_bad_chains) { 286 0 stevel mdb_warn(bad_dnlc, i, nc_va); 287 0 stevel break; 288 0 stevel } 289 0 stevel goto retry; 290 0 stevel } 291 0 stevel /* 292 0 stevel * Terminate the new name with a null. 293 0 stevel * Note, we allowed space for this null when 294 0 stevel * allocating space for the entry. 295 0 stevel */ 296 0 stevel ncp->name[ncp->namlen] = '\0'; 297 0 stevel 298 0 stevel /* 299 0 stevel * Validate new entry by re-hashing using the 300 0 stevel * kernel dnlc hash function and comparing the hash 301 0 stevel */ 302 0 stevel DNLCHASH(ncp->name, ncp->dp, khash, namelen); 303 0 stevel if ((namelen != ncp->namlen) || 304 0 stevel (khash != ncp->hash)) { 305 0 stevel mdb_free(ncp, nc_size); 306 0 stevel if (skip_bad_chains) { 307 0 stevel mdb_warn(bad_dnlc, i, nc_va); 308 0 stevel break; 309 0 stevel } 310 0 stevel goto retry; 311 0 stevel } 312 0 stevel 313 0 stevel /* 314 0 stevel * Finally put the validated entry into the mdb 315 0 stevel * hash chains. Reuse the kernel next hash field 316 0 stevel * for the mdb hash chain pointer. 317 0 stevel */ 318 0 stevel hash = MDB_DNLC_HASH(ncp->vp); 319 0 stevel ncprev_va = nc_va; 320 0 stevel nc_va = (uintptr_t)(ncp->hash_next); 321 0 stevel ncp->hash_next = dnlc_hash[hash]; 322 0 stevel dnlc_hash[hash] = ncp; 323 0 stevel } 324 0 stevel } 325 0 stevel return (0); 326 0 stevel } 327 0 stevel 328 0 stevel /*ARGSUSED*/ 329 0 stevel int 330 0 stevel dnlcdump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 331 0 stevel { 332 0 stevel ncache_t *ent; 333 0 stevel int i; 334 0 stevel 335 0 stevel if ((flags & DCMD_ADDRSPEC) || argc != 0) 336 0 stevel return (DCMD_USAGE); 337 0 stevel 338 0 stevel if (dnlc_load() == -1) 339 0 stevel return (DCMD_ERR); 340 0 stevel 341 0 stevel mdb_printf("%<u>%-?s %-?s %-32s%</u>\n", "VP", "DVP", "NAME"); 342 0 stevel 343 0 stevel for (i = 0; i < MDB_DNLC_HSIZE; i++) { 344 0 stevel for (ent = dnlc_hash[i]; ent != NULL; ent = ent->hash_next) { 345 0 stevel mdb_printf("%0?p %0?p %s\n", 346 0 stevel ent->vp, ent->dp, ent->name); 347 0 stevel } 348 0 stevel } 349 0 stevel 350 0 stevel return (DCMD_OK); 351 0 stevel } 352 0 stevel 353 0 stevel static int 354 0 stevel mdb_sprintpath(char *buf, size_t len, mdb_path_t *path) 355 0 stevel { 356 0 stevel char *s = buf; 357 0 stevel int i; 358 0 stevel 359 0 stevel if (len < sizeof ("/...")) 360 0 stevel return (-1); 361 0 stevel 362 0 stevel if (!path->mdp_complete) { 363 0 stevel (void) strcpy(s, "??"); 364 0 stevel s += 2; 365 0 stevel 366 0 stevel if (path->mdp_nelem == 0) 367 0 stevel return (-1); 368 0 stevel } 369 0 stevel 370 0 stevel if (path->mdp_nelem == 0) { 371 0 stevel (void) strcpy(s, "/"); 372 0 stevel return (0); 373 0 stevel } 374 0 stevel 375 0 stevel for (i = path->mdp_nelem - 1; i >= 0; i--) { 376 0 stevel /* 377 0 stevel * Number of bytes left is the distance from where we 378 0 stevel * are to the end, minus 2 for '/' and '\0' 379 0 stevel */ 380 0 stevel ssize_t left = (ssize_t)(&buf[len] - s) - 2; 381 0 stevel 382 0 stevel if (left <= 0) 383 0 stevel break; 384 0 stevel 385 0 stevel *s++ = '/'; 386 0 stevel (void) strncpy(s, path->mdp_name[i], left); 387 0 stevel s[left - 1] = '\0'; 388 0 stevel s += strlen(s); 389 0 stevel 390 0 stevel if (left < strlen(path->mdp_name[i])) 391 0 stevel break; 392 0 stevel } 393 0 stevel 394 0 stevel if (i >= 0) 395 0 stevel (void) strcpy(&buf[len - 4], "..."); 396 0 stevel 397 0 stevel return (0); 398 0 stevel } 399 0 stevel 400 0 stevel static int 401 0 stevel mdb_autonode2path(uintptr_t addr, mdb_path_t *path) 402 0 stevel { 403 0 stevel fninfo_t fni; 404 0 stevel fnnode_t fn; 405 0 stevel 406 0 stevel vnode_t vn; 407 0 stevel vfs_t vfs; 408 0 stevel struct vnodeops *autofs_vnops = NULL; 409 0 stevel 410 0 stevel /* 411 0 stevel * "autofs_vnops_ptr" is the address of the pointer to the vnodeops 412 0 stevel * structure for autofs. We want to read it each time we access 413 0 stevel * it since autofs could (in theory) be unloaded and reloaded. 414 0 stevel */ 415 0 stevel if (mdb_vread(&autofs_vnops, sizeof (autofs_vnops), 416 0 stevel (uintptr_t)autofs_vnops_ptr) == -1) 417 0 stevel return (-1); 418 0 stevel 419 0 stevel if (mdb_vread(&vn, sizeof (vn), addr) == -1) 420 0 stevel return (-1); 421 0 stevel 422 0 stevel if (autofs_vnops == NULL || vn.v_op != autofs_vnops) 423 0 stevel return (-1); 424 0 stevel 425 0 stevel addr = (uintptr_t)vn.v_data; 426 0 stevel 427 0 stevel if (mdb_vread(&vfs, sizeof (vfs), (uintptr_t)vn.v_vfsp) == -1 || 428 0 stevel mdb_vread(&fni, sizeof (fni), (uintptr_t)vfs.vfs_data) == -1 || 429 0 stevel mdb_vread(&vn, sizeof (vn), (uintptr_t)fni.fi_rootvp) == -1) 430 0 stevel return (-1); 431 0 stevel 432 0 stevel for (;;) { 433 0 stevel size_t elem = path->mdp_nelem++; 434 0 stevel char elemstr[MAXNAMELEN]; 435 0 stevel char *c, *p; 436 0 stevel 437 0 stevel if (elem == MDB_PATH_NELEM) { 438 0 stevel path->mdp_nelem--; 439 0 stevel return (-1); 440 0 stevel } 441 0 stevel 442 0 stevel if (mdb_vread(&fn, sizeof (fn), addr) != sizeof (fn)) { 443 0 stevel path->mdp_nelem--; 444 0 stevel return (-1); 445 0 stevel } 446 0 stevel 447 0 stevel if (mdb_readstr(elemstr, sizeof (elemstr), 448 0 stevel (uintptr_t)fn.fn_name) <= 0) { 449 0 stevel (void) strcpy(elemstr, "?"); 450 0 stevel } 451 0 stevel 452 0 stevel c = mdb_alloc(strlen(elemstr) + 1, UM_SLEEP | UM_GC); 453 0 stevel (void) strcpy(c, elemstr); 454 0 stevel 455 0 stevel path->mdp_vnode[elem] = (uintptr_t)fn.fn_vnode; 456 0 stevel 457 0 stevel if (addr == (uintptr_t)fn.fn_parent) { 458 0 stevel path->mdp_name[elem] = &c[1]; 459 0 stevel path->mdp_complete = TRUE; 460 0 stevel break; 461 0 stevel } 462 0 stevel 463 0 stevel if ((p = strrchr(c, '/')) != NULL) 464 0 stevel path->mdp_name[elem] = p + 1; 465 0 stevel else 466 0 stevel path->mdp_name[elem] = c; 467 0 stevel 468 0 stevel addr = (uintptr_t)fn.fn_parent; 469 0 stevel } 470 0 stevel 471 0 stevel return (0); 472 0 stevel } 473 0 stevel 474 0 stevel int 475 0 stevel mdb_vnode2path(uintptr_t addr, char *buf, size_t buflen) 476 0 stevel { 477 0 stevel uintptr_t rootdir; 478 0 stevel ncache_t *ent; 479 0 stevel vnode_t vp; 480 0 stevel mdb_path_t path; 481 0 stevel 482 0 stevel /* 483 0 stevel * Check to see if we have a cached value for this vnode 484 0 stevel */ 485 0 stevel if (mdb_vread(&vp, sizeof (vp), addr) != -1 && 486 0 stevel vp.v_path != NULL && 487 0 stevel mdb_readstr(buf, buflen, (uintptr_t)vp.v_path) != -1) 488 0 stevel return (0); 489 0 stevel 490 0 stevel if (dnlc_load() == -1) 491 0 stevel return (-1); 492 0 stevel 493 0 stevel if (mdb_readvar(&rootdir, "rootdir") == -1) { 494 0 stevel mdb_warn("failed to read 'rootdir'"); 495 0 stevel return (-1); 496 0 stevel } 497 0 stevel 498 0 stevel bzero(&path, sizeof (mdb_path_t)); 499 0 stevel again: 500 0 stevel if ((addr == NULL) && (path.mdp_nelem == 0)) { 501 0 stevel /* 502 0 stevel * 0 elems && complete tells sprintpath to just print "/" 503 0 stevel */ 504 0 stevel path.mdp_complete = TRUE; 505 0 stevel goto out; 506 0 stevel } 507 0 stevel 508 0 stevel if (addr == rootdir) { 509 0 stevel path.mdp_complete = TRUE; 510 0 stevel goto out; 511 0 stevel } 512 0 stevel 513 0 stevel for (ent = dnlc_hash[MDB_DNLC_HASH(addr)]; ent; ent = ent->hash_next) { 514 0 stevel if ((uintptr_t)ent->vp == addr) { 515 0 stevel if (strcmp(ent->name, "..") == 0 || 516 0 stevel strcmp(ent->name, ".") == 0) 517 0 stevel continue; 518 0 stevel 519 0 stevel path.mdp_vnode[path.mdp_nelem] = (uintptr_t)ent->vp; 520 0 stevel path.mdp_name[path.mdp_nelem] = ent->name; 521 0 stevel path.mdp_nelem++; 522 0 stevel 523 0 stevel if (path.mdp_nelem == MDB_PATH_NELEM) { 524 0 stevel path.mdp_nelem--; 525 0 stevel mdb_warn("path exceeded maximum expected " 526 0 stevel "elements\n"); 527 0 stevel return (-1); 528 0 stevel } 529 0 stevel 530 0 stevel addr = (uintptr_t)ent->dp; 531 0 stevel goto again; 532 0 stevel } 533 0 stevel } 534 0 stevel 535 0 stevel (void) mdb_autonode2path(addr, &path); 536 0 stevel 537 0 stevel out: 538 0 stevel return (mdb_sprintpath(buf, buflen, &path)); 539 0 stevel } 540 0 stevel 541 0 stevel 542 0 stevel uintptr_t 543 0 stevel mdb_pid2proc(pid_t pid, proc_t *proc) 544 0 stevel { 545 0 stevel int pid_hashsz, hash; 546 0 stevel uintptr_t paddr, pidhash, procdir; 547 0 stevel struct pid pidp; 548 0 stevel 549 0 stevel if (mdb_readvar(&pidhash, "pidhash") == -1) 550 0 stevel return (NULL); 551 0 stevel 552 0 stevel if (mdb_readvar(&pid_hashsz, "pid_hashsz") == -1) 553 0 stevel return (NULL); 554 0 stevel 555 0 stevel if (mdb_readvar(&procdir, "procdir") == -1) 556 0 stevel return (NULL); 557 0 stevel 558 0 stevel hash = pid & (pid_hashsz - 1); 559 0 stevel 560 0 stevel if (mdb_vread(&paddr, sizeof (paddr), 561 0 stevel pidhash + (hash * sizeof (paddr))) == -1) 562 0 stevel return (NULL); 563 0 stevel 564 0 stevel while (paddr != 0) { 565 0 stevel if (mdb_vread(&pidp, sizeof (pidp), paddr) == -1) 566 0 stevel return (NULL); 567 0 stevel 568 0 stevel if (pidp.pid_id == pid) { 569 0 stevel uintptr_t procp; 570 0 stevel 571 0 stevel if (mdb_vread(&procp, sizeof (procp), procdir + 572 0 stevel (pidp.pid_prslot * sizeof (procp))) == -1) 573 0 stevel return (NULL); 574 0 stevel 575 0 stevel if (proc != NULL) 576 0 stevel (void) mdb_vread(proc, sizeof (proc_t), procp); 577 0 stevel 578 0 stevel return (procp); 579 0 stevel } 580 0 stevel paddr = (uintptr_t)pidp.pid_link; 581 0 stevel } 582 0 stevel return (NULL); 583 0 stevel } 584 0 stevel 585 1234 johnlev int 586 1234 johnlev mdb_cpu2cpuid(uintptr_t cpup) 587 1234 johnlev { 588 1234 johnlev cpu_t cpu; 589 1234 johnlev 590 1234 johnlev if (mdb_vread(&cpu, sizeof (cpu_t), cpup) != sizeof (cpu_t)) 591 1234 johnlev return (-1); 592 1234 johnlev 593 1234 johnlev return (cpu.cpu_id); 594 1234 johnlev } 595 1234 johnlev 596 2116 anish int 597 2116 anish mdb_cpuset_find(uintptr_t cpusetp) 598 2116 anish { 599 2116 anish ulong_t *cpuset; 600 2116 anish size_t nr_words = BT_BITOUL(NCPU); 601 2116 anish size_t sz = nr_words * sizeof (ulong_t); 602 2116 anish size_t i; 603 2116 anish int cpu = -1; 604 2116 anish 605 2116 anish cpuset = mdb_alloc(sz, UM_SLEEP); 606 2116 anish 607 6336 bholler if (mdb_vread((void *)cpuset, sz, cpusetp) != sz) 608 2116 anish goto out; 609 2116 anish 610 2116 anish for (i = 0; i < nr_words; i++) { 611 2116 anish size_t j; 612 2116 anish ulong_t m; 613 2116 anish 614 2116 anish for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1) { 615 2116 anish if (cpuset[i] & m) { 616 2116 anish cpu = i * BT_NBIPUL + j; 617 2116 anish goto out; 618 2116 anish } 619 2116 anish } 620 2116 anish } 621 2116 anish 622 2116 anish out: 623 2116 anish mdb_free(cpuset, sz); 624 2116 anish return (cpu); 625 2116 anish } 626 2116 anish 627 0 stevel uintptr_t 628 0 stevel mdb_vnode2page(uintptr_t vp, uintptr_t offset) 629 0 stevel { 630 0 stevel long page_hashsz, ndx; 631 0 stevel uintptr_t page_hash, pp; 632 0 stevel 633 0 stevel if (mdb_readvar(&page_hashsz, "page_hashsz") == -1 || 634 0 stevel mdb_readvar(&page_hash, "page_hash") == -1) 635 0 stevel return (NULL); 636 0 stevel 637 0 stevel ndx = PAGE_HASH_FUNC(vp, offset); 638 0 stevel page_hash += ndx * sizeof (uintptr_t); 639 0 stevel 640 0 stevel mdb_vread(&pp, sizeof (pp), page_hash); 641 0 stevel 642 0 stevel while (pp != NULL) { 643 0 stevel page_t page; 644 0 stevel 645 0 stevel mdb_vread(&page, sizeof (page), pp); 646 0 stevel 647 0 stevel if ((uintptr_t)page.p_vnode == vp && 648 0 stevel (uintptr_t)page.p_offset == offset) 649 0 stevel return (pp); 650 0 stevel 651 0 stevel pp = (uintptr_t)page.p_hash; 652 0 stevel } 653 0 stevel 654 0 stevel return (NULL); 655 0 stevel } 656 0 stevel 657 0 stevel char 658 0 stevel mdb_vtype2chr(vtype_t type, mode_t mode) 659 0 stevel { 660 0 stevel static const char vttab[] = { 661 0 stevel ' ', /* VNON */ 662 0 stevel ' ', /* VREG */ 663 0 stevel '/', /* VDIR */ 664 0 stevel ' ', /* VBLK */ 665 0 stevel ' ', /* VCHR */ 666 0 stevel '@', /* VLNK */ 667 0 stevel '|', /* VFIFO */ 668 0 stevel '>', /* VDOOR */ 669 0 stevel ' ', /* VPROC */ 670 0 stevel '=', /* VSOCK */ 671 0 stevel ' ', /* VBAD */ 672 0 stevel }; 673 0 stevel 674 0 stevel if (type < 0 || type >= sizeof (vttab) / sizeof (vttab[0])) 675 0 stevel return ('?'); 676 0 stevel 677 0 stevel if (type == VREG && (mode & 0111) != 0) 678 0 stevel return ('*'); 679 0 stevel 680 0 stevel return (vttab[type]); 681 0 stevel } 682 0 stevel 683 0 stevel static int 684 0 stevel a2m_walk_modctl(uintptr_t addr, const struct modctl *m, a2m_query_t *a2m) 685 0 stevel { 686 0 stevel struct module mod; 687 0 stevel 688 0 stevel if (m->mod_mp == NULL) 689 0 stevel return (0); 690 0 stevel 691 0 stevel if (mdb_vread(&mod, sizeof (mod), (uintptr_t)m->mod_mp) == -1) { 692 0 stevel mdb_warn("couldn't read modctl %p's module", addr); 693 0 stevel return (0); 694 0 stevel } 695 0 stevel 696 0 stevel if (a2m->a2m_addr >= (uintptr_t)mod.text && 697 0 stevel a2m->a2m_addr < (uintptr_t)mod.text + mod.text_size) 698 0 stevel goto found; 699 0 stevel 700 0 stevel if (a2m->a2m_addr >= (uintptr_t)mod.data && 701 0 stevel a2m->a2m_addr < (uintptr_t)mod.data + mod.data_size) 702 0 stevel goto found; 703 0 stevel 704 0 stevel return (0); 705 0 stevel 706 0 stevel found: 707 0 stevel a2m->a2m_where = addr; 708 0 stevel return (-1); 709 0 stevel } 710 0 stevel 711 0 stevel uintptr_t 712 0 stevel mdb_addr2modctl(uintptr_t addr) 713 0 stevel { 714 0 stevel a2m_query_t a2m; 715 0 stevel 716 0 stevel a2m.a2m_addr = addr; 717 0 stevel a2m.a2m_where = NULL; 718 0 stevel 719 0 stevel (void) mdb_walk("modctl", (mdb_walk_cb_t)a2m_walk_modctl, &a2m); 720 0 stevel return (a2m.a2m_where); 721 0 stevel } 722 0 stevel 723 0 stevel static mdb_qinfo_t * 724 0 stevel qi_lookup(uintptr_t qinit_addr) 725 0 stevel { 726 0 stevel mdb_qinfo_t *qip; 727 0 stevel 728 0 stevel for (qip = qi_head; qip != NULL; qip = qip->qi_next) { 729 0 stevel if (qip->qi_addr == qinit_addr) 730 0 stevel return (qip); 731 0 stevel } 732 0 stevel 733 0 stevel return (NULL); 734 0 stevel } 735 0 stevel 736 0 stevel void 737 0 stevel mdb_qops_install(const mdb_qops_t *qops, uintptr_t qinit_addr) 738 0 stevel { 739 0 stevel mdb_qinfo_t *qip = qi_lookup(qinit_addr); 740 0 stevel 741 0 stevel if (qip != NULL) { 742 0 stevel qip->qi_ops = qops; 743 0 stevel return; 744 0 stevel } 745 0 stevel 746 0 stevel qip = mdb_alloc(sizeof (mdb_qinfo_t), UM_SLEEP); 747 0 stevel 748 0 stevel qip->qi_ops = qops; 749 0 stevel qip->qi_addr = qinit_addr; 750 0 stevel qip->qi_next = qi_head; 751 0 stevel 752 0 stevel qi_head = qip; 753 0 stevel } 754 0 stevel 755 0 stevel void 756 0 stevel mdb_qops_remove(const mdb_qops_t *qops, uintptr_t qinit_addr) 757 0 stevel { 758 0 stevel mdb_qinfo_t *qip, *p = NULL; 759 0 stevel 760 0 stevel for (qip = qi_head; qip != NULL; p = qip, qip = qip->qi_next) { 761 0 stevel if (qip->qi_addr == qinit_addr && qip->qi_ops == qops) { 762 0 stevel if (qi_head == qip) 763 0 stevel qi_head = qip->qi_next; 764 0 stevel else 765 0 stevel p->qi_next = qip->qi_next; 766 0 stevel mdb_free(qip, sizeof (mdb_qinfo_t)); 767 0 stevel return; 768 0 stevel } 769 0 stevel } 770 0 stevel } 771 0 stevel 772 0 stevel char * 773 0 stevel mdb_qname(const queue_t *q, char *buf, size_t nbytes) 774 0 stevel { 775 0 stevel struct module_info mi; 776 0 stevel struct qinit qi; 777 0 stevel 778 0 stevel if (mdb_vread(&qi, sizeof (qi), (uintptr_t)q->q_qinfo) == -1) { 779 0 stevel mdb_warn("failed to read qinit at %p", q->q_qinfo); 780 0 stevel goto err; 781 0 stevel } 782 0 stevel 783 0 stevel if (mdb_vread(&mi, sizeof (mi), (uintptr_t)qi.qi_minfo) == -1) { 784 0 stevel mdb_warn("failed to read module_info at %p", qi.qi_minfo); 785 0 stevel goto err; 786 0 stevel } 787 0 stevel 788 0 stevel if (mdb_readstr(buf, nbytes, (uintptr_t)mi.mi_idname) <= 0) { 789 0 stevel mdb_warn("failed to read mi_idname at %p", mi.mi_idname); 790 0 stevel goto err; 791 0 stevel } 792 0 stevel 793 0 stevel return (buf); 794 0 stevel 795 0 stevel err: 796 0 stevel (void) mdb_snprintf(buf, nbytes, "???"); 797 0 stevel return (buf); 798 0 stevel } 799 0 stevel 800 0 stevel void 801 0 stevel mdb_qinfo(const queue_t *q, char *buf, size_t nbytes) 802 0 stevel { 803 0 stevel mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo); 804 0 stevel buf[0] = '\0'; 805 0 stevel 806 0 stevel if (qip != NULL) 807 0 stevel qip->qi_ops->q_info(q, buf, nbytes); 808 0 stevel } 809 0 stevel 810 0 stevel uintptr_t 811 0 stevel mdb_qrnext(const queue_t *q) 812 0 stevel { 813 0 stevel mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo); 814 0 stevel 815 0 stevel if (qip != NULL) 816 0 stevel return (qip->qi_ops->q_rnext(q)); 817 0 stevel 818 0 stevel return (NULL); 819 0 stevel } 820 0 stevel 821 0 stevel uintptr_t 822 0 stevel mdb_qwnext(const queue_t *q) 823 0 stevel { 824 0 stevel mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo); 825 0 stevel 826 0 stevel if (qip != NULL) 827 0 stevel return (qip->qi_ops->q_wnext(q)); 828 0 stevel 829 0 stevel return (NULL); 830 0 stevel } 831 0 stevel 832 0 stevel uintptr_t 833 0 stevel mdb_qrnext_default(const queue_t *q) 834 0 stevel { 835 0 stevel return ((uintptr_t)q->q_next); 836 0 stevel } 837 0 stevel 838 0 stevel uintptr_t 839 0 stevel mdb_qwnext_default(const queue_t *q) 840 0 stevel { 841 0 stevel return ((uintptr_t)q->q_next); 842 0 stevel } 843 0 stevel 844 0 stevel /* 845 0 stevel * The following three routines borrowed from modsubr.c 846 0 stevel */ 847 0 stevel static int 848 0 stevel nm_hash(const char *name) 849 0 stevel { 850 0 stevel char c; 851 0 stevel int hash = 0; 852 0 stevel 853 0 stevel for (c = *name++; c; c = *name++) 854 0 stevel hash ^= c; 855 0 stevel 856 0 stevel return (hash & MOD_BIND_HASHMASK); 857 0 stevel } 858 0 stevel 859 0 stevel static uintptr_t 860 0 stevel find_mbind(const char *name, uintptr_t *hashtab) 861 0 stevel { 862 0 stevel int hashndx; 863 0 stevel uintptr_t mb; 864 0 stevel struct bind mb_local; 865 4145 cth char node_name[MAXPATHLEN + 1]; 866 0 stevel 867 0 stevel hashndx = nm_hash(name); 868 0 stevel mb = hashtab[hashndx]; 869 0 stevel while (mb) { 870 0 stevel if (mdb_vread(&mb_local, sizeof (mb_local), mb) == -1) { 871 0 stevel mdb_warn("failed to read struct bind at %p", mb); 872 0 stevel return (NULL); 873 0 stevel } 874 0 stevel if (mdb_readstr(node_name, sizeof (node_name), 875 0 stevel (uintptr_t)mb_local.b_name) == -1) { 876 0 stevel mdb_warn("failed to read node name string at %p", 877 6336 bholler mb_local.b_name); 878 0 stevel return (NULL); 879 0 stevel } 880 0 stevel 881 0 stevel if (strcmp(name, node_name) == 0) 882 0 stevel break; 883 0 stevel 884 0 stevel mb = (uintptr_t)mb_local.b_next; 885 0 stevel } 886 0 stevel return (mb); 887 0 stevel } 888 0 stevel 889 0 stevel int 890 0 stevel mdb_name_to_major(const char *name, major_t *major) 891 0 stevel { 892 0 stevel uintptr_t mbind; 893 0 stevel uintptr_t mb_hashtab[MOD_BIND_HASHSIZE]; 894 0 stevel struct bind mbind_local; 895 0 stevel 896 0 stevel 897 0 stevel if (mdb_readsym(mb_hashtab, sizeof (mb_hashtab), "mb_hashtab") == -1) { 898 0 stevel mdb_warn("failed to read symbol 'mb_hashtab'"); 899 0 stevel return (-1); 900 0 stevel } 901 0 stevel 902 0 stevel if ((mbind = find_mbind(name, mb_hashtab)) != NULL) { 903 0 stevel if (mdb_vread(&mbind_local, sizeof (mbind_local), mbind) == 904 0 stevel -1) { 905 0 stevel mdb_warn("failed to read mbind struct at %p", mbind); 906 0 stevel return (-1); 907 0 stevel } 908 0 stevel 909 0 stevel *major = (major_t)mbind_local.b_num; 910 0 stevel return (0); 911 0 stevel } 912 0 stevel return (-1); 913 0 stevel } 914 0 stevel 915 0 stevel const char * 916 0 stevel mdb_major_to_name(major_t major) 917 0 stevel { 918 0 stevel static char name[MODMAXNAMELEN + 1]; 919 0 stevel 920 0 stevel uintptr_t devnamesp; 921 0 stevel struct devnames dn; 922 0 stevel uint_t devcnt; 923 0 stevel 924 0 stevel if (mdb_readvar(&devcnt, "devcnt") == -1 || major >= devcnt || 925 0 stevel mdb_readvar(&devnamesp, "devnamesp") == -1) 926 0 stevel return (NULL); 927 0 stevel 928 0 stevel if (mdb_vread(&dn, sizeof (struct devnames), devnamesp + 929 0 stevel major * sizeof (struct devnames)) != sizeof (struct devnames)) 930 0 stevel return (NULL); 931 0 stevel 932 0 stevel if (mdb_readstr(name, MODMAXNAMELEN + 1, (uintptr_t)dn.dn_name) == -1) 933 0 stevel return (NULL); 934 0 stevel 935 0 stevel return ((const char *)name); 936 0 stevel } 937 0 stevel 938 0 stevel /* 939 0 stevel * Return the name of the driver attached to the dip in drivername. 940 0 stevel */ 941 0 stevel int 942 0 stevel mdb_devinfo2driver(uintptr_t dip_addr, char *drivername, size_t namebufsize) 943 0 stevel { 944 0 stevel struct dev_info devinfo; 945 4145 cth char bind_name[MAXPATHLEN + 1]; 946 0 stevel major_t major; 947 0 stevel const char *namestr; 948 0 stevel 949 0 stevel 950 0 stevel if (mdb_vread(&devinfo, sizeof (devinfo), dip_addr) == -1) { 951 0 stevel mdb_warn("failed to read devinfo at %p", dip_addr); 952 0 stevel return (-1); 953 0 stevel } 954 0 stevel 955 0 stevel if (mdb_readstr(bind_name, sizeof (bind_name), 956 0 stevel (uintptr_t)devinfo.devi_binding_name) == -1) { 957 0 stevel mdb_warn("failed to read binding name at %p", 958 0 stevel devinfo.devi_binding_name); 959 0 stevel return (-1); 960 0 stevel } 961 0 stevel 962 0 stevel /* 963 0 stevel * Many->one relation: various names to one major number 964 0 stevel */ 965 0 stevel if (mdb_name_to_major(bind_name, &major) == -1) { 966 0 stevel mdb_warn("failed to translate bind name to major number\n"); 967 0 stevel return (-1); 968 0 stevel } 969 0 stevel 970 0 stevel /* 971 0 stevel * One->one relation: one major number corresponds to one driver 972 0 stevel */ 973 0 stevel if ((namestr = mdb_major_to_name(major)) == NULL) { 974 0 stevel (void) strncpy(drivername, "???", namebufsize); 975 0 stevel return (-1); 976 0 stevel } 977 0 stevel 978 0 stevel (void) strncpy(drivername, namestr, namebufsize); 979 0 stevel return (0); 980 0 stevel } 981 0 stevel 982 0 stevel /* 983 0 stevel * Find the name of the driver attached to this dip (if any), given: 984 0 stevel * - the address of a dip (in core) 985 0 stevel * - the NAME of the global pointer to the driver's i_ddi_soft_state struct 986 0 stevel * - pointer to a pointer to receive the address 987 0 stevel */ 988 0 stevel int 989 0 stevel mdb_devinfo2statep(uintptr_t dip_addr, char *soft_statep_name, 990 0 stevel uintptr_t *statep) 991 0 stevel { 992 0 stevel struct dev_info dev_info; 993 0 stevel 994 0 stevel 995 0 stevel if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) { 996 0 stevel mdb_warn("failed to read devinfo at %p", dip_addr); 997 0 stevel return (-1); 998 0 stevel } 999 0 stevel 1000 0 stevel return (mdb_get_soft_state_byname(soft_statep_name, 1001 0 stevel dev_info.devi_instance, statep, NULL, 0)); 1002 0 stevel } 1003 0 stevel 1004 0 stevel /* 1005 0 stevel * Returns a pointer to the top of the soft state struct for the instance 1006 0 stevel * specified (in state_addr), given the address of the global soft state 1007 0 stevel * pointer and size of the struct. Also fills in the buffer pointed to by 1008 0 stevel * state_buf_p (if non-NULL) with the contents of the state struct. 1009 0 stevel */ 1010 0 stevel int 1011 0 stevel mdb_get_soft_state_byaddr(uintptr_t ssaddr, uint_t instance, 1012 0 stevel uintptr_t *state_addr, void *state_buf_p, size_t sizeof_state) 1013 0 stevel { 1014 0 stevel struct i_ddi_soft_state ss; 1015 0 stevel void *statep; 1016 0 stevel 1017 0 stevel 1018 0 stevel if (mdb_vread(&ss, sizeof (ss), ssaddr) == -1) 1019 0 stevel return (-1); 1020 0 stevel 1021 0 stevel if (instance >= ss.n_items) 1022 0 stevel return (-1); 1023 0 stevel 1024 0 stevel if (mdb_vread(&statep, sizeof (statep), (uintptr_t)ss.array + 1025 0 stevel (sizeof (statep) * instance)) == -1) 1026 0 stevel return (-1); 1027 0 stevel 1028 0 stevel if (state_addr != NULL) 1029 0 stevel *state_addr = (uintptr_t)statep; 1030 0 stevel 1031 0 stevel if (statep == NULL) { 1032 0 stevel errno = ENOENT; 1033 0 stevel return (-1); 1034 0 stevel } 1035 0 stevel 1036 0 stevel if (state_buf_p != NULL) { 1037 0 stevel 1038 0 stevel /* Read the state struct into the buffer in local space. */ 1039 0 stevel if (mdb_vread(state_buf_p, sizeof_state, 1040 0 stevel (uintptr_t)statep) == -1) 1041 0 stevel return (-1); 1042 0 stevel } 1043 0 stevel 1044 0 stevel return (0); 1045 0 stevel } 1046 0 stevel 1047 0 stevel 1048 0 stevel /* 1049 0 stevel * Returns a pointer to the top of the soft state struct for the instance 1050 0 stevel * specified (in state_addr), given the name of the global soft state pointer 1051 0 stevel * and size of the struct. Also fills in the buffer pointed to by 1052 0 stevel * state_buf_p (if non-NULL) with the contents of the state struct. 1053 0 stevel */ 1054 0 stevel int 1055 0 stevel mdb_get_soft_state_byname(char *softstatep_name, uint_t instance, 1056 0 stevel uintptr_t *state_addr, void *state_buf_p, size_t sizeof_state) 1057 0 stevel { 1058 0 stevel uintptr_t ssaddr; 1059 0 stevel 1060 0 stevel if (mdb_readvar((void *)&ssaddr, softstatep_name) == -1) 1061 0 stevel return (-1); 1062 0 stevel 1063 0 stevel return (mdb_get_soft_state_byaddr(ssaddr, instance, state_addr, 1064 0 stevel state_buf_p, sizeof_state)); 1065 0 stevel } 1066 0 stevel 1067 0 stevel static const mdb_dcmd_t dcmds[] = { 1068 0 stevel { "dnlc", NULL, "print DNLC contents", dnlcdump }, 1069 0 stevel { NULL } 1070 0 stevel }; 1071 0 stevel 1072 0 stevel static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds }; 1073 0 stevel 1074 0 stevel /*ARGSUSED*/ 1075 0 stevel static void 1076 0 stevel update_vars(void *arg) 1077 0 stevel { 1078 0 stevel GElf_Sym sym; 1079 0 stevel 1080 0 stevel if (mdb_lookup_by_name("auto_vnodeops", &sym) == 0) 1081 0 stevel autofs_vnops_ptr = (struct vnodeops *)(uintptr_t)sym.st_value; 1082 0 stevel else 1083 0 stevel autofs_vnops_ptr = NULL; 1084 0 stevel 1085 0 stevel (void) mdb_readvar(&_mdb_ks_pagesize, "_pagesize"); 1086 0 stevel (void) mdb_readvar(&_mdb_ks_pageshift, "_pageshift"); 1087 0 stevel (void) mdb_readvar(&_mdb_ks_pageoffset, "_pageoffset"); 1088 0 stevel (void) mdb_readvar(&_mdb_ks_pagemask, "_pagemask"); 1089 0 stevel (void) mdb_readvar(&_mdb_ks_mmu_pagesize, "_mmu_pagesize"); 1090 0 stevel (void) mdb_readvar(&_mdb_ks_mmu_pageshift, "_mmu_pageshift"); 1091 0 stevel (void) mdb_readvar(&_mdb_ks_mmu_pageoffset, "_mmu_pageoffset"); 1092 0 stevel (void) mdb_readvar(&_mdb_ks_mmu_pagemask, "_mmu_pagemask"); 1093 0 stevel (void) mdb_readvar(&_mdb_ks_kernelbase, "_kernelbase"); 1094 0 stevel 1095 0 stevel (void) mdb_readvar(&_mdb_ks_userlimit, "_userlimit"); 1096 0 stevel (void) mdb_readvar(&_mdb_ks_userlimit32, "_userlimit32"); 1097 0 stevel (void) mdb_readvar(&_mdb_ks_argsbase, "_argsbase"); 1098 0 stevel (void) mdb_readvar(&_mdb_ks_msg_bsize, "_msg_bsize"); 1099 0 stevel (void) mdb_readvar(&_mdb_ks_defaultstksz, "_defaultstksz"); 1100 0 stevel (void) mdb_readvar(&_mdb_ks_ncpu, "_ncpu"); 1101 0 stevel } 1102 0 stevel 1103 0 stevel const mdb_modinfo_t * 1104 0 stevel _mdb_init(void) 1105 0 stevel { 1106 0 stevel /* 1107 0 stevel * When used with mdb, mdb_ks is a separate dmod. With kmdb, however, 1108 0 stevel * mdb_ks is compiled into the debugger module. kmdb cannot 1109 0 stevel * automatically modunload itself when it exits. If it restarts after 1110 0 stevel * debugger fault, static variables may not be initialized to zero. 1111 0 stevel * They must be manually reinitialized here. 1112 0 stevel */ 1113 0 stevel dnlc_hash = NULL; 1114 0 stevel qi_head = NULL; 1115 0 stevel 1116 0 stevel mdb_callback_add(MDB_CALLBACK_STCHG, update_vars, NULL); 1117 0 stevel 1118 0 stevel update_vars(NULL); 1119 0 stevel 1120 0 stevel return (&modinfo); 1121 0 stevel } 1122 0 stevel 1123 0 stevel void 1124 0 stevel _mdb_fini(void) 1125 0 stevel { 1126 0 stevel dnlc_free(); 1127 0 stevel while (qi_head != NULL) { 1128 0 stevel mdb_qinfo_t *qip = qi_head; 1129 0 stevel qi_head = qip->qi_next; 1130 0 stevel mdb_free(qip, sizeof (mdb_qinfo_t)); 1131 0 stevel } 1132 0 stevel } 1133 0 stevel 1134 0 stevel /* 1135 0 stevel * Interface between MDB kproc target and mdb_ks. The kproc target relies 1136 0 stevel * on looking up and invoking these functions in mdb_ks so that dependencies 1137 0 stevel * on the current kernel implementation are isolated in mdb_ks. 1138 0 stevel */ 1139 0 stevel 1140 0 stevel /* 1141 0 stevel * Given the address of a proc_t, return the p.p_as pointer; return NULL 1142 0 stevel * if we were unable to read a proc structure from the given address. 1143 0 stevel */ 1144 0 stevel uintptr_t 1145 0 stevel mdb_kproc_as(uintptr_t proc_addr) 1146 0 stevel { 1147 0 stevel proc_t p; 1148 0 stevel 1149 0 stevel if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p)) 1150 0 stevel return ((uintptr_t)p.p_as); 1151 0 stevel 1152 0 stevel return (NULL); 1153 0 stevel } 1154 0 stevel 1155 0 stevel /* 1156 0 stevel * Given the address of a proc_t, return the p.p_model value; return 1157 0 stevel * PR_MODEL_UNKNOWN if we were unable to read a proc structure or if 1158 0 stevel * the model value does not match one of the two known values. 1159 0 stevel */ 1160 0 stevel uint_t 1161 0 stevel mdb_kproc_model(uintptr_t proc_addr) 1162 0 stevel { 1163 0 stevel proc_t p; 1164 0 stevel 1165 0 stevel if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p)) { 1166 0 stevel switch (p.p_model) { 1167 0 stevel case DATAMODEL_ILP32: 1168 0 stevel return (PR_MODEL_ILP32); 1169 0 stevel case DATAMODEL_LP64: 1170 0 stevel return (PR_MODEL_LP64); 1171 0 stevel } 1172 0 stevel } 1173 0 stevel 1174 0 stevel return (PR_MODEL_UNKNOWN); 1175 0 stevel } 1176 0 stevel 1177 0 stevel /* 1178 0 stevel * Callback function for walking process's segment list. For each segment, 1179 0 stevel * we fill in an mdb_map_t describing its properties, and then invoke 1180 0 stevel * the callback function provided by the kproc target. 1181 0 stevel */ 1182 0 stevel static int 1183 0 stevel asmap_step(uintptr_t addr, const struct seg *seg, asmap_arg_t *asmp) 1184 0 stevel { 1185 0 stevel struct segvn_data svd; 1186 0 stevel mdb_map_t map; 1187 0 stevel 1188 0 stevel if (seg->s_ops == asmp->asm_segvn_ops && mdb_vread(&svd, 1189 0 stevel sizeof (svd), (uintptr_t)seg->s_data) == sizeof (svd)) { 1190 0 stevel 1191 0 stevel if (svd.vp != NULL) { 1192 0 stevel if (mdb_vnode2path((uintptr_t)svd.vp, map.map_name, 1193 6336 bholler MDB_TGT_MAPSZ) != 0) { 1194 0 stevel (void) mdb_snprintf(map.map_name, 1195 0 stevel MDB_TGT_MAPSZ, "[ vnode %p ]", svd.vp); 1196 0 stevel } 1197 0 stevel } else 1198 0 stevel (void) strcpy(map.map_name, "[ anon ]"); 1199 0 stevel 1200 0 stevel } else { 1201 0 stevel (void) mdb_snprintf(map.map_name, MDB_TGT_MAPSZ, 1202 0 stevel "[ seg %p ]", addr); 1203 0 stevel } 1204 0 stevel 1205 0 stevel map.map_base = (uintptr_t)seg->s_base; 1206 0 stevel map.map_size = seg->s_size; 1207 0 stevel map.map_flags = 0; 1208 0 stevel 1209 0 stevel asmp->asm_callback((const struct mdb_map *)&map, asmp->asm_cbdata); 1210 0 stevel return (WALK_NEXT); 1211 0 stevel } 1212 0 stevel 1213 0 stevel /* 1214 0 stevel * Given a process address space, walk its segment list using the seg walker, 1215 0 stevel * convert the segment data to an mdb_map_t, and pass this information 1216 0 stevel * back to the kproc target via the given callback function. 1217 0 stevel */ 1218 0 stevel int 1219 0 stevel mdb_kproc_asiter(uintptr_t as, 1220 0 stevel void (*func)(const struct mdb_map *, void *), void *p) 1221 0 stevel { 1222 0 stevel asmap_arg_t arg; 1223 0 stevel GElf_Sym sym; 1224 0 stevel 1225 0 stevel arg.asm_segvn_ops = NULL; 1226 0 stevel arg.asm_callback = func; 1227 0 stevel arg.asm_cbdata = p; 1228 0 stevel 1229 0 stevel if (mdb_lookup_by_name("segvn_ops", &sym) == 0) 1230 0 stevel arg.asm_segvn_ops = (struct seg_ops *)(uintptr_t)sym.st_value; 1231 0 stevel 1232 0 stevel return (mdb_pwalk("seg", (mdb_walk_cb_t)asmap_step, &arg, as)); 1233 0 stevel } 1234 0 stevel 1235 0 stevel /* 1236 0 stevel * Copy the auxv array from the given process's u-area into the provided 1237 0 stevel * buffer. If the buffer is NULL, only return the size of the auxv array 1238 0 stevel * so the caller knows how much space will be required. 1239 0 stevel */ 1240 0 stevel int 1241 0 stevel mdb_kproc_auxv(uintptr_t proc, auxv_t *auxv) 1242 0 stevel { 1243 0 stevel if (auxv != NULL) { 1244 0 stevel proc_t p; 1245 0 stevel 1246 0 stevel if (mdb_vread(&p, sizeof (p), proc) != sizeof (p)) 1247 0 stevel return (-1); 1248 0 stevel 1249 0 stevel bcopy(p.p_user.u_auxv, auxv, 1250 0 stevel sizeof (auxv_t) * __KERN_NAUXV_IMPL); 1251 0 stevel } 1252 0 stevel 1253 0 stevel return (__KERN_NAUXV_IMPL); 1254 0 stevel } 1255 0 stevel 1256 0 stevel /* 1257 0 stevel * Given a process address, return the PID. 1258 0 stevel */ 1259 0 stevel pid_t 1260 0 stevel mdb_kproc_pid(uintptr_t proc_addr) 1261 0 stevel { 1262 0 stevel struct pid pid; 1263 0 stevel proc_t p; 1264 0 stevel 1265 0 stevel if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p) && 1266 0 stevel mdb_vread(&pid, sizeof (pid), (uintptr_t)p.p_pidp) == sizeof (pid)) 1267 0 stevel return (pid.pid_id); 1268 0 stevel 1269 0 stevel return (-1); 1270 0 stevel } 1271 0 stevel 1272 0 stevel /* 1273 0 stevel * Interface between the MDB kvm target and mdb_ks. The kvm target relies 1274 0 stevel * on looking up and invoking these functions in mdb_ks so that dependencies 1275 0 stevel * on the current kernel implementation are isolated in mdb_ks. 1276 0 stevel */ 1277 0 stevel 1278 0 stevel /* 1279 0 stevel * Determine whether or not the thread that panicked the given kernel was a 1280 0 stevel * kernel thread (panic_thread->t_procp == &p0). 1281 0 stevel */ 1282 0 stevel void 1283 0 stevel mdb_dump_print_content(dumphdr_t *dh, pid_t content) 1284 0 stevel { 1285 0 stevel GElf_Sym sym; 1286 0 stevel uintptr_t pt; 1287 0 stevel uintptr_t procp; 1288 0 stevel int expcont = 0; 1289 0 stevel int actcont; 1290 0 stevel 1291 0 stevel (void) mdb_readvar(&expcont, "dump_conflags"); 1292 0 stevel actcont = dh->dump_flags & DF_CONTENT; 1293 0 stevel 1294 0 stevel if (actcont == DF_ALL) { 1295 0 stevel mdb_printf("dump content: all kernel and user pages\n"); 1296 0 stevel return; 1297 0 stevel } else if (actcont == DF_CURPROC) { 1298 0 stevel mdb_printf("dump content: kernel pages and pages from " 1299 0 stevel "PID %d", content); 1300 0 stevel return; 1301 0 stevel } 1302 0 stevel 1303 0 stevel mdb_printf("dump content: kernel pages only\n"); 1304 0 stevel if (!(expcont & DF_CURPROC)) 1305 0 stevel return; 1306 0 stevel 1307 0 stevel if (mdb_readvar(&pt, "panic_thread") != sizeof (pt) || pt == NULL) 1308 0 stevel goto kthreadpanic_err; 1309 0 stevel 1310 0 stevel if (mdb_vread(&procp, sizeof (procp), pt + OFFSETOF(kthread_t, 1311 0 stevel t_procp)) == -1 || procp == NULL) 1312 0 stevel goto kthreadpanic_err; 1313 0 stevel 1314 0 stevel if (mdb_lookup_by_name("p0", &sym) != 0) 1315 0 stevel goto kthreadpanic_err; 1316 0 stevel 1317 0 stevel if (procp == (uintptr_t)sym.st_value) { 1318 0 stevel mdb_printf(" (curproc requested, but a kernel thread " 1319 0 stevel "panicked)\n"); 1320 0 stevel } else { 1321 0 stevel mdb_printf(" (curproc requested, but the process that " 1322 0 stevel "panicked could not be dumped)\n"); 1323 0 stevel } 1324 0 stevel 1325 0 stevel return; 1326 0 stevel 1327 0 stevel kthreadpanic_err: 1328 0 stevel mdb_printf(" (curproc requested, but the process that panicked could " 1329 0 stevel "not be found)\n"); 1330 0 stevel } 1331 0 stevel 1332 0 stevel /* 1333 0 stevel * Determine the process that was saved in a `curproc' dump. This process will 1334 0 stevel * be recorded as the first element in dump_pids[]. 1335 0 stevel */ 1336 0 stevel int 1337 0 stevel mdb_dump_find_curproc(void) 1338 0 stevel { 1339 0 stevel uintptr_t pidp; 1340 0 stevel pid_t pid = -1; 1341 0 stevel 1342 0 stevel if (mdb_readvar(&pidp, "dump_pids") == sizeof (pidp) && 1343 0 stevel mdb_vread(&pid, sizeof (pid), pidp) == sizeof (pid) && 1344 0 stevel pid > 0) 1345 0 stevel return (pid); 1346 0 stevel else 1347 0 stevel return (-1); 1348 0 stevel } 1349 0 stevel 1350 0 stevel 1351 0 stevel /* 1352 0 stevel * Following three funcs extracted from sunddi.c 1353 0 stevel */ 1354 0 stevel 1355 0 stevel /* 1356 0 stevel * Return core address of root node of devinfo tree 1357 0 stevel */ 1358 0 stevel static uintptr_t 1359 0 stevel mdb_ddi_root_node(void) 1360 0 stevel { 1361 0 stevel uintptr_t top_devinfo_addr; 1362 0 stevel 1363 0 stevel /* return (top_devinfo); */ 1364 0 stevel if (mdb_readvar(&top_devinfo_addr, "top_devinfo") == -1) { 1365 0 stevel mdb_warn("failed to read top_devinfo"); 1366 0 stevel return (NULL); 1367 0 stevel } 1368 0 stevel return (top_devinfo_addr); 1369 0 stevel } 1370 0 stevel 1371 0 stevel /* 1372 0 stevel * Return the name of the devinfo node pointed at by 'dip_addr' in the buffer 1373 0 stevel * pointed at by 'name.' 1374 0 stevel * 1375 0 stevel * - dip_addr is a pointer to a dev_info struct in core. 1376 0 stevel */ 1377 0 stevel static char * 1378 0 stevel mdb_ddi_deviname(uintptr_t dip_addr, char *name, size_t name_size) 1379 0 stevel { 1380 0 stevel uintptr_t addrname; 1381 0 stevel ssize_t length; 1382 0 stevel char *local_namep = name; 1383 0 stevel size_t local_name_size = name_size; 1384 0 stevel struct dev_info local_dip; 1385 0 stevel 1386 0 stevel 1387 0 stevel if (dip_addr == mdb_ddi_root_node()) { 1388 0 stevel if (name_size < 1) { 1389 0 stevel mdb_warn("failed to get node name: buf too small\n"); 1390 0 stevel return (NULL); 1391 0 stevel } 1392 0 stevel 1393 0 stevel *name = '\0'; 1394 0 stevel return (name); 1395 0 stevel } 1396 0 stevel 1397 0 stevel if (name_size < 2) { 1398 0 stevel mdb_warn("failed to get node name: buf too small\n"); 1399 0 stevel return (NULL); 1400 0 stevel } 1401 0 stevel 1402 0 stevel local_namep = name; 1403 0 stevel *local_namep++ = '/'; 1404 0 stevel *local_namep = '\0'; 1405 0 stevel local_name_size--; 1406 0 stevel 1407 0 stevel if (mdb_vread(&local_dip, sizeof (struct dev_info), dip_addr) == -1) { 1408 0 stevel mdb_warn("failed to read devinfo struct"); 1409 0 stevel } 1410 0 stevel 1411 0 stevel length = mdb_readstr(local_namep, local_name_size, 1412 0 stevel (uintptr_t)local_dip.devi_node_name); 1413 0 stevel if (length == -1) { 1414 0 stevel mdb_warn("failed to read node name"); 1415 0 stevel return (NULL); 1416 0 stevel } 1417 0 stevel local_namep += length; 1418 0 stevel local_name_size -= length; 1419 0 stevel addrname = (uintptr_t)local_dip.devi_addr; 1420 0 stevel 1421 0 stevel if (addrname != NULL) { 1422 0 stevel 1423 0 stevel if (local_name_size < 2) { 1424 0 stevel mdb_warn("not enough room for node address string"); 1425 0 stevel return (name); 1426 0 stevel } 1427 0 stevel *local_namep++ = '@'; 1428 0 stevel *local_namep = '\0'; 1429 0 stevel local_name_size--; 1430 0 stevel 1431 0 stevel length = mdb_readstr(local_namep, local_name_size, addrname); 1432 0 stevel if (length == -1) { 1433 0 stevel mdb_warn("failed to read name"); 1434 0 stevel return (NULL); 1435 0 stevel } 1436 0 stevel } 1437 0 stevel 1438 0 stevel return (name); 1439 0 stevel } 1440 0 stevel 1441 0 stevel /* 1442 0 stevel * Generate the full path under the /devices dir to the device entry. 1443 0 stevel * 1444 0 stevel * dip is a pointer to a devinfo struct in core (not in local memory). 1445 0 stevel */ 1446 0 stevel char * 1447 0 stevel mdb_ddi_pathname(uintptr_t dip_addr, char *path, size_t pathlen) 1448 0 stevel { 1449 0 stevel struct dev_info local_dip; 1450 0 stevel uintptr_t parent_dip; 1451 0 stevel char *bp; 1452 0 stevel size_t buf_left; 1453 0 stevel 1454 0 stevel 1455 0 stevel if (dip_addr == mdb_ddi_root_node()) { 1456 0 stevel *path = '\0'; 1457 0 stevel return (path); 1458 0 stevel } 1459 0 stevel 1460 0 stevel 1461 0 stevel if (mdb_vread(&local_dip, sizeof (struct dev_info), dip_addr) == -1) { 1462 0 stevel mdb_warn("failed to read devinfo struct"); 1463 0 stevel } 1464 0 stevel 1465 0 stevel parent_dip = (uintptr_t)local_dip.devi_parent; 1466 0 stevel (void) mdb_ddi_pathname(parent_dip, path, pathlen); 1467 0 stevel 1468 0 stevel bp = path + strlen(path); 1469 0 stevel buf_left = pathlen - strlen(path); 1470 0 stevel (void) mdb_ddi_deviname(dip_addr, bp, buf_left); 1471 0 stevel return (path); 1472 0 stevel } 1473 0 stevel 1474 0 stevel 1475 0 stevel /* 1476 0 stevel * Read in the string value of a refstr, which is appended to the end of 1477 0 stevel * the structure. 1478 0 stevel */ 1479 0 stevel ssize_t 1480 0 stevel mdb_read_refstr(uintptr_t refstr_addr, char *str, size_t nbytes) 1481 0 stevel { 1482 0 stevel struct refstr *r = (struct refstr *)refstr_addr; 1483 0 stevel 1484 0 stevel return (mdb_readstr(str, nbytes, (uintptr_t)r->rs_string)); 1485 0 stevel } 1486 2546 carlsonj 1487 2546 carlsonj /* 1488 2546 carlsonj * Chase an mblk list by b_next and return the length. 1489 2546 carlsonj */ 1490 2546 carlsonj int 1491 2546 carlsonj mdb_mblk_count(const mblk_t *mb) 1492 2546 carlsonj { 1493 2546 carlsonj int count; 1494 2546 carlsonj mblk_t mblk; 1495 2546 carlsonj 1496 2546 carlsonj if (mb == NULL) 1497 2546 carlsonj return (0); 1498 2546 carlsonj 1499 2546 carlsonj count = 1; 1500 2546 carlsonj while (mb->b_next != NULL) { 1501 2546 carlsonj count++; 1502 2546 carlsonj if (mdb_vread(&mblk, sizeof (mblk), (uintptr_t)mb->b_next) == 1503 2546 carlsonj -1) 1504 2546 carlsonj break; 1505 2546 carlsonj mb = &mblk; 1506 2546 carlsonj } 1507 2546 carlsonj return (count); 1508 2546 carlsonj } 1509 2546 carlsonj 1510 2546 carlsonj /* 1511 2546 carlsonj * Write the given MAC address as a printable string in the usual colon- 1512 2546 carlsonj * separated format. Assumes that buflen is at least 2. 1513 2546 carlsonj */ 1514 2546 carlsonj void 1515 2546 carlsonj mdb_mac_addr(const uint8_t *addr, size_t alen, char *buf, size_t buflen) 1516 2546 carlsonj { 1517 2546 carlsonj int slen; 1518 2546 carlsonj 1519 2546 carlsonj if (alen == 0 || buflen < 4) { 1520 2546 carlsonj (void) strcpy(buf, "?"); 1521 2546 carlsonj return; 1522 2546 carlsonj } 1523 2546 carlsonj for (;;) { 1524 2546 carlsonj /* 1525 2546 carlsonj * If there are more MAC address bytes available, but we won't 1526 2546 carlsonj * have any room to print them, then add "..." to the string 1527 2546 carlsonj * instead. See below for the 'magic number' explanation. 1528 2546 carlsonj */ 1529 2546 carlsonj if ((alen == 2 && buflen < 6) || (alen > 2 && buflen < 7)) { 1530 2546 carlsonj (void) strcpy(buf, "..."); 1531 2546 carlsonj break; 1532 2546 carlsonj } 1533 2546 carlsonj slen = mdb_snprintf(buf, buflen, "%02x", *addr++); 1534 2546 carlsonj buf += slen; 1535 2546 carlsonj if (--alen == 0) 1536 2546 carlsonj break; 1537 2546 carlsonj *buf++ = ':'; 1538 2546 carlsonj buflen -= slen + 1; 1539 2546 carlsonj /* 1540 2546 carlsonj * At this point, based on the first 'if' statement above, 1541 2546 carlsonj * either alen == 1 and buflen >= 3, or alen > 1 and 1542 2546 carlsonj * buflen >= 4. The first case leaves room for the final "xx" 1543 2546 carlsonj * number and trailing NUL byte. The second leaves room for at 1544 2546 carlsonj * least "...". Thus the apparently 'magic' numbers chosen for 1545 2546 carlsonj * that statement. 1546 2546 carlsonj */ 1547 2546 carlsonj } 1548 2546 carlsonj } 1549 2546 carlsonj 1550 2546 carlsonj /* 1551 2546 carlsonj * Produce a string that represents a DLPI primitive, or NULL if no such string 1552 2546 carlsonj * is possible. 1553 2546 carlsonj */ 1554 2546 carlsonj const char * 1555 2546 carlsonj mdb_dlpi_prim(int prim) 1556 2546 carlsonj { 1557 2546 carlsonj switch (prim) { 1558 2546 carlsonj case DL_INFO_REQ: return ("DL_INFO_REQ"); 1559 2546 carlsonj case DL_INFO_ACK: return ("DL_INFO_ACK"); 1560 2546 carlsonj case DL_ATTACH_REQ: return ("DL_ATTACH_REQ"); 1561 2546 carlsonj case DL_DETACH_REQ: return ("DL_DETACH_REQ"); 1562 2546 carlsonj case DL_BIND_REQ: return ("DL_BIND_REQ"); 1563 2546 carlsonj case DL_BIND_ACK: return ("DL_BIND_ACK"); 1564 2546 carlsonj case DL_UNBIND_REQ: return ("DL_UNBIND_REQ"); 1565 2546 carlsonj case DL_OK_ACK: return ("DL_OK_ACK"); 1566 2546 carlsonj case DL_ERROR_ACK: return ("DL_ERROR_ACK"); 1567 2546 carlsonj case DL_ENABMULTI_REQ: return ("DL_ENABMULTI_REQ"); 1568 2546 carlsonj case DL_DISABMULTI_REQ: return ("DL_DISABMULTI_REQ"); 1569 2546 carlsonj case DL_PROMISCON_REQ: return ("DL_PROMISCON_REQ"); 1570 2546 carlsonj case DL_PROMISCOFF_REQ: return ("DL_PROMISCOFF_REQ"); 1571 2546 carlsonj case DL_UNITDATA_REQ: return ("DL_UNITDATA_REQ"); 1572 2546 carlsonj case DL_UNITDATA_IND: return ("DL_UNITDATA_IND"); 1573 2546 carlsonj case DL_UDERROR_IND: return ("DL_UDERROR_IND"); 1574 2546 carlsonj case DL_PHYS_ADDR_REQ: return ("DL_PHYS_ADDR_REQ"); 1575 2546 carlsonj case DL_PHYS_ADDR_ACK: return ("DL_PHYS_ADDR_ACK"); 1576 2546 carlsonj case DL_SET_PHYS_ADDR_REQ: return ("DL_SET_PHYS_ADDR_REQ"); 1577 2546 carlsonj case DL_NOTIFY_REQ: return ("DL_NOTIFY_REQ"); 1578 2546 carlsonj case DL_NOTIFY_ACK: return ("DL_NOTIFY_ACK"); 1579 2546 carlsonj case DL_NOTIFY_IND: return ("DL_NOTIFY_IND"); 1580 9073 Cathy case DL_NOTIFY_CONF: return ("DL_NOTIFY_CONF"); 1581 2546 carlsonj case DL_CAPABILITY_REQ: return ("DL_CAPABILITY_REQ"); 1582 2546 carlsonj case DL_CAPABILITY_ACK: return ("DL_CAPABILITY_ACK"); 1583 2546 carlsonj case DL_CONTROL_REQ: return ("DL_CONTROL_REQ"); 1584 2546 carlsonj case DL_CONTROL_ACK: return ("DL_CONTROL_ACK"); 1585 2546 carlsonj case DL_PASSIVE_REQ: return ("DL_PASSIVE_REQ"); 1586 2546 carlsonj default: return (NULL); 1587 2546 carlsonj } 1588 2546 carlsonj } 1589 11066 rafael 1590 11066 rafael /* 1591 11066 rafael * mdb_gethrtime() returns the hires system time. This will be the timestamp at 1592 11066 rafael * which we dropped into, if called from, kmdb(1); the core dump's hires time 1593 11066 rafael * if inspecting one; or the running system's hires time if we're inspecting 1594 11066 rafael * a live kernel. 1595 11066 rafael */ 1596 11066 rafael hrtime_t 1597 11066 rafael mdb_gethrtime(void) 1598 11066 rafael { 1599 11066 rafael uintptr_t ptr; 1600 11066 rafael lbolt_info_t lbi; 1601 11066 rafael hrtime_t ts; 1602 11066 rafael 1603 11066 rafael #ifdef _KMDB 1604 11066 rafael if (mdb_readvar(&ptr, "lb_info") == -1) 1605 11066 rafael return (0); 1606 11066 rafael 1607 11066 rafael if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) != 1608 11066 rafael sizeof (lbolt_info_t)) 1609 11066 rafael return (0); 1610 11066 rafael 1611 11066 rafael ts = lbi.lbi_debug_ts; 1612 11066 rafael #else 1613 11066 rafael if (mdb_prop_postmortem) { 1614 11066 rafael if (mdb_readvar(&ptr, "lb_info") == -1) 1615 11066 rafael return (0); 1616 11066 rafael 1617 11066 rafael if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) != 1618 11066 rafael sizeof (lbolt_info_t)) 1619 11066 rafael return (0); 1620 11066 rafael 1621 11066 rafael ts = lbi.lbi_debug_ts; 1622 11066 rafael } else { 1623 11066 rafael ts = gethrtime(); 1624 11066 rafael } 1625 11066 rafael #endif 1626 11066 rafael return (ts); 1627 11066 rafael } 1628 11066 rafael 1629 11066 rafael /* 1630 11066 rafael * mdb_get_lbolt() returns the number of clock ticks since system boot. 1631 11066 rafael * Depending on the context in which it's called, the value will be derived 1632 11066 rafael * from different sources per mdb_gethrtime(). If inspecting a panicked 1633 11066 rafael * system, the routine returns the 'panic_lbolt64' variable from the core file. 1634 11066 rafael */ 1635 11066 rafael int64_t 1636 11066 rafael mdb_get_lbolt(void) 1637 11066 rafael { 1638 11066 rafael lbolt_info_t lbi; 1639 11066 rafael uintptr_t ptr; 1640 11066 rafael int64_t pl; 1641 11066 rafael hrtime_t ts; 1642 11066 rafael int nsec; 1643 11066 rafael 1644 11066 rafael if (mdb_readvar(&pl, "panic_lbolt64") != -1 && pl > 0) 1645 11066 rafael return (pl); 1646 11066 rafael 1647 11066 rafael /* 1648 11066 rafael * Load the time spent in kmdb, if any. 1649 11066 rafael */ 1650 11066 rafael if (mdb_readvar(&ptr, "lb_info") == -1) 1651 11066 rafael return (0); 1652 11066 rafael 1653 11066 rafael if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) != 1654 11066 rafael sizeof (lbolt_info_t)) 1655 11066 rafael return (0); 1656 11066 rafael 1657 11066 rafael if ((ts = mdb_gethrtime()) <= 0) 1658 11066 rafael return (0); 1659 11066 rafael 1660 11066 rafael if (mdb_readvar(&nsec, "nsec_per_tick") == -1 || nsec == 0) { 1661 11066 rafael mdb_warn("failed to read 'nsec_per_tick'"); 1662 11066 rafael return (-1); 1663 11066 rafael } 1664 11066 rafael 1665 11066 rafael return ((ts/nsec) - lbi.lbi_debug_time); 1666 11066 rafael } 1667