/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Core/EmulateInstruction.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- EmulateInstruction.h ------------------------------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #ifndef LLDB_CORE_EMULATEINSTRUCTION_H |
10 | | #define LLDB_CORE_EMULATEINSTRUCTION_H |
11 | | |
12 | | #include <optional> |
13 | | #include <string> |
14 | | |
15 | | #include "lldb/Core/Address.h" |
16 | | #include "lldb/Core/Opcode.h" |
17 | | #include "lldb/Core/PluginInterface.h" |
18 | | #include "lldb/Utility/ArchSpec.h" |
19 | | #include "lldb/lldb-defines.h" |
20 | | #include "lldb/lldb-enumerations.h" |
21 | | #include "lldb/lldb-private-enumerations.h" |
22 | | #include "lldb/lldb-private-types.h" |
23 | | #include "lldb/lldb-types.h" |
24 | | |
25 | | #include <cstddef> |
26 | | #include <cstdint> |
27 | | |
28 | | namespace lldb_private { |
29 | | class OptionValueDictionary; |
30 | | class RegisterContext; |
31 | | class RegisterValue; |
32 | | class Stream; |
33 | | class Target; |
34 | | class UnwindPlan; |
35 | | |
36 | | /// \class EmulateInstruction EmulateInstruction.h |
37 | | /// "lldb/Core/EmulateInstruction.h" |
38 | | /// A class that allows emulation of CPU opcodes. |
39 | | /// |
40 | | /// This class is a plug-in interface that is accessed through the standard |
41 | | /// static FindPlugin function call in the EmulateInstruction class. The |
42 | | /// FindPlugin takes a target triple and returns a new object if there is a |
43 | | /// plug-in that supports the architecture and OS. Four callbacks and a baton |
44 | | /// are provided. The four callbacks are read register, write register, read |
45 | | /// memory and write memory. |
46 | | /// |
47 | | /// This class is currently designed for these main use cases: - Auto |
48 | | /// generation of Call Frame Information (CFI) from assembly code - Predicting |
49 | | /// single step breakpoint locations - Emulating instructions for breakpoint |
50 | | /// traps |
51 | | /// |
52 | | /// Objects can be asked to read an instruction which will cause a call to the |
53 | | /// read register callback to get the PC, followed by a read memory call to |
54 | | /// read the opcode. If ReadInstruction () returns true, then a call to |
55 | | /// EmulateInstruction::EvaluateInstruction () can be made. At this point the |
56 | | /// EmulateInstruction subclass will use all of the callbacks to emulate an |
57 | | /// instruction. |
58 | | /// |
59 | | /// Clients that provide the callbacks can either do the read/write |
60 | | /// registers/memory to actually emulate the instruction on a real or virtual |
61 | | /// CPU, or watch for the EmulateInstruction::Context which is context for the |
62 | | /// read/write register/memory which explains why the callback is being |
63 | | /// called. Examples of a context are: "pushing register 3 onto the stack at |
64 | | /// offset -12", or "adjusting stack pointer by -16". This extra context |
65 | | /// allows the generation of |
66 | | /// CFI information from assembly code without having to actually do |
67 | | /// the read/write register/memory. |
68 | | /// |
69 | | /// Clients must be prepared that not all instructions for an Instruction Set |
70 | | /// Architecture (ISA) will be emulated. |
71 | | /// |
72 | | /// Subclasses at the very least should implement the instructions that save |
73 | | /// and restore registers onto the stack and adjustment to the stack pointer. |
74 | | /// By just implementing a few instructions for an ISA that are the typical |
75 | | /// prologue opcodes, you can then generate CFI using a class that will soon |
76 | | /// be available. |
77 | | /// |
78 | | /// Implementing all of the instructions that affect the PC can then allow |
79 | | /// single step prediction support. |
80 | | /// |
81 | | /// Implementing all of the instructions allows for emulation of opcodes for |
82 | | /// breakpoint traps and will pave the way for "thread centric" debugging. The |
83 | | /// current debugging model is "process centric" where all threads must be |
84 | | /// stopped when any thread is stopped; when hitting software breakpoints we |
85 | | /// must disable the breakpoint by restoring the original breakpoint opcode, |
86 | | /// single stepping and restoring the breakpoint trap. If all threads were |
87 | | /// allowed to run then other threads could miss the breakpoint. |
88 | | /// |
89 | | /// This class centralizes the code that usually is done in separate code |
90 | | /// paths in a debugger (single step prediction, finding save restore |
91 | | /// locations of registers for unwinding stack frame variables) and emulating |
92 | | /// the instruction is just a bonus. |
93 | | |
94 | | class EmulateInstruction : public PluginInterface { |
95 | | public: |
96 | | static EmulateInstruction *FindPlugin(const ArchSpec &arch, |
97 | | InstructionType supported_inst_type, |
98 | | const char *plugin_name); |
99 | | |
100 | | enum ContextType { |
101 | | eContextInvalid = 0, |
102 | | // Read an instruction opcode from memory |
103 | | eContextReadOpcode, |
104 | | |
105 | | // Usually used for writing a register value whose source value is an |
106 | | // immediate |
107 | | eContextImmediate, |
108 | | |
109 | | // Exclusively used when saving a register to the stack as part of the |
110 | | // prologue |
111 | | eContextPushRegisterOnStack, |
112 | | |
113 | | // Exclusively used when restoring a register off the stack as part of the |
114 | | // epilogue |
115 | | eContextPopRegisterOffStack, |
116 | | |
117 | | // Add or subtract a value from the stack |
118 | | eContextAdjustStackPointer, |
119 | | |
120 | | // Adjust the frame pointer for the current frame |
121 | | eContextSetFramePointer, |
122 | | |
123 | | // Typically in an epilogue sequence. Copy the frame pointer back into the |
124 | | // stack pointer, use SP for CFA calculations again. |
125 | | eContextRestoreStackPointer, |
126 | | |
127 | | // Add or subtract a value from a base address register (other than SP) |
128 | | eContextAdjustBaseRegister, |
129 | | |
130 | | // Add or subtract a value from the PC or store a value to the PC. |
131 | | eContextAdjustPC, |
132 | | |
133 | | // Used in WriteRegister callbacks to indicate where the |
134 | | eContextRegisterPlusOffset, |
135 | | |
136 | | // Used in WriteMemory callback to indicate where the data came from |
137 | | eContextRegisterStore, |
138 | | |
139 | | eContextRegisterLoad, |
140 | | |
141 | | // Used when performing a PC-relative branch where the |
142 | | eContextRelativeBranchImmediate, |
143 | | |
144 | | // Used when performing an absolute branch where the |
145 | | eContextAbsoluteBranchRegister, |
146 | | |
147 | | // Used when performing a supervisor call to an operating system to provide |
148 | | // a service: |
149 | | eContextSupervisorCall, |
150 | | |
151 | | // Used when performing a MemU operation to read the PC-relative offset |
152 | | // from an address. |
153 | | eContextTableBranchReadMemory, |
154 | | |
155 | | // Used when random bits are written into a register |
156 | | eContextWriteRegisterRandomBits, |
157 | | |
158 | | // Used when random bits are written to memory |
159 | | eContextWriteMemoryRandomBits, |
160 | | |
161 | | eContextArithmetic, |
162 | | |
163 | | eContextAdvancePC, |
164 | | |
165 | | eContextReturnFromException |
166 | | }; |
167 | | |
168 | | enum InfoType { |
169 | | eInfoTypeRegisterPlusOffset, |
170 | | eInfoTypeRegisterPlusIndirectOffset, |
171 | | eInfoTypeRegisterToRegisterPlusOffset, |
172 | | eInfoTypeRegisterToRegisterPlusIndirectOffset, |
173 | | eInfoTypeRegisterRegisterOperands, |
174 | | eInfoTypeOffset, |
175 | | eInfoTypeRegister, |
176 | | eInfoTypeImmediate, |
177 | | eInfoTypeImmediateSigned, |
178 | | eInfoTypeAddress, |
179 | | eInfoTypeISAAndImmediate, |
180 | | eInfoTypeISAAndImmediateSigned, |
181 | | eInfoTypeISA, |
182 | | eInfoTypeNoArgs |
183 | | }; |
184 | | |
185 | | struct Context { |
186 | | ContextType type = eContextInvalid; |
187 | | |
188 | | private: |
189 | | enum InfoType info_type = eInfoTypeNoArgs; |
190 | | |
191 | | public: |
192 | 117 | enum InfoType GetInfoType() const { return info_type; } |
193 | | union ContextInfo { |
194 | | struct RegisterPlusOffset { |
195 | | RegisterInfo reg; // base register |
196 | | int64_t signed_offset; // signed offset added to base register |
197 | | } RegisterPlusOffset; |
198 | | |
199 | | struct RegisterPlusIndirectOffset { |
200 | | RegisterInfo base_reg; // base register number |
201 | | RegisterInfo offset_reg; // offset register kind |
202 | | } RegisterPlusIndirectOffset; |
203 | | |
204 | | struct RegisterToRegisterPlusOffset { |
205 | | RegisterInfo data_reg; // source/target register for data |
206 | | RegisterInfo base_reg; // base register for address calculation |
207 | | int64_t offset; // offset for address calculation |
208 | | } RegisterToRegisterPlusOffset; |
209 | | |
210 | | struct RegisterToRegisterPlusIndirectOffset { |
211 | | RegisterInfo base_reg; // base register for address calculation |
212 | | RegisterInfo offset_reg; // offset register for address calculation |
213 | | RegisterInfo data_reg; // source/target register for data |
214 | | } RegisterToRegisterPlusIndirectOffset; |
215 | | |
216 | | struct RegisterRegisterOperands { |
217 | | RegisterInfo |
218 | | operand1; // register containing first operand for binary op |
219 | | RegisterInfo |
220 | | operand2; // register containing second operand for binary op |
221 | | } RegisterRegisterOperands; |
222 | | |
223 | | int64_t signed_offset; // signed offset by which to adjust self (for |
224 | | // registers only) |
225 | | |
226 | | RegisterInfo reg; // plain register |
227 | | |
228 | | uint64_t unsigned_immediate; // unsigned immediate value |
229 | | int64_t signed_immediate; // signed immediate value |
230 | | |
231 | | lldb::addr_t address; // direct address |
232 | | |
233 | | struct ISAAndImmediate { |
234 | | uint32_t isa; |
235 | | uint32_t unsigned_data32; // immediate data |
236 | | } ISAAndImmediate; |
237 | | |
238 | | struct ISAAndImmediateSigned { |
239 | | uint32_t isa; |
240 | | int32_t signed_data32; // signed immediate data |
241 | | } ISAAndImmediateSigned; |
242 | | |
243 | | uint32_t isa; |
244 | | } info; |
245 | | static_assert(std::is_trivial<ContextInfo>::value, |
246 | | "ContextInfo must be trivial."); |
247 | | |
248 | 796 | Context() = default; |
249 | | |
250 | 153 | void SetRegisterPlusOffset(RegisterInfo base_reg, int64_t signed_offset) { |
251 | 153 | info_type = eInfoTypeRegisterPlusOffset; |
252 | 153 | info.RegisterPlusOffset.reg = base_reg; |
253 | 153 | info.RegisterPlusOffset.signed_offset = signed_offset; |
254 | 153 | } |
255 | | |
256 | | void SetRegisterPlusIndirectOffset(RegisterInfo base_reg, |
257 | 0 | RegisterInfo offset_reg) { |
258 | 0 | info_type = eInfoTypeRegisterPlusIndirectOffset; |
259 | 0 | info.RegisterPlusIndirectOffset.base_reg = base_reg; |
260 | 0 | info.RegisterPlusIndirectOffset.offset_reg = offset_reg; |
261 | 0 | } |
262 | | |
263 | | void SetRegisterToRegisterPlusOffset(RegisterInfo data_reg, |
264 | | RegisterInfo base_reg, |
265 | 99 | int64_t offset) { |
266 | 99 | info_type = eInfoTypeRegisterToRegisterPlusOffset; |
267 | 99 | info.RegisterToRegisterPlusOffset.data_reg = data_reg; |
268 | 99 | info.RegisterToRegisterPlusOffset.base_reg = base_reg; |
269 | 99 | info.RegisterToRegisterPlusOffset.offset = offset; |
270 | 99 | } |
271 | | |
272 | | void SetRegisterToRegisterPlusIndirectOffset(RegisterInfo base_reg, |
273 | | RegisterInfo offset_reg, |
274 | 0 | RegisterInfo data_reg) { |
275 | 0 | info_type = eInfoTypeRegisterToRegisterPlusIndirectOffset; |
276 | 0 | info.RegisterToRegisterPlusIndirectOffset.base_reg = base_reg; |
277 | 0 | info.RegisterToRegisterPlusIndirectOffset.offset_reg = offset_reg; |
278 | 0 | info.RegisterToRegisterPlusIndirectOffset.data_reg = data_reg; |
279 | 0 | } |
280 | | |
281 | | void SetRegisterRegisterOperands(RegisterInfo op1_reg, |
282 | 16 | RegisterInfo op2_reg) { |
283 | 16 | info_type = eInfoTypeRegisterRegisterOperands; |
284 | 16 | info.RegisterRegisterOperands.operand1 = op1_reg; |
285 | 16 | info.RegisterRegisterOperands.operand2 = op2_reg; |
286 | 16 | } |
287 | | |
288 | 0 | void SetOffset(int64_t signed_offset) { |
289 | 0 | info_type = eInfoTypeOffset; |
290 | 0 | info.signed_offset = signed_offset; |
291 | 0 | } |
292 | | |
293 | 0 | void SetRegister(RegisterInfo reg) { |
294 | 0 | info_type = eInfoTypeRegister; |
295 | 0 | info.reg = reg; |
296 | 0 | } |
297 | | |
298 | 1 | void SetImmediate(uint64_t immediate) { |
299 | 1 | info_type = eInfoTypeImmediate; |
300 | 1 | info.unsigned_immediate = immediate; |
301 | 1 | } |
302 | | |
303 | 42 | void SetImmediateSigned(int64_t signed_immediate) { |
304 | 42 | info_type = eInfoTypeImmediateSigned; |
305 | 42 | info.signed_immediate = signed_immediate; |
306 | 42 | } |
307 | | |
308 | 83 | void SetAddress(lldb::addr_t address) { |
309 | 83 | info_type = eInfoTypeAddress; |
310 | 83 | info.address = address; |
311 | 83 | } |
312 | 0 | void SetISAAndImmediate(uint32_t isa, uint32_t data) { |
313 | 0 | info_type = eInfoTypeISAAndImmediate; |
314 | 0 | info.ISAAndImmediate.isa = isa; |
315 | 0 | info.ISAAndImmediate.unsigned_data32 = data; |
316 | 0 | } |
317 | | |
318 | 1 | void SetISAAndImmediateSigned(uint32_t isa, int32_t data) { |
319 | 1 | info_type = eInfoTypeISAAndImmediateSigned; |
320 | 1 | info.ISAAndImmediateSigned.isa = isa; |
321 | 1 | info.ISAAndImmediateSigned.signed_data32 = data; |
322 | 1 | } |
323 | | |
324 | 1 | void SetISA(uint32_t isa) { |
325 | 1 | info_type = eInfoTypeISA; |
326 | 1 | info.isa = isa; |
327 | 1 | } |
328 | | |
329 | 514 | void SetNoArgs() { info_type = eInfoTypeNoArgs; } |
330 | | |
331 | | void Dump(Stream &s, EmulateInstruction *instruction) const; |
332 | | }; |
333 | | |
334 | | typedef size_t (*ReadMemoryCallback)(EmulateInstruction *instruction, |
335 | | void *baton, const Context &context, |
336 | | lldb::addr_t addr, void *dst, |
337 | | size_t length); |
338 | | |
339 | | typedef size_t (*WriteMemoryCallback)(EmulateInstruction *instruction, |
340 | | void *baton, const Context &context, |
341 | | lldb::addr_t addr, const void *dst, |
342 | | size_t length); |
343 | | |
344 | | typedef bool (*ReadRegisterCallback)(EmulateInstruction *instruction, |
345 | | void *baton, |
346 | | const RegisterInfo *reg_info, |
347 | | RegisterValue ®_value); |
348 | | |
349 | | typedef bool (*WriteRegisterCallback)(EmulateInstruction *instruction, |
350 | | void *baton, const Context &context, |
351 | | const RegisterInfo *reg_info, |
352 | | const RegisterValue ®_value); |
353 | | |
354 | | // Type to represent the condition of an instruction. The UINT32 value is |
355 | | // reserved for the unconditional case and all other value can be used in an |
356 | | // architecture dependent way. |
357 | | typedef uint32_t InstructionCondition; |
358 | | static const InstructionCondition UnconditionalCondition = UINT32_MAX; |
359 | | |
360 | | EmulateInstruction(const ArchSpec &arch); |
361 | | |
362 | 252 | ~EmulateInstruction() override = default; |
363 | | |
364 | | // Mandatory overrides |
365 | | virtual bool |
366 | | SupportsEmulatingInstructionsOfType(InstructionType inst_type) = 0; |
367 | | |
368 | | virtual bool SetTargetTriple(const ArchSpec &arch) = 0; |
369 | | |
370 | | virtual bool ReadInstruction() = 0; |
371 | | |
372 | | virtual bool EvaluateInstruction(uint32_t evaluate_options) = 0; |
373 | | |
374 | 284 | virtual InstructionCondition GetInstructionCondition() { |
375 | 284 | return UnconditionalCondition; |
376 | 284 | } |
377 | | |
378 | | virtual bool TestEmulation(Stream &out_stream, ArchSpec &arch, |
379 | | OptionValueDictionary *test_data) = 0; |
380 | | |
381 | | virtual std::optional<RegisterInfo> |
382 | | GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num) = 0; |
383 | | |
384 | | // Optional overrides |
385 | | virtual bool SetInstruction(const Opcode &insn_opcode, |
386 | | const Address &inst_addr, Target *target); |
387 | | |
388 | | virtual bool CreateFunctionEntryUnwind(UnwindPlan &unwind_plan); |
389 | | |
390 | | static const char *TranslateRegister(lldb::RegisterKind reg_kind, |
391 | | uint32_t reg_num, std::string ®_name); |
392 | | |
393 | | // RegisterInfo variants |
394 | | std::optional<RegisterValue> ReadRegister(const RegisterInfo ®_info); |
395 | | |
396 | | uint64_t ReadRegisterUnsigned(const RegisterInfo ®_info, |
397 | | uint64_t fail_value, bool *success_ptr); |
398 | | |
399 | | bool WriteRegister(const Context &context, const RegisterInfo &ref_info, |
400 | | const RegisterValue ®_value); |
401 | | |
402 | | bool WriteRegisterUnsigned(const Context &context, |
403 | | const RegisterInfo ®_info, uint64_t reg_value); |
404 | | |
405 | | // Register kind and number variants |
406 | | bool ReadRegister(lldb::RegisterKind reg_kind, uint32_t reg_num, |
407 | | RegisterValue ®_value); |
408 | | |
409 | | bool WriteRegister(const Context &context, lldb::RegisterKind reg_kind, |
410 | | uint32_t reg_num, const RegisterValue ®_value); |
411 | | |
412 | | uint64_t ReadRegisterUnsigned(lldb::RegisterKind reg_kind, uint32_t reg_num, |
413 | | uint64_t fail_value, bool *success_ptr); |
414 | | |
415 | | bool WriteRegisterUnsigned(const Context &context, |
416 | | lldb::RegisterKind reg_kind, uint32_t reg_num, |
417 | | uint64_t reg_value); |
418 | | |
419 | | size_t ReadMemory(const Context &context, lldb::addr_t addr, void *dst, |
420 | | size_t dst_len); |
421 | | |
422 | | uint64_t ReadMemoryUnsigned(const Context &context, lldb::addr_t addr, |
423 | | size_t byte_size, uint64_t fail_value, |
424 | | bool *success_ptr); |
425 | | |
426 | | bool WriteMemory(const Context &context, lldb::addr_t addr, const void *src, |
427 | | size_t src_len); |
428 | | |
429 | | bool WriteMemoryUnsigned(const Context &context, lldb::addr_t addr, |
430 | | uint64_t uval, size_t uval_byte_size); |
431 | | |
432 | 275 | uint32_t GetAddressByteSize() const { return m_arch.GetAddressByteSize(); } |
433 | | |
434 | 225 | lldb::ByteOrder GetByteOrder() const { return m_arch.GetByteOrder(); } |
435 | | |
436 | 0 | const Opcode &GetOpcode() const { return m_opcode; } |
437 | | |
438 | 0 | lldb::addr_t GetAddress() const { return m_addr; } |
439 | | |
440 | 98 | const ArchSpec &GetArchitecture() const { return m_arch; } |
441 | | |
442 | | static size_t ReadMemoryFrame(EmulateInstruction *instruction, void *baton, |
443 | | const Context &context, lldb::addr_t addr, |
444 | | void *dst, size_t length); |
445 | | |
446 | | static size_t WriteMemoryFrame(EmulateInstruction *instruction, void *baton, |
447 | | const Context &context, lldb::addr_t addr, |
448 | | const void *dst, size_t length); |
449 | | |
450 | | static bool ReadRegisterFrame(EmulateInstruction *instruction, void *baton, |
451 | | const RegisterInfo *reg_info, |
452 | | RegisterValue ®_value); |
453 | | |
454 | | static bool WriteRegisterFrame(EmulateInstruction *instruction, void *baton, |
455 | | const Context &context, |
456 | | const RegisterInfo *reg_info, |
457 | | const RegisterValue ®_value); |
458 | | |
459 | | static size_t ReadMemoryDefault(EmulateInstruction *instruction, void *baton, |
460 | | const Context &context, lldb::addr_t addr, |
461 | | void *dst, size_t length); |
462 | | |
463 | | static size_t WriteMemoryDefault(EmulateInstruction *instruction, void *baton, |
464 | | const Context &context, lldb::addr_t addr, |
465 | | const void *dst, size_t length); |
466 | | |
467 | | static bool ReadRegisterDefault(EmulateInstruction *instruction, void *baton, |
468 | | const RegisterInfo *reg_info, |
469 | | RegisterValue ®_value); |
470 | | |
471 | | static bool WriteRegisterDefault(EmulateInstruction *instruction, void *baton, |
472 | | const Context &context, |
473 | | const RegisterInfo *reg_info, |
474 | | const RegisterValue ®_value); |
475 | | |
476 | | void SetBaton(void *baton); |
477 | | |
478 | | void SetCallbacks(ReadMemoryCallback read_mem_callback, |
479 | | WriteMemoryCallback write_mem_callback, |
480 | | ReadRegisterCallback read_reg_callback, |
481 | | WriteRegisterCallback write_reg_callback); |
482 | | |
483 | | void SetReadMemCallback(ReadMemoryCallback read_mem_callback); |
484 | | |
485 | | void SetWriteMemCallback(WriteMemoryCallback write_mem_callback); |
486 | | |
487 | | void SetReadRegCallback(ReadRegisterCallback read_reg_callback); |
488 | | |
489 | | void SetWriteRegCallback(WriteRegisterCallback write_reg_callback); |
490 | | |
491 | | static bool GetBestRegisterKindAndNumber(const RegisterInfo *reg_info, |
492 | | lldb::RegisterKind ®_kind, |
493 | | uint32_t ®_num); |
494 | | |
495 | | static uint32_t GetInternalRegisterNumber(RegisterContext *reg_ctx, |
496 | | const RegisterInfo ®_info); |
497 | | |
498 | | protected: |
499 | | ArchSpec m_arch; |
500 | | void *m_baton = nullptr; |
501 | | ReadMemoryCallback m_read_mem_callback = &ReadMemoryDefault; |
502 | | WriteMemoryCallback m_write_mem_callback = &WriteMemoryDefault; |
503 | | ReadRegisterCallback m_read_reg_callback = &ReadRegisterDefault; |
504 | | WriteRegisterCallback m_write_reg_callback = &WriteRegisterDefault; |
505 | | lldb::addr_t m_addr = LLDB_INVALID_ADDRESS; |
506 | | Opcode m_opcode; |
507 | | |
508 | | private: |
509 | | // For EmulateInstruction only |
510 | | EmulateInstruction(const EmulateInstruction &) = delete; |
511 | | const EmulateInstruction &operator=(const EmulateInstruction &) = delete; |
512 | | }; |
513 | | |
514 | | } // namespace lldb_private |
515 | | |
516 | | #endif // LLDB_CORE_EMULATEINSTRUCTION_H |