This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH V5 2/2] Add mpx-bnd-init-on-return set/show command for inferior calls.
- From: Walfred Tedeschi <walfred dot tedeschi at intel dot com>
- To: palves at redhat dot com, brobecker at adacore dot com
- Cc: gdb-patches at sourceware dot org, Walfred Tedeschi <walfred dot tedeschi at intel dot com>
- Date: Fri, 18 Mar 2016 15:16:17 +0100
- Subject: [PATCH V5 2/2] Add mpx-bnd-init-on-return set/show command for inferior calls.
- Authentication-results: sourceware.org; auth=none
When using the return command, execution of a function is aborted
and present values are returned from that point. That can cause
bound violations in the MPX context. To avoid such side-effects,
a new setting ("mpx-bnd-init-on-return") was added to control
the initialization of bound register when using the return command.
As default the value of "mpx-bnd-init-on-return" is set to 1. So
bound register are initialized when using the "return" command.
If set to True (the default), all bound registers are set to zero
when using the "return" command.
2016-03-02 Walfred Tedeschi <walfred.tedeschi@intel.com>
gdb/ChangeLog:
* i387-tdep.h (i387_reset_bnd0_reg): New function.
(mpx_bnd_init_on_return): Declare new external variable.
* i387-tdep.c (i387_reset_bnd0_reg): New function implementation.
* amd64-tdep.c (mpx_bnd_init_on_return): Declare new variable.
(amd64_return_value): Use mpx-bnd-init-on-return and .
(_initialize_amd64_tdep): Initialize mpx_bnd_init_on_return.
* i386-tdep.c (mpx_bnd_init_on_return): Declare new variable.
(i386_return_value): Use mpx-bnd-init-on-return.
(_initialize_i386_tdep): Initialize mpx_bnd_init_on_return.
(show_mpx_init_on_return): New function.
(_initialize_i386_tdepamd64_init_abi): Add new commands set/show
mpx-bnd-init-on-return.
* NEWS: Add entry for set/show mpx-bnd-init-on-return command.
gdb/doc/ChangeLog:
* gdb.texinfo (Intel Memory Protection Extensions): Add
documentation on using set/show mpx-bnd-init-on-return.
gdb/testsuite/ChangeLog:
* i386-mpx-call.c: New file.
* i386-mpx-call.exp: New file.
---
gdb/NEWS | 5 ++
gdb/amd64-tdep.c | 27 +++++++
gdb/doc/gdb.texinfo | 24 ++++++
gdb/i386-tdep.c | 40 +++++++++-
gdb/i387-tdep.c | 14 ++++
gdb/i387-tdep.h | 9 +++
gdb/testsuite/gdb.arch/i386-mpx-call.c | 126 +++++++++++++++++++++++++++++++
gdb/testsuite/gdb.arch/i386-mpx-call.exp | 92 ++++++++++++++++++++++
8 files changed, 336 insertions(+), 1 deletion(-)
create mode 100644 gdb/testsuite/gdb.arch/i386-mpx-call.c
create mode 100644 gdb/testsuite/gdb.arch/i386-mpx-call.exp
diff --git a/gdb/NEWS b/gdb/NEWS
index be15902..a123f7d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -27,6 +27,11 @@ skip -rfunction regular-expression
glob-style file names and regular expressions for function names.
Additionally, a file spec and a function spec may now be combined.
+show mpx-bnd-init-on-return
+set mpx-bnd-init-on-return on i386 and amd64
+ In case MPX-BND-INIT-ON-RETURN is true, bound registers
+ will be initialized when the "return" command is used.
+
*** Changes in GDB 7.11
* GDB now supports debugging kernel-based threads on FreeBSD.
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index c1aca26..3f21710 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -722,6 +722,8 @@ amd64_classify (struct type *type, enum amd64_reg_class theclass[2])
amd64_classify_aggregate (type, theclass);
}
+int mpx_bnd_init_on_return;
+
static enum return_value_convention
amd64_return_value (struct gdbarch *gdbarch, struct value *function,
struct type *type, struct regcache *regcache,
@@ -759,6 +761,21 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
regcache_raw_read_unsigned (regcache, AMD64_RAX_REGNUM, &addr);
read_memory (addr, readbuf, TYPE_LENGTH (type));
+
+ /* In MPX-enabled programs, if the class is MEMORY, boundary is
+ expected to be stored in bnd0 register.
+
+ If the return value we are setting is due to the use of the
+ "return" command (WRITEBUF is not NULL), it is likely that
+ the return is made prematurely. In that situation, it is
+ possible that the bnd0 register could still be unset, thus
+ causing the program to receive a spurious bound violation.
+
+ When "set mpx-bnd-init-on-return" is true, prevent this
+ from happening by setting the bnd0 register to zero. */
+
+ if (writebuf != NULL && mpx_bnd_init_on_return)
+ i387_reset_bnd0_reg (gdbarch, regcache);
}
return RETURN_VALUE_ABI_RETURNS_ADDRESS;
@@ -852,6 +869,15 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
writebuf + i * 8);
}
+ /* Same as in the class AMD64_MEMORY case above, where
+ we set bnd0 to zero when doing a premature "return"
+ and "set mpx-bnd-init-on-return" is true: Set all bound
+ registers to zero in order to avoid spurious bound
+ violations. */
+
+ if (writebuf != NULL && mpx_bnd_init_on_return)
+ i387_reset_bnd_regs (gdbarch, regcache);
+
return RETURN_VALUE_REGISTER_CONVENTION;
}
@@ -3181,6 +3207,7 @@ void _initialize_amd64_tdep (void);
void
_initialize_amd64_tdep (void)
{
+ mpx_bnd_init_on_return = 1;
initialize_tdesc_amd64 ();
initialize_tdesc_amd64_avx ();
initialize_tdesc_amd64_mpx ();
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4ec0ec1..0e8531a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22438,6 +22438,30 @@ whose bounds are to be changed, @var{lbound} and @var{ubound} are new values
for lower and upper bounds respectively.
@end table
+While calling functions from the debugger, of an Intel MPX enabled program,
+boundary registers have to be set to the INIT state before performing the
+call, to avoid boundary violations while performing the call. A bound is
+defined to be in the INIT state when the pointer associated to that boundary
+can access the whole memory, in this case the register bound register
+associated to it has value 0, e.g. if the register associated is bnd0raw
+its value will be @{0x0, 0x0@}.
+
+When you use the @code{return} command, the bound registers might
+cause boundary violations because they were not updated for the
+early return from the function.
+To countermand that, @value{GDBN} can force initialization of the
+bound registers when it performs the @code{return} command. This is
+controlled by the following option:
+
+@table @code
+@kindex set mpx-bnd-init-on-return
+When set to true bound registers will be set to the INIT state when
+using the "return" command.
+@kindex show mpx-bnd-init-on-return
+Show whether to set the bnd registers to INIT state when
+returning from a call.
+@end table
+
@node Alpha
@subsection Alpha
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index e8d41a3..b528772 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -2971,6 +2971,10 @@ i386_return_value (struct gdbarch *gdbarch, struct value *function,
read_memory (addr, readbuf, TYPE_LENGTH (type));
}
+ /* See amd64_return_value in amd64-tdep.c. */
+ if (writebuf != NULL && mpx_bnd_init_on_return)
+ i387_reset_bnd0_reg (gdbarch, regcache);
+
return RETURN_VALUE_ABI_RETURNS_ADDRESS;
}
@@ -2991,7 +2995,13 @@ i386_return_value (struct gdbarch *gdbarch, struct value *function,
if (readbuf)
i386_extract_return_value (gdbarch, type, regcache, readbuf);
if (writebuf)
- i386_store_return_value (gdbarch, type, regcache, writebuf);
+ {
+ /* See amd64_return_value in amd64-tdep.c. */
+ if (mpx_bnd_init_on_return)
+ i387_reset_bnd_regs (gdbarch, regcache);
+
+ i386_store_return_value (gdbarch, type, regcache, writebuf);
+ }
return RETURN_VALUE_REGISTER_CONVENTION;
}
@@ -8946,6 +8956,23 @@ i386_mpx_set_bounds (char *args, int from_tty)
bt_entry[i]);
}
+
+int mpx_bnd_init_on_return;
+
+/* Show state of the setting variable mpx-bnd-init-on-return. */
+
+static void
+show_mpx_bnd_init_on_return (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ if (mpx_bnd_init_on_return)
+ fprintf_filtered (file,
+ _("BND registers will be initialized on return.\n"));
+ else
+ fprintf_filtered (file,
+ _("BND registers will not be initialized on return.\n"));
+}
+
static struct cmd_list_element *mpx_set_cmdlist, *mpx_show_cmdlist;
/* Helper function for the CLI commands. */
@@ -8972,6 +8999,8 @@ _initialize_i386_tdep (void)
{
register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init);
+ mpx_bnd_init_on_return = 1;
+
/* Add the variable that controls the disassembly flavor. */
add_setshow_enum_cmd ("disassembly-flavor", no_class, valid_flavors,
&disassembly_flavor, _("\
@@ -9022,6 +9051,15 @@ Show Intel Memory Protection Extensions specific variables."),
in the bound table.",
&mpx_set_cmdlist);
+ add_setshow_boolean_cmd ("mpx-bnd-init-on-return", no_class,
+ &mpx_bnd_init_on_return, _("\
+Set the bnd registers to INIT state when returning from a call."), _("\
+Show whether to set the bnd registers to INIT state when returning from a call."),
+ NULL,
+ NULL,
+ show_mpx_bnd_init_on_return,
+ &setlist, &showlist);
+
gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
i386_coff_osabi_sniffer);
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
index 9bb3177..bec5245 100644
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -1788,3 +1788,17 @@ i387_reset_bnd_regs (struct gdbarch *gdbarch, struct regcache *regcache)
regcache_raw_write (regcache, I387_BND0R_REGNUM (tdep) + i, bnd_buf);
}
}
+
+void
+i387_reset_bnd0_reg (struct gdbarch *gdbarch, struct regcache *regcache)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (I387_BND0R_REGNUM (tdep) > 0)
+ {
+ gdb_byte bnd_buf[16];
+
+ memset (bnd_buf, 0, 16);
+ regcache_raw_write (regcache, I387_BND0R_REGNUM (tdep), bnd_buf);
+ }
+}
diff --git a/gdb/i387-tdep.h b/gdb/i387-tdep.h
index 3ac4b4d..3f64647 100644
--- a/gdb/i387-tdep.h
+++ b/gdb/i387-tdep.h
@@ -162,4 +162,13 @@ extern void i387_return_value (struct gdbarch *gdbarch,
extern void i387_reset_bnd_regs (struct gdbarch *gdbarch,
struct regcache *regcache);
+/* Set only bnd0 registers to the INIT state. INIT state means
+ all memory range can be accessed. */
+
+extern void i387_reset_bnd0_reg (struct gdbarch *gdbarch,
+ struct regcache *regcache);
+
+/* Value of the "set mpx-bnd-init-on-return setting. */
+extern int mpx_bnd_init_on_return;
+
#endif /* i387-tdep.h */
diff --git a/gdb/testsuite/gdb.arch/i386-mpx-call.c b/gdb/testsuite/gdb.arch/i386-mpx-call.c
new file mode 100644
index 0000000..d05b8a8
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-call.c
@@ -0,0 +1,126 @@
+/* Test for inferior function calls MPX context.
+
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <walfred.tedeschi@intel.com>
+
+ 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/>. */
+
+#include <stdio.h>
+#include "x86-cpuid.h"
+
+#define OUR_SIZE 5
+
+int gx[OUR_SIZE];
+int ga[OUR_SIZE];
+int gb[OUR_SIZE];
+int gc[OUR_SIZE];
+int gd[OUR_SIZE];
+
+unsigned int
+have_mpx (void)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+ return 0;
+
+ if ((ecx & bit_OSXSAVE) == bit_OSXSAVE)
+ {
+ if (__get_cpuid_max (0, NULL) < 7)
+ return 0;
+
+ __cpuid_count (7, 0, eax, ebx, ecx, edx);
+
+ if ((ebx & bit_MPX) == bit_MPX)
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+int
+bp1 (int value)
+{
+ return 1;
+}
+
+int
+bp2 (int value)
+{
+ return 1;
+}
+
+int
+upper (int *p, int *a, int *b, int *c, int *d, int len)
+{
+ int value;
+
+ value = *(p + len);
+ value = *(a + len);
+ value = *(b + len);
+ value = *(c + len);
+ value = *(d + len);
+
+ value = value - value + 1;
+ return value;
+}
+
+int *
+upper_ptr (int *p, int *a, int *b, int *c, int *d, int len)
+{
+ int value;
+
+ value = *(p + len);
+ value = *(a + len);
+ value = *(b + len);
+ value = *(c + len); /* bkpt 2. */
+ value = *(d + len); /* bkpt 3. */
+ free (p);
+ p = calloc (OUR_SIZE * 2, sizeof (int));
+
+ return ++p;
+}
+
+
+int
+main (void)
+{
+ if (have_mpx ())
+ {
+ int sx[OUR_SIZE];
+ int sa[OUR_SIZE];
+ int sb[OUR_SIZE];
+ int sc[OUR_SIZE];
+ int sd[OUR_SIZE];
+ int *x, *a, *b, *c, *d;
+
+ x = calloc (OUR_SIZE, sizeof (int));
+ a = calloc (OUR_SIZE, sizeof (int));
+ b = calloc (OUR_SIZE, sizeof (int));
+ c = calloc (OUR_SIZE, sizeof (int));
+ d = calloc (OUR_SIZE, sizeof (int));
+
+ upper (sx, sa, sb, sc, sd, 0); /* bkpt 1. */
+ x = upper_ptr (sx, sa, sb, sc, sd, 0);
+
+ free (x);
+ free (a);
+ free (b);
+ free (c);
+ free (d);
+ }
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/i386-mpx-call.exp b/gdb/testsuite/gdb.arch/i386-mpx-call.exp
new file mode 100644
index 0000000..b94aff5
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-call.exp
@@ -0,0 +1,92 @@
+# Copyright (C) 2016 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <walfred.tedeschi@intel.com>
+#
+# 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/>.
+
+
+if { ![istarget i?86-*-*] && ![istarget x86_64-*-* ] } {
+ verbose "Skipping x86 MPX tests."
+ return
+}
+
+standard_testfile
+
+set comp_flags "-mmpx -fcheck-pointer-bounds -I${srcdir}/../nat"
+
+if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} \
+ [list debug nowarnings additional_flags=${comp_flags}]] } {
+ return -1
+}
+
+if ![runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+gdb_test_multiple "print have_mpx ()" "have mpx" {
+ -re ".*= 1\r\n$gdb_prompt " {
+ pass "check whether processor supports MPX"
+ }
+ -re ".*= 0\r\n$gdb_prompt " {
+ verbose "processor does not support MPX; skipping MPX tests"
+ return
+ }
+}
+
+# Needed by the return command.
+gdb_test_no_output "set confirm off"
+
+set bound_reg " = \\\{lbound = $hex, ubound = $hex\\\}.*"
+
+set break "bkpt 1."
+gdb_breakpoint [gdb_get_line_number "${break}"]
+gdb_continue_to_breakpoint "${break}" ".*${break}.*"
+gdb_test "p upper (x, a, b, c, d, 0)" " = 1"\
+ "test the call of int function - int"
+gdb_test "p upper_ptr (x, a, b, c, d, 0)"\
+ " = \\\(int \\\*\\\) $hex" "test the call of function - ptr"
+
+set break "bkpt 2."
+gdb_breakpoint [gdb_get_line_number "${break}"]
+gdb_continue_to_breakpoint "${break}" ".*${break}.*"
+gdb_test "p \$bound0 = \$bnd0" "$bound_reg" "Saving the\
+ bnd0 result in a convenience variable 1"
+
+gdb_test "return a" "#0 $hex in main.*" "First return"
+gdb_test "p \(\$bnd0\.ubound == \$bound0\.ubound\)"\
+ " = 0" "return with bnd initialization off - ubound"
+gdb_test "p \(\$bnd0\.lbound ==\$bound0\.lbound\)"\
+ " = 0" "return with bnd initialization off - lbound"
+
+# Retesting with initialization off.
+# All breakpoints were deleted need to recreate what we need.
+runto_main
+gdb_test_no_output "set mpx-bnd-init-on-return off"\
+ "Turn off initialization on return"
+
+set break "bkpt 3."
+gdb_breakpoint [gdb_get_line_number "${break}"]
+gdb_continue_to_breakpoint "${break}" ".*${break}.*"
+gdb_test "p \$bound0 = \$bnd0" "$bound_reg" "Saving the\
+ bnd0 result in a convenience variable 2"
+gdb_test "return a" "#0 $hex in main.*" "Second return"
+gdb_test "p \(\$bnd0\.ubound == \$bound0\.ubound\)"\
+ " = 1" "return with bnd initialization on - ubound"
+gdb_test "p \(\$bnd0\.lbound ==\$bound0\.lbound\)"\
+ " = 1" "return with bnd initialization on - lbound"
+
+gdb_test "show mpx-bnd-init-on-return"\
+ "BND registers will not be initialized on return\\."\
+ "double check initialization on return"
--
2.1.4