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 }