Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/Makefile =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/Makefile +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/Makefile @@ -0,0 +1,7 @@ +LEVEL = ../../../../make + +CXX_SOURCES := main.cpp + +CFLAGS_EXTRAS += -mmpx -fcheck-pointer-bounds -fuse-ld=bfd + +include $(LEVEL)/Makefile.rules Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/TestBoundViolation.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/TestBoundViolation.py +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/TestBoundViolation.py @@ -0,0 +1,57 @@ +""" +Test the Intel(R) MPX bound violation signal. +""" + +from __future__ import print_function + + +import os +import sys +import time +import re +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class RegisterCommandsTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIf(compiler="clang") + @skipIf(oslist=no_match(['linux'])) + @skipIf(archs=no_match(['i386', 'x86_64'])) + @skipIf(oslist=["linux"], compiler="gcc", compiler_version=["<", "5"]) #GCC version >= 5 supports Intel(R) MPX. + def test_mpx_boundary_violation(self): + """Test Intel(R) MPX bound violation signal.""" + self.build() + self.mpx_boundary_violation() + + def mpx_boundary_violation(self): + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + self.runCmd("run", RUN_SUCCEEDED) + + target = self.dbg.GetSelectedTarget() + process = target.GetProcess() + + if (process.GetState() == lldb.eStateExited): + self.skipTest("Intel(R) MPX is not supported.") + + if (process.GetState() == lldb.eStateStopped): + self.expect("thread backtrace", STOPPED_DUE_TO_SIGNAL, + substrs = ['stop reason = signal SIGSEGV: upper bound violation', + 'fault address:', 'lower bound:', 'upper bound:']) + + self.runCmd("continue") + + if (process.GetState() == lldb.eStateStopped): + self.expect("thread backtrace", STOPPED_DUE_TO_SIGNAL, + substrs = ['stop reason = signal SIGSEGV: lower bound violation', + 'fault address:', 'lower bound:', 'upper bound:']) + + self.runCmd("continue") + self.assertTrue(process.GetState() == lldb.eStateExited, + PROCESS_EXITED) Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/main.cpp =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/main.cpp +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/main.cpp @@ -0,0 +1,40 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +//// +//// The LLVM Compiler Infrastructure +//// +//// This file is distributed under the University of Illinois Open Source +//// License. See LICENSE.TXT for details. +//// +////===----------------------------------------------------------------------===// +// + +#include +#include + +static void violate_upper_bound(int *ptr, int size) +{ + int i; + i = *(ptr + size); +} + +static void violate_lower_bound (int *ptr, int size) +{ + int i; + i = *(ptr - size); +} + +int +main(int argc, char const *argv[]) +{ + unsigned int rax, rbx, rcx, rdx; + int array[5]; + + // This call returns 0 only if the CPU and the kernel support Intel(R) MPX. + if (prctl(PR_MPX_ENABLE_MANAGEMENT, 0, 0, 0, 0) != 0) + return -1; + + violate_upper_bound(array, 5); + violate_lower_bound(array, 5); + + return 0; +} Index: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -316,8 +316,7 @@ (info->si_signo == SIGBUS && info->si_code == SI_KERNEL) ? CrashReason::eInvalidAddress : GetCrashReason(*info); - m_stop_description = GetCrashReasonString( - reason, reinterpret_cast(info->si_addr)); + m_stop_description = GetCrashReasonString(reason, *info); break; } } Index: lldb/trunk/source/Plugins/Process/POSIX/CrashReason.h =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/CrashReason.h +++ lldb/trunk/source/Plugins/Process/POSIX/CrashReason.h @@ -22,6 +22,7 @@ // SIGSEGV crash reasons. eInvalidAddress, ePrivilegedAddress, + eBoundViolation, // SIGILL crash reasons. eIllegalOpcode, @@ -49,7 +50,7 @@ eFloatSubscriptRange }; -std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr); +std::string GetCrashReasonString(CrashReason reason, const siginfo_t &info); const char *CrashReasonAsString(CrashReason reason); Index: lldb/trunk/source/Plugins/Process/POSIX/CrashReason.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/POSIX/CrashReason.cpp +++ lldb/trunk/source/Plugins/Process/POSIX/CrashReason.cpp @@ -9,6 +9,8 @@ #include "CrashReason.h" +#include "llvm/Support/raw_ostream.h" + #include namespace { @@ -19,6 +21,23 @@ str += ss.str(); } +void AppendBounds(std::string &str, lldb::addr_t lower_bound, + lldb::addr_t upper_bound, lldb::addr_t addr) { + llvm::raw_string_ostream stream(str); + if ((unsigned long)addr < lower_bound) + stream << ": lower bound violation "; + else + stream << ": upper bound violation "; + stream << "(fault address: 0x"; + stream.write_hex(addr); + stream << ", lower bound: 0x"; + stream.write_hex(lower_bound); + stream << ", upper bound: 0x"; + stream.write_hex(upper_bound); + stream << ")"; + stream.flush(); +} + CrashReason GetCrashReasonForSIGSEGV(const siginfo_t &info) { assert(info.si_signo == SIGSEGV); @@ -34,6 +53,11 @@ return CrashReason::eInvalidAddress; case SEGV_ACCERR: return CrashReason::ePrivilegedAddress; +#ifndef SEGV_BNDERR +#define SEGV_BNDERR 3 +#endif + case SEGV_BNDERR: + return CrashReason::eBoundViolation; } assert(false && "unexpected si_code for SIGSEGV"); @@ -109,7 +133,7 @@ } } -std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) { +std::string GetCrashReasonString(CrashReason reason, const siginfo_t &info) { std::string str; switch (reason) { @@ -119,11 +143,20 @@ case CrashReason::eInvalidAddress: str = "signal SIGSEGV: invalid address"; - AppendFaultAddr(str, fault_addr); + AppendFaultAddr(str, reinterpret_cast(info.si_addr)); break; case CrashReason::ePrivilegedAddress: str = "signal SIGSEGV: address access protected"; - AppendFaultAddr(str, fault_addr); + AppendFaultAddr(str, reinterpret_cast(info.si_addr)); + break; + case CrashReason::eBoundViolation: + str = "signal SIGSEGV"; +// Make sure that siginfo_t has the bound fields available. +#if defined(si_lower) && defined(si_upper) + AppendBounds(str, reinterpret_cast(info.si_lower), + reinterpret_cast(info.si_upper), + reinterpret_cast(info.si_addr)); +#endif break; case CrashReason::eIllegalOpcode: str = "signal SIGILL: illegal instruction"; @@ -207,6 +240,9 @@ case CrashReason::ePrivilegedAddress: str = "ePrivilegedAddress"; break; + case CrashReason::eBoundViolation: + str = "eBoundViolation"; + break; // SIGILL crash reasons. case CrashReason::eIllegalOpcode: