1 /* Skipping uninteresting files and functions while stepping.
3 Copyright (C) 2011-2020 Free Software Foundation, Inc.
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.
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.
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/>. */
26 #include "completer.h"
28 #include "cli/cli-utils.h"
29 #include "arch-utils.h"
32 #include "breakpoint.h" /* for get_sal_arch () */
34 #include "filenames.h"
36 #include "gdb_regex.h"
37 #include "gdbsupport/gdb_optional.h"
39 #include "cli/cli-style.h"
41 /* True if we want to print debug printouts related to file/function
43 static bool debug_skip
= false;
48 /* Create a skiplist_entry object and add it to the chain. */
49 static void add_entry (bool file_is_glob
,
51 bool function_is_regexp
,
52 std::string
&&function
);
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;
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;
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
; }
71 void enable () { m_enabled
= true; };
72 void disable () { m_enabled
= false; };
75 skiplist_entry (const skiplist_entry
&) = delete;
76 void operator= (const skiplist_entry
&) = delete;
79 /* Key that grants access to the constructor. */
80 struct private_key
{};
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
,
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;
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;
99 /* True if FILE is a glob-style pattern.
100 Otherwise it is the plain file name (possibly with directories). */
103 /* The name of the file or empty if no name. */
106 /* True if FUNCTION is a regexp.
107 Otherwise it is a plain function name (possibly with arguments,
109 bool m_function_is_regexp
;
111 /* The name of the function or empty if no name. */
112 std::string m_function
;
114 /* If this is a function regexp, the compiled form. */
115 gdb::optional
<compiled_regex
> m_compiled_function_regexp
;
117 /* Enabled/disabled state. */
118 bool m_enabled
= true;
121 static std::list
<skiplist_entry
> skiplist_entries
;
122 static int highest_skiplist_entry_num
= 0;
124 skiplist_entry::skiplist_entry (bool file_is_glob
,
126 bool function_is_regexp
,
127 std::string
&&function
,
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
))
134 gdb_assert (!m_file
.empty () || !m_function
.empty ());
137 gdb_assert (!m_file
.empty ());
139 if (m_function_is_regexp
)
141 gdb_assert (!m_function
.empty ());
143 int flags
= REG_NOSUB
;
145 flags
|= REG_EXTENDED
;
148 gdb_assert (!m_function
.empty ());
149 m_compiled_function_regexp
.emplace (m_function
.c_str (), flags
,
155 skiplist_entry::add_entry (bool file_is_glob
, std::string
&&file
,
156 bool function_is_regexp
, std::string
&&function
)
158 skiplist_entries
.emplace_back (file_is_glob
,
161 std::move (function
),
164 /* Incremented after push_back, in case push_back throws. */
165 skiplist_entries
.back ().m_number
= ++highest_skiplist_entry_num
;
169 skip_file_command (const char *arg
, int from_tty
)
171 struct symtab
*symtab
;
172 const char *filename
= NULL
;
174 /* If no argument was given, try to default to the last
175 displayed codepoint. */
178 symtab
= get_last_displayed_symtab ();
180 error (_("No default file now."));
182 /* It is not a typo, symtab_to_filename_for_display would be needlessly
184 filename
= symtab_to_fullname (symtab
);
189 skiplist_entry::add_entry (false, std::string (filename
),
190 false, std::string ());
192 printf_filtered (_("File %s will be skipped when stepping.\n"), filename
);
195 /* Create a skiplist entry for the given function NAME and add it to the
199 skip_function (const char *name
)
201 skiplist_entry::add_entry (false, std::string (), false, std::string (name
));
203 printf_filtered (_("Function %s will be skipped when stepping.\n"), name
);
207 skip_function_command (const char *arg
, int from_tty
)
209 /* Default to the current function if no argument is given. */
212 frame_info
*fi
= get_selected_frame (_("No default function now."));
213 struct symbol
*sym
= get_frame_function (fi
);
214 const char *name
= NULL
;
217 name
= sym
->print_name ();
219 error (_("No function found containing current program point %s."),
220 paddress (get_current_arch (), get_frame_pc (fi
)));
221 skip_function (name
);
228 /* Process "skip ..." that does not match "skip file" or "skip function". */
231 skip_command (const char *arg
, int from_tty
)
233 const char *file
= NULL
;
234 const char *gfile
= NULL
;
235 const char *function
= NULL
;
236 const char *rfunction
= NULL
;
241 skip_function_command (arg
, from_tty
);
247 for (i
= 0; argv
[i
] != NULL
; ++i
)
249 const char *p
= argv
[i
];
250 const char *value
= argv
[i
+ 1];
252 if (strcmp (p
, "-fi") == 0
253 || strcmp (p
, "-file") == 0)
256 error (_("Missing value for %s option."), p
);
260 else if (strcmp (p
, "-gfi") == 0
261 || strcmp (p
, "-gfile") == 0)
264 error (_("Missing value for %s option."), p
);
268 else if (strcmp (p
, "-fu") == 0
269 || strcmp (p
, "-function") == 0)
272 error (_("Missing value for %s option."), p
);
276 else if (strcmp (p
, "-rfu") == 0
277 || strcmp (p
, "-rfunction") == 0)
280 error (_("Missing value for %s option."), p
);
285 error (_("Invalid skip option: %s"), p
);
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
);
296 error (_("Invalid argument: %s"), p
);
299 if (file
!= NULL
&& gfile
!= NULL
)
300 error (_("Cannot specify both -file and -gfile."));
302 if (function
!= NULL
&& rfunction
!= NULL
)
303 error (_("Cannot specify both -function and -rfunction."));
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
);
310 std::string entry_file
;
313 else if (gfile
!= NULL
)
316 std::string entry_function
;
317 if (function
!= NULL
)
318 entry_function
= function
;
319 else if (rfunction
!= NULL
)
320 entry_function
= rfunction
;
322 skiplist_entry::add_entry (gfile
!= NULL
, std::move (entry_file
),
323 rfunction
!= NULL
, std::move (entry_function
));
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. */
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");
337 if (function_to_print
== NULL
)
339 printf_filtered (_("%s %s will be skipped when stepping.\n"),
340 file_text
, file_to_print
);
342 else if (file_to_print
== NULL
)
344 printf_filtered (_("%s %s will be skipped when stepping.\n"),
345 function_text
, function_to_print
);
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
);
358 info_skip_command (const char *arg
, int from_tty
)
360 int num_printable_entries
= 0;
361 struct value_print_options opts
;
363 get_user_print_options (&opts
);
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
++;
371 if (num_printable_entries
== 0)
374 current_uiout
->message (_("Not skipping any files or functions.\n"));
376 current_uiout
->message (
377 _("No skiplist entries found with number %s.\n"), arg
);
382 ui_out_emit_table
table_emitter (current_uiout
, 6, num_printable_entries
,
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 ();
393 for (const skiplist_entry
&e
: skiplist_entries
)
396 if (arg
!= NULL
&& !number_is_in_list (arg
, e
.number ()))
399 ui_out_emit_tuple
tuple_emitter (current_uiout
, "blklst-entry");
400 current_uiout
->field_signed ("number", e
.number ()); /* 1 */
403 current_uiout
->field_string ("enabled", "y"); /* 2 */
405 current_uiout
->field_string ("enabled", "n"); /* 2 */
407 if (e
.file_is_glob ())
408 current_uiout
->field_string ("regexp", "y"); /* 3 */
410 current_uiout
->field_string ("regexp", "n"); /* 3 */
412 current_uiout
->field_string ("file",
413 e
.file ().empty () ? "<none>"
414 : e
.file ().c_str (),
416 ? metadata_style
.style ()
417 : file_name_style
.style ()); /* 4 */
418 if (e
.function_is_regexp ())
419 current_uiout
->field_string ("regexp", "y"); /* 5 */
421 current_uiout
->field_string ("regexp", "n"); /* 5 */
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 */
430 current_uiout
->text ("\n");
435 skip_enable_command (const char *arg
, int from_tty
)
439 for (skiplist_entry
&e
: skiplist_entries
)
440 if (arg
== NULL
|| number_is_in_list (arg
, e
.number ()))
447 error (_("No skiplist entries found with number %s."), arg
);
451 skip_disable_command (const char *arg
, int from_tty
)
455 for (skiplist_entry
&e
: skiplist_entries
)
456 if (arg
== NULL
|| number_is_in_list (arg
, e
.number ()))
463 error (_("No skiplist entries found with number %s."), arg
);
467 skip_delete_command (const char *arg
, int from_tty
)
471 for (auto it
= skiplist_entries
.begin (),
472 end
= skiplist_entries
.end ();
475 const skiplist_entry
&e
= *it
;
477 if (arg
== NULL
|| number_is_in_list (arg
, e
.number ()))
479 it
= skiplist_entries
.erase (it
);
487 error (_("No skiplist entries found with number %s."), arg
);
491 skiplist_entry::do_skip_file_p (const symtab_and_line
&function_sal
) const
494 fprintf_unfiltered (gdb_stdlog
,
495 "skip: checking if file %s matches non-glob %s...",
496 function_sal
.symtab
->filename
, m_file
.c_str ());
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
,
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)
514 /* Note: symtab_to_fullname caches its result, thus we don't have to. */
515 const char *fullname
= symtab_to_fullname (function_sal
.symtab
);
517 result
= compare_filenames_for_search (fullname
, m_file
.c_str ());
521 fprintf_unfiltered (gdb_stdlog
, result
? "yes.\n" : "no.\n");
527 skiplist_entry::do_skip_gfile_p (const symtab_and_line
&function_sal
) const
530 fprintf_unfiltered (gdb_stdlog
,
531 "skip: checking if file %s matches glob %s...",
532 function_sal
.symtab
->filename
, m_file
.c_str ());
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)
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)
554 /* Note: symtab_to_fullname caches its result, thus we don't have to. */
555 const char *fullname
= symtab_to_fullname (function_sal
.symtab
);
557 result
= compare_glob_filenames_for_search (fullname
, m_file
.c_str ());
561 fprintf_unfiltered (gdb_stdlog
, result
? "yes.\n" : "no.\n");
567 skiplist_entry::skip_file_p (const symtab_and_line
&function_sal
) const
572 if (function_sal
.symtab
== NULL
)
576 return do_skip_gfile_p (function_sal
);
578 return do_skip_file_p (function_sal
);
582 skiplist_entry::skip_function_p (const char *function_name
) const
584 if (m_function
.empty ())
589 if (m_function_is_regexp
)
592 fprintf_unfiltered (gdb_stdlog
,
593 "skip: checking if function %s matches regex %s...",
594 function_name
, m_function
.c_str ());
596 gdb_assert (m_compiled_function_regexp
);
598 = (m_compiled_function_regexp
->exec (function_name
, 0, NULL
, 0) == 0);
603 fprintf_unfiltered (gdb_stdlog
,
604 ("skip: checking if function %s matches non-regex "
606 function_name
, m_function
.c_str ());
607 result
= (strcmp_iw (function_name
, m_function
.c_str ()) == 0);
611 fprintf_unfiltered (gdb_stdlog
, result
? "yes.\n" : "no.\n");
619 function_name_is_marked_for_skip (const char *function_name
,
620 const symtab_and_line
&function_sal
)
622 if (function_name
== NULL
)
625 for (const skiplist_entry
&e
: skiplist_entries
)
630 bool skip_by_file
= e
.skip_file_p (function_sal
);
631 bool skip_by_function
= e
.skip_function_p (function_name
);
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 ())
637 if (skip_by_file
&& skip_by_function
)
640 /* Only one of file/function is specified. */
641 else if (skip_by_file
|| skip_by_function
)
648 /* Completer for skip numbers. */
651 complete_skip_number (cmd_list_element
*cmd
,
652 completion_tracker
&completer
,
653 const char *text
, const char *word
)
655 size_t word_len
= strlen (word
);
657 for (const skiplist_entry
&entry
: skiplist_entries
)
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
));
665 void _initialize_step_skip ();
667 _initialize_step_skip ()
669 static struct cmd_list_element
*skiplist
= NULL
;
670 struct cmd_list_element
*c
;
672 add_prefix_cmd ("skip", class_breakpoint
, skip_command
, _("\
673 Ignore a function while stepping.\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\
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
);
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."),
692 set_cmd_completer (c
, filename_completer
);
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."),
699 set_cmd_completer (c
, location_completer
);
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."),
708 set_cmd_completer (c
, complete_skip_number
);
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."),
717 set_cmd_completer (c
, complete_skip_number
);
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."),
726 set_cmd_completer (c
, complete_skip_number
);
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
);
736 add_setshow_boolean_cmd ("skip", class_maintenance
,
738 Set whether to print the debug output about skipping files and functions."),
740 Show whether the debug output about skipping files and functions is printed."),
742 When non-zero, debug output about skipping files and functions is displayed."),
744 &setdebuglist
, &showdebuglist
);