Skip to content

Commit c0eeee7

Browse files
author
Valentina Giusti
committedJan 31, 2017
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@intel.com> Reviewers: labath, clayborg Reviewed By: clayborg Subscribers: lldb-commits, mgorny Differential Revision: https://reviews.llvm.org/D29078 llvm-svn: 293660
1 parent c368563 commit c0eeee7

File tree

7 files changed

+679
-0
lines changed

7 files changed

+679
-0
lines changed
 

‎lldb/tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ add_subdirectory(lldb-mi)
88
if (LLDB_CAN_USE_LLDB_SERVER)
99
add_subdirectory(lldb-server)
1010
endif()
11+
add_subdirectory(intel-mpx)

‎lldb/tools/intel-mpx/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
if (NOT CMAKE_SYSTEM_NAME MATCHES "Linux")
2+
return ()
3+
endif ()
4+
5+
include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake)
6+
7+
add_library(lldb-intel-mpxtable SHARED
8+
IntelMPXTablePlugin.cpp
9+
)
10+
11+
target_link_libraries(lldb-intel-mpxtable PUBLIC liblldb)
12+
13+
if (LLDB_LINKER_SUPPORTS_GROUPS)
14+
target_link_libraries(lldb-intel-mpxtable PUBLIC
15+
-Wl,--start-group ${LLDB_USED_LIBS} -Wl,--end-group)
16+
else()
17+
target_link_libraries(lldb-intel-mpxtable PUBLIC ${LLDB_USED_LIBS})
18+
endif()
19+
llvm_config(lldb-intel-mpxtable ${LLVM_LINK_COMPONENTS})
20+
21+
22+
install(TARGETS lldb-intel-mpxtable
23+
LIBRARY DESTINATION bin)
Lines changed: 426 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,426 @@
1+
//===-- IntelMPXTablePlugin.cpp----------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// C++ includes
11+
#include <string>
12+
13+
// Project includes
14+
#include "lldb/API/SBCommandInterpreter.h"
15+
#include "lldb/API/SBCommandReturnObject.h"
16+
#include "lldb/API/SBMemoryRegionInfo.h"
17+
#include "lldb/API/SBProcess.h"
18+
#include "lldb/API/SBTarget.h"
19+
#include "lldb/API/SBThread.h"
20+
21+
#include "llvm/ADT/Triple.h"
22+
23+
namespace lldb {
24+
bool PluginInitialize(lldb::SBDebugger debugger);
25+
}
26+
27+
static bool GetPtr(char *cptr, uint64_t &ptr, lldb::SBFrame &frame,
28+
lldb::SBCommandReturnObject &result) {
29+
if (!cptr) {
30+
result.SetError("Bad argument.");
31+
result.SetStatus(lldb::eReturnStatusFailed);
32+
return false;
33+
}
34+
35+
lldb::SBValue ptr_addr = frame.GetValueForVariablePath(cptr);
36+
if (!ptr_addr.IsValid()) {
37+
result.SetError("Invalid pointer.");
38+
result.SetStatus(lldb::eReturnStatusFailed);
39+
return false;
40+
}
41+
ptr = ptr_addr.GetLoadAddress();
42+
return true;
43+
}
44+
45+
enum {
46+
mpx_base_mask_64 = ~(uint64_t)0xFFFULL,
47+
mpx_bd_mask_64 = 0xFFFFFFF00000ULL,
48+
bd_r_shift_64 = 20,
49+
bd_l_shift_64 = 3,
50+
bt_r_shift_64 = 3,
51+
bt_l_shift_64 = 5,
52+
bt_mask_64 = 0x0000000FFFF8ULL,
53+
54+
mpx_base_mask_32 = 0xFFFFFFFFFFFFF000ULL,
55+
mpx_bd_mask_32 = 0xFFFFF000ULL,
56+
bd_r_shift_32 = 12,
57+
bd_l_shift_32 = 2,
58+
bt_r_shift_32 = 2,
59+
bt_l_shift_32 = 4,
60+
bt_mask_32 = 0x00000FFCULL,
61+
};
62+
63+
static void PrintBTEntry(lldb::addr_t lbound, lldb::addr_t ubound,
64+
uint64_t value, uint64_t meta,
65+
lldb::SBCommandReturnObject &result) {
66+
const lldb::addr_t one_cmpl64 = ~((lldb::addr_t)0);
67+
const lldb::addr_t one_cmpl32 = ~((uint32_t)0);
68+
69+
if ((lbound == one_cmpl64 || one_cmpl32) && ubound == 0) {
70+
result.Printf("Null bounds on map: pointer value = 0x%lx\n", value);
71+
} else {
72+
result.Printf(" lbound = 0x%lx,", lbound);
73+
result.Printf(" ubound = 0x%lx", ubound);
74+
result.Printf(" (pointer value = 0x%lx,", value);
75+
result.Printf(" metadata = 0x%lx)\n", meta);
76+
}
77+
}
78+
79+
static bool GetBTEntryAddr(uint64_t bndcfgu, uint64_t ptr,
80+
lldb::SBTarget &target, llvm::Triple::ArchType arch,
81+
size_t &size, lldb::addr_t &bt_entry_addr,
82+
lldb::SBCommandReturnObject &result,
83+
lldb::SBError &error) {
84+
lldb::addr_t mpx_base_mask;
85+
lldb::addr_t mpx_bd_mask;
86+
lldb::addr_t bd_r_shift;
87+
lldb::addr_t bd_l_shift;
88+
lldb::addr_t bt_r_shift;
89+
lldb::addr_t bt_l_shift;
90+
lldb::addr_t bt_mask;
91+
92+
if (arch == llvm::Triple::ArchType::x86_64) {
93+
mpx_base_mask = mpx_base_mask_64;
94+
mpx_bd_mask = mpx_bd_mask_64;
95+
bd_r_shift = bd_r_shift_64;
96+
bd_l_shift = bd_l_shift_64;
97+
bt_r_shift = bt_r_shift_64;
98+
bt_l_shift = bt_l_shift_64;
99+
bt_mask = bt_mask_64;
100+
} else if (arch == llvm::Triple::ArchType::x86) {
101+
mpx_base_mask = mpx_base_mask_32;
102+
mpx_bd_mask = mpx_bd_mask_32;
103+
bd_r_shift = bd_r_shift_32;
104+
bd_l_shift = bd_l_shift_32;
105+
bt_r_shift = bt_r_shift_32;
106+
bt_l_shift = bt_l_shift_32;
107+
bt_mask = bt_mask_32;
108+
} else {
109+
result.SetError("Invalid arch.");
110+
result.SetStatus(lldb::eReturnStatusFailed);
111+
return false;
112+
}
113+
114+
size = target.GetAddressByteSize();
115+
lldb::addr_t mpx_bd_base = bndcfgu & mpx_base_mask;
116+
lldb::addr_t bd_entry_offset = ((ptr & mpx_bd_mask) >> bd_r_shift)
117+
<< bd_l_shift;
118+
lldb::addr_t bd_entry_addr = mpx_bd_base + bd_entry_offset;
119+
120+
std::vector<uint8_t> bd_entry_v(size);
121+
size_t ret = target.GetProcess().ReadMemory(
122+
bd_entry_addr, static_cast<void *>(bd_entry_v.data()), size, error);
123+
if (ret != size || !error.Success()) {
124+
result.SetError("Failed access to BD entry.");
125+
return false;
126+
}
127+
128+
lldb::SBData data;
129+
data.SetData(error, bd_entry_v.data(), bd_entry_v.size(),
130+
target.GetByteOrder(), size);
131+
lldb::addr_t bd_entry = data.GetAddress(error, 0);
132+
133+
if (!error.Success()) {
134+
result.SetError("Failed access to BD entry.");
135+
return false;
136+
}
137+
138+
if ((bd_entry & 0x01) == 0) {
139+
result.SetError("Invalid bound directory.");
140+
result.SetStatus(lldb::eReturnStatusFailed);
141+
return false;
142+
}
143+
144+
// Clear status bit.
145+
//
146+
bd_entry--;
147+
148+
lldb::addr_t bt_addr = bd_entry & ~bt_r_shift;
149+
lldb::addr_t bt_entry_offset = ((ptr & bt_mask) >> bt_r_shift) << bt_l_shift;
150+
bt_entry_addr = bt_addr + bt_entry_offset;
151+
152+
return true;
153+
}
154+
155+
static bool GetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::SBTarget &target,
156+
llvm::Triple::ArchType arch,
157+
lldb::SBCommandReturnObject &result,
158+
lldb::SBError &error) {
159+
lldb::addr_t bt_entry_addr;
160+
size_t size;
161+
if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,
162+
error))
163+
return false;
164+
165+
// bt_entry_v must have space to store the 4 elements of the BT entry (lower
166+
// boundary,
167+
// upper boundary, pointer value and meta data), which all have the same size
168+
// 'size'.
169+
//
170+
std::vector<uint8_t> bt_entry_v(size * 4);
171+
size_t ret = target.GetProcess().ReadMemory(
172+
bt_entry_addr, static_cast<void *>(bt_entry_v.data()), size * 4, error);
173+
174+
if ((ret != (size * 4)) || !error.Success()) {
175+
result.SetError("Unsuccessful. Failed access to BT entry.");
176+
result.SetStatus(lldb::eReturnStatusFailed);
177+
return false;
178+
}
179+
180+
lldb::addr_t lbound;
181+
lldb::addr_t ubound;
182+
uint64_t value;
183+
uint64_t meta;
184+
lldb::SBData data;
185+
data.SetData(error, bt_entry_v.data(), bt_entry_v.size(),
186+
target.GetByteOrder(), size);
187+
lbound = data.GetAddress(error, size * 0);
188+
ubound = data.GetAddress(error, size * 1);
189+
value = data.GetAddress(error, size * 2);
190+
meta = data.GetAddress(error, size * 3);
191+
// ubound is stored as one's complement.
192+
if (arch == llvm::Triple::ArchType::x86) {
193+
ubound = (~ubound) & 0x00000000FFFFFFFF;
194+
} else {
195+
ubound = ~ubound;
196+
}
197+
198+
if (!error.Success()) {
199+
result.SetError("Failed access to BT entry.");
200+
return false;
201+
}
202+
203+
PrintBTEntry(lbound, ubound, value, meta, result);
204+
205+
result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
206+
return true;
207+
}
208+
209+
static std::vector<uint8_t> uIntToU8(uint64_t input, size_t size) {
210+
std::vector<uint8_t> output;
211+
for (size_t i = 0; i < size; i++)
212+
output.push_back(
213+
static_cast<uint8_t>((input & (0xFFULL << (i * 8))) >> (i * 8)));
214+
215+
return output;
216+
}
217+
218+
static bool SetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::addr_t lbound,
219+
lldb::addr_t ubound, lldb::SBTarget &target,
220+
llvm::Triple::ArchType arch,
221+
lldb::SBCommandReturnObject &result,
222+
lldb::SBError &error) {
223+
lldb::addr_t bt_entry_addr;
224+
size_t size;
225+
226+
if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,
227+
error))
228+
return false;
229+
230+
// bt_entry_v must have space to store only 2 elements of the BT Entry, the
231+
// lower boundary and the upper boundary, which both have size 'size'.
232+
//
233+
std::vector<uint8_t> bt_entry_v(size * 2);
234+
235+
std::vector<uint8_t> lbound_v = uIntToU8(lbound, size);
236+
bt_entry_v.insert(bt_entry_v.begin(), lbound_v.begin(), lbound_v.end());
237+
std::vector<uint8_t> ubound_v = uIntToU8(~ubound, size);
238+
bt_entry_v.insert(bt_entry_v.begin() + size, ubound_v.begin(),
239+
ubound_v.end());
240+
241+
size_t ret = target.GetProcess().WriteMemory(
242+
bt_entry_addr, (void *)(bt_entry_v.data()), size * 2, error);
243+
if ((ret != (size * 2)) || !error.Success()) {
244+
result.SetError("Failed access to BT entry.");
245+
result.SetStatus(lldb::eReturnStatusFailed);
246+
return false;
247+
}
248+
249+
result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
250+
return true;
251+
}
252+
253+
static bool GetInitInfo(lldb::SBDebugger debugger, lldb::SBTarget &target,
254+
llvm::Triple::ArchType &arch, uint64_t &bndcfgu,
255+
char *arg, uint64_t &ptr,
256+
lldb::SBCommandReturnObject &result,
257+
lldb::SBError &error) {
258+
target = debugger.GetSelectedTarget();
259+
if (!target.IsValid()) {
260+
result.SetError("Invalid target.");
261+
result.SetStatus(lldb::eReturnStatusFailed);
262+
return false;
263+
}
264+
265+
const std::string triple_s(target.GetTriple());
266+
const llvm::Triple triple(triple_s);
267+
268+
arch = triple.getArch();
269+
270+
if ((arch != llvm::Triple::ArchType::x86) &&
271+
(arch != llvm::Triple::ArchType::x86_64)) {
272+
result.SetError("Platform not supported.");
273+
result.SetStatus(lldb::eReturnStatusFailed);
274+
return false;
275+
}
276+
277+
lldb::SBFrame frame =
278+
target.GetProcess().GetSelectedThread().GetSelectedFrame();
279+
if (!frame.IsValid()) {
280+
result.SetError("No valid process, thread or frame.");
281+
result.SetStatus(lldb::eReturnStatusFailed);
282+
return false;
283+
}
284+
285+
lldb::SBValue bndcfgu_val = frame.FindRegister("bndcfgu");
286+
if (!bndcfgu_val.IsValid()) {
287+
result.SetError(
288+
"Cannot access register BNDCFGU. Does the target support MPX?");
289+
result.SetStatus(lldb::eReturnStatusFailed);
290+
return false;
291+
}
292+
293+
lldb::SBData bndcfgu_data = bndcfgu_val.GetData();
294+
bndcfgu = bndcfgu_data.GetUnsignedInt64(error, 0);
295+
if (!error.Success()) {
296+
result.SetError(error, "Invalid read of register BNDCFGU.");
297+
return false;
298+
}
299+
300+
if (!GetPtr(arg, ptr, frame, result))
301+
return false;
302+
303+
return true;
304+
}
305+
306+
class MPXTableShow : public lldb::SBCommandPluginInterface {
307+
public:
308+
virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
309+
lldb::SBCommandReturnObject &result) {
310+
311+
if (command) {
312+
int arg_c = 0;
313+
char *arg;
314+
315+
while (*command) {
316+
if (arg_c >= 1) {
317+
result.SetError("Too many arguments. See help.");
318+
result.SetStatus(lldb::eReturnStatusFailed);
319+
return false;
320+
}
321+
arg_c++;
322+
arg = *command;
323+
command++;
324+
}
325+
326+
if (!debugger.IsValid()) {
327+
result.SetError("Invalid debugger.");
328+
result.SetStatus(lldb::eReturnStatusFailed);
329+
return false;
330+
}
331+
332+
lldb::SBTarget target;
333+
llvm::Triple::ArchType arch;
334+
lldb::SBError error;
335+
uint64_t bndcfgu;
336+
uint64_t ptr;
337+
338+
if (!GetInitInfo(debugger, target, arch, bndcfgu, arg, ptr, result,
339+
error))
340+
return false;
341+
342+
return GetBTEntry(bndcfgu, ptr, target, arch, result, error);
343+
}
344+
345+
result.SetError("Too few arguments. See help.");
346+
result.SetStatus(lldb::eReturnStatusFailed);
347+
return false;
348+
}
349+
};
350+
351+
class MPXTableSet : public lldb::SBCommandPluginInterface {
352+
public:
353+
virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
354+
lldb::SBCommandReturnObject &result) {
355+
356+
if (command) {
357+
int arg_c = 0;
358+
char *arg[3];
359+
360+
while (*command) {
361+
arg[arg_c] = *command;
362+
command++;
363+
arg_c++;
364+
}
365+
366+
if (arg_c != 3) {
367+
result.SetError("Wrong arguments. See help.");
368+
return false;
369+
}
370+
371+
if (!debugger.IsValid()) {
372+
result.SetError("Invalid debugger.");
373+
return false;
374+
}
375+
376+
lldb::SBTarget target;
377+
llvm::Triple::ArchType arch;
378+
lldb::SBError error;
379+
uint64_t bndcfgu;
380+
uint64_t ptr;
381+
382+
if (!GetInitInfo(debugger, target, arch, bndcfgu, arg[0], ptr, result,
383+
error))
384+
return false;
385+
386+
char *endptr;
387+
errno = 0;
388+
uint64_t lbound = std::strtoul(arg[1], &endptr, 16);
389+
if (endptr == arg[1] || errno == ERANGE) {
390+
result.SetError("Lower Bound: bad argument format.");
391+
errno = 0;
392+
return false;
393+
}
394+
395+
uint64_t ubound = std::strtoul(arg[2], &endptr, 16);
396+
if (endptr == arg[1] || errno == ERANGE) {
397+
result.SetError("Upper Bound: bad argument format.");
398+
errno = 0;
399+
return false;
400+
}
401+
402+
return SetBTEntry(bndcfgu, ptr, lbound, ubound, target, arch, result,
403+
error);
404+
}
405+
406+
result.SetError("Too few arguments. See help.");
407+
return false;
408+
}
409+
};
410+
411+
bool lldb::PluginInitialize(lldb::SBDebugger debugger) {
412+
lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
413+
lldb::SBCommand mpxTable = interpreter.AddMultiwordCommand(
414+
"mpx-table", "A utility to access the MPX table entries.");
415+
416+
const char *mpx_show_help = "Show the MPX table entry of a pointer.\n"
417+
"mpx-table show <pointer>";
418+
mpxTable.AddCommand("show", new MPXTableShow(), mpx_show_help);
419+
420+
const char *mpx_set_help =
421+
"Set the MPX table entry of a pointer.\n"
422+
"mpx-table set <pointer> <lower bound> <upper bound>";
423+
mpxTable.AddCommand("set", new MPXTableSet(), mpx_set_help);
424+
425+
return true;
426+
}

‎lldb/tools/intel-mpx/test/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
LEVEL = ../../../../make
2+
3+
CXX_SOURCES := main.cpp
4+
5+
CFLAGS_EXTRAS += -mmpx -fcheck-pointer-bounds -lmpxwrappers -lmpx -fuse-ld=bfd
6+
7+
include $(LEVEL)/Makefile.rules

‎lldb/tools/intel-mpx/test/README.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
In order to run this test, create the following directory:
2+
3+
packages/Python/lldbsuite/test/functionalities/plugins/commands/mpxtablecmd
4+
5+
and copy into it the contents of this direcotry.
6+
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
"""
2+
Test mpx-table command.
3+
"""
4+
5+
from __future__ import print_function
6+
7+
8+
import os
9+
import time
10+
import re
11+
import lldb
12+
from lldbsuite.test.decorators import *
13+
from lldbsuite.test.lldbtest import *
14+
from lldbsuite.test import lldbutil
15+
16+
17+
class TestMPXTable(TestBase):
18+
19+
mydir = TestBase.compute_mydir(__file__)
20+
21+
def setUp(self):
22+
TestBase.setUp(self)
23+
24+
@skipIf(compiler="clang")
25+
@skipIf(oslist=no_match(['linux']))
26+
@skipIf(archs=no_match(['i386', 'x86_64']))
27+
@skipIf(compiler="gcc", compiler_version=["<", "5"]) #GCC version >= 5 supports Intel(R) MPX.
28+
def test_show_command(self):
29+
"""Test 'mpx-table show' command"""
30+
self.build()
31+
32+
lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"]
33+
lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib")
34+
plugin_file = os.path.join(lldb_lib_dir, "liblldb-intel-mpxtable.so")
35+
if not os.path.isfile(plugin_file):
36+
self.skipTest("Intel(R) mpx-table plugin missing.")
37+
plugin_command = " "
38+
seq = ("plugin", "load", plugin_file)
39+
plugin_command = plugin_command.join(seq)
40+
self.runCmd(plugin_command)
41+
42+
exe = os.path.join(os.getcwd(), "a.out")
43+
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
44+
45+
self.b1 = line_number('main.cpp', '// Break 1.')
46+
self.b2 = line_number('main.cpp', '// Break 2.')
47+
self.b3 = line_number('main.cpp', '// Break 3.')
48+
self.b4 = line_number('main.cpp', '// Break 4.')
49+
lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b1, num_expected_locations=1)
50+
lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b2, num_expected_locations=1)
51+
lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b3, num_expected_locations=1)
52+
lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b4, num_expected_locations=1)
53+
self.runCmd("run", RUN_SUCCEEDED)
54+
55+
target = self.dbg.GetSelectedTarget()
56+
process = target.GetProcess()
57+
58+
if (process.GetState() == lldb.eStateExited):
59+
self.skipTest("Intel(R) MPX is not supported.")
60+
else:
61+
self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
62+
substrs = ["stop reason = breakpoint 1."])
63+
64+
self.expect("mpx-table show a",
65+
substrs = ['lbound = 0x',
66+
', ubound = 0x',
67+
'(pointer value = 0x',
68+
', metadata = 0x',
69+
')'],
70+
error = False)
71+
72+
self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
73+
substrs = ["stop reason = breakpoint 2."])
74+
75+
# Check that out of scope pointer cannot be reached.
76+
#
77+
self.expect("mpx-table show a",
78+
substrs = ['Invalid pointer.'],
79+
error = True)
80+
81+
self.expect("mpx-table show tmp",
82+
substrs = ['lbound = 0x',
83+
', ubound = 0x',
84+
'(pointer value = 0x',
85+
', metadata = 0x',
86+
')'],
87+
error = False)
88+
89+
self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
90+
substrs = ["stop reason = breakpoint 3."])
91+
92+
# Check that the pointer value is correctly updated.
93+
#
94+
self.expect("mpx-table show tmp",
95+
substrs = ['lbound = 0x',
96+
', ubound = 0x',
97+
'(pointer value = 0x2',
98+
', metadata = 0x',
99+
')'],
100+
error = False)
101+
102+
self.expect("continue", STOPPED_DUE_TO_BREAKPOINT,
103+
substrs = ["stop reason = breakpoint 4."])
104+
105+
# After going back to main(), check that out of scope pointer cannot be
106+
# reached.
107+
#
108+
self.expect("mpx-table show tmp",
109+
substrs = ['Invalid pointer.'],
110+
error = True)
111+
112+
self.expect("mpx-table show a",
113+
substrs = ['lbound = 0x',
114+
', ubound = 0x',
115+
'(pointer value = 0x',
116+
', metadata = 0x',
117+
')'],
118+
error = False)
119+
120+
def test_set_command(self):
121+
"""Test 'mpx-table set' command"""
122+
self.build()
123+
124+
lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"]
125+
lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib")
126+
plugin_file = os.path.join(lldb_lib_dir, "liblldb-intel-mpxtable.so")
127+
if not os.path.isfile(plugin_file):
128+
self.skipTest("Intel(R) mpx-table plugin missing.")
129+
plugin_command = " "
130+
seq = ("plugin", "load", plugin_file)
131+
plugin_command = plugin_command.join(seq)
132+
self.runCmd(plugin_command)
133+
134+
exe = os.path.join(os.getcwd(), "a.out")
135+
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
136+
137+
self.b1 = line_number('main.cpp', '// Break 1.')
138+
lldbutil.run_break_set_by_file_and_line(self, "main.cpp", self.b1, num_expected_locations=1)
139+
self.runCmd("run", RUN_SUCCEEDED)
140+
141+
target = self.dbg.GetSelectedTarget()
142+
process = target.GetProcess()
143+
144+
if (process.GetState() == lldb.eStateExited):
145+
self.skipTest("Intel(R) MPX is not supported.")
146+
else:
147+
self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
148+
substrs = ["stop reason = breakpoint 1."])
149+
150+
# Check that the BT Entry doesn't already contain the test values.
151+
#
152+
self.expect("mpx-table show a", matching=False,
153+
substrs = ['lbound = 0xcafecafe',
154+
', ubound = 0xbeefbeef'])
155+
156+
# Set the test values.
157+
#
158+
self.expect("mpx-table set a 0xcafecafe 0xbeefbeef", error = False)
159+
160+
# Verify that the test values have been correctly written in the BT
161+
# entry.
162+
#
163+
self.expect("mpx-table show a",
164+
substrs = ['lbound = 0xcafecafe',
165+
', ubound = 0xbeefbeef'],
166+
error = False)
167+
168+

