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