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 * 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 * 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 * 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 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 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 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 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 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 344 mdb_tab_complete_dcmd(mdb_tab_cookie_t *mcp, const char *dcmd) 345 { 346 mdb_tab_setmbase(mcp, dcmd); 347 mdb_nv_sort_iter(&mdb.m_dcmds, tab_complete_dcmd, mcp, 348 UM_GC | UM_SLEEP); 349 return (0); 350 } 351 352 static int 353 tab_complete_walker(mdb_var_t *v, void *arg) 354 { 355 mdb_iwalker_t *iwp = mdb_nv_get_cookie(mdb_nv_get_cookie(v)); 356 mdb_tab_cookie_t *mcp = arg; 357 358 mdb_tab_insert(mcp, iwp->iwlk_name); 359 return (0); 360 } 361 362 int 363 mdb_tab_complete_walker(mdb_tab_cookie_t *mcp, const char *walker) 364 { 365 if (walker != NULL) 366 mdb_tab_setmbase(mcp, walker); 367 mdb_nv_sort_iter(&mdb.m_walkers, tab_complete_walker, mcp, 368 UM_GC | UM_SLEEP); 369 370 return (0); 371 } 372 373 mdb_tab_cookie_t * 374 mdb_tab_init(void) 375 { 376 mdb_tab_cookie_t *mcp; 377 378 mcp = mdb_zalloc(sizeof (mdb_tab_cookie_t), UM_SLEEP | UM_GC); 379 (void) mdb_nv_create(&mcp->mtc_nv, UM_SLEEP | UM_GC); 380 381 return (mcp); 382 } 383 384 size_t 385 mdb_tab_size(mdb_tab_cookie_t *mcp) 386 { 387 return (mdb_nv_size(&mcp->mtc_nv)); 388 } 389 390 /* 391 * Determine whether the specified name is a valid tab completion for 392 * the given command. If the name is a valid tab completion then 393 * it will be saved in the mdb_tab_cookie_t. 394 */ 395 void 396 mdb_tab_insert(mdb_tab_cookie_t *mcp, const char *name) 397 { 398 size_t matches, index; 399 mdb_var_t *v; 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 }