1 /* Skipping uninteresting files and functions while stepping. 2 3 Copyright (C) 2011-2023 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include "defs.h" 19 #include "skip.h" 20 #include "value.h" 21 #include "valprint.h" 22 #include "ui-out.h" 23 #include "symtab.h" 24 #include "gdbcmd.h" 25 #include "command.h" 26 #include "completer.h" 27 #include "stack.h" 28 #include "cli/cli-utils.h" 29 #include "arch-utils.h" 30 #include "linespec.h" 31 #include "objfiles.h" 32 #include "breakpoint.h" /* for get_sal_arch () */ 33 #include "source.h" 34 #include "filenames.h" 35 #include "fnmatch.h" 36 #include "gdbsupport/gdb_regex.h" 37 #include "gdbsupport/gdb_optional.h" 38 #include <list> 39 #include "cli/cli-style.h" 40 #include "gdbsupport/buildargv.h" 41 42 /* True if we want to print debug printouts related to file/function 43 skipping. */ 44 static bool debug_skip = false; 45 46 class skiplist_entry 47 { 48 public: 49 /* Create a skiplist_entry object and add it to the chain. */ 50 static void add_entry (bool file_is_glob, 51 std::string &&file, 52 bool function_is_regexp, 53 std::string &&function); 54 55 /* Return true if the skip entry has a file or glob-style file 56 pattern that matches FUNCTION_SAL. */ 57 bool skip_file_p (const symtab_and_line &function_sal) const; 58 59 /* Return true if the skip entry has a function or function regexp 60 that matches FUNCTION_NAME. */ 61 bool skip_function_p (const char *function_name) const; 62 63 /* Getters. */ 64 int number () const { return m_number; }; 65 bool enabled () const { return m_enabled; }; 66 bool file_is_glob () const { return m_file_is_glob; } 67 const std::string &file () const { return m_file; } 68 const std::string &function () const { return m_function; } 69 bool function_is_regexp () const { return m_function_is_regexp; } 70 71 /* Setters. */ 72 void enable () { m_enabled = true; }; 73 void disable () { m_enabled = false; }; 74 75 /* Disable copy. */ 76 skiplist_entry (const skiplist_entry &) = delete; 77 void operator= (const skiplist_entry &) = delete; 78 79 private: 80 /* Key that grants access to the constructor. */ 81 struct private_key {}; 82 public: 83 /* Public so we can construct with container::emplace_back. Since 84 it requires a private class key, it can't be called from outside. 85 Use the add_entry static factory method to construct instead. */ 86 skiplist_entry (bool file_is_glob, std::string &&file, 87 bool function_is_regexp, std::string &&function, 88 private_key); 89 90 private: 91 /* Return true if we're stopped at a file to be skipped. */ 92 bool do_skip_file_p (const symtab_and_line &function_sal) const; 93 94 /* Return true if we're stopped at a globbed file to be skipped. */ 95 bool do_skip_gfile_p (const symtab_and_line &function_sal) const; 96 97 private: /* data */ 98 int m_number = -1; 99 100 /* True if FILE is a glob-style pattern. 101 Otherwise it is the plain file name (possibly with directories). */ 102 bool m_file_is_glob; 103 104 /* The name of the file or empty if no name. */ 105 std::string m_file; 106 107 /* True if FUNCTION is a regexp. 108 Otherwise it is a plain function name (possibly with arguments, 109 for C++). */ 110 bool m_function_is_regexp; 111 112 /* The name of the function or empty if no name. */ 113 std::string m_function; 114 115 /* If this is a function regexp, the compiled form. */ 116 gdb::optional<compiled_regex> m_compiled_function_regexp; 117 118 /* Enabled/disabled state. */ 119 bool m_enabled = true; 120 }; 121 122 static std::list<skiplist_entry> skiplist_entries; 123 static int highest_skiplist_entry_num = 0; 124 125 skiplist_entry::skiplist_entry (bool file_is_glob, 126 std::string &&file, 127 bool function_is_regexp, 128 std::string &&function, 129 private_key) 130 : m_file_is_glob (file_is_glob), 131 m_file (std::move (file)), 132 m_function_is_regexp (function_is_regexp), 133 m_function (std::move (function)) 134 { 135 gdb_assert (!m_file.empty () || !m_function.empty ()); 136 137 if (m_file_is_glob) 138 gdb_assert (!m_file.empty ()); 139 140 if (m_function_is_regexp) 141 { 142 gdb_assert (!m_function.empty ()); 143 m_compiled_function_regexp.emplace (m_function.c_str (), 144 REG_NOSUB | REG_EXTENDED, 145 _("regexp")); 146 } 147 } 148 149 void 150 skiplist_entry::add_entry (bool file_is_glob, std::string &&file, 151 bool function_is_regexp, std::string &&function) 152 { 153 skiplist_entries.emplace_back (file_is_glob, 154 std::move (file), 155 function_is_regexp, 156 std::move (function), 157 private_key {}); 158 159 /* Incremented after push_back, in case push_back throws. */ 160 skiplist_entries.back ().m_number = ++highest_skiplist_entry_num; 161 } 162 163 static void 164 skip_file_command (const char *arg, int from_tty) 165 { 166 struct symtab *symtab; 167 const char *filename = NULL; 168 169 /* If no argument was given, try to default to the last 170 displayed codepoint. */ 171 if (arg == NULL) 172 { 173 symtab = get_last_displayed_symtab (); 174 if (symtab == NULL) 175 error (_("No default file now.")); 176 177 /* It is not a typo, symtab_to_filename_for_display would be needlessly 178 ambiguous. */ 179 filename = symtab_to_fullname (symtab); 180 } 181 else 182 filename = arg; 183 184 skiplist_entry::add_entry (false, std::string (filename), 185 false, std::string ()); 186 187 gdb_printf (_("File %s will be skipped when stepping.\n"), filename); 188 } 189 190 /* Create a skiplist entry for the given function NAME and add it to the 191 list. */ 192 193 static void 194 skip_function (const char *name) 195 { 196 skiplist_entry::add_entry (false, std::string (), false, std::string (name)); 197 198 gdb_printf (_("Function %s will be skipped when stepping.\n"), name); 199 } 200 201 static void 202 skip_function_command (const char *arg, int from_tty) 203 { 204 /* Default to the current function if no argument is given. */ 205 if (arg == NULL) 206 { 207 frame_info_ptr fi = get_selected_frame (_("No default function now.")); 208 struct symbol *sym = get_frame_function (fi); 209 const char *name = NULL; 210 211 if (sym != NULL) 212 name = sym->print_name (); 213 else 214 error (_("No function found containing current program point %s."), 215 paddress (get_current_arch (), get_frame_pc (fi))); 216 skip_function (name); 217 return; 218 } 219 220 skip_function (arg); 221 } 222 223 /* Process "skip ..." that does not match "skip file" or "skip function". */ 224 225 static void 226 skip_command (const char *arg, int from_tty) 227 { 228 const char *file = NULL; 229 const char *gfile = NULL; 230 const char *function = NULL; 231 const char *rfunction = NULL; 232 int i; 233 234 if (arg == NULL) 235 { 236 skip_function_command (arg, from_tty); 237 return; 238 } 239 240 gdb_argv argv (arg); 241 242 for (i = 0; argv[i] != NULL; ++i) 243 { 244 const char *p = argv[i]; 245 const char *value = argv[i + 1]; 246 247 if (strcmp (p, "-fi") == 0 248 || strcmp (p, "-file") == 0) 249 { 250 if (value == NULL) 251 error (_("Missing value for %s option."), p); 252 file = value; 253 ++i; 254 } 255 else if (strcmp (p, "-gfi") == 0 256 || strcmp (p, "-gfile") == 0) 257 { 258 if (value == NULL) 259 error (_("Missing value for %s option."), p); 260 gfile = value; 261 ++i; 262 } 263 else if (strcmp (p, "-fu") == 0 264 || strcmp (p, "-function") == 0) 265 { 266 if (value == NULL) 267 error (_("Missing value for %s option."), p); 268 function = value; 269 ++i; 270 } 271 else if (strcmp (p, "-rfu") == 0 272 || strcmp (p, "-rfunction") == 0) 273 { 274 if (value == NULL) 275 error (_("Missing value for %s option."), p); 276 rfunction = value; 277 ++i; 278 } 279 else if (*p == '-') 280 error (_("Invalid skip option: %s"), p); 281 else if (i == 0) 282 { 283 /* Assume the user entered "skip FUNCTION-NAME". 284 FUNCTION-NAME may be `foo (int)', and therefore we pass the 285 complete original arg to skip_function command as if the user 286 typed "skip function arg". */ 287 skip_function_command (arg, from_tty); 288 return; 289 } 290 else 291 error (_("Invalid argument: %s"), p); 292 } 293 294 if (file != NULL && gfile != NULL) 295 error (_("Cannot specify both -file and -gfile.")); 296 297 if (function != NULL && rfunction != NULL) 298 error (_("Cannot specify both -function and -rfunction.")); 299 300 /* This shouldn't happen as "skip" by itself gets punted to 301 skip_function_command. */ 302 gdb_assert (file != NULL || gfile != NULL 303 || function != NULL || rfunction != NULL); 304 305 std::string entry_file; 306 if (file != NULL) 307 entry_file = file; 308 else if (gfile != NULL) 309 entry_file = gfile; 310 311 std::string entry_function; 312 if (function != NULL) 313 entry_function = function; 314 else if (rfunction != NULL) 315 entry_function = rfunction; 316 317 skiplist_entry::add_entry (gfile != NULL, std::move (entry_file), 318 rfunction != NULL, std::move (entry_function)); 319 320 /* I18N concerns drive some of the choices here (we can't piece together 321 the output too much). OTOH we want to keep this simple. Therefore the 322 only polish we add to the output is to append "(s)" to "File" or 323 "Function" if they're a glob/regexp. */ 324 { 325 const char *file_to_print = file != NULL ? file : gfile; 326 const char *function_to_print = function != NULL ? function : rfunction; 327 const char *file_text = gfile != NULL ? _("File(s)") : _("File"); 328 const char *lower_file_text = gfile != NULL ? _("file(s)") : _("file"); 329 const char *function_text 330 = rfunction != NULL ? _("Function(s)") : _("Function"); 331 332 if (function_to_print == NULL) 333 { 334 gdb_printf (_("%s %s will be skipped when stepping.\n"), 335 file_text, file_to_print); 336 } 337 else if (file_to_print == NULL) 338 { 339 gdb_printf (_("%s %s will be skipped when stepping.\n"), 340 function_text, function_to_print); 341 } 342 else 343 { 344 gdb_printf (_("%s %s in %s %s will be skipped" 345 " when stepping.\n"), 346 function_text, function_to_print, 347 lower_file_text, file_to_print); 348 } 349 } 350 } 351 352 static void 353 info_skip_command (const char *arg, int from_tty) 354 { 355 int num_printable_entries = 0; 356 struct value_print_options opts; 357 358 get_user_print_options (&opts); 359 360 /* Count the number of rows in the table and see if we need space for a 361 64-bit address anywhere. */ 362 for (const skiplist_entry &e : skiplist_entries) 363 if (arg == NULL || number_is_in_list (arg, e.number ())) 364 num_printable_entries++; 365 366 if (num_printable_entries == 0) 367 { 368 if (arg == NULL) 369 current_uiout->message (_("Not skipping any files or functions.\n")); 370 else 371 current_uiout->message ( 372 _("No skiplist entries found with number %s.\n"), arg); 373 374 return; 375 } 376 377 ui_out_emit_table table_emitter (current_uiout, 6, num_printable_entries, 378 "SkiplistTable"); 379 380 current_uiout->table_header (5, ui_left, "number", "Num"); /* 1 */ 381 current_uiout->table_header (3, ui_left, "enabled", "Enb"); /* 2 */ 382 current_uiout->table_header (4, ui_right, "regexp", "Glob"); /* 3 */ 383 current_uiout->table_header (20, ui_left, "file", "File"); /* 4 */ 384 current_uiout->table_header (2, ui_right, "regexp", "RE"); /* 5 */ 385 current_uiout->table_header (40, ui_noalign, "function", "Function"); /* 6 */ 386 current_uiout->table_body (); 387 388 for (const skiplist_entry &e : skiplist_entries) 389 { 390 QUIT; 391 if (arg != NULL && !number_is_in_list (arg, e.number ())) 392 continue; 393 394 ui_out_emit_tuple tuple_emitter (current_uiout, "blklst-entry"); 395 current_uiout->field_signed ("number", e.number ()); /* 1 */ 396 397 if (e.enabled ()) 398 current_uiout->field_string ("enabled", "y"); /* 2 */ 399 else 400 current_uiout->field_string ("enabled", "n"); /* 2 */ 401 402 if (e.file_is_glob ()) 403 current_uiout->field_string ("regexp", "y"); /* 3 */ 404 else 405 current_uiout->field_string ("regexp", "n"); /* 3 */ 406 407 current_uiout->field_string ("file", 408 e.file ().empty () ? "<none>" 409 : e.file ().c_str (), 410 e.file ().empty () 411 ? metadata_style.style () 412 : file_name_style.style ()); /* 4 */ 413 if (e.function_is_regexp ()) 414 current_uiout->field_string ("regexp", "y"); /* 5 */ 415 else 416 current_uiout->field_string ("regexp", "n"); /* 5 */ 417 418 current_uiout->field_string ("function", 419 e.function ().empty () ? "<none>" 420 : e.function ().c_str (), 421 e.function ().empty () 422 ? metadata_style.style () 423 : function_name_style.style ()); /* 6 */ 424 425 current_uiout->text ("\n"); 426 } 427 } 428 429 static void 430 skip_enable_command (const char *arg, int from_tty) 431 { 432 bool found = false; 433 434 for (skiplist_entry &e : skiplist_entries) 435 if (arg == NULL || number_is_in_list (arg, e.number ())) 436 { 437 e.enable (); 438 found = true; 439 } 440 441 if (!found) 442 error (_("No skiplist entries found with number %s."), arg); 443 } 444 445 static void 446 skip_disable_command (const char *arg, int from_tty) 447 { 448 bool found = false; 449 450 for (skiplist_entry &e : skiplist_entries) 451 if (arg == NULL || number_is_in_list (arg, e.number ())) 452 { 453 e.disable (); 454 found = true; 455 } 456 457 if (!found) 458 error (_("No skiplist entries found with number %s."), arg); 459 } 460 461 static void 462 skip_delete_command (const char *arg, int from_tty) 463 { 464 bool found = false; 465 466 for (auto it = skiplist_entries.begin (), 467 end = skiplist_entries.end (); 468 it != end;) 469 { 470 const skiplist_entry &e = *it; 471 472 if (arg == NULL || number_is_in_list (arg, e.number ())) 473 { 474 it = skiplist_entries.erase (it); 475 found = true; 476 } 477 else 478 ++it; 479 } 480 481 if (!found) 482 error (_("No skiplist entries found with number %s."), arg); 483 } 484 485 bool 486 skiplist_entry::do_skip_file_p (const symtab_and_line &function_sal) const 487 { 488 if (debug_skip) 489 gdb_printf (gdb_stdlog, 490 "skip: checking if file %s matches non-glob %s...", 491 function_sal.symtab->filename, m_file.c_str ()); 492 493 bool result; 494 495 /* Check first sole SYMTAB->FILENAME. It may not be a substring of 496 symtab_to_fullname as it may contain "./" etc. */ 497 if (compare_filenames_for_search (function_sal.symtab->filename, 498 m_file.c_str ())) 499 result = true; 500 501 /* Before we invoke realpath, which can get expensive when many 502 files are involved, do a quick comparison of the basenames. */ 503 else if (!basenames_may_differ 504 && filename_cmp (lbasename (function_sal.symtab->filename), 505 lbasename (m_file.c_str ())) != 0) 506 result = false; 507 else 508 { 509 /* Note: symtab_to_fullname caches its result, thus we don't have to. */ 510 const char *fullname = symtab_to_fullname (function_sal.symtab); 511 512 result = compare_filenames_for_search (fullname, m_file.c_str ()); 513 } 514 515 if (debug_skip) 516 gdb_printf (gdb_stdlog, result ? "yes.\n" : "no.\n"); 517 518 return result; 519 } 520 521 bool 522 skiplist_entry::do_skip_gfile_p (const symtab_and_line &function_sal) const 523 { 524 if (debug_skip) 525 gdb_printf (gdb_stdlog, 526 "skip: checking if file %s matches glob %s...", 527 function_sal.symtab->filename, m_file.c_str ()); 528 529 bool result; 530 531 /* Check first sole SYMTAB->FILENAME. It may not be a substring of 532 symtab_to_fullname as it may contain "./" etc. */ 533 if (gdb_filename_fnmatch (m_file.c_str (), function_sal.symtab->filename, 534 FNM_FILE_NAME | FNM_NOESCAPE) == 0) 535 result = true; 536 537 /* Before we invoke symtab_to_fullname, which is expensive, do a quick 538 comparison of the basenames. 539 Note that we assume that lbasename works with glob-style patterns. 540 If the basename of the glob pattern is something like "*.c" then this 541 isn't much of a win. Oh well. */ 542 else if (!basenames_may_differ 543 && gdb_filename_fnmatch (lbasename (m_file.c_str ()), 544 lbasename (function_sal.symtab->filename), 545 FNM_FILE_NAME | FNM_NOESCAPE) != 0) 546 result = false; 547 else 548 { 549 /* Note: symtab_to_fullname caches its result, thus we don't have to. */ 550 const char *fullname = symtab_to_fullname (function_sal.symtab); 551 552 result = compare_glob_filenames_for_search (fullname, m_file.c_str ()); 553 } 554 555 if (debug_skip) 556 gdb_printf (gdb_stdlog, result ? "yes.\n" : "no.\n"); 557 558 return result; 559 } 560 561 bool 562 skiplist_entry::skip_file_p (const symtab_and_line &function_sal) const 563 { 564 if (m_file.empty ()) 565 return false; 566 567 if (function_sal.symtab == NULL) 568 return false; 569 570 if (m_file_is_glob) 571 return do_skip_gfile_p (function_sal); 572 else 573 return do_skip_file_p (function_sal); 574 } 575 576 bool 577 skiplist_entry::skip_function_p (const char *function_name) const 578 { 579 if (m_function.empty ()) 580 return false; 581 582 bool result; 583 584 if (m_function_is_regexp) 585 { 586 if (debug_skip) 587 gdb_printf (gdb_stdlog, 588 "skip: checking if function %s matches regex %s...", 589 function_name, m_function.c_str ()); 590 591 gdb_assert (m_compiled_function_regexp); 592 result 593 = (m_compiled_function_regexp->exec (function_name, 0, NULL, 0) == 0); 594 } 595 else 596 { 597 if (debug_skip) 598 gdb_printf (gdb_stdlog, 599 ("skip: checking if function %s matches non-regex " 600 "%s..."), 601 function_name, m_function.c_str ()); 602 result = (strcmp_iw (function_name, m_function.c_str ()) == 0); 603 } 604 605 if (debug_skip) 606 gdb_printf (gdb_stdlog, result ? "yes.\n" : "no.\n"); 607 608 return result; 609 } 610 611 /* See skip.h. */ 612 613 bool 614 function_name_is_marked_for_skip (const char *function_name, 615 const symtab_and_line &function_sal) 616 { 617 if (function_name == NULL) 618 return false; 619 620 for (const skiplist_entry &e : skiplist_entries) 621 { 622 if (!e.enabled ()) 623 continue; 624 625 bool skip_by_file = e.skip_file_p (function_sal); 626 bool skip_by_function = e.skip_function_p (function_name); 627 628 /* If both file and function must match, make sure we don't errantly 629 exit if only one of them match. */ 630 if (!e.file ().empty () && !e.function ().empty ()) 631 { 632 if (skip_by_file && skip_by_function) 633 return true; 634 } 635 /* Only one of file/function is specified. */ 636 else if (skip_by_file || skip_by_function) 637 return true; 638 } 639 640 return false; 641 } 642 643 /* Completer for skip numbers. */ 644 645 static void 646 complete_skip_number (cmd_list_element *cmd, 647 completion_tracker &completer, 648 const char *text, const char *word) 649 { 650 size_t word_len = strlen (word); 651 652 for (const skiplist_entry &entry : skiplist_entries) 653 { 654 gdb::unique_xmalloc_ptr<char> name = xstrprintf ("%d", entry.number ()); 655 if (strncmp (word, name.get (), word_len) == 0) 656 completer.add_completion (std::move (name)); 657 } 658 } 659 660 void _initialize_step_skip (); 661 void 662 _initialize_step_skip () 663 { 664 static struct cmd_list_element *skiplist = NULL; 665 struct cmd_list_element *c; 666 667 add_prefix_cmd ("skip", class_breakpoint, skip_command, _("\ 668 Ignore a function while stepping.\n\ 669 \n\ 670 Usage: skip [FUNCTION-NAME]\n\ 671 skip [FILE-SPEC] [FUNCTION-SPEC]\n\ 672 If no arguments are given, ignore the current function.\n\ 673 \n\ 674 FILE-SPEC is one of:\n\ 675 -fi|-file FILE-NAME\n\ 676 -gfi|-gfile GLOB-FILE-PATTERN\n\ 677 FUNCTION-SPEC is one of:\n\ 678 -fu|-function FUNCTION-NAME\n\ 679 -rfu|-rfunction FUNCTION-NAME-REGULAR-EXPRESSION"), 680 &skiplist, 1, &cmdlist); 681 682 c = add_cmd ("file", class_breakpoint, skip_file_command, _("\ 683 Ignore a file while stepping.\n\ 684 Usage: skip file [FILE-NAME]\n\ 685 If no filename is given, ignore the current file."), 686 &skiplist); 687 set_cmd_completer (c, filename_completer); 688 689 c = add_cmd ("function", class_breakpoint, skip_function_command, _("\ 690 Ignore a function while stepping.\n\ 691 Usage: skip function [FUNCTION-NAME]\n\ 692 If no function name is given, skip the current function."), 693 &skiplist); 694 set_cmd_completer (c, location_completer); 695 696 c = add_cmd ("enable", class_breakpoint, skip_enable_command, _("\ 697 Enable skip entries.\n\ 698 Usage: skip enable [NUMBER | RANGE]...\n\ 699 You can specify numbers (e.g. \"skip enable 1 3\"),\n\ 700 ranges (e.g. \"skip enable 4-8\"), or both (e.g. \"skip enable 1 3 4-8\").\n\n\ 701 If you don't specify any numbers or ranges, we'll enable all skip entries."), 702 &skiplist); 703 set_cmd_completer (c, complete_skip_number); 704 705 c = add_cmd ("disable", class_breakpoint, skip_disable_command, _("\ 706 Disable skip entries.\n\ 707 Usage: skip disable [NUMBER | RANGE]...\n\ 708 You can specify numbers (e.g. \"skip disable 1 3\"),\n\ 709 ranges (e.g. \"skip disable 4-8\"), or both (e.g. \"skip disable 1 3 4-8\").\n\n\ 710 If you don't specify any numbers or ranges, we'll disable all skip entries."), 711 &skiplist); 712 set_cmd_completer (c, complete_skip_number); 713 714 c = add_cmd ("delete", class_breakpoint, skip_delete_command, _("\ 715 Delete skip entries.\n\ 716 Usage: skip delete [NUMBER | RANGES]...\n\ 717 You can specify numbers (e.g. \"skip delete 1 3\"),\n\ 718 ranges (e.g. \"skip delete 4-8\"), or both (e.g. \"skip delete 1 3 4-8\").\n\n\ 719 If you don't specify any numbers or ranges, we'll delete all skip entries."), 720 &skiplist); 721 set_cmd_completer (c, complete_skip_number); 722 723 add_info ("skip", info_skip_command, _("\ 724 Display the status of skips.\n\ 725 Usage: info skip [NUMBER | RANGES]...\n\ 726 You can specify numbers (e.g. \"info skip 1 3\"), \n\ 727 ranges (e.g. \"info skip 4-8\"), or both (e.g. \"info skip 1 3 4-8\").\n\n\ 728 If you don't specify any numbers or ranges, we'll show all skips.")); 729 set_cmd_completer (c, complete_skip_number); 730 731 add_setshow_boolean_cmd ("skip", class_maintenance, 732 &debug_skip, _("\ 733 Set whether to print the debug output about skipping files and functions."), 734 _("\ 735 Show whether the debug output about skipping files and functions is printed."), 736 _("\ 737 When non-zero, debug output about skipping files and functions is displayed."), 738 NULL, NULL, 739 &setdebuglist, &showdebuglist); 740 } 741