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