diff options
-rw-r--r-- | gdb/ChangeLog | 17 | ||||
-rw-r--r-- | gdb/NEWS | 14 | ||||
-rw-r--r-- | gdb/amd64-linux-tdep.c | 2 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 27 | ||||
-rw-r--r-- | gdb/gdbarch.c | 32 | ||||
-rw-r--r-- | gdb/gdbarch.h | 12 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 7 | ||||
-rw-r--r-- | gdb/i386-linux-tdep.c | 68 | ||||
-rw-r--r-- | gdb/i386-linux-tdep.h | 5 | ||||
-rw-r--r-- | gdb/i386-tdep.c | 4 | ||||
-rw-r--r-- | gdb/i386-tdep.h | 2 | ||||
-rw-r--r-- | gdb/infrun.c | 18 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c | 120 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp | 76 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c | 66 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp | 140 |
18 files changed, 619 insertions, 3 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c8832c9..6fee07b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +2016-02-18 Walfred Tedeschi <walfred.tedeschi@intel.com> + + * NEWS: Add entry for bound violation. + * amd64-linux-tdep.c (amd64_linux_init_abi_common): + Add handler for segmentation fault. + * gdbarch.sh (handle_segmentation_fault): New. + * gdbarch.c: Regenerate. + * gdbarch.h: Regenerate. + * i386-linux-tdep.c (i386_linux_handle_segmentation_fault): New. + (SIG_CODE_BONDARY_FAULT): New define. + (i386_linux_init_abi): Use i386_mpx_bound_violation_handler. + * i386-linux-tdep.h (i386_linux_handle_segmentation_fault) New. + * i386-tdep.c (i386_mpx_enabled): Add as external. + * i386-tdep.c (i386_mpx_enabled): Add as external. + * infrun.c (handle_segmentation_fault): New function. + (print_signal_received_reason): Use handle_segmentation_fault. + 2016-02-18 Marcin KoĆcielnicki <koriakin@0x04.net> * arch-utils.c (default_guess_tracepoint_registers): New function. @@ -3,6 +3,20 @@ *** Changes since GDB 7.11 +* Intel MPX bound violation handling. + + Segmentation faults caused by a Intel MPX boundary violation + now display the kind of violation (upper or lower), the memory + address accessed and the memory bounds, along with the usual + signal received and code location. + + For example: + + Program received signal SIGSEGV, Segmentation fault + Upper bound violation while accessing address 0x7fffffffc3b3 + Bounds: [lower = 0x7fffffffc390, upper = 0x7fffffffc3a3] + 0x0000000000400d7c in upper () at i386-mpx-sigsegv.c:68 + *** Changes in GDB 7.11 * GDB now supports debugging kernel-based threads on FreeBSD. diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 21bcd99..4e82795 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_handle_segmentation_fault (gdbarch, + i386_linux_handle_segmentation_fault); } static void diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 8106d82..189dfdc 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2016-02-18 Walfred Tedeschi <walfred.tedeschi@intel.com> + + * gdb.texinfo (Signals): Add bound violation display hints for + a SIGSEGV. + 2016-02-18 Marcin KoĆcielnicki <koriakin@0x04.net> * gdb.texinfo (Trace File Format): Add documentation for description diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0028eda8..5db7cf2 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -5852,6 +5852,33 @@ $1 = (void *) 0x7ffff7ff7000 Depending on target support, @code{$_siginfo} may also be writable. +@cindex Intel MPX boundary violations +@cindex boundary violations, Intel MPX +On some targets, a @code{SIGSEGV} can be caused by a boundary +violation, i.e., accessing an address outside of the allowed range. +In those cases @value{GDBN} may displays additional information, +depending on how @value{GDBN} has been told to handle the signal. +With @code{handle stop SIGSEGV}, @value{GDBN} displays the violation +kind: "Upper" or "Lower", the memory address accessed and the +bounds, while with @code{handle nostop SIGSEGV} no additional +information is displayed. + +The usual output of a segfault is: +@smallexample +Program received signal SIGSEGV, Segmentation fault +0x0000000000400d7c in upper () at i386-mpx-sigsegv.c:68 +68 value = *(p + len); +@end smallexample + +While a bound violation is presented as: +@smallexample +Program received signal SIGSEGV, Segmentation fault +Upper bound violation while accessing address 0x7fffffffc3b3 +Bounds: [lower = 0x7fffffffc390, upper = 0x7fffffffc3a3] +0x0000000000400d7c in upper () at i386-mpx-sigsegv.c:68 +68 value = *(p + len); +@end smallexample + @node Thread Stops @section Stopping and Starting Multi-thread Programs diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 0136c75..bd0b48c 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_handle_segmentation_fault_ftype *handle_segmentation_fault; int sp_regnum; int pc_regnum; int ps_regnum; @@ -534,6 +535,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 handle_segmentation_fault, 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 */ @@ -1036,6 +1038,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: half_format = %s\n", pformat (gdbarch->half_format)); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_handle_segmentation_fault_p() = %d\n", + gdbarch_handle_segmentation_fault_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: handle_segmentation_fault = <%s>\n", + host_address_to_string (gdbarch->handle_segmentation_fault)); + fprintf_unfiltered (file, "gdbarch_dump: has_dos_based_file_system = %s\n", plongest (gdbarch->has_dos_based_file_system)); fprintf_unfiltered (file, @@ -2000,6 +2008,30 @@ set_gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch, } int +gdbarch_handle_segmentation_fault_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->handle_segmentation_fault != NULL; +} + +void +gdbarch_handle_segmentation_fault (struct gdbarch *gdbarch, struct ui_out *uiout) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->handle_segmentation_fault != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_handle_segmentation_fault called\n"); + gdbarch->handle_segmentation_fault (gdbarch, uiout); +} + +void +set_gdbarch_handle_segmentation_fault (struct gdbarch *gdbarch, + gdbarch_handle_segmentation_fault_ftype handle_segmentation_fault) +{ + gdbarch->handle_segmentation_fault = handle_segmentation_fault; +} + +int gdbarch_sp_regnum (struct gdbarch *gdbarch) { gdb_assert (gdbarch != NULL); diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 7ffbf1f..2225c76 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -64,6 +64,7 @@ struct elf_internal_linux_prpsinfo; struct mem_range; struct syscalls_info; struct thread_info; +struct ui_out; #include "regcache.h" @@ -300,6 +301,17 @@ 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); +/* Some targets/architectures can do extra processing/display of + segmentation faults. E.g., Intel MPX boundary faults. + Call the architecture dependent function to handle the fault. + UIOUT is the output stream where the handler will place information. */ + +extern int gdbarch_handle_segmentation_fault_p (struct gdbarch *gdbarch); + +typedef void (gdbarch_handle_segmentation_fault_ftype) (struct gdbarch *gdbarch, struct ui_out *uiout); +extern void gdbarch_handle_segmentation_fault (struct gdbarch *gdbarch, struct ui_out *uiout); +extern void set_gdbarch_handle_segmentation_fault (struct gdbarch *gdbarch, gdbarch_handle_segmentation_fault_ftype *handle_segmentation_fault); + /* 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 61cb04a..1d7377f 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -446,6 +446,12 @@ 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 +# Some targets/architectures can do extra processing/display of +# segmentation faults. E.g., Intel MPX boundary faults. +# Call the architecture dependent function to handle the fault. +# UIOUT is the output stream where the handler will place information. +M:void:handle_segmentation_fault: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). @@ -1257,6 +1263,7 @@ struct elf_internal_linux_prpsinfo; struct mem_range; struct syscalls_info; struct thread_info; +struct ui_out; #include "regcache.h" diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c index af39e78..63cda45 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,71 @@ i386_canonicalize_syscall (int syscall) return gdb_sys_no_syscall; } +/* Value of the sigcode in case of a boundary fault. */ + +#define SIG_CODE_BONDARY_FAULT 3 + +/* i386 GNU/Linux implementation of the handle_segmentation_fault + gdbarch hook. Displays information related to MPX bound + violations. */ +void +i386_linux_handle_segmentation_fault (struct gdbarch *gdbarch, + struct ui_out *uiout) +{ + CORE_ADDR lower_bound, upper_bound, access; + int is_upper; + long sig_code = 0; + + if (!i386_mpx_enabled ()) + return; + + TRY + { + /* Sigcode evaluates if the actual segfault is a boundary violation. */ + sig_code = parse_and_eval_long ("$_siginfo.si_code\n"); + + 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 + + /* If this is not a boundary violation just return. */ + if (sig_code != SIG_CODE_BONDARY_FAULT) + return; + + 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, _(" while accessing address ")); + ui_out_field_fmt (uiout, "bound-access", "%s", + paddress (gdbarch, access)); + + ui_out_text (uiout, _("\nBounds: [lower = ")); + ui_out_field_fmt (uiout, "lower-bound", "%s", + paddress (gdbarch, lower_bound)); + + ui_out_text (uiout, _(", upper = ")); + ui_out_field_fmt (uiout, "upper-bound", "%s", + paddress (gdbarch, upper_bound)); + + ui_out_text (uiout, _("]")); +} + /* 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 +1068,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_handle_segmentation_fault (gdbarch, + i386_linux_handle_segmentation_fault); } /* Provide a prototype to silence -Wmissing-prototypes. */ diff --git a/gdb/i386-linux-tdep.h b/gdb/i386-linux-tdep.h index ecc9e31..5c7a7f6 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); +/* Handle and display information related to the MPX bound violation + to the user. */ +extern void i386_linux_handle_segmentation_fault (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 db4cd0a..4c66edf 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -8729,9 +8729,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 770f59d..49dcce0 100644 --- a/gdb/i386-tdep.h +++ b/gdb/i386-tdep.h @@ -424,6 +424,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); +/* Return true iff the current target is MPX enabled. */ +extern int i386_mpx_enabled (void); /* Functions and variables exported from i386bsd-tdep.c. */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 15210c9..3e8c9e0 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -7904,6 +7904,20 @@ print_exited_reason (struct ui_out *uiout, int exitstatus) } } +/* Some targets/architectures can do extra processing/display of + segmentation faults. E.g., Intel MPX boundary faults. + Call the architecture dependent function to handle the fault. */ + +static void +handle_segmentation_fault (struct ui_out *uiout) +{ + struct regcache *regcache = get_current_regcache (); + struct gdbarch *gdbarch = get_regcache_arch (regcache); + + if (gdbarch_handle_segmentation_fault_p (gdbarch)) + gdbarch_handle_segmentation_fault (gdbarch, uiout); +} + void print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal) { @@ -7947,6 +7961,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_fault (uiout); + annotate_signal_string_end (); } ui_out_text (uiout, ".\n"); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 6882495..cedbb75 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2016-02-18 Walfred Tedeschi <walfred.tedeschi@intel.com> + + * gdb.arch/i386-mpx-sigsegv.c: New file. + * gdb.arch/i386-mpx-sigsegv.exp: New file. + * gdb.arch/i386-mpx-simple_segv.c: New file. + * gdb.arch/i386-mpx-simple_segv.exp: New file. + 2016-02-18 Yao Qi <yao.qi@linaro.org> * gdb.base/disp-step-syscall.exp (disp_step_cross_syscall): 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..70dfdb7 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2015-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 "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..164b2d0 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp @@ -0,0 +1,76 @@ +# Copyright (C) 2015-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 + } +} + +set u_fault [multi_line "Program received signal SIGSEGV, Segmentation fault" \ + "Upper bound violation while accessing address $hex" \ + "Bounds: \\\[lower = $hex, upper = $hex\\\]"] + +set l_fault [multi_line "Program received signal SIGSEGV, Segmentation fault" \ + "Lower bound violation while accessing address $hex" \ + "Bounds: \\\[lower = $hex, upper = $hex\\\]"] + +for {set i 0} {$i < 15} {incr i} { + set message "MPX signal segv Upper: ${i}" + + if {[gdb_test "continue" "$u_fault.*" $message] != 0} { + break + } + + gdb_test "where" ".*#0 $hex in upper.*"\ + "$message: should be in upper" +} + +for {set i 0} {$i < 15} {incr i} { + set message "MPX signal segv Lower: ${i}" + + if {[gdb_test "continue" "$l_fault.*" $message] != 0} { + break + } + + gdb_test "where" ".*#0 $hex 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..a26d238 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2015-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 "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..2eefc74 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp @@ -0,0 +1,140 @@ +# Copyright (C) 2015-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/>. + +# 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 +} + +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 violation [multi_line "Program received signal SIGSEGV, Segmentation fault" \ + "Upper bound violation while accessing address $hex" \ + "Bounds: \\\[lower = $hex, upper = $hex\\\]"] + +set segv_with_exit "Program received signal SIGSEGV,\ + Segmentation fault.*$inferior_exited_re.*" + + +# Test handler for segmentation fault for: +# print pass stop +# +set parameters "print pass stop" +with_test_prefix "$parameters" { + if ![runto_main] { + fail "could not run to main" + return -1 + } + + gdb_test "handle SIGSEGV $parameters"\ + ".*SIGSEGV.*Yes.*Yes.*Yes.*Segmentation fault.*"\ + "set parameters" + + gdb_test "continue" ".*$violation.*" "Display" + + gdb_test "where" ".*#0 $hex in upper.*"\ + "should be in upper" +} + +# Test handler for segmentation fault for: +# print pass nostop +# +set parameters "print pass nostop" +with_test_prefix "$parameters" { + if ![runto_main] { + fail "could not run to main" + return -1 + } + + gdb_test "handle SIGSEGV $parameters"\ + ".*SIGSEGV.*No.*Yes.*Yes.*Segmentation fault.*"\ + "set parameters" + + gdb_test "continue" ".*$segv_with_exit.*" "Display" + + gdb_test "where" "No stack." "no inferior" +} + +# Test handler for segmentation fault for: +# print nopass stop +# +set parameters "print nopass stop" +with_test_prefix "$parameters" { + if ![runto_main] { + fail "could not run to main" + return -1 + } + + gdb_test "handle SIGSEGV $parameters"\ + ".*SIGSEGV.*Yes.*Yes.*No.*Segmentation fault.*"\ + "set parameters" + + gdb_test "continue" ".*$violation.*" "Display" + + gdb_test "where" ".*#0 $hex in upper.*"\ + "should be in upper" +} + +# Test handler for segmentation fault for: +# print nopass stop +# +set parameters "noprint pass nostop" +with_test_prefix "$parameters" { + if ![runto_main] { + fail "could not run to main" + return -1 + } + + gdb_test "handle SIGSEGV $parameters"\ + ".*SIGSEGV.*No.*No.*Yes.*Segmentation fault.*"\ + "set parameters" + + gdb_test "continue" "Continuing\..*$inferior_exited_re.*"\ + "Display" + + gdb_test "where" "No stack." "no inferior" +} + |