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