xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_help.c (revision f985abb4a2473d3c04b086f7c9fab177e368ffef)
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