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