LLDB mainline
DisassemblerLLVMC.cpp
Go to the documentation of this file.
1//===-- DisassemblerLLVMC.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 "DisassemblerLLVMC.h"
10
11#include "llvm-c/Disassembler.h"
12#include "llvm/ADT/SmallString.h"
13#include "llvm/ADT/StringExtras.h"
14#include "llvm/MC/MCAsmInfo.h"
15#include "llvm/MC/MCContext.h"
16#include "llvm/MC/MCDisassembler/MCDisassembler.h"
17#include "llvm/MC/MCDisassembler/MCExternalSymbolizer.h"
18#include "llvm/MC/MCDisassembler/MCRelocationInfo.h"
19#include "llvm/MC/MCInst.h"
20#include "llvm/MC/MCInstPrinter.h"
21#include "llvm/MC/MCInstrAnalysis.h"
22#include "llvm/MC/MCInstrInfo.h"
23#include "llvm/MC/MCRegisterInfo.h"
24#include "llvm/MC/MCSubtargetInfo.h"
25#include "llvm/MC/MCTargetOptions.h"
26#include "llvm/MC/TargetRegistry.h"
27#include "llvm/Support/ErrorHandling.h"
28#include "llvm/Support/ScopedPrinter.h"
29#include "llvm/Support/TargetSelect.h"
30#include "llvm/TargetParser/AArch64TargetParser.h"
31
32#include "lldb/Core/Address.h"
33#include "lldb/Core/Debugger.h"
34#include "lldb/Core/Module.h"
38#include "lldb/Target/Process.h"
42#include "lldb/Target/Target.h"
45#include "lldb/Utility/Log.h"
47#include "lldb/Utility/Stream.h"
48#include <optional>
49
50using namespace lldb;
51using namespace lldb_private;
52
54
56public:
57 static std::unique_ptr<MCDisasmInstance>
58 Create(const char *triple, const char *cpu, const char *features_str,
59 unsigned flavor, DisassemblerLLVMC &owner);
60
61 ~MCDisasmInstance() = default;
62
63 bool GetMCInst(const uint8_t *opcode_data, size_t opcode_data_len,
64 lldb::addr_t pc, llvm::MCInst &mc_inst, uint64_t &size) const;
65 void PrintMCInst(llvm::MCInst &mc_inst, lldb::addr_t pc,
66 std::string &inst_string, std::string &comments_string);
67 void SetStyle(bool use_hex_immed, HexImmediateStyle hex_style);
68 void SetUseColor(bool use_color);
69 bool GetUseColor() const;
70 bool CanBranch(llvm::MCInst &mc_inst) const;
71 bool HasDelaySlot(llvm::MCInst &mc_inst) const;
72 bool IsCall(llvm::MCInst &mc_inst) const;
73 bool IsLoad(llvm::MCInst &mc_inst) const;
74 bool IsBarrier(llvm::MCInst &mc_inst) const;
75 bool IsAuthenticated(llvm::MCInst &mc_inst) const;
76
77private:
78 MCDisasmInstance(std::unique_ptr<llvm::MCInstrInfo> &&instr_info_up,
79 std::unique_ptr<llvm::MCRegisterInfo> &&reg_info_up,
80 std::unique_ptr<llvm::MCSubtargetInfo> &&subtarget_info_up,
81 llvm::MCTargetOptions mc_options,
82 std::unique_ptr<llvm::MCAsmInfo> &&asm_info_up,
83 std::unique_ptr<llvm::MCContext> &&context_up,
84 std::unique_ptr<llvm::MCDisassembler> &&disasm_up,
85 std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up,
86 std::unique_ptr<llvm::MCInstrAnalysis> &&instr_analysis_up);
87
88 std::unique_ptr<llvm::MCInstrInfo> m_instr_info_up;
89 std::unique_ptr<llvm::MCRegisterInfo> m_reg_info_up;
90 std::unique_ptr<llvm::MCSubtargetInfo> m_subtarget_info_up;
91 llvm::MCTargetOptions m_mc_options;
92 std::unique_ptr<llvm::MCAsmInfo> m_asm_info_up;
93 std::unique_ptr<llvm::MCContext> m_context_up;
94 std::unique_ptr<llvm::MCDisassembler> m_disasm_up;
95 std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_up;
96 std::unique_ptr<llvm::MCInstrAnalysis> m_instr_analysis_up;
97};
98
99namespace x86 {
100
101/// These are the three values deciding instruction control flow kind.
102/// InstructionLengthDecode function decodes an instruction and get this struct.
103///
104/// primary_opcode
105/// Primary opcode of the instruction.
106/// For one-byte opcode instruction, it's the first byte after prefix.
107/// For two- and three-byte opcodes, it's the second byte.
108///
109/// opcode_len
110/// The length of opcode in bytes. Valid opcode lengths are 1, 2, or 3.
111///
112/// modrm
113/// ModR/M byte of the instruction.
114/// Bits[7:6] indicate MOD. Bits[5:3] specify a register and R/M bits[2:0]
115/// may contain a register or specify an addressing mode, depending on MOD.
121
122/// Determine the InstructionControlFlowKind based on opcode and modrm bytes.
123/// Refer to http://ref.x86asm.net/coder.html for the full list of opcode and
124/// instruction set.
125///
126/// \param[in] opcode_and_modrm
127/// Contains primary_opcode byte, its length, and ModR/M byte.
128/// Refer to the struct InstructionOpcodeAndModrm for details.
129///
130/// \return
131/// The control flow kind of the instruction or
132/// eInstructionControlFlowKindOther if the instruction doesn't affect
133/// the control flow of the program.
136 uint8_t opcode = opcode_and_modrm.primary_opcode;
137 uint8_t opcode_len = opcode_and_modrm.opcode_len;
138 uint8_t modrm = opcode_and_modrm.modrm;
139
140 if (opcode_len > 2)
142
143 if (opcode >= 0x70 && opcode <= 0x7F) {
144 if (opcode_len == 1)
146 else
148 }
149
150 if (opcode >= 0x80 && opcode <= 0x8F) {
151 if (opcode_len == 2)
153 else
155 }
156
157 switch (opcode) {
158 case 0x9A:
159 if (opcode_len == 1)
161 break;
162 case 0xFF:
163 if (opcode_len == 1) {
164 uint8_t modrm_reg = (modrm >> 3) & 7;
165 if (modrm_reg == 2)
167 else if (modrm_reg == 3)
169 else if (modrm_reg == 4)
171 else if (modrm_reg == 5)
173 }
174 break;
175 case 0xE8:
176 if (opcode_len == 1)
178 break;
179 case 0xCD:
180 case 0xCC:
181 case 0xCE:
182 case 0xF1:
183 if (opcode_len == 1)
185 break;
186 case 0xCF:
187 if (opcode_len == 1)
189 break;
190 case 0xE9:
191 case 0xEB:
192 if (opcode_len == 1)
194 break;
195 case 0xEA:
196 if (opcode_len == 1)
198 break;
199 case 0xE3:
200 case 0xE0:
201 case 0xE1:
202 case 0xE2:
203 if (opcode_len == 1)
205 break;
206 case 0xC3:
207 case 0xC2:
208 if (opcode_len == 1)
210 break;
211 case 0xCB:
212 case 0xCA:
213 if (opcode_len == 1)
215 break;
216 case 0x05:
217 case 0x34:
218 if (opcode_len == 2)
220 break;
221 case 0x35:
222 case 0x07:
223 if (opcode_len == 2)
225 break;
226 case 0x01:
227 if (opcode_len == 2) {
228 switch (modrm) {
229 case 0xc1:
231 case 0xc2:
232 case 0xc3:
234 default:
235 break;
236 }
237 }
238 break;
239 default:
240 break;
241 }
242
244}
245
246/// Decode an instruction into opcode, modrm and opcode_len.
247/// Refer to http://ref.x86asm.net/coder.html for the instruction bytes layout.
248/// Opcodes in x86 are generally the first byte of instruction, though two-byte
249/// instructions and prefixes exist. ModR/M is the byte following the opcode
250/// and adds additional information for how the instruction is executed.
251///
252/// \param[in] inst_bytes
253/// Raw bytes of the instruction
254///
255///
256/// \param[in] bytes_len
257/// The length of the inst_bytes array.
258///
259/// \param[in] is_exec_mode_64b
260/// If true, the execution mode is 64 bit.
261///
262/// \return
263/// Returns decoded instruction as struct InstructionOpcodeAndModrm, holding
264/// primary_opcode, opcode_len and modrm byte. Refer to the struct definition
265/// for more details.
266/// Otherwise if the given instruction is invalid, returns std::nullopt.
267std::optional<InstructionOpcodeAndModrm>
268InstructionLengthDecode(const uint8_t *inst_bytes, int bytes_len,
269 bool is_exec_mode_64b) {
270 int op_idx = 0;
271 bool prefix_done = false;
272 InstructionOpcodeAndModrm ret = {0, 0, 0};
273
274 // In most cases, the primary_opcode is the first byte of the instruction
275 // but some instructions have a prefix to be skipped for these calculations.
276 // The following mapping is inspired from libipt's instruction decoding logic
277 // in `src/pt_ild.c`
278 while (!prefix_done) {
279 if (op_idx >= bytes_len)
280 return std::nullopt;
281
282 ret.primary_opcode = inst_bytes[op_idx];
283 switch (ret.primary_opcode) {
284 // prefix_ignore
285 case 0x26:
286 case 0x2e:
287 case 0x36:
288 case 0x3e:
289 case 0x64:
290 case 0x65:
291 // prefix_osz, prefix_asz
292 case 0x66:
293 case 0x67:
294 // prefix_lock, prefix_f2, prefix_f3
295 case 0xf0:
296 case 0xf2:
297 case 0xf3:
298 op_idx++;
299 break;
300
301 // prefix_rex
302 case 0x40:
303 case 0x41:
304 case 0x42:
305 case 0x43:
306 case 0x44:
307 case 0x45:
308 case 0x46:
309 case 0x47:
310 case 0x48:
311 case 0x49:
312 case 0x4a:
313 case 0x4b:
314 case 0x4c:
315 case 0x4d:
316 case 0x4e:
317 case 0x4f:
318 if (is_exec_mode_64b)
319 op_idx++;
320 else
321 prefix_done = true;
322 break;
323
324 // prefix_vex_c4, c5
325 case 0xc5:
326 if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
327 prefix_done = true;
328 break;
329 }
330
331 ret.opcode_len = 2;
332 ret.primary_opcode = inst_bytes[op_idx + 2];
333 ret.modrm = inst_bytes[op_idx + 3];
334 return ret;
335
336 case 0xc4:
337 if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
338 prefix_done = true;
339 break;
340 }
341 ret.opcode_len = inst_bytes[op_idx + 1] & 0x1f;
342 ret.primary_opcode = inst_bytes[op_idx + 3];
343 ret.modrm = inst_bytes[op_idx + 4];
344 return ret;
345
346 // prefix_evex
347 case 0x62:
348 if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
349 prefix_done = true;
350 break;
351 }
352 ret.opcode_len = inst_bytes[op_idx + 1] & 0x03;
353 ret.primary_opcode = inst_bytes[op_idx + 4];
354 ret.modrm = inst_bytes[op_idx + 5];
355 return ret;
356
357 default:
358 prefix_done = true;
359 break;
360 }
361 } // prefix done
362
363 ret.primary_opcode = inst_bytes[op_idx];
364 ret.modrm = inst_bytes[op_idx + 1];
365 ret.opcode_len = 1;
366
367 // If the first opcode is 0F, it's two- or three- byte opcodes.
368 if (ret.primary_opcode == 0x0F) {
369 ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
370
371 if (ret.primary_opcode == 0x38) {
372 ret.opcode_len = 3;
373 ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
374 ret.modrm = inst_bytes[op_idx + 1];
375 } else if (ret.primary_opcode == 0x3A) {
376 ret.opcode_len = 3;
377 ret.primary_opcode = inst_bytes[++op_idx];
378 ret.modrm = inst_bytes[op_idx + 1];
379 } else if ((ret.primary_opcode & 0xf8) == 0x38) {
380 ret.opcode_len = 0;
381 ret.primary_opcode = inst_bytes[++op_idx];
382 ret.modrm = inst_bytes[op_idx + 1];
383 } else if (ret.primary_opcode == 0x0F) {
384 ret.opcode_len = 3;
385 // opcode is 0x0F, no needs to update
386 ret.modrm = inst_bytes[op_idx + 1];
387 } else {
388 ret.opcode_len = 2;
389 ret.modrm = inst_bytes[op_idx + 1];
390 }
391 }
392
393 return ret;
394}
395
397 Opcode m_opcode) {
398 std::optional<InstructionOpcodeAndModrm> ret;
399
400 if (m_opcode.GetOpcodeBytes() == nullptr || m_opcode.GetByteSize() <= 0) {
401 // x86_64 and i386 instructions are categorized as Opcode::Type::eTypeBytes
403 }
404
405 // Opcode bytes will be decoded into primary_opcode, modrm and opcode length.
406 // These are the three values deciding instruction control flow kind.
407 ret = InstructionLengthDecode((const uint8_t *)m_opcode.GetOpcodeBytes(),
408 m_opcode.GetByteSize(), is_exec_mode_64b);
409 if (!ret)
411 else
412 return MapOpcodeIntoControlFlowKind(*ret);
413}
414
415} // namespace x86
416
418public:
420 const lldb_private::Address &address,
421 AddressClass addr_class)
422 : Instruction(address, addr_class),
423 m_disasm_wp(std::static_pointer_cast<DisassemblerLLVMC>(
424 disasm.shared_from_this())) {}
425
426 ~InstructionLLVMC() override = default;
427
428 bool DoesBranch() override {
430 return m_does_branch;
431 }
432
433 bool HasDelaySlot() override {
435 return m_has_delay_slot;
436 }
437
438 bool IsLoad() override {
440 return m_is_load;
441 }
442
443 bool IsBarrier() override {
445 return m_is_barrier;
446 }
447
448 bool IsAuthenticated() override {
450 return m_is_authenticated;
451 }
452
454 DisassemblerScope disasm(*this);
455 return GetDisasmToUse(is_alternate_isa, disasm);
456 }
457
458 size_t Decode(const lldb_private::Disassembler &disassembler,
459 const lldb_private::DataExtractor &data,
460 lldb::offset_t data_offset) override {
461 // All we have to do is read the opcode which can be easy for some
462 // architectures
463 DisassemblerScope disasm(*this);
464 if (disasm) {
465 const ArchSpec &arch = disasm->GetArchitecture();
466 const lldb::ByteOrder byte_order = data.GetByteOrder();
467
468 const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize();
469 const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize();
470 if (min_op_byte_size == max_op_byte_size) {
471 // Fixed size instructions, just read that amount of data.
472 if (!data.ValidOffsetForDataOfSize(data_offset, min_op_byte_size))
473 return 0;
474
475 switch (min_op_byte_size) {
476 case 1:
477 m_opcode.SetOpcode8(data.GetU8(&data_offset), byte_order);
478 break;
479
480 case 2:
481 m_opcode.SetOpcode16(data.GetU16(&data_offset), byte_order);
482 break;
483
484 case 4:
485 m_opcode.SetOpcode32(data.GetU32(&data_offset), byte_order);
486 break;
487
488 case 8:
489 m_opcode.SetOpcode64(data.GetU64(&data_offset), byte_order);
490 break;
491
492 default:
493 m_opcode.SetOpcodeBytes(data.PeekData(data_offset, min_op_byte_size),
494 min_op_byte_size);
495 break;
496 }
497 } else {
498 bool is_alternate_isa = false;
500 GetDisasmToUse(is_alternate_isa, disasm);
501
502 const llvm::Triple::ArchType machine = arch.GetMachine();
503 if (machine == llvm::Triple::arm || machine == llvm::Triple::thumb) {
504 if (machine == llvm::Triple::thumb || is_alternate_isa) {
505 uint32_t thumb_opcode = data.GetU16(&data_offset);
506 if ((thumb_opcode & 0xe000) != 0xe000 ||
507 ((thumb_opcode & 0x1800u) == 0)) {
508 m_opcode.SetOpcode16(thumb_opcode, byte_order);
509 m_is_valid = true;
510 } else {
511 thumb_opcode <<= 16;
512 thumb_opcode |= data.GetU16(&data_offset);
513 m_opcode.SetOpcode16_2(thumb_opcode, byte_order);
514 m_is_valid = true;
515 }
516 } else {
517 m_opcode.SetOpcode32(data.GetU32(&data_offset), byte_order);
518 m_is_valid = true;
519 }
520 } else {
521 // The opcode isn't evenly sized, so we need to actually use the llvm
522 // disassembler to parse it and get the size.
523 uint8_t *opcode_data =
524 const_cast<uint8_t *>(data.PeekData(data_offset, 1));
525 const size_t opcode_data_len = data.BytesLeft(data_offset);
526 const addr_t pc = m_address.GetFileAddress();
527 llvm::MCInst inst;
528
529 uint64_t inst_size = 0;
530 m_is_valid = mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len,
531 pc, inst, inst_size);
532 m_opcode.Clear();
533 if (inst_size != 0) {
534 if (arch.GetTriple().isRISCV())
535 m_opcode.SetOpcode16_32TupleBytes(opcode_data, inst_size,
536 byte_order);
537 else
538 m_opcode.SetOpcodeBytes(opcode_data, inst_size);
539 }
540 }
541 }
542 return m_opcode.GetByteSize();
543 }
544 return 0;
545 }
546
547 void AppendComment(std::string &description) {
548 if (m_comment.empty())
549 m_comment.swap(description);
550 else {
551 m_comment.append(", ");
552 m_comment.append(description);
553 }
554 }
555
558 DisassemblerScope disasm(*this, exe_ctx);
559 if (disasm) {
560 if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86)
561 return x86::GetControlFlowKind(/*is_64b=*/false, m_opcode);
562 else if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
563 return x86::GetControlFlowKind(/*is_64b=*/true, m_opcode);
564 }
565
567 }
568
570 const lldb_private::ExecutionContext *exe_ctx) override {
571 DataExtractor data;
572 const AddressClass address_class = GetAddressClass();
573
574 if (m_opcode.GetData(data)) {
575 std::string out_string;
576 std::string markup_out_string;
577 std::string comment_string;
578 std::string markup_comment_string;
579
580 DisassemblerScope disasm(*this, exe_ctx);
581 if (disasm) {
583
584 if (address_class == AddressClass::eCodeAlternateISA)
585 mc_disasm_ptr = disasm->m_alternate_disasm_up.get();
586 else
587 mc_disasm_ptr = disasm->m_disasm_up.get();
588
589 lldb::addr_t pc = m_address.GetFileAddress();
590 m_using_file_addr = true;
591
592 bool use_hex_immediates = true;
594
595 if (exe_ctx) {
596 Target *target = exe_ctx->GetTargetPtr();
597 if (target) {
598 use_hex_immediates = target->GetUseHexImmediates();
599 hex_style = target->GetHexImmediateStyle();
600
601 const lldb::addr_t load_addr = m_address.GetLoadAddress(target);
602 if (load_addr != LLDB_INVALID_ADDRESS) {
603 pc = load_addr;
604 m_using_file_addr = false;
605 }
606 }
607 }
608
609 const uint8_t *opcode_data = data.GetDataStart();
610 const size_t opcode_data_len = data.GetByteSize();
611 llvm::MCInst inst;
612 uint64_t inst_size = 0;
613 bool valid = mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len, pc,
614 inst, inst_size);
615
616 if (valid && inst_size > 0) {
617 mc_disasm_ptr->SetStyle(use_hex_immediates, hex_style);
618
619 const bool saved_use_color = mc_disasm_ptr->GetUseColor();
620 mc_disasm_ptr->SetUseColor(false);
621 mc_disasm_ptr->PrintMCInst(inst, pc, out_string, comment_string);
622 mc_disasm_ptr->SetUseColor(true);
623 mc_disasm_ptr->PrintMCInst(inst, pc, markup_out_string,
624 markup_comment_string);
625 mc_disasm_ptr->SetUseColor(saved_use_color);
626
627 if (!comment_string.empty()) {
628 AppendComment(comment_string);
629 }
630 }
631
632 if (inst_size == 0) {
633 m_comment.assign("unknown opcode");
634 inst_size = m_opcode.GetByteSize();
635 StreamString mnemonic_strm;
636 lldb::offset_t offset = 0;
637 lldb::ByteOrder byte_order = data.GetByteOrder();
638 switch (inst_size) {
639 case 1: {
640 const uint8_t uval8 = data.GetU8(&offset);
641 m_opcode.SetOpcode8(uval8, byte_order);
642 m_opcode_name.assign(".byte");
643 mnemonic_strm.Printf("0x%2.2x", uval8);
644 } break;
645 case 2: {
646 const uint16_t uval16 = data.GetU16(&offset);
647 m_opcode.SetOpcode16(uval16, byte_order);
648 m_opcode_name.assign(".short");
649 mnemonic_strm.Printf("0x%4.4x", uval16);
650 } break;
651 case 4: {
652 const uint32_t uval32 = data.GetU32(&offset);
653 m_opcode.SetOpcode32(uval32, byte_order);
654 m_opcode_name.assign(".long");
655 mnemonic_strm.Printf("0x%8.8x", uval32);
656 } break;
657 case 8: {
658 const uint64_t uval64 = data.GetU64(&offset);
659 m_opcode.SetOpcode64(uval64, byte_order);
660 m_opcode_name.assign(".quad");
661 mnemonic_strm.Printf("0x%16.16" PRIx64, uval64);
662 } break;
663 default:
664 if (inst_size == 0)
665 return;
666 else {
667 const uint8_t *bytes = data.PeekData(offset, inst_size);
668 if (bytes == nullptr)
669 return;
670 m_opcode_name.assign(".byte");
671 m_opcode.SetOpcodeBytes(bytes, inst_size);
672 mnemonic_strm.Printf("0x%2.2x", bytes[0]);
673 for (uint32_t i = 1; i < inst_size; ++i)
674 mnemonic_strm.Printf(" 0x%2.2x", bytes[i]);
675 }
676 break;
677 }
678 m_mnemonics = std::string(mnemonic_strm.GetString());
679 return;
680 }
681
682 static RegularExpression s_regex(
683 llvm::StringRef("[ \t]*([^ ^\t]+)[ \t]*([^ ^\t].*)?"));
684
685 llvm::SmallVector<llvm::StringRef, 4> matches;
686 if (s_regex.Execute(out_string, &matches)) {
687 m_opcode_name = matches[1].str();
688 m_mnemonics = matches[2].str();
689 }
690 matches.clear();
691 if (s_regex.Execute(markup_out_string, &matches)) {
692 m_markup_opcode_name = matches[1].str();
693 m_markup_mnemonics = matches[2].str();
694 }
695 }
696 }
697 }
698
699 bool IsValid() const { return m_is_valid; }
700
701 bool UsingFileAddress() const { return m_using_file_addr; }
702 size_t GetByteSize() const { return m_opcode.GetByteSize(); }
703
704 /// Grants exclusive access to the disassembler and initializes it with the
705 /// given InstructionLLVMC and an optional ExecutionContext.
707 std::shared_ptr<DisassemblerLLVMC> m_disasm;
708
709 public:
712 const lldb_private::ExecutionContext *exe_ctx = nullptr)
713 : m_disasm(i.m_disasm_wp.lock()) {
714 m_disasm->m_mutex.lock();
715 m_disasm->m_inst = &i;
716 m_disasm->m_exe_ctx = exe_ctx;
717 }
718 ~DisassemblerScope() { m_disasm->m_mutex.unlock(); }
719
720 /// Evaluates to true if this scope contains a valid disassembler.
721 operator bool() const { return static_cast<bool>(m_disasm); }
722
723 std::shared_ptr<DisassemblerLLVMC> operator->() { return m_disasm; }
724 };
725
726 static llvm::StringRef::const_iterator
727 ConsumeWhitespace(llvm::StringRef::const_iterator osi,
728 llvm::StringRef::const_iterator ose) {
729 while (osi != ose) {
730 switch (*osi) {
731 default:
732 return osi;
733 case ' ':
734 case '\t':
735 break;
736 }
737 ++osi;
738 }
739
740 return osi;
741 }
742
743 static std::pair<bool, llvm::StringRef::const_iterator>
744 ConsumeChar(llvm::StringRef::const_iterator osi, const char c,
745 llvm::StringRef::const_iterator ose) {
746 bool found = false;
747
748 osi = ConsumeWhitespace(osi, ose);
749 if (osi != ose && *osi == c) {
750 found = true;
751 ++osi;
752 }
753
754 return std::make_pair(found, osi);
755 }
756
757 static std::pair<Operand, llvm::StringRef::const_iterator>
758 ParseRegisterName(llvm::StringRef::const_iterator osi,
759 llvm::StringRef::const_iterator ose) {
760 Operand ret;
761 ret.m_type = Operand::Type::Register;
762 std::string str;
763
764 osi = ConsumeWhitespace(osi, ose);
765
766 while (osi != ose) {
767 if (*osi >= '0' && *osi <= '9') {
768 if (str.empty()) {
769 return std::make_pair(Operand(), osi);
770 } else {
771 str.push_back(*osi);
772 }
773 } else if (*osi >= 'a' && *osi <= 'z') {
774 str.push_back(*osi);
775 } else {
776 switch (*osi) {
777 default:
778 if (str.empty()) {
779 return std::make_pair(Operand(), osi);
780 } else {
781 ret.m_register = ConstString(str);
782 return std::make_pair(ret, osi);
783 }
784 case '%':
785 if (!str.empty()) {
786 return std::make_pair(Operand(), osi);
787 }
788 break;
789 }
790 }
791 ++osi;
792 }
793
794 ret.m_register = ConstString(str);
795 return std::make_pair(ret, osi);
796 }
797
798 static std::pair<Operand, llvm::StringRef::const_iterator>
799 ParseImmediate(llvm::StringRef::const_iterator osi,
800 llvm::StringRef::const_iterator ose) {
801 Operand ret;
802 ret.m_type = Operand::Type::Immediate;
803 std::string str;
804 bool is_hex = false;
805
806 osi = ConsumeWhitespace(osi, ose);
807
808 while (osi != ose) {
809 if (*osi >= '0' && *osi <= '9') {
810 str.push_back(*osi);
811 } else if (*osi >= 'a' && *osi <= 'f') {
812 if (is_hex) {
813 str.push_back(*osi);
814 } else {
815 return std::make_pair(Operand(), osi);
816 }
817 } else {
818 switch (*osi) {
819 default:
820 if (str.empty()) {
821 return std::make_pair(Operand(), osi);
822 } else {
823 ret.m_immediate = strtoull(str.c_str(), nullptr, 0);
824 return std::make_pair(ret, osi);
825 }
826 case 'x':
827 if (str == "0") {
828 is_hex = true;
829 str.push_back(*osi);
830 } else {
831 return std::make_pair(Operand(), osi);
832 }
833 break;
834 case '#':
835 case '$':
836 if (!str.empty()) {
837 return std::make_pair(Operand(), osi);
838 }
839 break;
840 case '-':
841 if (str.empty()) {
842 ret.m_negative = true;
843 } else {
844 return std::make_pair(Operand(), osi);
845 }
846 }
847 }
848 ++osi;
849 }
850
851 ret.m_immediate = strtoull(str.c_str(), nullptr, 0);
852 return std::make_pair(ret, osi);
853 }
854
855 // -0x5(%rax,%rax,2)
856 static std::pair<Operand, llvm::StringRef::const_iterator>
857 ParseIntelIndexedAccess(llvm::StringRef::const_iterator osi,
858 llvm::StringRef::const_iterator ose) {
859 std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator =
860 ParseImmediate(osi, ose);
861 if (offset_and_iterator.first.IsValid()) {
862 osi = offset_and_iterator.second;
863 }
864
865 bool found = false;
866 std::tie(found, osi) = ConsumeChar(osi, '(', ose);
867 if (!found) {
868 return std::make_pair(Operand(), osi);
869 }
870
871 std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator =
872 ParseRegisterName(osi, ose);
873 if (base_and_iterator.first.IsValid()) {
874 osi = base_and_iterator.second;
875 } else {
876 return std::make_pair(Operand(), osi);
877 }
878
879 std::tie(found, osi) = ConsumeChar(osi, ',', ose);
880 if (!found) {
881 return std::make_pair(Operand(), osi);
882 }
883
884 std::pair<Operand, llvm::StringRef::const_iterator> index_and_iterator =
885 ParseRegisterName(osi, ose);
886 if (index_and_iterator.first.IsValid()) {
887 osi = index_and_iterator.second;
888 } else {
889 return std::make_pair(Operand(), osi);
890 }
891
892 std::tie(found, osi) = ConsumeChar(osi, ',', ose);
893 if (!found) {
894 return std::make_pair(Operand(), osi);
895 }
896
897 std::pair<Operand, llvm::StringRef::const_iterator>
898 multiplier_and_iterator = ParseImmediate(osi, ose);
899 if (index_and_iterator.first.IsValid()) {
900 osi = index_and_iterator.second;
901 } else {
902 return std::make_pair(Operand(), osi);
903 }
904
905 std::tie(found, osi) = ConsumeChar(osi, ')', ose);
906 if (!found) {
907 return std::make_pair(Operand(), osi);
908 }
909
910 Operand product;
911 product.m_type = Operand::Type::Product;
912 product.m_children.push_back(index_and_iterator.first);
913 product.m_children.push_back(multiplier_and_iterator.first);
914
915 Operand index;
916 index.m_type = Operand::Type::Sum;
917 index.m_children.push_back(base_and_iterator.first);
918 index.m_children.push_back(product);
919
920 if (offset_and_iterator.first.IsValid()) {
921 Operand offset;
922 offset.m_type = Operand::Type::Sum;
923 offset.m_children.push_back(offset_and_iterator.first);
924 offset.m_children.push_back(index);
925
926 Operand deref;
927 deref.m_type = Operand::Type::Dereference;
928 deref.m_children.push_back(offset);
929 return std::make_pair(deref, osi);
930 } else {
931 Operand deref;
932 deref.m_type = Operand::Type::Dereference;
933 deref.m_children.push_back(index);
934 return std::make_pair(deref, osi);
935 }
936 }
937
938 // -0x10(%rbp)
939 static std::pair<Operand, llvm::StringRef::const_iterator>
940 ParseIntelDerefAccess(llvm::StringRef::const_iterator osi,
941 llvm::StringRef::const_iterator ose) {
942 std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator =
943 ParseImmediate(osi, ose);
944 if (offset_and_iterator.first.IsValid()) {
945 osi = offset_and_iterator.second;
946 }
947
948 bool found = false;
949 std::tie(found, osi) = ConsumeChar(osi, '(', ose);
950 if (!found) {
951 return std::make_pair(Operand(), osi);
952 }
953
954 std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator =
955 ParseRegisterName(osi, ose);
956 if (base_and_iterator.first.IsValid()) {
957 osi = base_and_iterator.second;
958 } else {
959 return std::make_pair(Operand(), osi);
960 }
961
962 std::tie(found, osi) = ConsumeChar(osi, ')', ose);
963 if (!found) {
964 return std::make_pair(Operand(), osi);
965 }
966
967 if (offset_and_iterator.first.IsValid()) {
968 Operand offset;
969 offset.m_type = Operand::Type::Sum;
970 offset.m_children.push_back(offset_and_iterator.first);
971 offset.m_children.push_back(base_and_iterator.first);
972
973 Operand deref;
974 deref.m_type = Operand::Type::Dereference;
975 deref.m_children.push_back(offset);
976 return std::make_pair(deref, osi);
977 } else {
978 Operand deref;
979 deref.m_type = Operand::Type::Dereference;
980 deref.m_children.push_back(base_and_iterator.first);
981 return std::make_pair(deref, osi);
982 }
983 }
984
985 // [sp, #8]!
986 static std::pair<Operand, llvm::StringRef::const_iterator>
987 ParseARMOffsetAccess(llvm::StringRef::const_iterator osi,
988 llvm::StringRef::const_iterator ose) {
989 bool found = false;
990 std::tie(found, osi) = ConsumeChar(osi, '[', ose);
991 if (!found) {
992 return std::make_pair(Operand(), osi);
993 }
994
995 std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator =
996 ParseRegisterName(osi, ose);
997 if (base_and_iterator.first.IsValid()) {
998 osi = base_and_iterator.second;
999 } else {
1000 return std::make_pair(Operand(), osi);
1001 }
1002
1003 std::tie(found, osi) = ConsumeChar(osi, ',', ose);
1004 if (!found) {
1005 return std::make_pair(Operand(), osi);
1006 }
1007
1008 std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator =
1009 ParseImmediate(osi, ose);
1010 if (offset_and_iterator.first.IsValid()) {
1011 osi = offset_and_iterator.second;
1012 }
1013
1014 std::tie(found, osi) = ConsumeChar(osi, ']', ose);
1015 if (!found) {
1016 return std::make_pair(Operand(), osi);
1017 }
1018
1019 Operand offset;
1020 offset.m_type = Operand::Type::Sum;
1021 offset.m_children.push_back(offset_and_iterator.first);
1022 offset.m_children.push_back(base_and_iterator.first);
1023
1024 Operand deref;
1025 deref.m_type = Operand::Type::Dereference;
1026 deref.m_children.push_back(offset);
1027 return std::make_pair(deref, osi);
1028 }
1029
1030 // [sp]
1031 static std::pair<Operand, llvm::StringRef::const_iterator>
1032 ParseARMDerefAccess(llvm::StringRef::const_iterator osi,
1033 llvm::StringRef::const_iterator ose) {
1034 bool found = false;
1035 std::tie(found, osi) = ConsumeChar(osi, '[', ose);
1036 if (!found) {
1037 return std::make_pair(Operand(), osi);
1038 }
1039
1040 std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator =
1041 ParseRegisterName(osi, ose);
1042 if (base_and_iterator.first.IsValid()) {
1043 osi = base_and_iterator.second;
1044 } else {
1045 return std::make_pair(Operand(), osi);
1046 }
1047
1048 std::tie(found, osi) = ConsumeChar(osi, ']', ose);
1049 if (!found) {
1050 return std::make_pair(Operand(), osi);
1051 }
1052
1053 Operand deref;
1054 deref.m_type = Operand::Type::Dereference;
1055 deref.m_children.push_back(base_and_iterator.first);
1056 return std::make_pair(deref, osi);
1057 }
1058
1059 static void DumpOperand(const Operand &op, Stream &s) {
1060 switch (op.m_type) {
1061 case Operand::Type::Dereference:
1062 s.PutCString("*");
1063 DumpOperand(op.m_children[0], s);
1064 break;
1065 case Operand::Type::Immediate:
1066 if (op.m_negative) {
1067 s.PutCString("-");
1068 }
1069 s.PutCString(llvm::to_string(op.m_immediate));
1070 break;
1071 case Operand::Type::Invalid:
1072 s.PutCString("Invalid");
1073 break;
1074 case Operand::Type::Product:
1075 s.PutCString("(");
1076 DumpOperand(op.m_children[0], s);
1077 s.PutCString("*");
1078 DumpOperand(op.m_children[1], s);
1079 s.PutCString(")");
1080 break;
1081 case Operand::Type::Register:
1083 break;
1084 case Operand::Type::Sum:
1085 s.PutCString("(");
1086 DumpOperand(op.m_children[0], s);
1087 s.PutCString("+");
1088 DumpOperand(op.m_children[1], s);
1089 s.PutCString(")");
1090 break;
1091 }
1092 }
1093
1096 const char *operands_string = GetOperands(nullptr);
1097
1098 if (!operands_string) {
1099 return false;
1100 }
1101
1102 llvm::StringRef operands_ref(operands_string);
1103
1104 llvm::StringRef::const_iterator osi = operands_ref.begin();
1105 llvm::StringRef::const_iterator ose = operands_ref.end();
1106
1107 while (osi != ose) {
1108 Operand operand;
1109 llvm::StringRef::const_iterator iter;
1110
1111 if ((std::tie(operand, iter) = ParseIntelIndexedAccess(osi, ose),
1112 operand.IsValid()) ||
1113 (std::tie(operand, iter) = ParseIntelDerefAccess(osi, ose),
1114 operand.IsValid()) ||
1115 (std::tie(operand, iter) = ParseARMOffsetAccess(osi, ose),
1116 operand.IsValid()) ||
1117 (std::tie(operand, iter) = ParseARMDerefAccess(osi, ose),
1118 operand.IsValid()) ||
1119 (std::tie(operand, iter) = ParseRegisterName(osi, ose),
1120 operand.IsValid()) ||
1121 (std::tie(operand, iter) = ParseImmediate(osi, ose),
1122 operand.IsValid())) {
1123 osi = iter;
1124 operands.push_back(operand);
1125 } else {
1126 return false;
1127 }
1128
1129 std::pair<bool, llvm::StringRef::const_iterator> found_and_iter =
1130 ConsumeChar(osi, ',', ose);
1131 if (found_and_iter.first) {
1132 osi = found_and_iter.second;
1133 }
1134
1135 osi = ConsumeWhitespace(osi, ose);
1136 }
1137
1138 DisassemblerSP disasm_sp = m_disasm_wp.lock();
1139
1140 if (disasm_sp && operands.size() > 1) {
1141 // TODO tie this into the MC Disassembler's notion of clobbers.
1142 switch (disasm_sp->GetArchitecture().GetMachine()) {
1143 default:
1144 break;
1145 case llvm::Triple::x86:
1146 case llvm::Triple::x86_64:
1147 operands[operands.size() - 1].m_clobbered = true;
1148 break;
1149 case llvm::Triple::arm:
1150 operands[0].m_clobbered = true;
1151 break;
1152 }
1153 }
1154
1156 StreamString ss;
1157
1158 ss.Printf("[%s] expands to %zu operands:\n", operands_string,
1159 operands.size());
1160 for (const Operand &operand : operands) {
1161 ss.PutCString(" ");
1162 DumpOperand(operand, ss);
1163 ss.PutCString("\n");
1164 }
1165
1166 log->PutString(ss.GetString());
1167 }
1168
1169 return true;
1170 }
1171
1172 bool IsCall() override {
1174 return m_is_call;
1175 }
1176
1177protected:
1178 std::weak_ptr<DisassemblerLLVMC> m_disasm_wp;
1179
1180 bool m_is_valid = false;
1181 bool m_using_file_addr = false;
1183
1184 // Be conservative. If we didn't understand the instruction, say it:
1185 // - Might branch
1186 // - Does not have a delay slot
1187 // - Is not a call
1188 // - Is not a load
1189 // - Is not an authenticated instruction
1190 bool m_does_branch = true;
1191 bool m_has_delay_slot = false;
1192 bool m_is_call = false;
1193 bool m_is_load = false;
1195 bool m_is_barrier = false;
1196
1199 return;
1200
1201 DisassemblerScope disasm(*this);
1202 if (!disasm)
1203 return;
1204
1205 DataExtractor data;
1206 if (!m_opcode.GetData(data))
1207 return;
1208
1209 bool is_alternate_isa;
1210 lldb::addr_t pc = m_address.GetFileAddress();
1212 GetDisasmToUse(is_alternate_isa, disasm);
1213 const uint8_t *opcode_data = data.GetDataStart();
1214 const size_t opcode_data_len = data.GetByteSize();
1215 llvm::MCInst inst;
1216 uint64_t inst_size = 0;
1217 const bool valid = mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len,
1218 pc, inst, inst_size);
1219 if (!valid)
1220 return;
1221
1223 m_does_branch = mc_disasm_ptr->CanBranch(inst);
1224 m_has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst);
1225 m_is_call = mc_disasm_ptr->IsCall(inst);
1226 m_is_load = mc_disasm_ptr->IsLoad(inst);
1227 m_is_authenticated = mc_disasm_ptr->IsAuthenticated(inst);
1228 m_is_barrier = mc_disasm_ptr->IsBarrier(inst);
1229 }
1230
1231private:
1233 GetDisasmToUse(bool &is_alternate_isa, DisassemblerScope &disasm) {
1234 is_alternate_isa = false;
1235 if (disasm) {
1236 if (disasm->m_alternate_disasm_up) {
1237 const AddressClass address_class = GetAddressClass();
1238
1239 if (address_class == AddressClass::eCodeAlternateISA) {
1240 is_alternate_isa = true;
1241 return disasm->m_alternate_disasm_up.get();
1242 }
1243 }
1244 return disasm->m_disasm_up.get();
1245 }
1246 return nullptr;
1247 }
1248};
1249
1250std::unique_ptr<DisassemblerLLVMC::MCDisasmInstance>
1252 const char *cpu,
1253 const char *features_str,
1254 unsigned flavor,
1255 DisassemblerLLVMC &owner) {
1256 using Instance = std::unique_ptr<DisassemblerLLVMC::MCDisasmInstance>;
1257
1258 llvm::Triple triple(triple_name);
1259
1260 std::string Status;
1261 const llvm::Target *curr_target =
1262 llvm::TargetRegistry::lookupTarget(triple, Status);
1263 if (!curr_target)
1264 return Instance();
1265
1266 std::unique_ptr<llvm::MCInstrInfo> instr_info_up(
1267 curr_target->createMCInstrInfo());
1268 if (!instr_info_up)
1269 return Instance();
1270
1271 std::unique_ptr<llvm::MCRegisterInfo> reg_info_up(
1272 curr_target->createMCRegInfo(triple));
1273 if (!reg_info_up)
1274 return Instance();
1275
1276 std::unique_ptr<llvm::MCSubtargetInfo> subtarget_info_up(
1277 curr_target->createMCSubtargetInfo(triple, cpu, features_str));
1278 if (!subtarget_info_up)
1279 return Instance();
1280
1281 llvm::MCTargetOptions MCOptions;
1282 std::unique_ptr<llvm::MCAsmInfo> asm_info_up(
1283 curr_target->createMCAsmInfo(*reg_info_up, triple, MCOptions));
1284 if (!asm_info_up)
1285 return Instance();
1286
1287 std::unique_ptr<llvm::MCContext> context_up(new llvm::MCContext(
1288 llvm::Triple(triple), *asm_info_up, *reg_info_up, *subtarget_info_up));
1289 if (!context_up)
1290 return Instance();
1291
1292 std::unique_ptr<llvm::MCDisassembler> disasm_up(
1293 curr_target->createMCDisassembler(*subtarget_info_up, *context_up));
1294 if (!disasm_up)
1295 return Instance();
1296
1297 std::unique_ptr<llvm::MCRelocationInfo> rel_info_up(
1298 curr_target->createMCRelocationInfo(triple, *context_up));
1299 if (!rel_info_up)
1300 return Instance();
1301
1302 std::unique_ptr<llvm::MCSymbolizer> symbolizer_up(
1303 curr_target->createMCSymbolizer(
1304 triple, nullptr, DisassemblerLLVMC::SymbolLookupCallback, &owner,
1305 context_up.get(), std::move(rel_info_up)));
1306 disasm_up->setSymbolizer(std::move(symbolizer_up));
1307
1308 unsigned asm_printer_variant =
1309 flavor == ~0U ? asm_info_up->getAssemblerDialect() : flavor;
1310
1311 std::unique_ptr<llvm::MCInstPrinter> instr_printer_up(
1312 curr_target->createMCInstPrinter(llvm::Triple{triple},
1313 asm_printer_variant, *asm_info_up,
1314 *instr_info_up, *reg_info_up));
1315 if (!instr_printer_up)
1316 return Instance();
1317
1318 instr_printer_up->setPrintBranchImmAsAddress(true);
1319
1320 // Not all targets may have registered createMCInstrAnalysis().
1321 std::unique_ptr<llvm::MCInstrAnalysis> instr_analysis_up(
1322 curr_target->createMCInstrAnalysis(instr_info_up.get()));
1323
1324 return Instance(new MCDisasmInstance(
1325 std::move(instr_info_up), std::move(reg_info_up),
1326 std::move(subtarget_info_up), MCOptions, std::move(asm_info_up),
1327 std::move(context_up), std::move(disasm_up), std::move(instr_printer_up),
1328 std::move(instr_analysis_up)));
1329}
1330
1332 std::unique_ptr<llvm::MCInstrInfo> &&instr_info_up,
1333 std::unique_ptr<llvm::MCRegisterInfo> &&reg_info_up,
1334 std::unique_ptr<llvm::MCSubtargetInfo> &&subtarget_info_up,
1335 llvm::MCTargetOptions mc_options,
1336 std::unique_ptr<llvm::MCAsmInfo> &&asm_info_up,
1337 std::unique_ptr<llvm::MCContext> &&context_up,
1338 std::unique_ptr<llvm::MCDisassembler> &&disasm_up,
1339 std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up,
1340 std::unique_ptr<llvm::MCInstrAnalysis> &&instr_analysis_up)
1341 : m_instr_info_up(std::move(instr_info_up)),
1342 m_reg_info_up(std::move(reg_info_up)),
1343 m_subtarget_info_up(std::move(subtarget_info_up)),
1344 m_mc_options(mc_options), m_asm_info_up(std::move(asm_info_up)),
1345 m_context_up(std::move(context_up)), m_disasm_up(std::move(disasm_up)),
1346 m_instr_printer_up(std::move(instr_printer_up)),
1347 m_instr_analysis_up(std::move(instr_analysis_up)) {
1350}
1351
1353 size_t opcode_data_len,
1355 llvm::MCInst &mc_inst,
1356 uint64_t &size) const {
1357 llvm::ArrayRef<uint8_t> data(opcode_data, opcode_data_len);
1358 llvm::MCDisassembler::DecodeStatus status;
1359
1360 status = m_disasm_up->getInstruction(mc_inst, size, data, pc, llvm::nulls());
1361 if (status == llvm::MCDisassembler::Success)
1362 return true;
1363 else
1364 return false;
1365}
1366
1368 llvm::MCInst &mc_inst, lldb::addr_t pc, std::string &inst_string,
1369 std::string &comments_string) {
1370 llvm::raw_string_ostream inst_stream(inst_string);
1371 llvm::raw_string_ostream comments_stream(comments_string);
1372
1373 inst_stream.enable_colors(m_instr_printer_up->getUseColor());
1374 m_instr_printer_up->setCommentStream(comments_stream);
1375 m_instr_printer_up->printInst(&mc_inst, pc, llvm::StringRef(),
1376 *m_subtarget_info_up, inst_stream);
1377 m_instr_printer_up->setCommentStream(llvm::nulls());
1378
1379 static std::string g_newlines("\r\n");
1380
1381 for (size_t newline_pos = 0;
1382 (newline_pos = comments_string.find_first_of(g_newlines, newline_pos)) !=
1383 comments_string.npos;
1384 /**/) {
1385 comments_string.replace(comments_string.begin() + newline_pos,
1386 comments_string.begin() + newline_pos + 1, 1, ' ');
1387 }
1388}
1389
1391 bool use_hex_immed, HexImmediateStyle hex_style) {
1392 m_instr_printer_up->setPrintImmHex(use_hex_immed);
1393 switch (hex_style) {
1394 case eHexStyleC:
1395 m_instr_printer_up->setPrintHexStyle(llvm::HexStyle::C);
1396 break;
1397 case eHexStyleAsm:
1398 m_instr_printer_up->setPrintHexStyle(llvm::HexStyle::Asm);
1399 break;
1400 }
1401}
1402
1404 m_instr_printer_up->setUseColor(use_color);
1405}
1406
1408 return m_instr_printer_up->getUseColor();
1409}
1410
1412 llvm::MCInst &mc_inst) const {
1414 return m_instr_analysis_up->mayAffectControlFlow(mc_inst, *m_reg_info_up);
1415 return m_instr_info_up->get(mc_inst.getOpcode())
1416 .mayAffectControlFlow(mc_inst, *m_reg_info_up);
1417}
1418
1420 llvm::MCInst &mc_inst) const {
1421 return m_instr_info_up->get(mc_inst.getOpcode()).hasDelaySlot();
1422}
1423
1424bool DisassemblerLLVMC::MCDisasmInstance::IsCall(llvm::MCInst &mc_inst) const {
1426 return m_instr_analysis_up->isCall(mc_inst);
1427 return m_instr_info_up->get(mc_inst.getOpcode()).isCall();
1428}
1429
1430bool DisassemblerLLVMC::MCDisasmInstance::IsLoad(llvm::MCInst &mc_inst) const {
1431 return m_instr_info_up->get(mc_inst.getOpcode()).mayLoad();
1432}
1433
1435 llvm::MCInst &mc_inst) const {
1436 return m_instr_info_up->get(mc_inst.getOpcode()).isBarrier();
1437}
1438
1440 llvm::MCInst &mc_inst) const {
1441 const auto &InstrDesc = m_instr_info_up->get(mc_inst.getOpcode());
1442
1443 // Treat software auth traps (brk 0xc470 + aut key, where 0x70 == 'p', 0xc4
1444 // == 'a' + 'c') as authenticated instructions for reporting purposes, in
1445 // addition to the standard authenticated instructions specified in ARMv8.3.
1446 bool IsBrkC47x = false;
1447 if (InstrDesc.isTrap() && mc_inst.getNumOperands() == 1) {
1448 const llvm::MCOperand &Op0 = mc_inst.getOperand(0);
1449 if (Op0.isImm() && Op0.getImm() >= 0xc470 && Op0.getImm() <= 0xc474)
1450 IsBrkC47x = true;
1451 }
1452
1453 return InstrDesc.isAuthenticated() || IsBrkC47x;
1454}
1455
1457 llvm::StringRef subtarget_features, std::string &user_feature_overrides) {
1458
1459 llvm::SmallVector<std::string, 0> valid_user_flags;
1460 llvm::StringSet<> user_disabled_features;
1461
1462 for (llvm::StringRef flag : llvm::split(user_feature_overrides, ",")) {
1463 bool is_valid = true;
1464 flag = flag.trim();
1465
1466 if (flag.empty())
1467 continue;
1468
1469 std::string warning_reason;
1470 llvm::raw_string_ostream ostream(warning_reason);
1471
1472 // 1. Must be at least 2 chars (e.g., "+a").
1473 // 2. Name cannot start with a digit (e.g. "+123" is invalid).
1474 // 3. Must start with '+' or '-'.
1475 // 4. All characters after the sign must be alphanumeric or '_' or '-'.
1476 if (flag.size() < 2) {
1477 is_valid = false;
1478 ostream << "must have a name";
1479 } else if (std::isdigit(static_cast<unsigned char>(flag[1]))) {
1480 is_valid = false;
1481 ostream << "name cannot start with a digit";
1482 } else if (flag.front() != '+' && flag.front() != '-') {
1483 is_valid = false;
1484 ostream << "must start with '+' or '-'";
1485 } else if (!std::all_of(flag.begin() + 1, flag.end(), [](unsigned char c) {
1486 return std::isalnum(c) || c == '_' || c == '-';
1487 })) {
1488 is_valid = false;
1489 ostream << "contains invalid characters";
1490 }
1491 if (!is_valid) {
1492 std::string message =
1493 ("feature flag '" + flag + "': " + warning_reason).str();
1494 lldb_private::Debugger::ReportWarning(message, std::nullopt);
1495 continue;
1496 }
1497 valid_user_flags.push_back(flag.str());
1498
1499 if (flag.starts_with('-'))
1500 user_disabled_features.insert(flag.substr(1));
1501 }
1502
1503 // User feature string with only valid flags.
1504 llvm::SmallVector<std::string, 0> final_features;
1505
1506 // Allow users to override default additional features.
1507 if (!subtarget_features.empty()) {
1508 for (llvm::StringRef flag : llvm::split(subtarget_features, ",")) {
1509 flag = flag.trim();
1510 if (flag.empty())
1511 continue;
1512 // By default, if both +flag and -flag are present in the feature string,
1513 // disassembler keeps the feature enabled (+flag).
1514 // To respect user intent, we make -flag(user) take priority over the
1515 // default +flag coming from ELF.
1516 bool add_flag = true;
1517 if (flag.size() >= 2 && flag.starts_with('+')) {
1518 llvm::StringRef feature_name = flag.substr(1);
1519 if (user_disabled_features.count(feature_name))
1520 add_flag = false;
1521 }
1522 if (add_flag)
1523 final_features.push_back(flag.str());
1524 }
1525 }
1526
1527 // Append user flags.
1528 final_features.insert(final_features.end(), valid_user_flags.begin(),
1529 valid_user_flags.end());
1530 user_feature_overrides = llvm::join(final_features, ",");
1531}
1532
1534 const char *flavor_string,
1535 const char *cpu_string,
1536 const char *features_string)
1537 : Disassembler(arch, flavor_string), m_exe_ctx(nullptr), m_inst(nullptr),
1539 m_adrp_insn() {
1540 if (!FlavorValidForArchSpec(arch, m_flavor.c_str())) {
1541 m_flavor.assign("default");
1542 }
1543
1544 const bool cpu_or_features_overriden = cpu_string || features_string;
1545 unsigned flavor = ~0U;
1546 llvm::Triple triple = arch.GetTriple();
1547
1548 // So far the only supported flavor is "intel" on x86. The base class will
1549 // set this correctly coming in.
1550 if (triple.getArch() == llvm::Triple::x86 ||
1551 triple.getArch() == llvm::Triple::x86_64) {
1552 if (m_flavor == "intel") {
1553 flavor = 1;
1554 } else if (m_flavor == "att") {
1555 flavor = 0;
1556 }
1557 }
1558
1559 ArchSpec thumb_arch(arch);
1560 if (triple.getArch() == llvm::Triple::arm) {
1561 std::string thumb_arch_name(thumb_arch.GetTriple().getArchName().str());
1562 // Replace "arm" with "thumb" so we get all thumb variants correct
1563 if (thumb_arch_name.size() > 3) {
1564 thumb_arch_name.erase(0, 3);
1565 thumb_arch_name.insert(0, "thumb");
1566 } else {
1567 thumb_arch_name = "thumbv9.3a";
1568 }
1569 thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name));
1570 }
1571
1572 // If no sub architecture specified then use the most recent arm architecture
1573 // so the disassembler will return all instructions. Without it we will see a
1574 // lot of unknown opcodes if the code uses instructions which are not
1575 // available in the oldest arm version (which is used when no sub architecture
1576 // is specified).
1577 if (triple.getArch() == llvm::Triple::arm &&
1578 triple.getSubArch() == llvm::Triple::NoSubArch)
1579 triple.setArchName("armv9.3a");
1580
1581 std::string features_str =
1582 features_string ? std::string(features_string) : "";
1583 const char *triple_str = triple.getTriple().c_str();
1584
1585 // ARM Cortex M0-M7 devices only execute thumb instructions
1586 if (arch.IsAlwaysThumbInstructions()) {
1587 triple_str = thumb_arch.GetTriple().getTriple().c_str();
1588 if (!features_string)
1589 features_str += "+fp-armv8,";
1590 }
1591
1592 const char *cpu = cpu_string;
1593
1594 if (!cpu_or_features_overriden) {
1595 switch (arch.GetCore()) {
1598 cpu = "mips32";
1599 break;
1602 cpu = "mips32r2";
1603 break;
1606 cpu = "mips32r3";
1607 break;
1610 cpu = "mips32r5";
1611 break;
1614 cpu = "mips32r6";
1615 break;
1618 cpu = "mips64";
1619 break;
1622 cpu = "mips64r2";
1623 break;
1626 cpu = "mips64r3";
1627 break;
1630 cpu = "mips64r5";
1631 break;
1634 cpu = "mips64r6";
1635 break;
1636 default:
1637 cpu = "";
1638 break;
1639 }
1640 }
1641
1642 if (arch.IsMIPS() && !cpu_or_features_overriden) {
1643 uint32_t arch_flags = arch.GetFlags();
1644 if (arch_flags & ArchSpec::eMIPSAse_msa)
1645 features_str += "+msa,";
1646 if (arch_flags & ArchSpec::eMIPSAse_dsp)
1647 features_str += "+dsp,";
1648 if (arch_flags & ArchSpec::eMIPSAse_dspr2)
1649 features_str += "+dspr2,";
1650 }
1651
1652 // If any AArch64 variant, enable latest ISA with all extensions unless the
1653 // CPU or features were overridden.
1654 if (triple.isAArch64() && !cpu_or_features_overriden) {
1655 features_str += "+all,";
1656 if (triple.getVendor() == llvm::Triple::Apple)
1657 cpu = "apple-latest";
1658 }
1659
1660 if (triple.isRISCV()) {
1661 auto subtarget_features = arch.GetSubtargetFeatures().getString();
1662 if (!cpu_or_features_overriden) {
1663 if (!subtarget_features.empty()) {
1664 features_str += subtarget_features;
1665 } else {
1666 uint32_t arch_flags = arch.GetFlags();
1667 if (arch_flags & ArchSpec::eRISCV_rvc)
1668 features_str += "+c,";
1669 if (arch_flags & ArchSpec::eRISCV_rve)
1670 features_str += "+e,";
1671 if ((arch_flags & ArchSpec::eRISCV_float_abi_single) ==
1673 features_str += "+f,";
1674 if ((arch_flags & ArchSpec::eRISCV_float_abi_double) ==
1676 features_str += "+f,+d,";
1677 if ((arch_flags & ArchSpec::eRISCV_float_abi_quad) ==
1679 features_str += "+f,+d,+q,";
1680 // FIXME: how do we detect features such as `+a`, `+m`?
1681 // Turn them on by default now, since everyone seems to use them
1682 features_str += "+a,+m,";
1683 }
1684 } else {
1685 // Merges default subtarget features with user overrides.
1686 UpdateSubtargetFeatures(subtarget_features, features_str);
1687 }
1688 }
1689
1690 // We use m_disasm_up.get() to tell whether we are valid or not, so if this
1691 // isn't good for some reason, we won't be valid and FindPlugin will fail and
1692 // we won't get used.
1693 m_disasm_up = MCDisasmInstance::Create(triple_str, cpu, features_str.c_str(),
1694 flavor, *this);
1695
1696 llvm::Triple::ArchType llvm_arch = triple.getArch();
1697
1698 // For arm CPUs that can execute arm or thumb instructions, also create a
1699 // thumb instruction disassembler.
1700 if (llvm_arch == llvm::Triple::arm) {
1701 std::string thumb_triple(thumb_arch.GetTriple().getTriple());
1702 m_alternate_disasm_up = MCDisasmInstance::Create(
1703 thumb_triple.c_str(), "", features_str.c_str(), flavor, *this);
1704 if (!m_alternate_disasm_up)
1705 m_disasm_up.reset();
1706
1707 } else if (arch.IsMIPS()) {
1708 /* Create alternate disassembler for MIPS16 and microMIPS */
1709 uint32_t arch_flags = arch.GetFlags();
1710 if (arch_flags & ArchSpec::eMIPSAse_mips16)
1711 features_str += "+mips16,";
1712 else if (arch_flags & ArchSpec::eMIPSAse_micromips)
1713 features_str += "+micromips,";
1714
1715 m_alternate_disasm_up = MCDisasmInstance::Create(
1716 triple_str, cpu, features_str.c_str(), flavor, *this);
1717 if (!m_alternate_disasm_up)
1718 m_disasm_up.reset();
1719 }
1720}
1721
1723
1725 const char *flavor,
1726 const char *cpu,
1727 const char *features) {
1728 if (arch.GetTriple().getArch() != llvm::Triple::UnknownArch) {
1729 auto disasm_sp =
1730 std::make_shared<DisassemblerLLVMC>(arch, flavor, cpu, features);
1731 if (disasm_sp && disasm_sp->IsValid())
1732 return disasm_sp;
1733 }
1734 return lldb::DisassemblerSP();
1735}
1736
1738 const DataExtractor &data,
1739 lldb::offset_t data_offset,
1740 size_t num_instructions,
1741 bool append, bool data_from_file) {
1742 if (!append)
1743 m_instruction_list.Clear();
1744
1745 if (!IsValid())
1746 return 0;
1747
1748 m_data_from_file = data_from_file;
1749 uint32_t data_cursor = data_offset;
1750 const size_t data_byte_size = data.GetByteSize();
1751 uint32_t instructions_parsed = 0;
1752 Address inst_addr(base_addr);
1753
1754 while (data_cursor < data_byte_size &&
1755 instructions_parsed < num_instructions) {
1756
1757 AddressClass address_class = AddressClass::eCode;
1758
1760 address_class = inst_addr.GetAddressClass();
1761
1762 InstructionSP inst_sp(
1763 new InstructionLLVMC(*this, inst_addr, address_class));
1764
1765 if (!inst_sp)
1766 break;
1767
1768 uint32_t inst_size = inst_sp->Decode(*this, data, data_cursor);
1769
1770 if (inst_size == 0)
1771 break;
1772
1773 m_instruction_list.Append(inst_sp);
1774 data_cursor += inst_size;
1775 inst_addr.Slide(inst_size);
1776 instructions_parsed++;
1777 }
1778
1779 return data_cursor - data_offset;
1780}
1781
1784 "Disassembler that uses LLVM MC to disassemble "
1785 "i386, x86_64, ARM, and ARM64.",
1787
1788 llvm::InitializeAllTargetInfos();
1789 llvm::InitializeAllTargetMCs();
1790 llvm::InitializeAllAsmParsers();
1791 llvm::InitializeAllDisassemblers();
1792}
1793
1797
1798int DisassemblerLLVMC::OpInfoCallback(void *disassembler, uint64_t pc,
1799 uint64_t offset, uint64_t size,
1800 int tag_type, void *tag_bug) {
1801 return static_cast<DisassemblerLLVMC *>(disassembler)
1802 ->OpInfo(pc, offset, size, tag_type, tag_bug);
1803}
1804
1805const char *DisassemblerLLVMC::SymbolLookupCallback(void *disassembler,
1806 uint64_t value,
1807 uint64_t *type, uint64_t pc,
1808 const char **name) {
1809 return static_cast<DisassemblerLLVMC *>(disassembler)
1810 ->SymbolLookup(value, type, pc, name);
1811}
1812
1814 const lldb_private::ArchSpec &arch, const char *flavor) {
1815 llvm::Triple triple = arch.GetTriple();
1816 if (flavor == nullptr || strcmp(flavor, "default") == 0)
1817 return true;
1818
1819 if (triple.getArch() == llvm::Triple::x86 ||
1820 triple.getArch() == llvm::Triple::x86_64) {
1821 return strcmp(flavor, "intel") == 0 || strcmp(flavor, "att") == 0;
1822 } else
1823 return false;
1824}
1825
1826bool DisassemblerLLVMC::IsValid() const { return m_disasm_up.operator bool(); }
1827
1828int DisassemblerLLVMC::OpInfo(uint64_t PC, uint64_t Offset, uint64_t Size,
1829 int tag_type, void *tag_bug) {
1830 switch (tag_type) {
1831 default:
1832 break;
1833 case 1:
1834 memset(tag_bug, 0, sizeof(::LLVMOpInfo1));
1835 break;
1836 }
1837 return 0;
1838}
1839
1840const char *DisassemblerLLVMC::SymbolLookup(uint64_t value, uint64_t *type_ptr,
1841 uint64_t pc, const char **name) {
1842 if (*type_ptr) {
1843 if (m_exe_ctx && m_inst) {
1844 // std::string remove_this_prior_to_checkin;
1845 Target *target = m_exe_ctx ? m_exe_ctx->GetTargetPtr() : nullptr;
1846 Address value_so_addr;
1847 Address pc_so_addr;
1848 if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64 ||
1849 target->GetArchitecture().GetMachine() == llvm::Triple::aarch64_be ||
1850 target->GetArchitecture().GetMachine() == llvm::Triple::aarch64_32) {
1851 if (*type_ptr == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {
1853 m_adrp_insn = value;
1854 *name = nullptr;
1855 *type_ptr = LLVMDisassembler_ReferenceType_InOut_None;
1856 return nullptr;
1857 }
1858 // If this instruction is an ADD and
1859 // the previous instruction was an ADRP and
1860 // the ADRP's register and this ADD's register are the same,
1861 // then this is a pc-relative address calculation.
1862 if (*type_ptr == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&
1863 m_adrp_insn && m_adrp_address == pc - 4 &&
1864 (*m_adrp_insn & 0x1f) == ((value >> 5) & 0x1f)) {
1865 uint32_t addxri_inst;
1866 uint64_t adrp_imm, addxri_imm;
1867 // Get immlo and immhi bits, OR them together to get the ADRP imm
1868 // value.
1869 adrp_imm =
1870 ((*m_adrp_insn & 0x00ffffe0) >> 3) | ((*m_adrp_insn >> 29) & 0x3);
1871 // if high bit of immhi after right-shifting set, sign extend
1872 if (adrp_imm & (1ULL << 20))
1873 adrp_imm |= ~((1ULL << 21) - 1);
1874
1875 addxri_inst = value;
1876 addxri_imm = (addxri_inst >> 10) & 0xfff;
1877 // check if 'sh' bit is set, shift imm value up if so
1878 // (this would make no sense, ADRP already gave us this part)
1879 if ((addxri_inst >> (12 + 5 + 5)) & 1)
1880 addxri_imm <<= 12;
1881 value = (m_adrp_address & 0xfffffffffffff000LL) + (adrp_imm << 12) +
1882 addxri_imm;
1883 }
1885 m_adrp_insn.reset();
1886 }
1887
1888 if (m_inst->UsingFileAddress()) {
1889 ModuleSP module_sp(m_inst->GetAddress().GetModule());
1890 if (module_sp) {
1891 module_sp->ResolveFileAddress(value, value_so_addr);
1892 module_sp->ResolveFileAddress(pc, pc_so_addr);
1893 }
1894 } else if (target && target->HasLoadedSections()) {
1895 target->ResolveLoadAddress(value, value_so_addr);
1896 target->ResolveLoadAddress(pc, pc_so_addr);
1897 }
1898
1899 SymbolContext sym_ctx;
1900 const SymbolContextItem resolve_scope =
1901 eSymbolContextFunction | eSymbolContextSymbol;
1902 if (pc_so_addr.IsValid() && pc_so_addr.GetModule()) {
1903 pc_so_addr.GetModule()->ResolveSymbolContextForAddress(
1904 pc_so_addr, resolve_scope, sym_ctx);
1905 }
1906
1907 if (value_so_addr.IsValid() && value_so_addr.GetSection()) {
1908 StreamString ss;
1909
1910 bool format_omitting_current_func_name = false;
1911 if (sym_ctx.symbol || sym_ctx.function) {
1912 AddressRange range;
1913 for (uint32_t idx = 0;
1914 sym_ctx.GetAddressRange(resolve_scope, idx, false, range);
1915 ++idx) {
1916 if (range.ContainsLoadAddress(value_so_addr, target)) {
1917 format_omitting_current_func_name = true;
1918 break;
1919 }
1920 }
1921 }
1922
1923 // If the "value" address (the target address we're symbolicating) is
1924 // inside the same SymbolContext as the current instruction pc
1925 // (pc_so_addr), don't print the full function name - just print it
1926 // with DumpStyleNoFunctionName style, e.g. "<+36>".
1927 if (format_omitting_current_func_name) {
1928 value_so_addr.Dump(&ss, target, Address::DumpStyleNoFunctionName,
1930 } else {
1931 value_so_addr.Dump(
1932 &ss, target,
1935 }
1936
1937 if (!ss.GetString().empty()) {
1938 // If Address::Dump returned a multi-line description, most commonly
1939 // seen when we have multiple levels of inlined functions at an
1940 // address, only show the first line.
1941 std::string str = std::string(ss.GetString());
1942 size_t first_eol_char = str.find_first_of("\r\n");
1943 if (first_eol_char != std::string::npos) {
1944 str.erase(first_eol_char);
1945 }
1946 m_inst->AppendComment(str);
1947 }
1948 }
1949 }
1950 }
1951
1952 // TODO: llvm-objdump sets the type_ptr to the
1953 // LLVMDisassembler_ReferenceType_Out_* values
1954 // based on where value_so_addr is pointing, with
1955 // Mach-O specific augmentations in MachODump.cpp. e.g.
1956 // see what AArch64ExternalSymbolizer::tryAddingSymbolicOperand
1957 // handles.
1958 *type_ptr = LLVMDisassembler_ReferenceType_InOut_None;
1959 *name = nullptr;
1960 return nullptr;
1961}
#define LLDB_PLUGIN_DEFINE(PluginName)
bool HasDelaySlot(llvm::MCInst &mc_inst) const
MCDisasmInstance(std::unique_ptr< llvm::MCInstrInfo > &&instr_info_up, std::unique_ptr< llvm::MCRegisterInfo > &&reg_info_up, std::unique_ptr< llvm::MCSubtargetInfo > &&subtarget_info_up, llvm::MCTargetOptions mc_options, std::unique_ptr< llvm::MCAsmInfo > &&asm_info_up, std::unique_ptr< llvm::MCContext > &&context_up, std::unique_ptr< llvm::MCDisassembler > &&disasm_up, std::unique_ptr< llvm::MCInstPrinter > &&instr_printer_up, std::unique_ptr< llvm::MCInstrAnalysis > &&instr_analysis_up)
bool IsAuthenticated(llvm::MCInst &mc_inst) const
std::unique_ptr< llvm::MCInstrInfo > m_instr_info_up
std::unique_ptr< llvm::MCRegisterInfo > m_reg_info_up
bool CanBranch(llvm::MCInst &mc_inst) const
std::unique_ptr< llvm::MCContext > m_context_up
std::unique_ptr< llvm::MCAsmInfo > m_asm_info_up
void PrintMCInst(llvm::MCInst &mc_inst, lldb::addr_t pc, std::string &inst_string, std::string &comments_string)
bool IsBarrier(llvm::MCInst &mc_inst) const
void SetStyle(bool use_hex_immed, HexImmediateStyle hex_style)
static std::unique_ptr< MCDisasmInstance > Create(const char *triple, const char *cpu, const char *features_str, unsigned flavor, DisassemblerLLVMC &owner)
bool GetMCInst(const uint8_t *opcode_data, size_t opcode_data_len, lldb::addr_t pc, llvm::MCInst &mc_inst, uint64_t &size) const
bool IsLoad(llvm::MCInst &mc_inst) const
bool IsCall(llvm::MCInst &mc_inst) const
std::unique_ptr< llvm::MCSubtargetInfo > m_subtarget_info_up
std::unique_ptr< llvm::MCInstrAnalysis > m_instr_analysis_up
std::unique_ptr< llvm::MCDisassembler > m_disasm_up
std::unique_ptr< llvm::MCInstPrinter > m_instr_printer_up
std::optional< uint32_t > m_adrp_insn
DisassemblerLLVMC(const lldb_private::ArchSpec &arch, const char *flavor, const char *cpu, const char *features)
static const char * SymbolLookupCallback(void *DisInfo, uint64_t ReferenceValue, uint64_t *ReferenceType, uint64_t ReferencePC, const char **ReferenceName)
static void UpdateSubtargetFeatures(llvm::StringRef subtarget_features, std::string &user_feature_overrides)
This function merges the user overwrite features (provided via -Y option) with the subtarget features...
int OpInfo(uint64_t PC, uint64_t Offset, uint64_t Size, int TagType, void *TagBug)
const lldb_private::ExecutionContext * m_exe_ctx
const char * SymbolLookup(uint64_t ReferenceValue, uint64_t *ReferenceType, uint64_t ReferencePC, const char **ReferenceName)
std::unique_ptr< MCDisasmInstance > m_disasm_up
static llvm::StringRef GetPluginNameStatic()
friend class InstructionLLVMC
static int OpInfoCallback(void *DisInfo, uint64_t PC, uint64_t Offset, uint64_t Size, int TagType, void *TagBug)
static lldb::DisassemblerSP CreateInstance(const lldb_private::ArchSpec &arch, const char *flavor, const char *cpu, const char *features)
lldb::addr_t m_adrp_address
bool FlavorValidForArchSpec(const lldb_private::ArchSpec &arch, const char *flavor) override
~DisassemblerLLVMC() override
std::unique_ptr< MCDisasmInstance > m_alternate_disasm_up
InstructionLLVMC * m_inst
size_t DecodeInstructions(const lldb_private::Address &base_addr, const lldb_private::DataExtractor &data, lldb::offset_t data_offset, size_t num_instructions, bool append, bool data_from_file) override
Grants exclusive access to the disassembler and initializes it with the given InstructionLLVMC and an...
std::shared_ptr< DisassemblerLLVMC > m_disasm
DisassemblerScope(InstructionLLVMC &i, const lldb_private::ExecutionContext *exe_ctx=nullptr)
std::shared_ptr< DisassemblerLLVMC > operator->()
static std::pair< Operand, llvm::StringRef::const_iterator > ParseIntelIndexedAccess(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
bool DoesBranch() override
DisassemblerLLVMC::MCDisasmInstance * GetDisasmToUse(bool &is_alternate_isa)
static void DumpOperand(const Operand &op, Stream &s)
size_t GetByteSize() const
static llvm::StringRef::const_iterator ConsumeWhitespace(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
std::weak_ptr< DisassemblerLLVMC > m_disasm_wp
void CalculateMnemonicOperandsAndComment(const lldb_private::ExecutionContext *exe_ctx) override
bool IsLoad() override
static std::pair< Operand, llvm::StringRef::const_iterator > ParseARMOffsetAccess(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
DisassemblerLLVMC::MCDisasmInstance * GetDisasmToUse(bool &is_alternate_isa, DisassemblerScope &disasm)
void AppendComment(std::string &description)
bool UsingFileAddress() const
bool IsAuthenticated() override
static std::pair< Operand, llvm::StringRef::const_iterator > ParseIntelDerefAccess(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
static std::pair< bool, llvm::StringRef::const_iterator > ConsumeChar(llvm::StringRef::const_iterator osi, const char c, llvm::StringRef::const_iterator ose)
size_t Decode(const lldb_private::Disassembler &disassembler, const lldb_private::DataExtractor &data, lldb::offset_t data_offset) override
bool ParseOperands(llvm::SmallVectorImpl< Instruction::Operand > &operands) override
bool IsBarrier() override
bool HasDelaySlot() override
static std::pair< Operand, llvm::StringRef::const_iterator > ParseARMDerefAccess(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
static std::pair< Operand, llvm::StringRef::const_iterator > ParseRegisterName(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
~InstructionLLVMC() override=default
lldb::InstructionControlFlowKind GetControlFlowKind(const lldb_private::ExecutionContext *exe_ctx) override
InstructionLLVMC(DisassemblerLLVMC &disasm, const lldb_private::Address &address, AddressClass addr_class)
static std::pair< Operand, llvm::StringRef::const_iterator > ParseImmediate(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
A section + offset based address range class.
bool ContainsLoadAddress(const Address &so_addr, Target *target) const
Check if a section offset so_addr when represented as a load address is contained within this object'...
A section + offset based address class.
Definition Address.h:62
lldb::SectionSP GetSection() const
Get const accessor for the section.
Definition Address.h:432
@ DumpStyleSectionNameOffset
Display as the section name + offset.
Definition Address.h:74
@ DumpStyleNoFunctionName
Elide the function name; display an offset into the current function.
Definition Address.h:109
@ DumpStyleResolvedDescriptionNoFunctionArguments
Definition Address.h:106
bool Slide(int64_t offset)
Definition Address.h:452
bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style=DumpStyleInvalid, uint32_t addr_byte_size=UINT32_MAX, bool all_ranges=false, std::optional< Stream::HighlightSettings > settings=std::nullopt) const
Dump a description of this object to a Stream.
Definition Address.cpp:396
lldb::ModuleSP GetModule() const
Get accessor for the module for this address.
Definition Address.cpp:273
bool IsValid() const
Check if the object state is valid.
Definition Address.h:355
AddressClass GetAddressClass() const
Definition Address.cpp:1020
An architecture specification class.
Definition ArchSpec.h:32
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:460
uint32_t GetMinimumOpcodeByteSize() const
Definition ArchSpec.cpp:931
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition ArchSpec.cpp:682
@ eRISCV_float_abi_double
single precision floating point, +f
Definition ArchSpec.h:98
@ eRISCV_float_abi_quad
double precision floating point, +d
Definition ArchSpec.h:99
@ eRISCV_float_abi_single
soft float
Definition ArchSpec.h:97
uint32_t GetMaximumOpcodeByteSize() const
Definition ArchSpec.cpp:938
A uniqued constant string class.
Definition ConstString.h:40
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
An data extractor class.
uint64_t GetU64(lldb::offset_t *offset_ptr) const
Extract a uint64_t value from *offset_ptr.
bool ValidOffsetForDataOfSize(lldb::offset_t offset, lldb::offset_t length) const
Test the availability of length bytes of data from offset.
virtual const uint8_t * PeekData(lldb::offset_t offset, lldb::offset_t length) const
Peek at a bytes at offset.
virtual uint64_t GetByteSize() const
Get the number of bytes contained in this object.
virtual lldb::offset_t BytesLeft(lldb::offset_t offset) const
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
uint16_t GetU16(lldb::offset_t *offset_ptr) const
Extract a uint16_t value from *offset_ptr.
const uint8_t * GetDataStart() const
Get the data start pointer.
lldb::ByteOrder GetByteOrder() const
Get the current byte order value.
uint8_t GetU8(lldb::offset_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
static void ReportWarning(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report warning events.
InstructionList m_instruction_list
Disassembler(const ArchSpec &arch, const char *flavor)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
Target * GetTargetPtr() const
Returns a pointer to the target object.
Instruction(const Address &address, AddressClass addr_class=AddressClass::eInvalid)
const char * GetOperands(const ExecutionContext *exe_ctx, bool markup=false)
uint32_t GetByteSize() const
Definition Opcode.h:231
const void * GetOpcodeBytes() const
Definition Opcode.h:225
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
bool Execute(llvm::StringRef string, llvm::SmallVectorImpl< llvm::StringRef > *matches=nullptr) const
Execute a regular expression match using the compiled regular expression that is already in this obje...
An error handling class.
Definition Status.h:118
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
Defines a symbol context baton that can be handed other debug core functions.
Function * function
The Function for a given query.
bool GetAddressRange(uint32_t scope, uint32_t range_idx, bool use_inline_block_range, AddressRange &range) const
Get the address range contained within a symbol context.
Symbol * symbol
The Symbol for a given query.
Disassembler::HexImmediateStyle GetHexImmediateStyle() const
Definition Target.cpp:5693
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, uint32_t stop_id=SectionLoadHistory::eStopIDNow, bool allow_section_end=false)
Definition Target.cpp:3449
const ArchSpec & GetArchitecture() const
Definition Target.h:1283
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:327
uint64_t offset_t
Definition lldb-types.h:85
std::shared_ptr< lldb_private::Instruction > InstructionSP
std::shared_ptr< lldb_private::Disassembler > DisassemblerSP
ByteOrder
Byte ordering definitions.
InstructionControlFlowKind
Architecture-agnostic categorization of instructions for traversing the control flow of a trace.
@ eInstructionControlFlowKindReturn
The instruction is a near (function) return.
@ eInstructionControlFlowKindFarJump
The instruction is a jump-like far transfer. E.g. FAR JMP.
@ eInstructionControlFlowKindOther
The instruction is something not listed below, i.e.
@ eInstructionControlFlowKindFarCall
The instruction is a call-like far transfer.
@ eInstructionControlFlowKindFarReturn
The instruction is a return-like far transfer.
@ eInstructionControlFlowKindUnknown
The instruction could not be classified.
@ eInstructionControlFlowKindJump
The instruction is a near unconditional jump.
@ eInstructionControlFlowKindCall
The instruction is a near (function) call.
@ eInstructionControlFlowKindCondJump
The instruction is a near conditional jump.
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Module > ModuleSP
std::optional< InstructionOpcodeAndModrm > InstructionLengthDecode(const uint8_t *inst_bytes, int bytes_len, bool is_exec_mode_64b)
Decode an instruction into opcode, modrm and opcode_len.
lldb::InstructionControlFlowKind GetControlFlowKind(bool is_exec_mode_64b, Opcode m_opcode)
lldb::InstructionControlFlowKind MapOpcodeIntoControlFlowKind(InstructionOpcodeAndModrm opcode_and_modrm)
Determine the InstructionControlFlowKind based on opcode and modrm bytes.
enum lldb_private::Instruction::Operand::Type m_type
std::vector< Operand > m_children
These are the three values deciding instruction control flow kind.