aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog17
-rw-r--r--gdb/breakpoint.c25
-rw-r--r--gdb/objfiles.c6
-rw-r--r--gdb/objfiles.h18
-rw-r--r--gdb/symfile.c10
-rw-r--r--gdb/testsuite/ChangeLog9
-rw-r--r--gdb/testsuite/gdb.base/break-main-file-remove-fail.c46
-rw-r--r--gdb/testsuite/gdb.base/break-main-file-remove-fail.exp106
-rw-r--r--gdb/testsuite/gdb.base/break-unload-file.exp71
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"
+ }
}
}