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