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
print_dcmd(mdb_var_t * v,void * ignored)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
print_walk(mdb_var_t * v,void * ignored)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
print_dmod_long(mdb_var_t * v,void * ignored)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
print_dmod_short(mdb_var_t * v,void * ignored)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
cmd_dmods(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
print_wdesc(mdb_var_t * v,void * ignored)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
cmd_walkers(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
print_ddesc(mdb_var_t * v,void * ignored)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
cmd_dcmds(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
cmd_help(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
cmd_help_tab(mdb_tab_cookie_t * mcp,uint_t flags,int argc,const mdb_arg_t * argv)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
print_dcmd_def(mdb_var_t * v,void * private)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
print_walker_def(mdb_var_t * v,void * private)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
cmd_which(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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