[PATCH V4 6/6] Intel MPX bound violation handling.

Walfred Tedeschi
2016-01-21T14:49:20Z

With Intel Memory Protection Extensions it was introduced the concept of
boundary violation. A boundary violations is presented to the inferior as
a segmentation fault having SIGCODE 3. This patch adds a
handler for a boundary violation extending the information displayed
when a bound violation is presented to the inferior. In the stop mode
case the debugger will also display the kind of violation: "upper" or
"lower", bounds and the address accessed.
On no stop mode the information will still remain unchanged. Additional
information about bound violations are not meaningful in that case user
does not know the line in which violation occurred as well.

When the segmentation fault handler is stop mode the out puts will be
changed as exemplified below.

The usual output of a segfault is:
Program received signal SIGSEGV, Segmentation fault
0x0000000000400d7c in upper (p=0x603010, a=0x603030, b=0x603050,
c=0x603070, d=0x603090, len=7) at i386-mpx-sigsegv.c:68
68 value = *(p + len);

In case it is a bound violation it will be presented as:
Program received signal SIGSEGV, Segmentation fault
upper bound violation - bounds {lbound = 0x603010, ubound = 0x603023}
accessing 0x60302f.
0x0000000000400d7c in upper (p=0x603010, a=0x603030, b=0x603050,
c=0x603070, d=0x603090, len=7) at i386-mpx-sigsegv.c:68
68 value = *(p + len);

In mi mode the output of a segfault is:
*stopped,reason="signal-received",signal-name="SIGSEGV",
signal-meaning="Segmentation fault", frame={addr="0x0000000000400d7c",
func="upper",args=[{name="p", value="0x603010"},{name="a",value="0x603030"}
,{name="b",value="0x603050"}, {name="c",value="0x603070"},
{name="d",value="0x603090"},{name="len",value="7"}],
file="i386-mpx-sigsegv.c",fullname="i386-mpx-sigsegv.c",line="68"},
thread-id="1",stopped-threads="all",core="6"

in the case of a bound violation:
*stopped,reason="signal-received",signal-name="SIGSEGV",
signal-meaning="Segmentation fault",
sigcode-meaning="upper bound violation",
lower-bound="0x603010",upper-bound="0x603023",bound-access="0x60302f",
frame={addr="0x0000000000400d7c",func="upper",args=[{name="p",
value="0x603010"},{name="a",value="0x603030"},{name="b",value="0x603050"},
{name="c",value="0x603070"},{name="d",value="0x603090"},
{name="len",value="7"}],file="i386-mpx-sigsegv.c",
fullname="i386-mpx-sigsegv.c",line="68"},thread-id="1",
stopped-threads="all",core="6"

2016-01-15 Walfred Tedeschi <walfred.tedeschi@intel.com>

gdb/ChangeLog:

* NEWS: Add entry for bound violation.
* amd64-linux-tdep.c (amd64_linux_init_abi_common):
Add handler for bound violation.
* gdbarch.sh (bound_violation_handler): New.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
* 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 (handle_segmentation_faults): New function.
(print_signal_received_reason): Use handle_segmentation_faults.
(normal_stop): Change order of observer in order to have the
inferior stopped for evaluation.

gdb/testsuite/ChangeLog:

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

gdb/doc/ChangeLog:

* gdb.texinfo (Intel Memory Protection Extensions): Add bound
violation handler.

Conflicts:
gdb/amd64-linux-tdep.c
gdb/i386-linux-tdep.c
---
gdb/NEWS | 15 +++
gdb/amd64-linux-tdep.c | 2 +
gdb/doc/gdb.texinfo | 51 ++++++++++
gdb/gdbarch.c | 32 ++++++
gdb/gdbarch.h | 11 ++
gdb/gdbarch.sh | 6 ++
gdb/i386-linux-tdep.c | 45 +++++++++
gdb/i386-linux-tdep.h | 5 +
gdb/i386-tdep.c | 4 +-
gdb/i386-tdep.h | 2 +
gdb/infrun.c | 34 +++++++
gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c | 120 ++++++++++++++++++++++
gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp | 86 ++++++++++++++++
gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c | 66 ++++++++++++
gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp | 129 ++++++++++++++++++++++++
15 files changed, 605 insertions(+), 3 deletions(-)
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/NEWS b/gdb/NEWS
index d9cbb80..d738874 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,21 @@

*** Changes since GDB 7.10

+* Intel MPX boud violation handler.
+
+ A boundary violations is presented to the inferior as
+ a segmentation fault having SIGCODE 3. In this case
+ GDB displays also the kind of violation (upper or lower),
+ bounds, poiter value and the memory accessed, besides displaying
+ the usual signal received and code location report.
+
+ As exemplified below:
+ Program received signal SIGSEGV, Segmentation fault
+ upper bound violation - bounds {lbound = 0x603010, ubound = 0x603023}
+ accessing 0x60302f.
+ 0x0000000000400d7c in upper (p=0x603010, a=0x603030, b=0x603050,
+ c=0x603070, d=0x603090, len=7) at i386-mpx-sigsegv.c:68
+
* Per-inferior thread numbers

