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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2013 by Delphix. All rights reserved.
23 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
24 */
25 /*
26 * This file contains all of the interfaces for mdb's tab completion engine.
27 * Currently some interfaces are private to mdb and its internal implementation,
28 * those are in mdb_tab.h. Other pieces are public interfaces. Those are in
29 * mdb_modapi.h.
30 *
31 * Memory allocations in tab completion context have to be done very carefully.
32 * We need to think of ourselves as the same as any other command that is being
33 * executed by the user, which means we must use UM_GC to handle being
34 * interrupted.
35 */
36
37 #include <mdb/mdb_modapi.h>
38 #include <mdb/mdb_ctf.h>
39 #include <mdb/mdb_ctf_impl.h>
40 #include <mdb/mdb_string.h>
41 #include <mdb/mdb_module.h>
42 #include <mdb/mdb_debug.h>
43 #include <mdb/mdb_print.h>
44 #include <mdb/mdb_nv.h>
45 #include <mdb/mdb_tab.h>
46 #include <mdb/mdb_target.h>
47 #include <mdb/mdb.h>
48
49 #include <ctype.h>
50
51 /*
52 * There may be another way to do this, but this works well enough.
53 */
54 #define COMMAND_SEPARATOR "::"
55
56 /*
57 * find_command_start --
58 *
59 * Given a buffer find the start of the last command.
60 */
61 static char *
62 tab_find_command_start(char *buf)
63 {
64 char *offset = strstr(buf, COMMAND_SEPARATOR);
65
66 if (offset == NULL)
67 return (NULL);
68
69 for (;;) {
70 char *next = strstr(offset + strlen(COMMAND_SEPARATOR),
71 COMMAND_SEPARATOR);
72
73 if (next == NULL) {
74 return (offset);
75 }
76
77 offset = next;
78 }
79 }
80
81 /*
82 * get_dcmd --
83 *
84 * Given a buffer containing a command and its argument return
85 * the name of the command and the offset in the buffer where
86 * the command arguments start.
87 *
88 * Note: This will modify the buffer.
89 */
90 char *
91 tab_get_dcmd(char *buf, char **args, uint_t *flags)
92 {
93 char *start = buf + strlen(COMMAND_SEPARATOR);
94 char *separator = start;
95 const char *end = buf + strlen(buf);
96 uint_t space = 0;
97
98 while (separator < end && !isspace(*separator))
99 separator++;
100
101 if (separator == end) {
102 *args = NULL;
103 } else {
104 if (isspace(*separator))
105 space = 1;
106
107 *separator++ = '\0';
108 *args = separator;
109 }
110
111 if (space)
112 *flags |= DCMD_TAB_SPACE;
113
114 return (start);
115 }
116
117 /*
118 * count_args --
119 *
120 * Given a buffer containing dmcd arguments return the total number
121 * of arguments.
122 *
123 * While parsing arguments we need to keep track of whether or not the last
124 * arguments ends with a trailing space.
125 */
126 static int
127 tab_count_args(const char *input, uint_t *flags)
128 {
129 const char *index;
130 int argc = 0;
131 uint_t space = *flags & DCMD_TAB_SPACE;
132 index = input;
133
134 while (*index != '\0') {
135 while (*index != '\0' && isspace(*index)) {
136 index++;
137 space = 1;
138 }
139
140 if (*index != '\0' && !isspace(*index)) {
141 argc++;
142 space = 0;
143 while (*index != '\0' && !isspace (*index)) {
144 index++;
145 }
146 }
147 }
148
149 if (space)
150 *flags |= DCMD_TAB_SPACE;
151 else
152 *flags &= ~DCMD_TAB_SPACE;
153
154 return (argc);
155 }
156
157 /*
158 * copy_args --
159 *
160 * Given a buffer containing dcmd arguments and an array of mdb_arg_t's
161 * initialize the string value of each mdb_arg_t.
162 *
163 * Note: This will modify the buffer.
164 */
165 static int
166 tab_copy_args(char *input, int argc, mdb_arg_t *argv)
167 {
168 int i = 0;
169 char *index;
170
171 index = input;
172
173 while (*index) {
174 while (*index && isspace(*index)) {
175 index++;
176 }
177
178 if (*index && !isspace(*index)) {
179 char *end = index;
180
181 while (*end && !isspace(*end)) {
182 end++;
183 }
184
185 if (*end) {
186 *end++ = '\0';
187 }
188
189 argv[i].a_type = MDB_TYPE_STRING;
190 argv[i].a_un.a_str = index;
191
192 index = end;
193 i++;
194 }
195 }
196
197 if (i != argc)
198 return (-1);
199
200 return (0);
201 }
202
203 /*
204 * parse-buf --
205 *
206 * Parse the given buffer and return the specified dcmd, the number
207 * of arguments, and array of mdb_arg_t containing the argument
208 * values.
209 *
210 * Note: this will modify the specified buffer. Caller is responisble
211 * for freeing argvp.
212 */
213 static int
214 tab_parse_buf(char *buf, char **dcmdp, int *argcp, mdb_arg_t **argvp,
215 uint_t *flags)
216 {
217 char *data = tab_find_command_start(buf);
218 char *args_data = NULL;
219 char *dcmd = NULL;
220 int argc = 0;
221 mdb_arg_t *argv = NULL;
222
223 if (data == NULL) {
224 return (-1);
225 }
226
227 dcmd = tab_get_dcmd(data, &args_data, flags);
228
229 if (dcmd == NULL) {
230 return (-1);
231 }
232
233 if (args_data != NULL) {
234 argc = tab_count_args(args_data, flags);
235
236 if (argc != 0) {
237 argv = mdb_alloc(sizeof (mdb_arg_t) * argc,
238 UM_SLEEP | UM_GC);
239
240 if (tab_copy_args(args_data, argc, argv) == -1)
241 return (-1);
242 }
243 }
244
245 *dcmdp = dcmd;
246 *argcp = argc;
247 *argvp = argv;
248
249 return (0);
250 }
251
252 /*
253 * tab_command --
254 *
255 * This function is executed anytime a tab is entered. It checks
256 * the current buffer to determine if there is a valid dmcd,
257 * if that dcmd has a tab completion handler it will invoke it.
258 *
259 * This function returns the string (if any) that should be added to the
260 * existing buffer to complete it.
261 */
262 int
263 mdb_tab_command(mdb_tab_cookie_t *mcp, const char *buf)
264 {
265 char *data;
266 char *dcmd = NULL;
267 int argc = 0;
268 mdb_arg_t *argv = NULL;
269 int ret = 0;
270 mdb_idcmd_t *cp;
271 uint_t flags = 0;
272
273 /*
274 * Parsing the command and arguments will modify the buffer
275 * (replacing spaces with \0), so make a copy of the specified
276 * buffer first.
277 */
278 data = mdb_alloc(strlen(buf) + 1, UM_SLEEP | UM_GC);
279 (void) strcpy(data, buf);
280
281 /*
282 * Get the specified dcmd and arguments from the buffer.
283 */
284 ret = tab_parse_buf(data, &dcmd, &argc, &argv, &flags);
285
286 /*
287 * Match against global symbols if the input is not a dcmd
288 */
289 if (ret != 0) {
290 (void) mdb_tab_complete_global(mcp, buf);
291 goto out;
292 }
293
294 /*
295 * Check to see if the buffer contains a valid dcmd
296 */
297 cp = mdb_dcmd_lookup(dcmd);
298
299 /*
300 * When argc is zero it indicates that we are trying to tab complete
301 * a dcmd or a global symbol. Note, that if there isn't the start of
302 * a dcmd, i.e. ::, then we will have already bailed in the call to
303 * tab_parse_buf.
304 */
305 if (cp == NULL && argc != 0) {
306 goto out;
307 }
308
309 /*
310 * Invoke the command specific tab completion handler or the built in
311 * dcmd one if there is no dcmd.
312 */
313 if (cp == NULL)
314 (void) mdb_tab_complete_dcmd(mcp, dcmd);
315 else
316 mdb_call_tab(cp, mcp, flags, argc, argv);
317
318 out:
319 return (mdb_tab_size(mcp));
320 }
321
322 static int
323 tab_complete_dcmd(mdb_var_t *v, void *arg)
324 {
325 mdb_idcmd_t *idcp = mdb_nv_get_cookie(mdb_nv_get_cookie(v));
326 mdb_tab_cookie_t *mcp = (mdb_tab_cookie_t *)arg;
327
328 /*
329 * The way that mdb is implemented, even commands like $C will show up
330 * here. As such, we don't want to match anything that doesn't start
331 * with an alpha or number. While nothing currently appears (via a
332 * cursory search with mdb -k) to start with a capital letter or a
333 * number, we'll support them anyways.
334 */
335 if (!isalnum(idcp->idc_name[0]))
336 return (0);
337
338 mdb_tab_insert(mcp, idcp->idc_name);
339 return (0);
340 }
341
342 int
343 mdb_tab_complete_dcmd(mdb_tab_cookie_t *mcp, const char *dcmd)
344 {
345 mdb_tab_setmbase(mcp, dcmd);
346 mdb_nv_sort_iter(&mdb.m_dcmds, tab_complete_dcmd, mcp,
347 UM_GC | UM_SLEEP);
348 return (0);
349 }
350
351 static int
352 tab_complete_walker(mdb_var_t *v, void *arg)
353 {
354 mdb_iwalker_t *iwp = mdb_nv_get_cookie(mdb_nv_get_cookie(v));
355 mdb_tab_cookie_t *mcp = arg;
356
357 mdb_tab_insert(mcp, iwp->iwlk_name);
358 return (0);
359 }
360
361 int
362 mdb_tab_complete_walker(mdb_tab_cookie_t *mcp, const char *walker)
363 {
364 if (walker != NULL)
365 mdb_tab_setmbase(mcp, walker);
366 mdb_nv_sort_iter(&mdb.m_walkers, tab_complete_walker, mcp,
367 UM_GC | UM_SLEEP);
368
369 return (0);
370 }
371
372 mdb_tab_cookie_t *
373 mdb_tab_init(void)
374 {
375 mdb_tab_cookie_t *mcp;
376
377 mcp = mdb_zalloc(sizeof (mdb_tab_cookie_t), UM_SLEEP | UM_GC);
378 (void) mdb_nv_create(&mcp->mtc_nv, UM_SLEEP | UM_GC);
379
380 return (mcp);
381 }
382
383 size_t
384 mdb_tab_size(mdb_tab_cookie_t *mcp)
385 {
386 return (mdb_nv_size(&mcp->mtc_nv));
387 }
388
389 /*
390 * Determine whether the specified name is a valid tab completion for
391 * the given command. If the name is a valid tab completion then
392 * it will be saved in the mdb_tab_cookie_t.
393 */
394 void
395 mdb_tab_insert(mdb_tab_cookie_t *mcp, const char *name)
396 {
397 size_t matches, index;
398 mdb_var_t *v;
399 char *n;
400
401 /*
402 * If we have a match set, then we want to verify that we actually match
403 * it.
404 */
405 if (mcp->mtc_base != NULL &&
406 strncmp(name, mcp->mtc_base, strlen(mcp->mtc_base)) != 0)
407 return;
408
409 v = mdb_nv_lookup(&mcp->mtc_nv, name);
410 if (v != NULL)
411 return;
412
413 (void) mdb_nv_insert(&mcp->mtc_nv, name, NULL, 0, MDB_NV_RDONLY);
414
415 matches = mdb_tab_size(mcp);
416 if (matches == 1) {
417 (void) strlcpy(mcp->mtc_match, name, MDB_SYM_NAMLEN);
418 } else {
419 index = 0;
420 while (mcp->mtc_match[index] &&
421 mcp->mtc_match[index] == name[index])
422 index++;
423
424 mcp->mtc_match[index] = '\0';
425 }
426 }
427
428 /*ARGSUSED*/
429 static int
430 tab_print_cb(mdb_var_t *v, void *ignored)
431 {
432 mdb_printf("%s\n", mdb_nv_get_name(v));
433 return (0);
434 }
435
436 void
437 mdb_tab_print(mdb_tab_cookie_t *mcp)
438 {
439 mdb_nv_sort_iter(&mcp->mtc_nv, tab_print_cb, NULL, UM_SLEEP | UM_GC);
440 }
441
442 const char *
443 mdb_tab_match(mdb_tab_cookie_t *mcp)
444 {
445 size_t blen;
446
447 if (mcp->mtc_base == NULL)
448 blen = 0;
449 else
450 blen = strlen(mcp->mtc_base);
451 return (mcp->mtc_match + blen);
452 }
453
454 void
455 mdb_tab_setmbase(mdb_tab_cookie_t *mcp, const char *base)
456 {
457 (void) strlcpy(mcp->mtc_base, base, MDB_SYM_NAMLEN);
458 }
459
460 /*
461 * This function is currently a no-op due to the fact that we have to GC because
462 * we're in command context.
463 */
464 /*ARGSUSED*/
465 void
466 mdb_tab_fini(mdb_tab_cookie_t *mcp)
467 {
468 }
469
470 /*ARGSUSED*/
471 static int
472 tab_complete_global(void *arg, const GElf_Sym *sym, const char *name,
473 const mdb_syminfo_t *sip, const char *obj)
474 {
475 mdb_tab_cookie_t *mcp = arg;
476 mdb_tab_insert(mcp, name);
477 return (0);
478 }
479
480 /*
481 * This function tab completes against all loaded global symbols.
482 */
483 int
484 mdb_tab_complete_global(mdb_tab_cookie_t *mcp, const char *name)
485 {
486 mdb_tab_setmbase(mcp, name);
487 (void) mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
488 MDB_TGT_SYMTAB, MDB_TGT_BIND_ANY | MDB_TGT_TYPE_OBJECT |
489 MDB_TGT_TYPE_FUNC, tab_complete_global, mcp);
490 return (0);
491 }
492
493 /*
494 * This function takes a ctf id and determines whether or not the associated
495 * type should be considered as a potential match for the given tab
496 * completion command. We verify that the type itself is valid
497 * for completion given the current context of the command, resolve
498 * its actual name, and then pass it off to mdb_tab_insert to determine
499 * if it's an actual match.
500 */
501 static int
502 tab_complete_type(mdb_ctf_id_t id, void *arg)
503 {
504 int rkind;
505 char buf[MDB_SYM_NAMLEN];
506 mdb_ctf_id_t rid;
507 mdb_tab_cookie_t *mcp = arg;
508 uint_t flags = (uint_t)(uintptr_t)mcp->mtc_cba;
509
510 /*
511 * CTF data includes types that mdb commands don't understand. Before
512 * we resolve the actual type prune any entry that is a type we
513 * don't care about.
514 */
515 switch (mdb_ctf_type_kind(id)) {
516 case CTF_K_CONST:
517 case CTF_K_RESTRICT:
518 case CTF_K_VOLATILE:
519 return (0);
520 }
521
522 if (mdb_ctf_type_resolve(id, &rid) != 0)
523 return (1);
524
525 rkind = mdb_ctf_type_kind(rid);
526
527 if ((flags & MDB_TABC_MEMBERS) && rkind != CTF_K_STRUCT &&
528 rkind != CTF_K_UNION)
529 return (0);
530
531 if ((flags & MDB_TABC_NOPOINT) && rkind == CTF_K_POINTER)
532 return (0);
533
534 if ((flags & MDB_TABC_NOARRAY) && rkind == CTF_K_ARRAY)
535 return (0);
536
537 (void) mdb_ctf_type_name(id, buf, sizeof (buf));
538
539 mdb_tab_insert(mcp, buf);
540 return (0);
541 }
542
543 /*ARGSUSED*/
544 static int
545 mdb_tab_complete_module(void *data, const mdb_map_t *mp, const char *name)
546 {
547 (void) mdb_ctf_type_iter(name, tab_complete_type, data);
548 return (0);
549 }
550
551 int
552 mdb_tab_complete_type(mdb_tab_cookie_t *mcp, const char *name, uint_t flags)
553 {
554 mdb_tgt_t *t = mdb.m_target;
555
556 mcp->mtc_cba = (void *)(uintptr_t)flags;
557 if (name != NULL)
558 mdb_tab_setmbase(mcp, name);
559
560 (void) mdb_tgt_object_iter(t, mdb_tab_complete_module, mcp);
561 (void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, tab_complete_type,
562 mcp);
563 return (0);
564 }
565
566 /*ARGSUSED*/
567 static int
568 tab_complete_member(const char *name, mdb_ctf_id_t id, ulong_t off, void *arg)
569 {
570 mdb_tab_cookie_t *mcp = arg;
571 mdb_tab_insert(mcp, name);
572 return (0);
573 }
574
575 int
576 mdb_tab_complete_member_by_id(mdb_tab_cookie_t *mcp, mdb_ctf_id_t id,
577 const char *member)
578 {
579 if (member != NULL)
580 mdb_tab_setmbase(mcp, member);
581 (void) mdb_ctf_member_iter(id, tab_complete_member, mcp);
582 return (0);
583 }
584
585 int
586 mdb_tab_complete_member(mdb_tab_cookie_t *mcp, const char *type,
587 const char *member)
588 {
589 mdb_ctf_id_t id;
590
591 if (mdb_ctf_lookup_by_name(type, &id) != 0)
592 return (-1);
593
594 return (mdb_tab_complete_member_by_id(mcp, id, member));
595 }
596
597 int
598 mdb_tab_complete_mt(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
599 const mdb_arg_t *argv)
600 {
601 char tn[MDB_SYM_NAMLEN];
602 int ret;
603
604 if (argc == 0 && !(flags & DCMD_TAB_SPACE))
605 return (0);
606
607 if (argc == 0)
608 return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_MEMBERS));
609
610 if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0)
611 return (ret);
612
613 if (argc == 1 && (!(flags & DCMD_TAB_SPACE) || ret == 1))
614 return (mdb_tab_complete_type(mcp, tn, MDB_TABC_MEMBERS));
615
616 if (argc == 1 && (flags & DCMD_TAB_SPACE))
617 return (mdb_tab_complete_member(mcp, tn, NULL));
618
619 if (argc == 2)
620 return (mdb_tab_complete_member(mcp, tn, argv[1].a_un.a_str));
621
622 return (0);
623 }
624
625 /*
626 * This is similar to mdb_print.c's args_to_typename, but it has subtle
627 * differences surrounding how the strings of one element are handled that have
628 * 'struct', 'enum', or 'union' in them and instead works with them for tab
629 * completion purposes.
630 */
631 int
632 mdb_tab_typename(int *argcp, const mdb_arg_t **argvp, char *buf, size_t len)
633 {
634 int argc = *argcp;
635 const mdb_arg_t *argv = *argvp;
636
637 if (argc < 1 || argv->a_type != MDB_TYPE_STRING)
638 return (DCMD_USAGE);
639
640 if (strcmp(argv->a_un.a_str, "struct") == 0 ||
641 strcmp(argv->a_un.a_str, "enum") == 0 ||
642 strcmp(argv->a_un.a_str, "union") == 0) {
643 if (argc == 1) {
644 (void) mdb_snprintf(buf, len, "%s ",
645 argv[0].a_un.a_str);
646 return (1);
647 }
648
649 if (argv[1].a_type != MDB_TYPE_STRING)
650 return (DCMD_USAGE);
651
652 (void) mdb_snprintf(buf, len, "%s %s",
653 argv[0].a_un.a_str, argv[1].a_un.a_str);
654
655 *argcp = argc - 1;
656 *argvp = argv + 1;
657 } else {
658 (void) mdb_snprintf(buf, len, "%s", argv[0].a_un.a_str);
659 }
660
661 return (0);
662 }