x86: refine when to trigger optimizations
[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 const char *name = NULL;
213 CORE_ADDR pc;
214
215 if (!last_displayed_sal_is_valid ())
216 error (_("No default function now."));
217
218 pc = get_last_displayed_addr ();
219 if (!find_pc_partial_function (pc, &name, NULL, NULL))
220 {
221 error (_("No function found containing current program point %s."),
222 paddress (get_current_arch (), pc));
223 }
224 skip_function (name);
225 return;
226 }
227
228 skip_function (arg);
229 }
230
231 /* Process "skip ..." that does not match "skip file" or "skip function". */
232
233 static void
234 skip_command (const char *arg, int from_tty)
235 {
236 const char *file = NULL;
237 const char *gfile = NULL;
238 const char *function = NULL;
239 const char *rfunction = NULL;
240 int i;
241
242 if (arg == NULL)
243 {
244 skip_function_command (arg, from_tty);
245 return;
246 }
247
248 gdb_argv argv (arg);
249
250 for (i = 0; argv[i] != NULL; ++i)
251 {
252 const char *p = argv[i];
253 const char *value = argv[i + 1];
254
255 if (strcmp (p, "-fi") == 0
256 || strcmp (p, "-file") == 0)
257 {
258 if (value == NULL)
259 error (_("Missing value for %s option."), p);
260 file = value;
261 ++i;
262 }
263 else if (strcmp (p, "-gfi") == 0
264 || strcmp (p, "-gfile") == 0)
265 {
266 if (value == NULL)
267 error (_("Missing value for %s option."), p);
268 gfile = value;
269 ++i;
270 }
271 else if (strcmp (p, "-fu") == 0
272 || strcmp (p, "-function") == 0)
273 {
274 if (value == NULL)
275 error (_("Missing value for %s option."), p);
276 function = value;
277 ++i;
278 }
279 else if (strcmp (p, "-rfu") == 0
280 || strcmp (p, "-rfunction") == 0)
281 {
282 if (value == NULL)
283 error (_("Missing value for %s option."), p);
284 rfunction = value;
285 ++i;
286 }
287 else if (*p == '-')
288 error (_("Invalid skip option: %s"), p);
289 else if (i == 0)
290 {
291 /* Assume the user entered "skip FUNCTION-NAME".
292 FUNCTION-NAME may be `foo (int)', and therefore we pass the
293 complete original arg to skip_function command as if the user
294 typed "skip function arg". */
295 skip_function_command (arg, from_tty);
296 return;
297 }
298 else
299 error (_("Invalid argument: %s"), p);
300 }
301
302 if (file != NULL && gfile != NULL)
303 error (_("Cannot specify both -file and -gfile."));
304
305 if (function != NULL && rfunction != NULL)
306 error (_("Cannot specify both -function and -rfunction."));
307
308 /* This shouldn't happen as "skip" by itself gets punted to
309 skip_function_command. */
310 gdb_assert (file != NULL || gfile != NULL
311 || function != NULL || rfunction != NULL);
312
313 std::string entry_file;
314 if (file != NULL)
315 entry_file = file;
316 else if (gfile != NULL)
317 entry_file = gfile;
318
319 std::string entry_function;
320 if (function != NULL)
321 entry_function = function;
322 else if (rfunction != NULL)
323 entry_function = rfunction;
324
325 skiplist_entry::add_entry (gfile != NULL, std::move (entry_file),
326 rfunction != NULL, std::move (entry_function));
327
328 /* I18N concerns drive some of the choices here (we can't piece together
329 the output too much). OTOH we want to keep this simple. Therefore the
330 only polish we add to the output is to append "(s)" to "File" or
331 "Function" if they're a glob/regexp. */
332 {
333 const char *file_to_print = file != NULL ? file : gfile;
334 const char *function_to_print = function != NULL ? function : rfunction;
335 const char *file_text = gfile != NULL ? _("File(s)") : _("File");
336 const char *lower_file_text = gfile != NULL ? _("file(s)") : _("file");
337 const char *function_text
338 = rfunction != NULL ? _("Function(s)") : _("Function");
339
340 if (function_to_print == NULL)
341 {
342 printf_filtered (_("%s %s will be skipped when stepping.\n"),
343 file_text, file_to_print);
344 }
345 else if (file_to_print == NULL)
346 {
347 printf_filtered (_("%s %s will be skipped when stepping.\n"),
348 function_text, function_to_print);
349 }
350 else
351 {
352 printf_filtered (_("%s %s in %s %s will be skipped"
353 " when stepping.\n"),
354 function_text, function_to_print,
355 lower_file_text, file_to_print);
356 }
357 }
358 }
359
360 static void
361 info_skip_command (const char *arg, int from_tty)
362 {
363 int num_printable_entries = 0;
364 struct value_print_options opts;
365
366 get_user_print_options (&opts);
367
368 /* Count the number of rows in the table and see if we need space for a
369 64-bit address anywhere. */
370 for (const skiplist_entry &e : skiplist_entries)
371 if (arg == NULL || number_is_in_list (arg, e.number ()))
372 num_printable_entries++;
373
374 if (num_printable_entries == 0)
375 {
376 if (arg == NULL)
377 current_uiout->message (_("Not skipping any files or functions.\n"));
378 else
379 current_uiout->message (
380 _("No skiplist entries found with number %s.\n"), arg);
381
382 return;
383 }
384
385 ui_out_emit_table table_emitter (current_uiout, 6, num_printable_entries,
386 "SkiplistTable");
387
388 current_uiout->table_header (5, ui_left, "number", "Num"); /* 1 */
389 current_uiout->table_header (3, ui_left, "enabled", "Enb"); /* 2 */
390 current_uiout->table_header (4, ui_right, "regexp", "Glob"); /* 3 */
391 current_uiout->table_header (20, ui_left, "file", "File"); /* 4 */
392 current_uiout->table_header (2, ui_right, "regexp", "RE"); /* 5 */
393 current_uiout->table_header (40, ui_noalign, "function", "Function"); /* 6 */
394 current_uiout->table_body ();
395
396 for (const skiplist_entry &e : skiplist_entries)
397 {
398 QUIT;
399 if (arg != NULL && !number_is_in_list (arg, e.number ()))
400 continue;
401
402 ui_out_emit_tuple tuple_emitter (current_uiout, "blklst-entry");
403 current_uiout->field_signed ("number", e.number ()); /* 1 */
404
405 if (e.enabled ())
406 current_uiout->field_string ("enabled", "y"); /* 2 */
407 else
408 current_uiout->field_string ("enabled", "n"); /* 2 */
409
410 if (e.file_is_glob ())
411 current_uiout->field_string ("regexp", "y"); /* 3 */
412 else
413 current_uiout->field_string ("regexp", "n"); /* 3 */
414
415 current_uiout->field_string ("file",
416 e.file ().empty () ? "<none>"
417 : e.file ().c_str (),
418 e.file ().empty ()
419 ? metadata_style.style ()
420 : file_name_style.style ()); /* 4 */
421 if (e.function_is_regexp ())
422 current_uiout->field_string ("regexp", "y"); /* 5 */
423 else
424 current_uiout->field_string ("regexp", "n"); /* 5 */
425
426 current_uiout->field_string ("function",
427 e.function ().empty () ? "<none>"
428 : e.function ().c_str (),
429 e.function ().empty ()
430 ? metadata_style.style ()
431 : function_name_style.style ()); /* 6 */
432
433 current_uiout->text ("\n");
434 }
435 }
436
437 static void
438 skip_enable_command (const char *arg, int from_tty)
439 {
440 bool found = false;
441
442 for (skiplist_entry &e : skiplist_entries)
443 if (arg == NULL || number_is_in_list (arg, e.number ()))
444 {
445 e.enable ();
446 found = true;
447 }
448
449 if (!found)
450 error (_("No skiplist entries found with number %s."), arg);
451 }
452
453 static void
454 skip_disable_command (const char *arg, int from_tty)
455 {
456 bool found = false;
457
458 for (skiplist_entry &e : skiplist_entries)
459 if (arg == NULL || number_is_in_list (arg, e.number ()))
460 {
461 e.disable ();
462 found = true;
463 }
464
465 if (!found)
466 error (_("No skiplist entries found with number %s."), arg);
467 }
468
469 static void
470 skip_delete_command (const char *arg, int from_tty)
471 {
472 bool found = false;
473
474 for (auto it = skiplist_entries.begin (),
475 end = skiplist_entries.end ();
476 it != end;)
477 {
478 const skiplist_entry &e = *it;
479
480 if (arg == NULL || number_is_in_list (arg, e.number ()))
481 {
482 it = skiplist_entries.erase (it);
483 found = true;
484 }
485 else
486 ++it;
487 }
488
489 if (!found)
490 error (_("No skiplist entries found with number %s."), arg);
491 }
492
493 bool
494 skiplist_entry::do_skip_file_p (const symtab_and_line &function_sal) const
495 {
496 if (debug_skip)
497 fprintf_unfiltered (gdb_stdlog,
498 "skip: checking if file %s matches non-glob %s...",
499 function_sal.symtab->filename, m_file.c_str ());
500
501 bool result;
502
503 /* Check first sole SYMTAB->FILENAME. It may not be a substring of
504 symtab_to_fullname as it may contain "./" etc. */
505 if (compare_filenames_for_search (function_sal.symtab->filename,
506 m_file.c_str ()))
507 result = true;
508
509 /* Before we invoke realpath, which can get expensive when many
510 files are involved, do a quick comparison of the basenames. */
511 else if (!basenames_may_differ
512 && filename_cmp (lbasename (function_sal.symtab->filename),
513 lbasename (m_file.c_str ())) != 0)
514 result = false;
515 else
516 {
517 /* Note: symtab_to_fullname caches its result, thus we don't have to. */
518 const char *fullname = symtab_to_fullname (function_sal.symtab);
519
520 result = compare_filenames_for_search (fullname, m_file.c_str ());
521 }
522
523 if (debug_skip)
524 fprintf_unfiltered (gdb_stdlog, result ? "yes.\n" : "no.\n");
525
526 return result;
527 }
528
529 bool
530 skiplist_entry::do_skip_gfile_p (const symtab_and_line &function_sal) const
531 {
532 if (debug_skip)
533 fprintf_unfiltered (gdb_stdlog,
534 "skip: checking if file %s matches glob %s...",
535 function_sal.symtab->filename, m_file.c_str ());
536
537 bool result;
538
539 /* Check first sole SYMTAB->FILENAME. It may not be a substring of
540 symtab_to_fullname as it may contain "./" etc. */
541 if (gdb_filename_fnmatch (m_file.c_str (), function_sal.symtab->filename,
542 FNM_FILE_NAME | FNM_NOESCAPE) == 0)
543 result = true;
544
545 /* Before we invoke symtab_to_fullname, which is expensive, do a quick
546 comparison of the basenames.
547 Note that we assume that lbasename works with glob-style patterns.
548 If the basename of the glob pattern is something like "*.c" then this
549 isn't much of a win. Oh well. */
550 else if (!basenames_may_differ
551 && gdb_filename_fnmatch (lbasename (m_file.c_str ()),
552 lbasename (function_sal.symtab->filename),
553 FNM_FILE_NAME | FNM_NOESCAPE) != 0)
554 result = false;
555 else
556 {
557 /* Note: symtab_to_fullname caches its result, thus we don't have to. */
558 const char *fullname = symtab_to_fullname (function_sal.symtab);
559
560 result = compare_glob_filenames_for_search (fullname, m_file.c_str ());
561 }
562
563 if (debug_skip)
564 fprintf_unfiltered (gdb_stdlog, result ? "yes.\n" : "no.\n");
565
566 return result;
567 }
568
569 bool
570 skiplist_entry::skip_file_p (const symtab_and_line &function_sal) const
571 {
572 if (m_file.empty ())
573 return false;
574
575 if (function_sal.symtab == NULL)
576 return false;
577
578 if (m_file_is_glob)
579 return do_skip_gfile_p (function_sal);
580 else
581 return do_skip_file_p (function_sal);
582 }
583
584 bool
585 skiplist_entry::skip_function_p (const char *function_name) const
586 {
587 if (m_function.empty ())
588 return false;
589
590 bool result;
591
592 if (m_function_is_regexp)
593 {
594 if (debug_skip)
595 fprintf_unfiltered (gdb_stdlog,
596 "skip: checking if function %s matches regex %s...",
597 function_name, m_function.c_str ());
598
599 gdb_assert (m_compiled_function_regexp);
600 result
601 = (m_compiled_function_regexp->exec (function_name, 0, NULL, 0) == 0);
602 }
603 else
604 {
605 if (debug_skip)
606 fprintf_unfiltered (gdb_stdlog,
607 ("skip: checking if function %s matches non-regex "
608 "%s..."),
609 function_name, m_function.c_str ());
610 result = (strcmp_iw (function_name, m_function.c_str ()) == 0);
611 }
612
613 if (debug_skip)
614 fprintf_unfiltered (gdb_stdlog, result ? "yes.\n" : "no.\n");
615
616 return result;
617 }
618
619 /* See skip.h. */
620
621 bool
622 function_name_is_marked_for_skip (const char *function_name,
623 const symtab_and_line &function_sal)
624 {
625 if (function_name == NULL)
626 return false;
627
628 for (const skiplist_entry &e : skiplist_entries)
629 {
630 if (!e.enabled ())
631 continue;
632
633 bool skip_by_file = e.skip_file_p (function_sal);
634 bool skip_by_function = e.skip_function_p (function_name);
635
636 /* If both file and function must match, make sure we don't errantly
637 exit if only one of them match. */
638 if (!e.file ().empty () && !e.function ().empty ())
639 {
640 if (skip_by_file && skip_by_function)
641 return true;
642 }
643 /* Only one of file/function is specified. */
644 else if (skip_by_file || skip_by_function)
645 return true;
646 }
647
648 return false;
649 }
650
651 /* Completer for skip numbers. */
652
653 static void
654 complete_skip_number (cmd_list_element *cmd,
655 completion_tracker &completer,
656 const char *text, const char *word)
657 {
658 size_t word_len = strlen (word);
659
660 for (const skiplist_entry &entry : skiplist_entries)
661 {
662 gdb::unique_xmalloc_ptr<char> name (xstrprintf ("%d", entry.number ()));
663 if (strncmp (word, name.get (), word_len) == 0)
664 completer.add_completion (std::move (name));
665 }
666 }
667
668 void
669 _initialize_step_skip (void)
670 {
671 static struct cmd_list_element *skiplist = NULL;
672 struct cmd_list_element *c;
673
674 add_prefix_cmd ("skip", class_breakpoint, skip_command, _("\
675 Ignore a function while stepping.\n\
676 \n\
677 Usage: skip [FUNCTION-NAME]\n\
678 skip [FILE-SPEC] [FUNCTION-SPEC]\n\
679 If no arguments are given, ignore the current function.\n\
680 \n\
681 FILE-SPEC is one of:\n\
682 -fi|-file FILE-NAME\n\
683 -gfi|-gfile GLOB-FILE-PATTERN\n\
684 FUNCTION-SPEC is one of:\n\
685 -fu|-function FUNCTION-NAME\n\
686 -rfu|-rfunction FUNCTION-NAME-REGULAR-EXPRESSION"),
687 &skiplist, "skip ", 1, &cmdlist);
688
689 c = add_cmd ("file", class_breakpoint, skip_file_command, _("\
690 Ignore a file while stepping.\n\
691 Usage: skip file [FILE-NAME]\n\
692 If no filename is given, ignore the current file."),
693 &skiplist);
694 set_cmd_completer (c, filename_completer);
695
696 c = add_cmd ("function", class_breakpoint, skip_function_command, _("\
697 Ignore a function while stepping.\n\
698 Usage: skip function [FUNCTION-NAME]\n\
699 If no function name is given, skip the current function."),
700 &skiplist);
701 set_cmd_completer (c, location_completer);
702
703 c = add_cmd ("enable", class_breakpoint, skip_enable_command, _("\
704 Enable skip entries.\n\
705 Usage: skip enable [NUMBER | RANGE]...\n\
706 You can specify numbers (e.g. \"skip enable 1 3\"),\n\
707 ranges (e.g. \"skip enable 4-8\"), or both (e.g. \"skip enable 1 3 4-8\").\n\n\
708 If you don't specify any numbers or ranges, we'll enable all skip entries."),
709 &skiplist);
710 set_cmd_completer (c, complete_skip_number);
711
712 c = add_cmd ("disable", class_breakpoint, skip_disable_command, _("\
713 Disable skip entries.\n\
714 Usage: skip disable [NUMBER | RANGE]...\n\
715 You can specify numbers (e.g. \"skip disable 1 3\"),\n\
716 ranges (e.g. \"skip disable 4-8\"), or both (e.g. \"skip disable 1 3 4-8\").\n\n\
717 If you don't specify any numbers or ranges, we'll disable all skip entries."),
718 &skiplist);
719 set_cmd_completer (c, complete_skip_number);
720
721 c = add_cmd ("delete", class_breakpoint, skip_delete_command, _("\
722 Delete skip entries.\n\
723 Usage: skip delete [NUMBER | RANGES]...\n\
724 You can specify numbers (e.g. \"skip delete 1 3\"),\n\
725 ranges (e.g. \"skip delete 4-8\"), or both (e.g. \"skip delete 1 3 4-8\").\n\n\
726 If you don't specify any numbers or ranges, we'll delete all skip entries."),
727 &skiplist);
728 set_cmd_completer (c, complete_skip_number);
729
730 add_info ("skip", info_skip_command, _("\
731 Display the status of skips.\n\
732 Usage: info skip [NUMBER | RANGES]...\n\
733 You can specify numbers (e.g. \"info skip 1 3\"), \n\
734 ranges (e.g. \"info skip 4-8\"), or both (e.g. \"info skip 1 3 4-8\").\n\n\
735 If you don't specify any numbers or ranges, we'll show all skips."));
736 set_cmd_completer (c, complete_skip_number);
737
738 add_setshow_boolean_cmd ("skip", class_maintenance,
739 &debug_skip, _("\
740 Set whether to print the debug output about skipping files and functions."),
741 _("\
742 Show whether the debug output about skipping files and functions is printed."),
743 _("\
744 When non-zero, debug output about skipping files and functions is displayed."),
745 NULL, NULL,
746 &setdebuglist, &showdebuglist);
747 }
This page took 0.043226 seconds and 4 git commands to generate.