Thread numbers are now per inferior instead of global. If you're
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 21bcd99..8af15c4 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1840,6 +1840,8 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_process_record_signal (gdbarch, amd64_linux_record_signal);

set_gdbarch_get_siginfo_type (gdbarch, x86_linux_get_siginfo_type);
+ set_gdbarch_bound_violation_handler(gdbarch,
+ i386_mpx_bound_violation_handler);
}

static void
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7da31c8..91add58 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22267,6 +22267,57 @@ whose bounds are to be changed, @var{lbound} and @var{ubound} are new values
for lower and upper bounds respectively.
@end table

+
+A boundary violation is presented to the inferior as
+a segmentation fault having SIGCODE 3. @value{GDBN} may display additional
+information is displayed in this case. On @code{STOP} mode
+@value{GDBN} will also display the kind of violation: "upper" or
+"lower", bounds, pointer value and the address accessed.
+On @code{NOSTOP} no additional information will be presented.
+
+The usual output of a segfault is:
+@smallexample
+Program received signal SIGSEGV, Segmentation fault
+0x0000000000400d7c in upper (p=0x603010, a=0x603030, b=0x603050,
+c=0x603070, d=0x603090, len=7) at i386-mpx-sigsegv.c:68
+68 value = *(p + len);
+@end smallexample
+
+In case it is a bound violation it will be presented as:
+@smallexample
+Program received signal SIGSEGV, Segmentation fault
+upper bound violation - bounds @{lbound = 0x603010, ubound = 0x603023@}
+accessing 0x60302f.
+0x0000000000400d7c in upper (p=0x603010, a=0x603030, b=0x603050,
+c=0x603070, d=0x603090, len=7) at i386-mpx-sigsegv.c:68
+68 value = *(p + len);
+@end smallexample
+
+@sc{gdb/mi} is also taken into account, the output of a segmentation fault is:
+@smallexample
+*stopped,reason="signal-received",signal-name="SIGSEGV",
+signal-meaning="Segmentation fault", frame=@{addr="0x0000000000400d7c",
+func="upper",args=[@{name="p", value="0x603010"@},@{name="a",value="0x603030"@}
+,@{name="b",value="0x603050"@}, @{name="c",value="0x603070"@},
+@{name="d",value="0x603090"@},@{name="len",value="7"@}],
+file="i386-mpx-sigsegv.c",fullname="i386-mpx-sigsegv.c",line="68"@},
+thread-id="1",stopped-threads="all",core="6"
+@end smallexample
+
+in case of a bound violation it will be presented as:
+@smallexample
+*stopped,reason="signal-received",signal-name="SIGSEGV",
+signal-meaning="Segmentation fault",
+sigcode-meaning="upper bound violation",
+lower-bound="0x603010",upper-bound="0x603023",bound-access="0x60302f",
+frame=@{addr="0x0000000000400d7c",func="upper",args=[@{name="p",
+value="0x603010"@},@{name="a",value="0x603030"@},@{name="b",value="0x603050"@},
+@{name="c",value="0x603070"@},@{name="d",value="0x603090"@},
+@{name="len",value="7"@}],file="i386-mpx-sigsegv.c",
+fullname="i386-mpx-sigsegv.c",line="68"@},thread-id="1",
+stopped-threads="all",core="6"
+@end smallexample
+
@node Alpha
@subsection Alpha

diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index d45af1a..f7fef25 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)
+{
+ 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 (gdbarch, uiout);
+}
+
+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 3c16af2..eb5de0d 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -63,6 +63,7 @@ struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo;
struct mem_range;
struct syscalls_info;
+struct ui_out;

#include "regcache.h"

@@ -299,6 +300,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);

+/* Function called when a segmentation fault signal is received by the inferior,
+ having SIGCODE 3 (SIG_CODE_BOUNDARY_FAULT).
+ UIOUT is the output stream where the handler will place information. */
+
+extern int gdbarch_bound_violation_handler_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_bound_violation_handler_ftype) (struct gdbarch *gdbarch, struct ui_out *uiout);
+extern void gdbarch_bound_violation_handler (struct gdbarch *gdbarch, struct ui_out *uiout);
+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 f80cd51..edd155a 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

