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