1 //===-- Disassembler.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Core/Disassembler.h"
11 #include "lldb/Core/AddressRange.h"
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Core/EmulateInstruction.h"
14 #include "lldb/Core/Mangled.h"
15 #include "lldb/Core/Module.h"
16 #include "lldb/Core/ModuleList.h"
17 #include "lldb/Core/PluginManager.h"
18 #include "lldb/Core/SourceManager.h"
19 #include "lldb/Host/FileSystem.h"
20 #include "lldb/Interpreter/OptionValue.h"
21 #include "lldb/Interpreter/OptionValueArray.h"
22 #include "lldb/Interpreter/OptionValueDictionary.h"
23 #include "lldb/Interpreter/OptionValueRegex.h"
24 #include "lldb/Interpreter/OptionValueString.h"
25 #include "lldb/Interpreter/OptionValueUInt64.h"
26 #include "lldb/Symbol/Function.h"
27 #include "lldb/Symbol/Symbol.h"
28 #include "lldb/Symbol/SymbolContext.h"
29 #include "lldb/Target/ExecutionContext.h"
30 #include "lldb/Target/SectionLoadList.h"
31 #include "lldb/Target/StackFrame.h"
32 #include "lldb/Target/Target.h"
33 #include "lldb/Target/Thread.h"
34 #include "lldb/Utility/DataBufferHeap.h"
35 #include "lldb/Utility/DataExtractor.h"
36 #include "lldb/Utility/RegularExpression.h"
37 #include "lldb/Utility/Status.h"
38 #include "lldb/Utility/Stream.h"
39 #include "lldb/Utility/StreamString.h"
40 #include "lldb/Utility/Timer.h"
41 #include "lldb/lldb-private-enumerations.h"
42 #include "lldb/lldb-private-interfaces.h"
43 #include "lldb/lldb-private-types.h"
44 #include "llvm/Support/Compiler.h"
45 #include "llvm/TargetParser/Triple.h"
53 #define DEFAULT_DISASM_BYTE_SIZE 32
56 using namespace lldb_private
;
58 DisassemblerSP
Disassembler::FindPlugin(const ArchSpec
&arch
,
59 const char *flavor
, const char *cpu
,
61 const char *plugin_name
) {
62 LLDB_SCOPED_TIMERF("Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
63 arch
.GetArchitectureName(), plugin_name
);
65 DisassemblerCreateInstance create_callback
= nullptr;
69 PluginManager::GetDisassemblerCreateCallbackForPluginName(plugin_name
);
70 if (create_callback
) {
71 if (auto disasm_sp
= create_callback(arch
, flavor
, cpu
, features
))
75 for (uint32_t idx
= 0;
76 (create_callback
= PluginManager::GetDisassemblerCreateCallbackAtIndex(
79 if (auto disasm_sp
= create_callback(arch
, flavor
, cpu
, features
))
83 return DisassemblerSP();
86 DisassemblerSP
Disassembler::FindPluginForTarget(
87 const Target
&target
, const ArchSpec
&arch
, const char *flavor
,
88 const char *cpu
, const char *features
, const char *plugin_name
) {
90 // FIXME - we don't have the mechanism in place to do per-architecture
91 // settings. But since we know that for now we only support flavors on x86
93 if (arch
.GetTriple().getArch() == llvm::Triple::x86
||
94 arch
.GetTriple().getArch() == llvm::Triple::x86_64
)
95 flavor
= target
.GetDisassemblyFlavor();
98 cpu
= target
.GetDisassemblyCPU();
100 features
= target
.GetDisassemblyFeatures();
102 return FindPlugin(arch
, flavor
, cpu
, features
, plugin_name
);
105 static Address
ResolveAddress(Target
&target
, const Address
&addr
) {
106 if (!addr
.IsSectionOffset()) {
107 Address resolved_addr
;
108 // If we weren't passed in a section offset address range, try and resolve
110 bool is_resolved
= target
.GetSectionLoadList().IsEmpty()
111 ? target
.GetImages().ResolveFileAddress(
112 addr
.GetOffset(), resolved_addr
)
113 : target
.GetSectionLoadList().ResolveLoadAddress(
114 addr
.GetOffset(), resolved_addr
);
116 // We weren't able to resolve the address, just treat it as a raw address
117 if (is_resolved
&& resolved_addr
.IsValid())
118 return resolved_addr
;
123 lldb::DisassemblerSP
Disassembler::DisassembleRange(
124 const ArchSpec
&arch
, const char *plugin_name
, const char *flavor
,
125 const char *cpu
, const char *features
, Target
&target
,
126 const AddressRange
&range
, bool force_live_memory
) {
127 if (range
.GetByteSize() <= 0)
130 if (!range
.GetBaseAddress().IsValid())
133 lldb::DisassemblerSP disasm_sp
= Disassembler::FindPluginForTarget(
134 target
, arch
, flavor
, cpu
, features
, plugin_name
);
139 const size_t bytes_disassembled
= disasm_sp
->ParseInstructions(
140 target
, range
.GetBaseAddress(), {Limit::Bytes
, range
.GetByteSize()},
141 nullptr, force_live_memory
);
142 if (bytes_disassembled
== 0)
149 Disassembler::DisassembleBytes(const ArchSpec
&arch
, const char *plugin_name
,
150 const char *flavor
, const char *cpu
,
151 const char *features
, const Address
&start
,
152 const void *src
, size_t src_len
,
153 uint32_t num_instructions
, bool data_from_file
) {
157 lldb::DisassemblerSP disasm_sp
=
158 Disassembler::FindPlugin(arch
, flavor
, cpu
, features
, plugin_name
);
163 DataExtractor
data(src
, src_len
, arch
.GetByteOrder(),
164 arch
.GetAddressByteSize());
166 (void)disasm_sp
->DecodeInstructions(start
, data
, 0, num_instructions
, false,
171 bool Disassembler::Disassemble(Debugger
&debugger
, const ArchSpec
&arch
,
172 const char *plugin_name
, const char *flavor
,
173 const char *cpu
, const char *features
,
174 const ExecutionContext
&exe_ctx
,
175 const Address
&address
, Limit limit
,
176 bool mixed_source_and_assembly
,
177 uint32_t num_mixed_context_lines
,
178 uint32_t options
, Stream
&strm
) {
179 if (!exe_ctx
.GetTargetPtr())
182 lldb::DisassemblerSP
disasm_sp(Disassembler::FindPluginForTarget(
183 exe_ctx
.GetTargetRef(), arch
, flavor
, cpu
, features
, plugin_name
));
187 const bool force_live_memory
= true;
188 size_t bytes_disassembled
= disasm_sp
->ParseInstructions(
189 exe_ctx
.GetTargetRef(), address
, limit
, &strm
, force_live_memory
);
190 if (bytes_disassembled
== 0)
193 disasm_sp
->PrintInstructions(debugger
, arch
, exe_ctx
,
194 mixed_source_and_assembly
,
195 num_mixed_context_lines
, options
, strm
);
199 Disassembler::SourceLine
200 Disassembler::GetFunctionDeclLineEntry(const SymbolContext
&sc
) {
204 if (!sc
.line_entry
.IsValid())
207 LineEntry prologue_end_line
= sc
.line_entry
;
208 SupportFileSP func_decl_file_sp
;
209 uint32_t func_decl_line
;
210 sc
.function
->GetStartLineSourceInfo(func_decl_file_sp
, func_decl_line
);
212 if (!func_decl_file_sp
)
214 if (!func_decl_file_sp
->Equal(*prologue_end_line
.file_sp
,
215 SupportFile::eEqualFileSpecAndChecksumIfSet
) &&
216 !func_decl_file_sp
->Equal(*prologue_end_line
.original_file_sp
,
217 SupportFile::eEqualFileSpecAndChecksumIfSet
))
220 SourceLine decl_line
;
221 decl_line
.file
= func_decl_file_sp
->GetSpecOnly();
222 decl_line
.line
= func_decl_line
;
223 // TODO: Do we care about column on these entries? If so, we need to plumb
224 // that through GetStartLineSourceInfo.
225 decl_line
.column
= 0;
229 void Disassembler::AddLineToSourceLineTables(
231 std::map
<FileSpec
, std::set
<uint32_t>> &source_lines_seen
) {
232 if (line
.IsValid()) {
233 auto source_lines_seen_pos
= source_lines_seen
.find(line
.file
);
234 if (source_lines_seen_pos
== source_lines_seen
.end()) {
235 std::set
<uint32_t> lines
;
236 lines
.insert(line
.line
);
237 source_lines_seen
.emplace(line
.file
, lines
);
239 source_lines_seen_pos
->second
.insert(line
.line
);
244 bool Disassembler::ElideMixedSourceAndDisassemblyLine(
245 const ExecutionContext
&exe_ctx
, const SymbolContext
&sc
,
248 // TODO: should we also check target.process.thread.step-avoid-libraries ?
250 const RegularExpression
*avoid_regex
= nullptr;
252 // Skip any line #0 entries - they are implementation details
256 ThreadSP thread_sp
= exe_ctx
.GetThreadSP();
258 avoid_regex
= thread_sp
->GetSymbolsToAvoidRegexp();
260 TargetSP target_sp
= exe_ctx
.GetTargetSP();
263 OptionValueSP value_sp
= target_sp
->GetDebugger().GetPropertyValue(
264 &exe_ctx
, "target.process.thread.step-avoid-regexp", error
);
265 if (value_sp
&& value_sp
->GetType() == OptionValue::eTypeRegex
) {
266 OptionValueRegex
*re
= value_sp
->GetAsRegex();
268 avoid_regex
= re
->GetCurrentValue();
273 if (avoid_regex
&& sc
.symbol
!= nullptr) {
274 const char *function_name
=
275 sc
.GetFunctionName(Mangled::ePreferDemangledWithoutArguments
)
277 if (function_name
&& avoid_regex
->Execute(function_name
)) {
278 // skip this source line
282 // don't skip this source line
286 void Disassembler::PrintInstructions(Debugger
&debugger
, const ArchSpec
&arch
,
287 const ExecutionContext
&exe_ctx
,
288 bool mixed_source_and_assembly
,
289 uint32_t num_mixed_context_lines
,
290 uint32_t options
, Stream
&strm
) {
291 // We got some things disassembled...
292 size_t num_instructions_found
= GetInstructionList().GetSize();
294 const uint32_t max_opcode_byte_size
=
295 GetInstructionList().GetMaxOpcocdeByteSize();
297 SymbolContext prev_sc
;
298 AddressRange current_source_line_range
;
299 const Address
*pc_addr_ptr
= nullptr;
300 StackFrame
*frame
= exe_ctx
.GetFramePtr();
302 TargetSP
target_sp(exe_ctx
.GetTargetSP());
303 SourceManager
&source_manager
=
304 target_sp
? target_sp
->GetSourceManager() : debugger
.GetSourceManager();
307 pc_addr_ptr
= &frame
->GetFrameCodeAddress();
309 const uint32_t scope
=
310 eSymbolContextLineEntry
| eSymbolContextFunction
| eSymbolContextSymbol
;
311 const bool use_inline_block_range
= false;
313 const FormatEntity::Entry
*disassembly_format
= nullptr;
314 FormatEntity::Entry format
;
315 if (exe_ctx
.HasTargetScope()) {
317 exe_ctx
.GetTargetRef().GetDebugger().GetDisassemblyFormat();
319 FormatEntity::Parse("${addr}: ", format
);
320 disassembly_format
= &format
;
323 // First pass: step through the list of instructions, find how long the
324 // initial addresses strings are, insert padding in the second pass so the
325 // opcodes all line up nicely.
327 // Also build up the source line mapping if this is mixed source & assembly
328 // mode. Calculate the source line for each assembly instruction (eliding
329 // inlined functions which the user wants to skip).
331 std::map
<FileSpec
, std::set
<uint32_t>> source_lines_seen
;
332 Symbol
*previous_symbol
= nullptr;
334 size_t address_text_size
= 0;
335 for (size_t i
= 0; i
< num_instructions_found
; ++i
) {
336 Instruction
*inst
= GetInstructionList().GetInstructionAtIndex(i
).get();
338 const Address
&addr
= inst
->GetAddress();
339 ModuleSP
module_sp(addr
.GetModule());
341 const SymbolContextItem resolve_mask
= eSymbolContextFunction
|
342 eSymbolContextSymbol
|
343 eSymbolContextLineEntry
;
344 uint32_t resolved_mask
=
345 module_sp
->ResolveSymbolContextForAddress(addr
, resolve_mask
, sc
);
347 StreamString strmstr
;
348 Debugger::FormatDisassemblerAddress(disassembly_format
, &sc
, nullptr,
349 &exe_ctx
, &addr
, strmstr
);
350 size_t cur_line
= strmstr
.GetSizeOfLastLine();
351 if (cur_line
> address_text_size
)
352 address_text_size
= cur_line
;
354 // Add entries to our "source_lines_seen" map+set which list which
355 // sources lines occur in this disassembly session. We will print
356 // lines of context around a source line, but we don't want to print
357 // a source line that has a line table entry of its own - we'll leave
358 // that source line to be printed when it actually occurs in the
361 if (mixed_source_and_assembly
&& sc
.line_entry
.IsValid()) {
362 if (sc
.symbol
!= previous_symbol
) {
363 SourceLine decl_line
= GetFunctionDeclLineEntry(sc
);
364 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx
, sc
, decl_line
))
365 AddLineToSourceLineTables(decl_line
, source_lines_seen
);
367 if (sc
.line_entry
.IsValid()) {
368 SourceLine this_line
;
369 this_line
.file
= sc
.line_entry
.GetFile();
370 this_line
.line
= sc
.line_entry
.line
;
371 this_line
.column
= sc
.line_entry
.column
;
372 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx
, sc
, this_line
))
373 AddLineToSourceLineTables(this_line
, source_lines_seen
);
382 previous_symbol
= nullptr;
383 SourceLine previous_line
;
384 for (size_t i
= 0; i
< num_instructions_found
; ++i
) {
385 Instruction
*inst
= GetInstructionList().GetInstructionAtIndex(i
).get();
388 const Address
&addr
= inst
->GetAddress();
389 const bool inst_is_at_pc
= pc_addr_ptr
&& addr
== *pc_addr_ptr
;
390 SourceLinesToDisplay source_lines_to_display
;
394 ModuleSP
module_sp(addr
.GetModule());
396 uint32_t resolved_mask
= module_sp
->ResolveSymbolContextForAddress(
397 addr
, eSymbolContextEverything
, sc
);
399 if (mixed_source_and_assembly
) {
401 // If we've started a new function (non-inlined), print all of the
402 // source lines from the function declaration until the first line
403 // table entry - typically the opening curly brace of the function.
404 if (previous_symbol
!= sc
.symbol
) {
405 // The default disassembly format puts an extra blank line
406 // between functions - so when we're displaying the source
407 // context for a function, we don't want to add a blank line
408 // after the source context or we'll end up with two of them.
409 if (previous_symbol
!= nullptr)
410 source_lines_to_display
.print_source_context_end_eol
= false;
412 previous_symbol
= sc
.symbol
;
413 if (sc
.function
&& sc
.line_entry
.IsValid()) {
414 LineEntry prologue_end_line
= sc
.line_entry
;
415 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx
, sc
,
416 prologue_end_line
)) {
417 SupportFileSP func_decl_file_sp
;
418 uint32_t func_decl_line
;
419 sc
.function
->GetStartLineSourceInfo(func_decl_file_sp
,
421 if (func_decl_file_sp
&&
422 (func_decl_file_sp
->Equal(
423 *prologue_end_line
.file_sp
,
424 SupportFile::eEqualFileSpecAndChecksumIfSet
) ||
425 func_decl_file_sp
->Equal(
426 *prologue_end_line
.original_file_sp
,
427 SupportFile::eEqualFileSpecAndChecksumIfSet
))) {
428 // Add all the lines between the function declaration and
429 // the first non-prologue source line to the list of lines
431 for (uint32_t lineno
= func_decl_line
;
432 lineno
<= prologue_end_line
.line
; lineno
++) {
433 SourceLine this_line
;
434 this_line
.file
= func_decl_file_sp
->GetSpecOnly();
435 this_line
.line
= lineno
;
436 source_lines_to_display
.lines
.push_back(this_line
);
438 // Mark the last line as the "current" one. Usually this
439 // is the open curly brace.
440 if (source_lines_to_display
.lines
.size() > 0)
441 source_lines_to_display
.current_source_line
=
442 source_lines_to_display
.lines
.size() - 1;
446 sc
.GetAddressRange(scope
, 0, use_inline_block_range
,
447 current_source_line_range
);
450 // If we've left a previous source line's address range, print a
452 if (!current_source_line_range
.ContainsFileAddress(addr
)) {
453 sc
.GetAddressRange(scope
, 0, use_inline_block_range
,
454 current_source_line_range
);
456 if (sc
!= prev_sc
&& sc
.comp_unit
&& sc
.line_entry
.IsValid()) {
457 SourceLine this_line
;
458 this_line
.file
= sc
.line_entry
.GetFile();
459 this_line
.line
= sc
.line_entry
.line
;
461 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx
, sc
,
463 // Only print this source line if it is different from the
464 // last source line we printed. There may have been inlined
465 // functions between these lines that we elided, resulting in
466 // the same line being printed twice in a row for a
467 // contiguous block of assembly instructions.
468 if (this_line
!= previous_line
) {
470 std::vector
<uint32_t> previous_lines
;
472 i
< num_mixed_context_lines
&&
473 (this_line
.line
- num_mixed_context_lines
) > 0;
476 this_line
.line
- num_mixed_context_lines
+ i
;
477 auto pos
= source_lines_seen
.find(this_line
.file
);
478 if (pos
!= source_lines_seen
.end()) {
479 if (pos
->second
.count(line
) == 1) {
480 previous_lines
.clear();
482 previous_lines
.push_back(line
);
486 for (size_t i
= 0; i
< previous_lines
.size(); i
++) {
487 SourceLine previous_line
;
488 previous_line
.file
= this_line
.file
;
489 previous_line
.line
= previous_lines
[i
];
490 auto pos
= source_lines_seen
.find(previous_line
.file
);
491 if (pos
!= source_lines_seen
.end()) {
492 pos
->second
.insert(previous_line
.line
);
494 source_lines_to_display
.lines
.push_back(previous_line
);
497 source_lines_to_display
.lines
.push_back(this_line
);
498 source_lines_to_display
.current_source_line
=
499 source_lines_to_display
.lines
.size() - 1;
501 for (uint32_t i
= 0; i
< num_mixed_context_lines
; i
++) {
502 SourceLine next_line
;
503 next_line
.file
= this_line
.file
;
504 next_line
.line
= this_line
.line
+ i
+ 1;
505 auto pos
= source_lines_seen
.find(next_line
.file
);
506 if (pos
!= source_lines_seen
.end()) {
507 if (pos
->second
.count(next_line
.line
) == 1)
509 pos
->second
.insert(next_line
.line
);
511 source_lines_to_display
.lines
.push_back(next_line
);
514 previous_line
= this_line
;
524 if (source_lines_to_display
.lines
.size() > 0) {
526 for (size_t idx
= 0; idx
< source_lines_to_display
.lines
.size();
528 SourceLine ln
= source_lines_to_display
.lines
[idx
];
529 const char *line_highlight
= "";
530 if (inst_is_at_pc
&& (options
& eOptionMarkPCSourceLine
)) {
531 line_highlight
= "->";
532 } else if (idx
== source_lines_to_display
.current_source_line
) {
533 line_highlight
= "**";
535 source_manager
.DisplaySourceLinesWithLineNumbers(
536 std::make_shared
<SupportFile
>(ln
.file
), ln
.line
, ln
.column
, 0, 0,
537 line_highlight
, &strm
);
539 if (source_lines_to_display
.print_source_context_end_eol
)
543 const bool show_bytes
= (options
& eOptionShowBytes
) != 0;
544 const bool show_control_flow_kind
=
545 (options
& eOptionShowControlFlowKind
) != 0;
546 inst
->Dump(&strm
, max_opcode_byte_size
, true, show_bytes
,
547 show_control_flow_kind
, &exe_ctx
, &sc
, &prev_sc
, nullptr,
556 bool Disassembler::Disassemble(Debugger
&debugger
, const ArchSpec
&arch
,
557 StackFrame
&frame
, Stream
&strm
) {
560 frame
.GetSymbolContext(eSymbolContextFunction
| eSymbolContextSymbol
));
562 range
= sc
.function
->GetAddressRange();
563 } else if (sc
.symbol
&& sc
.symbol
->ValueIsAddress()) {
564 range
.GetBaseAddress() = sc
.symbol
->GetAddressRef();
565 range
.SetByteSize(sc
.symbol
->GetByteSize());
567 range
.GetBaseAddress() = frame
.GetFrameCodeAddress();
570 if (range
.GetBaseAddress().IsValid() && range
.GetByteSize() == 0)
571 range
.SetByteSize(DEFAULT_DISASM_BYTE_SIZE
);
573 Disassembler::Limit limit
= {Disassembler::Limit::Bytes
,
574 range
.GetByteSize()};
575 if (limit
.value
== 0)
576 limit
.value
= DEFAULT_DISASM_BYTE_SIZE
;
578 return Disassemble(debugger
, arch
, nullptr, nullptr, nullptr, nullptr,
579 frame
, range
.GetBaseAddress(), limit
, false, 0, 0, strm
);
582 Instruction::Instruction(const Address
&address
, AddressClass addr_class
)
583 : m_address(address
), m_address_class(addr_class
), m_opcode(),
584 m_calculated_strings(false) {}
586 Instruction::~Instruction() = default;
588 AddressClass
Instruction::GetAddressClass() {
589 if (m_address_class
== AddressClass::eInvalid
)
590 m_address_class
= m_address
.GetAddressClass();
591 return m_address_class
;
594 const char *Instruction::GetNameForInstructionControlFlowKind(
595 lldb::InstructionControlFlowKind instruction_control_flow_kind
) {
596 switch (instruction_control_flow_kind
) {
597 case eInstructionControlFlowKindUnknown
:
599 case eInstructionControlFlowKindOther
:
601 case eInstructionControlFlowKindCall
:
603 case eInstructionControlFlowKindReturn
:
605 case eInstructionControlFlowKindJump
:
607 case eInstructionControlFlowKindCondJump
:
609 case eInstructionControlFlowKindFarCall
:
611 case eInstructionControlFlowKindFarReturn
:
613 case eInstructionControlFlowKindFarJump
:
616 llvm_unreachable("Fully covered switch above!");
619 void Instruction::Dump(lldb_private::Stream
*s
, uint32_t max_opcode_byte_size
,
620 bool show_address
, bool show_bytes
,
621 bool show_control_flow_kind
,
622 const ExecutionContext
*exe_ctx
,
623 const SymbolContext
*sym_ctx
,
624 const SymbolContext
*prev_sym_ctx
,
625 const FormatEntity::Entry
*disassembly_addr_format
,
626 size_t max_address_text_size
) {
627 size_t opcode_column_width
= 7;
628 const size_t operand_column_width
= 25;
630 CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx
);
635 Debugger::FormatDisassemblerAddress(disassembly_addr_format
, sym_ctx
,
636 prev_sym_ctx
, exe_ctx
, &m_address
, ss
);
637 ss
.FillLastLineToColumn(max_address_text_size
, ' ');
641 if (m_opcode
.GetType() == Opcode::eTypeBytes
) {
642 // x86_64 and i386 are the only ones that use bytes right now so pad out
643 // the byte dump to be able to always show 15 bytes (3 chars each) plus a
645 if (max_opcode_byte_size
> 0)
646 m_opcode
.Dump(&ss
, max_opcode_byte_size
* 3 + 1);
648 m_opcode
.Dump(&ss
, 15 * 3 + 1);
650 // Else, we have ARM or MIPS which can show up to a uint32_t 0x00000000
651 // (10 spaces) plus two for padding...
652 if (max_opcode_byte_size
> 0)
653 m_opcode
.Dump(&ss
, max_opcode_byte_size
* 3 + 1);
655 m_opcode
.Dump(&ss
, 12);
659 if (show_control_flow_kind
) {
660 lldb::InstructionControlFlowKind instruction_control_flow_kind
=
661 GetControlFlowKind(exe_ctx
);
662 ss
.Printf("%-12s", GetNameForInstructionControlFlowKind(
663 instruction_control_flow_kind
));
666 bool show_color
= false;
668 if (TargetSP target_sp
= exe_ctx
->GetTargetSP()) {
669 show_color
= target_sp
->GetDebugger().GetUseColor();
672 const size_t opcode_pos
= ss
.GetSizeOfLastLine();
673 const std::string
&opcode_name
=
674 show_color
? m_markup_opcode_name
: m_opcode_name
;
675 const std::string
&mnemonics
= show_color
? m_markup_mnemonics
: m_mnemonics
;
677 // The default opcode size of 7 characters is plenty for most architectures
678 // but some like arm can pull out the occasional vqrshrun.s16. We won't get
679 // consistent column spacing in these cases, unfortunately. Also note that we
680 // need to directly use m_opcode_name here (instead of opcode_name) so we
681 // don't include color codes as characters.
682 if (m_opcode_name
.length() >= opcode_column_width
) {
683 opcode_column_width
= m_opcode_name
.length() + 1;
686 ss
.PutCString(opcode_name
);
687 ss
.FillLastLineToColumn(opcode_pos
+ opcode_column_width
, ' ');
688 ss
.PutCString(mnemonics
);
690 if (!m_comment
.empty()) {
691 ss
.FillLastLineToColumn(
692 opcode_pos
+ opcode_column_width
+ operand_column_width
, ' ');
693 ss
.PutCString(" ; ");
694 ss
.PutCString(m_comment
);
696 s
->PutCString(ss
.GetString());
699 bool Instruction::DumpEmulation(const ArchSpec
&arch
) {
700 std::unique_ptr
<EmulateInstruction
> insn_emulator_up(
701 EmulateInstruction::FindPlugin(arch
, eInstructionTypeAny
, nullptr));
702 if (insn_emulator_up
) {
703 insn_emulator_up
->SetInstruction(GetOpcode(), GetAddress(), nullptr);
704 return insn_emulator_up
->EvaluateInstruction(0);
710 bool Instruction::CanSetBreakpoint () {
711 return !HasDelaySlot();
714 bool Instruction::HasDelaySlot() {
719 OptionValueSP
Instruction::ReadArray(FILE *in_file
, Stream
&out_stream
,
720 OptionValue::Type data_type
) {
724 auto option_value_sp
= std::make_shared
<OptionValueArray
>(1u << data_type
);
728 if (!fgets(buffer
, 1023, in_file
)) {
730 "Instruction::ReadArray: Error reading file (fgets).\n");
731 option_value_sp
.reset();
732 return option_value_sp
;
735 std::string
line(buffer
);
737 size_t len
= line
.size();
738 if (line
[len
- 1] == '\n') {
739 line
[len
- 1] = '\0';
740 line
.resize(len
- 1);
743 if ((line
.size() == 1) && line
[0] == ']') {
750 static RegularExpression
g_reg_exp(
751 llvm::StringRef("^[ \t]*([^ \t]+)[ \t]*$"));
752 llvm::SmallVector
<llvm::StringRef
, 2> matches
;
753 if (g_reg_exp
.Execute(line
, &matches
))
754 value
= matches
[1].str();
758 OptionValueSP data_value_sp
;
760 case OptionValue::eTypeUInt64
:
761 data_value_sp
= std::make_shared
<OptionValueUInt64
>(0, 0);
762 data_value_sp
->SetValueFromString(value
);
764 // Other types can be added later as needed.
766 data_value_sp
= std::make_shared
<OptionValueString
>(value
.c_str(), "");
770 option_value_sp
->GetAsArray()->InsertValue(idx
, data_value_sp
);
775 return option_value_sp
;
778 OptionValueSP
Instruction::ReadDictionary(FILE *in_file
, Stream
&out_stream
) {
782 auto option_value_sp
= std::make_shared
<OptionValueDictionary
>();
783 static constexpr llvm::StringLiteral
encoding_key("data_encoding");
784 OptionValue::Type data_type
= OptionValue::eTypeInvalid
;
787 // Read the next line in the file
788 if (!fgets(buffer
, 1023, in_file
)) {
790 "Instruction::ReadDictionary: Error reading file (fgets).\n");
791 option_value_sp
.reset();
792 return option_value_sp
;
795 // Check to see if the line contains the end-of-dictionary marker ("}")
796 std::string
line(buffer
);
798 size_t len
= line
.size();
799 if (line
[len
- 1] == '\n') {
800 line
[len
- 1] = '\0';
801 line
.resize(len
- 1);
804 if ((line
.size() == 1) && (line
[0] == '}')) {
809 // Try to find a key-value pair in the current line and add it to the
812 static RegularExpression
g_reg_exp(llvm::StringRef(
813 "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$"));
815 llvm::SmallVector
<llvm::StringRef
, 3> matches
;
817 bool reg_exp_success
= g_reg_exp
.Execute(line
, &matches
);
820 if (reg_exp_success
) {
821 key
= matches
[1].str();
822 value
= matches
[2].str();
824 out_stream
.Printf("Instruction::ReadDictionary: Failure executing "
825 "regular expression.\n");
826 option_value_sp
.reset();
827 return option_value_sp
;
830 // Check value to see if it's the start of an array or dictionary.
832 lldb::OptionValueSP value_sp
;
833 assert(value
.empty() == false);
834 assert(key
.empty() == false);
836 if (value
[0] == '{') {
837 assert(value
.size() == 1);
838 // value is a dictionary
839 value_sp
= ReadDictionary(in_file
, out_stream
);
841 option_value_sp
.reset();
842 return option_value_sp
;
844 } else if (value
[0] == '[') {
845 assert(value
.size() == 1);
847 value_sp
= ReadArray(in_file
, out_stream
, data_type
);
849 option_value_sp
.reset();
850 return option_value_sp
;
852 // We've used the data_type to read an array; re-set the type to
854 data_type
= OptionValue::eTypeInvalid
;
855 } else if ((value
[0] == '0') && (value
[1] == 'x')) {
856 value_sp
= std::make_shared
<OptionValueUInt64
>(0, 0);
857 value_sp
->SetValueFromString(value
);
859 size_t len
= value
.size();
860 if ((value
[0] == '"') && (value
[len
- 1] == '"'))
861 value
= value
.substr(1, len
- 2);
862 value_sp
= std::make_shared
<OptionValueString
>(value
.c_str(), "");
865 if (key
== encoding_key
) {
866 // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data
867 // indicating the data type of an upcoming array (usually the next bit
868 // of data to be read in).
869 if (llvm::StringRef(value
) == "uint32_t")
870 data_type
= OptionValue::eTypeUInt64
;
872 option_value_sp
->GetAsDictionary()->SetValueForKey(key
, value_sp
,
877 return option_value_sp
;
880 bool Instruction::TestEmulation(Stream
&out_stream
, const char *file_name
) {
882 out_stream
.Printf("Instruction::TestEmulation: Missing file_name.");
885 FILE *test_file
= FileSystem::Instance().Fopen(file_name
, "r");
888 "Instruction::TestEmulation: Attempt to open test file failed.");
893 if (!fgets(buffer
, 255, test_file
)) {
895 "Instruction::TestEmulation: Error reading first line of test file.\n");
900 if (strncmp(buffer
, "InstructionEmulationState={", 27) != 0) {
901 out_stream
.Printf("Instructin::TestEmulation: Test file does not contain "
902 "emulation state dictionary\n");
907 // Read all the test information from the test file into an
908 // OptionValueDictionary.
910 OptionValueSP
data_dictionary_sp(ReadDictionary(test_file
, out_stream
));
911 if (!data_dictionary_sp
) {
913 "Instruction::TestEmulation: Error reading Dictionary Object.\n");
920 OptionValueDictionary
*data_dictionary
=
921 data_dictionary_sp
->GetAsDictionary();
922 static constexpr llvm::StringLiteral
description_key("assembly_string");
923 static constexpr llvm::StringLiteral
triple_key("triple");
925 OptionValueSP value_sp
= data_dictionary
->GetValueForKey(description_key
);
928 out_stream
.Printf("Instruction::TestEmulation: Test file does not "
929 "contain description string.\n");
933 SetDescription(value_sp
->GetValueAs
<llvm::StringRef
>().value_or(""));
935 value_sp
= data_dictionary
->GetValueForKey(triple_key
);
938 "Instruction::TestEmulation: Test file does not contain triple.\n");
944 llvm::Triple(value_sp
->GetValueAs
<llvm::StringRef
>().value_or("")));
946 bool success
= false;
947 std::unique_ptr
<EmulateInstruction
> insn_emulator_up(
948 EmulateInstruction::FindPlugin(arch
, eInstructionTypeAny
, nullptr));
949 if (insn_emulator_up
)
951 insn_emulator_up
->TestEmulation(out_stream
, arch
, data_dictionary
);
954 out_stream
.Printf("Emulation test succeeded.");
956 out_stream
.Printf("Emulation test failed.");
961 bool Instruction::Emulate(
962 const ArchSpec
&arch
, uint32_t evaluate_options
, void *baton
,
963 EmulateInstruction::ReadMemoryCallback read_mem_callback
,
964 EmulateInstruction::WriteMemoryCallback write_mem_callback
,
965 EmulateInstruction::ReadRegisterCallback read_reg_callback
,
966 EmulateInstruction::WriteRegisterCallback write_reg_callback
) {
967 std::unique_ptr
<EmulateInstruction
> insn_emulator_up(
968 EmulateInstruction::FindPlugin(arch
, eInstructionTypeAny
, nullptr));
969 if (insn_emulator_up
) {
970 insn_emulator_up
->SetBaton(baton
);
971 insn_emulator_up
->SetCallbacks(read_mem_callback
, write_mem_callback
,
972 read_reg_callback
, write_reg_callback
);
973 insn_emulator_up
->SetInstruction(GetOpcode(), GetAddress(), nullptr);
974 return insn_emulator_up
->EvaluateInstruction(evaluate_options
);
980 uint32_t Instruction::GetData(DataExtractor
&data
) {
981 return m_opcode
.GetData(data
);
984 InstructionList::InstructionList() : m_instructions() {}
986 InstructionList::~InstructionList() = default;
988 size_t InstructionList::GetSize() const { return m_instructions
.size(); }
990 uint32_t InstructionList::GetMaxOpcocdeByteSize() const {
991 uint32_t max_inst_size
= 0;
992 collection::const_iterator pos
, end
;
993 for (pos
= m_instructions
.begin(), end
= m_instructions
.end(); pos
!= end
;
995 uint32_t inst_size
= (*pos
)->GetOpcode().GetByteSize();
996 if (max_inst_size
< inst_size
)
997 max_inst_size
= inst_size
;
999 return max_inst_size
;
1002 InstructionSP
InstructionList::GetInstructionAtIndex(size_t idx
) const {
1003 InstructionSP inst_sp
;
1004 if (idx
< m_instructions
.size())
1005 inst_sp
= m_instructions
[idx
];
1009 InstructionSP
InstructionList::GetInstructionAtAddress(const Address
&address
) {
1010 uint32_t index
= GetIndexOfInstructionAtAddress(address
);
1011 if (index
!= UINT32_MAX
)
1012 return GetInstructionAtIndex(index
);
1016 void InstructionList::Dump(Stream
*s
, bool show_address
, bool show_bytes
,
1017 bool show_control_flow_kind
,
1018 const ExecutionContext
*exe_ctx
) {
1019 const uint32_t max_opcode_byte_size
= GetMaxOpcocdeByteSize();
1020 collection::const_iterator pos
, begin
, end
;
1022 const FormatEntity::Entry
*disassembly_format
= nullptr;
1023 FormatEntity::Entry format
;
1024 if (exe_ctx
&& exe_ctx
->HasTargetScope()) {
1025 disassembly_format
=
1026 exe_ctx
->GetTargetRef().GetDebugger().GetDisassemblyFormat();
1028 FormatEntity::Parse("${addr}: ", format
);
1029 disassembly_format
= &format
;
1032 for (begin
= m_instructions
.begin(), end
= m_instructions
.end(), pos
= begin
;
1033 pos
!= end
; ++pos
) {
1036 (*pos
)->Dump(s
, max_opcode_byte_size
, show_address
, show_bytes
,
1037 show_control_flow_kind
, exe_ctx
, nullptr, nullptr,
1038 disassembly_format
, 0);
1042 void InstructionList::Clear() { m_instructions
.clear(); }
1044 void InstructionList::Append(lldb::InstructionSP
&inst_sp
) {
1046 m_instructions
.push_back(inst_sp
);
1050 InstructionList::GetIndexOfNextBranchInstruction(uint32_t start
,
1052 bool *found_calls
) const {
1053 size_t num_instructions
= m_instructions
.size();
1055 uint32_t next_branch
= UINT32_MAX
;
1058 *found_calls
= false;
1059 for (size_t i
= start
; i
< num_instructions
; i
++) {
1060 if (m_instructions
[i
]->DoesBranch()) {
1061 if (ignore_calls
&& m_instructions
[i
]->IsCall()) {
1063 *found_calls
= true;
1075 InstructionList::GetIndexOfInstructionAtAddress(const Address
&address
) {
1076 size_t num_instructions
= m_instructions
.size();
1077 uint32_t index
= UINT32_MAX
;
1078 for (size_t i
= 0; i
< num_instructions
; i
++) {
1079 if (m_instructions
[i
]->GetAddress() == address
) {
1088 InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr
,
1091 address
.SetLoadAddress(load_addr
, &target
);
1092 return GetIndexOfInstructionAtAddress(address
);
1095 size_t Disassembler::ParseInstructions(Target
&target
, Address start
,
1096 Limit limit
, Stream
*error_strm_ptr
,
1097 bool force_live_memory
) {
1098 m_instruction_list
.Clear();
1100 if (!start
.IsValid())
1103 start
= ResolveAddress(target
, start
);
1105 addr_t byte_size
= limit
.value
;
1106 if (limit
.kind
== Limit::Instructions
)
1107 byte_size
*= m_arch
.GetMaximumOpcodeByteSize();
1108 auto data_sp
= std::make_shared
<DataBufferHeap
>(byte_size
, '\0');
1111 lldb::addr_t load_addr
= LLDB_INVALID_ADDRESS
;
1112 const size_t bytes_read
=
1113 target
.ReadMemory(start
, data_sp
->GetBytes(), data_sp
->GetByteSize(),
1114 error
, force_live_memory
, &load_addr
);
1115 const bool data_from_file
= load_addr
== LLDB_INVALID_ADDRESS
;
1117 if (bytes_read
== 0) {
1118 if (error_strm_ptr
) {
1119 if (const char *error_cstr
= error
.AsCString())
1120 error_strm_ptr
->Printf("error: %s\n", error_cstr
);
1125 if (bytes_read
!= data_sp
->GetByteSize())
1126 data_sp
->SetByteSize(bytes_read
);
1127 DataExtractor
data(data_sp
, m_arch
.GetByteOrder(),
1128 m_arch
.GetAddressByteSize());
1129 return DecodeInstructions(start
, data
, 0,
1130 limit
.kind
== Limit::Instructions
? limit
.value
1132 false, data_from_file
);
1135 // Disassembler copy constructor
1136 Disassembler::Disassembler(const ArchSpec
&arch
, const char *flavor
)
1137 : m_arch(arch
), m_instruction_list(), m_flavor() {
1138 if (flavor
== nullptr)
1139 m_flavor
.assign("default");
1141 m_flavor
.assign(flavor
);
1143 // If this is an arm variant that can only include thumb (T16, T32)
1144 // instructions, force the arch triple to be "thumbv.." instead of "armv..."
1145 if (arch
.IsAlwaysThumbInstructions()) {
1146 std::string
thumb_arch_name(arch
.GetTriple().getArchName().str());
1147 // Replace "arm" with "thumb" so we get all thumb variants correct
1148 if (thumb_arch_name
.size() > 3) {
1149 thumb_arch_name
.erase(0, 3);
1150 thumb_arch_name
.insert(0, "thumb");
1152 m_arch
.SetTriple(thumb_arch_name
.c_str());
1156 Disassembler::~Disassembler() = default;
1158 InstructionList
&Disassembler::GetInstructionList() {
1159 return m_instruction_list
;
1162 const InstructionList
&Disassembler::GetInstructionList() const {
1163 return m_instruction_list
;
1166 // Class PseudoInstruction
1168 PseudoInstruction::PseudoInstruction()
1169 : Instruction(Address(), AddressClass::eUnknown
), m_description() {}
1171 PseudoInstruction::~PseudoInstruction() = default;
1173 bool PseudoInstruction::DoesBranch() {
1174 // This is NOT a valid question for a pseudo instruction.
1178 bool PseudoInstruction::HasDelaySlot() {
1179 // This is NOT a valid question for a pseudo instruction.
1183 bool PseudoInstruction::IsLoad() { return false; }
1185 bool PseudoInstruction::IsAuthenticated() { return false; }
1187 size_t PseudoInstruction::Decode(const lldb_private::Disassembler
&disassembler
,
1188 const lldb_private::DataExtractor
&data
,
1189 lldb::offset_t data_offset
) {
1190 return m_opcode
.GetByteSize();
1193 void PseudoInstruction::SetOpcode(size_t opcode_size
, void *opcode_data
) {
1197 switch (opcode_size
) {
1199 uint8_t value8
= *((uint8_t *)opcode_data
);
1200 m_opcode
.SetOpcode8(value8
, eByteOrderInvalid
);
1204 uint16_t value16
= *((uint16_t *)opcode_data
);
1205 m_opcode
.SetOpcode16(value16
, eByteOrderInvalid
);
1209 uint32_t value32
= *((uint32_t *)opcode_data
);
1210 m_opcode
.SetOpcode32(value32
, eByteOrderInvalid
);
1214 uint64_t value64
= *((uint64_t *)opcode_data
);
1215 m_opcode
.SetOpcode64(value64
, eByteOrderInvalid
);
1223 void PseudoInstruction::SetDescription(llvm::StringRef description
) {
1224 m_description
= std::string(description
);
1227 Instruction::Operand
Instruction::Operand::BuildRegister(ConstString
&r
) {
1229 ret
.m_type
= Type::Register
;
1234 Instruction::Operand
Instruction::Operand::BuildImmediate(lldb::addr_t imm
,
1237 ret
.m_type
= Type::Immediate
;
1238 ret
.m_immediate
= imm
;
1239 ret
.m_negative
= neg
;
1243 Instruction::Operand
Instruction::Operand::BuildImmediate(int64_t imm
) {
1245 ret
.m_type
= Type::Immediate
;
1247 ret
.m_immediate
= -imm
;
1248 ret
.m_negative
= true;
1250 ret
.m_immediate
= imm
;
1251 ret
.m_negative
= false;
1256 Instruction::Operand
1257 Instruction::Operand::BuildDereference(const Operand
&ref
) {
1259 ret
.m_type
= Type::Dereference
;
1260 ret
.m_children
= {ref
};
1264 Instruction::Operand
Instruction::Operand::BuildSum(const Operand
&lhs
,
1265 const Operand
&rhs
) {
1267 ret
.m_type
= Type::Sum
;
1268 ret
.m_children
= {lhs
, rhs
};
1272 Instruction::Operand
Instruction::Operand::BuildProduct(const Operand
&lhs
,
1273 const Operand
&rhs
) {
1275 ret
.m_type
= Type::Product
;
1276 ret
.m_children
= {lhs
, rhs
};
1280 std::function
<bool(const Instruction::Operand
&)>
1281 lldb_private::OperandMatchers::MatchBinaryOp(
1282 std::function
<bool(const Instruction::Operand
&)> base
,
1283 std::function
<bool(const Instruction::Operand
&)> left
,
1284 std::function
<bool(const Instruction::Operand
&)> right
) {
1285 return [base
, left
, right
](const Instruction::Operand
&op
) -> bool {
1286 return (base(op
) && op
.m_children
.size() == 2 &&
1287 ((left(op
.m_children
[0]) && right(op
.m_children
[1])) ||
1288 (left(op
.m_children
[1]) && right(op
.m_children
[0]))));
1292 std::function
<bool(const Instruction::Operand
&)>
1293 lldb_private::OperandMatchers::MatchUnaryOp(
1294 std::function
<bool(const Instruction::Operand
&)> base
,
1295 std::function
<bool(const Instruction::Operand
&)> child
) {
1296 return [base
, child
](const Instruction::Operand
&op
) -> bool {
1297 return (base(op
) && op
.m_children
.size() == 1 && child(op
.m_children
[0]));
1301 std::function
<bool(const Instruction::Operand
&)>
1302 lldb_private::OperandMatchers::MatchRegOp(const RegisterInfo
&info
) {
1303 return [&info
](const Instruction::Operand
&op
) {
1304 return (op
.m_type
== Instruction::Operand::Type::Register
&&
1305 (op
.m_register
== ConstString(info
.name
) ||
1306 op
.m_register
== ConstString(info
.alt_name
)));
1310 std::function
<bool(const Instruction::Operand
&)>
1311 lldb_private::OperandMatchers::FetchRegOp(ConstString
®
) {
1312 return [®
](const Instruction::Operand
&op
) {
1313 if (op
.m_type
!= Instruction::Operand::Type::Register
) {
1316 reg
= op
.m_register
;
1321 std::function
<bool(const Instruction::Operand
&)>
1322 lldb_private::OperandMatchers::MatchImmOp(int64_t imm
) {
1323 return [imm
](const Instruction::Operand
&op
) {
1324 return (op
.m_type
== Instruction::Operand::Type::Immediate
&&
1325 ((op
.m_negative
&& op
.m_immediate
== (uint64_t)-imm
) ||
1326 (!op
.m_negative
&& op
.m_immediate
== (uint64_t)imm
)));
1330 std::function
<bool(const Instruction::Operand
&)>
1331 lldb_private::OperandMatchers::FetchImmOp(int64_t &imm
) {
1332 return [&imm
](const Instruction::Operand
&op
) {
1333 if (op
.m_type
!= Instruction::Operand::Type::Immediate
) {
1336 if (op
.m_negative
) {
1337 imm
= -((int64_t)op
.m_immediate
);
1339 imm
= ((int64_t)op
.m_immediate
);
1345 std::function
<bool(const Instruction::Operand
&)>
1346 lldb_private::OperandMatchers::MatchOpType(Instruction::Operand::Type type
) {
1347 return [type
](const Instruction::Operand
&op
) { return op
.m_type
== type
; };