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 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 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 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 * 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 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 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 (mcp->mtc_base != NULL && 407 strncmp(name, mcp->mtc_base, strlen(mcp->mtc_base)) != 0) 408 return; 409 410 v = mdb_nv_lookup(&mcp->mtc_nv, name); 411 if (v != NULL) 412 return; 413 414 (void) mdb_nv_insert(&mcp->mtc_nv, name, NULL, 0, MDB_NV_RDONLY); 415 416 matches = mdb_tab_size(mcp); 417 if (matches == 1) { 418 (void) strlcpy(mcp->mtc_match, name, MDB_SYM_NAMLEN); 419 } else { 420 index = 0; 421 while (mcp->mtc_match[index] && 422 mcp->mtc_match[index] == name[index]) 423 index++; 424 425 mcp->mtc_match[index] = '\0'; 426 } 427 } 428 429 /*ARGSUSED*/ 430 static int 431 tab_print_cb(mdb_var_t *v, void *ignored) 432 { 433 mdb_printf("%s\n", mdb_nv_get_name(v)); 434 return (0); 435 } 436 437 void 438 mdb_tab_print(mdb_tab_cookie_t *mcp) 439 { 440 mdb_nv_sort_iter(&mcp->mtc_nv, tab_print_cb, NULL, UM_SLEEP | UM_GC); 441 } 442 443 const char * 444 mdb_tab_match(mdb_tab_cookie_t *mcp) 445 { 446 size_t blen; 447 448 if (mcp->mtc_base == NULL) 449 blen = 0; 450 else 451 blen = strlen(mcp->mtc_base); 452 return (mcp->mtc_match + blen); 453 } 454 455 void 456 mdb_tab_setmbase(mdb_tab_cookie_t *mcp, const char *base) 457 { 458 (void) strlcpy(mcp->mtc_base, base, MDB_SYM_NAMLEN); 459 } 460 461 /* 462 * This function is currently a no-op due to the fact that we have to GC because 463 * we're in command context. 464 */ 465 /*ARGSUSED*/ 466 void 467 mdb_tab_fini(mdb_tab_cookie_t *mcp) 468 { 469 } 470 471 /*ARGSUSED*/ 472 static int 473 tab_complete_global(void *arg, const GElf_Sym *sym, const char *name, 474 const mdb_syminfo_t *sip, const char *obj) 475 { 476 mdb_tab_cookie_t *mcp = arg; 477 mdb_tab_insert(mcp, name); 478 return (0); 479 } 480 481 /* 482 * This function tab completes against all loaded global symbols. 483 */ 484 int 485 mdb_tab_complete_global(mdb_tab_cookie_t *mcp, const char *name) 486 { 487 mdb_tab_setmbase(mcp, name); 488 (void) mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY, 489 MDB_TGT_SYMTAB, MDB_TGT_BIND_ANY | MDB_TGT_TYPE_OBJECT | 490 MDB_TGT_TYPE_FUNC, tab_complete_global, mcp); 491 return (0); 492 } 493 494 /* 495 * This function takes a ctf id and determines whether or not the associated 496 * type should be considered as a potential match for the given tab 497 * completion command. We verify that the type itself is valid 498 * for completion given the current context of the command, resolve 499 * its actual name, and then pass it off to mdb_tab_insert to determine 500 * if it's an actual match. 501 */ 502 static int 503 tab_complete_type(mdb_ctf_id_t id, void *arg) 504 { 505 int rkind; 506 char buf[MDB_SYM_NAMLEN]; 507 mdb_ctf_id_t rid; 508 mdb_tab_cookie_t *mcp = arg; 509 uint_t flags = (uint_t)(uintptr_t)mcp->mtc_cba; 510 511 /* 512 * CTF data includes types that mdb commands don't understand. Before 513 * we resolve the actual type prune any entry that is a type we 514 * don't care about. 515 */ 516 switch (mdb_ctf_type_kind(id)) { 517 case CTF_K_CONST: 518 case CTF_K_RESTRICT: 519 case CTF_K_VOLATILE: 520 return (0); 521 } 522 523 if (mdb_ctf_type_resolve(id, &rid) != 0) 524 return (1); 525 526 rkind = mdb_ctf_type_kind(rid); 527 528 if ((flags & MDB_TABC_MEMBERS) && rkind != CTF_K_STRUCT && 529 rkind != CTF_K_UNION) 530 return (0); 531 532 if ((flags & MDB_TABC_NOPOINT) && rkind == CTF_K_POINTER) 533 return (0); 534 535 if ((flags & MDB_TABC_NOARRAY) && rkind == CTF_K_ARRAY) 536 return (0); 537 538 (void) mdb_ctf_type_name(id, buf, sizeof (buf)); 539 540 mdb_tab_insert(mcp, buf); 541 return (0); 542 } 543 544 /*ARGSUSED*/ 545 static int 546 mdb_tab_complete_module(void *data, const mdb_map_t *mp, const char *name) 547 { 548 (void) mdb_ctf_type_iter(name, tab_complete_type, data); 549 return (0); 550 } 551 552 int 553 mdb_tab_complete_type(mdb_tab_cookie_t *mcp, const char *name, uint_t flags) 554 { 555 mdb_tgt_t *t = mdb.m_target; 556 557 mcp->mtc_cba = (void *)(uintptr_t)flags; 558 if (name != NULL) 559 mdb_tab_setmbase(mcp, name); 560 561 (void) mdb_tgt_object_iter(t, mdb_tab_complete_module, mcp); 562 (void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, tab_complete_type, 563 mcp); 564 return (0); 565 } 566 567 /*ARGSUSED*/ 568 static int 569 tab_complete_member(const char *name, mdb_ctf_id_t id, ulong_t off, void *arg) 570 { 571 mdb_tab_cookie_t *mcp = arg; 572 mdb_tab_insert(mcp, name); 573 return (0); 574 } 575 576 int 577 mdb_tab_complete_member_by_id(mdb_tab_cookie_t *mcp, mdb_ctf_id_t id, 578 const char *member) 579 { 580 if (member != NULL) 581 mdb_tab_setmbase(mcp, member); 582 (void) mdb_ctf_member_iter(id, tab_complete_member, mcp); 583 return (0); 584 } 585 586 int 587 mdb_tab_complete_member(mdb_tab_cookie_t *mcp, const char *type, 588 const char *member) 589 { 590 mdb_ctf_id_t id; 591 592 if (mdb_ctf_lookup_by_name(type, &id) != 0) 593 return (-1); 594 595 return (mdb_tab_complete_member_by_id(mcp, id, member)); 596 } 597 598 int 599 mdb_tab_complete_mt(mdb_tab_cookie_t *mcp, uint_t flags, int argc, 600 const mdb_arg_t *argv) 601 { 602 char tn[MDB_SYM_NAMLEN]; 603 int ret; 604 605 if (argc == 0 && !(flags & DCMD_TAB_SPACE)) 606 return (0); 607 608 if (argc == 0) 609 return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_MEMBERS)); 610 611 if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0) 612 return (ret); 613 614 if (argc == 1 && (!(flags & DCMD_TAB_SPACE) || ret == 1)) 615 return (mdb_tab_complete_type(mcp, tn, MDB_TABC_MEMBERS)); 616 617 if (argc == 1 && (flags & DCMD_TAB_SPACE)) 618 return (mdb_tab_complete_member(mcp, tn, NULL)); 619 620 if (argc == 2) 621 return (mdb_tab_complete_member(mcp, tn, argv[1].a_un.a_str)); 622 623 return (0); 624 } 625 626 /* 627 * This is similar to mdb_print.c's args_to_typename, but it has subtle 628 * differences surrounding how the strings of one element are handled that have 629 * 'struct', 'enum', or 'union' in them and instead works with them for tab 630 * completion purposes. 631 */ 632 int 633 mdb_tab_typename(int *argcp, const mdb_arg_t **argvp, char *buf, size_t len) 634 { 635 int argc = *argcp; 636 const mdb_arg_t *argv = *argvp; 637 638 if (argc < 1 || argv->a_type != MDB_TYPE_STRING) 639 return (DCMD_USAGE); 640 641 if (strcmp(argv->a_un.a_str, "struct") == 0 || 642 strcmp(argv->a_un.a_str, "enum") == 0 || 643 strcmp(argv->a_un.a_str, "union") == 0) { 644 if (argc == 1) { 645 (void) mdb_snprintf(buf, len, "%s ", 646 argv[0].a_un.a_str); 647 return (1); 648 } 649 650 if (argv[1].a_type != MDB_TYPE_STRING) 651 return (DCMD_USAGE); 652 653 (void) mdb_snprintf(buf, len, "%s %s", 654 argv[0].a_un.a_str, argv[1].a_un.a_str); 655 656 *argcp = argc - 1; 657 *argvp = argv + 1; 658 } else { 659 (void) mdb_snprintf(buf, len, "%s", argv[0].a_un.a_str); 660 } 661 662 return (0); 663 }