‎lldb/tools/intel-mpx/test/main.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
2+
////
3+
//// The LLVM Compiler Infrastructure
4+
////
5+
//// This file is distributed under the University of Illinois Open Source
6+
//// License. See LICENSE.TXT for details.
7+
////
8+
////===----------------------------------------------------------------------===//
9+
//
10+
11+
const int size = 5;
12+
13+
#include <cstddef>
14+
#include <cstdlib>
15+
#include <sys/prctl.h>
16+
17+
void func(int *ptr) {
18+
int *tmp;
19+
20+
#if defined __GNUC__ && !defined __INTEL_COMPILER
21+
__builtin___bnd_store_ptr_bounds ((void**)&ptr, ptr);
22+
#endif
23+
tmp = ptr + size - 1;
24+
#if defined __GNUC__ && !defined __INTEL_COMPILER
25+
__builtin___bnd_store_ptr_bounds ((void**)&tmp, tmp);
26+
#endif
27+
tmp = (int*)0x2; // Break 2.
28+
29+
return; // Break 3.
30+
}
31+
32+
int
33+
main(int argc, char const *argv[])
34+
{
35+
// This call returns 0 only if the CPU and the kernel support Intel(R) MPX.
36+
if (prctl(PR_MPX_ENABLE_MANAGEMENT, 0, 0, 0, 0) != 0)
37+
return -1;
38+
39+
int* a = (int *) calloc(size, sizeof(int));
40+
#if defined __GNUC__ && !defined __INTEL_COMPILER
41+
__builtin___bnd_store_ptr_bounds ((void**)&a, a);
42+
#endif
43+
func(a); // Break 1.
44+
45+
free(a); // Break 4.
46+
47+
return 0;
48+
}

0 commit comments

Comments
 (0)
Please sign in to comment.