[Lldb-commits] [lldb] r293660 - Add a command to access and manipulate the Intel(R) MPX Boundary Tables.

Valentina Giusti via lldb-commits lldb-commits at lists.llvm.org
Tue Jan 31 10:02:55 PST 2017


Author: valentinagiusti
Date: Tue Jan 31 12:02:54 2017
New Revision: 293660

URL: http://llvm.org/viewvc/llvm-project?rev=293660&view=rev
Log:
Add a command to access and manipulate the Intel(R) MPX Boundary Tables.

Summary:
The Boundary Table Entries are stored in the application memory and allow
to store boundary info for all the pointers of the program, also those that
otherwise wouldn't fit in the 4 bound registers provided by the HW.

Here is an example of how it works:
 * mpx-table show <pointer>
        lbound = 0x..., ubound = 0x..., (pointer value = 0x..., metadata = 0x...)
 * mpx-table set <pointer>

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

Reviewers: labath, clayborg

Reviewed By: clayborg

Subscribers: lldb-commits, mgorny

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

Added:
    lldb/trunk/tools/intel-mpx/
    lldb/trunk/tools/intel-mpx/CMakeLists.txt
    lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp
    lldb/trunk/tools/intel-mpx/test/
    lldb/trunk/tools/intel-mpx/test/Makefile
    lldb/trunk/tools/intel-mpx/test/README.txt
    lldb/trunk/tools/intel-mpx/test/TestMPXTable.py
    lldb/trunk/tools/intel-mpx/test/main.cpp
Modified:
    lldb/trunk/tools/CMakeLists.txt

Modified: lldb/trunk/tools/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/CMakeLists.txt?rev=293660&r1=293659&r2=293660&view=diff
==============================================================================
--- lldb/trunk/tools/CMakeLists.txt (original)
+++ lldb/trunk/tools/CMakeLists.txt Tue Jan 31 12:02:54 2017
@@ -8,3 +8,4 @@ add_subdirectory(lldb-mi)
 if (LLDB_CAN_USE_LLDB_SERVER)
   add_subdirectory(lldb-server)
 endif()
+add_subdirectory(intel-mpx)

Added: lldb/trunk/tools/intel-mpx/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/CMakeLists.txt?rev=293660&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/CMakeLists.txt (added)
+++ lldb/trunk/tools/intel-mpx/CMakeLists.txt Tue Jan 31 12:02:54 2017
@@ -0,0 +1,23 @@
+if (NOT CMAKE_SYSTEM_NAME MATCHES "Linux")
+  return ()
+endif ()
+
+include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake)
+
+add_library(lldb-intel-mpxtable SHARED
+  IntelMPXTablePlugin.cpp
+  )
+
+target_link_libraries(lldb-intel-mpxtable PUBLIC liblldb)
+
+if (LLDB_LINKER_SUPPORTS_GROUPS)
+  target_link_libraries(lldb-intel-mpxtable PUBLIC
+                        -Wl,--start-group ${LLDB_USED_LIBS} -Wl,--end-group)
+else()
+  target_link_libraries(lldb-intel-mpxtable PUBLIC ${LLDB_USED_LIBS})
+endif()
+llvm_config(lldb-intel-mpxtable ${LLVM_LINK_COMPONENTS})
+
+
+install(TARGETS lldb-intel-mpxtable
+  LIBRARY DESTINATION bin)

Added: lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp?rev=293660&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp (added)
+++ lldb/trunk/tools/intel-mpx/IntelMPXTablePlugin.cpp Tue Jan 31 12:02:54 2017
@@ -0,0 +1,426 @@
+//===-- IntelMPXTablePlugin.cpp----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C++ includes
+#include <string>
+
+// Project includes
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBMemoryRegionInfo.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBThread.h"
+
+#include "llvm/ADT/Triple.h"
+
+namespace lldb {
+bool PluginInitialize(lldb::SBDebugger debugger);
+}
+
+static bool GetPtr(char *cptr, uint64_t &ptr, lldb::SBFrame &frame,
+                   lldb::SBCommandReturnObject &result) {
+  if (!cptr) {
+    result.SetError("Bad argument.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  lldb::SBValue ptr_addr = frame.GetValueForVariablePath(cptr);
+  if (!ptr_addr.IsValid()) {
+    result.SetError("Invalid pointer.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+  ptr = ptr_addr.GetLoadAddress();
+  return true;
+}
+
+enum {
+  mpx_base_mask_64 = ~(uint64_t)0xFFFULL,
+  mpx_bd_mask_64 = 0xFFFFFFF00000ULL,
+  bd_r_shift_64 = 20,
+  bd_l_shift_64 = 3,
+  bt_r_shift_64 = 3,
+  bt_l_shift_64 = 5,
+  bt_mask_64 = 0x0000000FFFF8ULL,
+
+  mpx_base_mask_32 = 0xFFFFFFFFFFFFF000ULL,
+  mpx_bd_mask_32 = 0xFFFFF000ULL,
+  bd_r_shift_32 = 12,
+  bd_l_shift_32 = 2,
+  bt_r_shift_32 = 2,
+  bt_l_shift_32 = 4,
+  bt_mask_32 = 0x00000FFCULL,
+};
+
+static void PrintBTEntry(lldb::addr_t lbound, lldb::addr_t ubound,
+                         uint64_t value, uint64_t meta,
+                         lldb::SBCommandReturnObject &result) {
+  const lldb::addr_t one_cmpl64 = ~((lldb::addr_t)0);
+  const lldb::addr_t one_cmpl32 = ~((uint32_t)0);
+
+  if ((lbound == one_cmpl64 || one_cmpl32) && ubound == 0) {
+    result.Printf("Null bounds on map: pointer value = 0x%lx\n", value);
+  } else {
+    result.Printf("    lbound = 0x%lx,", lbound);
+    result.Printf(" ubound = 0x%lx", ubound);
+    result.Printf(" (pointer value = 0x%lx,", value);
+    result.Printf(" metadata = 0x%lx)\n", meta);
+  }
+}
+
+static bool GetBTEntryAddr(uint64_t bndcfgu, uint64_t ptr,
+                           lldb::SBTarget &target, llvm::Triple::ArchType arch,
+                           size_t &size, lldb::addr_t &bt_entry_addr,
+                           lldb::SBCommandReturnObject &result,
+                           lldb::SBError &error) {
+  lldb::addr_t mpx_base_mask;
+  lldb::addr_t mpx_bd_mask;
+  lldb::addr_t bd_r_shift;
+  lldb::addr_t bd_l_shift;
+  lldb::addr_t bt_r_shift;
+  lldb::addr_t bt_l_shift;
+  lldb::addr_t bt_mask;
+
+  if (arch == llvm::Triple::ArchType::x86_64) {
+    mpx_base_mask = mpx_base_mask_64;
+    mpx_bd_mask = mpx_bd_mask_64;
+    bd_r_shift = bd_r_shift_64;
+    bd_l_shift = bd_l_shift_64;
+    bt_r_shift = bt_r_shift_64;
+    bt_l_shift = bt_l_shift_64;
+    bt_mask = bt_mask_64;
+  } else if (arch == llvm::Triple::ArchType::x86) {
+    mpx_base_mask = mpx_base_mask_32;
+    mpx_bd_mask = mpx_bd_mask_32;
+    bd_r_shift = bd_r_shift_32;
+    bd_l_shift = bd_l_shift_32;
+    bt_r_shift = bt_r_shift_32;
+    bt_l_shift = bt_l_shift_32;
+    bt_mask = bt_mask_32;
+  } else {
+    result.SetError("Invalid arch.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  size = target.GetAddressByteSize();
+  lldb::addr_t mpx_bd_base = bndcfgu & mpx_base_mask;
+  lldb::addr_t bd_entry_offset = ((ptr & mpx_bd_mask) >> bd_r_shift)
+                                 << bd_l_shift;
+  lldb::addr_t bd_entry_addr = mpx_bd_base + bd_entry_offset;
+
+  std::vector<uint8_t> bd_entry_v(size);
+  size_t ret = target.GetProcess().ReadMemory(
+      bd_entry_addr, static_cast<void *>(bd_entry_v.data()), size, error);
+  if (ret != size || !error.Success()) {
+    result.SetError("Failed access to BD entry.");
+    return false;
+  }
+
+  lldb::SBData data;
+  data.SetData(error, bd_entry_v.data(), bd_entry_v.size(),
+               target.GetByteOrder(), size);
+  lldb::addr_t bd_entry = data.GetAddress(error, 0);
+
+  if (!error.Success()) {
+    result.SetError("Failed access to BD entry.");
+    return false;
+  }
+
+  if ((bd_entry & 0x01) == 0) {
+    result.SetError("Invalid bound directory.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  // Clear status bit.
+  //
+  bd_entry--;
+
+  lldb::addr_t bt_addr = bd_entry & ~bt_r_shift;
+  lldb::addr_t bt_entry_offset = ((ptr & bt_mask) >> bt_r_shift) << bt_l_shift;
+  bt_entry_addr = bt_addr + bt_entry_offset;
+
+  return true;
+}
+
+static bool GetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::SBTarget &target,
+                       llvm::Triple::ArchType arch,
+                       lldb::SBCommandReturnObject &result,
+                       lldb::SBError &error) {
+  lldb::addr_t bt_entry_addr;
+  size_t size;
+  if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,
+                      error))
+    return false;
+
+  // bt_entry_v must have space to store the 4 elements of the BT entry (lower
+  // boundary,
+  // upper boundary, pointer value and meta data), which all have the same size
+  // 'size'.
+  //
+  std::vector<uint8_t> bt_entry_v(size * 4);
+  size_t ret = target.GetProcess().ReadMemory(
+      bt_entry_addr, static_cast<void *>(bt_entry_v.data()), size * 4, error);
+
+  if ((ret != (size * 4)) || !error.Success()) {
+    result.SetError("Unsuccessful. Failed access to BT entry.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  lldb::addr_t lbound;
+  lldb::addr_t ubound;
+  uint64_t value;
+  uint64_t meta;
+  lldb::SBData data;
+  data.SetData(error, bt_entry_v.data(), bt_entry_v.size(),
+               target.GetByteOrder(), size);
+  lbound = data.GetAddress(error, size * 0);
+  ubound = data.GetAddress(error, size * 1);
+  value = data.GetAddress(error, size * 2);
+  meta = data.GetAddress(error, size * 3);
+  // ubound is stored as one's complement.
+  if (arch == llvm::Triple::ArchType::x86) {
+    ubound = (~ubound) & 0x00000000FFFFFFFF;
+  } else {
+    ubound = ~ubound;
+  }
+
+  if (!error.Success()) {
+    result.SetError("Failed access to BT entry.");
+    return false;
+  }
+
+  PrintBTEntry(lbound, ubound, value, meta, result);
+
+  result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
+  return true;
+}
+
+static std::vector<uint8_t> uIntToU8(uint64_t input, size_t size) {
+  std::vector<uint8_t> output;
+  for (size_t i = 0; i < size; i++)
+    output.push_back(
+        static_cast<uint8_t>((input & (0xFFULL << (i * 8))) >> (i * 8)));
+
+  return output;
+}
+
+static bool SetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::addr_t lbound,
+                       lldb::addr_t ubound, lldb::SBTarget &target,
+                       llvm::Triple::ArchType arch,
+                       lldb::SBCommandReturnObject &result,
+                       lldb::SBError &error) {
+  lldb::addr_t bt_entry_addr;
+  size_t size;
+
+  if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,
+                      error))
+    return false;
+
+  // bt_entry_v must have space to store only 2 elements of the BT Entry, the
+  // lower boundary and the upper boundary, which both have size 'size'.
+  //
+  std::vector<uint8_t> bt_entry_v(size * 2);
+
+  std::vector<uint8_t> lbound_v = uIntToU8(lbound, size);
+  bt_entry_v.insert(bt_entry_v.begin(), lbound_v.begin(), lbound_v.end());
+  std::vector<uint8_t> ubound_v = uIntToU8(~ubound, size);
+  bt_entry_v.insert(bt_entry_v.begin() + size, ubound_v.begin(),
+                    ubound_v.end());
+
+  size_t ret = target.GetProcess().WriteMemory(
+      bt_entry_addr, (void *)(bt_entry_v.data()), size * 2, error);
+  if ((ret != (size * 2)) || !error.Success()) {
+    result.SetError("Failed access to BT entry.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
+  return true;
+}
+
+static bool GetInitInfo(lldb::SBDebugger debugger, lldb::SBTarget &target,
+                        llvm::Triple::ArchType &arch, uint64_t &bndcfgu,
+                        char *arg, uint64_t &ptr,
+                        lldb::SBCommandReturnObject &result,
+                        lldb::SBError &error) {
+  target = debugger.GetSelectedTarget();
+  if (!target.IsValid()) {
+    result.SetError("Invalid target.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  const std::string triple_s(target.GetTriple());
+  const llvm::Triple triple(triple_s);
+
+  arch = triple.getArch();
+
+  if ((arch != llvm::Triple::ArchType::x86) &&
+      (arch != llvm::Triple::ArchType::x86_64)) {
+    result.SetError("Platform not supported.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  lldb::SBFrame frame =
+      target.GetProcess().GetSelectedThread().GetSelectedFrame();
+  if (!frame.IsValid()) {
+    result.SetError("No valid process, thread or frame.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  lldb::SBValue bndcfgu_val = frame.FindRegister("bndcfgu");
+  if (!bndcfgu_val.IsValid()) {
+    result.SetError(
+        "Cannot access register BNDCFGU. Does the target support MPX?");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+
+  lldb::SBData bndcfgu_data = bndcfgu_val.GetData();
+  bndcfgu = bndcfgu_data.GetUnsignedInt64(error, 0);
+  if (!error.Success()) {
+    result.SetError(error, "Invalid read of register BNDCFGU.");
+    return false;
+  }
+
+  if (!GetPtr(arg, ptr, frame, result))
+    return false;
+
+  return true;
+}
+
+class MPXTableShow : public lldb::SBCommandPluginInterface {
+public:
+  virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
+                         lldb::SBCommandReturnObject &result) {
+
+    if (command) {
+      int arg_c = 0;
+      char *arg;
+
+      while (*command) {
+        if (arg_c >= 1) {
+          result.SetError("Too many arguments. See help.");
+          result.SetStatus(lldb::eReturnStatusFailed);
+          return false;
+        }
+        arg_c++;
+        arg = *command;
+        command++;
+      }
+
+      if (!debugger.IsValid()) {
+        result.SetError("Invalid debugger.");
+        result.SetStatus(lldb::eReturnStatusFailed);
+        return false;
+      }
+
+      lldb::SBTarget target;
+      llvm::Triple::ArchType arch;
+      lldb::SBError error;
+      uint64_t bndcfgu;
+      uint64_t ptr;
+
+      if (!GetInitInfo(debugger, target, arch, bndcfgu, arg, ptr, result,
+                       error))
+        return false;
+
+      return GetBTEntry(bndcfgu, ptr, target, arch, result, error);
+    }
+
+    result.SetError("Too few arguments. See help.");
+    result.SetStatus(lldb::eReturnStatusFailed);
+    return false;
+  }
+};
+
+class MPXTableSet : public lldb::SBCommandPluginInterface {
+public:
+  virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
+                         lldb::SBCommandReturnObject &result) {
+
+    if (command) {
+      int arg_c = 0;
+      char *arg[3];
+
+      while (*command) {
+        arg[arg_c] = *command;
+        command++;
+        arg_c++;
+      }
+
+      if (arg_c != 3) {
+        result.SetError("Wrong arguments. See help.");
+        return false;
+      }
+
+      if (!debugger.IsValid()) {
+        result.SetError("Invalid debugger.");
+        return false;
+      }
+
+      lldb::SBTarget target;
+      llvm::Triple::ArchType arch;
+      lldb::SBError error;
+      uint64_t bndcfgu;
+      uint64_t ptr;
+
+      if (!GetInitInfo(debugger, target, arch, bndcfgu, arg[0], ptr, result,
+                       error))
+        return false;
+
+      char *endptr;
+      errno = 0;
+      uint64_t lbound = std::strtoul(arg[1], &endptr, 16);
+      if (endptr == arg[1] || errno == ERANGE) {
+        result.SetError("Lower Bound: bad argument format.");
+        errno = 0;
+        return false;
+      }
+
+      uint64_t ubound = std::strtoul(arg[2], &endptr, 16);
+      if (endptr == arg[1] || errno == ERANGE) {
+        result.SetError("Upper Bound: bad argument format.");
+        errno = 0;
+        return false;
+      }
+
+      return SetBTEntry(bndcfgu, ptr, lbound, ubound, target, arch, result,
+                        error);
+    }
+
+    result.SetError("Too few arguments. See help.");
+    return false;
+  }
+};
+
+bool lldb::PluginInitialize(lldb::SBDebugger debugger) {
+  lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+  lldb::SBCommand mpxTable = interpreter.AddMultiwordCommand(
+      "mpx-table", "A utility to access the MPX table entries.");
+
+  const char *mpx_show_help = "Show the MPX table entry of a pointer.\n"
+                              "mpx-table show <pointer>";
+  mpxTable.AddCommand("show", new MPXTableShow(), mpx_show_help);
+
+  const char *mpx_set_help =
+      "Set the MPX table entry of a pointer.\n"
+      "mpx-table set <pointer> <lower bound> <upper bound>";
+  mpxTable.AddCommand("set", new MPXTableSet(), mpx_set_help);
+
+  return true;
+}

Added: lldb/trunk/tools/intel-mpx/test/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/test/Makefile?rev=293660&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/Makefile (added)
+++ lldb/trunk/tools/intel-mpx/test/Makefile Tue Jan 31 12:02:54 2017
@@ -0,0 +1,7 @@
+LEVEL = ../../../../make
+
+CXX_SOURCES := main.cpp
+
+CFLAGS_EXTRAS += -mmpx -fcheck-pointer-bounds -lmpxwrappers -lmpx -fuse-ld=bfd
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/tools/intel-mpx/test/README.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/test/README.txt?rev=293660&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/README.txt (added)
+++ lldb/trunk/tools/intel-mpx/test/README.txt Tue Jan 31 12:02:54 2017
@@ -0,0 +1,6 @@
+In order to run this test, create the following directory:
+
+    packages/Python/lldbsuite/test/functionalities/plugins/commands/mpxtablecmd
+
+and copy into it the contents of this direcotry.
+

Added: lldb/trunk/tools/intel-mpx/test/TestMPXTable.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/test/TestMPXTable.py?rev=293660&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/TestMPXTable.py (added)
+++ lldb/trunk/tools/intel-mpx/test/TestMPXTable.py Tue Jan 31 12:02:54 2017
@@ -0,0 +1,168 @@
+"""
+Test mpx-table command.
+"""
+
+from __future__ import print_function
+
+
+import os
+import time
+import re
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestMPXTable(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        TestBase.setUp(self)
+
+    @skipIf(compiler="clang")
+    @skipIf(oslist=no_match(['linux']))
+    @skipIf(archs=no_match(['i386', 'x86_64']))
+    @skipIf(compiler="gcc", compiler_version=["<", "5"]) #GCC version >= 5 supports Intel(R) MPX.
+    def test_show_command(self):
+        """Test 'mpx-table show' command"""
+        self.build()
+
+        lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"]
+        lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib")
+        plugin_file = os.path.join(lldb_lib_dir, "liblldb-intel-mpxtable.so")
+        if not os.path.isfile(plugin_file):
+            self.skipTest("Intel(R) mpx-table plugin missing.")
+        plugin_command = " "
+        seq = ("plugin", "load", plugin_file)
+        plugin_command = plugin_command.join(seq)
+        self.runCmd(plugin_command)
+
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        self.b1 = line_number('main.cpp', '// Break 1.')
+        self.b2 = line_number('main.cpp', '// Break 2.')
+        self.b3 = line_number('main.cpp', '// Break 3.')
+        self.b4 = line_number('main.cpp', '// Break 4.')
+        lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b1, num_expected_locations=1)
+        lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b2, num_expected_locations=1)
+        lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b3, num_expected_locations=1)
+        lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b4, num_expected_locations=1)
+        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.")
+        else:
+            self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
+                        substrs = ["stop reason = breakpoint 1."])
+
+        self.expect("mpx-table show a",
+                     substrs = ['lbound = 0x',
+                                ', ubound = 0x',
+                                '(pointer value = 0x',
+                                ', metadata = 0x',
+                                ')'],
+                     error = False)
+
+        self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
+                     substrs = ["stop reason = breakpoint 2."])
+
+        # Check that out of scope pointer cannot be reached.
+        #
+        self.expect("mpx-table show a",
+                     substrs = ['Invalid pointer.'],
+                     error = True)
+
+        self.expect("mpx-table show tmp",
+                     substrs = ['lbound = 0x',
+                                ', ubound = 0x',
+                                '(pointer value = 0x',
+                                ', metadata = 0x',
+                                ')'],
+                     error = False)
+
+        self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
+                     substrs = ["stop reason = breakpoint 3."])
+
+        # Check that the pointer value is correctly updated.
+        #
+        self.expect("mpx-table show tmp",
+                     substrs = ['lbound = 0x',
+                                ', ubound = 0x',
+                                '(pointer value = 0x2',
+                                ', metadata = 0x',
+                                ')'],
+                     error = False)
+
+        self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
+                     substrs = ["stop reason = breakpoint 4."])
+
+        # After going back to main(), check that out of scope pointer cannot be
+        # reached.
+        #
+        self.expect("mpx-table show tmp",
+                     substrs = ['Invalid pointer.'],
+                     error = True)
+
+        self.expect("mpx-table show a",
+                     substrs = ['lbound = 0x',
+                                ', ubound = 0x',
+                                '(pointer value = 0x',
+                                ', metadata = 0x',
+                                ')'],
+                     error = False)
+
+    def test_set_command(self):
+        """Test 'mpx-table set' command"""
+        self.build()
+
+        lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"]
+        lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib")
+        plugin_file = os.path.join(lldb_lib_dir, "liblldb-intel-mpxtable.so")
+        if not os.path.isfile(plugin_file):
+            self.skipTest("Intel(R) mpx-table plugin missing.")
+        plugin_command = " "
+        seq = ("plugin", "load", plugin_file)
+        plugin_command = plugin_command.join(seq)
+        self.runCmd(plugin_command)
+
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        self.b1 = line_number('main.cpp', '// Break 1.')
+        lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b1, num_expected_locations=1)
+        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.")
+        else:
+            self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
+                        substrs = ["stop reason = breakpoint 1."])
+
+        # Check that the BT Entry doesn't already contain the test values.
+        #
+        self.expect("mpx-table show a", matching=False,
+                     substrs = ['lbound = 0xcafecafe',
+                                ', ubound = 0xbeefbeef'])
+
+        # Set the test values.
+        #
+        self.expect("mpx-table set a 0xcafecafe 0xbeefbeef", error = False)
+
+        # Verify that the test values have been correctly written in the BT
+        # entry.
+        #
+        self.expect("mpx-table show a",
+                     substrs = ['lbound = 0xcafecafe',
+                                ', ubound = 0xbeefbeef'],
+                     error = False)
+
+

Added: lldb/trunk/tools/intel-mpx/test/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/intel-mpx/test/main.cpp?rev=293660&view=auto
==============================================================================
--- lldb/trunk/tools/intel-mpx/test/main.cpp (added)
+++ lldb/trunk/tools/intel-mpx/test/main.cpp Tue Jan 31 12:02:54 2017
@@ -0,0 +1,48 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+////
+////                     The LLVM Compiler Infrastructure
+////
+//// This file is distributed under the University of Illinois Open Source
+//// License. See LICENSE.TXT for details.
+////
+////===----------------------------------------------------------------------===//
+//
+
+const int size = 5;
+
+#include <cstddef>
+#include <cstdlib>
+#include <sys/prctl.h>
+
+void func(int *ptr) {
+  int *tmp;
+
+#if defined  __GNUC__ && !defined __INTEL_COMPILER
+  __builtin___bnd_store_ptr_bounds ((void**)&ptr, ptr);
+#endif
+  tmp = ptr + size - 1;
+#if defined  __GNUC__ && !defined __INTEL_COMPILER
+  __builtin___bnd_store_ptr_bounds ((void**)&tmp, tmp);
+#endif
+  tmp = (int*)0x2; // Break 2.
+
+  return; // Break 3.
+}
+
+int
+main(int argc, char const *argv[])
+{
+  // 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;
+
+  int*  a = (int *) calloc(size, sizeof(int));
+#if defined  __GNUC__ && !defined __INTEL_COMPILER
+  __builtin___bnd_store_ptr_bounds ((void**)&a, a);
+#endif
+  func(a); // Break 1.
+
+  free(a); // Break 4.
+
+  return 0;
+}




More information about the lldb-commits mailing list