Skip to content

Commit

Permalink
Intel(R) Memory Protection Extensions (Intel(R) MPX) support.
Browse files Browse the repository at this point in the history
Summary:

The Intel(R) Memory Protection Extensions (Intel(R) MPX) associates pointers
to bounds, against which the software can check memory references to
prevent out of bound memory access.

This patch allows accessing the MPX registers:
  * bnd0-3: 128-bit registers to hold the bound values,
  * bndcfgu, bndstatus: 64-bit configuration registers,

This patch also adds read/write tests for the MPX registers in the register
command tests and adds a new subdirectory for MPX specific tests.

Signed-off-by: Valentina Giusti <valentina.giusti@intel.com>

Reviewers: labath, granata.enrico, lldb-commits, clayborg

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D24187

llvm-svn: 280668
  • Loading branch information
Valentina Giusti committed Sep 5, 2016
1 parent 9bd34f9 commit f105abb
Show file tree
Hide file tree
Showing 17 changed files with 501 additions and 26 deletions.
@@ -0,0 +1,6 @@
LEVEL = ../../../make

CXX_SOURCES := main.cpp
CXXFLAGS += -mmpx -fcheck-pointer-bounds -fuse-ld=bfd
LDFLAGS += -mmpx -fcheck-pointer-bounds -fuse-ld=bfd
include $(LEVEL)/Makefile.rules
@@ -0,0 +1,59 @@
"""
Test the MPX registers.
"""

from __future__ import print_function

import os, sys, 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__)

def setUp(self):
TestBase.setUp(self)
self.has_teardown = False

def tearDown(self):
self.dbg.GetSelectedTarget().GetProcess().Destroy()
TestBase.tearDown(self)

@skipIfiOSSimulator
@skipIf(compiler="clang")
@expectedFailureAll(oslist=["linux"], compiler="gcc", compiler_version=["<", "5"])
@skipIf(archs=no_match(['amd64', 'i386', 'x86_64']))
def test_mpx_registers_with_example_code(self):
"""Test MPX registers with example code."""
self.build()
self.mpx_registers_with_example_code()

def mpx_registers_with_example_code(self):
"""Test MPX registers after running example code."""
self.line = line_number('main.cpp', '// Set a break point here.')

exe = os.path.join(os.getcwd(), "a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

self.runCmd('settings set target.inline-breakpoint-strategy always')
self.addTearDownHook(
lambda: self.runCmd("settings set target.inline-breakpoint-strategy always"))

lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.line, num_expected_locations=1)
self.runCmd("run", RUN_SUCCEEDED)

self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
substrs = ["stop reason = breakpoint 1."])

self.expect("register read -s 3",
substrs = ['bnd0 = {0x0000000000000010 0xffffffffffffffe6}',
'bnd1 = {0x0000000000000020 0xffffffffffffffd6}',
'bnd2 = {0x0000000000000030 0xffffffffffffffc6}',
'bnd3 = {0x0000000000000040 0xffffffffffffffb6}',
'bndcfgu = {0x01 0x80 0xb5 0x76 0xff 0x7f 0x00 0x00}',
'bndstatus = {0x02 0x80 0xb5 0x76 0xff 0x7f 0x00 0x00}'])
@@ -0,0 +1,69 @@
//===-- 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 <cpuid.h>
#include <cstddef>

int
main(int argc, char const *argv[])
{
unsigned int rax, rbx, rcx, rdx;

// Check if XSAVE is enabled.
if (!__get_cpuid(1, &rax, &rbx, &rcx, &rdx) || (rcx & bit_OSXSAVE) != bit_OSXSAVE)
return -1;

// Check if MPX is enabled.
if (__get_cpuid_max(0, NULL) > 7)
{
__cpuid_count(7, 0, rax, rbx, rcx, rdx);
if ((rbx & bit_MPX) != bit_MPX)
return -1;
}
else
return -1;

// Run MPX test code.
#if defined(__x86_64__)
asm("mov $16, %rax\n\t"
"mov $9, %rdx\n\t"
"bndmk (%rax,%rdx), %bnd0\n\t"
"mov $32, %rax\n\t"
"mov $9, %rdx\n\t"
"bndmk (%rax,%rdx), %bnd1\n\t"
"mov $48, %rax\n\t"
"mov $9, %rdx\n\t"
"bndmk (%rax,%rdx), %bnd2\n\t"
"mov $64, %rax\n\t"
"mov $9, %rdx\n\t"
"bndmk (%rax,%rdx), %bnd3\n\t"
"bndstx %bnd3, (%rax) \n\t"
"nop\n\t");
#endif
#if defined(__i386__)
asm("mov $16, %eax\n\t"
"mov $9, %edx\n\t"
"bndmk (%eax,%edx), %bnd0\n\t"
"mov $32, %eax\n\t"
"mov $9, %edx\n\t"
"bndmk (%eax,%edx), %bnd1\n\t"
"mov $48, %eax\n\t"
"mov $9, %edx\n\t"
"bndmk (%eax,%edx), %bnd2\n\t"
"mov $64, %eax\n\t"
"mov $9, %edx\n\t"
"bndmk (%eax,%edx), %bnd3\n\t"
"bndstx %bnd3, (%eax)\n\t"
"nop\n\t");
#endif
asm("nop\n\t"); // Set a break point here.

return 0;
}
@@ -1,4 +1,4 @@
LEVEL = ../../make
LEVEL = ../../../make

CXX_SOURCES := main.cpp a.cpp

Expand Down
Expand Up @@ -41,11 +41,12 @@ def test_register_commands(self):
if self.getArchitecture() in ['amd64', 'i386', 'x86_64']:
self.runCmd("register read xmm0")
self.runCmd("register read ymm15") # may be available
self.runCmd("register read bnd0") # may be available
elif self.getArchitecture() in ['arm']:
self.runCmd("register read s0")
self.runCmd("register read q15") # may be available

self.expect("register read -s 3", substrs = ['invalid register set index: 3'], error = True)
self.expect("register read -s 4", substrs = ['invalid register set index: 4'], error = True)

@skipIfiOSSimulator
@skipIfTargetAndroid(archs=["i386"]) # Writing of mxcsr register fails, presumably due to a kernel/hardware problem
Expand Down Expand Up @@ -289,12 +290,14 @@ def fp_register_write(self):
self.runCmd("register write " + st0regname + " \"{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}\"")
self.expect("register read " + st0regname + " --format f", substrs = [st0regname + ' = 0'])

has_avx = False
has_avx = False
has_mpx = False
registerSets = currentFrame.GetRegisters() # Returns an SBValueList.
for registerSet in registerSets:
if 'advanced vector extensions' in registerSet.GetName().lower():
has_avx = True
break
if 'memory protection extension' in registerSet.GetName().lower():
has_mpx = True

if has_avx:
new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0c 0x0d 0x0e 0x0f}"
Expand All @@ -304,6 +307,21 @@ def fp_register_write(self):
else:
self.runCmd("register read ymm0")

if has_mpx:
# Test write and read for bnd0.
new_value_w = "{0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10}"
self.runCmd("register write bnd0 \'" + new_value_w + "\'")
new_value_r = "{0x0807060504030201 0x100f0e0d0c0b0a09}"
self.expect("register read bnd0", substrs = ['bnd0 = ', new_value_r])
self.expect("expr $bnd0", substrs = ['vector_type'])

# Test write and for bndstatus.
new_value = "{0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08}"
self.write_and_read(currentFrame, "bndstatus", new_value)
self.expect("expr $bndstatus", substrs = ['vector_type'])
else:
self.runCmd("register read bnd0")

def convenience_registers(self):
"""Test convenience registers."""
self.common_setup()
Expand Down
15 changes: 13 additions & 2 deletions lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp
Expand Up @@ -104,7 +104,12 @@ enum dwarf_regnums
dwarf_mm4,
dwarf_mm5,
dwarf_mm6,
dwarf_mm7
dwarf_mm7,

dwarf_bnd0 = 101,
dwarf_bnd1,
dwarf_bnd2,
dwarf_bnd3
};

static RegisterInfo g_register_infos[] =
Expand Down Expand Up @@ -159,7 +164,13 @@ static RegisterInfo g_register_infos[] =
{ "ymm4" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm4 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "ymm5" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm5 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "ymm6" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm6 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "ymm7" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm7 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0}
{ "ymm7" , nullptr, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm7 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "bnd0" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{ dwarf_bnd0 , dwarf_bnd0 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "bnd1" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{ dwarf_bnd1 , dwarf_bnd1 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "bnd2" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{ dwarf_bnd2 , dwarf_bnd2 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "bnd3" , nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt64,{ dwarf_bnd3 , dwarf_bnd3 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "bndcfgu", nullptr, 8, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0},
{ "bndstatus", nullptr, 8, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0}
};

static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
Expand Down
14 changes: 12 additions & 2 deletions lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
Expand Up @@ -95,7 +95,11 @@ enum dwarf_regnums
dwarf_ymm12,
dwarf_ymm13,
dwarf_ymm14,
dwarf_ymm15
dwarf_ymm15,
dwarf_bnd0 = 126,
dwarf_bnd1,
dwarf_bnd2,
dwarf_bnd3
};

static RegisterInfo g_register_infos[] =
Expand Down Expand Up @@ -174,7 +178,13 @@ static RegisterInfo g_register_infos[] =
{ "ymm12" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm12 , dwarf_ymm12 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "ymm13" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm13 , dwarf_ymm13 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "ymm14" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm14 , dwarf_ymm14 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "ymm15" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm15 , dwarf_ymm15 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 }
{ "ymm15" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm15 , dwarf_ymm15 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "bnd0" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt64,{ dwarf_bnd0 , dwarf_bnd0 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "bnd1" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt64,{ dwarf_bnd1 , dwarf_bnd1 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "bnd2" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt64,{ dwarf_bnd2 , dwarf_bnd2 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "bnd3" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt64,{ dwarf_bnd3 , dwarf_bnd3 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "bndcfgu", nullptr,8, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
{ "bndstatus", nullptr,8, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 }
};

static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
Expand Down

0 comments on commit f105abb

Please sign in to comment.