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