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