1 /* Skipping uninteresting files and functions while stepping.
3 Copyright (C) 2011-2018 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 "common/gdb_optional.h"
40 /* True if we want to print debug printouts related to file/function
42 static int debug_skip
= 0;
47 /* Create a skiplist_entry object and add it to the chain. */
48 static void add_entry (bool file_is_glob
,
50 bool function_is_regexp
,
51 std::string
&&function
);
53 /* Return true if the skip entry has a file or glob-style file
54 pattern that matches FUNCTION_SAL. */
55 bool skip_file_p (const symtab_and_line
&function_sal
) const;
57 /* Return true if the skip entry has a function or function regexp
58 that matches FUNCTION_NAME. */
59 bool skip_function_p (const char *function_name
) const;
62 int number () const { return m_number
; };
63 bool enabled () const { return m_enabled
; };
64 bool file_is_glob () const { return m_file_is_glob
; }
65 const std::string
&file () const { return m_file
; }
66 const std::string
&function () const { return m_function
; }
67 bool function_is_regexp () const { return m_function_is_regexp
; }
70 void enable () { m_enabled
= true; };
71 void disable () { m_enabled
= false; };
74 skiplist_entry (const skiplist_entry
&) = delete;
75 void operator= (const skiplist_entry
&) = delete;
78 /* Key that grants access to the constructor. */
79 struct private_key
{};
81 /* Public so we can construct with container::emplace_back. Since
82 it requires a private class key, it can't be called from outside.
83 Use the add_entry static factory method to construct instead. */
84 skiplist_entry (bool file_is_glob
, std::string
&&file
,
85 bool function_is_regexp
, std::string
&&function
,
89 /* Return true if we're stopped at a file to be skipped. */
90 bool do_skip_file_p (const symtab_and_line
&function_sal
) const;
92 /* Return true if we're stopped at a globbed file to be skipped. */
93 bool do_skip_gfile_p (const symtab_and_line
&function_sal
) const;
98 /* True if FILE is a glob-style pattern.
99 Otherwise it is the plain file name (possibly with directories). */
102 /* The name of the file or empty if no name. */
105 /* True if FUNCTION is a regexp.
106 Otherwise it is a plain function name (possibly with arguments,
108 bool m_function_is_regexp
;
110 /* The name of the function or empty if no name. */
111 std::string m_function
;
113 /* If this is a function regexp, the compiled form. */
114 gdb::optional
<compiled_regex
> m_compiled_function_regexp
;
116 /* Enabled/disabled state. */
117 bool m_enabled
= true;
120 static std::list
<skiplist_entry
> skiplist_entries
;
121 static int highest_skiplist_entry_num
= 0;
123 skiplist_entry::skiplist_entry (bool file_is_glob
,
125 bool function_is_regexp
,
126 std::string
&&function
,
128 : m_file_is_glob (file_is_glob
),
129 m_file (std::move (file
)),
130 m_function_is_regexp (function_is_regexp
),
131 m_function (std::move (function
))
133 gdb_assert (!m_file
.empty () || !m_function
.empty ());
136 gdb_assert (!m_file
.empty ());
138 if (m_function_is_regexp
)
140 gdb_assert (!m_function
.empty ());
142 int flags
= REG_NOSUB
;
144 flags
|= REG_EXTENDED
;
147 gdb_assert (!m_function
.empty ());
148 m_compiled_function_regexp
.emplace (m_function
.c_str (), flags
,
154 skiplist_entry::add_entry (bool file_is_glob
, std::string
&&file
,
155 bool function_is_regexp
, std::string
&&function
)
157 skiplist_entries
.emplace_back (file_is_glob
,
160 std::move (function
),
163 /* Incremented after push_back, in case push_back throws. */
164 skiplist_entries
.back ().m_number
= ++highest_skiplist_entry_num
;
168 skip_file_command (const char *arg
, int from_tty
)
170 struct symtab
*symtab
;
171 const char *filename
= NULL
;
173 /* If no argument was given, try to default to the last
174 displayed codepoint. */
177 symtab
= get_last_displayed_symtab ();
179 error (_("No default file now."));
181 /* It is not a typo, symtab_to_filename_for_display woule be needlessly
183 filename
= symtab_to_fullname (symtab
);
188 skiplist_entry::add_entry (false, std::string (filename
),
189 false, std::string ());
191 printf_filtered (_("File %s will be skipped when stepping.\n"), filename
);
194 /* Create a skiplist entry for the given function NAME and add it to the
198 skip_function (const char *name
)
200 skiplist_entry::add_entry (false, std::string (), false, std::string (name
));
202 printf_filtered (_("Function %s will be skipped when stepping.\n"), name
);
206 skip_function_command (const char *arg
, int from_tty
)
208 /* Default to the current function if no argument is given. */
211 const char *name
= NULL
;
214 if (!last_displayed_sal_is_valid ())
215 error (_("No default function now."));
217 pc
= get_last_displayed_addr ();
218 if (!find_pc_partial_function (pc
, &name
, NULL
, NULL
))
220 error (_("No function found containing current program point %s."),
221 paddress (get_current_arch (), pc
));
223 skip_function (name
);
230 /* Process "skip ..." that does not match "skip file" or "skip function". */
233 skip_command (const char *arg
, int from_tty
)
235 const char *file
= NULL
;
236 const char *gfile
= NULL
;
237 const char *function
= NULL
;
238 const char *rfunction
= NULL
;
243 skip_function_command (arg
, from_tty
);
249 for (i
= 0; argv
[i
] != NULL
; ++i
)
251 const char *p
= argv
[i
];
252 const char *value
= argv
[i
+ 1];
254 if (strcmp (p
, "-fi") == 0
255 || strcmp (p
, "-file") == 0)
258 error (_("Missing value for %s option."), p
);
262 else if (strcmp (p
, "-gfi") == 0
263 || strcmp (p
, "-gfile") == 0)
266 error (_("Missing value for %s option."), p
);
270 else if (strcmp (p
, "-fu") == 0
271 || strcmp (p
, "-function") == 0)
274 error (_("Missing value for %s option."), p
);
278 else if (strcmp (p
, "-rfu") == 0
279 || strcmp (p
, "-rfunction") == 0)
282 error (_("Missing value for %s option."), p
);
287 error (_("Invalid skip option: %s"), p
);
290 /* Assume the user entered "skip FUNCTION-NAME".
291 FUNCTION-NAME may be `foo (int)', and therefore we pass the
292 complete original arg to skip_function command as if the user
293 typed "skip function arg". */
294 skip_function_command (arg
, from_tty
);
298 error (_("Invalid argument: %s"), p
);
301 if (file
!= NULL
&& gfile
!= NULL
)
302 error (_("Cannot specify both -file and -gfile."));
304 if (function
!= NULL
&& rfunction
!= NULL
)
305 error (_("Cannot specify both -function and -rfunction."));
307 /* This shouldn't happen as "skip" by itself gets punted to
308 skip_function_command. */
309 gdb_assert (file
!= NULL
|| gfile
!= NULL
310 || function
!= NULL
|| rfunction
!= NULL
);
312 std::string entry_file
;
315 else if (gfile
!= NULL
)
318 std::string entry_function
;
319 if (function
!= NULL
)
320 entry_function
= function
;
321 else if (rfunction
!= NULL
)
322 entry_function
= rfunction
;
324 skiplist_entry::add_entry (gfile
!= NULL
, std::move (entry_file
),
325 rfunction
!= NULL
, std::move (entry_function
));
327 /* I18N concerns drive some of the choices here (we can't piece together
328 the output too much). OTOH we want to keep this simple. Therefore the
329 only polish we add to the output is to append "(s)" to "File" or
330 "Function" if they're a glob/regexp. */
332 const char *file_to_print
= file
!= NULL
? file
: gfile
;
333 const char *function_to_print
= function
!= NULL
? function
: rfunction
;
334 const char *file_text
= gfile
!= NULL
? _("File(s)") : _("File");
335 const char *lower_file_text
= gfile
!= NULL
? _("file(s)") : _("file");
336 const char *function_text
337 = rfunction
!= NULL
? _("Function(s)") : _("Function");
339 if (function_to_print
== NULL
)
341 printf_filtered (_("%s %s will be skipped when stepping.\n"),
342 file_text
, file_to_print
);
344 else if (file_to_print
== NULL
)
346 printf_filtered (_("%s %s will be skipped when stepping.\n"),
347 function_text
, function_to_print
);
351 printf_filtered (_("%s %s in %s %s will be skipped"
352 " when stepping.\n"),
353 function_text
, function_to_print
,
354 lower_file_text
, file_to_print
);
360 info_skip_command (const char *arg
, int from_tty
)
362 int num_printable_entries
= 0;
363 struct value_print_options opts
;
365 get_user_print_options (&opts
);
367 /* Count the number of rows in the table and see if we need space for a
368 64-bit address anywhere. */
369 for (const skiplist_entry
&e
: skiplist_entries
)
370 if (arg
== NULL
|| number_is_in_list (arg
, e
.number ()))
371 num_printable_entries
++;
373 if (num_printable_entries
== 0)
376 current_uiout
->message (_("Not skipping any files or functions.\n"));
378 current_uiout
->message (
379 _("No skiplist entries found with number %s.\n"), arg
);
384 ui_out_emit_table
table_emitter (current_uiout
, 6, num_printable_entries
,
387 current_uiout
->table_header (5, ui_left
, "number", "Num"); /* 1 */
388 current_uiout
->table_header (3, ui_left
, "enabled", "Enb"); /* 2 */
389 current_uiout
->table_header (4, ui_right
, "regexp", "Glob"); /* 3 */
390 current_uiout
->table_header (20, ui_left
, "file", "File"); /* 4 */
391 current_uiout
->table_header (2, ui_right
, "regexp", "RE"); /* 5 */
392 current_uiout
->table_header (40, ui_noalign
, "function", "Function"); /* 6 */
393 current_uiout
->table_body ();
395 for (const skiplist_entry
&e
: skiplist_entries
)
398 if (arg
!= NULL
&& !number_is_in_list (arg
, e
.number ()))
401 ui_out_emit_tuple
tuple_emitter (current_uiout
, "blklst-entry");
402 current_uiout
->field_int ("number", e
.number ()); /* 1 */
405 current_uiout
->field_string ("enabled", "y"); /* 2 */
407 current_uiout
->field_string ("enabled", "n"); /* 2 */
409 if (e
.file_is_glob ())
410 current_uiout
->field_string ("regexp", "y"); /* 3 */
412 current_uiout
->field_string ("regexp", "n"); /* 3 */
414 current_uiout
->field_string ("file",
415 e
.file ().empty () ? "<none>"
416 : e
.file ().c_str ()); /* 4 */
417 if (e
.function_is_regexp ())
418 current_uiout
->field_string ("regexp", "y"); /* 5 */
420 current_uiout
->field_string ("regexp", "n"); /* 5 */
422 current_uiout
->field_string ("function",
423 e
.function ().empty () ? "<none>"
424 : e
.function ().c_str ()); /* 6 */
426 current_uiout
->text ("\n");
431 skip_enable_command (const char *arg
, int from_tty
)
435 for (skiplist_entry
&e
: skiplist_entries
)
436 if (arg
== NULL
|| number_is_in_list (arg
, e
.number ()))
443 error (_("No skiplist entries found with number %s."), arg
);
447 skip_disable_command (const char *arg
, int from_tty
)
451 for (skiplist_entry
&e
: skiplist_entries
)
452 if (arg
== NULL
|| number_is_in_list (arg
, e
.number ()))
459 error (_("No skiplist entries found with number %s."), arg
);
463 skip_delete_command (const char *arg
, int from_tty
)
467 for (auto it
= skiplist_entries
.begin (),
468 end
= skiplist_entries
.end ();
471 const skiplist_entry
&e
= *it
;
473 if (arg
== NULL
|| number_is_in_list (arg
, e
.number ()))
475 it
= skiplist_entries
.erase (it
);
483 error (_("No skiplist entries found with number %s."), arg
);
487 skiplist_entry::do_skip_file_p (const symtab_and_line
&function_sal
) const
490 fprintf_unfiltered (gdb_stdlog
,
491 "skip: checking if file %s matches non-glob %s...",
492 function_sal
.symtab
->filename
, m_file
.c_str ());
496 /* Check first sole SYMTAB->FILENAME. It may not be a substring of
497 symtab_to_fullname as it may contain "./" etc. */
498 if (compare_filenames_for_search (function_sal
.symtab
->filename
,
502 /* Before we invoke realpath, which can get expensive when many
503 files are involved, do a quick comparison of the basenames. */
504 else if (!basenames_may_differ
505 && filename_cmp (lbasename (function_sal
.symtab
->filename
),
506 lbasename (m_file
.c_str ())) != 0)
510 /* Note: symtab_to_fullname caches its result, thus we don't have to. */
511 const char *fullname
= symtab_to_fullname (function_sal
.symtab
);
513 result
= compare_filenames_for_search (fullname
, m_file
.c_str ());
517 fprintf_unfiltered (gdb_stdlog
, result
? "yes.\n" : "no.\n");
523 skiplist_entry::do_skip_gfile_p (const symtab_and_line
&function_sal
) const
526 fprintf_unfiltered (gdb_stdlog
,
527 "skip: checking if file %s matches glob %s...",
528 function_sal
.symtab
->filename
, m_file
.c_str ());
532 /* Check first sole SYMTAB->FILENAME. It may not be a substring of
533 symtab_to_fullname as it may contain "./" etc. */
534 if (gdb_filename_fnmatch (m_file
.c_str (), function_sal
.symtab
->filename
,
535 FNM_FILE_NAME
| FNM_NOESCAPE
) == 0)
538 /* Before we invoke symtab_to_fullname, which is expensive, do a quick
539 comparison of the basenames.
540 Note that we assume that lbasename works with glob-style patterns.
541 If the basename of the glob pattern is something like "*.c" then this
542 isn't much of a win. Oh well. */
543 else if (!basenames_may_differ
544 && gdb_filename_fnmatch (lbasename (m_file
.c_str ()),
545 lbasename (function_sal
.symtab
->filename
),
546 FNM_FILE_NAME
| FNM_NOESCAPE
) != 0)
550 /* Note: symtab_to_fullname caches its result, thus we don't have to. */
551 const char *fullname
= symtab_to_fullname (function_sal
.symtab
);
553 result
= compare_glob_filenames_for_search (fullname
, m_file
.c_str ());
557 fprintf_unfiltered (gdb_stdlog
, result
? "yes.\n" : "no.\n");
563 skiplist_entry::skip_file_p (const symtab_and_line
&function_sal
) const
568 if (function_sal
.symtab
== NULL
)
572 return do_skip_gfile_p (function_sal
);
574 return do_skip_file_p (function_sal
);
578 skiplist_entry::skip_function_p (const char *function_name
) const
580 if (m_function
.empty ())
585 if (m_function_is_regexp
)
588 fprintf_unfiltered (gdb_stdlog
,
589 "skip: checking if function %s matches regex %s...",
590 function_name
, m_function
.c_str ());
592 gdb_assert (m_compiled_function_regexp
);
594 = (m_compiled_function_regexp
->exec (function_name
, 0, NULL
, 0) == 0);
599 fprintf_unfiltered (gdb_stdlog
,
600 ("skip: checking if function %s matches non-regex "
602 function_name
, m_function
.c_str ());
603 result
= (strcmp_iw (function_name
, m_function
.c_str ()) == 0);
607 fprintf_unfiltered (gdb_stdlog
, result
? "yes.\n" : "no.\n");
615 function_name_is_marked_for_skip (const char *function_name
,
616 const symtab_and_line
&function_sal
)
618 if (function_name
== NULL
)
621 for (const skiplist_entry
&e
: skiplist_entries
)
626 bool skip_by_file
= e
.skip_file_p (function_sal
);
627 bool skip_by_function
= e
.skip_function_p (function_name
);
629 /* If both file and function must match, make sure we don't errantly
630 exit if only one of them match. */
631 if (!e
.file ().empty () && !e
.function ().empty ())
633 if (skip_by_file
&& skip_by_function
)
636 /* Only one of file/function is specified. */
637 else if (skip_by_file
|| skip_by_function
)
645 _initialize_step_skip (void)
647 static struct cmd_list_element
*skiplist
= NULL
;
648 struct cmd_list_element
*c
;
650 add_prefix_cmd ("skip", class_breakpoint
, skip_command
, _("\
651 Ignore a function while stepping.\n\
653 Usage: skip [FUNCTION-NAME]\n\
654 skip [FILE-SPEC] [FUNCTION-SPEC]\n\
655 If no arguments are given, ignore the current function.\n\
657 FILE-SPEC is one of:\n\
658 -fi|-file FILE-NAME\n\
659 -gfi|-gfile GLOB-FILE-PATTERN\n\
660 FUNCTION-SPEC is one of:\n\
661 -fu|-function FUNCTION-NAME\n\
662 -rfu|-rfunction FUNCTION-NAME-REGULAR-EXPRESSION"),
663 &skiplist
, "skip ", 1, &cmdlist
);
665 c
= add_cmd ("file", class_breakpoint
, skip_file_command
, _("\
666 Ignore a file while stepping.\n\
667 Usage: skip file [FILE-NAME]\n\
668 If no filename is given, ignore the current file."),
670 set_cmd_completer (c
, filename_completer
);
672 c
= add_cmd ("function", class_breakpoint
, skip_function_command
, _("\
673 Ignore a function while stepping.\n\
674 Usage: skip function [FUNCTION-NAME]\n\
675 If no function name is given, skip the current function."),
677 set_cmd_completer (c
, location_completer
);
679 add_cmd ("enable", class_breakpoint
, skip_enable_command
, _("\
680 Enable skip entries. You can specify numbers (e.g. \"skip enable 1 3\"), \
681 ranges (e.g. \"skip enable 4-8\"), or both (e.g. \"skip enable 1 3 4-8\").\n\n\
682 If you don't specify any numbers or ranges, we'll enable all skip entries.\n\n\
683 Usage: skip enable [NUMBER | RANGE]..."),
686 add_cmd ("disable", class_breakpoint
, skip_disable_command
, _("\
687 Disable skip entries. You can specify numbers (e.g. \"skip disable 1 3\"), \
688 ranges (e.g. \"skip disable 4-8\"), or both (e.g. \"skip disable 1 3 4-8\").\n\n\
689 If you don't specify any numbers or ranges, we'll disable all skip entries.\n\n\
690 Usage: skip disable [NUMBER | RANGE]..."),
693 add_cmd ("delete", class_breakpoint
, skip_delete_command
, _("\
694 Delete skip entries. You can specify numbers (e.g. \"skip delete 1 3\"), \
695 ranges (e.g. \"skip delete 4-8\"), or both (e.g. \"skip delete 1 3 4-8\").\n\n\
696 If you don't specify any numbers or ranges, we'll delete all skip entries.\n\n\
697 Usage: skip delete [NUMBER | RANGES]..."),
700 add_info ("skip", info_skip_command
, _("\
701 Display the status of skips. You can specify numbers (e.g. \"skip info 1 3\"), \
702 ranges (e.g. \"skip info 4-8\"), or both (e.g. \"skip info 1 3 4-8\").\n\n\
703 If you don't specify any numbers or ranges, we'll show all skips.\n\n\
704 Usage: skip info [NUMBER | RANGES]...\n\
705 The \"Type\" column indicates one of:\n\
706 \tfile - ignored file\n\
707 \tfunction - ignored function"));
709 add_setshow_boolean_cmd ("skip", class_maintenance
,
711 Set whether to print the debug output about skipping files and functions."),
713 Show whether the debug output about skipping files and functions is printed"),
715 When non-zero, debug output about skipping files and functions is displayed."),
717 &setdebuglist
, &showdebuglist
);