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.
This commit is contained in:
parent
5f034a78b9
commit
012b3a217a
@ -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.
|
||||
|
14
gdb/NEWS
14
gdb/NEWS
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
@ -1035,6 +1037,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
|
||||
fprintf_unfiltered (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));
|
||||
@ -1999,6 +2007,30 @@ set_gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch,
|
||||
gdbarch->ax_pseudo_register_push_stack = ax_pseudo_register_push_stack;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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).
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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 ());
|
||||
|
@ -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. */
|
||||
|
18
gdb/infrun.c
18
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");
|
||||
|
@ -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):
|
||||
|
120
gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c
Normal file
120
gdb/testsuite/gdb.arch/i386-mpx-sigsegv.c
Normal file
@ -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;
|
||||
}
|
76
gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp
Normal file
76
gdb/testsuite/gdb.arch/i386-mpx-sigsegv.exp
Normal file
@ -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"
|
||||
}
|
66
gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c
Normal file
66
gdb/testsuite/gdb.arch/i386-mpx-simple_segv.c
Normal file
@ -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;
|
||||
}
|
140
gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp
Normal file
140
gdb/testsuite/gdb.arch/i386-mpx-simple_segv.exp
Normal file
@ -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"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user