* [patch] ia64: Fix breakpoints memory shadow
@ 2008-10-28 17:52 Jan Kratochvil
2008-10-30 1:51 ` Joel Brobecker
0 siblings, 1 reply; 13+ messages in thread
From: Jan Kratochvil @ 2008-10-28 17:52 UTC (permalink / raw)
To: gdb-patches; +Cc: Joel Brobecker
[-- Attachment #1: Type: text/plain, Size: 609 bytes --]
Hi,
fix a corruption of ia64 `disass' with breakpoints placed in the target.
It is another part of the Joel Brobecker's ia64-specific breakpoints fix:
[commit] SIGILL in ld.so when running program from GDB on ia64-linux
http://sourceware.org/ml/gdb-patches/2008-04/msg00674.html
Currently ia64-tdep.c considers SHADOW_CONTENTS as a private memory space. But
it is in use by breakpoint_restore_shadows to undo the breakpoints for display.
Not going to speculate here if it may fix a breakpoints functionality. It is
at least not a regression. No regressions found (on ia64). New testcase.
Thanks,
Jan
[-- Attachment #2: ia64-align.patch --]
[-- Type: text/plain, Size: 10747 bytes --]
gdb/
2008-10-28 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix automatic restoration of breakpoints memory for ia64.
* ia64-tdep.c (ia64_memory_insert_breakpoint): New comment part for
SHADOW_CONTENTS content. Remova variable instr. New variable cleanup.
Force automatic breakpoints restoration. PLACED_SIZE and SHADOW_LEN
are now set larger, to BUNDLE_LEN - 2.
(ia64_memory_remove_breakpoint): Rename variables bundle to bundle_mem
and instr to instr_saved. New variables bundle_saved and
instr_breakpoint. Comment new reasons why we need to disable automatic
restoration of breakpoints. Assert PLACED_SIZE and SHADOW_LEN. New
check of the original memory content.
(ia64_breakpoint_from_pc): Array breakpoint extended to BUNDLE_LEN.
Sanity check the PCPTR parameter SLOTNUM value. New #if check on
BREAKPOINT_MAX vs. BUNDLE_LEN. Increase LENPTR to BUNDLE_LEN - 2.
gdb/testsuite/
2008-10-28 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/breakpoint-shadow.exp, gdb.base/breakpoint-shadow.c: New.
--- gdb/ia64-tdep.c 11 Sep 2008 14:23:15 -0000 1.184
+++ gdb/ia64-tdep.c 28 Oct 2008 10:28:41 -0000
@@ -545,7 +545,21 @@ fetch_instruction (CORE_ADDR addr, instr
simulators. So I changed the pattern slightly to do "break.i 0x080001"
instead. But that didn't work either (I later found out that this
pattern was used by the simulator that I was using.) So I ended up
- using the pattern seen below. */
+ using the pattern seen below.
+
+ SHADOW_CONTENTS has byte-based addressing (PLACED_ADDRESS and SHADOW_LEN)
+ while we need bit-based addressing as the instructions length is 41 bits and
+ we must not modify/corrupt the adjacent ones in the same bundle.
+ Fortunately we may store larger memory incl. the adjacent bits with the
+ original memory content (not the possibly already stored breakpoints there).
+ We need to be careful in ia64_memory_remove_breakpoint to always restore
+ only the specific bits of this instruction ignoring any adjacent stored
+ bits.
+
+ We use the original addressing with the low nibble 0..2 which gets
+ incorrectly interpreted by the generic GDB code as the byte offset of
+ SHADOW_CONTENTS. We store whole BUNDLE_LEN bytes just without these two
+ possibly skipped bytes. */
#if 0
#define IA64_BREAKPOINT 0x00002000040LL
@@ -559,15 +573,21 @@ ia64_memory_insert_breakpoint (struct gd
CORE_ADDR addr = bp_tgt->placed_address;
char bundle[BUNDLE_LEN];
int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER;
- long long instr;
int val;
int template;
+ struct cleanup *cleanup;
if (slotnum > 2)
error (_("Can't insert breakpoint for slot numbers greater than 2."));
addr &= ~0x0f;
+ /* Enable the automatic memory restoration from breakpoints while
+ we read our instruction bundle. Otherwise, we could store into
+ SHADOW_CONTENTS an already stored breakpoint at the same location.
+ In practice it is already being prevented by the DUPLICATE field and
+ update_global_location_list. */
+ cleanup = make_show_memory_breakpoints_cleanup (0);
val = target_read_memory (addr, bundle, BUNDLE_LEN);
/* Check for L type instruction in 2nd slot, if present then
@@ -578,13 +598,18 @@ ia64_memory_insert_breakpoint (struct gd
slotnum = 2;
}
- instr = slotN_contents (bundle, slotnum);
- memcpy (bp_tgt->shadow_contents, &instr, sizeof (instr));
- bp_tgt->placed_size = bp_tgt->shadow_len = sizeof (instr);
+ /* Slot number 2 may skip at most 2 bytes at the beginning. */
+ bp_tgt->placed_size = bp_tgt->shadow_len = BUNDLE_LEN - 2;
+
+ /* Store the whole bundle, except for the initial skipped bytes by the slot
+ number interpreted as bytes offset in PLACED_ADDRESS. */
+ memcpy (bp_tgt->shadow_contents, bundle + slotnum, bp_tgt->shadow_len);
+
replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum);
if (val == 0)
- target_write_memory (addr, bundle, BUNDLE_LEN);
+ target_write_memory (addr + slotnum, bundle + slotnum, bp_tgt->shadow_len);
+ do_cleanups (cleanup);
return val;
}
@@ -593,9 +618,9 @@ ia64_memory_remove_breakpoint (struct gd
struct bp_target_info *bp_tgt)
{
CORE_ADDR addr = bp_tgt->placed_address;
- char bundle[BUNDLE_LEN];
+ char bundle_mem[BUNDLE_LEN], bundle_saved[BUNDLE_LEN];
int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER;
- long long instr;
+ long long instr_breakpoint, instr_saved;
int val;
int template;
struct cleanup *cleanup;
@@ -604,23 +629,39 @@ ia64_memory_remove_breakpoint (struct gd
/* Disable the automatic memory restoration from breakpoints while
we read our instruction bundle. Otherwise, the general restoration
- mechanism kicks in and ends up corrupting our bundle, because it
- is not aware of the concept of instruction bundles. */
+ mechanism kicks in and we would possibly remove parts of the adjacent
+ placed breakpoints. It is due to our SHADOW_CONTENTS overlapping the real
+ breakpoint instruction bits region. */
cleanup = make_show_memory_breakpoints_cleanup (1);
- val = target_read_memory (addr, bundle, BUNDLE_LEN);
+ val = target_read_memory (addr, bundle_mem, BUNDLE_LEN);
/* Check for L type instruction in 2nd slot, if present then
bump up the slot number to the 3rd slot */
- template = extract_bit_field (bundle, 0, 5);
+ template = extract_bit_field (bundle_mem, 0, 5);
if (slotnum == 1 && template_encoding_table[template][1] == L)
{
slotnum = 2;
}
- memcpy (&instr, bp_tgt->shadow_contents, sizeof instr);
- replace_slotN_contents (bundle, instr, slotnum);
+ gdb_assert (bp_tgt->placed_size == BUNDLE_LEN - 2);
+ gdb_assert (bp_tgt->placed_size == bp_tgt->shadow_len);
+
+ instr_breakpoint = slotN_contents (bundle_mem, slotnum);
+ if (instr_breakpoint != IA64_BREAKPOINT)
+ warning (_("Breakpoint removal cannot find the placed breakpoint at %s"),
+ paddr_nz (bp_tgt->placed_address));
+
+ /* Extract the original saved instruction from SLOTNUM normalizing its
+ bit-shift for INSTR_SAVED. */
+ memcpy (bundle_saved, bundle_mem, BUNDLE_LEN);
+ memcpy (bundle_saved + slotnum, bp_tgt->shadow_contents, bp_tgt->shadow_len);
+ instr_saved = slotN_contents (bundle_saved, slotnum);
+
+ /* In BUNDLE_MEM be careful to modify only the bits belonging to SLOTNUM and
+ never any other possibly also stored in SHADOW_CONTENTS. */
+ replace_slotN_contents (bundle_mem, instr_saved, slotnum);
if (val == 0)
- target_write_memory (addr, bundle, BUNDLE_LEN);
+ target_write_memory (addr, bundle_mem, BUNDLE_LEN);
do_cleanups (cleanup);
return val;
@@ -631,12 +672,18 @@ ia64_memory_remove_breakpoint (struct gd
const unsigned char *
ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
{
- static unsigned char breakpoint[] =
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- *lenptr = sizeof (breakpoint);
-#if 0
- *pcptr &= ~0x0f;
+ static unsigned char breakpoint[BUNDLE_LEN];
+ int slotnum = (int) (*pcptr & 0x0f) / SLOT_MULTIPLIER;
+
+ if (slotnum > 2)
+ error (_("Can't insert breakpoint for slot numbers greater than 2."));
+
+#if BREAKPOINT_MAX < BUNDLE_LEN
+# error "BREAKPOINT_MAX < BUNDLE_LEN"
#endif
+
+ *lenptr = BUNDLE_LEN - 2;
+
return breakpoint;
}
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/breakpoint-shadow.c 28 Oct 2008 10:28:41 -0000
@@ -0,0 +1,27 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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/>. */
+
+int
+main (void)
+{
+ volatile int i;
+
+ i = 1; /* break-first */
+ i = 2; /* break-second */
+
+ return 0;
+}
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/breakpoint-shadow.exp 28 Oct 2008 10:28:41 -0000
@@ -0,0 +1,64 @@
+# Copyright 2008 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/>.
+
+set testfile breakpoint-shadow
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# We need to start the inferior to place the breakpoints in the memory at all.
+if { [gdb_start_cmd] < 0 } {
+ untested start
+ return -1
+}
+gdb_test "" "main \\(\\) at .*" "start"
+
+# The default "auto" mode removes all the breakpoints when we stop (and not
+# running the nonstop mode). We would not be able to test the shadow.
+gdb_test "set breakpoint always-inserted on"
+gdb_test "show breakpoint always-inserted" "Always inserted breakpoint mode is on."
+
+set match "\nDump of assembler code for function main:\r\n(.*)End of assembler dump.\r\n$gdb_prompt $"
+
+set test "disassembly without breakpoints"
+gdb_test_multiple "disass main" $test {
+ -re $match {
+ set orig $expect_out(1,string)
+ pass $test
+ }
+}
+
+gdb_test "b [gdb_get_line_number "break-first"]" "Breakpoint \[0-9\] at .*" "First breakpoint placed"
+gdb_test "b [gdb_get_line_number "break-second"]" "Breakpoint \[0-9\] at .*" "Second breakpoint placed"
+
+set test "disassembly with breakpoints"
+gdb_test_multiple "disass main" $test {
+ -re $match {
+ set got $expect_out(1,string)
+ if [string equal -nocase $orig $got] {
+ pass $test
+ } else {
+ fail $test
+ }
+ }
+}
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [patch] ia64: Fix breakpoints memory shadow 2008-10-28 17:52 [patch] ia64: Fix breakpoints memory shadow Jan Kratochvil @ 2008-10-30 1:51 ` Joel Brobecker 2008-10-31 0:03 ` Jan Kratochvil 0 siblings, 1 reply; 13+ messages in thread From: Joel Brobecker @ 2008-10-30 1:51 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches Hi Jan, > 2008-10-28 Jan Kratochvil <jan.kratochvil@redhat.com> > > Fix automatic restoration of breakpoints memory for ia64. > * ia64-tdep.c (ia64_memory_insert_breakpoint): New comment part for > SHADOW_CONTENTS content. Remova variable instr. New variable cleanup. > Force automatic breakpoints restoration. PLACED_SIZE and SHADOW_LEN > are now set larger, to BUNDLE_LEN - 2. > (ia64_memory_remove_breakpoint): Rename variables bundle to bundle_mem > and instr to instr_saved. New variables bundle_saved and > instr_breakpoint. Comment new reasons why we need to disable automatic > restoration of breakpoints. Assert PLACED_SIZE and SHADOW_LEN. New > check of the original memory content. > (ia64_breakpoint_from_pc): Array breakpoint extended to BUNDLE_LEN. > Sanity check the PCPTR parameter SLOTNUM value. New #if check on > BREAKPOINT_MAX vs. BUNDLE_LEN. Increase LENPTR to BUNDLE_LEN - 2. I understand the overall idea, but I don't understand the logic behind saving BUNDLE_LEN - 2 bytes (14 bytes, then) of the bundle at bundle address + slotnum. It looks like this introduces extra complexity. Instead, would it be possible to save the entire bundle, when inserting the breakpoint? When comes time to remove it, we would only need to read the whole bundle, extract the original insn from our saved bundle, and then push it back into the target bundle. > +# We need to start the inferior to place the breakpoints in the memory at all. > +if { [gdb_start_cmd] < 0 } { > + untested start > + return -1 > +} > +gdb_test "" "main \\(\\) at .*" "start" Why not use runto_main here? -- Joel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-10-30 1:51 ` Joel Brobecker @ 2008-10-31 0:03 ` Jan Kratochvil 2008-11-01 18:54 ` Joel Brobecker 0 siblings, 1 reply; 13+ messages in thread From: Jan Kratochvil @ 2008-10-31 0:03 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches Hi Joel, On Wed, 29 Oct 2008 22:02:42 +0100, Joel Brobecker wrote: > I understand the overall idea, but I don't understand the logic behind > saving BUNDLE_LEN - 2 bytes (14 bytes, then) of the bundle at bundle > address + slotnum. It looks like this introduces extra complexity. > > Instead, would it be possible to save the entire bundle, when > inserting the breakpoint? When comes time to remove it, we would > only need to read the whole bundle, extract the original insn from > our saved bundle, and then push it back into the target bundle. I agree your proposal would be better but we have to comply with the current `struct bp_target_info' layout which is being intepreted outside of ia64-tdep.c - in breakpoint_restore_shadows. If we would like to store the whole bundle to SHADOW_CONTENTS we would have to store already the base address (`address & ~0x0f') into PLACED_ADDRESS. In such case there is no other place where to store SLOTNUM (`adress & 0x0f', value in the range <0..2>). We need to know SLOTNUM in ia64_memory_remove_breakpoint. ia64 16-byte bundle layout: | 5 bits | slot 0 with 41 bits | slot 1 with 41 bits | slot 2 with 41 bits | (A) The current way of the patch: original PC placed_address placed_size required covered == bp_tgt->shadow_len required \subset covered 0xABCDE0 0xABCDE0 0xE <0x0...0x5> <0x0..0xD> 0xABCDE1 0xABCDE1 0xE <0x5...0xA> <0x1..0xE> 0xABCDE2 0xABCDE2 0xE <0xA...0xF> <0x2..0xF> (B) Another way would be (converting `original PC' -> `placed_address' in ia64_breakpoint_from_pc): original PC placed_address placed_size required covered == bp_tgt->shadow_len 0xABCDE0 0xABCDE0 0x6 <0x0...0x5> <0x0..0x5> 0xABCDE1 0xABCDE5 0x6 <0x5...0xA> <0x5..0xA> 0xABCDE2 0xABCDEA 0x6 <0xA...0xF> <0xA..0xF> `objdump -d' and some other tools show a bit unjustified offsets: original PC byte where starts the instruction objdump offset 0xABCDE0 0xABCDE0 0xABCDE0 0xABCDE1 0xABCDE5 0xABCDE6 0xABCDE2 0xABCDEA 0xABCDEC I can freely change the current (A) way for (B) but I found the code easier this way. (B) would be more minimal/effective but sure it does not matter. > > +# We need to start the inferior to place the breakpoints in the memory at all. > > +if { [gdb_start_cmd] < 0 } { > > + untested start > > + return -1 > > +} > > +gdb_test "" "main \\(\\) at .*" "start" > > Why not use runto_main here? I will change it in the final patch together with a note in gdb.base/start.exp that it is there to test gdb_start_cmd, not to start a program. Thanks, Jan ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-10-31 0:03 ` Jan Kratochvil @ 2008-11-01 18:54 ` Joel Brobecker 2008-11-11 20:20 ` Jan Kratochvil 0 siblings, 1 reply; 13+ messages in thread From: Joel Brobecker @ 2008-11-01 18:54 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches > I agree your proposal would be better but we have to comply with the current > `struct bp_target_info' layout which is being intepreted outside of > ia64-tdep.c - in breakpoint_restore_shadows. > > If we would like to store the whole bundle to SHADOW_CONTENTS we would have to > store already the base address (`address & ~0x0f') into PLACED_ADDRESS. In > such case there is no other place where to store SLOTNUM (`adress & 0x0f', > value in the range <0..2>). We need to know SLOTNUM in > ia64_memory_remove_breakpoint. Aie aie aie, that's true. I was also looking at the idea of stuffing the slot number in the first 5 bits of the bundle, but that wouldn't work either, as breakpoint_restore_shadows can restore those bits as well. There is one alternative which is to define a gdbarch restore_shadow, but your approach does work after all, so let's not complexify the rest of GDB just for ia64. Can we maybe expand the comment explaining why we can't save the whole bundle in the shadow buffer? > const unsigned char * > ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) > { > - static unsigned char breakpoint[] = > - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; > - *lenptr = sizeof (breakpoint); > -#if 0 > - *pcptr &= ~0x0f; > + static unsigned char breakpoint[BUNDLE_LEN]; > + int slotnum = (int) (*pcptr & 0x0f) / SLOT_MULTIPLIER; > + > + if (slotnum > 2) > + error (_("Can't insert breakpoint for slot numbers greater than 2.")); > + > +#if BREAKPOINT_MAX < BUNDLE_LEN > +# error "BREAKPOINT_MAX < BUNDLE_LEN" > #endif > + > + *lenptr = BUNDLE_LEN - 2; > + > return breakpoint; > } I think there is a piece missing in this change. Looks like breakpoint is no longer initialized. I think that what you need to do is read the instruction bundle from memory, and insert the breakpoint instruction, and then copy you BUNDLE_LEN - 2 bytes into the breakpoint buffer. The reason why we didn't trip over this, I believe, is because this routine is only used when using the default insert/remove bp routines, or when using the remote protocol. It's also used from monitor.c. Also, the check for BUNDLE_LEN against BREAKPOINT_MAX is slightly over-pessimistic. Can you move it somewhere at the beginning of the file (this assumption is required in other parts of the code), and compare BREAKPOINT_MAX against the actual size of data saved (BUNDLE_LEN -2)? The rest looks OK to me. -- Joel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-01 18:54 ` Joel Brobecker @ 2008-11-11 20:20 ` Jan Kratochvil 2008-11-13 14:27 ` Joel Brobecker 0 siblings, 1 reply; 13+ messages in thread From: Jan Kratochvil @ 2008-11-11 20:20 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 1636 bytes --] On Sat, 01 Nov 2008 19:54:10 +0100, Joel Brobecker wrote: > Can we maybe expand the comment explaining why we can't save the whole > bundle in the shadow buffer? Done, mostly copied the mail of mine there. > > const unsigned char * > > ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) > > { > > - static unsigned char breakpoint[] = > > - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ... > I think there is a piece missing in this change. Looks like breakpoint > is no longer initialized. According to ISO C90 6.5.7 such a static array is (was) initialized to zeroes. > I think that what you need to do is read the instruction bundle from memory, > and insert the breakpoint instruction, and then copy you > BUNDLE_LEN - 2 bytes into the breakpoint buffer. I just kept it broken with no regressions. But OK, fixed. > The reason why we didn't trip over this, I believe, is because this routine > is only used when using the default insert/remove bp routines, or when using > the remote protocol. It's also used from monitor.c. The return value is used for the ia64 case only in bp_loc_is_permanent, nowhere else. And for ia64 the arch interface is inappropriate but we can keep it this way as it is probably the right interface for anything non-ia64. > Also, the check for BUNDLE_LEN against BREAKPOINT_MAX is slightly > over-pessimistic. Can you move it somewhere at the beginning of > the file (this assumption is required in other parts of the code), > and compare BREAKPOINT_MAX against the actual size of data saved > (BUNDLE_LEN -2)? Right, thanks, done. Regards, Jan [-- Attachment #2: ia64-align2.patch --] [-- Type: text/plain, Size: 17568 bytes --] gdb/ 2008-11-11 Jan Kratochvil <jan.kratochvil@redhat.com> Fix automatic restoration of breakpoints memory for ia64. * ia64-tdep.c: New #if check on BREAKPOINT_MAX vs. BUNDLE_LEN. (ia64_memory_insert_breakpoint): New comment part for SHADOW_CONTENTS content. Remova variable instr. New variable cleanup. Force automatic breakpoints restoration. PLACED_SIZE and SHADOW_LEN are now set larger, to BUNDLE_LEN - 2. Variable `bundle' type update. (ia64_memory_remove_breakpoint): Rename variables bundle to bundle_mem and instr to instr_saved. New variables bundle_saved and instr_breakpoint. Comment new reasons why we need to disable automatic restoration of breakpoints. Assert PLACED_SIZE and SHADOW_LEN. New check of the original memory content. (ia64_breakpoint_from_pc): Implement the emulation of permanent breakpoints compatible with current bp_loc_is_permanent. (template_encoding_table): Make it `const'. * breakpoint.c (bp_loc_is_permanent): Support unsupported software breakpoints. New variables `cleanup' and `retval' to protect target_read_memory by make_show_memory_breakpoints_cleanup. * monitor.c (monitor_insert_breakpoint): Remove unused variable `bp'. gdb/testsuite/ 2008-11-11 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.base/breakpoint-shadow.exp, gdb.base/breakpoint-shadow.c: New. * gdb.base/start.exp: New comment about an alternative - `runto_main'. --- gdb/breakpoint.c 3 Nov 2008 14:01:26 -0000 1.359 +++ gdb/breakpoint.c 11 Nov 2008 12:57:12 -0000 @@ -5234,19 +5234,32 @@ bp_loc_is_permanent (struct bp_location CORE_ADDR addr; const gdb_byte *brk; gdb_byte *target_mem; + struct cleanup *cleanup; + int retval = 0; gdb_assert (loc != NULL); addr = loc->address; brk = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &len); + /* Software breakpoints unsupported? */ + if (brk == NULL) + return 0; + target_mem = alloca (len); + /* Enable the automatic memory restoration from breakpoints while + we read the memory. Otherwise we could say about our temporary + breakpoints they are permanent. */ + cleanup = make_show_memory_breakpoints_cleanup (0); + if (target_read_memory (loc->address, target_mem, len) == 0 && memcmp (target_mem, brk, len) == 0) - return 1; + retval = 1; - return 0; + do_cleanups (cleanup); + + return retval; } --- gdb/ia64-tdep.c 11 Sep 2008 14:23:15 -0000 1.184 +++ gdb/ia64-tdep.c 11 Nov 2008 12:57:12 -0000 @@ -110,6 +110,12 @@ typedef enum instruction_type #define BUNDLE_LEN 16 +/* See the saved memory layout comment for ia64_memory_insert_breakpoint. */ + +#if BREAKPOINT_MAX < BUNDLE_LEN - 2 +# error "BREAKPOINT_MAX < BUNDLE_LEN - 2" +#endif + static gdbarch_init_ftype ia64_gdbarch_init; static gdbarch_register_name_ftype ia64_register_name; @@ -442,7 +448,7 @@ replace_slotN_contents (char *bundle, lo replace_bit_field (bundle, instr, 5+41*slotnum, 41); } -static enum instruction_type template_encoding_table[32][3] = +static const enum instruction_type template_encoding_table[32][3] = { { M, I, I }, /* 00 */ { M, I, I }, /* 01 */ @@ -545,7 +551,45 @@ fetch_instruction (CORE_ADDR addr, instr simulators. So I changed the pattern slightly to do "break.i 0x080001" instead. But that didn't work either (I later found out that this pattern was used by the simulator that I was using.) So I ended up - using the pattern seen below. */ + using the pattern seen below. + + SHADOW_CONTENTS has byte-based addressing (PLACED_ADDRESS and SHADOW_LEN) + while we need bit-based addressing as the instructions length is 41 bits and + we must not modify/corrupt the adjacent slots in the same bundle. + Fortunately we may store larger memory incl. the adjacent bits with the + original memory content (not the possibly already stored breakpoints there). + We need to be careful in ia64_memory_remove_breakpoint to always restore + only the specific bits of this instruction ignoring any adjacent stored + bits. + + We use the original addressing with the low nibble in the range <0..2> which + gets incorrectly interpreted by generic non-ia64 breakpoint_restore_shadows + as the direct byte offset of SHADOW_CONTENTS. We store whole BUNDLE_LEN + bytes just without these two possibly skipped bytes to not to exceed to the + next bundle. + + If we would like to store the whole bundle to SHADOW_CONTENTS we would have + to store already the base address (`address & ~0x0f') into PLACED_ADDRESS. + In such case there is no other place where to store + SLOTNUM (`adress & 0x0f', value in the range <0..2>). We need to know + SLOTNUM in ia64_memory_remove_breakpoint. + + ia64 16-byte bundle layout: + | 5 bits | slot 0 with 41 bits | slot 1 with 41 bits | slot 2 with 41 bits | + + The current addressing used by the code below: + original PC placed_address placed_size required covered + == bp_tgt->shadow_len reqd \subset covered + 0xABCDE0 0xABCDE0 0xE <0x0...0x5> <0x0..0xD> + 0xABCDE1 0xABCDE1 0xE <0x5...0xA> <0x1..0xE> + 0xABCDE2 0xABCDE2 0xE <0xA...0xF> <0x2..0xF> + + `objdump -d' and some other tools show a bit unjustified offsets: + original PC byte where starts the instruction objdump offset + 0xABCDE0 0xABCDE0 0xABCDE0 + 0xABCDE1 0xABCDE5 0xABCDE6 + 0xABCDE2 0xABCDEA 0xABCDEC + */ #if 0 #define IA64_BREAKPOINT 0x00002000040LL @@ -557,34 +601,43 @@ ia64_memory_insert_breakpoint (struct gd struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; - char bundle[BUNDLE_LEN]; + gdb_byte bundle[BUNDLE_LEN]; int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; int val; int template; + struct cleanup *cleanup; if (slotnum > 2) error (_("Can't insert breakpoint for slot numbers greater than 2.")); addr &= ~0x0f; + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle. Otherwise, we could store into + SHADOW_CONTENTS an already stored breakpoint at the same location. + In practice it is already being prevented by the DUPLICATE field and + update_global_location_list. */ + cleanup = make_show_memory_breakpoints_cleanup (0); val = target_read_memory (addr, bundle, BUNDLE_LEN); /* Check for L type instruction in 2nd slot, if present then bump up the slot number to the 3rd slot */ template = extract_bit_field (bundle, 0, 5); - if (slotnum == 1 && template_encoding_table[template][1] == L) - { - slotnum = 2; - } + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + /* Slot number 2 may skip at most 2 bytes at the beginning. */ + bp_tgt->placed_size = bp_tgt->shadow_len = BUNDLE_LEN - 2; + + /* Store the whole bundle, except for the initial skipped bytes by the slot + number interpreted as bytes offset in PLACED_ADDRESS. */ + memcpy (bp_tgt->shadow_contents, bundle + slotnum, bp_tgt->shadow_len); - instr = slotN_contents (bundle, slotnum); - memcpy (bp_tgt->shadow_contents, &instr, sizeof (instr)); - bp_tgt->placed_size = bp_tgt->shadow_len = sizeof (instr); replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum); if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + target_write_memory (addr + slotnum, bundle + slotnum, bp_tgt->shadow_len); + do_cleanups (cleanup); return val; } @@ -593,9 +646,9 @@ ia64_memory_remove_breakpoint (struct gd struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; - char bundle[BUNDLE_LEN]; + gdb_byte bundle_mem[BUNDLE_LEN], bundle_saved[BUNDLE_LEN]; int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; + long long instr_breakpoint, instr_saved; int val; int template; struct cleanup *cleanup; @@ -604,40 +657,93 @@ ia64_memory_remove_breakpoint (struct gd /* Disable the automatic memory restoration from breakpoints while we read our instruction bundle. Otherwise, the general restoration - mechanism kicks in and ends up corrupting our bundle, because it - is not aware of the concept of instruction bundles. */ + mechanism kicks in and we would possibly remove parts of the adjacent + placed breakpoints. It is due to our SHADOW_CONTENTS overlapping the real + breakpoint instruction bits region. */ cleanup = make_show_memory_breakpoints_cleanup (1); - val = target_read_memory (addr, bundle, BUNDLE_LEN); + val = target_read_memory (addr, bundle_mem, BUNDLE_LEN); /* Check for L type instruction in 2nd slot, if present then bump up the slot number to the 3rd slot */ - template = extract_bit_field (bundle, 0, 5); - if (slotnum == 1 && template_encoding_table[template][1] == L) - { - slotnum = 2; - } - - memcpy (&instr, bp_tgt->shadow_contents, sizeof instr); - replace_slotN_contents (bundle, instr, slotnum); + template = extract_bit_field (bundle_mem, 0, 5); + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + gdb_assert (bp_tgt->placed_size == BUNDLE_LEN - 2); + gdb_assert (bp_tgt->placed_size == bp_tgt->shadow_len); + + instr_breakpoint = slotN_contents (bundle_mem, slotnum); + if (instr_breakpoint != IA64_BREAKPOINT) + warning (_("Breakpoint removal cannot find the placed breakpoint at %s"), + paddr_nz (bp_tgt->placed_address)); + + /* Extract the original saved instruction from SLOTNUM normalizing its + bit-shift for INSTR_SAVED. */ + memcpy (bundle_saved, bundle_mem, BUNDLE_LEN); + memcpy (bundle_saved + slotnum, bp_tgt->shadow_contents, bp_tgt->shadow_len); + instr_saved = slotN_contents (bundle_saved, slotnum); + + /* In BUNDLE_MEM be careful to modify only the bits belonging to SLOTNUM and + never any other possibly also stored in SHADOW_CONTENTS. */ + replace_slotN_contents (bundle_mem, instr_saved, slotnum); if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + target_write_memory (addr, bundle_mem, BUNDLE_LEN); do_cleanups (cleanup); return val; } -/* We don't really want to use this, but remote.c needs to call it in order - to figure out if Z-packets are supported or not. Oh, well. */ -const unsigned char * +/* Our caller bp_loc_is_permanent uses plain memcmp expecting byte ranges of + the instructions. We provide the extended range as described for + ia64_memory_insert_breakpoint simulating a placed breakpoint there - memcmp + will return true iff there was already a breakpoint (and so we returned the + original memory). We just take care of preserving the `break' instruction + 21-bit (or 62-bit) parameter as the memcmp match would fail otherwise. */ + +static const gdb_byte * ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) { - static unsigned char breakpoint[] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - *lenptr = sizeof (breakpoint); -#if 0 - *pcptr &= ~0x0f; -#endif - return breakpoint; + CORE_ADDR addr = *pcptr; + static gdb_byte bundle[BUNDLE_LEN]; + int slotnum = (int) (*pcptr & 0x0f) / SLOT_MULTIPLIER; + long long instr_fetched; + int val; + int template; + struct cleanup *cleanup; + + if (slotnum > 2) + error (_("Can't insert breakpoint for slot numbers greater than 2.")); + + addr &= ~0x0f; + + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle to match bp_loc_is_permanent. */ + cleanup = make_show_memory_breakpoints_cleanup (0); + val = target_read_memory (addr, bundle, BUNDLE_LEN); + do_cleanups (cleanup); + + /* It may be currently unreachable breakpoint which is never permanent. */ + if (val != 0) + return NULL; + + /* Check for L type instruction in 2nd slot, if present then + bump up the slot number to the 3rd slot */ + template = extract_bit_field (bundle, 0, 5); + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + /* We need to keep the possible `break' instruction parameter value intact. + Opcode with cleared all the bits (except the parameter value) is `break'. + For L+X slot pair we are at the X slot (3) so we should not touch the + L slot - the upper 41 bits of the parameter. */ + instr_fetched = slotN_contents (bundle, slotnum); + instr_fetched &= 0x1003ffffc0; + replace_slotN_contents (bundle, instr_fetched, slotnum); + + *lenptr = BUNDLE_LEN - 2; + + /* SLOTNUM is possibly already locally modified - use caller's *PCPTR. */ + return bundle + (*pcptr & 0x0f); } static CORE_ADDR --- gdb/monitor.c 9 Nov 2008 11:27:17 -0000 1.82 +++ gdb/monitor.c 11 Nov 2008 12:57:12 -0000 @@ -2026,7 +2026,6 @@ monitor_insert_breakpoint (struct bp_tar { CORE_ADDR addr = bp_tgt->placed_address; int i; - const unsigned char *bp; int bplen; monitor_debug ("MON inst bkpt %s\n", paddr (addr)); @@ -2037,7 +2036,7 @@ monitor_insert_breakpoint (struct bp_tar addr = gdbarch_addr_bits_remove (current_gdbarch, addr); /* Determine appropriate breakpoint size for this address. */ - bp = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &bplen); + gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &bplen); bp_tgt->placed_address = addr; bp_tgt->placed_size = bplen; --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gdb/testsuite/gdb.base/breakpoint-shadow.c 11 Nov 2008 12:57:13 -0000 @@ -0,0 +1,27 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 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/>. */ + +int +main (void) +{ + volatile int i; + + i = 1; /* break-first */ + i = 2; /* break-second */ + + return 0; +} --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gdb/testsuite/gdb.base/breakpoint-shadow.exp 11 Nov 2008 12:57:13 -0000 @@ -0,0 +1,63 @@ +# Copyright 2008 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/>. + +set testfile breakpoint-shadow +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# We need to start the inferior to place the breakpoints in the memory at all. +if ![runto_main] { + untested start + return -1 +} + +# The default "auto" mode removes all the breakpoints when we stop (and not +# running the nonstop mode). We would not be able to test the shadow. +gdb_test "set breakpoint always-inserted on" +gdb_test "show breakpoint always-inserted" "Always inserted breakpoint mode is on." + +set match "\nDump of assembler code for function main:\r\n(.*)End of assembler dump.\r\n$gdb_prompt $" + +set test "disassembly without breakpoints" +gdb_test_multiple "disass main" $test { + -re $match { + set orig $expect_out(1,string) + pass $test + } +} + +gdb_test "b [gdb_get_line_number "break-first"]" "Breakpoint \[0-9\] at .*" "First breakpoint placed" +gdb_test "b [gdb_get_line_number "break-second"]" "Breakpoint \[0-9\] at .*" "Second breakpoint placed" + +set test "disassembly with breakpoints" +gdb_test_multiple "disass main" $test { + -re $match { + set got $expect_out(1,string) + if [string equal -nocase $orig $got] { + pass $test + } else { + fail $test + } + } +} --- gdb/testsuite/gdb.base/start.exp 1 Jan 2008 22:53:19 -0000 1.5 +++ gdb/testsuite/gdb.base/start.exp 11 Nov 2008 12:57:13 -0000 @@ -35,6 +35,9 @@ gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} +# This is a testcase specifically for the `start' GDB command. For regular +# stop-in-main goal in the testcases please use `runto_main' instead. + # For C programs, "start" should stop in main(). if { [gdb_start_cmd] < 0 } { untested start @@ -44,4 +47,3 @@ if { [gdb_start_cmd] < 0 } { gdb_test "" \ "main \\(\\) at .*start.c.*" \ "start" - ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-11 20:20 ` Jan Kratochvil @ 2008-11-13 14:27 ` Joel Brobecker 2008-11-21 1:11 ` Jan Kratochvil 0 siblings, 1 reply; 13+ messages in thread From: Joel Brobecker @ 2008-11-13 14:27 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches > According to ISO C90 6.5.7 such a static array is (was) initialized to zeroes. Ah - I actually looked at the draft document I have, but I cannot seem to be able to navigate this document just yet, so I didn't find anything that confirmed this. From outside, it did look like the logic was broken, which is why I pointed this out. As you said, it was already broken before, so thanks for fixing it. > 2008-11-11 Jan Kratochvil <jan.kratochvil@redhat.com> > > Fix automatic restoration of breakpoints memory for ia64. > * ia64-tdep.c: New #if check on BREAKPOINT_MAX vs. BUNDLE_LEN. > (ia64_memory_insert_breakpoint): New comment part for SHADOW_CONTENTS > content. Remova variable instr. New variable cleanup. Force ^^^^^^ Typo: Remove > automatic breakpoints restoration. PLACED_SIZE and SHADOW_LEN are now > set larger, to BUNDLE_LEN - 2. Variable `bundle' type update. > (ia64_memory_remove_breakpoint): Rename variables bundle to bundle_mem > and instr to instr_saved. New variables bundle_saved and > instr_breakpoint. Comment new reasons why we need to disable automatic > restoration of breakpoints. Assert PLACED_SIZE and SHADOW_LEN. New > check of the original memory content. > (ia64_breakpoint_from_pc): Implement the emulation of permanent > breakpoints compatible with current bp_loc_is_permanent. > (template_encoding_table): Make it `const'. > * breakpoint.c (bp_loc_is_permanent): Support unsupported software > breakpoints. New variables `cleanup' and `retval' to protect > target_read_memory by make_show_memory_breakpoints_cleanup. For the future, I think that the second sentence is unnecessarily precise, so you can save yourself a little bit. But that's OK too. > * monitor.c (monitor_insert_breakpoint): Remove unused variable `bp'. This one should really have been a separate change. It also qualifies as obvious, so you could have checked it in immediately. > +/* Our caller bp_loc_is_permanent uses plain memcmp expecting byte ranges of > + the instructions. We provide the extended range as described for > + ia64_memory_insert_breakpoint simulating a placed breakpoint there - memcmp > + will return true iff there was already a breakpoint (and so we returned the > + original memory). We just take care of preserving the `break' instruction > + 21-bit (or 62-bit) parameter as the memcmp match would fail otherwise. */ I don't think it's a good idea to refer to the caller in the description of a routine. We might add more in the future... What you could say is that this function implements the semantics of the breakpoint_from_pc gdbarch method, and then proceed to explain the way you did why this function is tricky to implement on ia64. > + /* It may be currently unreachable breakpoint which is never permanent. */ > + if (val != 0) > + return NULL; I am not sure I understand the relationship between the fact that the memory is unreachable (do we know when this might happen?) and the conclusion that you are reaching. I tend to have simplistic views of the real situation, so this may be a little too simple to be acurate, but I would have just said that we need to be able to read the original memory location to produce the breakpoint sequence. > + /* We need to keep the possible `break' instruction parameter value intact. > + Opcode with cleared all the bits (except the parameter value) is `break'. It took me a long while to understand this, and it's probably because it's getting for me. But could it also be due to pure English. IIUC, I propose instead (in my own broken English ;-): A break instruction has its all its opcode bits cleared except for the parameter value. > + For L+X slot pair we are at the X slot (3) so we should not touch the > + L slot - the upper 41 bits of the parameter. */ Not being extremely familiar with the ia64 chip, I think I'll trust you with how the above translates into the code below: > + instr_fetched = slotN_contents (bundle, slotnum); > + instr_fetched &= 0x1003ffffc0; > + replace_slotN_contents (bundle, instr_fetched, slotnum); > +# This is a testcase specifically for the `start' GDB command. For regular > +# stop-in-main goal in the testcases please use `runto_main' instead. ^^^^^^^^^^^^ Can you just change the wording to "consider using"? It's softer. There might be some cases in the future where gdb_start_cmd might be more useful than using runto_main. Overall, the patch looks good is and is pre-approved once the observations above are addressed. Thanks, -- Joel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-13 14:27 ` Joel Brobecker @ 2008-11-21 1:11 ` Jan Kratochvil 2008-11-22 18:35 ` Joel Brobecker 2008-11-22 19:08 ` Eli Zaretskii 0 siblings, 2 replies; 13+ messages in thread From: Jan Kratochvil @ 2008-11-21 1:11 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 1753 bytes --] On Thu, 13 Nov 2008 06:31:00 +0100, Joel Brobecker wrote: > > + /* It may be currently unreachable breakpoint which is never permanent. */ > > + if (val != 0) > > + return NULL; > > I am not sure I understand the relationship between the fact that > the memory is unreachable (do we know when this might happen?) Originally I called there error() in the case of failed target_read_memory() as being done in score_breakpoint_from_pc(). But it broke the testsuite for: FAIL: gdb.cp/cp-relocate.exp: break *'int func<1>(int)' FAIL: gdb.cp/cp-relocate.exp: break *'int func<2>(int)' One can reproduce it more easily by simple `b *0': echo 'int main (void) { return 0; }' >mainx.c; gcc -o mainx mainx.c -Wall -ggdb2; ./gdb -nx -ex start -ex 'b *0' ./mainx > I would have just said that we need to be able to read the original memory > location to produce the breakpoint sequence. It currently depends on `set breakpoint always-inserted'. In the default mode it broke the testsuite. Found `return NULL' as a minimal regression-free solution. > > + For L+X slot pair we are at the X slot (3) so we should not touch the > > + L slot - the upper 41 bits of the parameter. */ > > Not being extremely familiar with the ia64 chip, I think I'll trust you > with how the above translates into the code below: There exist these templates (volume 3, rev 2.2, page 284/986): MII MII MLX --- MMI MMI MFI MMF MIB MBB --- BBB MMB --- MFB --- In the MLX template case slot 1 contains the opcode + 21 data bits and slot 2 contains 41 data bits (slot 2 is used whole as a data field). Updated my '(3)' (meaning 3rd slot). Intel uses naming `slot {0,1,2}' while GDB had there naming `{2nd,3rd} slot'. Unified it to `slot {0,1,2}'. Thanks, Jan [-- Attachment #2: ia64-align3.patch --] [-- Type: text/plain, Size: 18574 bytes --] gdb/ 2008-11-20 Jan Kratochvil <jan.kratochvil@redhat.com> Fix automatic restoration of breakpoints memory for ia64. * ia64-tdep.c: New #if check on BREAKPOINT_MAX vs. BUNDLE_LEN. (ia64_memory_insert_breakpoint): New comment part for SHADOW_CONTENTS content. Remove variable instr. New variable cleanup. Force automatic breakpoints restoration. PLACED_SIZE and SHADOW_LEN are now set larger, to BUNDLE_LEN - 2. Variable `bundle' type update. (ia64_memory_remove_breakpoint): Rename variables bundle to bundle_mem and instr to instr_saved. New variables bundle_saved and instr_breakpoint. Comment new reasons why we need to disable automatic restoration of breakpoints. Assert PLACED_SIZE and SHADOW_LEN. New check of the original memory content. (ia64_breakpoint_from_pc): Implement the emulation of permanent breakpoints compatible with current bp_loc_is_permanent. (template_encoding_table): Make it `const'. * breakpoint.c (bp_loc_is_permanent): Support unsupported software breakpoints. New variables `cleanup' and `retval'. * monitor.c (monitor_insert_breakpoint): Remove unused variable `bp'. gdb/doc/ 2008-11-20 Jan Kratochvil <jan.kratochvil@redhat.com> * gdbint.texinfo (Target Conditionals): Extend the gdbarch_breakpoint_from_pc description. gdb/testsuite/ 2008-11-20 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.base/breakpoint-shadow.exp, gdb.base/breakpoint-shadow.c: New. * gdb.base/start.exp: New comment about an alternative - `runto_main'. --- gdb/breakpoint.c 16 Nov 2008 18:05:26 -0000 1.361 +++ gdb/breakpoint.c 20 Nov 2008 14:37:15 -0000 @@ -5018,19 +5018,32 @@ bp_loc_is_permanent (struct bp_location CORE_ADDR addr; const gdb_byte *brk; gdb_byte *target_mem; + struct cleanup *cleanup; + int retval = 0; gdb_assert (loc != NULL); addr = loc->address; brk = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &len); + /* Software breakpoints unsupported? */ + if (brk == NULL) + return 0; + target_mem = alloca (len); + /* Enable the automatic memory restoration from breakpoints while + we read the memory. Otherwise we could say about our temporary + breakpoints they are permanent. */ + cleanup = make_show_memory_breakpoints_cleanup (0); + if (target_read_memory (loc->address, target_mem, len) == 0 && memcmp (target_mem, brk, len) == 0) - return 1; + retval = 1; - return 0; + do_cleanups (cleanup); + + return retval; } --- gdb/ia64-tdep.c 13 Nov 2008 05:05:07 -0000 1.185 +++ gdb/ia64-tdep.c 20 Nov 2008 14:37:19 -0000 @@ -110,6 +110,12 @@ typedef enum instruction_type #define BUNDLE_LEN 16 +/* See the saved memory layout comment for ia64_memory_insert_breakpoint. */ + +#if BREAKPOINT_MAX < BUNDLE_LEN - 2 +# error "BREAKPOINT_MAX < BUNDLE_LEN - 2" +#endif + static gdbarch_init_ftype ia64_gdbarch_init; static gdbarch_register_name_ftype ia64_register_name; @@ -442,7 +448,7 @@ replace_slotN_contents (char *bundle, lo replace_bit_field (bundle, instr, 5+41*slotnum, 41); } -static enum instruction_type template_encoding_table[32][3] = +static const enum instruction_type template_encoding_table[32][3] = { { M, I, I }, /* 00 */ { M, I, I }, /* 01 */ @@ -545,7 +551,45 @@ fetch_instruction (CORE_ADDR addr, instr simulators. So I changed the pattern slightly to do "break.i 0x080001" instead. But that didn't work either (I later found out that this pattern was used by the simulator that I was using.) So I ended up - using the pattern seen below. */ + using the pattern seen below. + + SHADOW_CONTENTS has byte-based addressing (PLACED_ADDRESS and SHADOW_LEN) + while we need bit-based addressing as the instructions length is 41 bits and + we must not modify/corrupt the adjacent slots in the same bundle. + Fortunately we may store larger memory incl. the adjacent bits with the + original memory content (not the possibly already stored breakpoints there). + We need to be careful in ia64_memory_remove_breakpoint to always restore + only the specific bits of this instruction ignoring any adjacent stored + bits. + + We use the original addressing with the low nibble in the range <0..2> which + gets incorrectly interpreted by generic non-ia64 breakpoint_restore_shadows + as the direct byte offset of SHADOW_CONTENTS. We store whole BUNDLE_LEN + bytes just without these two possibly skipped bytes to not to exceed to the + next bundle. + + If we would like to store the whole bundle to SHADOW_CONTENTS we would have + to store already the base address (`address & ~0x0f') into PLACED_ADDRESS. + In such case there is no other place where to store + SLOTNUM (`adress & 0x0f', value in the range <0..2>). We need to know + SLOTNUM in ia64_memory_remove_breakpoint. + + ia64 16-byte bundle layout: + | 5 bits | slot 0 with 41 bits | slot 1 with 41 bits | slot 2 with 41 bits | + + The current addressing used by the code below: + original PC placed_address placed_size required covered + == bp_tgt->shadow_len reqd \subset covered + 0xABCDE0 0xABCDE0 0xE <0x0...0x5> <0x0..0xD> + 0xABCDE1 0xABCDE1 0xE <0x5...0xA> <0x1..0xE> + 0xABCDE2 0xABCDE2 0xE <0xA...0xF> <0x2..0xF> + + `objdump -d' and some other tools show a bit unjustified offsets: + original PC byte where starts the instruction objdump offset + 0xABCDE0 0xABCDE0 0xABCDE0 + 0xABCDE1 0xABCDE5 0xABCDE6 + 0xABCDE2 0xABCDEA 0xABCDEC + */ #define IA64_BREAKPOINT 0x00003333300LL @@ -554,34 +598,43 @@ ia64_memory_insert_breakpoint (struct gd struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; - char bundle[BUNDLE_LEN]; + gdb_byte bundle[BUNDLE_LEN]; int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; int val; int template; + struct cleanup *cleanup; if (slotnum > 2) error (_("Can't insert breakpoint for slot numbers greater than 2.")); addr &= ~0x0f; + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle. Otherwise, we could store into + SHADOW_CONTENTS an already stored breakpoint at the same location. + In practice it is already being prevented by the DUPLICATE field and + update_global_location_list. */ + cleanup = make_show_memory_breakpoints_cleanup (0); val = target_read_memory (addr, bundle, BUNDLE_LEN); - /* Check for L type instruction in 2nd slot, if present then - bump up the slot number to the 3rd slot */ + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ template = extract_bit_field (bundle, 0, 5); - if (slotnum == 1 && template_encoding_table[template][1] == L) - { - slotnum = 2; - } + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + /* Slot number 2 may skip at most 2 bytes at the beginning. */ + bp_tgt->placed_size = bp_tgt->shadow_len = BUNDLE_LEN - 2; + + /* Store the whole bundle, except for the initial skipped bytes by the slot + number interpreted as bytes offset in PLACED_ADDRESS. */ + memcpy (bp_tgt->shadow_contents, bundle + slotnum, bp_tgt->shadow_len); - instr = slotN_contents (bundle, slotnum); - memcpy (bp_tgt->shadow_contents, &instr, sizeof (instr)); - bp_tgt->placed_size = bp_tgt->shadow_len = sizeof (instr); replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum); if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + target_write_memory (addr + slotnum, bundle + slotnum, bp_tgt->shadow_len); + do_cleanups (cleanup); return val; } @@ -590,9 +643,9 @@ ia64_memory_remove_breakpoint (struct gd struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; - char bundle[BUNDLE_LEN]; + gdb_byte bundle_mem[BUNDLE_LEN], bundle_saved[BUNDLE_LEN]; int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; + long long instr_breakpoint, instr_saved; int val; int template; struct cleanup *cleanup; @@ -601,40 +654,92 @@ ia64_memory_remove_breakpoint (struct gd /* Disable the automatic memory restoration from breakpoints while we read our instruction bundle. Otherwise, the general restoration - mechanism kicks in and ends up corrupting our bundle, because it - is not aware of the concept of instruction bundles. */ + mechanism kicks in and we would possibly remove parts of the adjacent + placed breakpoints. It is due to our SHADOW_CONTENTS overlapping the real + breakpoint instruction bits region. */ cleanup = make_show_memory_breakpoints_cleanup (1); - val = target_read_memory (addr, bundle, BUNDLE_LEN); - - /* Check for L type instruction in 2nd slot, if present then - bump up the slot number to the 3rd slot */ - template = extract_bit_field (bundle, 0, 5); - if (slotnum == 1 && template_encoding_table[template][1] == L) - { - slotnum = 2; - } + val = target_read_memory (addr, bundle_mem, BUNDLE_LEN); - memcpy (&instr, bp_tgt->shadow_contents, sizeof instr); - replace_slotN_contents (bundle, instr, slotnum); + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ + template = extract_bit_field (bundle_mem, 0, 5); + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + gdb_assert (bp_tgt->placed_size == BUNDLE_LEN - 2); + gdb_assert (bp_tgt->placed_size == bp_tgt->shadow_len); + + instr_breakpoint = slotN_contents (bundle_mem, slotnum); + if (instr_breakpoint != IA64_BREAKPOINT) + warning (_("Breakpoint removal cannot find the placed breakpoint at %s"), + paddr_nz (bp_tgt->placed_address)); + + /* Extract the original saved instruction from SLOTNUM normalizing its + bit-shift for INSTR_SAVED. */ + memcpy (bundle_saved, bundle_mem, BUNDLE_LEN); + memcpy (bundle_saved + slotnum, bp_tgt->shadow_contents, bp_tgt->shadow_len); + instr_saved = slotN_contents (bundle_saved, slotnum); + + /* In BUNDLE_MEM be careful to modify only the bits belonging to SLOTNUM and + never any other possibly also stored in SHADOW_CONTENTS. */ + replace_slotN_contents (bundle_mem, instr_saved, slotnum); if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + target_write_memory (addr, bundle_mem, BUNDLE_LEN); do_cleanups (cleanup); return val; } -/* We don't really want to use this, but remote.c needs to call it in order - to figure out if Z-packets are supported or not. Oh, well. */ -const unsigned char * +/* As gdbarch_breakpoint_from_pc ranges have byte granularity and ia64 + instruction slots ranges are bit-granular (41 bits) we have to provide an + extended range as described for ia64_memory_insert_breakpoint. We also take + care of preserving the `break' instruction 21-bit (or 62-bit) parameter to + make a match for permanent breakpoints. */ + +static const gdb_byte * ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) { - static unsigned char breakpoint[] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - *lenptr = sizeof (breakpoint); -#if 0 - *pcptr &= ~0x0f; -#endif - return breakpoint; + CORE_ADDR addr = *pcptr; + static gdb_byte bundle[BUNDLE_LEN]; + int slotnum = (int) (*pcptr & 0x0f) / SLOT_MULTIPLIER; + long long instr_fetched; + int val; + int template; + struct cleanup *cleanup; + + if (slotnum > 2) + error (_("Can't insert breakpoint for slot numbers greater than 2.")); + + addr &= ~0x0f; + + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle to match bp_loc_is_permanent. */ + cleanup = make_show_memory_breakpoints_cleanup (0); + val = target_read_memory (addr, bundle, BUNDLE_LEN); + do_cleanups (cleanup); + + /* It may be currently unreachable breakpoint which is never permanent, it + may happen for `b *0' and `set breakpoint always-inserted off'. */ + if (val != 0) + return NULL; + + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ + template = extract_bit_field (bundle, 0, 5); + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + /* A break instruction has its all its opcode bits cleared except for + the parameter value. For L+X slot pair we are at the X slot (slot 2) so + we should not touch the L slot - the upper 41 bits of the parameter. */ + instr_fetched = slotN_contents (bundle, slotnum); + instr_fetched &= 0x1003ffffc0; + replace_slotN_contents (bundle, instr_fetched, slotnum); + + *lenptr = BUNDLE_LEN - 2; + + /* SLOTNUM is possibly already locally modified - use caller's *PCPTR. */ + return bundle + (*pcptr & 0x0f); } static CORE_ADDR --- gdb/doc/gdbint.texinfo 27 Oct 2008 11:37:40 -0000 1.292 +++ gdb/doc/gdbint.texinfo 20 Nov 2008 14:37:36 -0000 @@ -3430,16 +3430,23 @@ favor of @code{gdbarch_breakpoint_from_p @findex gdbarch_breakpoint_from_pc @anchor{gdbarch_breakpoint_from_pc} Use the program counter to determine the contents and size of a breakpoint instruction. It returns a pointer to -a string of bytes that encode a breakpoint instruction, stores the +a static string of bytes that encode a breakpoint instruction, stores the length of the string to @code{*@var{lenptr}}, and adjusts the program counter (if necessary) to point to the actual memory location where the -breakpoint should be inserted. +breakpoint should be inserted. May return @code{NULL} to indicate that +software breakpoints are not supported. Although it is common to use a trap instruction for a breakpoint, it's not required; for instance, the bit pattern could be an invalid instruction. The breakpoint must be no longer than the shortest instruction of the architecture. +Provided breakpoint bytes can be also used by @code{bp_loc_is_permanent} to +detect permanent breakpoints. @code{gdbarch_breakpoint_from_pc} should return +an unchanged memory copy if it was called for a location with permanent +breakpoint as some architectures use breakpoint instructions containing +arbitrary parameter value. + Replaces all the other @var{BREAKPOINT} macros. @item int gdbarch_memory_insert_breakpoint (@var{gdbarch}, @var{bp_tgt}) --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gdb/testsuite/gdb.base/breakpoint-shadow.c 20 Nov 2008 14:37:40 -0000 @@ -0,0 +1,27 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 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/>. */ + +int +main (void) +{ + volatile int i; + + i = 1; /* break-first */ + i = 2; /* break-second */ + + return 0; +} --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gdb/testsuite/gdb.base/breakpoint-shadow.exp 20 Nov 2008 14:37:40 -0000 @@ -0,0 +1,63 @@ +# Copyright 2008 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/>. + +set testfile breakpoint-shadow +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# We need to start the inferior to place the breakpoints in the memory at all. +if ![runto_main] { + untested start + return -1 +} + +# The default "auto" mode removes all the breakpoints when we stop (and not +# running the nonstop mode). We would not be able to test the shadow. +gdb_test "set breakpoint always-inserted on" +gdb_test "show breakpoint always-inserted" "Always inserted breakpoint mode is on." + +set match "\nDump of assembler code for function main:\r\n(.*)End of assembler dump.\r\n$gdb_prompt $" + +set test "disassembly without breakpoints" +gdb_test_multiple "disass main" $test { + -re $match { + set orig $expect_out(1,string) + pass $test + } +} + +gdb_test "b [gdb_get_line_number "break-first"]" "Breakpoint \[0-9\] at .*" "First breakpoint placed" +gdb_test "b [gdb_get_line_number "break-second"]" "Breakpoint \[0-9\] at .*" "Second breakpoint placed" + +set test "disassembly with breakpoints" +gdb_test_multiple "disass main" $test { + -re $match { + set got $expect_out(1,string) + if [string equal -nocase $orig $got] { + pass $test + } else { + fail $test + } + } +} --- gdb/testsuite/gdb.base/start.exp 1 Jan 2008 22:53:19 -0000 1.5 +++ gdb/testsuite/gdb.base/start.exp 20 Nov 2008 14:37:40 -0000 @@ -35,6 +35,9 @@ gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} +# This is a testcase specifically for the `start' GDB command. For regular +# stop-in-main goal in the testcases consider using `runto_main' instead. + # For C programs, "start" should stop in main(). if { [gdb_start_cmd] < 0 } { untested start @@ -44,4 +47,3 @@ if { [gdb_start_cmd] < 0 } { gdb_test "" \ "main \\(\\) at .*start.c.*" \ "start" - ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-21 1:11 ` Jan Kratochvil @ 2008-11-22 18:35 ` Joel Brobecker 2008-11-22 19:08 ` Eli Zaretskii 1 sibling, 0 replies; 13+ messages in thread From: Joel Brobecker @ 2008-11-22 18:35 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches > gdb/doc/ > 2008-11-20 Jan Kratochvil <jan.kratochvil@redhat.com> > > * gdbint.texinfo (Target Conditionals): Extend the > gdbarch_breakpoint_from_pc description. This part needs to be reviewed by Eli. > One can reproduce it more easily by simple `b *0': > echo 'int main (void) { return 0; }' >mainx.c; gcc -o mainx mainx.c -Wall -ggdb2; ./gdb -nx -ex start -ex 'b *0' ./mainx Ah, yes - if you place a breakpoint at an invalid address (whether it was invalid right from the start as in your case, or if it became invalid later on)... > > I would have just said that we need to be able to read the original memory > > location to produce the breakpoint sequence. > > It currently depends on `set breakpoint always-inserted'. In the > default mode it broke the testsuite. Found `return NULL' as a minimal > regression-free solution. Right. I wasn't questioning the code, I just wasn't sure about the comment. > + /* It may be currently unreachable breakpoint which is never permanent, it > + may happen for `b *0' and `set breakpoint always-inserted off'. */ Maybe just an English suggestion, and a suggestion to make your comment more general: /* The memory might be unreachable. This can happen, for instance, when the user inserts a breakpoint at an invalid address. */ You'll notice that I removed the reference to permanent breakpoints, because I still don't understand why it's relevant. I suggest you checkin your patch with the comment as I suggested (once the doco part is approved by Eli), and then we can discuss together just that one comment (reviewing the whole patch at each iteration is a little time-consuming). Thanks, -- Joel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-21 1:11 ` Jan Kratochvil 2008-11-22 18:35 ` Joel Brobecker @ 2008-11-22 19:08 ` Eli Zaretskii 2008-11-24 2:25 ` Joel Brobecker 1 sibling, 1 reply; 13+ messages in thread From: Eli Zaretskii @ 2008-11-22 19:08 UTC (permalink / raw) To: Jan Kratochvil; +Cc: brobecker, gdb-patches > Date: Thu, 20 Nov 2008 15:49:36 +0100 > From: Jan Kratochvil <jan.kratochvil@redhat.com> > Cc: gdb-patches@sourceware.org > > gdb/doc/ > 2008-11-20 Jan Kratochvil <jan.kratochvil@redhat.com> > > * gdbint.texinfo (Target Conditionals): Extend the > gdbarch_breakpoint_from_pc description. This part is approved, thanks. However, I'm slightly worried by these parts in your code: > + instr_breakpoint = slotN_contents (bundle_mem, slotnum); > + if (instr_breakpoint != IA64_BREAKPOINT) > + warning (_("Breakpoint removal cannot find the placed breakpoint at %s"), > + paddr_nz (bp_tgt->placed_address)); Can this happen as part of normal GDB behavior? If not, we should make this internal_error, I think. If indeed this is a warning, we should tell users what to do with such a warning, either as part of the message or at least in the manual. > + if (slotnum > 2) > + error (_("Can't insert breakpoint for slot numbers greater than 2.")); Similarly here: assuming slot numbers are not something exposed to the user, I'd be bewildered if presented with such a message. If this is an internal GDB error (a.k.a. bug), let's treat it like one. (Yes, I do realize that there's already a similar call to `error' elsewhere in the existing GDB code. My comments apply to that place as well.) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-22 19:08 ` Eli Zaretskii @ 2008-11-24 2:25 ` Joel Brobecker 2008-11-24 7:09 ` Jan Kratochvil 0 siblings, 1 reply; 13+ messages in thread From: Joel Brobecker @ 2008-11-24 2:25 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Jan Kratochvil, gdb-patches > > + instr_breakpoint = slotN_contents (bundle_mem, slotnum); > > + if (instr_breakpoint != IA64_BREAKPOINT) > > + warning (_("Breakpoint removal cannot find the placed breakpoint at %s"), > > + paddr_nz (bp_tgt->placed_address)); > > Can this happen as part of normal GDB behavior? If not, we should > make this internal_error, I think. If indeed this is a warning, we > should tell users what to do with such a warning, either as part of > the message or at least in the manual. Maybe we can imagine some far-fetched scenario where the user is in non-stop mode, meaning that the breakpoints are always inserted, and that the user somehow overwrites the breakpoint instruction manually before switching back to all-stop (is that even possible?). In that case, that would be a valid warning. Regardless of that, I thought that the warning was a judicious choice because the debugger might be able to recover from this situation. Whether or not there was a breakpoint there, it can still restore the instruction at that address and hopefully continue working normally. Changing the warning into an internal_error would cause the debugger to abruptly abort the current operation (after which the user might choose to end the debugging session). I thought that attempting to recover would bring more benefit in this case. I would agree that some extra documentation explaining this warning might be useful. That being said, I'm not opposed to changing the warning into an internal_error, if you still think it's better. > > + if (slotnum > 2) > > + error (_("Can't insert breakpoint for slot numbers greater than 2.")); > > Similarly here: assuming slot numbers are not something exposed to the > user, I'd be bewildered if presented with such a message. If this is > an internal GDB error (a.k.a. bug), let's treat it like one. In this case, the invalid address can occur as a result of bad user input: (top-gdb) b *0x4000000000054c73 Breakpoint 4 at 0x4000000000054c73: file gdb.c, line 28. (top-gdb) c Continuing. Can't insert breakpoint for slot numbers greater than 2. So this is not necessarily an internal error. I wish GDB would catch the invalid address a little earlier, though. -- Joel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-24 2:25 ` Joel Brobecker @ 2008-11-24 7:09 ` Jan Kratochvil 2008-11-25 17:49 ` Joel Brobecker 0 siblings, 1 reply; 13+ messages in thread From: Jan Kratochvil @ 2008-11-24 7:09 UTC (permalink / raw) To: Joel Brobecker; +Cc: Eli Zaretskii, gdb-patches [-- Attachment #1: Type: text/plain, Size: 6113 bytes --] On Sat, 22 Nov 2008 12:30:04 +0100, Eli Zaretskii wrote: > > gdb/doc/ > > This part is approved, thanks. OK, thanks. On Sat, 22 Nov 2008 19:15:25 +0100, Joel Brobecker wrote: > > > + instr_breakpoint = slotN_contents (bundle_mem, slotnum); > > > + if (instr_breakpoint != IA64_BREAKPOINT) > > > + warning (_("Breakpoint removal cannot find the placed breakpoint at %s"), > > > + paddr_nz (bp_tgt->placed_address)); > > > > Can this happen as part of normal GDB behavior? If not, we should > > make this internal_error, I think. If indeed this is a warning, we > > should tell users what to do with such a warning, either as part of > > the message or at least in the manual. [...] > I would agree that some extra documentation explaining this warning > might be useful. That being said, I'm not opposed to changing the > warning into an internal_error, if you still think it's better. As the remote target memory may change arbitrarily across time I do not find there internal error appropriate. Still I rather found another defect compared to mem-break.c in the ia64 breakpoints code. It is another problem unrelated to the original intention of this ia64 patch. target_write_memory result was not checked and thus failed write to readonly memory still made ia64_memory_insert_breakpoint to succeed. The write fails in the testcases for VDSO memory range which is not writable on ia64: kernel-xen-2.6.18-92.el5.ia64 a000000000000000-a000000000020000 r-xp 00000000 00:00 0 [vdso] ptrace(PTRACE_PEEKTEXT, 30592, 0xa000000000000000, NULL) = 282584257676671 ptrace(PTRACE_PEEKTEXT, 30592, 0xa000000000000008, NULL) = 0 ptrace(PTRACE_POKEDATA, 30592, 0xa000000000000000, 0x100006666601f) = -1 EIO (Input/output error) ptrace(PTRACE_POKETEXT, 30592, 0xa000000000000000, 0x100006666601f) = -1 EIO (Input/output error) But on x86_64 (using PTRACE_POKE* error checking mem-break.c) it is writable: kernel-2.6.25.10-86.fc9.x86_64 7ffff7ffd000-7ffff7fff000 r-xp 7ffff7ffd000 00:00 0 [vdso] ptrace(PTRACE_PEEKTEXT, 2761, 0x7ffff7ffd7a0, [0x8bfffffd41058b48]) = 0 ptrace(PTRACE_POKEDATA, 2761, 0x7ffff7ffd7a0, 0x8bfffffd41058bcc) = 0 ptrace(PTRACE_PEEKTEXT, 2761, 0x7ffff7ffd7a0, [0x8bfffffd41058bcc]) = 0 The attached patch changes on ia64 the breakpoints to readonly memory to fail: (gdb) b *0xa000000000000000 Breakpoint 2 at 0xa000000000000000 Warning: Cannot insert breakpoint 2. Error accessing memory address 0xa000000000000000: Input/output error. (gdb) info break Num Type Disp Enb Address What 2 breakpoint keep y 0xa000000000000000 (gdb) delete 2 (gdb) Unaware how to invoke the ia64_memory_remove_breakpoint error of (instr_breakpoint != IA64_BREAKPOINT) but by patching GDB code one can get: (gdb) b *0xa000000000000000 Breakpoint 2 at 0xa000000000000000 (gdb) info break Num Type Disp Enb Address What 2 breakpoint keep y 0xa000000000000000 (gdb) delete 2 warning: Error removing breakpoint 2 (gdb) info break No breakpoints or watchpoints. For the ia64-specific code: > > > + instr_breakpoint = slotN_contents (bundle_mem, slotnum); > > > + if (instr_breakpoint != IA64_BREAKPOINT) > > > + warning (_("Breakpoint removal cannot find the placed breakpoint at %s"), > > > + paddr_nz (bp_tgt->placed_address)); -> + instr_breakpoint = slotN_contents (bundle_mem, slotnum); + if (instr_breakpoint != IA64_BREAKPOINT) + return -1; I am open to a possibility to also give a warning() there besides the current failure (-1) return. Requesting another approval due to this change although the patch covers now more ia64 parts than it was not intended for. Thanks for pinpointing this another ia64-tdep.c bug, Jan ia64 testsuite changes (no regression) with this patch: -FAIL: gdb.base/advance.exp: advance line number +PASS: gdb.base/advance.exp: advance line number -FAIL: gdb.base/advance.exp: advance func +PASS: gdb.base/advance.exp: advance func -FAIL: gdb.base/advance.exp: advance function not called by current frame +PASS: gdb.base/advance.exp: advance function not called by current frame -FAIL: gdb.base/advance.exp: continue to call to func3 in main (the program is no longer running) +PASS: gdb.base/advance.exp: continue to call to func3 in main -FAIL: gdb.base/advance.exp: advance with no argument +PASS: gdb.base/advance.exp: advance with no argument -FAIL: gdb.base/sigaltstack.exp: finish from catch LEAF +FAIL: gdb.base/sigaltstack.exp: finish from catch LEAF (could not set breakpoint) -FAIL: gdb.base/sigaltstack.exp: finish to throw INNER +FAIL: gdb.base/sigaltstack.exp: finish to throw INNER (could not set breakpoint) -FAIL: gdb.base/sigaltstack.exp: finish to catch INNER +FAIL: gdb.base/sigaltstack.exp: finish to catch INNER (could not set breakpoint) -FAIL: gdb.base/sigaltstack.exp: finish from catch INNER +FAIL: gdb.base/sigaltstack.exp: finish from catch INNER (could not set breakpoint) -FAIL: gdb.base/sigaltstack.exp: finish to OUTER +FAIL: gdb.base/sigaltstack.exp: finish to OUTER (could not set breakpoint) -FAIL: gdb.base/sigaltstack.exp: finish to catch MAIN +FAIL: gdb.base/sigaltstack.exp: finish to catch MAIN (could not set breakpoint) -FAIL: gdb.base/sigaltstack.exp: finish to MAIN +FAIL: gdb.base/sigaltstack.exp: finish to MAIN (could not set breakpoint) -FAIL: gdb.base/sigstep.exp: finish from handleri; leave handler (hit breakpoint again) -FAIL: gdb.base/sigstep.exp: finish from handleri; leave signal trampoline +FAIL: gdb.base/sigstep.exp: finish from handleri; leave handler (could not set breakpoint) +Running ../.././gdb/testsuite/gdb.base/breakpoint-shadow.exp ... +PASS: gdb.base/breakpoint-shadow.exp: set breakpoint always-inserted on +PASS: gdb.base/breakpoint-shadow.exp: show breakpoint always-inserted +PASS: gdb.base/breakpoint-shadow.exp: disassembly without breakpoints +PASS: gdb.base/breakpoint-shadow.exp: First breakpoint placed +PASS: gdb.base/breakpoint-shadow.exp: Second breakpoint placed +PASS: gdb.base/breakpoint-shadow.exp: disassembly with breakpoints [-- Attachment #2: ia64-align5.patch --] [-- Type: text/plain, Size: 18625 bytes --] gdb/ 2008-11-23 Jan Kratochvil <jan.kratochvil@redhat.com> Fix automatic restoration of breakpoints memory for ia64. * ia64-tdep.c: New #if check on BREAKPOINT_MAX vs. BUNDLE_LEN. (ia64_memory_insert_breakpoint): New comment part for SHADOW_CONTENTS content. Remove variable instr. New variable cleanup. Force automatic breakpoints restoration. PLACED_SIZE and SHADOW_LEN are now set larger, to BUNDLE_LEN - 2. Variable `bundle' type update. Return error if even just final target_write_memory has failed. (ia64_memory_remove_breakpoint): Rename variables bundle to bundle_mem and instr to instr_saved. New variables bundle_saved and instr_breakpoint. Comment new reasons why we need to disable automatic restoration of breakpoints. Assert PLACED_SIZE and SHADOW_LEN. New check of the original memory content. Return error if even just final target_write_memory has failed. (ia64_breakpoint_from_pc): Implement the emulation of permanent breakpoints compatible with current bp_loc_is_permanent. (template_encoding_table): Make it `const'. * breakpoint.c (bp_loc_is_permanent): Support unsupported software breakpoints. New variables `cleanup' and `retval'. * monitor.c (monitor_insert_breakpoint): Remove unused variable `bp'. gdb/doc/ 2008-11-23 Jan Kratochvil <jan.kratochvil@redhat.com> * gdbint.texinfo (Target Conditionals): Extend the gdbarch_breakpoint_from_pc description. gdb/testsuite/ 2008-11-23 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.base/breakpoint-shadow.exp, gdb.base/breakpoint-shadow.c: New. * gdb.base/start.exp: New comment about an alternative - `runto_main'. --- ./gdb/breakpoint.c 22 Nov 2008 04:41:45 -0000 1.362 +++ ./gdb/breakpoint.c 22 Nov 2008 17:36:51 -0000 @@ -5010,19 +5010,32 @@ bp_loc_is_permanent (struct bp_location CORE_ADDR addr; const gdb_byte *brk; gdb_byte *target_mem; + struct cleanup *cleanup; + int retval = 0; gdb_assert (loc != NULL); addr = loc->address; brk = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &len); + /* Software breakpoints unsupported? */ + if (brk == NULL) + return 0; + target_mem = alloca (len); + /* Enable the automatic memory restoration from breakpoints while + we read the memory. Otherwise we could say about our temporary + breakpoints they are permanent. */ + cleanup = make_show_memory_breakpoints_cleanup (0); + if (target_read_memory (loc->address, target_mem, len) == 0 && memcmp (target_mem, brk, len) == 0) - return 1; + retval = 1; - return 0; + do_cleanups (cleanup); + + return retval; } --- ./gdb/ia64-tdep.c 13 Nov 2008 05:05:07 -0000 1.185 +++ ./gdb/ia64-tdep.c 22 Nov 2008 17:36:51 -0000 @@ -110,6 +110,12 @@ typedef enum instruction_type #define BUNDLE_LEN 16 +/* See the saved memory layout comment for ia64_memory_insert_breakpoint. */ + +#if BREAKPOINT_MAX < BUNDLE_LEN - 2 +# error "BREAKPOINT_MAX < BUNDLE_LEN - 2" +#endif + static gdbarch_init_ftype ia64_gdbarch_init; static gdbarch_register_name_ftype ia64_register_name; @@ -442,7 +448,7 @@ replace_slotN_contents (char *bundle, lo replace_bit_field (bundle, instr, 5+41*slotnum, 41); } -static enum instruction_type template_encoding_table[32][3] = +static const enum instruction_type template_encoding_table[32][3] = { { M, I, I }, /* 00 */ { M, I, I }, /* 01 */ @@ -545,7 +551,45 @@ fetch_instruction (CORE_ADDR addr, instr simulators. So I changed the pattern slightly to do "break.i 0x080001" instead. But that didn't work either (I later found out that this pattern was used by the simulator that I was using.) So I ended up - using the pattern seen below. */ + using the pattern seen below. + + SHADOW_CONTENTS has byte-based addressing (PLACED_ADDRESS and SHADOW_LEN) + while we need bit-based addressing as the instructions length is 41 bits and + we must not modify/corrupt the adjacent slots in the same bundle. + Fortunately we may store larger memory incl. the adjacent bits with the + original memory content (not the possibly already stored breakpoints there). + We need to be careful in ia64_memory_remove_breakpoint to always restore + only the specific bits of this instruction ignoring any adjacent stored + bits. + + We use the original addressing with the low nibble in the range <0..2> which + gets incorrectly interpreted by generic non-ia64 breakpoint_restore_shadows + as the direct byte offset of SHADOW_CONTENTS. We store whole BUNDLE_LEN + bytes just without these two possibly skipped bytes to not to exceed to the + next bundle. + + If we would like to store the whole bundle to SHADOW_CONTENTS we would have + to store already the base address (`address & ~0x0f') into PLACED_ADDRESS. + In such case there is no other place where to store + SLOTNUM (`adress & 0x0f', value in the range <0..2>). We need to know + SLOTNUM in ia64_memory_remove_breakpoint. + + ia64 16-byte bundle layout: + | 5 bits | slot 0 with 41 bits | slot 1 with 41 bits | slot 2 with 41 bits | + + The current addressing used by the code below: + original PC placed_address placed_size required covered + == bp_tgt->shadow_len reqd \subset covered + 0xABCDE0 0xABCDE0 0xE <0x0...0x5> <0x0..0xD> + 0xABCDE1 0xABCDE1 0xE <0x5...0xA> <0x1..0xE> + 0xABCDE2 0xABCDE2 0xE <0xA...0xF> <0x2..0xF> + + `objdump -d' and some other tools show a bit unjustified offsets: + original PC byte where starts the instruction objdump offset + 0xABCDE0 0xABCDE0 0xABCDE0 + 0xABCDE1 0xABCDE5 0xABCDE6 + 0xABCDE2 0xABCDEA 0xABCDEC + */ #define IA64_BREAKPOINT 0x00003333300LL @@ -554,34 +598,44 @@ ia64_memory_insert_breakpoint (struct gd struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; - char bundle[BUNDLE_LEN]; + gdb_byte bundle[BUNDLE_LEN]; int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; int val; int template; + struct cleanup *cleanup; if (slotnum > 2) error (_("Can't insert breakpoint for slot numbers greater than 2.")); addr &= ~0x0f; + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle. Otherwise, we could store into + SHADOW_CONTENTS an already stored breakpoint at the same location. + In practice it is already being prevented by the DUPLICATE field and + update_global_location_list. */ + cleanup = make_show_memory_breakpoints_cleanup (0); val = target_read_memory (addr, bundle, BUNDLE_LEN); - /* Check for L type instruction in 2nd slot, if present then - bump up the slot number to the 3rd slot */ + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ template = extract_bit_field (bundle, 0, 5); - if (slotnum == 1 && template_encoding_table[template][1] == L) - { - slotnum = 2; - } + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + /* Slot number 2 may skip at most 2 bytes at the beginning. */ + bp_tgt->placed_size = bp_tgt->shadow_len = BUNDLE_LEN - 2; + + /* Store the whole bundle, except for the initial skipped bytes by the slot + number interpreted as bytes offset in PLACED_ADDRESS. */ + memcpy (bp_tgt->shadow_contents, bundle + slotnum, bp_tgt->shadow_len); - instr = slotN_contents (bundle, slotnum); - memcpy (bp_tgt->shadow_contents, &instr, sizeof (instr)); - bp_tgt->placed_size = bp_tgt->shadow_len = sizeof (instr); replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum); if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + val = target_write_memory (addr + slotnum, bundle + slotnum, + bp_tgt->shadow_len); + do_cleanups (cleanup); return val; } @@ -590,9 +644,9 @@ ia64_memory_remove_breakpoint (struct gd struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; - char bundle[BUNDLE_LEN]; + gdb_byte bundle_mem[BUNDLE_LEN], bundle_saved[BUNDLE_LEN]; int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; + long long instr_breakpoint, instr_saved; int val; int template; struct cleanup *cleanup; @@ -601,40 +655,91 @@ ia64_memory_remove_breakpoint (struct gd /* Disable the automatic memory restoration from breakpoints while we read our instruction bundle. Otherwise, the general restoration - mechanism kicks in and ends up corrupting our bundle, because it - is not aware of the concept of instruction bundles. */ + mechanism kicks in and we would possibly remove parts of the adjacent + placed breakpoints. It is due to our SHADOW_CONTENTS overlapping the real + breakpoint instruction bits region. */ cleanup = make_show_memory_breakpoints_cleanup (1); - val = target_read_memory (addr, bundle, BUNDLE_LEN); + val = target_read_memory (addr, bundle_mem, BUNDLE_LEN); - /* Check for L type instruction in 2nd slot, if present then - bump up the slot number to the 3rd slot */ - template = extract_bit_field (bundle, 0, 5); - if (slotnum == 1 && template_encoding_table[template][1] == L) - { - slotnum = 2; - } + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ + template = extract_bit_field (bundle_mem, 0, 5); + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + gdb_assert (bp_tgt->placed_size == BUNDLE_LEN - 2); + gdb_assert (bp_tgt->placed_size == bp_tgt->shadow_len); - memcpy (&instr, bp_tgt->shadow_contents, sizeof instr); - replace_slotN_contents (bundle, instr, slotnum); + instr_breakpoint = slotN_contents (bundle_mem, slotnum); + if (instr_breakpoint != IA64_BREAKPOINT) + return -1; + + /* Extract the original saved instruction from SLOTNUM normalizing its + bit-shift for INSTR_SAVED. */ + memcpy (bundle_saved, bundle_mem, BUNDLE_LEN); + memcpy (bundle_saved + slotnum, bp_tgt->shadow_contents, bp_tgt->shadow_len); + instr_saved = slotN_contents (bundle_saved, slotnum); + + /* In BUNDLE_MEM be careful to modify only the bits belonging to SLOTNUM and + never any other possibly also stored in SHADOW_CONTENTS. */ + replace_slotN_contents (bundle_mem, instr_saved, slotnum); if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + val = target_write_memory (addr, bundle_mem, BUNDLE_LEN); do_cleanups (cleanup); return val; } -/* We don't really want to use this, but remote.c needs to call it in order - to figure out if Z-packets are supported or not. Oh, well. */ -const unsigned char * +/* As gdbarch_breakpoint_from_pc ranges have byte granularity and ia64 + instruction slots ranges are bit-granular (41 bits) we have to provide an + extended range as described for ia64_memory_insert_breakpoint. We also take + care of preserving the `break' instruction 21-bit (or 62-bit) parameter to + make a match for permanent breakpoints. */ + +static const gdb_byte * ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) { - static unsigned char breakpoint[] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - *lenptr = sizeof (breakpoint); -#if 0 - *pcptr &= ~0x0f; -#endif - return breakpoint; + CORE_ADDR addr = *pcptr; + static gdb_byte bundle[BUNDLE_LEN]; + int slotnum = (int) (*pcptr & 0x0f) / SLOT_MULTIPLIER; + long long instr_fetched; + int val; + int template; + struct cleanup *cleanup; + + if (slotnum > 2) + error (_("Can't insert breakpoint for slot numbers greater than 2.")); + + addr &= ~0x0f; + + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle to match bp_loc_is_permanent. */ + cleanup = make_show_memory_breakpoints_cleanup (0); + val = target_read_memory (addr, bundle, BUNDLE_LEN); + do_cleanups (cleanup); + + /* The memory might be unreachable. This can happen, for instance, + when the user inserts a breakpoint at an invalid address. */ + if (val != 0) + return NULL; + + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ + template = extract_bit_field (bundle, 0, 5); + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + /* A break instruction has its all its opcode bits cleared except for + the parameter value. For L+X slot pair we are at the X slot (slot 2) so + we should not touch the L slot - the upper 41 bits of the parameter. */ + instr_fetched = slotN_contents (bundle, slotnum); + instr_fetched &= 0x1003ffffc0; + replace_slotN_contents (bundle, instr_fetched, slotnum); + + *lenptr = BUNDLE_LEN - 2; + + /* SLOTNUM is possibly already locally modified - use caller's *PCPTR. */ + return bundle + (*pcptr & 0x0f); } static CORE_ADDR --- ./gdb/doc/gdbint.texinfo 27 Oct 2008 11:37:40 -0000 1.292 +++ ./gdb/doc/gdbint.texinfo 22 Nov 2008 17:36:51 -0000 @@ -3430,16 +3430,23 @@ favor of @code{gdbarch_breakpoint_from_p @findex gdbarch_breakpoint_from_pc @anchor{gdbarch_breakpoint_from_pc} Use the program counter to determine the contents and size of a breakpoint instruction. It returns a pointer to -a string of bytes that encode a breakpoint instruction, stores the +a static string of bytes that encode a breakpoint instruction, stores the length of the string to @code{*@var{lenptr}}, and adjusts the program counter (if necessary) to point to the actual memory location where the -breakpoint should be inserted. +breakpoint should be inserted. May return @code{NULL} to indicate that +software breakpoints are not supported. Although it is common to use a trap instruction for a breakpoint, it's not required; for instance, the bit pattern could be an invalid instruction. The breakpoint must be no longer than the shortest instruction of the architecture. +Provided breakpoint bytes can be also used by @code{bp_loc_is_permanent} to +detect permanent breakpoints. @code{gdbarch_breakpoint_from_pc} should return +an unchanged memory copy if it was called for a location with permanent +breakpoint as some architectures use breakpoint instructions containing +arbitrary parameter value. + Replaces all the other @var{BREAKPOINT} macros. @item int gdbarch_memory_insert_breakpoint (@var{gdbarch}, @var{bp_tgt}) --- .//dev/null 1 Jan 1970 00:00:00 -0000 +++ ./gdb/testsuite/gdb.base/breakpoint-shadow.c 22 Nov 2008 17:36:51 -0000 @@ -0,0 +1,27 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 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/>. */ + +int +main (void) +{ + volatile int i; + + i = 1; /* break-first */ + i = 2; /* break-second */ + + return 0; +} --- .//dev/null 1 Jan 1970 00:00:00 -0000 +++ ./gdb/testsuite/gdb.base/breakpoint-shadow.exp 22 Nov 2008 17:36:51 -0000 @@ -0,0 +1,63 @@ +# Copyright 2008 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/>. + +set testfile breakpoint-shadow +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# We need to start the inferior to place the breakpoints in the memory at all. +if ![runto_main] { + untested start + return -1 +} + +# The default "auto" mode removes all the breakpoints when we stop (and not +# running the nonstop mode). We would not be able to test the shadow. +gdb_test "set breakpoint always-inserted on" +gdb_test "show breakpoint always-inserted" "Always inserted breakpoint mode is on." + +set match "\nDump of assembler code for function main:\r\n(.*)End of assembler dump.\r\n$gdb_prompt $" + +set test "disassembly without breakpoints" +gdb_test_multiple "disass main" $test { + -re $match { + set orig $expect_out(1,string) + pass $test + } +} + +gdb_test "b [gdb_get_line_number "break-first"]" "Breakpoint \[0-9\] at .*" "First breakpoint placed" +gdb_test "b [gdb_get_line_number "break-second"]" "Breakpoint \[0-9\] at .*" "Second breakpoint placed" + +set test "disassembly with breakpoints" +gdb_test_multiple "disass main" $test { + -re $match { + set got $expect_out(1,string) + if [string equal -nocase $orig $got] { + pass $test + } else { + fail $test + } + } +} --- ./gdb/testsuite/gdb.base/start.exp 1 Jan 2008 22:53:19 -0000 1.5 +++ ./gdb/testsuite/gdb.base/start.exp 22 Nov 2008 17:36:51 -0000 @@ -35,6 +35,9 @@ gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} +# This is a testcase specifically for the `start' GDB command. For regular +# stop-in-main goal in the testcases consider using `runto_main' instead. + # For C programs, "start" should stop in main(). if { [gdb_start_cmd] < 0 } { untested start @@ -44,4 +47,3 @@ if { [gdb_start_cmd] < 0 } { gdb_test "" \ "main \\(\\) at .*start.c.*" \ "start" - ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-24 7:09 ` Jan Kratochvil @ 2008-11-25 17:49 ` Joel Brobecker 2008-11-27 0:41 ` Jan Kratochvil 0 siblings, 1 reply; 13+ messages in thread From: Joel Brobecker @ 2008-11-25 17:49 UTC (permalink / raw) To: Jan Kratochvil; +Cc: Eli Zaretskii, gdb-patches > Still I rather found another defect compared to mem-break.c in the ia64 > breakpoints code. It is another problem unrelated to the original intention > of this ia64 patch. Jan, please don't take it personally, I really appreciate the way you are trying to make your patch better and better. But since this was unrelated, I really wished that you committed the first part as approved, and then sent a followup patch that dealt with that part on its own. With the approach you took, I had to fish out the previous version of the patch, and then compare the two patches to see exactly what changed. And since I've always found that a diff of diff is some kind of mental gymnastics, and the whole process is more work than just looking at the subsequent patch, I had to delay the review until I had 30min of quiet time. Anyway, back to the one important change: > - memcpy (&instr, bp_tgt->shadow_contents, sizeof instr); > - replace_slotN_contents (bundle, instr, slotnum); > + instr_breakpoint = slotN_contents (bundle_mem, slotnum); > + if (instr_breakpoint != IA64_BREAKPOINT) > + return -1; I think we need to give the user a way to understand the error message that returning -1 will cause. Otherwise, it's going to be hard for the user to have a clue of why the debugger failed to de-insert the breakpoint. I propose a warning saying something like this: cannot remove breakpoint at address %s, no break instruction at such address. Cheers, -- Joel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [patch] ia64: Fix breakpoints memory shadow 2008-11-25 17:49 ` Joel Brobecker @ 2008-11-27 0:41 ` Jan Kratochvil 0 siblings, 0 replies; 13+ messages in thread From: Jan Kratochvil @ 2008-11-27 0:41 UTC (permalink / raw) To: Joel Brobecker; +Cc: Eli Zaretskii, gdb-patches [-- Attachment #1: Type: text/plain, Size: 1996 bytes --] On Tue, 25 Nov 2008 07:12:35 +0100, Joel Brobecker wrote: > > Still I rather found another defect compared to mem-break.c in the ia64 > > breakpoints code. It is another problem unrelated to the original intention > > of this ia64 patch. > > Jan, please don't take it personally, I really appreciate the way > you are trying to make your patch better and better. But since > this was unrelated, I really wished that you committed the first part > as approved, and then sent a followup patch that dealt with that part > on its own. As I got also this mail before the commit On Sat, 22 Nov 2008 12:30:04 +0100, Eli Zaretskii wrote: > However, I'm slightly worried by these parts in your code: I considered it as a valid veto of your approval until Eli's concerns get resolved. I appreciate your time although I do not see I would make mistakes in the unwritten formal approval process I try to follow. > With the approach you took, I had to fish out the previous version of the > patch, and then compare the two patches to see exactly what changed. Using this VIM macro for reviewing "metadiffs": noremap <Esc>D :set hlsearch<cr>/^[+-][+-]\([^+-].*\\|\)$<cr> The committed patch has these changes against the last post here: ia64_memory_insert_breakpoint: make_show_memory_breakpoints_cleanup (0 -> 1); - A real Bug of my former patch (although it was not a regression). ia64_memory_insert_breakpoint: == IA64_BREAKPOINT => internal_error - New sanity check, unaware it would be possible to reach it as a user. > I propose a warning saying something like this: > > cannot remove breakpoint at address %s, no break instruction at such address. Therefore included this warning again: ia64_memory_remove_breakpoint: != IA64_BREAKPOINT => warning - Happens for: gdb.base/checkpoint.exp gdb.base/foll-fork.exp - IMO such sanity check is missing even in default_memory_remove_breakpoint and these warnings would be then present also on x86. Not checked, though. Thanks, Jan [-- Attachment #2: ia64-aligncvs.patch --] [-- Type: text/plain, Size: 19991 bytes --] gdb/ 2008-11-25 Jan Kratochvil <jan.kratochvil@redhat.com> Fix automatic restoration of breakpoints memory for ia64. * ia64-tdep.c: New #if check on BREAKPOINT_MAX vs. BUNDLE_LEN. (ia64_memory_insert_breakpoint): New comment part for SHADOW_CONTENTS content. Remove variable instr. New variable cleanup. Disable automatic breakpoints restoration. PLACED_SIZE and SHADOW_LEN are now set larger, to BUNDLE_LEN - 2. Variable `bundle' type update. Return error if even just final target_write_memory has failed. (ia64_memory_remove_breakpoint): Rename variables bundle to bundle_mem and instr to instr_saved. New variables bundle_saved and instr_breakpoint. Comment new reasons why we need to disable automatic restoration of breakpoints. Assert PLACED_SIZE and SHADOW_LEN. New check of the original memory content. Return error if even just final target_write_memory has failed. (ia64_breakpoint_from_pc): Implement the emulation of permanent breakpoints compatible with current bp_loc_is_permanent. (template_encoding_table): Make it `const'. * breakpoint.c (bp_loc_is_permanent): Support unsupported software breakpoints. New variables `cleanup' and `retval'. * monitor.c (monitor_insert_breakpoint): Remove unused variable `bp'. gdb/doc/ 2008-11-25 Jan Kratochvil <jan.kratochvil@redhat.com> * gdbint.texinfo (Target Conditionals): Extend the gdbarch_breakpoint_from_pc description. gdb/testsuite/ 2008-11-25 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.base/breakpoint-shadow.exp, gdb.base/breakpoint-shadow.c: New. * gdb.base/start.exp: New comment about an alternative - `runto_main'. =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.c,v retrieving revision 1.362 retrieving revision 1.363 diff -u -r1.362 -r1.363 --- src/gdb/breakpoint.c 2008/11/22 04:41:45 1.362 +++ src/gdb/breakpoint.c 2008/11/26 05:27:48 1.363 @@ -5010,19 +5010,32 @@ CORE_ADDR addr; const gdb_byte *brk; gdb_byte *target_mem; + struct cleanup *cleanup; + int retval = 0; gdb_assert (loc != NULL); addr = loc->address; brk = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &len); + /* Software breakpoints unsupported? */ + if (brk == NULL) + return 0; + target_mem = alloca (len); + /* Enable the automatic memory restoration from breakpoints while + we read the memory. Otherwise we could say about our temporary + breakpoints they are permanent. */ + cleanup = make_show_memory_breakpoints_cleanup (0); + if (target_read_memory (loc->address, target_mem, len) == 0 && memcmp (target_mem, brk, len) == 0) - return 1; + retval = 1; - return 0; + do_cleanups (cleanup); + + return retval; } =================================================================== RCS file: /cvs/src/src/gdb/ia64-tdep.c,v retrieving revision 1.185 retrieving revision 1.186 diff -u -r1.185 -r1.186 --- src/gdb/ia64-tdep.c 2008/11/13 05:05:07 1.185 +++ src/gdb/ia64-tdep.c 2008/11/26 05:27:48 1.186 @@ -110,6 +110,12 @@ #define BUNDLE_LEN 16 +/* See the saved memory layout comment for ia64_memory_insert_breakpoint. */ + +#if BREAKPOINT_MAX < BUNDLE_LEN - 2 +# error "BREAKPOINT_MAX < BUNDLE_LEN - 2" +#endif + static gdbarch_init_ftype ia64_gdbarch_init; static gdbarch_register_name_ftype ia64_register_name; @@ -442,7 +448,7 @@ replace_bit_field (bundle, instr, 5+41*slotnum, 41); } -static enum instruction_type template_encoding_table[32][3] = +static const enum instruction_type template_encoding_table[32][3] = { { M, I, I }, /* 00 */ { M, I, I }, /* 01 */ @@ -545,7 +551,45 @@ simulators. So I changed the pattern slightly to do "break.i 0x080001" instead. But that didn't work either (I later found out that this pattern was used by the simulator that I was using.) So I ended up - using the pattern seen below. */ + using the pattern seen below. + + SHADOW_CONTENTS has byte-based addressing (PLACED_ADDRESS and SHADOW_LEN) + while we need bit-based addressing as the instructions length is 41 bits and + we must not modify/corrupt the adjacent slots in the same bundle. + Fortunately we may store larger memory incl. the adjacent bits with the + original memory content (not the possibly already stored breakpoints there). + We need to be careful in ia64_memory_remove_breakpoint to always restore + only the specific bits of this instruction ignoring any adjacent stored + bits. + + We use the original addressing with the low nibble in the range <0..2> which + gets incorrectly interpreted by generic non-ia64 breakpoint_restore_shadows + as the direct byte offset of SHADOW_CONTENTS. We store whole BUNDLE_LEN + bytes just without these two possibly skipped bytes to not to exceed to the + next bundle. + + If we would like to store the whole bundle to SHADOW_CONTENTS we would have + to store already the base address (`address & ~0x0f') into PLACED_ADDRESS. + In such case there is no other place where to store + SLOTNUM (`adress & 0x0f', value in the range <0..2>). We need to know + SLOTNUM in ia64_memory_remove_breakpoint. + + ia64 16-byte bundle layout: + | 5 bits | slot 0 with 41 bits | slot 1 with 41 bits | slot 2 with 41 bits | + + The current addressing used by the code below: + original PC placed_address placed_size required covered + == bp_tgt->shadow_len reqd \subset covered + 0xABCDE0 0xABCDE0 0xE <0x0...0x5> <0x0..0xD> + 0xABCDE1 0xABCDE1 0xE <0x5...0xA> <0x1..0xE> + 0xABCDE2 0xABCDE2 0xE <0xA...0xF> <0x2..0xF> + + `objdump -d' and some other tools show a bit unjustified offsets: + original PC byte where starts the instruction objdump offset + 0xABCDE0 0xABCDE0 0xABCDE0 + 0xABCDE1 0xABCDE5 0xABCDE6 + 0xABCDE2 0xABCDEA 0xABCDEC + */ #define IA64_BREAKPOINT 0x00003333300LL @@ -554,34 +598,55 @@ struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; - char bundle[BUNDLE_LEN]; + gdb_byte bundle[BUNDLE_LEN]; int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; + long long instr_breakpoint; int val; int template; + struct cleanup *cleanup; if (slotnum > 2) error (_("Can't insert breakpoint for slot numbers greater than 2.")); addr &= ~0x0f; + /* Disable the automatic memory restoration from breakpoints while + we read our instruction bundle. Otherwise, the general restoration + mechanism kicks in and we would possibly remove parts of the adjacent + placed breakpoints. It is due to our SHADOW_CONTENTS overlapping the real + breakpoint instruction bits region. */ + cleanup = make_show_memory_breakpoints_cleanup (1); val = target_read_memory (addr, bundle, BUNDLE_LEN); - /* Check for L type instruction in 2nd slot, if present then - bump up the slot number to the 3rd slot */ + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ template = extract_bit_field (bundle, 0, 5); - if (slotnum == 1 && template_encoding_table[template][1] == L) - { - slotnum = 2; - } + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; - instr = slotN_contents (bundle, slotnum); - memcpy (bp_tgt->shadow_contents, &instr, sizeof (instr)); - bp_tgt->placed_size = bp_tgt->shadow_len = sizeof (instr); + /* Slot number 2 may skip at most 2 bytes at the beginning. */ + bp_tgt->placed_size = bp_tgt->shadow_len = BUNDLE_LEN - 2; + + /* Store the whole bundle, except for the initial skipped bytes by the slot + number interpreted as bytes offset in PLACED_ADDRESS. */ + memcpy (bp_tgt->shadow_contents, bundle + slotnum, bp_tgt->shadow_len); + + /* Breakpoints already present in the code will get deteacted and not get + reinserted by bp_loc_is_permanent. Multiple breakpoints at the same + location cannot induce the internal error as they are optimized into + a single instance by update_global_location_list. */ + instr_breakpoint = slotN_contents (bundle, slotnum); + if (instr_breakpoint == IA64_BREAKPOINT) + internal_error (__FILE__, __LINE__, + _("Address %s already contains a breakpoint."), + paddr_nz (bp_tgt->placed_address)); replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum); + if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + val = target_write_memory (addr + slotnum, bundle + slotnum, + bp_tgt->shadow_len); + do_cleanups (cleanup); return val; } @@ -590,9 +655,9 @@ struct bp_target_info *bp_tgt) { CORE_ADDR addr = bp_tgt->placed_address; - char bundle[BUNDLE_LEN]; + gdb_byte bundle_mem[BUNDLE_LEN], bundle_saved[BUNDLE_LEN]; int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; + long long instr_breakpoint, instr_saved; int val; int template; struct cleanup *cleanup; @@ -601,40 +666,96 @@ /* Disable the automatic memory restoration from breakpoints while we read our instruction bundle. Otherwise, the general restoration - mechanism kicks in and ends up corrupting our bundle, because it - is not aware of the concept of instruction bundles. */ + mechanism kicks in and we would possibly remove parts of the adjacent + placed breakpoints. It is due to our SHADOW_CONTENTS overlapping the real + breakpoint instruction bits region. */ cleanup = make_show_memory_breakpoints_cleanup (1); - val = target_read_memory (addr, bundle, BUNDLE_LEN); + val = target_read_memory (addr, bundle_mem, BUNDLE_LEN); - /* Check for L type instruction in 2nd slot, if present then - bump up the slot number to the 3rd slot */ - template = extract_bit_field (bundle, 0, 5); - if (slotnum == 1 && template_encoding_table[template][1] == L) - { - slotnum = 2; - } - - memcpy (&instr, bp_tgt->shadow_contents, sizeof instr); - replace_slotN_contents (bundle, instr, slotnum); + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ + template = extract_bit_field (bundle_mem, 0, 5); + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + gdb_assert (bp_tgt->placed_size == BUNDLE_LEN - 2); + gdb_assert (bp_tgt->placed_size == bp_tgt->shadow_len); + + instr_breakpoint = slotN_contents (bundle_mem, slotnum); + if (instr_breakpoint != IA64_BREAKPOINT) + { + warning (_("Cannot remove breakpoint at address %s, " + "no break instruction at such address."), + paddr_nz (bp_tgt->placed_address)); + return -1; + } + + /* Extract the original saved instruction from SLOTNUM normalizing its + bit-shift for INSTR_SAVED. */ + memcpy (bundle_saved, bundle_mem, BUNDLE_LEN); + memcpy (bundle_saved + slotnum, bp_tgt->shadow_contents, bp_tgt->shadow_len); + instr_saved = slotN_contents (bundle_saved, slotnum); + + /* In BUNDLE_MEM be careful to modify only the bits belonging to SLOTNUM and + never any other possibly also stored in SHADOW_CONTENTS. */ + replace_slotN_contents (bundle_mem, instr_saved, slotnum); if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + val = target_write_memory (addr, bundle_mem, BUNDLE_LEN); do_cleanups (cleanup); return val; } -/* We don't really want to use this, but remote.c needs to call it in order - to figure out if Z-packets are supported or not. Oh, well. */ -const unsigned char * +/* As gdbarch_breakpoint_from_pc ranges have byte granularity and ia64 + instruction slots ranges are bit-granular (41 bits) we have to provide an + extended range as described for ia64_memory_insert_breakpoint. We also take + care of preserving the `break' instruction 21-bit (or 62-bit) parameter to + make a match for permanent breakpoints. */ + +static const gdb_byte * ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) { - static unsigned char breakpoint[] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - *lenptr = sizeof (breakpoint); -#if 0 - *pcptr &= ~0x0f; -#endif - return breakpoint; + CORE_ADDR addr = *pcptr; + static gdb_byte bundle[BUNDLE_LEN]; + int slotnum = (int) (*pcptr & 0x0f) / SLOT_MULTIPLIER; + long long instr_fetched; + int val; + int template; + struct cleanup *cleanup; + + if (slotnum > 2) + error (_("Can't insert breakpoint for slot numbers greater than 2.")); + + addr &= ~0x0f; + + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle to match bp_loc_is_permanent. */ + cleanup = make_show_memory_breakpoints_cleanup (0); + val = target_read_memory (addr, bundle, BUNDLE_LEN); + do_cleanups (cleanup); + + /* The memory might be unreachable. This can happen, for instance, + when the user inserts a breakpoint at an invalid address. */ + if (val != 0) + return NULL; + + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ + template = extract_bit_field (bundle, 0, 5); + if (slotnum == 1 && template_encoding_table[template][slotnum] == L) + slotnum = 2; + + /* A break instruction has its all its opcode bits cleared except for + the parameter value. For L+X slot pair we are at the X slot (slot 2) so + we should not touch the L slot - the upper 41 bits of the parameter. */ + instr_fetched = slotN_contents (bundle, slotnum); + instr_fetched &= 0x1003ffffc0; + replace_slotN_contents (bundle, instr_fetched, slotnum); + + *lenptr = BUNDLE_LEN - 2; + + /* SLOTNUM is possibly already locally modified - use caller's *PCPTR. */ + return bundle + (*pcptr & 0x0f); } static CORE_ADDR =================================================================== RCS file: /cvs/src/src/gdb/doc/gdbint.texinfo,v retrieving revision 1.292 retrieving revision 1.293 diff -u -r1.292 -r1.293 --- src/gdb/doc/gdbint.texinfo 2008/10/27 11:37:40 1.292 +++ src/gdb/doc/gdbint.texinfo 2008/11/26 05:26:40 1.293 @@ -3430,16 +3430,23 @@ @findex gdbarch_breakpoint_from_pc @anchor{gdbarch_breakpoint_from_pc} Use the program counter to determine the contents and size of a breakpoint instruction. It returns a pointer to -a string of bytes that encode a breakpoint instruction, stores the +a static string of bytes that encode a breakpoint instruction, stores the length of the string to @code{*@var{lenptr}}, and adjusts the program counter (if necessary) to point to the actual memory location where the -breakpoint should be inserted. +breakpoint should be inserted. May return @code{NULL} to indicate that +software breakpoints are not supported. Although it is common to use a trap instruction for a breakpoint, it's not required; for instance, the bit pattern could be an invalid instruction. The breakpoint must be no longer than the shortest instruction of the architecture. +Provided breakpoint bytes can be also used by @code{bp_loc_is_permanent} to +detect permanent breakpoints. @code{gdbarch_breakpoint_from_pc} should return +an unchanged memory copy if it was called for a location with permanent +breakpoint as some architectures use breakpoint instructions containing +arbitrary parameter value. + Replaces all the other @var{BREAKPOINT} macros. @item int gdbarch_memory_insert_breakpoint (@var{gdbarch}, @var{bp_tgt}) /cvs/src/src/gdb/testsuite/gdb.base/breakpoint-shadow.c,v --> standard output revision 1.1 --- src/gdb/testsuite/gdb.base/breakpoint-shadow.c +++ src/gdb/testsuite/gdb.base/breakpoint-shadow.c 2008-11-26 05:29:49.128279000 +0000 @@ -0,0 +1,27 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 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/>. */ + +int +main (void) +{ + volatile int i; + + i = 1; /* break-first */ + i = 2; /* break-second */ + + return 0; +} /cvs/src/src/gdb/testsuite/gdb.base/breakpoint-shadow.exp,v --> standard output revision 1.1 --- src/gdb/testsuite/gdb.base/breakpoint-shadow.exp +++ src/gdb/testsuite/gdb.base/breakpoint-shadow.exp 2008-11-26 05:29:49.855090000 +0000 @@ -0,0 +1,63 @@ +# Copyright 2008 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/>. + +set testfile breakpoint-shadow +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# We need to start the inferior to place the breakpoints in the memory at all. +if ![runto_main] { + untested start + return -1 +} + +# The default "auto" mode removes all the breakpoints when we stop (and not +# running the nonstop mode). We would not be able to test the shadow. +gdb_test "set breakpoint always-inserted on" +gdb_test "show breakpoint always-inserted" "Always inserted breakpoint mode is on." + +set match "\nDump of assembler code for function main:\r\n(.*)End of assembler dump.\r\n$gdb_prompt $" + +set test "disassembly without breakpoints" +gdb_test_multiple "disass main" $test { + -re $match { + set orig $expect_out(1,string) + pass $test + } +} + +gdb_test "b [gdb_get_line_number "break-first"]" "Breakpoint \[0-9\] at .*" "First breakpoint placed" +gdb_test "b [gdb_get_line_number "break-second"]" "Breakpoint \[0-9\] at .*" "Second breakpoint placed" + +set test "disassembly with breakpoints" +gdb_test_multiple "disass main" $test { + -re $match { + set got $expect_out(1,string) + if [string equal -nocase $orig $got] { + pass $test + } else { + fail $test + } + } +} =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/start.exp,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- src/gdb/testsuite/gdb.base/start.exp 2008/01/01 22:53:19 1.5 +++ src/gdb/testsuite/gdb.base/start.exp 2008/11/26 05:25:56 1.6 @@ -35,6 +35,9 @@ gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} +# This is a testcase specifically for the `start' GDB command. For regular +# stop-in-main goal in the testcases consider using `runto_main' instead. + # For C programs, "start" should stop in main(). if { [gdb_start_cmd] < 0 } { untested start @@ -44,4 +47,3 @@ gdb_test "" \ "main \\(\\) at .*start.c.*" \ "start" - ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2008-11-26 6:34 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-10-28 17:52 [patch] ia64: Fix breakpoints memory shadow Jan Kratochvil 2008-10-30 1:51 ` Joel Brobecker 2008-10-31 0:03 ` Jan Kratochvil 2008-11-01 18:54 ` Joel Brobecker 2008-11-11 20:20 ` Jan Kratochvil 2008-11-13 14:27 ` Joel Brobecker 2008-11-21 1:11 ` Jan Kratochvil 2008-11-22 18:35 ` Joel Brobecker 2008-11-22 19:08 ` Eli Zaretskii 2008-11-24 2:25 ` Joel Brobecker 2008-11-24 7:09 ` Jan Kratochvil 2008-11-25 17:49 ` Joel Brobecker 2008-11-27 0:41 ` Jan Kratochvil
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox