old-cross-binutils/gdb/testsuite/gdb.base/break-unload-file.exp
Pedro Alves d03de42190 "$ gdb PROGRAM" vs "(gdb) file PROGRAM" difference; warn on failure to remove breakpoint.
Turns out there's a difference between loading the program with "gdb
PROGRAM", vs loading it with "(gdb) file PROGRAM".  The latter results
in the objfile ending up with OBJF_USERLOADED set, while not with the
former.  (That difference seems bogus, but still that's not the point
of this patch.  We can revisit that afterwards.)

The new code that suppresses breakpoint removal errors for
add-symbol-file objects ends up being too greedy:

      /* In some cases, we might not be able to remove a breakpoint in
         a shared library that has already been removed, but we have
         not yet processed the shlib unload event.  Similarly for an
         unloaded add-symbol-file object - the user might not yet have
         had the chance to remove-symbol-file it.  shlib_disabled will
         be set if the library/object has already been removed, but
         the breakpoint hasn't been uninserted yet, e.g., after
         "nosharedlibrary" or "remove-symbol-file" with breakpoints
         always-inserted mode.  */
      if (val
          && (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))))
        val = 0;

as it turns out that OBJF_USERLOADED can be set for objfiles loaded by
some other means not add-symbol-file.  In this case, symbol-file (or
"file", which is really just "exec-file"+"symbol-file").

Recall that add-symbol-file is documented as:

 (gdb) help add-symbol-file
 Load symbols from FILE, assuming FILE has been dynamically loaded.
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

And it's the "dynamically loaded" aspect that the breakpoint.c code
cares about.  So make add-symbol-file set OBJF_SHARED on its objfiles
too, and tweak the breakpoint.c code to look for OBJF_SHARED instead
of OBJF_USERLOADED.

This restores back the missing breakpoint removal warning when we let
sss-bp-on-user-bp-2.exp run on native GNU/Linux
(https://sourceware.org/ml/gdb-patches/2014-06/msg00335.html):

 (gdb) PASS: gdb.base/sss-bp-on-user-bp-2.exp: define stepi_del_break
 stepi_del_break
 warning: Error removing breakpoint 3
 (gdb) FAIL: gdb.base/sss-bp-on-user-bp-2.exp: stepi_del_break

I say "restores" because this was GDB's behavior in 7.7 and earlier.

And, likewise, "file" with no arguments only started turning
breakpoints set in the main executable to "<pending>" with the
remote-symbol-file patch (63644780).  The old behavior is now
restored, and we break-unload-file.exp test now exercizes both "gdb;
file PROGRAM" and "gdb PROGRAM".

gdb/
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.

gdb/testsuite/
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-16 15:38:13 +01:00

157 lines
4.6 KiB
Text

# 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 "file" doesn't leave stale breakpoints planted in the
# target.
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. ALWAYS_INSERT determines whether always-inserted
# mode is on/off. BREAK_COMMAND is the break command being tested.
#
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
}
gdb_reinitialize_dir $srcdir/$subdir
gdb_reload
set GDBFLAGS $saved_gdbflags
if ![runto_main] then {
fail "Can't run to main"
return
}
delete_breakpoints
gdb_test_no_output "set breakpoint always-inserted $always_inserted"
set test "$break_command foo"
gdb_test_multiple "$break_command foo" $test {
-re "No hardware breakpoint support in the target.*$gdb_prompt $" {
unsupported $test
return
}
-re "Hardware breakpoints used exceeds limit.*$gdb_prompt $" {
unsupported $test
return
}
-re "Cannot insert hardware breakpoint.*$gdb_prompt $" {
unsupported $test
return
}
-re ".*reakpoint .* at .*$gdb_prompt $" {
pass $test
}
}
# The breakpoint shouldn't be pending now.
gdb_test "info break" "y.*$hex.*in foo at.*" \
"breakpoint is not pending"
# Remove the file, while the breakpoint above is inserted in a
# function in the main objfile. GDB used to have a bug where
# it would mark the breakpoint as uninserted, but actually
# would leave it inserted in the target.
set test "file"
gdb_test_multiple "file" $test {
-re "Are you sure you want to change the file. .*y or n. $" {
send_gdb "y\n"
exp_continue
}
-re "Discard symbol table from `.*'? .y or n. $" {
send_gdb "y\n"
exp_continue
}
-re "No symbol file now\\.\r\n$gdb_prompt $" {
pass $test
}
}
# 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
# re-insert, GDB would fill the shadow buffer with a
# breakpoint instruction). Avoid delete_breakpoints as that
# doesn't record a pass/fail.
gdb_test "delete" "" "delete all breakpoints" \
"Delete all breakpoints.*y or n.*$" "y"
# Re-add symbols back.
set test "file \$binfile"
gdb_test_multiple "file $binfile" $test {
-re "Are you sure you want to change the file. .*y or n. $" {
send_gdb "y\n"
exp_continue
}
-re "Reading symbols from.*done.*$gdb_prompt $" {
pass $test
}
}
# Run to another function now. With the bug, GDB would trip
# on a spurious trap at foo.
gdb_test "b bar" ".*reakpoint .* at .*"
gdb_test "continue" "Breakpoint .*, bar .*"
}
}
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"
}
}
}