+# Function called when a segmentation fault signal is received by the inferior,
+# having SIGCODE 3 (SIG_CODE_BOUNDARY_FAULT).
+# UIOUT is the output stream where the handler will place information.
+M:void:bound_violation_handler:struct ui_out *uiout:uiout
+
# 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).
@@ -1247,6 +1252,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 af39e78..96c8e06 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -30,6 +30,7 @@
#include "i386-tdep.h"
#include "i386-linux-tdep.h"
#include "linux-tdep.h"
+#include "utils.h"
#include "glibc-tdep.h"
#include "solib-svr4.h"
#include "symtab.h"
@@ -384,6 +385,48 @@ i386_canonicalize_syscall (int syscall)
return gdb_sys_no_syscall;
}

+void
+i386_mpx_bound_violation_handler (struct gdbarch *gdbarch, struct ui_out *uiout)
+{
+ CORE_ADDR lower_bound, upper_bound, access;
+ int is_upper;
+
+ if (!i386_mpx_enabled ())
+ return;
+ TRY
+ {
+ lower_bound
+ = parse_and_eval_long ("$_siginfo._sifields._sigfault._addr_bnd._lower");
+ upper_bound
+ = parse_and_eval_long ("$_siginfo._sifields._sigfault._addr_bnd._upper");
+ access
+ = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
+ }
+ CATCH (exception, RETURN_MASK_ALL)
+ {
+ return;
+ }
+ END_CATCH
+
+ is_upper = (access > upper_bound ? 1 : 0);
+
+ ui_out_text (uiout, "\n");
+ 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_text (uiout, " - bounds {lbound = ");
+ ui_out_field_fmt (uiout,"lower-bound", "%s", paddress (gdbarch, lower_bound));
+ ui_out_text (uiout, ", ubound = ");
+ ui_out_field_fmt (uiout,"upper-bound", "%s", paddress (gdbarch, upper_bound));
+ ui_out_text (uiout, "}");
+ ui_out_text (uiout, " accessing ");
+ ui_out_field_fmt (uiout,"bound-access", "%s", paddress (gdbarch, 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
@@ -1002,6 +1045,8 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
i386_linux_get_syscall_number);

set_gdbarch_get_siginfo_type (gdbarch, x86_linux_get_siginfo_type);
+ 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 f8e0074..5dc22ca 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 gdbarch *gdbarch, struct ui_out *uiout);
+
/* 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 b706463..b5d0d14 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -8651,9 +8651,7 @@ i386_mpx_bd_base (void)
return ret & MPX_BASE_MASK;
}

-/* 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 10d2772..26933f2 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -420,6 +420,8 @@ 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 64c729e..87b930e 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -7893,6 +7893,36 @@ print_exited_reason (struct ui_out *uiout, int exitstatus)
}
}

+/* Value of the sigcode in case of a boundary fault. */
+
+#define SIG_CODE_BONDARY_FAULT 3
+
+/* Verifies if a received segmentation fault is a boundary fault.
+ In the case it is it calls the architecture dependent function
+ to handle the boundary fault. */
+
+static void
+handle_segmentation_faults (struct ui_out *uiout)
+{
+ long sig_code = 0;
+ struct regcache *regcache = get_current_regcache ();
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+ TRY
+ {
+ sig_code = parse_and_eval_long ("$_siginfo.si_code\n");
+ }
+ CATCH (exception, RETURN_MASK_ALL)
+ {
+ return;
+ }
+ END_CATCH
+
+ if (sig_code == SIG_CODE_BONDARY_FAULT
+ && gdbarch_bound_violation_handler_p (gdbarch))
+ gdbarch_bound_violation_handler (gdbarch, uiout);
+}
+
void
print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
{
@@ -7922,6 +7952,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)
+ handle_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..7500352
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c
@@ -0,0 +1,120 @@
+/* Copyright (C) 2015 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 "x86-cpuid.h"
+#include <stdio.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;
+}
+
+void
+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);
+}
+
+void
+lower (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);
+ bp2 (value);
+ value = *(d - len);
+}
+
+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 (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..2de6b4a
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp
@@ -0,0 +1,86 @@
+# Copyright (C) 2015 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
+ }
+}
+
+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}"
+ gdb_test_multiple "continue" "$message ${i}" {
+ -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"
+}
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..5317369
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2015 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 "x86-cpuid.h"
+#include <stdio.h>
+
+#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 (int * p, int len)
+{
+ int value;
+ len++; /* b0-size-test. */
+ value = *(p + len);
+}
+
+int
+main (void)
+{
+ if (have_mpx ())
+ {
+ int a = 0; /* Dummy variable for debugging purposes. */
+ int 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..6b099d6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp
@@ -0,0 +1,129 @@
+# Copyright (C) 2015 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
+ }
+}
+
+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.*"
+
+set segv_with_exit ".*Program received signal SIGSEGV,\
+ Segmentation fault.*$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
+ }
+}
+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_with_exit {
+ pass $parameters
+ }
+ -re "$gdb_prompt $" {
+ 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
+ }
+}
+
+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
+ }
+}
+
+gdb_test "where" "No stack." "no inferior $parameters"
--
2.1.4