1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <string.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/modhash_impl.h> 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 33*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_ks.h> 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include "modhash.h" 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate /* This is passed to the modent callback; allows caller to get context */ 38*7c478bd9Sstevel@tonic-gate typedef struct modent_step_data_s { 39*7c478bd9Sstevel@tonic-gate struct mod_hash_entry msd_mhe; /* must be first */ 40*7c478bd9Sstevel@tonic-gate int msd_hash_index; 41*7c478bd9Sstevel@tonic-gate int msd_position; /* entry position in chain */ 42*7c478bd9Sstevel@tonic-gate uintptr_t msd_first_addr; /* first address in chain */ 43*7c478bd9Sstevel@tonic-gate } modent_step_data_t; 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate /* Context for a walk over a modhash (variable length) */ 46*7c478bd9Sstevel@tonic-gate typedef struct hash_walk_s { 47*7c478bd9Sstevel@tonic-gate modent_step_data_t hwalk_msd; /* current entry data */ 48*7c478bd9Sstevel@tonic-gate mod_hash_t hwalk_hash; /* always last (var. len) */ 49*7c478bd9Sstevel@tonic-gate } hash_walk_t; 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* Computes number of bytes to allocate for hash_walk_t structure. */ 52*7c478bd9Sstevel@tonic-gate #define HW_SIZE(n) (sizeof (modent_step_data_t) + MH_SIZE(n)) 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* Used for decoding hash keys for display */ 55*7c478bd9Sstevel@tonic-gate typedef struct hash_type_entry_s { 56*7c478bd9Sstevel@tonic-gate const char *hte_type; /* name of hash type for ::modent -t */ 57*7c478bd9Sstevel@tonic-gate const char *hte_comparator; /* name of comparator function */ 58*7c478bd9Sstevel@tonic-gate void (*hte_format)(const mod_hash_key_t, char *, size_t); 59*7c478bd9Sstevel@tonic-gate } hash_type_entry_t; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate static void format_strhash(const mod_hash_key_t, char *, size_t); 62*7c478bd9Sstevel@tonic-gate static void format_ptrhash(const mod_hash_key_t, char *, size_t); 63*7c478bd9Sstevel@tonic-gate static void format_idhash(const mod_hash_key_t, char *, size_t); 64*7c478bd9Sstevel@tonic-gate static void format_default(const mod_hash_key_t, char *, size_t); 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate static const hash_type_entry_t hte_table[] = { 67*7c478bd9Sstevel@tonic-gate { "str", "mod_hash_strkey_cmp", format_strhash }, 68*7c478bd9Sstevel@tonic-gate { "ptr", "mod_hash_ptrkey_cmp", format_ptrhash }, 69*7c478bd9Sstevel@tonic-gate { "id", "mod_hash_idkey_cmp", format_idhash }, 70*7c478bd9Sstevel@tonic-gate { NULL, NULL, format_default } 71*7c478bd9Sstevel@tonic-gate }; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate static int modent_print(uintptr_t, int, uint_t, const hash_type_entry_t *, 74*7c478bd9Sstevel@tonic-gate boolean_t, uint_t, uint_t); 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate /* The information used during a walk */ 77*7c478bd9Sstevel@tonic-gate typedef struct mod_walk_data_s { 78*7c478bd9Sstevel@tonic-gate const hash_type_entry_t *mwd_hte; /* pointer to entry type */ 79*7c478bd9Sstevel@tonic-gate int mwd_main_flags; /* ::modhash flags */ 80*7c478bd9Sstevel@tonic-gate int mwd_flags; /* DCMD_* flags for looping */ 81*7c478bd9Sstevel@tonic-gate uint_t mwd_opt_e; /* call-modent mode */ 82*7c478bd9Sstevel@tonic-gate uint_t mwd_opt_c; /* chain head only mode */ 83*7c478bd9Sstevel@tonic-gate uint_t mwd_opt_h; /* hash index output */ 84*7c478bd9Sstevel@tonic-gate boolean_t mwd_opt_k_set; /* key supplied */ 85*7c478bd9Sstevel@tonic-gate boolean_t mwd_opt_v_set; /* value supplied */ 86*7c478bd9Sstevel@tonic-gate uintptr_t mwd_opt_k; /* key */ 87*7c478bd9Sstevel@tonic-gate uintptr_t mwd_opt_v; /* value */ 88*7c478bd9Sstevel@tonic-gate int mwd_maxposn; /* len of longest chain - 1 */ 89*7c478bd9Sstevel@tonic-gate int mwd_maxidx; /* hash idx of longest chain */ 90*7c478bd9Sstevel@tonic-gate uintptr_t mwd_maxaddr; /* addr of 1st elem @ maxidx */ 91*7c478bd9Sstevel@tonic-gate uintptr_t mwd_idxtoprint; /* desired hash pos to print */ 92*7c478bd9Sstevel@tonic-gate uintptr_t mwd_addr; /* 1st elem addr @idxtoprint */ 93*7c478bd9Sstevel@tonic-gate } mod_walk_data_t; 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* 96*7c478bd9Sstevel@tonic-gate * Initialize a walk over all the modhashes in the system. 97*7c478bd9Sstevel@tonic-gate */ 98*7c478bd9Sstevel@tonic-gate int 99*7c478bd9Sstevel@tonic-gate modhash_walk_init(mdb_walk_state_t *wsp) 100*7c478bd9Sstevel@tonic-gate { 101*7c478bd9Sstevel@tonic-gate mod_hash_t *mh_head; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate if (mdb_readvar(&mh_head, "mh_head") == -1) { 104*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read mh_head"); 105*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 106*7c478bd9Sstevel@tonic-gate } 107*7c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)mh_head; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate return (WALK_NEXT); 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * Step to the next modhash in the system. 114*7c478bd9Sstevel@tonic-gate */ 115*7c478bd9Sstevel@tonic-gate int 116*7c478bd9Sstevel@tonic-gate modhash_walk_step(mdb_walk_state_t *wsp) 117*7c478bd9Sstevel@tonic-gate { 118*7c478bd9Sstevel@tonic-gate mod_hash_t mh; 119*7c478bd9Sstevel@tonic-gate int status; 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 122*7c478bd9Sstevel@tonic-gate return (WALK_DONE); 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate if (mdb_vread(&mh, sizeof (mh), wsp->walk_addr) == -1) { 125*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read mod_hash_t at %p", wsp->walk_addr); 126*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &mh, wsp->walk_cbdata); 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)mh.mh_next; 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate return (status); 134*7c478bd9Sstevel@tonic-gate } 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate /* 137*7c478bd9Sstevel@tonic-gate * Initialize a walk over the entries in a given modhash. 138*7c478bd9Sstevel@tonic-gate */ 139*7c478bd9Sstevel@tonic-gate int 140*7c478bd9Sstevel@tonic-gate modent_walk_init(mdb_walk_state_t *wsp) 141*7c478bd9Sstevel@tonic-gate { 142*7c478bd9Sstevel@tonic-gate mod_hash_t mh; 143*7c478bd9Sstevel@tonic-gate hash_walk_t *hwp; 144*7c478bd9Sstevel@tonic-gate int retv; 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) { 147*7c478bd9Sstevel@tonic-gate mdb_warn("mod_hash_t address required\n"); 148*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate if (mdb_vread(&mh, sizeof (mh), wsp->walk_addr) == -1) { 152*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read mod_hash_t at %p", wsp->walk_addr); 153*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate if (mh.mh_nchains <= 1) { 157*7c478bd9Sstevel@tonic-gate mdb_warn("impossible number of chains in mod_hash_t at %p", 158*7c478bd9Sstevel@tonic-gate wsp->walk_addr); 159*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * If the user presents us with a garbage pointer, and thus the number 164*7c478bd9Sstevel@tonic-gate * of chains is just absurd, we don't want to bail out of mdb. Fail to 165*7c478bd9Sstevel@tonic-gate * walk instead. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate hwp = mdb_alloc(HW_SIZE(mh.mh_nchains), UM_NOSLEEP); 168*7c478bd9Sstevel@tonic-gate if (hwp == NULL) { 169*7c478bd9Sstevel@tonic-gate mdb_warn("unable to allocate %#x bytes for mod_hash_t at %p", 170*7c478bd9Sstevel@tonic-gate HW_SIZE(mh.mh_nchains), wsp->walk_addr); 171*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate (void) memcpy(&hwp->hwalk_hash, &mh, sizeof (hwp->hwalk_hash)); 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate retv = mdb_vread(hwp->hwalk_hash.mh_entries + 1, 177*7c478bd9Sstevel@tonic-gate (mh.mh_nchains - 1) * sizeof (struct mod_hash_entry *), 178*7c478bd9Sstevel@tonic-gate wsp->walk_addr + sizeof (mh)); 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate if (retv == -1) { 181*7c478bd9Sstevel@tonic-gate mdb_free(hwp, HW_SIZE(mh.mh_nchains)); 182*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read %#x mod_hash_entry pointers at %p", 183*7c478bd9Sstevel@tonic-gate mh.mh_nchains - 1, wsp->walk_addr + sizeof (mh)); 184*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate hwp->hwalk_msd.msd_hash_index = -1; 188*7c478bd9Sstevel@tonic-gate hwp->hwalk_msd.msd_position = 0; 189*7c478bd9Sstevel@tonic-gate hwp->hwalk_msd.msd_first_addr = NULL; 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate wsp->walk_addr = NULL; 192*7c478bd9Sstevel@tonic-gate wsp->walk_data = hwp; 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate return (WALK_NEXT); 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /* 198*7c478bd9Sstevel@tonic-gate * Step to the next entry in the modhash. 199*7c478bd9Sstevel@tonic-gate */ 200*7c478bd9Sstevel@tonic-gate int 201*7c478bd9Sstevel@tonic-gate modent_walk_step(mdb_walk_state_t *wsp) 202*7c478bd9Sstevel@tonic-gate { 203*7c478bd9Sstevel@tonic-gate hash_walk_t *hwp = wsp->walk_data; 204*7c478bd9Sstevel@tonic-gate int status; 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate while (wsp->walk_addr == NULL) { 207*7c478bd9Sstevel@tonic-gate hwp->hwalk_msd.msd_position = 0; 208*7c478bd9Sstevel@tonic-gate if (++hwp->hwalk_msd.msd_hash_index >= 209*7c478bd9Sstevel@tonic-gate hwp->hwalk_hash.mh_nchains) 210*7c478bd9Sstevel@tonic-gate return (WALK_DONE); 211*7c478bd9Sstevel@tonic-gate wsp->walk_addr = hwp->hwalk_msd.msd_first_addr = 212*7c478bd9Sstevel@tonic-gate (uintptr_t)hwp->hwalk_hash.mh_entries[ 213*7c478bd9Sstevel@tonic-gate hwp->hwalk_msd.msd_hash_index]; 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate if (mdb_vread(&hwp->hwalk_msd.msd_mhe, sizeof (hwp->hwalk_msd.msd_mhe), 217*7c478bd9Sstevel@tonic-gate wsp->walk_addr) == -1) { 218*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read mod_hash_entry at %p", 219*7c478bd9Sstevel@tonic-gate wsp->walk_addr); 220*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &hwp->hwalk_msd, 224*7c478bd9Sstevel@tonic-gate wsp->walk_cbdata); 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate hwp->hwalk_msd.msd_position++; 227*7c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)hwp->hwalk_msd.msd_mhe.mhe_next; 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate return (status); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate /* 233*7c478bd9Sstevel@tonic-gate * Clean up after walking the entries in a modhash. 234*7c478bd9Sstevel@tonic-gate */ 235*7c478bd9Sstevel@tonic-gate void 236*7c478bd9Sstevel@tonic-gate modent_walk_fini(mdb_walk_state_t *wsp) 237*7c478bd9Sstevel@tonic-gate { 238*7c478bd9Sstevel@tonic-gate hash_walk_t *hwp = wsp->walk_data; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate mdb_free(hwp, HW_SIZE(hwp->hwalk_hash.mh_nchains)); 241*7c478bd9Sstevel@tonic-gate wsp->walk_data = NULL; 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * Step to next entry on a hash chain. 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate int 248*7c478bd9Sstevel@tonic-gate modchain_walk_step(mdb_walk_state_t *wsp) 249*7c478bd9Sstevel@tonic-gate { 250*7c478bd9Sstevel@tonic-gate struct mod_hash_entry mhe; 251*7c478bd9Sstevel@tonic-gate int status; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 254*7c478bd9Sstevel@tonic-gate return (WALK_DONE); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate if (mdb_vread(&mhe, sizeof (mhe), wsp->walk_addr) == -1) { 257*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read mod_hash_entry at %p", 258*7c478bd9Sstevel@tonic-gate wsp->walk_addr); 259*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &mhe, wsp->walk_cbdata); 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)mhe.mhe_next; 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate return (status); 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* 270*7c478bd9Sstevel@tonic-gate * This is called by ::modhash (via a callback) when gathering data about the 271*7c478bd9Sstevel@tonic-gate * entries in a given modhash. It keeps track of the longest chain, finds a 272*7c478bd9Sstevel@tonic-gate * specific entry (if the user requested one) and prints out a summary of the 273*7c478bd9Sstevel@tonic-gate * entry or entries. 274*7c478bd9Sstevel@tonic-gate */ 275*7c478bd9Sstevel@tonic-gate static int 276*7c478bd9Sstevel@tonic-gate modent_format(uintptr_t addr, const void *data, void *private) 277*7c478bd9Sstevel@tonic-gate { 278*7c478bd9Sstevel@tonic-gate const modent_step_data_t *msd = data; 279*7c478bd9Sstevel@tonic-gate mod_walk_data_t *mwd = private; 280*7c478bd9Sstevel@tonic-gate int retv = DCMD_OK; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* If this chain is longest seen, then save start of chain */ 283*7c478bd9Sstevel@tonic-gate if (msd->msd_position > mwd->mwd_maxposn) { 284*7c478bd9Sstevel@tonic-gate mwd->mwd_maxposn = msd->msd_position; 285*7c478bd9Sstevel@tonic-gate mwd->mwd_maxidx = msd->msd_hash_index; 286*7c478bd9Sstevel@tonic-gate mwd->mwd_maxaddr = msd->msd_first_addr; 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate /* If the user specified a particular chain, then ignore others */ 290*7c478bd9Sstevel@tonic-gate if (mwd->mwd_idxtoprint != (uintptr_t)-1) { 291*7c478bd9Sstevel@tonic-gate /* Save address of *first* entry */ 292*7c478bd9Sstevel@tonic-gate if (mwd->mwd_idxtoprint == msd->msd_hash_index) 293*7c478bd9Sstevel@tonic-gate mwd->mwd_addr = msd->msd_first_addr; 294*7c478bd9Sstevel@tonic-gate else 295*7c478bd9Sstevel@tonic-gate return (retv); 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate /* If the user specified a particular key, ignore others. */ 299*7c478bd9Sstevel@tonic-gate if (mwd->mwd_opt_k_set && 300*7c478bd9Sstevel@tonic-gate (uintptr_t)msd->msd_mhe.mhe_key != mwd->mwd_opt_k) 301*7c478bd9Sstevel@tonic-gate return (retv); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* If the user specified a particular value, ignore others. */ 304*7c478bd9Sstevel@tonic-gate if (mwd->mwd_opt_v_set && 305*7c478bd9Sstevel@tonic-gate (uintptr_t)msd->msd_mhe.mhe_val != mwd->mwd_opt_v) 306*7c478bd9Sstevel@tonic-gate return (retv); 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate /* If the user just wants the chain heads, skip intermediate nodes. */ 309*7c478bd9Sstevel@tonic-gate if (mwd->mwd_opt_c && msd->msd_position != 0) 310*7c478bd9Sstevel@tonic-gate return (retv); 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate /* If the user asked to have the entries printed, then do that. */ 313*7c478bd9Sstevel@tonic-gate if (mwd->mwd_opt_e) { 314*7c478bd9Sstevel@tonic-gate /* If the output is to a pipeline, just print addresses */ 315*7c478bd9Sstevel@tonic-gate if (mwd->mwd_main_flags & DCMD_PIPE_OUT) 316*7c478bd9Sstevel@tonic-gate mdb_printf("%p\n", addr); 317*7c478bd9Sstevel@tonic-gate else 318*7c478bd9Sstevel@tonic-gate retv = modent_print(addr, msd->msd_hash_index, 319*7c478bd9Sstevel@tonic-gate mwd->mwd_flags, mwd->mwd_hte, mwd->mwd_opt_h, 0, 0); 320*7c478bd9Sstevel@tonic-gate mwd->mwd_flags &= ~DCMD_LOOPFIRST; 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate return (retv); 323*7c478bd9Sstevel@tonic-gate } 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate void 326*7c478bd9Sstevel@tonic-gate modhash_help(void) 327*7c478bd9Sstevel@tonic-gate { 328*7c478bd9Sstevel@tonic-gate mdb_printf("Prints information about one or all mod_hash_t databases " 329*7c478bd9Sstevel@tonic-gate "in the system.\n" 330*7c478bd9Sstevel@tonic-gate "This command has three basic forms, summarized below.\n\n" 331*7c478bd9Sstevel@tonic-gate " ::modhash [-t]\n <addr>::modhash\n" 332*7c478bd9Sstevel@tonic-gate " <addr>::modhash -e [-ch] [-k key] [-v val] [-i index]\n\n" 333*7c478bd9Sstevel@tonic-gate "In the first form, no address is provided, and a summary of all " 334*7c478bd9Sstevel@tonic-gate "registered\n" 335*7c478bd9Sstevel@tonic-gate "hashes in the system is printed; adding the '-t' option shows" 336*7c478bd9Sstevel@tonic-gate " the hash\n" 337*7c478bd9Sstevel@tonic-gate "type instead of the limits. In the second form, the address of a" 338*7c478bd9Sstevel@tonic-gate " mod_hash_t\n" 339*7c478bd9Sstevel@tonic-gate "is provided, and the output is in a verbose format. The final " 340*7c478bd9Sstevel@tonic-gate "form prints\n" 341*7c478bd9Sstevel@tonic-gate "the elements of the hash, optionally selecting just those with a " 342*7c478bd9Sstevel@tonic-gate "particular\n" 343*7c478bd9Sstevel@tonic-gate "key, value, and/or hash index, or just the chain heads (-c). " 344*7c478bd9Sstevel@tonic-gate "The -h option\n" 345*7c478bd9Sstevel@tonic-gate "shows hash indices instead of addresses.\n"); 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate int 349*7c478bd9Sstevel@tonic-gate modhash(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 350*7c478bd9Sstevel@tonic-gate { 351*7c478bd9Sstevel@tonic-gate mod_hash_t mh; 352*7c478bd9Sstevel@tonic-gate char name[256]; 353*7c478bd9Sstevel@tonic-gate int len; 354*7c478bd9Sstevel@tonic-gate mod_walk_data_t mwd; 355*7c478bd9Sstevel@tonic-gate uint_t opt_s = FALSE; 356*7c478bd9Sstevel@tonic-gate uint_t opt_t = FALSE; 357*7c478bd9Sstevel@tonic-gate char kfunc[MDB_SYM_NAMLEN]; 358*7c478bd9Sstevel@tonic-gate const hash_type_entry_t *htep; 359*7c478bd9Sstevel@tonic-gate boolean_t elem_flags; 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate (void) memset(&mwd, 0, sizeof (mwd)); 362*7c478bd9Sstevel@tonic-gate mwd.mwd_main_flags = flags; 363*7c478bd9Sstevel@tonic-gate mwd.mwd_flags = DCMD_ADDRSPEC | DCMD_LOOP | DCMD_LOOPFIRST; 364*7c478bd9Sstevel@tonic-gate mwd.mwd_maxposn = -1; 365*7c478bd9Sstevel@tonic-gate mwd.mwd_idxtoprint = (uintptr_t)-1; 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate len = mdb_getopts(argc, argv, 368*7c478bd9Sstevel@tonic-gate 's', MDB_OPT_SETBITS, TRUE, &opt_s, 369*7c478bd9Sstevel@tonic-gate 't', MDB_OPT_SETBITS, TRUE, &opt_t, 370*7c478bd9Sstevel@tonic-gate 'c', MDB_OPT_SETBITS, TRUE, &mwd.mwd_opt_c, 371*7c478bd9Sstevel@tonic-gate 'e', MDB_OPT_SETBITS, TRUE, &mwd.mwd_opt_e, 372*7c478bd9Sstevel@tonic-gate 'h', MDB_OPT_SETBITS, TRUE, &mwd.mwd_opt_h, 373*7c478bd9Sstevel@tonic-gate 'i', MDB_OPT_UINTPTR, &mwd.mwd_idxtoprint, 374*7c478bd9Sstevel@tonic-gate 'k', MDB_OPT_UINTPTR_SET, &mwd.mwd_opt_k_set, &mwd.mwd_opt_k, 375*7c478bd9Sstevel@tonic-gate 'v', MDB_OPT_UINTPTR_SET, &mwd.mwd_opt_v_set, &mwd.mwd_opt_v, 376*7c478bd9Sstevel@tonic-gate NULL); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate if (len < argc) { 379*7c478bd9Sstevel@tonic-gate argv += len; 380*7c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_STRING) 381*7c478bd9Sstevel@tonic-gate mdb_warn("unexpected argument: %s\n", 382*7c478bd9Sstevel@tonic-gate argv->a_un.a_str); 383*7c478bd9Sstevel@tonic-gate else 384*7c478bd9Sstevel@tonic-gate mdb_warn("unexpected argument(s)\n"); 385*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate /* true if any element-related flags are set */ 389*7c478bd9Sstevel@tonic-gate elem_flags = mwd.mwd_opt_c || mwd.mwd_opt_e || mwd.mwd_opt_h || 390*7c478bd9Sstevel@tonic-gate mwd.mwd_opt_k_set || mwd.mwd_opt_v_set || 391*7c478bd9Sstevel@tonic-gate mwd.mwd_idxtoprint != (uintptr_t)-1; 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 394*7c478bd9Sstevel@tonic-gate mdb_arg_t new_argv[1]; 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate if (elem_flags) { 397*7c478bd9Sstevel@tonic-gate /* 398*7c478bd9Sstevel@tonic-gate * This isn't allowed so that the output doesn't become 399*7c478bd9Sstevel@tonic-gate * a confusing mix of hash table descriptions and 400*7c478bd9Sstevel@tonic-gate * element entries. 401*7c478bd9Sstevel@tonic-gate */ 402*7c478bd9Sstevel@tonic-gate mdb_warn("printing elements from all hashes is not " 403*7c478bd9Sstevel@tonic-gate "permitted\n"); 404*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate /* we force short mode here, no matter what he says */ 407*7c478bd9Sstevel@tonic-gate new_argv[0].a_type = MDB_TYPE_STRING; 408*7c478bd9Sstevel@tonic-gate new_argv[0].a_un.a_str = opt_t ? "-st" : "-s"; 409*7c478bd9Sstevel@tonic-gate if (mdb_walk_dcmd("modhash", "modhash", 1, new_argv) == -1) { 410*7c478bd9Sstevel@tonic-gate mdb_warn("can't walk mod_hash structures"); 411*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate if (mwd.mwd_opt_e) { 417*7c478bd9Sstevel@tonic-gate if (opt_s | opt_t) { 418*7c478bd9Sstevel@tonic-gate mdb_warn("hash summary options not permitted when " 419*7c478bd9Sstevel@tonic-gate "displaying elements\n"); 420*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate } else { 423*7c478bd9Sstevel@tonic-gate if (elem_flags) { 424*7c478bd9Sstevel@tonic-gate /* 425*7c478bd9Sstevel@tonic-gate * This isn't allowed so that the output doesn't become 426*7c478bd9Sstevel@tonic-gate * a confusing mix of hash table description and 427*7c478bd9Sstevel@tonic-gate * element entries. 428*7c478bd9Sstevel@tonic-gate */ 429*7c478bd9Sstevel@tonic-gate mdb_warn("printing elements requires -e\n"); 430*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate } 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate if (mdb_vread(&mh, sizeof (mh), addr) == -1) { 435*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read mod_hash_t at %p", addr); 436*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate if (mwd.mwd_idxtoprint != (uintptr_t)-1 && 440*7c478bd9Sstevel@tonic-gate mwd.mwd_idxtoprint >= mh.mh_nchains) { 441*7c478bd9Sstevel@tonic-gate mdb_warn("mod_hash chain index %x out of range 0..%x\n", 442*7c478bd9Sstevel@tonic-gate mwd.mwd_idxtoprint, mh.mh_nchains - 1); 443*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 444*7c478bd9Sstevel@tonic-gate } 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags) && opt_s) { 447*7c478bd9Sstevel@tonic-gate if (opt_t != 0) { 448*7c478bd9Sstevel@tonic-gate mdb_printf("%<u>%?s %6s %5s %?s %s%</u>\n", 449*7c478bd9Sstevel@tonic-gate "ADDR", "CHAINS", "ELEMS", "TYPE", "NAME"); 450*7c478bd9Sstevel@tonic-gate } else { 451*7c478bd9Sstevel@tonic-gate mdb_printf("%<u>%?s %6s %5s %6s %6s %s%</u>\n", 452*7c478bd9Sstevel@tonic-gate "ADDR", "CHAINS", "ELEMS", "MAXLEN", "MAXIDX", 453*7c478bd9Sstevel@tonic-gate "NAME"); 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate len = mdb_readstr(name, sizeof (name), (uintptr_t)mh.mh_name); 458*7c478bd9Sstevel@tonic-gate if (len < 0) 459*7c478bd9Sstevel@tonic-gate (void) strcpy(name, "??"); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate if (mdb_lookup_by_addr((uintptr_t)mh.mh_keycmp, MDB_SYM_EXACT, kfunc, 462*7c478bd9Sstevel@tonic-gate sizeof (kfunc), NULL) == -1) 463*7c478bd9Sstevel@tonic-gate kfunc[0] = '\0'; 464*7c478bd9Sstevel@tonic-gate for (htep = hte_table; htep->hte_type != NULL; htep++) 465*7c478bd9Sstevel@tonic-gate if (strcmp(kfunc, htep->hte_comparator) == 0) 466*7c478bd9Sstevel@tonic-gate break; 467*7c478bd9Sstevel@tonic-gate mwd.mwd_hte = htep; 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate if (!mwd.mwd_opt_e && !opt_s) { 470*7c478bd9Sstevel@tonic-gate mdb_printf("mod_hash_t %?p %s%s:\n", addr, name, 471*7c478bd9Sstevel@tonic-gate len == sizeof (name) ? "..." : ""); 472*7c478bd9Sstevel@tonic-gate mdb_printf("\tKey comparator: %?p %s\n", 473*7c478bd9Sstevel@tonic-gate mh.mh_keycmp, kfunc); 474*7c478bd9Sstevel@tonic-gate mdb_printf("\tType: %s\n", 475*7c478bd9Sstevel@tonic-gate htep->hte_type == NULL ? "unknown" : htep->hte_type); 476*7c478bd9Sstevel@tonic-gate mdb_printf("\tSleep flag = %s, alloc failed = %#x\n", 477*7c478bd9Sstevel@tonic-gate mh.mh_sleep ? "true" : "false", 478*7c478bd9Sstevel@tonic-gate mh.mh_stat.mhs_nomem); 479*7c478bd9Sstevel@tonic-gate mdb_printf("\tNumber of chains = %#x, elements = %#x\n", 480*7c478bd9Sstevel@tonic-gate mh.mh_nchains, mh.mh_stat.mhs_nelems); 481*7c478bd9Sstevel@tonic-gate mdb_printf("\tHits = %#x, misses = %#x, dups = %#x\n", 482*7c478bd9Sstevel@tonic-gate mh.mh_stat.mhs_hit, mh.mh_stat.mhs_miss, 483*7c478bd9Sstevel@tonic-gate mh.mh_stat.mhs_coll); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate if (mdb_pwalk("modent", modent_format, &mwd, addr) == -1) { 486*7c478bd9Sstevel@tonic-gate mdb_warn("can't walk mod_hash entries"); 487*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate if (opt_s) { 490*7c478bd9Sstevel@tonic-gate const char *tname; 491*7c478bd9Sstevel@tonic-gate char tbuf[64]; 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate if (htep->hte_type == NULL) { 494*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(tbuf, sizeof (tbuf), "%p", 495*7c478bd9Sstevel@tonic-gate mh.mh_keycmp); 496*7c478bd9Sstevel@tonic-gate tname = tbuf; 497*7c478bd9Sstevel@tonic-gate } else { 498*7c478bd9Sstevel@tonic-gate tname = htep->hte_type; 499*7c478bd9Sstevel@tonic-gate } 500*7c478bd9Sstevel@tonic-gate mdb_printf("%?p %6x %5x ", addr, mh.mh_nchains, 501*7c478bd9Sstevel@tonic-gate mh.mh_stat.mhs_nelems); 502*7c478bd9Sstevel@tonic-gate if (opt_t != 0) { 503*7c478bd9Sstevel@tonic-gate mdb_printf("%?s", tname); 504*7c478bd9Sstevel@tonic-gate } else { 505*7c478bd9Sstevel@tonic-gate mdb_printf("%6x %6x", mwd.mwd_maxposn + 1, 506*7c478bd9Sstevel@tonic-gate mwd.mwd_maxidx); 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate mdb_printf(" %s%s\n", name, len == sizeof (name) ? "..." : ""); 509*7c478bd9Sstevel@tonic-gate } else if (!mwd.mwd_opt_e) { 510*7c478bd9Sstevel@tonic-gate mdb_printf("\tMaximum chain length = %x (at index %x, first " 511*7c478bd9Sstevel@tonic-gate "entry %p)\n", mwd.mwd_maxposn + 1, mwd.mwd_maxidx, 512*7c478bd9Sstevel@tonic-gate mwd.mwd_maxaddr); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate static void 518*7c478bd9Sstevel@tonic-gate format_strhash(const mod_hash_key_t key, char *keystr, size_t keystrlen) 519*7c478bd9Sstevel@tonic-gate { 520*7c478bd9Sstevel@tonic-gate int len; 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(keystr, keystrlen, "%?p ", key); 523*7c478bd9Sstevel@tonic-gate len = strlen(keystr); 524*7c478bd9Sstevel@tonic-gate (void) mdb_readstr(keystr + len, keystrlen - len, (uintptr_t)key); 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate static void 528*7c478bd9Sstevel@tonic-gate format_ptrhash(const mod_hash_key_t key, char *keystr, size_t keystrlen) 529*7c478bd9Sstevel@tonic-gate { 530*7c478bd9Sstevel@tonic-gate int len; 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(keystr, keystrlen, "%?p ", key); 533*7c478bd9Sstevel@tonic-gate len = strlen(keystr); 534*7c478bd9Sstevel@tonic-gate (void) mdb_lookup_by_addr((uintptr_t)key, MDB_SYM_EXACT, keystr + len, 535*7c478bd9Sstevel@tonic-gate keystrlen - len, NULL); 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate static void 539*7c478bd9Sstevel@tonic-gate format_idhash(const mod_hash_key_t key, char *keystr, size_t keystrlen) 540*7c478bd9Sstevel@tonic-gate { 541*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(keystr, keystrlen, "%?x", (uint_t)(uintptr_t)key); 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate static void 545*7c478bd9Sstevel@tonic-gate format_default(const mod_hash_key_t key, char *keystr, size_t keystrlen) 546*7c478bd9Sstevel@tonic-gate { 547*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(keystr, keystrlen, "%?p", key); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate void 551*7c478bd9Sstevel@tonic-gate modent_help(void) 552*7c478bd9Sstevel@tonic-gate { 553*7c478bd9Sstevel@tonic-gate mdb_printf("Options are mutually exclusive:\n" 554*7c478bd9Sstevel@tonic-gate " -t <type> print key in symbolic form; <type> is one of str, " 555*7c478bd9Sstevel@tonic-gate "ptr, or id\n" 556*7c478bd9Sstevel@tonic-gate " -v print value pointer alone\n" 557*7c478bd9Sstevel@tonic-gate " -k print key pointer alone\n"); 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate static int 561*7c478bd9Sstevel@tonic-gate modent_print(uintptr_t addr, int hidx, uint_t flags, 562*7c478bd9Sstevel@tonic-gate const hash_type_entry_t *htep, boolean_t prtidx, uint_t opt_k, 563*7c478bd9Sstevel@tonic-gate uint_t opt_v) 564*7c478bd9Sstevel@tonic-gate { 565*7c478bd9Sstevel@tonic-gate char keystr[256]; 566*7c478bd9Sstevel@tonic-gate struct mod_hash_entry mhe; 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags) && opt_k == 0 && opt_v == 0) { 569*7c478bd9Sstevel@tonic-gate mdb_printf("%<u>%?s %?s %?s%</u>\n", 570*7c478bd9Sstevel@tonic-gate prtidx ? "HASH_IDX" : "ADDR", "VAL", "KEY"); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate if (mdb_vread(&mhe, sizeof (mhe), addr) == -1) { 574*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read mod_hash_entry at %p", addr); 575*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate if (opt_k) { 579*7c478bd9Sstevel@tonic-gate mdb_printf("%p\n", mhe.mhe_key); 580*7c478bd9Sstevel@tonic-gate } else if (opt_v) { 581*7c478bd9Sstevel@tonic-gate mdb_printf("%p\n", mhe.mhe_val); 582*7c478bd9Sstevel@tonic-gate } else { 583*7c478bd9Sstevel@tonic-gate htep->hte_format(mhe.mhe_key, keystr, sizeof (keystr)); 584*7c478bd9Sstevel@tonic-gate if (prtidx) 585*7c478bd9Sstevel@tonic-gate mdb_printf("%?x", hidx); 586*7c478bd9Sstevel@tonic-gate else 587*7c478bd9Sstevel@tonic-gate mdb_printf("%?p", addr); 588*7c478bd9Sstevel@tonic-gate mdb_printf(" %?p %s\n", mhe.mhe_val, keystr); 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate /* 595*7c478bd9Sstevel@tonic-gate * This prints out a single mod_hash element, showing its value and its key. 596*7c478bd9Sstevel@tonic-gate * The key is decoded based on the type of hash keys in use. 597*7c478bd9Sstevel@tonic-gate */ 598*7c478bd9Sstevel@tonic-gate int 599*7c478bd9Sstevel@tonic-gate modent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 600*7c478bd9Sstevel@tonic-gate { 601*7c478bd9Sstevel@tonic-gate const char *opt_t = NULL; 602*7c478bd9Sstevel@tonic-gate const hash_type_entry_t *htep; 603*7c478bd9Sstevel@tonic-gate int len; 604*7c478bd9Sstevel@tonic-gate uint_t opt_k = 0; 605*7c478bd9Sstevel@tonic-gate uint_t opt_v = 0; 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 608*7c478bd9Sstevel@tonic-gate mdb_warn("address of mod_hash_entry must be specified\n"); 609*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate len = mdb_getopts(argc, argv, 613*7c478bd9Sstevel@tonic-gate 't', MDB_OPT_STR, &opt_t, 614*7c478bd9Sstevel@tonic-gate 'k', MDB_OPT_SETBITS, 1, &opt_k, 615*7c478bd9Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, 1, &opt_v, 616*7c478bd9Sstevel@tonic-gate NULL); 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate /* options are mutually exclusive */ 619*7c478bd9Sstevel@tonic-gate if ((opt_k && opt_v) || (opt_t != NULL && (opt_k || opt_v)) || 620*7c478bd9Sstevel@tonic-gate len < argc) { 621*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate for (htep = hte_table; htep->hte_type != NULL; htep++) 625*7c478bd9Sstevel@tonic-gate if (opt_t != NULL && strcmp(opt_t, htep->hte_type) == 0) 626*7c478bd9Sstevel@tonic-gate break; 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate if (opt_t != NULL && htep->hte_type == NULL) { 629*7c478bd9Sstevel@tonic-gate mdb_warn("unknown hash type %s\n", opt_t); 630*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate return (modent_print(addr, 0, flags, htep, FALSE, opt_k, opt_v)); 634*7c478bd9Sstevel@tonic-gate } 635