Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Yao Qi <yao@codesourcery.com>
To: Tom Tromey <tromey@redhat.com>
Cc: Doug Evans <dje@google.com>, <gdb-patches@sourceware.org>
Subject: Re: [RFC] Don't allow setting register in non-innermost frame
Date: Wed, 29 Aug 2012 09:51:00 -0000	[thread overview]
Message-ID: <503DE604.5070904@codesourcery.com> (raw)
In-Reply-To: <87hartpodt.fsf@fleche.redhat.com>

On 08/24/2012 12:24 AM, Tom Tromey wrote:
> Doug> fwiw, I've been able to work around corrupt, or otherwise not
> Doug> completely useful, core files by setting registers in non-innermost
> Doug> frames.
> Doug> Granted, I knew what was happening underneath the covers, so to speak,
> Doug> and I could have done things differently, but I like this capability.
> 
> It does seem like a useful power user tool.
> I'm swayed by this argument.

OK, looks like I underestimate the power of it. :)

> 
> Doug> I*could*  accept a warning when changing a register in a non-innermost
> Doug> frame, fwiw.
> 
> That would be ok by me.

Anyway, this new patch is to emit warning if user modifies register on
non-innermost frame.  Regression tested on x86_64-linux native and
gdbserver.  OK to apply?

Note that this test case should be tuned for each target, because of
registers.  So far, this test is run effectively on x86 and x86_64.

-- 
Yao

gdb/testsuite:

2012-08-29  Yao Qi  <yao@codesourcery.com>

	* gdb.base/set-reg.exp: New.
	* gdb.base/set-reg.c: New.

gdb:

2012-08-29  Yao Qi  <yao@codesourcery.com>

	* valops.c (value_assign): Emit warning if get_next_frame returns
	non-NULL.
---
 gdb/testsuite/gdb.base/set-reg.c   |   40 +++++++++++++
 gdb/testsuite/gdb.base/set-reg.exp |  108 ++++++++++++++++++++++++++++++++++++
 gdb/valops.c                       |   12 ++++
 3 files changed, 160 insertions(+), 0 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/set-reg.c
 create mode 100644 gdb/testsuite/gdb.base/set-reg.exp

