bb9a89c
gdb/
bb9a89c
2008-10-28  Jan Kratochvil  <jan.kratochvil@redhat.com>
bb9a89c
bb9a89c
	Fix automatic restoration of breakpoints memory for ia64.
bb9a89c
	* ia64-tdep.c (ia64_memory_insert_breakpoint): New comment part for
bb9a89c
	SHADOW_CONTENTS content.  Remova variable instr.  New variable cleanup.
bb9a89c
	Force automatic breakpoints restoration.  PLACED_SIZE and SHADOW_LEN
bb9a89c
	are now set larger, to BUNDLE_LEN - 2.
bb9a89c
	(ia64_memory_remove_breakpoint): Rename variables bundle to bundle_mem
bb9a89c
	and instr to instr_saved.  New variables bundle_saved and
bb9a89c
	instr_breakpoint.  Comment new reasons why we need to disable automatic
bb9a89c
	restoration of breakpoints.  Assert PLACED_SIZE and SHADOW_LEN.  New
bb9a89c
	check of the original memory content.
bb9a89c
	(ia64_breakpoint_from_pc): Array breakpoint extended to BUNDLE_LEN.
bb9a89c
	Sanity check the PCPTR parameter SLOTNUM value.  New #if check on
bb9a89c
	BREAKPOINT_MAX vs. BUNDLE_LEN.  Increase LENPTR to BUNDLE_LEN - 2.
bb9a89c
bb9a89c
gdb/testsuite/
bb9a89c
2008-10-28  Jan Kratochvil  <jan.kratochvil@redhat.com>
bb9a89c
bb9a89c
	* gdb.base/breakpoint-shadow.exp, gdb.base/breakpoint-shadow.c: New.
