1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <mdb/mdb_modapi.h> 30 #include <mdb/mdb_macalias.h> 31 #include <mdb/mdb_fmt.h> 32 #include <mdb/mdb_err.h> 33 #include <mdb/mdb_help.h> 34 #include <mdb/mdb.h> 35 36 const char _mdb_help[] = 37 "\nEach debugger command in %s is structured as follows:\n\n" 38 " [ address [, count]] verb [ arguments ... ]\n" 39 " ^ ^ ^ ^\n" 40 " the start --+ | | +-- arguments are strings which can be\n" 41 " address can be an | | quoted using \"\" or '' or\n" 42 " expression | | expressions enclosed in $[ ]\n" 43 " | |\n" 44 " the repeat count --+ +--------- the verb is a name which begins\n" 45 " is also an expression with either $, :, or ::. it can also\n" 46 " be a format specifier (/ \\ ? or =)\n\n" 47 "For information on debugger commands (dcmds) and walkers, type:\n\n" 48 " ::help cmdname ... for more detailed information on a command\n" 49 " ::dcmds ... for a list of dcmds and their descriptions\n" 50 " ::walkers ... for a list of walkers and their descriptions\n" 51 " ::dmods -l ... for a list of modules and their dcmds and walkers\n" 52 " ::formats ... for a list of format characters for / \\ ? and =\n\n" 53 "For information on command-line options, type:\n\n" 54 " $ %s -? ... in your shell for a complete list of options\n\n"; 55 56 /*ARGSUSED*/ 57 static int 58 print_dcmd(mdb_var_t *v, void *ignored) 59 { 60 const mdb_idcmd_t *idcp = mdb_nv_get_cookie(v); 61 if (idcp->idc_descr != NULL) 62 mdb_printf(" dcmd %-20s - %s\n", 63 idcp->idc_name, idcp->idc_descr); 64 return (0); 65 } 66 67 /*ARGSUSED*/ 68 static int 69 print_walk(mdb_var_t *v, void *ignored) 70 { 71 const mdb_iwalker_t *iwp = mdb_nv_get_cookie(v); 72 if (iwp->iwlk_descr != NULL) 73 mdb_printf(" walk %-20s - %s\n", 74 iwp->iwlk_name, iwp->iwlk_descr); 75 return (0); 76 } 77 78 /*ARGSUSED*/ 79 static int 80 print_dmod_long(mdb_var_t *v, void *ignored) 81 { 82 mdb_module_t *mod = mdb_nv_get_cookie(v); 83 84 mdb_printf("\n%<u>%-70s%</u>\n", mod->mod_name); 85 86 if (mod->mod_tgt_ctor != NULL) { 87 mdb_printf(" ctor 0x%-18lx - target constructor\n", 88 (ulong_t)mod->mod_tgt_ctor); 89 } 90 91 if (mod->mod_dis_ctor != NULL) { 92 mdb_printf(" ctor 0x%-18lx - disassembler constructor\n", 93 (ulong_t)mod->mod_dis_ctor); 94 } 95 96 mdb_nv_sort_iter(&mod->mod_dcmds, print_dcmd, NULL, UM_SLEEP | UM_GC); 97 mdb_nv_sort_iter(&mod->mod_walkers, print_walk, NULL, UM_SLEEP | UM_GC); 98 99 return (0); 100 } 101 102 /*ARGSUSED*/ 103 static int 104 print_dmod_short(mdb_var_t *v, void *ignored) 105 { 106 mdb_printf("%s\n", mdb_nv_get_name(v)); 107 return (0); 108 } 109 110 /*ARGSUSED*/ 111 int 112 cmd_dmods(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 113 { 114 int (*func)(mdb_var_t *, void *); 115 uint_t opt_l = FALSE; 116 mdb_var_t *v; 117 int i; 118 119 if (flags & DCMD_ADDRSPEC) 120 return (DCMD_USAGE); 121 122 i = mdb_getopts(argc, argv, 'l', MDB_OPT_SETBITS, TRUE, &opt_l, NULL); 123 func = opt_l ? print_dmod_long : print_dmod_short; 124 125 if (i != argc) { 126 if (argc - i != 1 || argv[i].a_type != MDB_TYPE_STRING) 127 return (DCMD_USAGE); 128 129 v = mdb_nv_lookup(&mdb.m_modules, argv[i].a_un.a_str); 130 131 if (v == NULL) 132 mdb_warn("%s module not loaded\n", argv[i].a_un.a_str); 133 else 134 (void) func(v, NULL); 135 136 } else 137 mdb_nv_sort_iter(&mdb.m_modules, func, NULL, UM_SLEEP | UM_GC); 138 139 return (DCMD_OK); 140 } 141 142 /*ARGSUSED*/ 143 static int 144 print_wdesc(mdb_var_t *v, void *ignored) 145 { 146 mdb_iwalker_t *iwp = mdb_nv_get_cookie(mdb_nv_get_cookie(v)); 147 148 if (iwp->iwlk_descr != NULL) 149 mdb_printf("%-24s - %s\n", mdb_nv_get_name(v), iwp->iwlk_descr); 150 return (0); 151 } 152 153 /*ARGSUSED*/ 154 int 155 cmd_walkers(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 156 { 157 if ((flags && DCMD_ADDRSPEC) || argc != 0) 158 return (DCMD_USAGE); 159 160 mdb_nv_sort_iter(&mdb.m_walkers, print_wdesc, NULL, UM_SLEEP | UM_GC); 161 return (DCMD_OK); 162 } 163 164 /*ARGSUSED*/ 165 static int 166 print_ddesc(mdb_var_t *v, void *ignored) 167 { 168 mdb_idcmd_t *idcp = mdb_nv_get_cookie(mdb_nv_get_cookie(v)); 169 170 if (idcp->idc_descr != NULL) 171 mdb_printf("%-24s - %s\n", mdb_nv_get_name(v), idcp->idc_descr); 172 return (0); 173 } 174 175 /*ARGSUSED*/ 176 int 177 cmd_dcmds(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 178 { 179 if ((flags && DCMD_ADDRSPEC) || argc != 0) 180 return (DCMD_USAGE); 181 182 mdb_nv_sort_iter(&mdb.m_dcmds, print_ddesc, NULL, UM_SLEEP | UM_GC); 183 return (DCMD_OK); 184 } 185 186 /*ARGSUSED*/ 187 int 188 cmd_help(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 189 { 190 const char *prefix, *usage; 191 const mdb_idcmd_t *idcp; 192 193 if ((flags & DCMD_ADDRSPEC) || argc > 1) 194 return (DCMD_USAGE); 195 196 if (argc == 0) { 197 mdb_printf(_mdb_help, mdb.m_pname, mdb.m_pname); 198 return (DCMD_OK); 199 } 200 201 if (argv->a_type != MDB_TYPE_STRING) { 202 warn("expected string argument\n"); 203 return (DCMD_USAGE); 204 } 205 206 if (strncmp(argv->a_un.a_str, "::", 2) == 0) 207 idcp = mdb_dcmd_lookup(argv->a_un.a_str + 2); 208 else 209 idcp = mdb_dcmd_lookup(argv->a_un.a_str); 210 211 if (idcp == NULL) { 212 mdb_warn("unknown command: %s\n", argv->a_un.a_str); 213 return (DCMD_ERR); 214 } 215 216 prefix = strchr(":$=/\\?>", idcp->idc_name[0]) ? "" : "::"; 217 usage = idcp->idc_usage ? idcp->idc_usage : ""; 218 219 mdb_printf("\n%<b>NAME%</b>\n %s - %s\n\n", 220 idcp->idc_name, idcp->idc_descr); 221 222 mdb_printf("%<b>SYNOPSIS%</b>\n "); 223 if (usage[0] == '?') { 224 mdb_printf("[ %<u>addr%</u> ] "); 225 usage++; 226 } else if (usage[0] == ':') { 227 mdb_printf("%<u>addr%</u> "); 228 usage++; 229 } 230 231 mdb_printf("%s%s %s\n\n", prefix, idcp->idc_name, usage); 232 233 if (idcp->idc_help != NULL) { 234 mdb_printf("%<b>DESCRIPTION%</b>\n"); 235 (void) mdb_inc_indent(2); 236 idcp->idc_help(); 237 (void) mdb_dec_indent(2); 238 mdb_printf("\n"); 239 } 240 241 /* 242 * For now, modules that are built-in mark their interfaces Evolving 243 * (documented in mdb(1)) and modules that are loaded mark their 244 * interfaces Unstable. In the future we could extend the dmod linkage 245 * to include the module's intended stability and then show it here. 246 */ 247 mdb_printf("%<b>ATTRIBUTES%</b>\n\n"); 248 mdb_printf(" Target: %s\n", mdb_tgt_name(mdb.m_target)); 249 mdb_printf(" Module: %s\n", idcp->idc_modp->mod_name); 250 mdb_printf(" Interface Stability: %s\n\n", 251 (idcp->idc_descr != NULL && idcp->idc_modp->mod_hdl == NULL) ? 252 "Evolving" : "Unstable"); 253 254 return (DCMD_OK); 255 } 256 257 static int 258 print_dcmd_def(mdb_var_t *v, void *private) 259 { 260 mdb_idcmd_t *idcp = mdb_nv_get_cookie(mdb_nv_get_cookie(v)); 261 int *ip = private; 262 263 mdb_printf(" [%d] %s`%s\n", 264 (*ip)++, idcp->idc_modp->mod_name, idcp->idc_name); 265 266 return (0); 267 } 268 269 static int 270 print_walker_def(mdb_var_t *v, void *private) 271 { 272 mdb_iwalker_t *iwp = mdb_nv_get_cookie(mdb_nv_get_cookie(v)); 273 int *ip = private; 274 275 mdb_printf(" [%d] %s`%s\n", 276 (*ip)++, iwp->iwlk_modp->mod_name, iwp->iwlk_name); 277 278 return (0); 279 } 280 281 /*ARGSUSED*/ 282 int 283 cmd_which(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 284 { 285 const char defn_hdr[] = " > definition list:\n"; 286 uint_t opt_v = FALSE; 287 int i; 288 289 i = mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL); 290 291 for (; i < argc; i++) { 292 const char *s = argv[i].a_un.a_str; 293 int found = FALSE; 294 mdb_iwalker_t *iwp; 295 mdb_idcmd_t *idcp; 296 const char *alias; 297 298 if (argv->a_type != MDB_TYPE_STRING) 299 continue; 300 301 if (s[0] == '$' && s[1] == '<') 302 s += 2; 303 304 if ((idcp = mdb_dcmd_lookup(s)) != NULL) { 305 mdb_var_t *v = idcp->idc_var; 306 int i = 1; 307 308 if (idcp->idc_modp != &mdb.m_rmod) { 309 mdb_printf("%s is a dcmd from module %s\n", 310 s, idcp->idc_modp->mod_name); 311 } else 312 mdb_printf("%s is a built-in dcmd\n", s); 313 314 if (opt_v) { 315 mdb_printf(defn_hdr); 316 mdb_nv_defn_iter(v, print_dcmd_def, &i); 317 } 318 found = TRUE; 319 } 320 321 if ((iwp = mdb_walker_lookup(s)) != NULL) { 322 mdb_var_t *v = iwp->iwlk_var; 323 int i = 1; 324 325 if (iwp->iwlk_modp != &mdb.m_rmod) { 326 mdb_printf("%s is a walker from module %s\n", 327 s, iwp->iwlk_modp->mod_name); 328 } else 329 mdb_printf("%s is a built-in walker\n", s); 330 331 if (opt_v) { 332 mdb_printf(defn_hdr); 333 mdb_nv_defn_iter(v, print_walker_def, &i); 334 } 335 found = TRUE; 336 } 337 338 if ((alias = mdb_macalias_lookup(s)) != NULL) { 339 mdb_printf("%s is a macro alias for '%s'\n", s, alias); 340 found = TRUE; 341 } 342 343 if (!found) 344 mdb_warn("%s not found\n", s); 345 } 346 347 return (DCMD_OK); 348 } 349