]> Git Repo - binutils.git/blob - gdb/skip.c
Update copyright year range in all GDB files.
[binutils.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.067225 seconds and 4 git commands to generate.