+2014-05-20 Pedro Alves <palves@redhat.com>
+
+ * NEWS: Mention that compare-sections now works with all targets.
+
+ * remote.c (PACKET_qCRC): New enum value.
+ (remote_verify_memory): Don't send qCRC if the target has no
+ execution. Use packet_support/packet_ok. If the target doesn't
+ support the qCRC packet, fallback to a deep memory copy.
+ (compare_sections_command): Say "target image" instead of "remote
+ executable".
+ (_initialize_remote): Add PACKET_qCRC to the list of config
+ packets that have no associated command. Extend comment.
+ * target.c (simple_verify_memory, default_verify_memory): New
+ function.
+ * target.h (struct target_ops) <to_verify_memory>: Default to
+ default_verify_memory.
+ (simple_verify_memory): New declaration.
+ * target-delegates.c: Regenerate.
+
2014-05-20 Markus Metzger <markus.t.metzger@intel.com>
* record-btrace.c (record_btrace_step_thread): Check for empty history.
* The "catch syscall" command now works on s390*-linux* targets.
+* The "compare-sections" command is no longer specific to target
+ remote. It now works with all targets.
+
* New remote packets
qXfer:btrace:read's annex
+2014-05-20 Pedro Alves <palves@redhat.com>
+
+ * gdb.texinfo (Memory) <compare-sections>: Generalize comments to
+ not be remote specific. Add cross reference to the qCRC packet.
+ (Separate Debug Files): Update cross reference to the qCRC packet.
+ (General Query Packets) <qCRC packet>: Add anchor.
+
2014-05-17 Doug Evans <xdje42@gmail.com>
Copy over changes from guile.texi.
address printed if several units were printed on the last line of output.
@cindex remote memory comparison
+@cindex target memory comparison
@cindex verify remote memory image
+@cindex verify target memory image
When you are debugging a program running on a remote target machine
-(@pxref{Remote Debugging}), you may wish to verify the program's image in the
-remote machine's memory against the executable file you downloaded to
-the target. The @code{compare-sections} command is provided for such
-situations.
+(@pxref{Remote Debugging}), you may wish to verify the program's image
+in the remote machine's memory against the executable file you
+downloaded to the target. Or, on any target, you may want to check
+whether the program has corrupted its own read-only sections. The
+@code{compare-sections} command is provided for such situations.
@table @code
@kindex compare-sections
@item compare-sections @r{[}@var{section-name}@r{|}@code{-r}@r{]}
Compare the data of a loadable section @var{section-name} in the
executable file of the program being debugged with the same section in
-the remote machine's memory, and report any mismatches. With no
+the target machine's memory, and report any mismatches. With no
arguments, compares all loadable sections. With an argument of
-@code{-r}, compares all loadable read-only sections. This command's
-availability depends on the target's support for the @code{"qCRC"}
-remote request.
+@code{-r}, compares all loadable read-only sections.
+
+Note: for remote targets, this command can be accelerated if the
+target supports computing the CRC checksum of a block of memory
+(@pxref{qCRC packet}).
@end table
@node Auto Display
CRC.
@emph{Note:} This is the same CRC polynomial as used in handling the
-@dfn{Remote Serial Protocol} @code{qCRC} packet (@pxref{Remote Protocol,
-, @value{GDBN} Remote Serial Protocol}). However in the
-case of the Remote Serial Protocol, the CRC is computed @emph{most}
-significant bit first, and the result is not inverted, so trailing
-zeros have no effect on the CRC value.
+@dfn{Remote Serial Protocol} @code{qCRC} packet (@pxref{qCRC packet}).
+However in the case of the Remote Serial Protocol, the CRC is computed
+@emph{most} significant bit first, and the result is not inverted, so
+trailing zeros have no effect on the CRC value.
To complete the description, we show below the code of the function
which produces the CRC used in @code{.gnu_debuglink}. Inverting the
@item qCRC:@var{addr},@var{length}
@cindex CRC of memory block, remote request
@cindex @samp{qCRC} packet
+@anchor{qCRC packet}
Compute the CRC checksum of a block of memory using CRC-32 defined in
IEEE 802.3. The CRC is computed byte at a time, taking the most
significant bit of each byte first. The initial pattern code
PACKET_qTStatus,
PACKET_QPassSignals,
PACKET_QProgramSignals,
+ PACKET_qCRC,
PACKET_qSearch_memory,
PACKET_vAttach,
PACKET_vRun,
unsigned long host_crc, target_crc;
char *tmp;
- /* Make sure the remote is pointing at the right process. */
- set_general_process ();
+ /* It doesn't make sense to use qCRC if the remote target is
+ connected but not running. */
+ if (target_has_execution && packet_support (PACKET_qCRC) != PACKET_DISABLE)
+ {
+ enum packet_result result;
- /* FIXME: assumes lma can fit into long. */
- xsnprintf (rs->buf, get_remote_packet_size (), "qCRC:%lx,%lx",
- (long) lma, (long) size);
- putpkt (rs->buf);
+ /* Make sure the remote is pointing at the right process. */
+ set_general_process ();
- /* Be clever; compute the host_crc before waiting for target
- reply. */
- host_crc = xcrc32 (data, size, 0xffffffff);
+ /* FIXME: assumes lma can fit into long. */
+ xsnprintf (rs->buf, get_remote_packet_size (), "qCRC:%lx,%lx",
+ (long) lma, (long) size);
+ putpkt (rs->buf);
- getpkt (&rs->buf, &rs->buf_size, 0);
- if (rs->buf[0] == 'E')
- return -1;
+ /* Be clever; compute the host_crc before waiting for target
+ reply. */
+ host_crc = xcrc32 (data, size, 0xffffffff);
+
+ getpkt (&rs->buf, &rs->buf_size, 0);
- if (rs->buf[0] != 'C')
- error (_("remote target does not support this operation"));
+ result = packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_qCRC]);
+ if (result == PACKET_ERROR)
+ return -1;
+ else if (result == PACKET_OK)
+ {
+ for (target_crc = 0, tmp = &rs->buf[1]; *tmp; tmp++)
+ target_crc = target_crc * 16 + fromhex (*tmp);
- for (target_crc = 0, tmp = &rs->buf[1]; *tmp; tmp++)
- target_crc = target_crc * 16 + fromhex (*tmp);
+ return (host_crc == target_crc);
+ }
+ }
- return (host_crc == target_crc);
+ return simple_verify_memory (ops, data, lma, size);
}
/* compare-sections command
do_cleanups (old_chain);
}
if (mismatched > 0)
- warning (_("One or more sections of the remote executable does not match\n\
+ warning (_("One or more sections of the target image does not match\n\
the loaded file\n"));
if (args && !matched)
printf_filtered (_("No loaded section named '%s'.\n"), args);
case PACKET_tracenz_feature:
case PACKET_DisconnectedTracing_feature:
case PACKET_augmented_libraries_svr4_read_feature:
- /* Additions to this list need to be well justified. */
+ case PACKET_qCRC:
+ /* Additions to this list need to be well justified:
+ pre-existing packets are OK; new packets are not. */
excepted = 1;
break;
default:
return self->to_verify_memory (self, arg1, arg2, arg3);
}
-static int
-tdefault_verify_memory (struct target_ops *self, const gdb_byte *arg1, CORE_ADDR arg2, ULONGEST arg3)
-{
- tcomplain ();
-}
-
static int
delegate_get_tib_address (struct target_ops *self, ptid_t arg1, CORE_ADDR *arg2)
{
ops->to_set_trace_buffer_size = tdefault_set_trace_buffer_size;
ops->to_set_trace_notes = tdefault_set_trace_notes;
ops->to_core_of_thread = tdefault_core_of_thread;
- ops->to_verify_memory = tdefault_verify_memory;
+ ops->to_verify_memory = default_verify_memory;
ops->to_get_tib_address = tdefault_get_tib_address;
ops->to_set_permissions = tdefault_set_permissions;
ops->to_static_tracepoint_marker_at = tdefault_static_tracepoint_marker_at;
ULONGEST pattern_len,
CORE_ADDR *found_addrp);
+static int default_verify_memory (struct target_ops *self,
+ const gdb_byte *data,
+ CORE_ADDR memaddr, ULONGEST size);
+
static void tcomplain (void) ATTRIBUTE_NORETURN;
static int return_zero (struct target_ops *);
return retval;
}
+int
+simple_verify_memory (struct target_ops *ops,
+ const gdb_byte *data, CORE_ADDR lma, ULONGEST size)
+{
+ LONGEST total_xfered = 0;
+
+ while (total_xfered < size)
+ {
+ ULONGEST xfered_len;
+ enum target_xfer_status status;
+ gdb_byte buf[1024];
+ ULONGEST howmuch = min (sizeof (buf), size - total_xfered);
+
+ status = target_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL,
+ buf, NULL, lma + total_xfered, howmuch,
+ &xfered_len);
+ if (status == TARGET_XFER_OK
+ && memcmp (data + total_xfered, buf, xfered_len) == 0)
+ {
+ total_xfered += xfered_len;
+ QUIT;
+ }
+ else
+ return 0;
+ }
+ return 1;
+}
+
+/* Default implementation of memory verification. */
+
+static int
+default_verify_memory (struct target_ops *self,
+ const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
+{
+ /* Start over from the top of the target stack. */
+ return simple_verify_memory (current_target.beneath,
+ data, memaddr, size);
+}
+
int
target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
{
encountered while reading memory. */
int (*to_verify_memory) (struct target_ops *, const gdb_byte *data,
CORE_ADDR memaddr, ULONGEST size)
- TARGET_DEFAULT_NORETURN (tcomplain ());
+ TARGET_DEFAULT_FUNC (default_verify_memory);
/* Return the address of the start of the Thread Information Block
a Windows OS specific feature. */
/* See to_get_tailcall_unwinder in struct target_ops. */
extern const struct frame_unwind *target_get_tailcall_unwinder (void);
+/* This implements basic memory verification, reading target memory
+ and performing the comparison here (as opposed to accelerated
+ verification making use of the qCRC packet, for example). */
+
+extern int simple_verify_memory (struct target_ops* ops,
+ const gdb_byte *data,
+ CORE_ADDR memaddr, ULONGEST size);
+
/* Verify that the memory in the [MEMADDR, MEMADDR+SIZE) range matches
the contents of [DATA,DATA+SIZE). Returns 1 if there's a match, 0
if there's a mismatch, and -1 if an error is encountered while
+2014-05-20 Pedro Alves <palves@redhat.com>
+
+ * gdb.base/compare-sections.c: New file.
+ * gdb.base/compare-sections.exp: New file.
+
2014-05-20 Pedro Alves <palves@redhat.com>
* gdb.base/break-idempotent.c: New file.
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011-2014 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int bss_variable = 0;
+int data_variable = 1;
+const int const_variable = 2;
+
+int
+main (void)
+{
+ return 0;
+}
--- /dev/null
+# Copyright 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test the compare-sections command.
+
+standard_testfile
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug}]} {
+ return -1
+}
+
+# Run the compare-sections command along with any options as specified
+# by OPTIONS, and check that no mismatch is found.
+proc compare_sections { {options ""} } {
+ global gdb_prompt
+
+ if {$options != ""} {
+ set command "compare-sections $options"
+ } else {
+ set command "compare-sections"
+ }
+ set test $command
+ gdb_test_multiple $command $test {
+ -re "MIS-MATCHED.*$gdb_prompt $" {
+ fail $test
+ }
+ -re "warning.*One or more sections.*does not match.*loaded file.*$gdb_prompt $" {
+ fail $test
+ }
+ -re "Section.*matched.*$gdb_prompt $" {
+ pass $test
+ }
+ }
+}
+
+gdb_file_cmd $binfile
+
+with_test_prefix "after file" {
+ # Before starting the target, we're just comparing the
+ # executable's sections against themselves... This should never
+ # find a mismatch.
+ compare_sections
+ compare_sections "-r"
+}
+
+# Load the file into the target.
+gdb_reload
+
+with_test_prefix "after reload" {
+ # We're presumabily still stopped at the entry point. All
+ # sections should match.
+ compare_sections
+ compare_sections "-r"
+}
+
+# Try comparing just one section. Assume there's a .text section,
+# which is a pretty safe bet.
+set command "compare-sections .text"
+set command_re [string_to_regexp $command]
+set test $command
+gdb_test_multiple $command $test {
+ -re "^$command_re\r\nSection .text, range $hex -- $hex. matched\.\r\n$gdb_prompt $" {
+ pass $test
+ }
+}
+
+# Now get past startup code.
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
+with_test_prefix "after run to main" {
+ # Assume all targets' startup code changes some loaded variable.
+ gdb_test "compare-sections" \
+ "MIS-MATCHED.*warning.*One or more sections.*does not match.*loaded file"
+
+ # Assume startup code doesn't change read-only sections.
+ compare_sections "-r"
+}
+
+# Now test that "compare-sections -r" works as expected. Look for an
+# address in a read-only section, patch it, and check that
+# "compare-sections -r" detects a mismatch.
+with_test_prefix "read-only" {
+ set ro_address 0
+ set has_ro_sections 0
+ set test "list read-only sections"
+ gdb_test_multiple "maint info sections READONLY" $test {
+ -re "($hex)->$hex at $hex. \[^\r\n\]* READONLY.*$gdb_prompt $" {
+ set ro_address $expect_out(1,string)
+ set has_ro_sections 1
+ pass $test
+ }
+ -re "$gdb_prompt $" {
+ pass $test
+ }
+ }
+
+ if {!$has_ro_sections} {
+ unsupported "no read-only sections"
+ return -1;
+ }
+
+ set orig -1
+
+ set test "get value of read-only section"
+ gdb_test_multiple "print /d *(unsigned char *) $ro_address" "$test" {
+ -re " = (\[0-9\]*).*$gdb_prompt $" {
+ set orig $expect_out(1,string)
+ pass "$test"
+ }
+ }
+
+ if {$orig == -1} {
+ untested "couldn't read address of read-only section"
+ return -1
+ }
+
+ # Come up with different value.
+ set patch [expr 255 - $orig]
+
+ # Write PATCH to memory.
+ set written -1
+ set test "corrupt read-only section"
+ gdb_test_multiple "print /d *(unsigned char *) $ro_address = $patch" "$test" {
+ -re " = (\[0-9\]*).*$gdb_prompt $" {
+ set written $expect_out(1,string)
+ pass "$test"
+ }
+ }
+
+ if { $written != $patch } {
+ unsupported "can't patch read-only section"
+ return -1
+ }
+
+ gdb_test "compare-sections -r" \
+ "MIS-MATCHED.*warning.*One or more sections.*does not match.*loaded file.*"
+}