diff options
author | Walfred Tedeschi <walfred.tedeschi@intel.com> | 2016-02-18 17:24:59 +0100 |
---|---|---|
committer | Walfred Tedeschi <walfred.tedeschi@intel.com> | 2016-02-18 17:25:49 +0100 |
commit | 012b3a217a60cc74b802b059029c72a25d77808c (patch) | |
tree | 63f0e9fb65406b6de748f61eb83a158bab54a021 /gdb/testsuite | |
parent | 5f034a78b986d30a90030b2409c61a8660b9b48c (diff) | |
download | gdb-012b3a217a60cc74b802b059029c72a25d77808c.zip gdb-012b3a217a60cc74b802b059029c72a25d77808c.tar.gz gdb-012b3a217a60cc74b802b059029c72a25d77808c.tar.bz2 |
Intel MPX bound violation handling
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 while accessing address 0x7fffffffc3b3
Bounds: [lower = 0x7fffffffc390, upper = 0x7fffffffc3a3]
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-02-18 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 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.
gdb/testsuite/ChangeLog:
* 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.
gdb/doc/ChangeLog:
* gdb.texinfo (Signals): Add bound violation display hints for
a SIGSEGV.
Diffstat (limited to 'gdb/testsuite')
-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 |
5 files changed, 409 insertions, 0 deletions
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" +} + |