[PATCH v1] Intel(R) MPX - Bound violation handling.

Walfred Tedeschi
2015-10-26T12:55:31Z

With Intel(R) Memory Protection Extensions it was introduced the concept of
boundary violation. A boundary violations is presented to the inferior as
a segmentation fault having as sigcode the value 3. This patch adds a
handler for a boundary violation extending the information displayed
when a bound violation is presented to the inferior (segfault with code 3).
In this case the debugger will also display the kind of violation upper or
lower the violated bounds and the address accessed.

There some open points to be discussed though before asking permission to
commit.
They are:
1. infrun.c (process_segmentation_faults): The inferior is stopped to
allow doing some evaluations. I have seen no side effect on doing that,
on the other hand it does not look so natural to me.
2. i386-linux-tdep.c (i386_mpx_bound_violation_handler): I was wondering if
the right place for it wouldn't be the linux-tdep.c as it is done for the
siginfo things. This is a new structure in the kernel. Doing at the
linux-tdep.c documentation should be simplified and all architectures
providing that functionality in a different way only have to set the right
function pointer.
3. Still need to add documentation, expected mi changes and siginfo changes

Thanks a lot for your support!

Changelog:

2015-07-21 Walfred Tedeschi <walfred.tedeschi@intel.com>

* amd64-linux-tdep.c (amd64_linux_init_abi_common):
Add handler for bound violation signal.
* gdbarch.sh (bound_violation_handler): New.
* i386-linux-tdep.c (i386_mpx_bound_violation_handler): New.
(i386_linux_init_abi): Use i386_mpx_bound_violation_handler.
* i386-linux-tdep.h (i386_mpx_bound_violation_handler) New.
* i386-tdep.c (i386_mpx_enabled): Add as external.
* i386-tdep.c (i386_mpx_enabled): Add as external.
* infrun.c (process_segmentation_faults): New.
(print_signal_received_reason): Use process_segmentation_faults.

testsuite/gdb.arch
* i386-mpx-sigsegv.c: New.
* i386-mpx-sigsegv.exp: New.
* i386-mpx-simple_segv.c: New.
* i386-mpx-simple_segv.exp: New.

---
gdb/amd64-linux-tdep.c | 3 +
gdb/gdbarch.c | 32 ++++++
gdb/gdbarch.h | 11 ++
gdb/gdbarch.sh | 7 ++
gdb/i386-linux-tdep.c | 66 ++++++++++++
gdb/i386-linux-tdep.h | 5 +
gdb/i386-tdep.c | 2 +-
gdb/i386-tdep.h | 3 +
gdb/infrun.c | 18 ++++
gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c | 128 +++++++++++++++++++++++
gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp | 95 +++++++++++++++++
gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c | 70 +++++++++++++
gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp | 130 ++++++++++++++++++++++++
13 files changed, 569 insertions(+), 1 deletion(-)
create mode 100644 gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c
create mode 100644 gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp
create mode 100644 gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c
create mode 100644 gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp

diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 021dca6..12e9e01 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1838,6 +1838,9 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch)

set_gdbarch_process_record (gdbarch, i386_process_record);
set_gdbarch_process_record_signal (gdbarch, amd64_linux_record_signal);
+
+ set_gdbarch_bound_violation_handler(gdbarch,
+ i386_mpx_bound_violation_handler);
}

static void
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index f04eef9..e63f141 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -189,6 +189,7 @@ struct gdbarch
int num_pseudo_regs;
gdbarch_ax_pseudo_register_collect_ftype *ax_pseudo_register_collect;
gdbarch_ax_pseudo_register_push_stack_ftype *ax_pseudo_register_push_stack;
+ gdbarch_bound_violation_handler_ftype *bound_violation_handler;
int sp_regnum;
int pc_regnum;
int ps_regnum;
@@ -531,6 +532,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of num_pseudo_regs, invalid_p == 0 */
/* Skip verify of ax_pseudo_register_collect, has predicate. */
/* Skip verify of ax_pseudo_register_push_stack, has predicate. */
+ /* Skip verify of bound_violation_handler, has predicate. */
/* Skip verify of sp_regnum, invalid_p == 0 */
/* Skip verify of pc_regnum, invalid_p == 0 */
/* Skip verify of ps_regnum, invalid_p == 0 */
@@ -773,6 +775,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: bits_big_endian = %s\n",
plongest (gdbarch->bits_big_endian));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_bound_violation_handler_p() = %d\n",
+ gdbarch_bound_violation_handler_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: bound_violation_handler = <%s>\n",
+ host_address_to_string (gdbarch->bound_violation_handler));
+ fprintf_unfiltered (file,
"gdbarch_dump: breakpoint_from_pc = <%s>\n",
host_address_to_string (gdbarch->breakpoint_from_pc));
fprintf_unfiltered (file,
@@ -1986,6 +1994,30 @@ set_gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch,
}

int
+gdbarch_bound_violation_handler_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->bound_violation_handler != NULL;
+}
+
+void
+gdbarch_bound_violation_handler (struct gdbarch *gdbarch, struct ui_out *uiout, long si_code)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->bound_violation_handler != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_bound_violation_handler called\n");
+ gdbarch->bound_violation_handler (uiout, si_code);
+}
+
+void
+set_gdbarch_bound_violation_handler (struct gdbarch *gdbarch,
+ gdbarch_bound_violation_handler_ftype bound_violation_handler)
+{
+ gdbarch->bound_violation_handler = bound_violation_handler;
+}
+
+int
gdbarch_sp_regnum (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 2e4ed3e..c2dd767 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -64,6 +64,7 @@ struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo;
struct mem_range;
struct syscalls_info;
+struct ui_out;

#include "regcache.h"

@@ -300,6 +301,16 @@ typedef int (gdbarch_ax_pseudo_register_push_stack_ftype) (struct gdbarch *gdbar
extern int gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch, struct agent_expr *ax, int reg);
extern void set_gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch, gdbarch_ax_pseudo_register_push_stack_ftype *ax_pseudo_register_push_stack);

+/* Bound violation can be handled differently accross architectures.
+ UIOUT is the output stream where the handler will place information.
+ si_code is the value of the field with the same name in the siginfo structure. */
+
+extern int gdbarch_bound_violation_handler_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_bound_violation_handler_ftype) (struct ui_out *uiout, long si_code);
+extern void gdbarch_bound_violation_handler (struct gdbarch *gdbarch, struct ui_out *uiout, long si_code);
+extern void set_gdbarch_bound_violation_handler (struct gdbarch *gdbarch, gdbarch_bound_violation_handler_ftype *bound_violation_handler);
+
/* GDB's standard (or well known) register numbers. These can map onto
a real register or a pseudo (computed) register or not be defined at
all (-1).
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index a13d9b9..b4d231c 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -446,6 +446,11 @@ M:int:ax_pseudo_register_collect:struct agent_expr *ax, int reg:ax, reg
# Return -1 if something goes wrong, 0 otherwise.
M:int:ax_pseudo_register_push_stack:struct agent_expr *ax, int reg:ax, reg

+# Bound violation can be handled differently accross architectures.
+# UIOUT is the output stream where the handler will place information.
+# si_code is the value of the field with the same name in the siginfo structure.
+F:void:bound_violation_handler:struct ui_out *uiout, long si_code:uiout, si_code
+
# GDB's standard (or well known) register numbers. These can map onto
# a real register or a pseudo (computed) register or not be defined at
# all (-1).
@@ -696,6 +701,7 @@ M:void:iterate_over_regset_sections:iterate_over_regset_sections_cb *cb, void *c
# Create core file notes
M:char *:make_corefile_notes:bfd *obfd, int *note_size:obfd, note_size

+
# The elfcore writer hook to use to write Linux prpsinfo notes to core
# files. Most Linux architectures use the same prpsinfo32 or
# prpsinfo64 layouts, and so won't need to provide this hook, as we
@@ -1247,6 +1253,7 @@ struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo;
struct mem_range;
struct syscalls_info;
+struct ui_out;

#include "regcache.h"

diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index d02c527..fe3b52f 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -384,6 +384,68 @@ i386_canonicalize_syscall (int syscall)
return gdb_sys_no_syscall;
}

+/* Code for faulty boundary has to be introduced. */
+#define SIG_CODE_BONDARY_FAULT 3
+
+void
+i386_mpx_bound_violation_handler (struct ui_out *uiout, long si_code)
+{
+ CORE_ADDR lower_bound, upper_bound, access;
+ int is_upper;
+
+ if (!i386_mpx_enabled () || si_code != SIG_CODE_BONDARY_FAULT)
+ return;
+
+ lower_bound = parse_and_eval_long (
+ "$_siginfo._sifields._sigfault._addr_bnd._lower\n");
+ upper_bound = parse_and_eval_long (
+ "$_siginfo._sifields._sigfault._addr_bnd._upper\n");
+ access = parse_and_eval_long (
+ "$_siginfo._sifields._sigfault.si_addr\n");
+ is_upper = (access > upper_bound ? 1 : 0);
+
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ if (is_upper)
+ ui_out_field_string (uiout, "sigcode-meaning",
+ "upper bound violation");
+ else
+ ui_out_field_string (uiout, "sigcode-meaning",
+ "lower bound violation");
+ ui_out_field_fmt (uiout,"lower-bound",
+ "0x%lx",
+ lower_bound);
+ ui_out_field_fmt (uiout,"upper-bound",
+ "0x%lx",
+ upper_bound);
+ ui_out_field_fmt (uiout,"bound-access",
+ "0x%lx",
+ access);
+ }
+ else
+ {
+ if (is_upper)
+ ui_out_field_string (uiout, "sigcode-meaning",
+ "\nupper bound violation");
+ else
+ ui_out_field_string (uiout, "sigcode-meaning",
+ "\nlower bound violation");
+
+ ui_out_field_string (uiout, "bounds",
+ " - bounds");
+ ui_out_field_fmt (uiout,"bound-values",
+ " {lbound = 0x%lx, ubound = 0x%lx}",
+ lower_bound,
+ upper_bound);
+ ui_out_field_fmt (uiout,"bound-access",
+ " accessing 0x%lx",
+ access);
+ }
+
+ return;
+}
+
+
/* Parse the arguments of current system call instruction and record
the values of the registers and memory that will be changed into
"record_arch_list". This instruction is "int 0x80" (Linux
@@ -995,6 +1057,10 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_I386);
set_gdbarch_get_syscall_number (gdbarch,
i386_linux_get_syscall_number);
+
+ set_gdbarch_bound_violation_handler(gdbarch,
+ i386_mpx_bound_violation_handler);
+
}

/* Provide a prototype to silence -Wmissing-prototypes. */
diff --git a/gdb/i386-linux-tdep.h b/gdb/i386-linux-tdep.h
index 5ac08d3..5655081 100644
--- a/gdb/i386-linux-tdep.h
+++ b/gdb/i386-linux-tdep.h
@@ -37,6 +37,11 @@
/* Get XSAVE extended state xcr0 from core dump. */
extern uint64_t i386_linux_core_read_xcr0 (bfd *abfd);