diff --git a/gdb/testsuite/gdb.base/set-reg.c b/gdb/testsuite/gdb.base/set-reg.c
new file mode 100644
index 0000000..7ce350d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-reg.c
@@ -0,0 +1,40 @@
+/* This test is part of GDB, the GNU debugger.
+
+   Copyright 2012 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
+inner (int x)
+{
+  return x + 2;
+}
+
+static short
+middle (int x)
+{
+  return 2 * inner (x);
+}
+
+short
+top (int x)
+{
+  return 2 * middle (x);
+}
+
+int
+main (int argc,  char **argv)
+{
+  return top (argc);
+}
diff --git a/gdb/testsuite/gdb.base/set-reg.exp b/gdb/testsuite/gdb.base/set-reg.exp
new file mode 100644
index 0000000..3eace34
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-reg.exp
@@ -0,0 +1,108 @@
+# Copyright 2012 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/>.
+
+standard_testfile
+set executable $testfile
+
+if { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug}] != "" } {
+    untested "Failed to compile"
+    return -1
+}
+
+# A value in register in previous frame.
+set reg_prev_frame_in_reg "unknown"
+# A value in memory in previous frame.
+set reg_prev_frame_in_memory "unknown"
+
+if [is_amd64_regs_target] {
+    set reg_prev_frame_in_reg "rax"
+    set reg_prev_frame_in_memory "rbp"
+} elseif [is_x86_like_target] {
+    set reg_prev_frame_in_reg "eax"
+    set reg_prev_frame_in_memory "ebp"
+} else {
+    # set reg_prev_frame_in_reg for other arch.
+
+}
+
+# Test setting register on innermost frame and non-innermost frame.
+
+proc test_set_reg_on_frame {} {with_test_prefix "on frame" {
+    global executable
+    global reg_prev_frame_in_reg
+    global reg_prev_frame_in_memory
+    global decimal
+    global hex
+    global expect_out
+    global gdb_prompt
+
+    clean_restart $executable
+
+    if ![runto_main] {
+	return -1
+    }
+
+    # Name of register is not set, skip the rest of test.
+    if { [string equal $reg_prev_frame_in_reg "unknown"] } {
+	return 1
+    }
+
+    gdb_test "break inner" "Breakpoint.*at.* file .*, line.*"
+    gdb_test "continue" "Continuing.\r\n\r\nBreakpoint.*inner.*at.*" \
+	"continue to inner"
+
+    gdb_test_sequence "bt" "bt before setting reg" {
+	"\[\r\n\]#0 .* inner \\(x=1\\) at "
+	"\[\r\n\]#1 .* middle \\(x=1\\) at "
+	"\[\r\n\]#2 .* top \\(x=1\\) at "
+	"\[\r\n\]#3 .* main \\(.*\\) at"
+    }
+
+    set reg_val ""
+    gdb_test_multiple "p/x \$${reg_prev_frame_in_reg}" "print register ${reg_prev_frame_in_reg}" {
+	-re ".*${decimal} = ($hex).*$gdb_prompt $" {
+	    set reg_val $expect_out(1,string)
+	}
+    }
+
+    gdb_test_no_output "set \$${reg_prev_frame_in_reg}=${reg_val}" \
+	"set register ${reg_prev_frame_in_reg} on inner frame"
+
+    # Stack is unchanged.
+    gdb_test_sequence "bt" "bt after setting reg" {
+	"\[\r\n\]#0 .* inner \\(x=1\\) at "
+	"\[\r\n\]#1 .* middle \\(x=1\\) at "
+	"\[\r\n\]#2 .* top \\(x=1\\) at "
+	"\[\r\n\]#3 .* main \\(.*\\) at"
+    }
+
+    gdb_test "up"
+    gdb_test "set \$${reg_prev_frame_in_reg}=${reg_val}" \
+	"Frame in which this value is assigned to is not innermost.*" \
+	"set register ${reg_prev_frame_in_reg} on non-inner frame"
+
+   gdb_test_sequence "bt" "bt after up" {
+	"\[\r\n\]#0 .* inner \\(x=1\\) at "
+	"\[\r\n\]#1 .* middle \\(x=1\\) at "
+	"\[\r\n\]#2 .* top \\(x=1\\) at "
+	"\[\r\n\]#3 .* main \\(.*\\) at"
+    }
+
+    gdb_test "set \$${reg_prev_frame_in_memory}=${reg_val}" \
+	"Frame in which this value is assigned to is not innermost.*" \
+	"set register ${reg_prev_frame_in_memory} on non-inner frame"
+}}
+
+test_set_reg_on_frame
diff --git a/gdb/valops.c b/gdb/valops.c
index 17696ee..cb84c87 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1241,6 +1241,18 @@ value_assign (struct value *toval, struct value *fromval)
      and then restore the new frame afterwards.  */
   old_frame = get_frame_id (deprecated_safe_get_selected_frame ());
 
+  /* TOVAL is a register, although VALUE_LVAL(TOVAL) may not be
+     lval_register.  */
+  if (VALUE_REGNUM (toval) >= 0)
+    {
+      /* Figure out which frame this is in currently.  */
+      struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (toval));
+
+      if (get_next_frame (frame) != NULL)
+	warning (_("Frame in which this value is assigned to is"
+		   " not innermost."));
+    }
+
   switch (VALUE_LVAL (toval))
     {
     case lval_internalvar:
-- 
1.7.7.6


  reply	other threads:[~2012-08-29  9:51 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-17  2:21 Yao Qi
2012-08-20 20:19 ` Doug Evans
2012-08-21  3:27   ` Yao Qi
2012-08-23 16:25   ` Tom Tromey
2012-08-29  9:51     ` Yao Qi [this message]
2012-09-04 22:37       ` dje
2012-09-07 10:01         ` Yao Qi
2012-09-07 10:11           ` Eli Zaretskii
2012-09-07 10:21             ` Yao Qi
2012-09-07 11:27               ` Eli Zaretskii
2012-09-07 13:14                 ` Yao Qi
2012-09-07 14:32                   ` Eli Zaretskii
2012-09-07 16:46     ` Jan Kratochvil
2012-09-09  2:31       ` Yao Qi
2012-09-10  2:02       ` Yao Qi
2012-09-10  7:47         ` Jan Kratochvil
2012-09-10 19:43           ` Jan Kratochvil
2012-09-11 17:12         ` Tom Tromey
2012-09-11 17:19           ` Jan Kratochvil
2012-09-11 17:23             ` Tom Tromey
2012-09-12  0:51           ` Yao Qi
2012-09-12 13:19             ` Jan Kratochvil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=503DE604.5070904@codesourcery.com \
    --to=yao@codesourcery.com \
    --cc=dje@google.com \
    --cc=gdb-patches@sourceware.org \
    --cc=tromey@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox