1 | //===-- EmulateInstruction.cpp --------------------------------------------===// |
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 | #include "lldb/Core/EmulateInstruction.h" |
10 | |
11 | #include "lldb/Core/Address.h" |
12 | #include "lldb/Core/DumpRegisterValue.h" |
13 | #include "lldb/Core/PluginManager.h" |
14 | #include "lldb/Core/StreamFile.h" |
15 | #include "lldb/Symbol/UnwindPlan.h" |
16 | #include "lldb/Target/Process.h" |
17 | #include "lldb/Target/RegisterContext.h" |
18 | #include "lldb/Target/StackFrame.h" |
19 | #include "lldb/Utility/ConstString.h" |
20 | #include "lldb/Utility/DataExtractor.h" |
21 | #include "lldb/Utility/RegisterValue.h" |
22 | #include "lldb/Utility/Status.h" |
23 | #include "lldb/Utility/Stream.h" |
24 | #include "lldb/Utility/StreamString.h" |
25 | #include "lldb/lldb-forward.h" |
26 | #include "lldb/lldb-private-interfaces.h" |
27 | |
28 | #include "llvm/ADT/StringRef.h" |
29 | |
30 | #include <cstring> |
31 | #include <memory> |
32 | |
33 | #include <inttypes.h> |
34 | #include <stdio.h> |
35 | |
36 | namespace lldb_private { |
37 | class Target; |
38 | } |
39 | |
40 | using namespace lldb; |
41 | using namespace lldb_private; |
42 | |
43 | EmulateInstruction * |
44 | EmulateInstruction::FindPlugin(const ArchSpec &arch, |
45 | InstructionType supported_inst_type, |
46 | const char *plugin_name) { |
47 | EmulateInstructionCreateInstance create_callback = nullptr; |
48 | if (plugin_name) { |
49 | ConstString const_plugin_name(plugin_name); |
50 | create_callback = |
51 | PluginManager::GetEmulateInstructionCreateCallbackForPluginName( |
52 | const_plugin_name); |
53 | if (create_callback) { |
54 | EmulateInstruction *emulate_insn_ptr = |
55 | create_callback(arch, supported_inst_type); |
56 | if (emulate_insn_ptr) |
57 | return emulate_insn_ptr; |
58 | } |
59 | } else { |
60 | for (uint32_t idx = 0; |
61 | (create_callback = |
62 | PluginManager::GetEmulateInstructionCreateCallbackAtIndex(idx)) != |
63 | nullptr; |
64 | ++idx) { |
65 | EmulateInstruction *emulate_insn_ptr = |
66 | create_callback(arch, supported_inst_type); |
67 | if (emulate_insn_ptr) |
68 | return emulate_insn_ptr; |
69 | } |
70 | } |
71 | return nullptr; |
72 | } |
73 | |
74 | EmulateInstruction::EmulateInstruction(const ArchSpec &arch) : m_arch(arch) {} |
75 | |
76 | bool EmulateInstruction::ReadRegister(const RegisterInfo *reg_info, |
77 | RegisterValue ®_value) { |
78 | if (m_read_reg_callback != nullptr) |
79 | return m_read_reg_callback(this, m_baton, reg_info, reg_value); |
80 | return false; |
81 | } |
82 | |
83 | bool EmulateInstruction::ReadRegister(lldb::RegisterKind reg_kind, |
84 | uint32_t reg_num, |
85 | RegisterValue ®_value) { |
86 | RegisterInfo reg_info; |
87 | if (GetRegisterInfo(reg_kind, reg_num, reg_info)) |
88 | return ReadRegister(®_info, reg_value); |
89 | return false; |
90 | } |
91 | |
92 | uint64_t EmulateInstruction::ReadRegisterUnsigned(lldb::RegisterKind reg_kind, |
93 | uint32_t reg_num, |
94 | uint64_t fail_value, |
95 | bool *success_ptr) { |
96 | RegisterValue reg_value; |
97 | if (ReadRegister(reg_kind, reg_num, reg_value)) |
98 | return reg_value.GetAsUInt64(fail_value, success_ptr); |
99 | if (success_ptr) |
100 | *success_ptr = false; |
101 | return fail_value; |
102 | } |
103 | |
104 | uint64_t EmulateInstruction::ReadRegisterUnsigned(const RegisterInfo *reg_info, |
105 | uint64_t fail_value, |
106 | bool *success_ptr) { |
107 | RegisterValue reg_value; |
108 | if (ReadRegister(reg_info, reg_value)) |
109 | return reg_value.GetAsUInt64(fail_value, success_ptr); |
110 | if (success_ptr) |
111 | *success_ptr = false; |
112 | return fail_value; |
113 | } |
114 | |
115 | bool EmulateInstruction::WriteRegister(const Context &context, |
116 | const RegisterInfo *reg_info, |
117 | const RegisterValue ®_value) { |
118 | if (m_write_reg_callback != nullptr) |
119 | return m_write_reg_callback(this, m_baton, context, reg_info, reg_value); |
120 | return false; |
121 | } |
122 | |
123 | bool EmulateInstruction::WriteRegister(const Context &context, |
124 | lldb::RegisterKind reg_kind, |
125 | uint32_t reg_num, |
126 | const RegisterValue ®_value) { |
127 | RegisterInfo reg_info; |
128 | if (GetRegisterInfo(reg_kind, reg_num, reg_info)) |
129 | return WriteRegister(context, ®_info, reg_value); |
130 | return false; |
131 | } |
132 | |
133 | bool EmulateInstruction::WriteRegisterUnsigned(const Context &context, |
134 | lldb::RegisterKind reg_kind, |
135 | uint32_t reg_num, |
136 | uint64_t uint_value) { |
137 | RegisterInfo reg_info; |
138 | if (GetRegisterInfo(reg_kind, reg_num, reg_info)) { |
139 | RegisterValue reg_value; |
140 | if (reg_value.SetUInt(uint_value, reg_info.byte_size)) |
141 | return WriteRegister(context, ®_info, reg_value); |
142 | } |
143 | return false; |
144 | } |
145 | |
146 | bool EmulateInstruction::WriteRegisterUnsigned(const Context &context, |
147 | const RegisterInfo *reg_info, |
148 | uint64_t uint_value) { |
149 | if (reg_info != nullptr) { |
150 | RegisterValue reg_value; |
151 | if (reg_value.SetUInt(uint_value, reg_info->byte_size)) |
152 | return WriteRegister(context, reg_info, reg_value); |
153 | } |
154 | return false; |
155 | } |
156 | |
157 | size_t EmulateInstruction::ReadMemory(const Context &context, lldb::addr_t addr, |
158 | void *dst, size_t dst_len) { |
159 | if (m_read_mem_callback != nullptr) |
160 | return m_read_mem_callback(this, m_baton, context, addr, dst, dst_len) == |
161 | dst_len; |
162 | return false; |
163 | } |
164 | |
165 | uint64_t EmulateInstruction::ReadMemoryUnsigned(const Context &context, |
166 | lldb::addr_t addr, |
167 | size_t byte_size, |
168 | uint64_t fail_value, |
169 | bool *success_ptr) { |
170 | uint64_t uval64 = 0; |
171 | bool success = false; |
172 | if (byte_size <= 8) { |
173 | uint8_t buf[sizeof(uint64_t)]; |
174 | size_t bytes_read = |
175 | m_read_mem_callback(this, m_baton, context, addr, buf, byte_size); |
176 | if (bytes_read == byte_size) { |
177 | lldb::offset_t offset = 0; |
178 | DataExtractor data(buf, byte_size, GetByteOrder(), GetAddressByteSize()); |
179 | uval64 = data.GetMaxU64(&offset, byte_size); |
180 | success = true; |
181 | } |
182 | } |
183 | |
184 | if (success_ptr) |
185 | *success_ptr = success; |
186 | |
187 | if (!success) |
188 | uval64 = fail_value; |
189 | return uval64; |
190 | } |
191 | |
192 | bool EmulateInstruction::WriteMemoryUnsigned(const Context &context, |
193 | lldb::addr_t addr, uint64_t uval, |
194 | size_t uval_byte_size) { |
195 | StreamString strm(Stream::eBinary, GetAddressByteSize(), GetByteOrder()); |
196 | strm.PutMaxHex64(uval, uval_byte_size); |
197 | |
198 | size_t bytes_written = m_write_mem_callback( |
199 | this, m_baton, context, addr, strm.GetString().data(), uval_byte_size); |
200 | return (bytes_written == uval_byte_size); |
201 | } |
202 | |
203 | bool EmulateInstruction::WriteMemory(const Context &context, lldb::addr_t addr, |
204 | const void *src, size_t src_len) { |
205 | if (m_write_mem_callback != nullptr) |
206 | return m_write_mem_callback(this, m_baton, context, addr, src, src_len) == |
207 | src_len; |
208 | return false; |
209 | } |
210 | |
211 | void EmulateInstruction::SetBaton(void *baton) { m_baton = baton; } |
212 | |
213 | void EmulateInstruction::SetCallbacks( |
214 | ReadMemoryCallback read_mem_callback, |
215 | WriteMemoryCallback write_mem_callback, |
216 | ReadRegisterCallback read_reg_callback, |
217 | WriteRegisterCallback write_reg_callback) { |
218 | m_read_mem_callback = read_mem_callback; |
219 | m_write_mem_callback = write_mem_callback; |
220 | m_read_reg_callback = read_reg_callback; |
221 | m_write_reg_callback = write_reg_callback; |
222 | } |
223 | |
224 | void EmulateInstruction::SetReadMemCallback( |
225 | ReadMemoryCallback read_mem_callback) { |
226 | m_read_mem_callback = read_mem_callback; |
227 | } |
228 | |
229 | void EmulateInstruction::SetWriteMemCallback( |
230 | WriteMemoryCallback write_mem_callback) { |
231 | m_write_mem_callback = write_mem_callback; |
232 | } |
233 | |
234 | void EmulateInstruction::SetReadRegCallback( |
235 | ReadRegisterCallback read_reg_callback) { |
236 | m_read_reg_callback = read_reg_callback; |
237 | } |
238 | |
239 | void EmulateInstruction::SetWriteRegCallback( |
240 | WriteRegisterCallback write_reg_callback) { |
241 | m_write_reg_callback = write_reg_callback; |
242 | } |
243 | |
244 | // |
245 | // Read & Write Memory and Registers callback functions. |
246 | // |
247 | |
248 | size_t EmulateInstruction::ReadMemoryFrame(EmulateInstruction *instruction, |
249 | void *baton, const Context &context, |
250 | lldb::addr_t addr, void *dst, |
251 | size_t dst_len) { |
252 | if (baton == nullptr || dst == nullptr || dst_len == 0) |
253 | return 0; |
254 | |
255 | StackFrame *frame = (StackFrame *)baton; |
256 | |
257 | ProcessSP process_sp(frame->CalculateProcess()); |
258 | if (process_sp) { |
259 | Status error; |
260 | return process_sp->ReadMemory(addr, dst, dst_len, error); |
261 | } |
262 | return 0; |
263 | } |
264 | |
265 | size_t EmulateInstruction::WriteMemoryFrame(EmulateInstruction *instruction, |
266 | void *baton, const Context &context, |
267 | lldb::addr_t addr, const void *src, |
268 | size_t src_len) { |
269 | if (baton == nullptr || src == nullptr || src_len == 0) |
270 | return 0; |
271 | |
272 | StackFrame *frame = (StackFrame *)baton; |
273 | |
274 | ProcessSP process_sp(frame->CalculateProcess()); |
275 | if (process_sp) { |
276 | Status error; |
277 | return process_sp->WriteMemory(addr, src, src_len, error); |
278 | } |
279 | |
280 | return 0; |
281 | } |
282 | |
283 | bool EmulateInstruction::ReadRegisterFrame(EmulateInstruction *instruction, |
284 | void *baton, |
285 | const RegisterInfo *reg_info, |
286 | RegisterValue ®_value) { |
287 | if (baton == nullptr) |
288 | return false; |
289 | |
290 | StackFrame *frame = (StackFrame *)baton; |
291 | return frame->GetRegisterContext()->ReadRegister(reg_info, reg_value); |
292 | } |
293 | |
294 | bool EmulateInstruction::WriteRegisterFrame(EmulateInstruction *instruction, |
295 | void *baton, const Context &context, |
296 | const RegisterInfo *reg_info, |
297 | const RegisterValue ®_value) { |
298 | if (baton == nullptr) |
299 | return false; |
300 | |
301 | StackFrame *frame = (StackFrame *)baton; |
302 | return frame->GetRegisterContext()->WriteRegister(reg_info, reg_value); |
303 | } |
304 | |
305 | size_t EmulateInstruction::ReadMemoryDefault(EmulateInstruction *instruction, |
306 | void *baton, |
307 | const Context &context, |
308 | lldb::addr_t addr, void *dst, |
309 | size_t length) { |
310 | StreamFile strm(stdout, false); |
311 | strm.Printf(" Read from Memory (address = 0x%" PRIx64 ", length = %" PRIu64 |
312 | ", context = " , |
313 | addr, (uint64_t)length); |
314 | context.Dump(strm, instruction); |
315 | strm.EOL(); |
316 | *((uint64_t *)dst) = 0xdeadbeef; |
317 | return length; |
318 | } |
319 | |
320 | size_t EmulateInstruction::WriteMemoryDefault(EmulateInstruction *instruction, |
321 | void *baton, |
322 | const Context &context, |
323 | lldb::addr_t addr, |
324 | const void *dst, size_t length) { |
325 | StreamFile strm(stdout, false); |
326 | strm.Printf(" Write to Memory (address = 0x%" PRIx64 ", length = %" PRIu64 |
327 | ", context = " , |
328 | addr, (uint64_t)length); |
329 | context.Dump(strm, instruction); |
330 | strm.EOL(); |
331 | return length; |
332 | } |
333 | |
334 | bool EmulateInstruction::ReadRegisterDefault(EmulateInstruction *instruction, |
335 | void *baton, |
336 | const RegisterInfo *reg_info, |
337 | RegisterValue ®_value) { |
338 | StreamFile strm(stdout, false); |
339 | strm.Printf(" Read Register (%s)\n" , reg_info->name); |
340 | lldb::RegisterKind reg_kind; |
341 | uint32_t reg_num; |
342 | if (GetBestRegisterKindAndNumber(reg_info, reg_kind, reg_num)) |
343 | reg_value.SetUInt64((uint64_t)reg_kind << 24 | reg_num); |
344 | else |
345 | reg_value.SetUInt64(0); |
346 | |
347 | return true; |
348 | } |
349 | |
350 | bool EmulateInstruction::WriteRegisterDefault(EmulateInstruction *instruction, |
351 | void *baton, |
352 | const Context &context, |
353 | const RegisterInfo *reg_info, |
354 | const RegisterValue ®_value) { |
355 | StreamFile strm(stdout, false); |
356 | strm.Printf(" Write to Register (name = %s, value = " , reg_info->name); |
357 | DumpRegisterValue(reg_value, &strm, reg_info, false, false, eFormatDefault); |
358 | strm.PutCString(", context = " ); |
359 | context.Dump(strm, instruction); |
360 | strm.EOL(); |
361 | return true; |
362 | } |
363 | |
364 | void EmulateInstruction::Context::Dump(Stream &strm, |
365 | EmulateInstruction *instruction) const { |
366 | switch (type) { |
367 | case eContextReadOpcode: |
368 | strm.PutCString("reading opcode" ); |
369 | break; |
370 | |
371 | case eContextImmediate: |
372 | strm.PutCString("immediate" ); |
373 | break; |
374 | |
375 | case eContextPushRegisterOnStack: |
376 | strm.PutCString("push register" ); |
377 | break; |
378 | |
379 | case eContextPopRegisterOffStack: |
380 | strm.PutCString("pop register" ); |
381 | break; |
382 | |
383 | case eContextAdjustStackPointer: |
384 | strm.PutCString("adjust sp" ); |
385 | break; |
386 | |
387 | case eContextSetFramePointer: |
388 | strm.PutCString("set frame pointer" ); |
389 | break; |
390 | |
391 | case eContextAdjustBaseRegister: |
392 | strm.PutCString("adjusting (writing value back to) a base register" ); |
393 | break; |
394 | |
395 | case eContextRegisterPlusOffset: |
396 | strm.PutCString("register + offset" ); |
397 | break; |
398 | |
399 | case eContextRegisterStore: |
400 | strm.PutCString("store register" ); |
401 | break; |
402 | |
403 | case eContextRegisterLoad: |
404 | strm.PutCString("load register" ); |
405 | break; |
406 | |
407 | case eContextRelativeBranchImmediate: |
408 | strm.PutCString("relative branch immediate" ); |
409 | break; |
410 | |
411 | case eContextAbsoluteBranchRegister: |
412 | strm.PutCString("absolute branch register" ); |
413 | break; |
414 | |
415 | case eContextSupervisorCall: |
416 | strm.PutCString("supervisor call" ); |
417 | break; |
418 | |
419 | case eContextTableBranchReadMemory: |
420 | strm.PutCString("table branch read memory" ); |
421 | break; |
422 | |
423 | case eContextWriteRegisterRandomBits: |
424 | strm.PutCString("write random bits to a register" ); |
425 | break; |
426 | |
427 | case eContextWriteMemoryRandomBits: |
428 | strm.PutCString("write random bits to a memory address" ); |
429 | break; |
430 | |
431 | case eContextArithmetic: |
432 | strm.PutCString("arithmetic" ); |
433 | break; |
434 | |
435 | case eContextReturnFromException: |
436 | strm.PutCString("return from exception" ); |
437 | break; |
438 | |
439 | default: |
440 | strm.PutCString("unrecognized context." ); |
441 | break; |
442 | } |
443 | |
444 | switch (info_type) { |
445 | case eInfoTypeRegisterPlusOffset: |
446 | strm.Printf(" (reg_plus_offset = %s%+" PRId64 ")" , |
447 | info.RegisterPlusOffset.reg.name, |
448 | info.RegisterPlusOffset.signed_offset); |
449 | break; |
450 | |
451 | case eInfoTypeRegisterPlusIndirectOffset: |
452 | strm.Printf(" (reg_plus_reg = %s + %s)" , |
453 | info.RegisterPlusIndirectOffset.base_reg.name, |
454 | info.RegisterPlusIndirectOffset.offset_reg.name); |
455 | break; |
456 | |
457 | case eInfoTypeRegisterToRegisterPlusOffset: |
458 | strm.Printf(" (base_and_imm_offset = %s%+" PRId64 ", data_reg = %s)" , |
459 | info.RegisterToRegisterPlusOffset.base_reg.name, |
460 | info.RegisterToRegisterPlusOffset.offset, |
461 | info.RegisterToRegisterPlusOffset.data_reg.name); |
462 | break; |
463 | |
464 | case eInfoTypeRegisterToRegisterPlusIndirectOffset: |
465 | strm.Printf(" (base_and_reg_offset = %s + %s, data_reg = %s)" , |
466 | info.RegisterToRegisterPlusIndirectOffset.base_reg.name, |
467 | info.RegisterToRegisterPlusIndirectOffset.offset_reg.name, |
468 | info.RegisterToRegisterPlusIndirectOffset.data_reg.name); |
469 | break; |
470 | |
471 | case eInfoTypeRegisterRegisterOperands: |
472 | strm.Printf(" (register to register binary op: %s and %s)" , |
473 | info.RegisterRegisterOperands.operand1.name, |
474 | info.RegisterRegisterOperands.operand2.name); |
475 | break; |
476 | |
477 | case eInfoTypeOffset: |
478 | strm.Printf(" (signed_offset = %+" PRId64 ")" , info.signed_offset); |
479 | break; |
480 | |
481 | case eInfoTypeRegister: |
482 | strm.Printf(" (reg = %s)" , info.reg.name); |
483 | break; |
484 | |
485 | case eInfoTypeImmediate: |
486 | strm.Printf(" (unsigned_immediate = %" PRIu64 " (0x%16.16" PRIx64 "))" , |
487 | info.unsigned_immediate, info.unsigned_immediate); |
488 | break; |
489 | |
490 | case eInfoTypeImmediateSigned: |
491 | strm.Printf(" (signed_immediate = %+" PRId64 " (0x%16.16" PRIx64 "))" , |
492 | info.signed_immediate, info.signed_immediate); |
493 | break; |
494 | |
495 | case eInfoTypeAddress: |
496 | strm.Printf(" (address = 0x%" PRIx64 ")" , info.address); |
497 | break; |
498 | |
499 | case eInfoTypeISAAndImmediate: |
500 | strm.Printf(" (isa = %u, unsigned_immediate = %u (0x%8.8x))" , |
501 | info.ISAAndImmediate.isa, info.ISAAndImmediate.unsigned_data32, |
502 | info.ISAAndImmediate.unsigned_data32); |
503 | break; |
504 | |
505 | case eInfoTypeISAAndImmediateSigned: |
506 | strm.Printf(" (isa = %u, signed_immediate = %i (0x%8.8x))" , |
507 | info.ISAAndImmediateSigned.isa, |
508 | info.ISAAndImmediateSigned.signed_data32, |
509 | info.ISAAndImmediateSigned.signed_data32); |
510 | break; |
511 | |
512 | case eInfoTypeISA: |
513 | strm.Printf(" (isa = %u)" , info.isa); |
514 | break; |
515 | |
516 | case eInfoTypeNoArgs: |
517 | break; |
518 | } |
519 | } |
520 | |
521 | bool EmulateInstruction::SetInstruction(const Opcode &opcode, |
522 | const Address &inst_addr, |
523 | Target *target) { |
524 | m_opcode = opcode; |
525 | m_addr = LLDB_INVALID_ADDRESS; |
526 | if (inst_addr.IsValid()) { |
527 | if (target != nullptr) |
528 | m_addr = inst_addr.GetLoadAddress(target); |
529 | if (m_addr == LLDB_INVALID_ADDRESS) |
530 | m_addr = inst_addr.GetFileAddress(); |
531 | } |
532 | return true; |
533 | } |
534 | |
535 | bool EmulateInstruction::GetBestRegisterKindAndNumber( |
536 | const RegisterInfo *reg_info, lldb::RegisterKind ®_kind, |
537 | uint32_t ®_num) { |
538 | // Generic and DWARF should be the two most popular register kinds when |
539 | // emulating instructions since they are the most platform agnostic... |
540 | reg_num = reg_info->kinds[eRegisterKindGeneric]; |
541 | if (reg_num != LLDB_INVALID_REGNUM) { |
542 | reg_kind = eRegisterKindGeneric; |
543 | return true; |
544 | } |
545 | |
546 | reg_num = reg_info->kinds[eRegisterKindDWARF]; |
547 | if (reg_num != LLDB_INVALID_REGNUM) { |
548 | reg_kind = eRegisterKindDWARF; |
549 | return true; |
550 | } |
551 | |
552 | reg_num = reg_info->kinds[eRegisterKindLLDB]; |
553 | if (reg_num != LLDB_INVALID_REGNUM) { |
554 | reg_kind = eRegisterKindLLDB; |
555 | return true; |
556 | } |
557 | |
558 | reg_num = reg_info->kinds[eRegisterKindEHFrame]; |
559 | if (reg_num != LLDB_INVALID_REGNUM) { |
560 | reg_kind = eRegisterKindEHFrame; |
561 | return true; |
562 | } |
563 | |
564 | reg_num = reg_info->kinds[eRegisterKindProcessPlugin]; |
565 | if (reg_num != LLDB_INVALID_REGNUM) { |
566 | reg_kind = eRegisterKindProcessPlugin; |
567 | return true; |
568 | } |
569 | return false; |
570 | } |
571 | |
572 | uint32_t |
573 | EmulateInstruction::GetInternalRegisterNumber(RegisterContext *reg_ctx, |
574 | const RegisterInfo ®_info) { |
575 | lldb::RegisterKind reg_kind; |
576 | uint32_t reg_num; |
577 | if (reg_ctx && GetBestRegisterKindAndNumber(®_info, reg_kind, reg_num)) |
578 | return reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); |
579 | return LLDB_INVALID_REGNUM; |
580 | } |
581 | |
582 | bool EmulateInstruction::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) { |
583 | unwind_plan.Clear(); |
584 | return false; |
585 | } |
586 | |