>From b61a0bf98f7effdbee30f0a2b9dfe488b69edf54 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Tue, 11 Sep 2018 22:56:36 +0100
Subject: [PATCH] Fix PR gdb/20948: --write option to GDB causes segmentation
 fault

When opening a BFD for update, as gdb --write does, modifications to
anything but the contents of sections is restricted.

Do not try to write back any ELF headers in this case.

	PR gdb/20948
	* bfd/elf.c (_bfd_elf_write_object_contents): Return from function
	early if abfd->direction == both_direction.
	* gdb/testsuite/gdb.base/write_mem.exp: New test.
	* gdb/testsuite/gdb.base/write_mem.c: Likewise.
---
 bfd/elf.c                            | 12 ++++++++++++
 gdb/testsuite/gdb.base/write_mem.c   |  7 +++++++
 gdb/testsuite/gdb.base/write_mem.exp | 30 ++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+)
 create mode 100644 gdb/testsuite/gdb.base/write_mem.c
 create mode 100644 gdb/testsuite/gdb.base/write_mem.exp

diff --git a/bfd/elf.c b/bfd/elf.c
index 02d605c..5320ae2 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -6391,6 +6391,18 @@ _bfd_elf_write_object_contents (bfd *abfd)
   if (! abfd->output_has_begun
       && ! _bfd_elf_compute_section_file_positions (abfd, NULL))
     return FALSE;
+  /* Do not rewrite ELF data when the BFD has been opened for update.
+     abfd->output_has_begun was set to TRUE on opening, so creation of new
+     sections, and modification of existing section sizes was restricted.
+     This means the ELF header, program headers and section headers can't have
+     changed.
+     If the contents of any sections has been modified, then those changes have
+     already been written to the BFD.  */
+  else if (abfd->direction == both_direction)
+    {
+      BFD_ASSERT (abfd->output_has_begun);
+      return TRUE;
+    }
 
   i_shdrp = elf_elfsections (abfd);
 
diff --git a/gdb/testsuite/gdb.base/write_mem.c b/gdb/testsuite/gdb.base/write_mem.c
new file mode 100644
index 0000000..941f172
--- /dev/null
+++ b/gdb/testsuite/gdb.base/write_mem.c
@@ -0,0 +1,7 @@
+/* Test for PR gdb/20948.  */
+
+int main (void)
+{
+  while (1);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/write_mem.exp b/gdb/testsuite/gdb.base/write_mem.exp
new file mode 100644
index 0000000..e1f393a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/write_mem.exp
@@ -0,0 +1,30 @@
+# Test for PR gdb/20948
+# Verify that invoking gdb with the --write argument works as expected
+
+global GDBFLAGS
+standard_testfile
+
+if {[build_executable $testfile.exp $testfile \
+  $srcfile [list debug nowarnings] ] == -1} {
+    untested $testfile.exp
+    return -1
+}
+
+set old_gdbflags $GDBFLAGS
+
+# Expect a failure before --write has been added to the command line
+set GDBFLAGS "$old_gdbflags $binfile"
+clean_restart
+test_print_reject "set {int}main = 0x4242" "Cannot access memory at address"
+
+# Setting memory should now work correctly after adding --write
+set GDBFLAGS "$old_gdbflags --write $binfile"
+clean_restart
+gdb_test_no_output "set {int}main = 0x4242"
+
+# Check that memory write persists after quitting GDB
+gdb_exit
+gdb_start
+gdb_test "x /xh main" "<main>:.*4242"
+
+set GDBFLAGS $old_gdbflags
-- 
2.7.4

