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