diff options
-rw-r--r-- | gdb/ChangeLog | 17 | ||||
-rw-r--r-- | gdb/breakpoint.c | 25 | ||||
-rw-r--r-- | gdb/objfiles.c | 6 | ||||
-rw-r--r-- | gdb/objfiles.h | 18 | ||||
-rw-r--r-- | gdb/symfile.c | 10 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/break-main-file-remove-fail.c | 46 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/break-main-file-remove-fail.exp | 106 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/break-unload-file.exp | 71 |
9 files changed, 256 insertions, 52 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a999390..de892a2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +2014-06-16 Pedro Alves <palves@redhat.com> + + * breakpoint.c (insert_bp_location, remove_breakpoint_1): Adjust. + (disable_breakpoints_in_freed_objfile): Skip objfiles that don't + have OBJF_SHARED set. + * objfiles.c (userloaded_objfile_contains_address_p): Rename to... + (shared_objfile_contains_address_p): ... this. Check OBJF_SHARED + instead of OBJF_USERLOADED. + * objfiles.h (OBJF_SHARED): Update comment. + (userloaded_objfile_contains_address_p): Rename to ... + (shared_objfile_contains_address_p): ... this, and update + comments. + * symfile.c (add_symbol_file_command): Also set OBJF_SHARED in the + new objfile. + (remove_symbol_file_command): Skip objfiles that don't have + OBJF_SHARED set. + 2014-06-16 Tom Tromey <tromey@redhat.com> * minsyms.h (prim_record_minimal_symbol) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 8f702e2..2240f08 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -2665,8 +2665,8 @@ insert_bp_location (struct bp_location *bl, if ((bp_err == GENERIC_ERROR || bp_err == MEMORY_ERROR) && bl->loc_type == bp_loc_software_breakpoint && (solib_name_from_address (bl->pspace, bl->address) - || userloaded_objfile_contains_address_p (bl->pspace, - bl->address))) + || shared_objfile_contains_address_p (bl->pspace, + bl->address))) { /* See also: disable_breakpoints_in_shlibs. */ bl->shlib_disabled = 1; @@ -3805,7 +3805,7 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is) whether another dynamic object might have loaded over the breakpoint's address -- the user might well let us know about it next with add-symbol-file (the whole point of - OBJF_USERLOADED is letting the user manually maintain a + add-symbol-file is letting the user manually maintain a list of dynamically loaded objects). If we have the breakpoint's shadow memory, that is, this is a software breakpoint managed by GDB, check whether the breakpoint @@ -3878,8 +3878,8 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is) && (bl->loc_type == bp_loc_software_breakpoint && (bl->shlib_disabled || solib_name_from_address (bl->pspace, bl->address) - || userloaded_objfile_contains_address_p (bl->pspace, - bl->address)))) + || shared_objfile_contains_address_p (bl->pspace, + bl->address)))) val = 0; if (val) @@ -7729,18 +7729,19 @@ disable_breakpoints_in_freed_objfile (struct objfile *objfile) if (objfile == NULL) return; - /* OBJF_USERLOADED are dynamic modules manually managed by the user - with add-symbol-file/remove-symbol-file. Similarly to how - breakpoints in shared libraries are handled in response to - "nosharedlibrary", mark breakpoints in OBJF_USERLOADED modules + /* OBJF_SHARED|OBJF_USERLOADED objfiles are dynamic modules manually + managed by the user with add-symbol-file/remove-symbol-file. + Similarly to how breakpoints in shared libraries are handled in + response to "nosharedlibrary", mark breakpoints in such modules shlib_disabled so they end up uninserted on the next global location list update. Shared libraries not loaded by the user aren't handled here -- they're already handled in disable_breakpoints_in_unloaded_shlib, called by solib.c's solib_unloaded observer. We skip objfiles that are not - OBJF_USERLOADED (nor OBJF_SHARED) as those aren't considered - dynamic objects (e.g. the main objfile). */ - if ((objfile->flags & OBJF_USERLOADED) == 0) + OBJF_SHARED as those aren't considered dynamic objects (e.g. the + main objfile). */ + if ((objfile->flags & OBJF_SHARED) == 0 + || (objfile->flags & OBJF_USERLOADED) == 0) return; ALL_BREAKPOINTS (b) diff --git a/gdb/objfiles.c b/gdb/objfiles.c index 81bbf24..a86e8bc 100644 --- a/gdb/objfiles.c +++ b/gdb/objfiles.c @@ -1454,14 +1454,14 @@ is_addr_in_objfile (CORE_ADDR addr, const struct objfile *objfile) } int -userloaded_objfile_contains_address_p (struct program_space *pspace, - CORE_ADDR address) +shared_objfile_contains_address_p (struct program_space *pspace, + CORE_ADDR address) { struct objfile *objfile; ALL_PSPACE_OBJFILES (pspace, objfile) { - if ((objfile->flags & OBJF_USERLOADED) != 0 + if ((objfile->flags & OBJF_SHARED) != 0 && is_addr_in_objfile (address, objfile)) return 1; } diff --git a/gdb/objfiles.h b/gdb/objfiles.h index 6684278..57a94e1 100644 --- a/gdb/objfiles.h +++ b/gdb/objfiles.h @@ -427,12 +427,9 @@ struct objfile #define OBJF_REORDERED (1 << 0) /* Functions are reordered */ /* Distinguish between an objfile for a shared library and a "vanilla" - objfile. (If not set, the objfile may still actually be a solib. - This can happen if the user created the objfile by using the - add-symbol-file command. GDB doesn't in that situation actually - check whether the file is a solib. Rather, the target's - implementation of the solib interface is responsible for setting - this flag when noticing solibs used by an inferior.) */ + objfile. This may come from a target's implementation of the solib + interface, from add-symbol-file, or any other mechanism that loads + dynamic objects. */ #define OBJF_SHARED (1 << 1) /* From a shared library */ @@ -515,12 +512,11 @@ extern void objfiles_changed (void); extern int is_addr_in_objfile (CORE_ADDR addr, const struct objfile *objfile); -/* Return true if ADDRESS maps into one of the sections of the - userloaded ("add-symbol-file") objfiles of PSPACE and false - otherwise. */ +/* Return true if ADDRESS maps into one of the sections of a + OBJF_SHARED objfile of PSPACE and false otherwise. */ -extern int userloaded_objfile_contains_address_p (struct program_space *pspace, - CORE_ADDR address); +extern int shared_objfile_contains_address_p (struct program_space *pspace, + CORE_ADDR address); /* This operation deletes all objfile entries that represent solibs that weren't explicitly loaded by the user, via e.g., the add-symbol-file diff --git a/gdb/symfile.c b/gdb/symfile.c index d94db48..84858dc 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -2262,7 +2262,7 @@ add_symbol_file_command (char *args, int from_tty) { struct gdbarch *gdbarch = get_current_arch (); char *filename = NULL; - int flags = OBJF_USERLOADED; + int flags = OBJF_USERLOADED | OBJF_SHARED; char *arg; int section_index = 0; int argcnt = 0; @@ -2445,8 +2445,8 @@ remove_symbol_file_command (char *args, int from_tty) ALL_OBJFILES (objf) { - if (objf != 0 - && objf->flags & OBJF_USERLOADED + if ((objf->flags & OBJF_USERLOADED) != 0 + && (objf->flags & OBJF_SHARED) != 0 && objf->pspace == pspace && is_addr_in_objfile (addr, objf)) break; } @@ -2464,8 +2464,8 @@ remove_symbol_file_command (char *args, int from_tty) ALL_OBJFILES (objf) { - if (objf != 0 - && objf->flags & OBJF_USERLOADED + if ((objf->flags & OBJF_USERLOADED) != 0 + && (objf->flags & OBJF_SHARED) != 0 && objf->pspace == pspace && filename_cmp (filename, objfile_name (objf)) == 0) break; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 607eba7..17e2a1a 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2014-06-16 Pedro Alves <palves@redhat.com> + + * gdb.base/break-main-file-remove-fail.c: New file. + * gdb.base/break-main-file-remove-fail.exp: New file. + * gdb.base/break-unload-file.exp: Use build_executable instead of + prepare_for_testing. + (test_break): New parameter "initial_load". Handle it. + (top level): Add initial_load cmdline/file axis. + 2014-06-12 Tom Tromey <tromey@redhat.com> * gdb.base/completion.exp: Don't use directory name in test. diff --git a/gdb/testsuite/gdb.base/break-main-file-remove-fail.c b/gdb/testsuite/gdb.base/break-main-file-remove-fail.c new file mode 100644 index 0000000..8d89b6b --- /dev/null +++ b/gdb/testsuite/gdb.base/break-main-file-remove-fail.c @@ -0,0 +1,46 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/mman.h> + +size_t pg_size; + +void +start (void) +{ +} + +void +foo (void) +{ +} + +int +main (void) +{ + pg_size = getpagesize (); + + /* This just makes sure the test fails to compile (and is therefore + skipped) on targets that don't have munmap. */ + munmap (0, 0); + + start (); + foo (); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/break-main-file-remove-fail.exp b/gdb/testsuite/gdb.base/break-main-file-remove-fail.exp new file mode 100644 index 0000000..395cf97 --- /dev/null +++ b/gdb/testsuite/gdb.base/break-main-file-remove-fail.exp @@ -0,0 +1,106 @@ +# Copyright 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +# Test that GDB isn't silent if it fails to remove a breakpoint from +# the main program, independently of whether the program was loaded +# with "file PROGRAM" or directly from the command line with "gdb +# PROGRAM". + +standard_testfile + +if {[build_executable "failed to prepare" $testfile $srcfile debug]} { + return -1 +} + +# Run the test proper. INITIAL_LOAD determines whether the program is +# initially loaded by the "file" command or by passing it to GDB on +# the command line. +proc test_remove_bp { initial_load } { + with_test_prefix "$initial_load" { + global srcdir subdir binfile + global gdb_prompt hex + global GDBFLAGS + + gdb_exit + + set saved_gdbflags $GDBFLAGS + + # See "used to behave differently" further below. + if { $initial_load == "file" } { + gdb_start + gdb_file_cmd $binfile + } else { + global last_loaded_file + + # gdb_file_cmd sets this. This is what gdb_reload + # implementations use as binary. + set last_loaded_file $binfile + + set GDBFLAGS "$GDBFLAGS $binfile" + gdb_start + } + gdb_reinitialize_dir $srcdir/$subdir + gdb_reload + set GDBFLAGS $saved_gdbflags + + if ![runto start] { + fail "Can't run to start" + return + } + + delete_breakpoints + + # So we can easily control when are breakpoints removed. + gdb_test_no_output "set breakpoint always-inserted on" + + set bp_addr "" + + set test "break foo" + gdb_test_multiple $test $test { + -re "Breakpoint .* at ($hex).*$gdb_prompt $" { + set bp_addr $expect_out(1,string) + pass $test + } + } + + if {$bp_addr == ""} { + unsupported "can't extract foo's address" + return + } + + gdb_test "info break" "y.*$hex.*in foo at.*" \ + "breakpoint is set" + + # Now unmap the page where the breakpoint is set. Trying to + # remove the memory breakpoint afterwards should fail, and GDB + # should warn the user about it. + set pagesize [get_integer_valueof "pg_size" 0] + set align_addr [expr $bp_addr - $bp_addr % $pagesize] + set munmap [get_integer_valueof "munmap ($align_addr, $pagesize)" -1] + + if {$munmap != 0} { + unsupported "can't munmap foo's page" + return + } + + gdb_test "delete \$bpnum" \ + "warning: Error removing breakpoint .*" \ + "failure to remove breakpoint warns" + } +} + +foreach initial_load { "cmdline" "file" } { + test_remove_bp $initial_load +} diff --git a/gdb/testsuite/gdb.base/break-unload-file.exp b/gdb/testsuite/gdb.base/break-unload-file.exp index 342bcf5..20762bb 100644 --- a/gdb/testsuite/gdb.base/break-unload-file.exp +++ b/gdb/testsuite/gdb.base/break-unload-file.exp @@ -18,24 +18,46 @@ standard_testfile -if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { +if {[build_executable "failed to prepare" $testfile $srcfile debug]} { return -1 } -if ![runto_main] then { - fail "Can't run to main" - return 0 -} - -# Run the test proper. ALWAYS_INSERT determines whether -# always-inserted mode is on/off, and BREAK_COMMAND is the break -# command being tested. +# Run the test proper. INITIAL_LOAD determines whether the program is +# initially loaded by the "file" command or by passing it to GDB on +# the command line. ALWAYS_INSERT determines whether always-inserted +# mode is on/off. BREAK_COMMAND is the break command being tested. # -proc test_break { always_inserted break_command } { - global gdb_prompt binfile hex +proc test_break { initial_load always_inserted break_command } { + global srcdir subdir binfile + global gdb_prompt hex + global GDBFLAGS + + append prefix "$initial_load: " + append prefix "always-inserted $always_inserted: " + append prefix "$break_command" + with_test_prefix "$prefix" { + gdb_exit + + set saved_gdbflags $GDBFLAGS + + # See "used to behave differently" further below. + if { $initial_load == "file" } { + gdb_start + gdb_file_cmd $binfile + } else { + global last_loaded_file + + # gdb_file_cmd sets this. This is what gdb_reload + # implementations use as binary. + set last_loaded_file $binfile + + set GDBFLAGS "$GDBFLAGS $binfile" + gdb_start + } - with_test_prefix "always-inserted $always_inserted: $break_command" { - clean_restart $binfile + gdb_reinitialize_dir $srcdir/$subdir + gdb_reload + set GDBFLAGS $saved_gdbflags if ![runto_main] then { fail "Can't run to main" @@ -88,8 +110,12 @@ proc test_break { always_inserted break_command } { } } - gdb_test "info break" "y.*PENDING.*foo" \ - "breakpoint is pending" + # This test used to behave differently depending on whether + # the program was first loaded through "file PROGRAM" or "gdb + # PROGRAM". + set ws "\[ \t\]" + gdb_test "info break" "breakpoint${ws}+keep${ws}+n${ws}+$hex${ws}*" \ + "breakpoint is disabled" # Now delete the breakpoint from GDB's tables, to make sure # GDB doesn't reinsert it, masking the bug (with the bug, on @@ -118,11 +144,14 @@ proc test_break { always_inserted break_command } { } } -# While it doesn't trigger the original bug this is a regression test -# for, test with breakpoint always-inserted off for extra coverage. -foreach always_inserted { "off" "on" } { - test_break $always_inserted "break" - if {![skip_hw_breakpoint_tests]} { - test_break $always_inserted "hbreak" +foreach initial_load { "cmdline" "file" } { + # While it doesn't trigger the original bug this is a regression + # test for, test with breakpoint always-inserted off for extra + # coverage. + foreach always_inserted { "off" "on" } { + test_break $initial_load $always_inserted "break" + if {![skip_hw_breakpoint_tests]} { + test_break $initial_load $always_inserted "hbreak" + } } } |