diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 5a9352c26fe..1d7926dcefb 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2405,6 +2405,69 @@ breakpoint_kind (struct bp_location *bl, CORE_ADDR *addr)
return gdbarch_breakpoint_kind_from_pc (bl->gdbarch, addr);
}
+/* This should be called when we fail to insert a breakpoint, with ADDRESS
+ set to the location at which we tried to insert the breakpoint.
+
+ This function checks to see if it is possible the user tried to place
+ the breakpoint within an executable section of an object file that has
+ been relocated at run time. If this is the case then an extra warning
+ is printed to TMP_ERROR_STREAM. */
+
+static void
+pic_code_error_check (struct ui_file *tmp_error_stream,
+ CORE_ADDR address)
+{
+ for (objfile *objfile : current_program_space->objfiles ())
+ {
+ struct obj_section *osect;
+
+ /* If the primary text section is not relocated then nothing should
+ be relocated - maybe? */
+ if (objfile->text_section_offset () == 0)
+ continue;
+
+ /* We know this object file was relocated, but was the breakpoint
+ inside one of the code sections before relocation? */
+ ALL_OBJFILE_OSECTIONS (objfile, osect)
+ {
+ /* Ignore non-code sections. */
+ if ((bfd_section_flags (osect->the_bfd_section) & SEC_CODE) == 0)
+ continue;
+
+ /* Was ADDRESS within this section before relocation? */
+ if (!(address >= bfd_section_vma (osect->the_bfd_section)
+ && address < (bfd_section_vma (osect->the_bfd_section)
+ + bfd_section_size (osect->the_bfd_section))))
+ continue;
+
+ /* Final check that this section was relocated. */
+ int idx = osect - objfile->sections;
+ CORE_ADDR offset = objfile->section_offsets[idx];
+ if (offset == 0)
+ continue;
+
+ /* Let the user know that they may have made a mistake. One
+ final check that it might be nice to do is to only give this
+ warning if the user placed the breakpoint by address, that is
+ using 'break *0x.......', if they did anything else and we
+ still have this issue then I'm not sure what the user could
+ reasonably do about it. However, for now, we just always
+ give this error. */
+ CORE_ADDR len = bfd_section_size (osect->the_bfd_section);
+ CORE_ADDR start = bfd_section_vma (osect->the_bfd_section);
+ fprintf_unfiltered (tmp_error_stream, "\
+The address is located within a code region of `%s' which was dynamically\n\
+relocated at run time. The code region `%s ... %s' is now located\n\
+at `%s ... %s', you may need to adjust your breakpoints.\n",
+ objfile_name (objfile),
+ core_addr_to_string (start),
+ core_addr_to_string (start + len),
+ core_addr_to_string (offset + start),
+ core_addr_to_string (offset + start + len));
+ }
+ }
+}
+
/* Insert a low-level "breakpoint" of some type. BL is the breakpoint
location. Any error messages are printed to TMP_ERROR_STREAM; and
DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
@@ -2670,6 +2733,8 @@ insert_bp_location (struct bp_location *bl,
"Cannot insert breakpoint %d.\n"
"%s\n",
bl->owner->number, message.c_str ());
+
+ pic_code_error_check (tmp_error_stream, bl->address);
}
else
{
diff --git a/gdb/testsuite/gdb.base/pie-bp-addr-error.c b/gdb/testsuite/gdb.base/pie-bp-addr-error.c
new file mode 100644
index 00000000000..f4825c8a7c1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/pie-bp-addr-error.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2020 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 . */
+
+int
+main ()
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/pie-bp-addr-error.exp b/gdb/testsuite/gdb.base/pie-bp-addr-error.exp
new file mode 100644
index 00000000000..a54320c0d7f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/pie-bp-addr-error.exp
@@ -0,0 +1,61 @@
+# Copyright 2020 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 .
+
+# Check that, if the user places a breakpoint on an address within a
+# PIE before relocation, then we get a suitable error.
+
+global inferior_spawn_id
+global gdb_spawn_id
+
+if ![istarget *-linux*] {
+ continue
+}
+
+standard_testfile .c
+
+set opts [list debug additional_flags=-fPIE ldflags=-pie]
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile $opts] } {
+ return -1
+}
+
+# Figure out the address of main before sectionns are relocated.
+set main_addr_before_reloc \
+ [get_hexadecimal_valueof "&main" 0 "address of main"]
+
+# Start the inferior and run to main, this will relocate the sections.
+if ![runto_main] {
+ return -1
+}
+
+# First confirm that main has moved.
+set main_relocated_address \
+ [get_hexadecimal_valueof "&main" 0 "runtime address of main"]
+gdb_assert { ${main_addr_before_reloc} != ${main_relocated_address} } \
+ "address of main has changed"
+
+# Now place a breakpoint using the before relocation address.
+gdb_breakpoint "*${main_addr_before_reloc}"
+
+# Continue the inferior, inserting all breakpoints - which should
+# error due to our use of an invalid address.
+gdb_test "continue" \
+ [multi_line \
+ "Cannot insert breakpoint $decimal." \
+ "Cannot access memory at address $hex" \
+ "The address is located within a code region of `\[^\r\n\]+' which was dynamically" \
+ "relocated at run time. The code region `$hex ... $hex' is now located" \
+ "at `$hex ... $hex', you may need to adjust your breakpoints." \
+ "" \
+ "Command aborted." ]