bb9a89c
bb9a89c
[ RHEL-5 disable of `set breakpoint always-inserted'.  ]
bb9a89c
bb9a89c
--- ./gdb/ia64-tdep.c	11 Sep 2008 14:23:15 -0000	1.184
bb9a89c
+++ ./gdb/ia64-tdep.c	28 Oct 2008 10:28:41 -0000
bb9a89c
@@ -545,7 +545,21 @@ fetch_instruction (CORE_ADDR addr, instr
bb9a89c
    simulators.  So I changed the pattern slightly to do "break.i 0x080001"
bb9a89c
    instead.  But that didn't work either (I later found out that this
bb9a89c
    pattern was used by the simulator that I was using.)  So I ended up
bb9a89c
-   using the pattern seen below. */
bb9a89c
+   using the pattern seen below.
bb9a89c
+
bb9a89c
+   SHADOW_CONTENTS has byte-based addressing (PLACED_ADDRESS and SHADOW_LEN)
bb9a89c
+   while we need bit-based addressing as the instructions length is 41 bits and
bb9a89c
+   we must not modify/corrupt the adjacent ones in the same bundle.
bb9a89c
+   Fortunately we may store larger memory incl. the adjacent bits with the
bb9a89c
+   original memory content (not the possibly already stored breakpoints there).
bb9a89c
+   We need to be careful in ia64_memory_remove_breakpoint to always restore
bb9a89c
+   only the specific bits of this instruction ignoring any adjacent stored
bb9a89c
+   bits.
bb9a89c
+
bb9a89c
+   We use the original addressing with the low nibble 0..2 which gets
bb9a89c
+   incorrectly interpreted by the generic GDB code as the byte offset of
bb9a89c
+   SHADOW_CONTENTS.  We store whole BUNDLE_LEN bytes just without these two
bb9a89c
+   possibly skipped bytes.  */
bb9a89c
 
bb9a89c
 #if 0
bb9a89c
 #define IA64_BREAKPOINT 0x00002000040LL
bb9a89c
@@ -559,15 +573,21 @@ ia64_memory_insert_breakpoint (struct gd
bb9a89c
   CORE_ADDR addr = bp_tgt->placed_address;
bb9a89c
   char bundle[BUNDLE_LEN];
bb9a89c
   int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER;
bb9a89c
-  long long instr;
bb9a89c
   int val;
bb9a89c
   int template;
bb9a89c
+  struct cleanup *cleanup;
bb9a89c
 
bb9a89c
   if (slotnum > 2)
bb9a89c
     error (_("Can't insert breakpoint for slot numbers greater than 2."));
bb9a89c
 
bb9a89c
   addr &= ~0x0f;
bb9a89c
 
bb9a89c
+  /* Enable the automatic memory restoration from breakpoints while
bb9a89c
+     we read our instruction bundle.  Otherwise, we could store into
bb9a89c
+     SHADOW_CONTENTS an already stored breakpoint at the same location.
bb9a89c
+     In practice it is already being prevented by the DUPLICATE field and
bb9a89c
+     update_global_location_list.  */
bb9a89c
+  cleanup = make_show_memory_breakpoints_cleanup (0);
bb9a89c
   val = target_read_memory (addr, bundle, BUNDLE_LEN);
bb9a89c
 
bb9a89c
   /* Check for L type instruction in 2nd slot, if present then
bb9a89c
@@ -578,13 +598,18 @@ ia64_memory_insert_breakpoint (struct gd
bb9a89c
       slotnum = 2;
bb9a89c
     }
bb9a89c
 
bb9a89c
-  instr = slotN_contents (bundle, slotnum);
bb9a89c
-  memcpy (bp_tgt->shadow_contents, &instr, sizeof (instr));
bb9a89c
-  bp_tgt->placed_size = bp_tgt->shadow_len = sizeof (instr);
bb9a89c
+  /* Slot number 2 may skip at most 2 bytes at the beginning.  */
bb9a89c
+  bp_tgt->placed_size = bp_tgt->shadow_len = BUNDLE_LEN - 2;
bb9a89c
+
bb9a89c
+  /* Store the whole bundle, except for the initial skipped bytes by the slot
bb9a89c
+     number interpreted as bytes offset in PLACED_ADDRESS.  */
bb9a89c
+  memcpy (bp_tgt->shadow_contents, bundle + slotnum, bp_tgt->shadow_len);
bb9a89c
+
bb9a89c
   replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum);
bb9a89c
   if (val == 0)
bb9a89c
-    target_write_memory (addr, bundle, BUNDLE_LEN);
bb9a89c
+    target_write_memory (addr + slotnum, bundle + slotnum, bp_tgt->shadow_len);
bb9a89c
 
bb9a89c
+  do_cleanups (cleanup);
bb9a89c
   return val;
bb9a89c
 }
bb9a89c
 
bb9a89c
@@ -593,9 +618,9 @@ ia64_memory_remove_breakpoint (struct gd
bb9a89c
 			       struct bp_target_info *bp_tgt)
bb9a89c
 {
bb9a89c
   CORE_ADDR addr = bp_tgt->placed_address;
bb9a89c
-  char bundle[BUNDLE_LEN];
bb9a89c
+  char bundle_mem[BUNDLE_LEN], bundle_saved[BUNDLE_LEN];
bb9a89c
   int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER;
bb9a89c
-  long long instr;
bb9a89c
+  long long instr_breakpoint, instr_saved;
bb9a89c
   int val;
bb9a89c
   int template;
bb9a89c
   struct cleanup *cleanup;
bb9a89c
@@ -604,23 +629,39 @@ ia64_memory_remove_breakpoint (struct gd
bb9a89c
 
bb9a89c
   /* Disable the automatic memory restoration from breakpoints while
bb9a89c
      we read our instruction bundle.  Otherwise, the general restoration
bb9a89c
-     mechanism kicks in and ends up corrupting our bundle, because it
bb9a89c
-     is not aware of the concept of instruction bundles.  */
bb9a89c
+     mechanism kicks in and we would possibly remove parts of the adjacent
bb9a89c
+     placed breakpoints.  It is due to our SHADOW_CONTENTS overlapping the real
bb9a89c
+     breakpoint instruction bits region.  */
bb9a89c
   cleanup = make_show_memory_breakpoints_cleanup (1);
bb9a89c
-  val = target_read_memory (addr, bundle, BUNDLE_LEN);
bb9a89c
+  val = target_read_memory (addr, bundle_mem, BUNDLE_LEN);
bb9a89c
 
bb9a89c
   /* Check for L type instruction in 2nd slot, if present then
bb9a89c
      bump up the slot number to the 3rd slot */
bb9a89c
-  template = extract_bit_field (bundle, 0, 5);
bb9a89c
+  template = extract_bit_field (bundle_mem, 0, 5);
bb9a89c
   if (slotnum == 1 && template_encoding_table[template][1] == L)
bb9a89c
     {
bb9a89c
       slotnum = 2;
bb9a89c
     }
bb9a89c
 
bb9a89c
-  memcpy (&instr, bp_tgt->shadow_contents, sizeof instr);
bb9a89c
-  replace_slotN_contents (bundle, instr, slotnum);
bb9a89c
+  gdb_assert (bp_tgt->placed_size == BUNDLE_LEN - 2);
bb9a89c
+  gdb_assert (bp_tgt->placed_size == bp_tgt->shadow_len);
bb9a89c
+
bb9a89c
+  instr_breakpoint = slotN_contents (bundle_mem, slotnum);
bb9a89c
+  if (instr_breakpoint != IA64_BREAKPOINT)
bb9a89c
+    warning (_("Breakpoint removal cannot find the placed breakpoint at %s"),
bb9a89c
+             paddr_nz (bp_tgt->placed_address));
bb9a89c
+
bb9a89c
+  /* Extract the original saved instruction from SLOTNUM normalizing its
bb9a89c
+     bit-shift for INSTR_SAVED.  */
bb9a89c
+  memcpy (bundle_saved, bundle_mem, BUNDLE_LEN);
bb9a89c
+  memcpy (bundle_saved + slotnum, bp_tgt->shadow_contents, bp_tgt->shadow_len);
bb9a89c
+  instr_saved = slotN_contents (bundle_saved, slotnum);
bb9a89c
+
bb9a89c
+  /* In BUNDLE_MEM be careful to modify only the bits belonging to SLOTNUM and
bb9a89c
+     never any other possibly also stored in SHADOW_CONTENTS.  */
bb9a89c
+  replace_slotN_contents (bundle_mem, instr_saved, slotnum);
bb9a89c
   if (val == 0)
bb9a89c
-    target_write_memory (addr, bundle, BUNDLE_LEN);
bb9a89c
+    target_write_memory (addr, bundle_mem, BUNDLE_LEN);
bb9a89c
 
bb9a89c
   do_cleanups (cleanup);
bb9a89c
   return val;
bb9a89c
@@ -631,12 +672,18 @@ ia64_memory_remove_breakpoint (struct gd
bb9a89c
 const unsigned char *
bb9a89c
 ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
bb9a89c
 {
bb9a89c
-  static unsigned char breakpoint[] =
bb9a89c
-    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
bb9a89c
-  *lenptr = sizeof (breakpoint);
bb9a89c
-#if 0
bb9a89c
-  *pcptr &= ~0x0f;
bb9a89c
+  static unsigned char breakpoint[BUNDLE_LEN];
bb9a89c
+  int slotnum = (int) (*pcptr & 0x0f) / SLOT_MULTIPLIER;
bb9a89c
+
bb9a89c
+  if (slotnum > 2)
bb9a89c
+    error (_("Can't insert breakpoint for slot numbers greater than 2."));
bb9a89c
+
bb9a89c
+#if BREAKPOINT_MAX < BUNDLE_LEN
bb9a89c
+# error "BREAKPOINT_MAX < BUNDLE_LEN"
bb9a89c
 #endif
bb9a89c
+
bb9a89c
+  *lenptr = BUNDLE_LEN - 2;
bb9a89c
+
bb9a89c
   return breakpoint;
bb9a89c
 }
bb9a89c
 
bb9a89c
--- /dev/null	1 Jan 1970 00:00:00 -0000
bb9a89c
+++ ./gdb/testsuite/gdb.base/breakpoint-shadow.c	28 Oct 2008 10:28:41 -0000
bb9a89c
@@ -0,0 +1,27 @@
bb9a89c
+/* This testcase is part of GDB, the GNU debugger.
bb9a89c
+
bb9a89c
+   Copyright 2008 Free Software Foundation, Inc.
bb9a89c
+
bb9a89c
+   This program is free software; you can redistribute it and/or modify
bb9a89c
+   it under the terms of the GNU General Public License as published by
bb9a89c
+   the Free Software Foundation; either version 3 of the License, or
bb9a89c
+   (at your option) any later version.
bb9a89c
+
bb9a89c
+   This program is distributed in the hope that it will be useful,
bb9a89c
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
bb9a89c
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bb9a89c
+   GNU General Public License for more details.
bb9a89c
+
bb9a89c
+   You should have received a copy of the GNU General Public License
bb9a89c
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
bb9a89c
+
bb9a89c
+int
bb9a89c
+main (void)
bb9a89c
+{
bb9a89c
+  volatile int i;
bb9a89c
+  
bb9a89c
+  i = 1;	/* break-first */
bb9a89c
+  i = 2;	/* break-second */
bb9a89c
+
bb9a89c
+  return 0;
bb9a89c
+}
bb9a89c
--- /dev/null	1 Jan 1970 00:00:00 -0000
bb9a89c
+++ ./gdb/testsuite/gdb.base/breakpoint-shadow.exp	28 Oct 2008 10:28:41 -0000
bb9a89c
@@ -0,0 +1,65 @@
bb9a89c
+# Copyright 2008 Free Software Foundation, Inc.
bb9a89c
+
bb9a89c
+# This program is free software; you can redistribute it and/or modify
bb9a89c
+# it under the terms of the GNU General Public License as published by
bb9a89c
+# the Free Software Foundation; either version 3 of the License, or
bb9a89c
+# (at your option) any later version.
bb9a89c
+#
bb9a89c
+# This program is distributed in the hope that it will be useful,
bb9a89c
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
bb9a89c
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bb9a89c
+# GNU General Public License for more details.
bb9a89c
+#
bb9a89c
+# You should have received a copy of the GNU General Public License
bb9a89c
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
bb9a89c
+
bb9a89c
+set testfile breakpoint-shadow
bb9a89c
+set srcfile ${testfile}.c
bb9a89c
+set binfile ${objdir}/${subdir}/${testfile}
bb9a89c
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
bb9a89c
+    untested "Couldn't compile test program"
bb9a89c
+    return -1
bb9a89c
+}
bb9a89c
+
bb9a89c
+gdb_exit
bb9a89c
+gdb_start
bb9a89c
+gdb_reinitialize_dir $srcdir/$subdir
bb9a89c
+gdb_load ${binfile}
bb9a89c
+
bb9a89c
+# We need to start the inferior to place the breakpoints in the memory at all.
bb9a89c
+if { [gdb_start_cmd] < 0 } {
bb9a89c
+    untested start
bb9a89c
+    return -1
bb9a89c
+}
bb9a89c
+gdb_test "" "main \\(\\) at .*" "start"
bb9a89c
+
bb9a89c
+# The default "auto" mode removes all the breakpoints when we stop (and not
bb9a89c
+# running the nonstop mode).  We would not be able to test the shadow.
bb9a89c
+#RHEL-5:
bb9a89c
+#gdb_test "set breakpoint always-inserted on"
bb9a89c
+#gdb_test "show breakpoint always-inserted" "Always inserted breakpoint mode is on."
bb9a89c
+
bb9a89c
+set match "\nDump of assembler code for function main:\r\n(.*)End of assembler dump.\r\n$gdb_prompt $"
bb9a89c
+
bb9a89c
+set test "disassembly without breakpoints"
bb9a89c
+gdb_test_multiple "disass main" $test {
bb9a89c
+    -re $match {
bb9a89c
+    	set orig $expect_out(1,string)
bb9a89c
+	pass $test
bb9a89c
+    }
bb9a89c
+}
bb9a89c
+
bb9a89c
+gdb_test "b [gdb_get_line_number "break-first"]" "Breakpoint \[0-9\] at .*" "First breakpoint placed"
bb9a89c
+gdb_test "b [gdb_get_line_number "break-second"]" "Breakpoint \[0-9\] at .*" "Second breakpoint placed"
bb9a89c
+
bb9a89c
+set test "disassembly with breakpoints"
bb9a89c
+gdb_test_multiple "disass main" $test {
bb9a89c
+    -re $match {
bb9a89c
+    	set got $expect_out(1,string)
bb9a89c
+	if [string equal -nocase $orig $got] {
bb9a89c
+	    pass $test
bb9a89c
+	} else {
bb9a89c
+	    fail $test
bb9a89c
+	}
bb9a89c
+    }
bb9a89c
+}