clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cli-wrapper-mpxtable.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-8/lib/clang/8.0.0 -D HAVE_ROUND -D LLDB_CONFIGURATION_RELEASE -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lldb/tools/intel-features/intel-mpx -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/tools/intel-features/intel-mpx -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lldb/include -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/include -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/include -I /build/llvm-toolchain-snapshot-8~svn345461/include -I /usr/include/python2.7 -I /build/llvm-toolchain-snapshot-8~svn345461/tools/clang/include -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lldb/../clang/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/include/clang/8.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-8/lib/clang/8.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-deprecated-register -Wno-vla-extension -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lldb/tools/intel-features/intel-mpx -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-10-27-211344-32123-1 -x c++ /build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp -faddrsig
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | #include <cerrno> |
13 | #include <string> |
14 | |
15 | |
16 | #include "cli-wrapper-mpxtable.h" |
17 | #include "lldb/API/SBCommandInterpreter.h" |
18 | #include "lldb/API/SBCommandReturnObject.h" |
19 | #include "lldb/API/SBMemoryRegionInfo.h" |
20 | #include "lldb/API/SBProcess.h" |
21 | #include "lldb/API/SBTarget.h" |
22 | #include "lldb/API/SBThread.h" |
23 | |
24 | #include "llvm/ADT/Triple.h" |
25 | |
26 | static bool GetPtr(char *cptr, uint64_t &ptr, lldb::SBFrame &frame, |
27 | lldb::SBCommandReturnObject &result) { |
28 | if (!cptr) { |
29 | result.SetError("Bad argument."); |
30 | result.SetStatus(lldb::eReturnStatusFailed); |
31 | return false; |
32 | } |
33 | |
34 | lldb::SBValue ptr_addr = frame.GetValueForVariablePath(cptr); |
35 | if (!ptr_addr.IsValid()) { |
36 | result.SetError("Invalid pointer."); |
37 | result.SetStatus(lldb::eReturnStatusFailed); |
38 | return false; |
39 | } |
40 | ptr = ptr_addr.GetLoadAddress(); |
41 | return true; |
42 | } |
43 | |
44 | enum { |
45 | mpx_base_mask_64 = ~(uint64_t)0xFFFULL, |
46 | mpx_bd_mask_64 = 0xFFFFFFF00000ULL, |
47 | bd_r_shift_64 = 20, |
48 | bd_l_shift_64 = 3, |
49 | bt_r_shift_64 = 3, |
50 | bt_l_shift_64 = 5, |
51 | bt_mask_64 = 0x0000000FFFF8ULL, |
52 | |
53 | mpx_base_mask_32 = 0xFFFFFFFFFFFFF000ULL, |
54 | mpx_bd_mask_32 = 0xFFFFF000ULL, |
55 | bd_r_shift_32 = 12, |
56 | bd_l_shift_32 = 2, |
57 | bt_r_shift_32 = 2, |
58 | bt_l_shift_32 = 4, |
59 | bt_mask_32 = 0x00000FFCULL, |
60 | }; |
61 | |
62 | static void PrintBTEntry(lldb::addr_t lbound, lldb::addr_t ubound, |
63 | uint64_t value, uint64_t meta, |
64 | lldb::SBCommandReturnObject &result) { |
65 | const lldb::addr_t one_cmpl64 = ~((lldb::addr_t)0); |
66 | const lldb::addr_t one_cmpl32 = ~((uint32_t)0); |
67 | |
68 | if ((lbound == one_cmpl64 || one_cmpl32) && ubound == 0) { |
69 | result.Printf("Null bounds on map: pointer value = 0x%lx\n", value); |
70 | } else { |
71 | result.Printf(" lbound = 0x%lx,", lbound); |
72 | result.Printf(" ubound = 0x%lx", ubound); |
73 | result.Printf(" (pointer value = 0x%lx,", value); |
74 | result.Printf(" metadata = 0x%lx)\n", meta); |
75 | } |
76 | } |
77 | |
78 | static bool GetBTEntryAddr(uint64_t bndcfgu, uint64_t ptr, |
79 | lldb::SBTarget &target, llvm::Triple::ArchType arch, |
80 | size_t &size, lldb::addr_t &bt_entry_addr, |
81 | lldb::SBCommandReturnObject &result, |
82 | lldb::SBError &error) { |
83 | lldb::addr_t mpx_base_mask; |
84 | lldb::addr_t mpx_bd_mask; |
85 | lldb::addr_t bd_r_shift; |
86 | lldb::addr_t bd_l_shift; |
87 | lldb::addr_t bt_r_shift; |
88 | lldb::addr_t bt_l_shift; |
89 | lldb::addr_t bt_mask; |
90 | |
91 | if (arch == llvm::Triple::ArchType::x86_64) { |
92 | mpx_base_mask = mpx_base_mask_64; |
93 | mpx_bd_mask = mpx_bd_mask_64; |
94 | bd_r_shift = bd_r_shift_64; |
95 | bd_l_shift = bd_l_shift_64; |
96 | bt_r_shift = bt_r_shift_64; |
97 | bt_l_shift = bt_l_shift_64; |
98 | bt_mask = bt_mask_64; |
99 | } else if (arch == llvm::Triple::ArchType::x86) { |
100 | mpx_base_mask = mpx_base_mask_32; |
101 | mpx_bd_mask = mpx_bd_mask_32; |
102 | bd_r_shift = bd_r_shift_32; |
103 | bd_l_shift = bd_l_shift_32; |
104 | bt_r_shift = bt_r_shift_32; |
105 | bt_l_shift = bt_l_shift_32; |
106 | bt_mask = bt_mask_32; |
107 | } else { |
108 | result.SetError("Invalid arch."); |
109 | result.SetStatus(lldb::eReturnStatusFailed); |
110 | return false; |
111 | } |
112 | |
113 | size = target.GetAddressByteSize(); |
114 | lldb::addr_t mpx_bd_base = bndcfgu & mpx_base_mask; |
115 | lldb::addr_t bd_entry_offset = ((ptr & mpx_bd_mask) >> bd_r_shift) |
116 | << bd_l_shift; |
117 | lldb::addr_t bd_entry_addr = mpx_bd_base + bd_entry_offset; |
118 | |
119 | std::vector<uint8_t> bd_entry_v(size); |
120 | size_t ret = target.GetProcess().ReadMemory( |
121 | bd_entry_addr, static_cast<void *>(bd_entry_v.data()), size, error); |
122 | if (ret != size || !error.Success()) { |
123 | result.SetError("Failed access to BD entry."); |
124 | return false; |
125 | } |
126 | |
127 | lldb::SBData data; |
128 | data.SetData(error, bd_entry_v.data(), bd_entry_v.size(), |
129 | target.GetByteOrder(), size); |
130 | lldb::addr_t bd_entry = data.GetAddress(error, 0); |
131 | |
132 | if (!error.Success()) { |
133 | result.SetError("Failed access to BD entry."); |
134 | return false; |
135 | } |
136 | |
137 | if ((bd_entry & 0x01) == 0) { |
138 | result.SetError("Invalid bound directory."); |
139 | result.SetStatus(lldb::eReturnStatusFailed); |
140 | return false; |
141 | } |
142 | |
143 | |
144 | |
145 | bd_entry--; |
146 | |
147 | lldb::addr_t bt_addr = bd_entry & ~bt_r_shift; |
148 | lldb::addr_t bt_entry_offset = ((ptr & bt_mask) >> bt_r_shift) << bt_l_shift; |
149 | bt_entry_addr = bt_addr + bt_entry_offset; |
150 | |
151 | return true; |
152 | } |
153 | |
154 | static bool GetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::SBTarget &target, |
155 | llvm::Triple::ArchType arch, |
156 | lldb::SBCommandReturnObject &result, |
157 | lldb::SBError &error) { |
158 | lldb::addr_t bt_entry_addr; |
159 | size_t size; |
160 | if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result, |
161 | error)) |
162 | return false; |
163 | |
164 | |
165 | |
166 | |
167 | |
168 | |
169 | std::vector<uint8_t> bt_entry_v(size * 4); |
170 | size_t ret = target.GetProcess().ReadMemory( |
171 | bt_entry_addr, static_cast<void *>(bt_entry_v.data()), size * 4, error); |
172 | |
173 | if ((ret != (size * 4)) || !error.Success()) { |
174 | result.SetError("Unsuccessful. Failed access to BT entry."); |
175 | result.SetStatus(lldb::eReturnStatusFailed); |
176 | return false; |
177 | } |
178 | |
179 | lldb::addr_t lbound; |
180 | lldb::addr_t ubound; |
181 | uint64_t value; |
182 | uint64_t meta; |
183 | lldb::SBData data; |
184 | data.SetData(error, bt_entry_v.data(), bt_entry_v.size(), |
185 | target.GetByteOrder(), size); |
186 | lbound = data.GetAddress(error, size * 0); |
187 | ubound = data.GetAddress(error, size * 1); |
188 | value = data.GetAddress(error, size * 2); |
189 | meta = data.GetAddress(error, size * 3); |
190 | |
191 | if (arch == llvm::Triple::ArchType::x86) { |
192 | ubound = (~ubound) & 0x00000000FFFFFFFF; |
193 | } else { |
194 | ubound = ~ubound; |
195 | } |
196 | |
197 | if (!error.Success()) { |
198 | result.SetError("Failed access to BT entry."); |
199 | return false; |
200 | } |
201 | |
202 | PrintBTEntry(lbound, ubound, value, meta, result); |
203 | |
204 | result.SetStatus(lldb::eReturnStatusSuccessFinishResult); |
205 | return true; |
206 | } |
207 | |
208 | static std::vector<uint8_t> uIntToU8(uint64_t input, size_t size) { |
209 | std::vector<uint8_t> output; |
210 | for (size_t i = 0; i < size; i++) |
211 | output.push_back( |
212 | static_cast<uint8_t>((input & (0xFFULL << (i * 8))) >> (i * 8))); |
213 | |
214 | return output; |
215 | } |
216 | |
217 | static bool SetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::addr_t lbound, |
218 | lldb::addr_t ubound, lldb::SBTarget &target, |
219 | llvm::Triple::ArchType arch, |
220 | lldb::SBCommandReturnObject &result, |
221 | lldb::SBError &error) { |
222 | lldb::addr_t bt_entry_addr; |
223 | size_t size; |
224 | |
225 | if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result, |
226 | error)) |
227 | return false; |
228 | |
229 | |
230 | |
231 | |
232 | std::vector<uint8_t> bt_entry_v(size * 2); |
233 | |
234 | std::vector<uint8_t> lbound_v = uIntToU8(lbound, size); |
235 | bt_entry_v.insert(bt_entry_v.begin(), lbound_v.begin(), lbound_v.end()); |
236 | std::vector<uint8_t> ubound_v = uIntToU8(~ubound, size); |
237 | bt_entry_v.insert(bt_entry_v.begin() + size, ubound_v.begin(), |
238 | ubound_v.end()); |
239 | |
240 | size_t ret = target.GetProcess().WriteMemory( |
241 | bt_entry_addr, (void *)(bt_entry_v.data()), size * 2, error); |
242 | if ((ret != (size * 2)) || !error.Success()) { |
243 | result.SetError("Failed access to BT entry."); |
244 | result.SetStatus(lldb::eReturnStatusFailed); |
245 | return false; |
246 | } |
247 | |
248 | result.SetStatus(lldb::eReturnStatusSuccessFinishResult); |
249 | return true; |
250 | } |
251 | |
252 | static bool GetInitInfo(lldb::SBDebugger debugger, lldb::SBTarget &target, |
253 | llvm::Triple::ArchType &arch, uint64_t &bndcfgu, |
254 | char *arg, uint64_t &ptr, |
255 | lldb::SBCommandReturnObject &result, |
256 | lldb::SBError &error) { |
257 | target = debugger.GetSelectedTarget(); |
258 | if (!target.IsValid()) { |
259 | result.SetError("Invalid target."); |
260 | result.SetStatus(lldb::eReturnStatusFailed); |
261 | return false; |
262 | } |
263 | |
264 | const std::string triple_s(target.GetTriple()); |
265 | const llvm::Triple triple(triple_s); |
266 | |
267 | arch = triple.getArch(); |
268 | |
269 | if ((arch != llvm::Triple::ArchType::x86) && |
270 | (arch != llvm::Triple::ArchType::x86_64)) { |
271 | result.SetError("Platform not supported."); |
272 | result.SetStatus(lldb::eReturnStatusFailed); |
273 | return false; |
274 | } |
275 | |
276 | lldb::SBFrame frame = |
277 | target.GetProcess().GetSelectedThread().GetSelectedFrame(); |
278 | if (!frame.IsValid()) { |
279 | result.SetError("No valid process, thread or frame."); |
280 | result.SetStatus(lldb::eReturnStatusFailed); |
281 | return false; |
282 | } |
283 | |
284 | lldb::SBValue bndcfgu_val = frame.FindRegister("bndcfgu"); |
285 | if (!bndcfgu_val.IsValid()) { |
286 | result.SetError("Cannot access register BNDCFGU. Does the target support " |
287 | "Intel(R) Memory Protection Extensions (Intel(R) MPX)?"); |
288 | result.SetStatus(lldb::eReturnStatusFailed); |
289 | return false; |
290 | } |
291 | |
292 | lldb::SBData bndcfgu_data = bndcfgu_val.GetData(); |
293 | bndcfgu = bndcfgu_data.GetUnsignedInt64(error, 0); |
294 | if (!error.Success()) { |
295 | result.SetError(error, "Invalid read of register BNDCFGU."); |
296 | return false; |
297 | } |
298 | |
299 | if (!GetPtr(arg, ptr, frame, result)) |
300 | return false; |
301 | |
302 | return true; |
303 | } |
304 | |
305 | class MPXTableShow : public lldb::SBCommandPluginInterface { |
306 | public: |
307 | virtual bool DoExecute(lldb::SBDebugger debugger, char **command, |
308 | lldb::SBCommandReturnObject &result) { |
309 | |
310 | if (command) { |
| 1 | Assuming 'command' is non-null | |
|
| |
311 | int arg_c = 0; |
312 | char *arg; |
| 3 | | 'arg' declared without an initial value | |
|
313 | |
314 | while (*command) { |
| 4 | | Loop condition is false. Execution continues on line 325 | |
|
315 | if (arg_c >= 1) { |
316 | result.SetError("Too many arguments. See help."); |
317 | result.SetStatus(lldb::eReturnStatusFailed); |
318 | return false; |
319 | } |
320 | arg_c++; |
321 | arg = *command; |
322 | command++; |
323 | } |
324 | |
325 | if (!debugger.IsValid()) { |
| 5 | | Assuming the condition is false | |
|
| |
326 | result.SetError("Invalid debugger."); |
327 | result.SetStatus(lldb::eReturnStatusFailed); |
328 | return false; |
329 | } |
330 | |
331 | lldb::SBTarget target; |
332 | llvm::Triple::ArchType arch; |
333 | lldb::SBError error; |
334 | uint64_t bndcfgu; |
335 | uint64_t ptr; |
336 | |
337 | if (!GetInitInfo(debugger, target, arch, bndcfgu, arg, ptr, result, |
| 7 | | 5th function call argument is an uninitialized value |
|
338 | error)) |
339 | return false; |
340 | |
341 | return GetBTEntry(bndcfgu, ptr, target, arch, result, error); |
342 | } |
343 | |
344 | result.SetError("Too few arguments. See help."); |
345 | result.SetStatus(lldb::eReturnStatusFailed); |
346 | return false; |
347 | } |
348 | }; |
349 | |
350 | class MPXTableSet : public lldb::SBCommandPluginInterface { |
351 | public: |
352 | virtual bool DoExecute(lldb::SBDebugger debugger, char **command, |
353 | lldb::SBCommandReturnObject &result) { |
354 | |
355 | if (command) { |
356 | int arg_c = 0; |
357 | char *arg[3]; |
358 | |
359 | while (*command) { |
360 | arg[arg_c] = *command; |
361 | command++; |
362 | arg_c++; |
363 | } |
364 | |
365 | if (arg_c != 3) { |
366 | result.SetError("Wrong arguments. See help."); |
367 | return false; |
368 | } |
369 | |
370 | if (!debugger.IsValid()) { |
371 | result.SetError("Invalid debugger."); |
372 | return false; |
373 | } |
374 | |
375 | lldb::SBTarget target; |
376 | llvm::Triple::ArchType arch; |
377 | lldb::SBError error; |
378 | uint64_t bndcfgu; |
379 | uint64_t ptr; |
380 | |
381 | if (!GetInitInfo(debugger, target, arch, bndcfgu, arg[0], ptr, result, |
382 | error)) |
383 | return false; |
384 | |
385 | char *endptr; |
386 | errno(*__errno_location ()) = 0; |
387 | uint64_t lbound = std::strtoul(arg[1], &endptr, 16); |
388 | if (endptr == arg[1] || errno(*__errno_location ()) == ERANGE34) { |
389 | result.SetError("Lower Bound: bad argument format."); |
390 | errno(*__errno_location ()) = 0; |
391 | return false; |
392 | } |
393 | |
394 | uint64_t ubound = std::strtoul(arg[2], &endptr, 16); |
395 | if (endptr == arg[1] || errno(*__errno_location ()) == ERANGE34) { |
396 | result.SetError("Upper Bound: bad argument format."); |
397 | errno(*__errno_location ()) = 0; |
398 | return false; |
399 | } |
400 | |
401 | return SetBTEntry(bndcfgu, ptr, lbound, ubound, target, arch, result, |
402 | error); |
403 | } |
404 | |
405 | result.SetError("Too few arguments. See help."); |
406 | return false; |
407 | } |
408 | }; |
409 | |
410 | bool MPXPluginInitialize(lldb::SBDebugger &debugger) { |
411 | lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter(); |
412 | lldb::SBCommand mpxTable = interpreter.AddMultiwordCommand( |
413 | "mpx-table", "A utility to access the Intel(R) MPX table entries."); |
414 | |
415 | const char *mpx_show_help = "Show the Intel(R) MPX table entry of a pointer." |
416 | "\nmpx-table show <pointer>"; |
417 | mpxTable.AddCommand("show", new MPXTableShow(), mpx_show_help); |
418 | |
419 | const char *mpx_set_help = |
420 | "Set the Intel(R) MPX table entry of a pointer.\n" |
421 | "mpx-table set <pointer> <lower bound> <upper bound>"; |
422 | mpxTable.AddCommand("set", new MPXTableSet(), mpx_set_help); |
423 | |
424 | return true; |
425 | } |