+/* Handles and displays information related to the MPX bound violation
+ to the user. */
+void
+i386_mpx_bound_violation_handler (struct ui_out *uiout, long si_code);
+
/* Linux target description. */
extern struct target_desc *tdesc_i386_linux;
extern struct target_desc *tdesc_i386_mmx_linux;
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index b8edff6..6349389 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -8641,7 +8641,7 @@ i386_mpx_bd_base (void)

/* Check if the current target is MPX enabled. */

-static int
+int
i386_mpx_enabled (void)
{
const struct gdbarch_tdep *tdep = gdbarch_tdep (get_current_arch ());
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 95288ba..4e81288 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -420,6 +420,9 @@ extern int i386_process_record (struct gdbarch *gdbarch,
struct regcache *regcache, CORE_ADDR addr);
extern const struct target_desc *i386_target_description (uint64_t xcr0);

+/* Verify if target is MPX enabled. */
+extern int i386_mpx_enabled (void);
+
\f

/* Functions and variables exported from i386bsd-tdep.c. */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 0c268ff..3a323ae 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -7744,6 +7744,20 @@ print_exited_reason (struct ui_out *uiout, int exitstatus)
}
}

+
+static void
+process_segmentation_faults (struct ui_out * uiout)
+{
+ long si_code;
+ struct regcache *regcache = get_current_regcache ();
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+ set_running (user_visible_resume_ptid (1), 0);
+ si_code = parse_and_eval_long ("$_siginfo.si_code\n");
+ if (gdbarch_bound_violation_handler_p (gdbarch))
+ gdbarch_bound_violation_handler (gdbarch, uiout, si_code);
+}
+
void
print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
{
@@ -7773,6 +7787,10 @@ print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
annotate_signal_string ();
ui_out_field_string (uiout, "signal-meaning",
gdb_signal_to_string (siggnal));
+
+ if (siggnal == GDB_SIGNAL_SEGV)
+ process_segmentation_faults (uiout);
+
annotate_signal_string_end ();
}
ui_out_text (uiout, ".\n");
diff --git a/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c b/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c
new file mode 100644
index 0000000..5f20aa2
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c
@@ -0,0 +1,128 @@
+/*
+* Copyright 2012 Free Software Foundation, Inc.
+*
+* Contributed by Intel Corp. <christian.himpel@intel.com>,
+* <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/>.
+*
+* This test was converted from idb/test/td/runreg/Biendian/bi.c_bitfield
+*
+*/
+#include <stdio.h>
+#include "x86-cpuid.h"
+
+
+#define MYTYPE int
+#define OUR_SIZE 5
+
+MYTYPE gx[OUR_SIZE];
+MYTYPE ga[OUR_SIZE];
+MYTYPE gb[OUR_SIZE];
+MYTYPE gc[OUR_SIZE];
+MYTYPE 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 (MYTYPE value)
+{
+ return 1;
+}
+
+int
+bp2 (MYTYPE value)
+{
+ return 1;
+}
+
+void
+upper (MYTYPE * p, MYTYPE * a, MYTYPE * b, MYTYPE * c, MYTYPE * d, int len)
+{
+ MYTYPE value;
+ value = *(p + len);
+ value = *(a + len);
+ value = *(b + len);
+ value = *(c + len);
+ value = *(d + len);
+}
+
+void
+lower (MYTYPE * p, MYTYPE * a, MYTYPE * b, MYTYPE * c, MYTYPE * d, int len)
+{
+ MYTYPE value;
+ value = *(p - len);
+ value = *(a - len);
+ value = *(b - len);
+ value = *(c - len);
+ bp2 (value);
+ value = *(d - len);
+}
+
+
+int
+main (void)
+{
+ if (have_mpx ())
+ {
+ MYTYPE sx[OUR_SIZE];
+ MYTYPE sa[OUR_SIZE];
+ MYTYPE sb[OUR_SIZE];
+ MYTYPE sc[OUR_SIZE];
+ MYTYPE sd[OUR_SIZE];
+ MYTYPE *x, *a, *b, *c, *d;
+
+ x = calloc (OUR_SIZE, sizeof (MYTYPE));
+ a = calloc (OUR_SIZE, sizeof (MYTYPE));
+ b = calloc (OUR_SIZE, sizeof (MYTYPE));
+ c = calloc (OUR_SIZE, sizeof (MYTYPE));
+ d = calloc (OUR_SIZE, sizeof (MYTYPE));
+
+ upper (x, a, b, c, d, OUR_SIZE + 2);
+ upper (sx, sa, sb, sc, sd, OUR_SIZE + 2);
+ upper (gx, ga, gb, gc, gd, OUR_SIZE + 2);
+ lower (x, a, b, c, d, 1);
+ lower (sx, sa, sb, sc, sd, 1);
+ bp1 (*x);
+ lower (gx, ga, gb, gc, gd, 1);
+
+ free (x);
+ free (a);
+ free (b);
+ free (c);
+ free (d);
+ }
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp b/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp
new file mode 100644
index 0000000..f689018
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp
@@ -0,0 +1,95 @@
+# Copyright 2012 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
+ }
+ -re ".*$gdb_prompt $" {
+ fail "check whether processor supports MPX"
+ }
+ timeout {
+ fail "check whether processor supports MPX (timeout)"
+ }
+}
+
+set segv_lower_bound ".*Program received signal SIGSEGV,\
+ Segmentation fault\r\nlower bound violation - bounds \\\{lbound\
+ = 0x\[0-9a-fA-F\]+, ubound = 0x\[0-9a-fA-F\]+\\\} accessing\
+ 0x\[0-9a-fA-F\]+.*$gdb_prompt $"
+
+set segv_upper_bound ".*Program received signal SIGSEGV,\
+ Segmentation fault\r\nupper bound violation - bounds \\\{lbound\
+ = 0x\[0-9a-fA-F\]+, ubound = 0x\[0-9a-fA-F\]+\\\} accessing\
+ 0x\[0-9a-fA-F\]+.*$gdb_prompt $"
+
+for {set i 0} {$i < 15} {incr i} {
+ set message "MPX signal segv Upper: ${i}"
+ send_gdb "continue\n"
+ gdb_expect {
+ -re $segv_upper_bound
+ { pass "$message" }
+ -re ".*$inferior_exited_re normally.*$gdb_prompt $"
+ {
+ fail "$message"
+ break
+ }
+ }
+ gdb_test "where" ".*#0 0x\[0-9a-fA-F\]+ in upper.*"\
+ "$message: should be in upper"
+}
+
+for {set i 0} {$i < 15} {incr i} {
+ set message "MPX signal segv Lower: ${i}"
+ gdb_test_multiple "continue" "$message ${i}" {
+ -re $segv_lower_bound
+ { pass "$message ${i}" }
+ -re ".*$inferior_exited_re normally.*$gdb_prompt $"
+ {
+ fail "$message ${i}"
+ break
+ }
+ }
+ gdb_test "where" ".*#0 0x\[0-9a-fA-F\]+ in lower.*"\
+ "$message: should be in lower"
+}
+
+send_gdb "quit\n"
diff --git a/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c b/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c
new file mode 100644
index 0000000..407086b
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c
@@ -0,0 +1,70 @@
+/*
+* Copyright 2012 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 MYTYPE int
+#define OUR_SIZE 5
+
+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;
+}
+
+void
+upper (MYTYPE * p, int len)
+{
+ MYTYPE value;
+ len++; /* b0-size-test. */
+ value = *(p + len);
+}
+
+int
+main (void)
+{
+ if (have_mpx ())
+ {
+ int a = 0; /* Dummy variable for debugging purposes. */
+ MYTYPE sx[OUR_SIZE];
+ a++; /* register-eval. */
+ upper (sx, OUR_SIZE + 2);
+ return sx[1];
+ }
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp b/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp
new file mode 100644
index 0000000..988a8b4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp
@@ -0,0 +1,130 @@
+# Copyright 2013 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/>.
+
+# Testing handle setup together with boundary violation signals.
+#
+# Some states are not allowed as reported on the manual, as noprint
+# implies nostop, but nostop might print.
+#
+# Caveat: Setting the handle to nopass, ends up in a endless loop.
+
+
+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
+}
+
+send_gdb "print have_mpx ()\r"
+gdb_expect {
+ -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
+ }
+ -re ".*$gdb_prompt $" {
+ fail "check whether processor supports MPX"
+ }
+ timeout {
+ fail "check whether processor supports MPX (timeout)"
+ }
+}
+
+set segv_bound_with_prompt ".*Program received signal SIGSEGV,\
+ Segmentation fault\r\nupper bound violation - bounds \\\{lbound\
+ = 0x\[0-9a-fA-F\]+, ubound = 0x\[0-9a-fA-F\]+\\\} accessing\
+ 0x\[0-9a-fA-F\]+.*$gdb_prompt $"
+
+set segv_bound_with_exit ".*Program received signal SIGSEGV,\
+ Segmentation fault\r\nupper bound violation - bounds \\\{lbound\
+ = 0x\[0-9a-fA-F\]+, ubound = 0x\[0-9a-fA-F\]+\\\} accessing\
+ 0x\[0-9a-fA-F\]+.*$inferior_exited_re.*"
+
+# Using the handler for SIGSEGV as "print pass stop"
+set parameters "print pass stop"
+runto main
+send_gdb "handle SIGSEGV $parameters\n"
+send_gdb "continue\n"
+
+gdb_expect {
+ -re $segv_bound_with_prompt
+ { pass $parameters}
+ timeout { fail $parameters }
+}
+gdb_test "where" ".*#0 0x\[0-9a-fA-F\]+ in upper.*"\
+ "should be in upper; $parameters"
+
+# Using the handler for SIGSEGV as "print pass nostop"
+set parameters "print pass nostop"
+runto main
+gdb_test "handle SIGSEGV $parameters" "" "Setting the handler for segfault 0"
+
+gdb_test_multiple "continue" "test 0" {
+ -re $segv_bound_with_exit
+ { pass $parameters}
+ -re "$gdb_prompt $"
+ { fail $parameters }
+ timeout { fail $parameters }
+}
+
+gdb_test "where" "No stack." "no inferior $parameters"
+
+# Using the handler for SIGSEGV as "print nopass stop"
+set parameters "print nopass stop"
+runto main
+gdb_test "handle SIGSEGV $parameters" "" "Setting the handler for segfault 1"
+
+gdb_test_multiple "continue" "test 1" {
+ -re $segv_bound_with_prompt
+ { pass $parameters}
+ timeout
+ { fail $parameters }
+}
+
+gdb_test "where" ".*#0 0x\[0-9a-fA-F\]+ in upper.*"\
+ "should be in upper $parameters"
+
+# print nopass stop
+set parameters "noprint pass nostop"
+runto main
+gdb_test "handle SIGSEGV $parameters" "" "Setting the handler for segfault 2"
+
+gdb_test_multiple "continue" "test 2" {
+ -re "Continuing\..*$inferior_exited_re.*"
+ { pass $parameters}
+ timeout { fail $parameters }
+}
+
+gdb_test "where" "No stack." "no inferior $parameters"
+
+send_gdb "quit\n"
+
--
2.1.4