15ffd83dbSDimitry Andric //===-- Disassembler.cpp --------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Core/Disassembler.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Core/AddressRange.h"
120b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
130b57cec5SDimitry Andric #include "lldb/Core/EmulateInstruction.h"
140b57cec5SDimitry Andric #include "lldb/Core/Mangled.h"
150b57cec5SDimitry Andric #include "lldb/Core/Module.h"
160b57cec5SDimitry Andric #include "lldb/Core/ModuleList.h"
170b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h"
180b57cec5SDimitry Andric #include "lldb/Core/SourceManager.h"
190b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
200b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValue.h"
210b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueArray.h"
220b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueDictionary.h"
230b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueRegex.h"
240b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueString.h"
250b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h"
260b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
270b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
280b57cec5SDimitry Andric #include "lldb/Symbol/SymbolContext.h"
290b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h"
300b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h"
310b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h"
320b57cec5SDimitry Andric #include "lldb/Target/Target.h"
330b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
340b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
350b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h"
360b57cec5SDimitry Andric #include "lldb/Utility/RegularExpression.h"
370b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
380b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
390b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
400b57cec5SDimitry Andric #include "lldb/Utility/Timer.h"
410b57cec5SDimitry Andric #include "lldb/lldb-private-enumerations.h"
420b57cec5SDimitry Andric #include "lldb/lldb-private-interfaces.h"
430b57cec5SDimitry Andric #include "lldb/lldb-private-types.h"
440b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
4506c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric #include <cstdint>
480b57cec5SDimitry Andric #include <cstring>
490b57cec5SDimitry Andric #include <utility>
500b57cec5SDimitry Andric
51fe6060f1SDimitry Andric #include <cassert>
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric #define DEFAULT_DISASM_BYTE_SIZE 32
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric using namespace lldb;
560b57cec5SDimitry Andric using namespace lldb_private;
570b57cec5SDimitry Andric
FindPlugin(const ArchSpec & arch,const char * flavor,const char * plugin_name)580b57cec5SDimitry Andric DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,
590b57cec5SDimitry Andric const char *flavor,
600b57cec5SDimitry Andric const char *plugin_name) {
61e8d8bef9SDimitry Andric LLDB_SCOPED_TIMERF("Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
620b57cec5SDimitry Andric arch.GetArchitectureName(), plugin_name);
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric DisassemblerCreateInstance create_callback = nullptr;
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric if (plugin_name) {
67349cc55cSDimitry Andric create_callback =
68349cc55cSDimitry Andric PluginManager::GetDisassemblerCreateCallbackForPluginName(plugin_name);
690b57cec5SDimitry Andric if (create_callback) {
7006c3fb27SDimitry Andric if (auto disasm_sp = create_callback(arch, flavor))
7106c3fb27SDimitry Andric return disasm_sp;
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric } else {
740b57cec5SDimitry Andric for (uint32_t idx = 0;
750b57cec5SDimitry Andric (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(
760b57cec5SDimitry Andric idx)) != nullptr;
770b57cec5SDimitry Andric ++idx) {
7806c3fb27SDimitry Andric if (auto disasm_sp = create_callback(arch, flavor))
7906c3fb27SDimitry Andric return disasm_sp;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric return DisassemblerSP();
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric
FindPluginForTarget(const Target & target,const ArchSpec & arch,const char * flavor,const char * plugin_name)855ffd83dbSDimitry Andric DisassemblerSP Disassembler::FindPluginForTarget(const Target &target,
860b57cec5SDimitry Andric const ArchSpec &arch,
870b57cec5SDimitry Andric const char *flavor,
880b57cec5SDimitry Andric const char *plugin_name) {
895ffd83dbSDimitry Andric if (flavor == nullptr) {
900b57cec5SDimitry Andric // FIXME - we don't have the mechanism in place to do per-architecture
910b57cec5SDimitry Andric // settings. But since we know that for now we only support flavors on x86
920b57cec5SDimitry Andric // & x86_64,
930b57cec5SDimitry Andric if (arch.GetTriple().getArch() == llvm::Triple::x86 ||
940b57cec5SDimitry Andric arch.GetTriple().getArch() == llvm::Triple::x86_64)
955ffd83dbSDimitry Andric flavor = target.GetDisassemblyFlavor();
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric return FindPlugin(arch, flavor, plugin_name);
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric
ResolveAddress(Target & target,const Address & addr)1005ffd83dbSDimitry Andric static Address ResolveAddress(Target &target, const Address &addr) {
1010b57cec5SDimitry Andric if (!addr.IsSectionOffset()) {
1025ffd83dbSDimitry Andric Address resolved_addr;
1030b57cec5SDimitry Andric // If we weren't passed in a section offset address range, try and resolve
1040b57cec5SDimitry Andric // it to something
1055ffd83dbSDimitry Andric bool is_resolved = target.GetSectionLoadList().IsEmpty()
1065ffd83dbSDimitry Andric ? target.GetImages().ResolveFileAddress(
1075ffd83dbSDimitry Andric addr.GetOffset(), resolved_addr)
1085ffd83dbSDimitry Andric : target.GetSectionLoadList().ResolveLoadAddress(
1095ffd83dbSDimitry Andric addr.GetOffset(), resolved_addr);
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric // We weren't able to resolve the address, just treat it as a raw address
1120b57cec5SDimitry Andric if (is_resolved && resolved_addr.IsValid())
1135ffd83dbSDimitry Andric return resolved_addr;
1140b57cec5SDimitry Andric }
1155ffd83dbSDimitry Andric return addr;
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
DisassembleRange(const ArchSpec & arch,const char * plugin_name,const char * flavor,Target & target,const AddressRange & range,bool force_live_memory)1180b57cec5SDimitry Andric lldb::DisassemblerSP Disassembler::DisassembleRange(
1190b57cec5SDimitry Andric const ArchSpec &arch, const char *plugin_name, const char *flavor,
120fe6060f1SDimitry Andric Target &target, const AddressRange &range, bool force_live_memory) {
1219dba64beSDimitry Andric if (range.GetByteSize() <= 0)
1229dba64beSDimitry Andric return {};
1230b57cec5SDimitry Andric
1249dba64beSDimitry Andric if (!range.GetBaseAddress().IsValid())
1259dba64beSDimitry Andric return {};
1269dba64beSDimitry Andric
1275ffd83dbSDimitry Andric lldb::DisassemblerSP disasm_sp =
1285ffd83dbSDimitry Andric Disassembler::FindPluginForTarget(target, arch, flavor, plugin_name);
1299dba64beSDimitry Andric
1309dba64beSDimitry Andric if (!disasm_sp)
1319dba64beSDimitry Andric return {};
1329dba64beSDimitry Andric
1335ffd83dbSDimitry Andric const size_t bytes_disassembled = disasm_sp->ParseInstructions(
1345ffd83dbSDimitry Andric target, range.GetBaseAddress(), {Limit::Bytes, range.GetByteSize()},
135fe6060f1SDimitry Andric nullptr, force_live_memory);
1360b57cec5SDimitry Andric if (bytes_disassembled == 0)
1379dba64beSDimitry Andric return {};
1389dba64beSDimitry Andric
1390b57cec5SDimitry Andric return disasm_sp;
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric lldb::DisassemblerSP
DisassembleBytes(const ArchSpec & arch,const char * plugin_name,const char * flavor,const Address & start,const void * src,size_t src_len,uint32_t num_instructions,bool data_from_file)1430b57cec5SDimitry Andric Disassembler::DisassembleBytes(const ArchSpec &arch, const char *plugin_name,
1440b57cec5SDimitry Andric const char *flavor, const Address &start,
1450b57cec5SDimitry Andric const void *src, size_t src_len,
1460b57cec5SDimitry Andric uint32_t num_instructions, bool data_from_file) {
1479dba64beSDimitry Andric if (!src)
1489dba64beSDimitry Andric return {};
1490b57cec5SDimitry Andric
1509dba64beSDimitry Andric lldb::DisassemblerSP disasm_sp =
1519dba64beSDimitry Andric Disassembler::FindPlugin(arch, flavor, plugin_name);
1520b57cec5SDimitry Andric
1539dba64beSDimitry Andric if (!disasm_sp)
1549dba64beSDimitry Andric return {};
1559dba64beSDimitry Andric
1560b57cec5SDimitry Andric DataExtractor data(src, src_len, arch.GetByteOrder(),
1570b57cec5SDimitry Andric arch.GetAddressByteSize());
1580b57cec5SDimitry Andric
1599dba64beSDimitry Andric (void)disasm_sp->DecodeInstructions(start, data, 0, num_instructions, false,
1609dba64beSDimitry Andric data_from_file);
1610b57cec5SDimitry Andric return disasm_sp;
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric
Disassemble(Debugger & debugger,const ArchSpec & arch,const char * plugin_name,const char * flavor,const ExecutionContext & exe_ctx,const Address & address,Limit limit,bool mixed_source_and_assembly,uint32_t num_mixed_context_lines,uint32_t options,Stream & strm)1640b57cec5SDimitry Andric bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
1650b57cec5SDimitry Andric const char *plugin_name, const char *flavor,
1660b57cec5SDimitry Andric const ExecutionContext &exe_ctx,
1675ffd83dbSDimitry Andric const Address &address, Limit limit,
1680b57cec5SDimitry Andric bool mixed_source_and_assembly,
1690b57cec5SDimitry Andric uint32_t num_mixed_context_lines,
1700b57cec5SDimitry Andric uint32_t options, Stream &strm) {
1715ffd83dbSDimitry Andric if (!exe_ctx.GetTargetPtr())
1729dba64beSDimitry Andric return false;
1739dba64beSDimitry Andric
1740b57cec5SDimitry Andric lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget(
1755ffd83dbSDimitry Andric exe_ctx.GetTargetRef(), arch, flavor, plugin_name));
1769dba64beSDimitry Andric if (!disasm_sp)
1779dba64beSDimitry Andric return false;
1789dba64beSDimitry Andric
179fe6060f1SDimitry Andric const bool force_live_memory = true;
1800b57cec5SDimitry Andric size_t bytes_disassembled = disasm_sp->ParseInstructions(
181fe6060f1SDimitry Andric exe_ctx.GetTargetRef(), address, limit, &strm, force_live_memory);
1820b57cec5SDimitry Andric if (bytes_disassembled == 0)
1830b57cec5SDimitry Andric return false;
1849dba64beSDimitry Andric
1855ffd83dbSDimitry Andric disasm_sp->PrintInstructions(debugger, arch, exe_ctx,
1865ffd83dbSDimitry Andric mixed_source_and_assembly,
1870b57cec5SDimitry Andric num_mixed_context_lines, options, strm);
1885ffd83dbSDimitry Andric return true;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric Disassembler::SourceLine
GetFunctionDeclLineEntry(const SymbolContext & sc)1920b57cec5SDimitry Andric Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {
1939dba64beSDimitry Andric if (!sc.function)
1949dba64beSDimitry Andric return {};
1959dba64beSDimitry Andric
1969dba64beSDimitry Andric if (!sc.line_entry.IsValid())
1979dba64beSDimitry Andric return {};
1989dba64beSDimitry Andric
1990b57cec5SDimitry Andric LineEntry prologue_end_line = sc.line_entry;
2000b57cec5SDimitry Andric FileSpec func_decl_file;
2010b57cec5SDimitry Andric uint32_t func_decl_line;
2020b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line);
2039dba64beSDimitry Andric
2049dba64beSDimitry Andric if (func_decl_file != prologue_end_line.file &&
2057a6dacacSDimitry Andric func_decl_file != prologue_end_line.original_file_sp->GetSpecOnly())
2069dba64beSDimitry Andric return {};
2079dba64beSDimitry Andric
2089dba64beSDimitry Andric SourceLine decl_line;
2090b57cec5SDimitry Andric decl_line.file = func_decl_file;
2100b57cec5SDimitry Andric decl_line.line = func_decl_line;
2119dba64beSDimitry Andric // TODO: Do we care about column on these entries? If so, we need to plumb
2129dba64beSDimitry Andric // that through GetStartLineSourceInfo.
2130b57cec5SDimitry Andric decl_line.column = 0;
2140b57cec5SDimitry Andric return decl_line;
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
AddLineToSourceLineTables(SourceLine & line,std::map<FileSpec,std::set<uint32_t>> & source_lines_seen)2170b57cec5SDimitry Andric void Disassembler::AddLineToSourceLineTables(
2180b57cec5SDimitry Andric SourceLine &line,
2190b57cec5SDimitry Andric std::map<FileSpec, std::set<uint32_t>> &source_lines_seen) {
2200b57cec5SDimitry Andric if (line.IsValid()) {
2210b57cec5SDimitry Andric auto source_lines_seen_pos = source_lines_seen.find(line.file);
2220b57cec5SDimitry Andric if (source_lines_seen_pos == source_lines_seen.end()) {
2230b57cec5SDimitry Andric std::set<uint32_t> lines;
2240b57cec5SDimitry Andric lines.insert(line.line);
2250b57cec5SDimitry Andric source_lines_seen.emplace(line.file, lines);
2260b57cec5SDimitry Andric } else {
2270b57cec5SDimitry Andric source_lines_seen_pos->second.insert(line.line);
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric
ElideMixedSourceAndDisassemblyLine(const ExecutionContext & exe_ctx,const SymbolContext & sc,SourceLine & line)2320b57cec5SDimitry Andric bool Disassembler::ElideMixedSourceAndDisassemblyLine(
2330b57cec5SDimitry Andric const ExecutionContext &exe_ctx, const SymbolContext &sc,
2340b57cec5SDimitry Andric SourceLine &line) {
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric // TODO: should we also check target.process.thread.step-avoid-libraries ?
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric const RegularExpression *avoid_regex = nullptr;
2390b57cec5SDimitry Andric
2400b57cec5SDimitry Andric // Skip any line #0 entries - they are implementation details
2410b57cec5SDimitry Andric if (line.line == 0)
24206c3fb27SDimitry Andric return true;
2430b57cec5SDimitry Andric
2440b57cec5SDimitry Andric ThreadSP thread_sp = exe_ctx.GetThreadSP();
2450b57cec5SDimitry Andric if (thread_sp) {
2460b57cec5SDimitry Andric avoid_regex = thread_sp->GetSymbolsToAvoidRegexp();
2470b57cec5SDimitry Andric } else {
2480b57cec5SDimitry Andric TargetSP target_sp = exe_ctx.GetTargetSP();
2490b57cec5SDimitry Andric if (target_sp) {
2500b57cec5SDimitry Andric Status error;
2510b57cec5SDimitry Andric OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue(
25206c3fb27SDimitry Andric &exe_ctx, "target.process.thread.step-avoid-regexp", error);
2530b57cec5SDimitry Andric if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) {
2540b57cec5SDimitry Andric OptionValueRegex *re = value_sp->GetAsRegex();
2550b57cec5SDimitry Andric if (re) {
2560b57cec5SDimitry Andric avoid_regex = re->GetCurrentValue();
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric if (avoid_regex && sc.symbol != nullptr) {
2620b57cec5SDimitry Andric const char *function_name =
2630b57cec5SDimitry Andric sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
2640b57cec5SDimitry Andric .GetCString();
2659dba64beSDimitry Andric if (function_name && avoid_regex->Execute(function_name)) {
2660b57cec5SDimitry Andric // skip this source line
2670b57cec5SDimitry Andric return true;
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric // don't skip this source line
2710b57cec5SDimitry Andric return false;
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric
PrintInstructions(Debugger & debugger,const ArchSpec & arch,const ExecutionContext & exe_ctx,bool mixed_source_and_assembly,uint32_t num_mixed_context_lines,uint32_t options,Stream & strm)2745ffd83dbSDimitry Andric void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
2750b57cec5SDimitry Andric const ExecutionContext &exe_ctx,
2760b57cec5SDimitry Andric bool mixed_source_and_assembly,
2770b57cec5SDimitry Andric uint32_t num_mixed_context_lines,
2780b57cec5SDimitry Andric uint32_t options, Stream &strm) {
2790b57cec5SDimitry Andric // We got some things disassembled...
2805ffd83dbSDimitry Andric size_t num_instructions_found = GetInstructionList().GetSize();
2810b57cec5SDimitry Andric
2820b57cec5SDimitry Andric const uint32_t max_opcode_byte_size =
2835ffd83dbSDimitry Andric GetInstructionList().GetMaxOpcocdeByteSize();
2840b57cec5SDimitry Andric SymbolContext sc;
2850b57cec5SDimitry Andric SymbolContext prev_sc;
2860b57cec5SDimitry Andric AddressRange current_source_line_range;
2870b57cec5SDimitry Andric const Address *pc_addr_ptr = nullptr;
2880b57cec5SDimitry Andric StackFrame *frame = exe_ctx.GetFramePtr();
2890b57cec5SDimitry Andric
2900b57cec5SDimitry Andric TargetSP target_sp(exe_ctx.GetTargetSP());
2910b57cec5SDimitry Andric SourceManager &source_manager =
2920b57cec5SDimitry Andric target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
2930b57cec5SDimitry Andric
2940b57cec5SDimitry Andric if (frame) {
2950b57cec5SDimitry Andric pc_addr_ptr = &frame->GetFrameCodeAddress();
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric const uint32_t scope =
2980b57cec5SDimitry Andric eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
2990b57cec5SDimitry Andric const bool use_inline_block_range = false;
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric const FormatEntity::Entry *disassembly_format = nullptr;
3020b57cec5SDimitry Andric FormatEntity::Entry format;
3030b57cec5SDimitry Andric if (exe_ctx.HasTargetScope()) {
3040b57cec5SDimitry Andric disassembly_format =
3050b57cec5SDimitry Andric exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat();
3060b57cec5SDimitry Andric } else {
3070b57cec5SDimitry Andric FormatEntity::Parse("${addr}: ", format);
3080b57cec5SDimitry Andric disassembly_format = &format;
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric
3110b57cec5SDimitry Andric // First pass: step through the list of instructions, find how long the
3120b57cec5SDimitry Andric // initial addresses strings are, insert padding in the second pass so the
3130b57cec5SDimitry Andric // opcodes all line up nicely.
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andric // Also build up the source line mapping if this is mixed source & assembly
3160b57cec5SDimitry Andric // mode. Calculate the source line for each assembly instruction (eliding
3170b57cec5SDimitry Andric // inlined functions which the user wants to skip).
3180b57cec5SDimitry Andric
3190b57cec5SDimitry Andric std::map<FileSpec, std::set<uint32_t>> source_lines_seen;
3200b57cec5SDimitry Andric Symbol *previous_symbol = nullptr;
3210b57cec5SDimitry Andric
3220b57cec5SDimitry Andric size_t address_text_size = 0;
3230b57cec5SDimitry Andric for (size_t i = 0; i < num_instructions_found; ++i) {
3245ffd83dbSDimitry Andric Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();
3250b57cec5SDimitry Andric if (inst) {
3260b57cec5SDimitry Andric const Address &addr = inst->GetAddress();
3270b57cec5SDimitry Andric ModuleSP module_sp(addr.GetModule());
3280b57cec5SDimitry Andric if (module_sp) {
3290b57cec5SDimitry Andric const SymbolContextItem resolve_mask = eSymbolContextFunction |
3300b57cec5SDimitry Andric eSymbolContextSymbol |
3310b57cec5SDimitry Andric eSymbolContextLineEntry;
3320b57cec5SDimitry Andric uint32_t resolved_mask =
3330b57cec5SDimitry Andric module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);
3340b57cec5SDimitry Andric if (resolved_mask) {
3350b57cec5SDimitry Andric StreamString strmstr;
3360b57cec5SDimitry Andric Debugger::FormatDisassemblerAddress(disassembly_format, &sc, nullptr,
3370b57cec5SDimitry Andric &exe_ctx, &addr, strmstr);
3380b57cec5SDimitry Andric size_t cur_line = strmstr.GetSizeOfLastLine();
3390b57cec5SDimitry Andric if (cur_line > address_text_size)
3400b57cec5SDimitry Andric address_text_size = cur_line;
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric // Add entries to our "source_lines_seen" map+set which list which
3430b57cec5SDimitry Andric // sources lines occur in this disassembly session. We will print
3440b57cec5SDimitry Andric // lines of context around a source line, but we don't want to print
3450b57cec5SDimitry Andric // a source line that has a line table entry of its own - we'll leave
3460b57cec5SDimitry Andric // that source line to be printed when it actually occurs in the
3470b57cec5SDimitry Andric // disassembly.
3480b57cec5SDimitry Andric
3490b57cec5SDimitry Andric if (mixed_source_and_assembly && sc.line_entry.IsValid()) {
3500b57cec5SDimitry Andric if (sc.symbol != previous_symbol) {
3510b57cec5SDimitry Andric SourceLine decl_line = GetFunctionDeclLineEntry(sc);
3520b57cec5SDimitry Andric if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, decl_line))
3530b57cec5SDimitry Andric AddLineToSourceLineTables(decl_line, source_lines_seen);
3540b57cec5SDimitry Andric }
3550b57cec5SDimitry Andric if (sc.line_entry.IsValid()) {
3560b57cec5SDimitry Andric SourceLine this_line;
3570b57cec5SDimitry Andric this_line.file = sc.line_entry.file;
3580b57cec5SDimitry Andric this_line.line = sc.line_entry.line;
3590b57cec5SDimitry Andric this_line.column = sc.line_entry.column;
3600b57cec5SDimitry Andric if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line))
3610b57cec5SDimitry Andric AddLineToSourceLineTables(this_line, source_lines_seen);
3620b57cec5SDimitry Andric }
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric sc.Clear(false);
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric
3700b57cec5SDimitry Andric previous_symbol = nullptr;
3710b57cec5SDimitry Andric SourceLine previous_line;
3720b57cec5SDimitry Andric for (size_t i = 0; i < num_instructions_found; ++i) {
3735ffd83dbSDimitry Andric Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();
3740b57cec5SDimitry Andric
3750b57cec5SDimitry Andric if (inst) {
3760b57cec5SDimitry Andric const Address &addr = inst->GetAddress();
3770b57cec5SDimitry Andric const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;
3780b57cec5SDimitry Andric SourceLinesToDisplay source_lines_to_display;
3790b57cec5SDimitry Andric
3800b57cec5SDimitry Andric prev_sc = sc;
3810b57cec5SDimitry Andric
3820b57cec5SDimitry Andric ModuleSP module_sp(addr.GetModule());
3830b57cec5SDimitry Andric if (module_sp) {
3840b57cec5SDimitry Andric uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(
3850b57cec5SDimitry Andric addr, eSymbolContextEverything, sc);
3860b57cec5SDimitry Andric if (resolved_mask) {
3870b57cec5SDimitry Andric if (mixed_source_and_assembly) {
3880b57cec5SDimitry Andric
3890b57cec5SDimitry Andric // If we've started a new function (non-inlined), print all of the
3900b57cec5SDimitry Andric // source lines from the function declaration until the first line
3910b57cec5SDimitry Andric // table entry - typically the opening curly brace of the function.
3920b57cec5SDimitry Andric if (previous_symbol != sc.symbol) {
3930b57cec5SDimitry Andric // The default disassembly format puts an extra blank line
3940b57cec5SDimitry Andric // between functions - so when we're displaying the source
3950b57cec5SDimitry Andric // context for a function, we don't want to add a blank line
3960b57cec5SDimitry Andric // after the source context or we'll end up with two of them.
3970b57cec5SDimitry Andric if (previous_symbol != nullptr)
3980b57cec5SDimitry Andric source_lines_to_display.print_source_context_end_eol = false;
3990b57cec5SDimitry Andric
4000b57cec5SDimitry Andric previous_symbol = sc.symbol;
4010b57cec5SDimitry Andric if (sc.function && sc.line_entry.IsValid()) {
4020b57cec5SDimitry Andric LineEntry prologue_end_line = sc.line_entry;
4030b57cec5SDimitry Andric if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
4040b57cec5SDimitry Andric prologue_end_line)) {
4050b57cec5SDimitry Andric FileSpec func_decl_file;
4060b57cec5SDimitry Andric uint32_t func_decl_line;
4070b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(func_decl_file,
4080b57cec5SDimitry Andric func_decl_line);
4090b57cec5SDimitry Andric if (func_decl_file == prologue_end_line.file ||
4107a6dacacSDimitry Andric func_decl_file ==
4117a6dacacSDimitry Andric prologue_end_line.original_file_sp->GetSpecOnly()) {
4120b57cec5SDimitry Andric // Add all the lines between the function declaration and
4130b57cec5SDimitry Andric // the first non-prologue source line to the list of lines
4140b57cec5SDimitry Andric // to print.
4150b57cec5SDimitry Andric for (uint32_t lineno = func_decl_line;
4160b57cec5SDimitry Andric lineno <= prologue_end_line.line; lineno++) {
4170b57cec5SDimitry Andric SourceLine this_line;
4180b57cec5SDimitry Andric this_line.file = func_decl_file;
4190b57cec5SDimitry Andric this_line.line = lineno;
4200b57cec5SDimitry Andric source_lines_to_display.lines.push_back(this_line);
4210b57cec5SDimitry Andric }
4220b57cec5SDimitry Andric // Mark the last line as the "current" one. Usually this
4230b57cec5SDimitry Andric // is the open curly brace.
4240b57cec5SDimitry Andric if (source_lines_to_display.lines.size() > 0)
4250b57cec5SDimitry Andric source_lines_to_display.current_source_line =
4260b57cec5SDimitry Andric source_lines_to_display.lines.size() - 1;
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric }
4300b57cec5SDimitry Andric sc.GetAddressRange(scope, 0, use_inline_block_range,
4310b57cec5SDimitry Andric current_source_line_range);
4320b57cec5SDimitry Andric }
4330b57cec5SDimitry Andric
4340b57cec5SDimitry Andric // If we've left a previous source line's address range, print a
4350b57cec5SDimitry Andric // new source line
4360b57cec5SDimitry Andric if (!current_source_line_range.ContainsFileAddress(addr)) {
4370b57cec5SDimitry Andric sc.GetAddressRange(scope, 0, use_inline_block_range,
4380b57cec5SDimitry Andric current_source_line_range);
4390b57cec5SDimitry Andric
4400b57cec5SDimitry Andric if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) {
4410b57cec5SDimitry Andric SourceLine this_line;
4420b57cec5SDimitry Andric this_line.file = sc.line_entry.file;
4430b57cec5SDimitry Andric this_line.line = sc.line_entry.line;
4440b57cec5SDimitry Andric
4450b57cec5SDimitry Andric if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
4460b57cec5SDimitry Andric this_line)) {
4470b57cec5SDimitry Andric // Only print this source line if it is different from the
4480b57cec5SDimitry Andric // last source line we printed. There may have been inlined
4490b57cec5SDimitry Andric // functions between these lines that we elided, resulting in
4500b57cec5SDimitry Andric // the same line being printed twice in a row for a
4510b57cec5SDimitry Andric // contiguous block of assembly instructions.
4520b57cec5SDimitry Andric if (this_line != previous_line) {
4530b57cec5SDimitry Andric
4540b57cec5SDimitry Andric std::vector<uint32_t> previous_lines;
4550b57cec5SDimitry Andric for (uint32_t i = 0;
4560b57cec5SDimitry Andric i < num_mixed_context_lines &&
4570b57cec5SDimitry Andric (this_line.line - num_mixed_context_lines) > 0;
4580b57cec5SDimitry Andric i++) {
4590b57cec5SDimitry Andric uint32_t line =
4600b57cec5SDimitry Andric this_line.line - num_mixed_context_lines + i;
4610b57cec5SDimitry Andric auto pos = source_lines_seen.find(this_line.file);
4620b57cec5SDimitry Andric if (pos != source_lines_seen.end()) {
4630b57cec5SDimitry Andric if (pos->second.count(line) == 1) {
4640b57cec5SDimitry Andric previous_lines.clear();
4650b57cec5SDimitry Andric } else {
4660b57cec5SDimitry Andric previous_lines.push_back(line);
4670b57cec5SDimitry Andric }
4680b57cec5SDimitry Andric }
4690b57cec5SDimitry Andric }
4700b57cec5SDimitry Andric for (size_t i = 0; i < previous_lines.size(); i++) {
4710b57cec5SDimitry Andric SourceLine previous_line;
4720b57cec5SDimitry Andric previous_line.file = this_line.file;
4730b57cec5SDimitry Andric previous_line.line = previous_lines[i];
4740b57cec5SDimitry Andric auto pos = source_lines_seen.find(previous_line.file);
4750b57cec5SDimitry Andric if (pos != source_lines_seen.end()) {
4760b57cec5SDimitry Andric pos->second.insert(previous_line.line);
4770b57cec5SDimitry Andric }
4780b57cec5SDimitry Andric source_lines_to_display.lines.push_back(previous_line);
4790b57cec5SDimitry Andric }
4800b57cec5SDimitry Andric
4810b57cec5SDimitry Andric source_lines_to_display.lines.push_back(this_line);
4820b57cec5SDimitry Andric source_lines_to_display.current_source_line =
4830b57cec5SDimitry Andric source_lines_to_display.lines.size() - 1;
4840b57cec5SDimitry Andric
4850b57cec5SDimitry Andric for (uint32_t i = 0; i < num_mixed_context_lines; i++) {
4860b57cec5SDimitry Andric SourceLine next_line;
4870b57cec5SDimitry Andric next_line.file = this_line.file;
4880b57cec5SDimitry Andric next_line.line = this_line.line + i + 1;
4890b57cec5SDimitry Andric auto pos = source_lines_seen.find(next_line.file);
4900b57cec5SDimitry Andric if (pos != source_lines_seen.end()) {
4910b57cec5SDimitry Andric if (pos->second.count(next_line.line) == 1)
4920b57cec5SDimitry Andric break;
4930b57cec5SDimitry Andric pos->second.insert(next_line.line);
4940b57cec5SDimitry Andric }
4950b57cec5SDimitry Andric source_lines_to_display.lines.push_back(next_line);
4960b57cec5SDimitry Andric }
4970b57cec5SDimitry Andric }
4980b57cec5SDimitry Andric previous_line = this_line;
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric }
5020b57cec5SDimitry Andric }
5030b57cec5SDimitry Andric } else {
5040b57cec5SDimitry Andric sc.Clear(true);
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric }
5070b57cec5SDimitry Andric
5080b57cec5SDimitry Andric if (source_lines_to_display.lines.size() > 0) {
5090b57cec5SDimitry Andric strm.EOL();
5100b57cec5SDimitry Andric for (size_t idx = 0; idx < source_lines_to_display.lines.size();
5110b57cec5SDimitry Andric idx++) {
5120b57cec5SDimitry Andric SourceLine ln = source_lines_to_display.lines[idx];
5130b57cec5SDimitry Andric const char *line_highlight = "";
5140b57cec5SDimitry Andric if (inst_is_at_pc && (options & eOptionMarkPCSourceLine)) {
5150b57cec5SDimitry Andric line_highlight = "->";
5160b57cec5SDimitry Andric } else if (idx == source_lines_to_display.current_source_line) {
5170b57cec5SDimitry Andric line_highlight = "**";
5180b57cec5SDimitry Andric }
5190b57cec5SDimitry Andric source_manager.DisplaySourceLinesWithLineNumbers(
5200b57cec5SDimitry Andric ln.file, ln.line, ln.column, 0, 0, line_highlight, &strm);
5210b57cec5SDimitry Andric }
5220b57cec5SDimitry Andric if (source_lines_to_display.print_source_context_end_eol)
5230b57cec5SDimitry Andric strm.EOL();
5240b57cec5SDimitry Andric }
5250b57cec5SDimitry Andric
5260b57cec5SDimitry Andric const bool show_bytes = (options & eOptionShowBytes) != 0;
527753f127fSDimitry Andric const bool show_control_flow_kind =
528753f127fSDimitry Andric (options & eOptionShowControlFlowKind) != 0;
529753f127fSDimitry Andric inst->Dump(&strm, max_opcode_byte_size, true, show_bytes,
530753f127fSDimitry Andric show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
531753f127fSDimitry Andric address_text_size);
5320b57cec5SDimitry Andric strm.EOL();
5330b57cec5SDimitry Andric } else {
5340b57cec5SDimitry Andric break;
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric
Disassemble(Debugger & debugger,const ArchSpec & arch,StackFrame & frame,Stream & strm)5390b57cec5SDimitry Andric bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
540e8d8bef9SDimitry Andric StackFrame &frame, Stream &strm) {
5410b57cec5SDimitry Andric AddressRange range;
5420b57cec5SDimitry Andric SymbolContext sc(
543e8d8bef9SDimitry Andric frame.GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
5440b57cec5SDimitry Andric if (sc.function) {
5450b57cec5SDimitry Andric range = sc.function->GetAddressRange();
5460b57cec5SDimitry Andric } else if (sc.symbol && sc.symbol->ValueIsAddress()) {
5470b57cec5SDimitry Andric range.GetBaseAddress() = sc.symbol->GetAddressRef();
5480b57cec5SDimitry Andric range.SetByteSize(sc.symbol->GetByteSize());
5490b57cec5SDimitry Andric } else {
550e8d8bef9SDimitry Andric range.GetBaseAddress() = frame.GetFrameCodeAddress();
5510b57cec5SDimitry Andric }
5520b57cec5SDimitry Andric
5530b57cec5SDimitry Andric if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
5540b57cec5SDimitry Andric range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
5550b57cec5SDimitry Andric
556e8d8bef9SDimitry Andric Disassembler::Limit limit = {Disassembler::Limit::Bytes,
557e8d8bef9SDimitry Andric range.GetByteSize()};
558e8d8bef9SDimitry Andric if (limit.value == 0)
559e8d8bef9SDimitry Andric limit.value = DEFAULT_DISASM_BYTE_SIZE;
560e8d8bef9SDimitry Andric
561e8d8bef9SDimitry Andric return Disassemble(debugger, arch, nullptr, nullptr, frame,
562e8d8bef9SDimitry Andric range.GetBaseAddress(), limit, false, 0, 0, strm);
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric
Instruction(const Address & address,AddressClass addr_class)5650b57cec5SDimitry Andric Instruction::Instruction(const Address &address, AddressClass addr_class)
5660b57cec5SDimitry Andric : m_address(address), m_address_class(addr_class), m_opcode(),
5670b57cec5SDimitry Andric m_calculated_strings(false) {}
5680b57cec5SDimitry Andric
5690b57cec5SDimitry Andric Instruction::~Instruction() = default;
5700b57cec5SDimitry Andric
GetAddressClass()5710b57cec5SDimitry Andric AddressClass Instruction::GetAddressClass() {
5720b57cec5SDimitry Andric if (m_address_class == AddressClass::eInvalid)
5730b57cec5SDimitry Andric m_address_class = m_address.GetAddressClass();
5740b57cec5SDimitry Andric return m_address_class;
5750b57cec5SDimitry Andric }
5760b57cec5SDimitry Andric
GetNameForInstructionControlFlowKind(lldb::InstructionControlFlowKind instruction_control_flow_kind)577972a253aSDimitry Andric const char *Instruction::GetNameForInstructionControlFlowKind(
578972a253aSDimitry Andric lldb::InstructionControlFlowKind instruction_control_flow_kind) {
579972a253aSDimitry Andric switch (instruction_control_flow_kind) {
580972a253aSDimitry Andric case eInstructionControlFlowKindUnknown:
581972a253aSDimitry Andric return "unknown";
582972a253aSDimitry Andric case eInstructionControlFlowKindOther:
583972a253aSDimitry Andric return "other";
584972a253aSDimitry Andric case eInstructionControlFlowKindCall:
585972a253aSDimitry Andric return "call";
586972a253aSDimitry Andric case eInstructionControlFlowKindReturn:
587972a253aSDimitry Andric return "return";
588972a253aSDimitry Andric case eInstructionControlFlowKindJump:
589972a253aSDimitry Andric return "jump";
590972a253aSDimitry Andric case eInstructionControlFlowKindCondJump:
591972a253aSDimitry Andric return "cond jump";
592972a253aSDimitry Andric case eInstructionControlFlowKindFarCall:
593972a253aSDimitry Andric return "far call";
594972a253aSDimitry Andric case eInstructionControlFlowKindFarReturn:
595972a253aSDimitry Andric return "far return";
596972a253aSDimitry Andric case eInstructionControlFlowKindFarJump:
597972a253aSDimitry Andric return "far jump";
598972a253aSDimitry Andric }
59961cfbce3SDimitry Andric llvm_unreachable("Fully covered switch above!");
600972a253aSDimitry Andric }
601972a253aSDimitry Andric
Dump(lldb_private::Stream * s,uint32_t max_opcode_byte_size,bool show_address,bool show_bytes,bool show_control_flow_kind,const ExecutionContext * exe_ctx,const SymbolContext * sym_ctx,const SymbolContext * prev_sym_ctx,const FormatEntity::Entry * disassembly_addr_format,size_t max_address_text_size)6020b57cec5SDimitry Andric void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
6030b57cec5SDimitry Andric bool show_address, bool show_bytes,
604753f127fSDimitry Andric bool show_control_flow_kind,
6050b57cec5SDimitry Andric const ExecutionContext *exe_ctx,
6060b57cec5SDimitry Andric const SymbolContext *sym_ctx,
6070b57cec5SDimitry Andric const SymbolContext *prev_sym_ctx,
6080b57cec5SDimitry Andric const FormatEntity::Entry *disassembly_addr_format,
6090b57cec5SDimitry Andric size_t max_address_text_size) {
6100b57cec5SDimitry Andric size_t opcode_column_width = 7;
6110b57cec5SDimitry Andric const size_t operand_column_width = 25;
6120b57cec5SDimitry Andric
6130b57cec5SDimitry Andric CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx);
6140b57cec5SDimitry Andric
6150b57cec5SDimitry Andric StreamString ss;
6160b57cec5SDimitry Andric
6170b57cec5SDimitry Andric if (show_address) {
6180b57cec5SDimitry Andric Debugger::FormatDisassemblerAddress(disassembly_addr_format, sym_ctx,
6190b57cec5SDimitry Andric prev_sym_ctx, exe_ctx, &m_address, ss);
6200b57cec5SDimitry Andric ss.FillLastLineToColumn(max_address_text_size, ' ');
6210b57cec5SDimitry Andric }
6220b57cec5SDimitry Andric
6230b57cec5SDimitry Andric if (show_bytes) {
6240b57cec5SDimitry Andric if (m_opcode.GetType() == Opcode::eTypeBytes) {
6250b57cec5SDimitry Andric // x86_64 and i386 are the only ones that use bytes right now so pad out
6260b57cec5SDimitry Andric // the byte dump to be able to always show 15 bytes (3 chars each) plus a
6270b57cec5SDimitry Andric // space
6280b57cec5SDimitry Andric if (max_opcode_byte_size > 0)
6290b57cec5SDimitry Andric m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
6300b57cec5SDimitry Andric else
6310b57cec5SDimitry Andric m_opcode.Dump(&ss, 15 * 3 + 1);
6320b57cec5SDimitry Andric } else {
6330b57cec5SDimitry Andric // Else, we have ARM or MIPS which can show up to a uint32_t 0x00000000
6340b57cec5SDimitry Andric // (10 spaces) plus two for padding...
6350b57cec5SDimitry Andric if (max_opcode_byte_size > 0)
6360b57cec5SDimitry Andric m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
6370b57cec5SDimitry Andric else
6380b57cec5SDimitry Andric m_opcode.Dump(&ss, 12);
6390b57cec5SDimitry Andric }
6400b57cec5SDimitry Andric }
6410b57cec5SDimitry Andric
642753f127fSDimitry Andric if (show_control_flow_kind) {
643972a253aSDimitry Andric lldb::InstructionControlFlowKind instruction_control_flow_kind =
644972a253aSDimitry Andric GetControlFlowKind(exe_ctx);
645972a253aSDimitry Andric ss.Printf("%-12s", GetNameForInstructionControlFlowKind(
646972a253aSDimitry Andric instruction_control_flow_kind));
647753f127fSDimitry Andric }
648753f127fSDimitry Andric
6495f757f3fSDimitry Andric bool show_color = false;
6505f757f3fSDimitry Andric if (exe_ctx) {
6515f757f3fSDimitry Andric if (TargetSP target_sp = exe_ctx->GetTargetSP()) {
6525f757f3fSDimitry Andric show_color = target_sp->GetDebugger().GetUseColor();
6535f757f3fSDimitry Andric }
6545f757f3fSDimitry Andric }
6550b57cec5SDimitry Andric const size_t opcode_pos = ss.GetSizeOfLastLine();
6565f757f3fSDimitry Andric const std::string &opcode_name =
6575f757f3fSDimitry Andric show_color ? m_markup_opcode_name : m_opcode_name;
6585f757f3fSDimitry Andric const std::string &mnemonics = show_color ? m_markup_mnemonics : m_mnemonics;
6590b57cec5SDimitry Andric
6600b57cec5SDimitry Andric // The default opcode size of 7 characters is plenty for most architectures
6610b57cec5SDimitry Andric // but some like arm can pull out the occasional vqrshrun.s16. We won't get
6625f757f3fSDimitry Andric // consistent column spacing in these cases, unfortunately. Also note that we
6635f757f3fSDimitry Andric // need to directly use m_opcode_name here (instead of opcode_name) so we
6645f757f3fSDimitry Andric // don't include color codes as characters.
6650b57cec5SDimitry Andric if (m_opcode_name.length() >= opcode_column_width) {
6660b57cec5SDimitry Andric opcode_column_width = m_opcode_name.length() + 1;
6670b57cec5SDimitry Andric }
6680b57cec5SDimitry Andric
6695f757f3fSDimitry Andric ss.PutCString(opcode_name);
6700b57cec5SDimitry Andric ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
6715f757f3fSDimitry Andric ss.PutCString(mnemonics);
6720b57cec5SDimitry Andric
6730b57cec5SDimitry Andric if (!m_comment.empty()) {
6740b57cec5SDimitry Andric ss.FillLastLineToColumn(
6750b57cec5SDimitry Andric opcode_pos + opcode_column_width + operand_column_width, ' ');
6760b57cec5SDimitry Andric ss.PutCString(" ; ");
6770b57cec5SDimitry Andric ss.PutCString(m_comment);
6780b57cec5SDimitry Andric }
6790b57cec5SDimitry Andric s->PutCString(ss.GetString());
6800b57cec5SDimitry Andric }
6810b57cec5SDimitry Andric
DumpEmulation(const ArchSpec & arch)6820b57cec5SDimitry Andric bool Instruction::DumpEmulation(const ArchSpec &arch) {
6830b57cec5SDimitry Andric std::unique_ptr<EmulateInstruction> insn_emulator_up(
6840b57cec5SDimitry Andric EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
6850b57cec5SDimitry Andric if (insn_emulator_up) {
6860b57cec5SDimitry Andric insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);
6870b57cec5SDimitry Andric return insn_emulator_up->EvaluateInstruction(0);
6880b57cec5SDimitry Andric }
6890b57cec5SDimitry Andric
6900b57cec5SDimitry Andric return false;
6910b57cec5SDimitry Andric }
6920b57cec5SDimitry Andric
CanSetBreakpoint()6930b57cec5SDimitry Andric bool Instruction::CanSetBreakpoint () {
6940b57cec5SDimitry Andric return !HasDelaySlot();
6950b57cec5SDimitry Andric }
6960b57cec5SDimitry Andric
HasDelaySlot()6970b57cec5SDimitry Andric bool Instruction::HasDelaySlot() {
6980b57cec5SDimitry Andric // Default is false.
6990b57cec5SDimitry Andric return false;
7000b57cec5SDimitry Andric }
7010b57cec5SDimitry Andric
ReadArray(FILE * in_file,Stream & out_stream,OptionValue::Type data_type)70206c3fb27SDimitry Andric OptionValueSP Instruction::ReadArray(FILE *in_file, Stream &out_stream,
7030b57cec5SDimitry Andric OptionValue::Type data_type) {
7040b57cec5SDimitry Andric bool done = false;
7050b57cec5SDimitry Andric char buffer[1024];
7060b57cec5SDimitry Andric
7070b57cec5SDimitry Andric auto option_value_sp = std::make_shared<OptionValueArray>(1u << data_type);
7080b57cec5SDimitry Andric
7090b57cec5SDimitry Andric int idx = 0;
7100b57cec5SDimitry Andric while (!done) {
7110b57cec5SDimitry Andric if (!fgets(buffer, 1023, in_file)) {
71206c3fb27SDimitry Andric out_stream.Printf(
7130b57cec5SDimitry Andric "Instruction::ReadArray: Error reading file (fgets).\n");
7140b57cec5SDimitry Andric option_value_sp.reset();
7150b57cec5SDimitry Andric return option_value_sp;
7160b57cec5SDimitry Andric }
7170b57cec5SDimitry Andric
7180b57cec5SDimitry Andric std::string line(buffer);
7190b57cec5SDimitry Andric
7200b57cec5SDimitry Andric size_t len = line.size();
7210b57cec5SDimitry Andric if (line[len - 1] == '\n') {
7220b57cec5SDimitry Andric line[len - 1] = '\0';
7230b57cec5SDimitry Andric line.resize(len - 1);
7240b57cec5SDimitry Andric }
7250b57cec5SDimitry Andric
7260b57cec5SDimitry Andric if ((line.size() == 1) && line[0] == ']') {
7270b57cec5SDimitry Andric done = true;
7280b57cec5SDimitry Andric line.clear();
7290b57cec5SDimitry Andric }
7300b57cec5SDimitry Andric
7310b57cec5SDimitry Andric if (!line.empty()) {
7320b57cec5SDimitry Andric std::string value;
7330b57cec5SDimitry Andric static RegularExpression g_reg_exp(
7340b57cec5SDimitry Andric llvm::StringRef("^[ \t]*([^ \t]+)[ \t]*$"));
7359dba64beSDimitry Andric llvm::SmallVector<llvm::StringRef, 2> matches;
7369dba64beSDimitry Andric if (g_reg_exp.Execute(line, &matches))
7379dba64beSDimitry Andric value = matches[1].str();
7380b57cec5SDimitry Andric else
7390b57cec5SDimitry Andric value = line;
7400b57cec5SDimitry Andric
7410b57cec5SDimitry Andric OptionValueSP data_value_sp;
7420b57cec5SDimitry Andric switch (data_type) {
7430b57cec5SDimitry Andric case OptionValue::eTypeUInt64:
7440b57cec5SDimitry Andric data_value_sp = std::make_shared<OptionValueUInt64>(0, 0);
7450b57cec5SDimitry Andric data_value_sp->SetValueFromString(value);
7460b57cec5SDimitry Andric break;
7470b57cec5SDimitry Andric // Other types can be added later as needed.
7480b57cec5SDimitry Andric default:
7490b57cec5SDimitry Andric data_value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
7500b57cec5SDimitry Andric break;
7510b57cec5SDimitry Andric }
7520b57cec5SDimitry Andric
7530b57cec5SDimitry Andric option_value_sp->GetAsArray()->InsertValue(idx, data_value_sp);
7540b57cec5SDimitry Andric ++idx;
7550b57cec5SDimitry Andric }
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric
7580b57cec5SDimitry Andric return option_value_sp;
7590b57cec5SDimitry Andric }
7600b57cec5SDimitry Andric
ReadDictionary(FILE * in_file,Stream & out_stream)76106c3fb27SDimitry Andric OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream &out_stream) {
7620b57cec5SDimitry Andric bool done = false;
7630b57cec5SDimitry Andric char buffer[1024];
7640b57cec5SDimitry Andric
7650b57cec5SDimitry Andric auto option_value_sp = std::make_shared<OptionValueDictionary>();
76606c3fb27SDimitry Andric static constexpr llvm::StringLiteral encoding_key("data_encoding");
7670b57cec5SDimitry Andric OptionValue::Type data_type = OptionValue::eTypeInvalid;
7680b57cec5SDimitry Andric
7690b57cec5SDimitry Andric while (!done) {
7700b57cec5SDimitry Andric // Read the next line in the file
7710b57cec5SDimitry Andric if (!fgets(buffer, 1023, in_file)) {
77206c3fb27SDimitry Andric out_stream.Printf(
7730b57cec5SDimitry Andric "Instruction::ReadDictionary: Error reading file (fgets).\n");
7740b57cec5SDimitry Andric option_value_sp.reset();
7750b57cec5SDimitry Andric return option_value_sp;
7760b57cec5SDimitry Andric }
7770b57cec5SDimitry Andric
7780b57cec5SDimitry Andric // Check to see if the line contains the end-of-dictionary marker ("}")
7790b57cec5SDimitry Andric std::string line(buffer);
7800b57cec5SDimitry Andric
7810b57cec5SDimitry Andric size_t len = line.size();
7820b57cec5SDimitry Andric if (line[len - 1] == '\n') {
7830b57cec5SDimitry Andric line[len - 1] = '\0';
7840b57cec5SDimitry Andric line.resize(len - 1);
7850b57cec5SDimitry Andric }
7860b57cec5SDimitry Andric
7870b57cec5SDimitry Andric if ((line.size() == 1) && (line[0] == '}')) {
7880b57cec5SDimitry Andric done = true;
7890b57cec5SDimitry Andric line.clear();
7900b57cec5SDimitry Andric }
7910b57cec5SDimitry Andric
7920b57cec5SDimitry Andric // Try to find a key-value pair in the current line and add it to the
7930b57cec5SDimitry Andric // dictionary.
7940b57cec5SDimitry Andric if (!line.empty()) {
7950b57cec5SDimitry Andric static RegularExpression g_reg_exp(llvm::StringRef(
7960b57cec5SDimitry Andric "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$"));
7970b57cec5SDimitry Andric
7989dba64beSDimitry Andric llvm::SmallVector<llvm::StringRef, 3> matches;
7999dba64beSDimitry Andric
8009dba64beSDimitry Andric bool reg_exp_success = g_reg_exp.Execute(line, &matches);
8010b57cec5SDimitry Andric std::string key;
8020b57cec5SDimitry Andric std::string value;
8030b57cec5SDimitry Andric if (reg_exp_success) {
8049dba64beSDimitry Andric key = matches[1].str();
8059dba64beSDimitry Andric value = matches[2].str();
8060b57cec5SDimitry Andric } else {
80706c3fb27SDimitry Andric out_stream.Printf("Instruction::ReadDictionary: Failure executing "
8080b57cec5SDimitry Andric "regular expression.\n");
8090b57cec5SDimitry Andric option_value_sp.reset();
8100b57cec5SDimitry Andric return option_value_sp;
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric
8130b57cec5SDimitry Andric // Check value to see if it's the start of an array or dictionary.
8140b57cec5SDimitry Andric
8150b57cec5SDimitry Andric lldb::OptionValueSP value_sp;
8160b57cec5SDimitry Andric assert(value.empty() == false);
8170b57cec5SDimitry Andric assert(key.empty() == false);
8180b57cec5SDimitry Andric
8190b57cec5SDimitry Andric if (value[0] == '{') {
8200b57cec5SDimitry Andric assert(value.size() == 1);
8210b57cec5SDimitry Andric // value is a dictionary
8220b57cec5SDimitry Andric value_sp = ReadDictionary(in_file, out_stream);
8230b57cec5SDimitry Andric if (!value_sp) {
8240b57cec5SDimitry Andric option_value_sp.reset();
8250b57cec5SDimitry Andric return option_value_sp;
8260b57cec5SDimitry Andric }
8270b57cec5SDimitry Andric } else if (value[0] == '[') {
8280b57cec5SDimitry Andric assert(value.size() == 1);
8290b57cec5SDimitry Andric // value is an array
8300b57cec5SDimitry Andric value_sp = ReadArray(in_file, out_stream, data_type);
8310b57cec5SDimitry Andric if (!value_sp) {
8320b57cec5SDimitry Andric option_value_sp.reset();
8330b57cec5SDimitry Andric return option_value_sp;
8340b57cec5SDimitry Andric }
8350b57cec5SDimitry Andric // We've used the data_type to read an array; re-set the type to
8360b57cec5SDimitry Andric // Invalid
8370b57cec5SDimitry Andric data_type = OptionValue::eTypeInvalid;
8380b57cec5SDimitry Andric } else if ((value[0] == '0') && (value[1] == 'x')) {
8390b57cec5SDimitry Andric value_sp = std::make_shared<OptionValueUInt64>(0, 0);
8400b57cec5SDimitry Andric value_sp->SetValueFromString(value);
8410b57cec5SDimitry Andric } else {
8420b57cec5SDimitry Andric size_t len = value.size();
8430b57cec5SDimitry Andric if ((value[0] == '"') && (value[len - 1] == '"'))
8440b57cec5SDimitry Andric value = value.substr(1, len - 2);
8450b57cec5SDimitry Andric value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric
84806c3fb27SDimitry Andric if (key == encoding_key) {
8490b57cec5SDimitry Andric // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data
85006c3fb27SDimitry Andric // indicating the data type of an upcoming array (usually the next bit
85106c3fb27SDimitry Andric // of data to be read in).
85206c3fb27SDimitry Andric if (llvm::StringRef(value) == "uint32_t")
8530b57cec5SDimitry Andric data_type = OptionValue::eTypeUInt64;
8540b57cec5SDimitry Andric } else
85506c3fb27SDimitry Andric option_value_sp->GetAsDictionary()->SetValueForKey(key, value_sp,
8560b57cec5SDimitry Andric false);
8570b57cec5SDimitry Andric }
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric
8600b57cec5SDimitry Andric return option_value_sp;
8610b57cec5SDimitry Andric }
8620b57cec5SDimitry Andric
TestEmulation(Stream & out_stream,const char * file_name)86306c3fb27SDimitry Andric bool Instruction::TestEmulation(Stream &out_stream, const char *file_name) {
8640b57cec5SDimitry Andric if (!file_name) {
86506c3fb27SDimitry Andric out_stream.Printf("Instruction::TestEmulation: Missing file_name.");
8660b57cec5SDimitry Andric return false;
8670b57cec5SDimitry Andric }
8680b57cec5SDimitry Andric FILE *test_file = FileSystem::Instance().Fopen(file_name, "r");
8690b57cec5SDimitry Andric if (!test_file) {
87006c3fb27SDimitry Andric out_stream.Printf(
8710b57cec5SDimitry Andric "Instruction::TestEmulation: Attempt to open test file failed.");
8720b57cec5SDimitry Andric return false;
8730b57cec5SDimitry Andric }
8740b57cec5SDimitry Andric
8750b57cec5SDimitry Andric char buffer[256];
8760b57cec5SDimitry Andric if (!fgets(buffer, 255, test_file)) {
87706c3fb27SDimitry Andric out_stream.Printf(
8780b57cec5SDimitry Andric "Instruction::TestEmulation: Error reading first line of test file.\n");
8790b57cec5SDimitry Andric fclose(test_file);
8800b57cec5SDimitry Andric return false;
8810b57cec5SDimitry Andric }
8820b57cec5SDimitry Andric
8830b57cec5SDimitry Andric if (strncmp(buffer, "InstructionEmulationState={", 27) != 0) {
88406c3fb27SDimitry Andric out_stream.Printf("Instructin::TestEmulation: Test file does not contain "
8850b57cec5SDimitry Andric "emulation state dictionary\n");
8860b57cec5SDimitry Andric fclose(test_file);
8870b57cec5SDimitry Andric return false;
8880b57cec5SDimitry Andric }
8890b57cec5SDimitry Andric
8900b57cec5SDimitry Andric // Read all the test information from the test file into an
8910b57cec5SDimitry Andric // OptionValueDictionary.
8920b57cec5SDimitry Andric
8930b57cec5SDimitry Andric OptionValueSP data_dictionary_sp(ReadDictionary(test_file, out_stream));
8940b57cec5SDimitry Andric if (!data_dictionary_sp) {
89506c3fb27SDimitry Andric out_stream.Printf(
8960b57cec5SDimitry Andric "Instruction::TestEmulation: Error reading Dictionary Object.\n");
8970b57cec5SDimitry Andric fclose(test_file);
8980b57cec5SDimitry Andric return false;
8990b57cec5SDimitry Andric }
9000b57cec5SDimitry Andric
9010b57cec5SDimitry Andric fclose(test_file);
9020b57cec5SDimitry Andric
9030b57cec5SDimitry Andric OptionValueDictionary *data_dictionary =
9040b57cec5SDimitry Andric data_dictionary_sp->GetAsDictionary();
90506c3fb27SDimitry Andric static constexpr llvm::StringLiteral description_key("assembly_string");
90606c3fb27SDimitry Andric static constexpr llvm::StringLiteral triple_key("triple");
9070b57cec5SDimitry Andric
9080b57cec5SDimitry Andric OptionValueSP value_sp = data_dictionary->GetValueForKey(description_key);
9090b57cec5SDimitry Andric
9100b57cec5SDimitry Andric if (!value_sp) {
91106c3fb27SDimitry Andric out_stream.Printf("Instruction::TestEmulation: Test file does not "
9120b57cec5SDimitry Andric "contain description string.\n");
9130b57cec5SDimitry Andric return false;
9140b57cec5SDimitry Andric }
9150b57cec5SDimitry Andric
91606c3fb27SDimitry Andric SetDescription(value_sp->GetValueAs<llvm::StringRef>().value_or(""));
9170b57cec5SDimitry Andric
9180b57cec5SDimitry Andric value_sp = data_dictionary->GetValueForKey(triple_key);
9190b57cec5SDimitry Andric if (!value_sp) {
92006c3fb27SDimitry Andric out_stream.Printf(
9210b57cec5SDimitry Andric "Instruction::TestEmulation: Test file does not contain triple.\n");
9220b57cec5SDimitry Andric return false;
9230b57cec5SDimitry Andric }
9240b57cec5SDimitry Andric
9250b57cec5SDimitry Andric ArchSpec arch;
92606c3fb27SDimitry Andric arch.SetTriple(
92706c3fb27SDimitry Andric llvm::Triple(value_sp->GetValueAs<llvm::StringRef>().value_or("")));
9280b57cec5SDimitry Andric
9290b57cec5SDimitry Andric bool success = false;
9300b57cec5SDimitry Andric std::unique_ptr<EmulateInstruction> insn_emulator_up(
9310b57cec5SDimitry Andric EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
9320b57cec5SDimitry Andric if (insn_emulator_up)
9330b57cec5SDimitry Andric success =
9340b57cec5SDimitry Andric insn_emulator_up->TestEmulation(out_stream, arch, data_dictionary);
9350b57cec5SDimitry Andric
9360b57cec5SDimitry Andric if (success)
93706c3fb27SDimitry Andric out_stream.Printf("Emulation test succeeded.");
9380b57cec5SDimitry Andric else
93906c3fb27SDimitry Andric out_stream.Printf("Emulation test failed.");
9400b57cec5SDimitry Andric
9410b57cec5SDimitry Andric return success;
9420b57cec5SDimitry Andric }
9430b57cec5SDimitry Andric
Emulate(const ArchSpec & arch,uint32_t evaluate_options,void * baton,EmulateInstruction::ReadMemoryCallback read_mem_callback,EmulateInstruction::WriteMemoryCallback write_mem_callback,EmulateInstruction::ReadRegisterCallback read_reg_callback,EmulateInstruction::WriteRegisterCallback write_reg_callback)9440b57cec5SDimitry Andric bool Instruction::Emulate(
9450b57cec5SDimitry Andric const ArchSpec &arch, uint32_t evaluate_options, void *baton,
9460b57cec5SDimitry Andric EmulateInstruction::ReadMemoryCallback read_mem_callback,
9470b57cec5SDimitry Andric EmulateInstruction::WriteMemoryCallback write_mem_callback,
9480b57cec5SDimitry Andric EmulateInstruction::ReadRegisterCallback read_reg_callback,
9490b57cec5SDimitry Andric EmulateInstruction::WriteRegisterCallback write_reg_callback) {
9500b57cec5SDimitry Andric std::unique_ptr<EmulateInstruction> insn_emulator_up(
9510b57cec5SDimitry Andric EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
9520b57cec5SDimitry Andric if (insn_emulator_up) {
9530b57cec5SDimitry Andric insn_emulator_up->SetBaton(baton);
9540b57cec5SDimitry Andric insn_emulator_up->SetCallbacks(read_mem_callback, write_mem_callback,
9550b57cec5SDimitry Andric read_reg_callback, write_reg_callback);
9560b57cec5SDimitry Andric insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);
9570b57cec5SDimitry Andric return insn_emulator_up->EvaluateInstruction(evaluate_options);
9580b57cec5SDimitry Andric }
9590b57cec5SDimitry Andric
9600b57cec5SDimitry Andric return false;
9610b57cec5SDimitry Andric }
9620b57cec5SDimitry Andric
GetData(DataExtractor & data)9630b57cec5SDimitry Andric uint32_t Instruction::GetData(DataExtractor &data) {
9640b57cec5SDimitry Andric return m_opcode.GetData(data);
9650b57cec5SDimitry Andric }
9660b57cec5SDimitry Andric
InstructionList()9670b57cec5SDimitry Andric InstructionList::InstructionList() : m_instructions() {}
9680b57cec5SDimitry Andric
9690b57cec5SDimitry Andric InstructionList::~InstructionList() = default;
9700b57cec5SDimitry Andric
GetSize() const9710b57cec5SDimitry Andric size_t InstructionList::GetSize() const { return m_instructions.size(); }
9720b57cec5SDimitry Andric
GetMaxOpcocdeByteSize() const9730b57cec5SDimitry Andric uint32_t InstructionList::GetMaxOpcocdeByteSize() const {
9740b57cec5SDimitry Andric uint32_t max_inst_size = 0;
9750b57cec5SDimitry Andric collection::const_iterator pos, end;
9760b57cec5SDimitry Andric for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end;
9770b57cec5SDimitry Andric ++pos) {
9780b57cec5SDimitry Andric uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();
9790b57cec5SDimitry Andric if (max_inst_size < inst_size)
9800b57cec5SDimitry Andric max_inst_size = inst_size;
9810b57cec5SDimitry Andric }
9820b57cec5SDimitry Andric return max_inst_size;
9830b57cec5SDimitry Andric }
9840b57cec5SDimitry Andric
GetInstructionAtIndex(size_t idx) const9850b57cec5SDimitry Andric InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const {
9860b57cec5SDimitry Andric InstructionSP inst_sp;
9870b57cec5SDimitry Andric if (idx < m_instructions.size())
9880b57cec5SDimitry Andric inst_sp = m_instructions[idx];
9890b57cec5SDimitry Andric return inst_sp;
9900b57cec5SDimitry Andric }
9910b57cec5SDimitry Andric
GetInstructionAtAddress(const Address & address)992e8d8bef9SDimitry Andric InstructionSP InstructionList::GetInstructionAtAddress(const Address &address) {
993e8d8bef9SDimitry Andric uint32_t index = GetIndexOfInstructionAtAddress(address);
994e8d8bef9SDimitry Andric if (index != UINT32_MAX)
995e8d8bef9SDimitry Andric return GetInstructionAtIndex(index);
996e8d8bef9SDimitry Andric return nullptr;
997e8d8bef9SDimitry Andric }
998e8d8bef9SDimitry Andric
Dump(Stream * s,bool show_address,bool show_bytes,bool show_control_flow_kind,const ExecutionContext * exe_ctx)9990b57cec5SDimitry Andric void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,
1000753f127fSDimitry Andric bool show_control_flow_kind,
10010b57cec5SDimitry Andric const ExecutionContext *exe_ctx) {
10020b57cec5SDimitry Andric const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
10030b57cec5SDimitry Andric collection::const_iterator pos, begin, end;
10040b57cec5SDimitry Andric
10050b57cec5SDimitry Andric const FormatEntity::Entry *disassembly_format = nullptr;
10060b57cec5SDimitry Andric FormatEntity::Entry format;
10070b57cec5SDimitry Andric if (exe_ctx && exe_ctx->HasTargetScope()) {
10080b57cec5SDimitry Andric disassembly_format =
10090b57cec5SDimitry Andric exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
10100b57cec5SDimitry Andric } else {
10110b57cec5SDimitry Andric FormatEntity::Parse("${addr}: ", format);
10120b57cec5SDimitry Andric disassembly_format = &format;
10130b57cec5SDimitry Andric }
10140b57cec5SDimitry Andric
10150b57cec5SDimitry Andric for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
10160b57cec5SDimitry Andric pos != end; ++pos) {
10170b57cec5SDimitry Andric if (pos != begin)
10180b57cec5SDimitry Andric s->EOL();
1019753f127fSDimitry Andric (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes,
1020753f127fSDimitry Andric show_control_flow_kind, exe_ctx, nullptr, nullptr,
1021753f127fSDimitry Andric disassembly_format, 0);
10220b57cec5SDimitry Andric }
10230b57cec5SDimitry Andric }
10240b57cec5SDimitry Andric
Clear()10250b57cec5SDimitry Andric void InstructionList::Clear() { m_instructions.clear(); }
10260b57cec5SDimitry Andric
Append(lldb::InstructionSP & inst_sp)10270b57cec5SDimitry Andric void InstructionList::Append(lldb::InstructionSP &inst_sp) {
10280b57cec5SDimitry Andric if (inst_sp)
10290b57cec5SDimitry Andric m_instructions.push_back(inst_sp);
10300b57cec5SDimitry Andric }
10310b57cec5SDimitry Andric
10320b57cec5SDimitry Andric uint32_t
GetIndexOfNextBranchInstruction(uint32_t start,bool ignore_calls,bool * found_calls) const10330b57cec5SDimitry Andric InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
1034480093f4SDimitry Andric bool ignore_calls,
1035480093f4SDimitry Andric bool *found_calls) const {
10360b57cec5SDimitry Andric size_t num_instructions = m_instructions.size();
10370b57cec5SDimitry Andric
10380b57cec5SDimitry Andric uint32_t next_branch = UINT32_MAX;
1039480093f4SDimitry Andric
1040480093f4SDimitry Andric if (found_calls)
1041480093f4SDimitry Andric *found_calls = false;
1042e8d8bef9SDimitry Andric for (size_t i = start; i < num_instructions; i++) {
10430b57cec5SDimitry Andric if (m_instructions[i]->DoesBranch()) {
1044480093f4SDimitry Andric if (ignore_calls && m_instructions[i]->IsCall()) {
1045480093f4SDimitry Andric if (found_calls)
1046480093f4SDimitry Andric *found_calls = true;
10470b57cec5SDimitry Andric continue;
1048480093f4SDimitry Andric }
10490b57cec5SDimitry Andric next_branch = i;
10500b57cec5SDimitry Andric break;
10510b57cec5SDimitry Andric }
10520b57cec5SDimitry Andric }
10530b57cec5SDimitry Andric
10540b57cec5SDimitry Andric return next_branch;
10550b57cec5SDimitry Andric }
10560b57cec5SDimitry Andric
10570b57cec5SDimitry Andric uint32_t
GetIndexOfInstructionAtAddress(const Address & address)10580b57cec5SDimitry Andric InstructionList::GetIndexOfInstructionAtAddress(const Address &address) {
10590b57cec5SDimitry Andric size_t num_instructions = m_instructions.size();
10600b57cec5SDimitry Andric uint32_t index = UINT32_MAX;
10610b57cec5SDimitry Andric for (size_t i = 0; i < num_instructions; i++) {
10620b57cec5SDimitry Andric if (m_instructions[i]->GetAddress() == address) {
10630b57cec5SDimitry Andric index = i;
10640b57cec5SDimitry Andric break;
10650b57cec5SDimitry Andric }
10660b57cec5SDimitry Andric }
10670b57cec5SDimitry Andric return index;
10680b57cec5SDimitry Andric }
10690b57cec5SDimitry Andric
10700b57cec5SDimitry Andric uint32_t
GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,Target & target)10710b57cec5SDimitry Andric InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,
10720b57cec5SDimitry Andric Target &target) {
10730b57cec5SDimitry Andric Address address;
10740b57cec5SDimitry Andric address.SetLoadAddress(load_addr, &target);
10750b57cec5SDimitry Andric return GetIndexOfInstructionAtAddress(address);
10760b57cec5SDimitry Andric }
10770b57cec5SDimitry Andric
ParseInstructions(Target & target,Address start,Limit limit,Stream * error_strm_ptr,bool force_live_memory)10785ffd83dbSDimitry Andric size_t Disassembler::ParseInstructions(Target &target, Address start,
10795ffd83dbSDimitry Andric Limit limit, Stream *error_strm_ptr,
1080fe6060f1SDimitry Andric bool force_live_memory) {
10815ffd83dbSDimitry Andric m_instruction_list.Clear();
10825ffd83dbSDimitry Andric
10835ffd83dbSDimitry Andric if (!start.IsValid())
10840b57cec5SDimitry Andric return 0;
10850b57cec5SDimitry Andric
10865ffd83dbSDimitry Andric start = ResolveAddress(target, start);
10875ffd83dbSDimitry Andric
10885ffd83dbSDimitry Andric addr_t byte_size = limit.value;
10895ffd83dbSDimitry Andric if (limit.kind == Limit::Instructions)
10905ffd83dbSDimitry Andric byte_size *= m_arch.GetMaximumOpcodeByteSize();
10910b57cec5SDimitry Andric auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0');
10920b57cec5SDimitry Andric
10930b57cec5SDimitry Andric Status error;
10940b57cec5SDimitry Andric lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
10955ffd83dbSDimitry Andric const size_t bytes_read =
1096fe6060f1SDimitry Andric target.ReadMemory(start, data_sp->GetBytes(), data_sp->GetByteSize(),
1097fe6060f1SDimitry Andric error, force_live_memory, &load_addr);
10985ffd83dbSDimitry Andric const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
10990b57cec5SDimitry Andric
11005ffd83dbSDimitry Andric if (bytes_read == 0) {
11015ffd83dbSDimitry Andric if (error_strm_ptr) {
11025ffd83dbSDimitry Andric if (const char *error_cstr = error.AsCString())
11035ffd83dbSDimitry Andric error_strm_ptr->Printf("error: %s\n", error_cstr);
11045ffd83dbSDimitry Andric }
11055ffd83dbSDimitry Andric return 0;
11065ffd83dbSDimitry Andric }
11075ffd83dbSDimitry Andric
11080b57cec5SDimitry Andric if (bytes_read != data_sp->GetByteSize())
11090b57cec5SDimitry Andric data_sp->SetByteSize(bytes_read);
11100b57cec5SDimitry Andric DataExtractor data(data_sp, m_arch.GetByteOrder(),
11110b57cec5SDimitry Andric m_arch.GetAddressByteSize());
11125ffd83dbSDimitry Andric return DecodeInstructions(start, data, 0,
11135ffd83dbSDimitry Andric limit.kind == Limit::Instructions ? limit.value
11145ffd83dbSDimitry Andric : UINT32_MAX,
11150b57cec5SDimitry Andric false, data_from_file);
11160b57cec5SDimitry Andric }
11170b57cec5SDimitry Andric
11180b57cec5SDimitry Andric // Disassembler copy constructor
Disassembler(const ArchSpec & arch,const char * flavor)11190b57cec5SDimitry Andric Disassembler::Disassembler(const ArchSpec &arch, const char *flavor)
11200b57cec5SDimitry Andric : m_arch(arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS),
11210b57cec5SDimitry Andric m_flavor() {
11220b57cec5SDimitry Andric if (flavor == nullptr)
11230b57cec5SDimitry Andric m_flavor.assign("default");
11240b57cec5SDimitry Andric else
11250b57cec5SDimitry Andric m_flavor.assign(flavor);
11260b57cec5SDimitry Andric
11270b57cec5SDimitry Andric // If this is an arm variant that can only include thumb (T16, T32)
11280b57cec5SDimitry Andric // instructions, force the arch triple to be "thumbv.." instead of "armv..."
11290b57cec5SDimitry Andric if (arch.IsAlwaysThumbInstructions()) {
11300b57cec5SDimitry Andric std::string thumb_arch_name(arch.GetTriple().getArchName().str());
11310b57cec5SDimitry Andric // Replace "arm" with "thumb" so we get all thumb variants correct
11320b57cec5SDimitry Andric if (thumb_arch_name.size() > 3) {
11330b57cec5SDimitry Andric thumb_arch_name.erase(0, 3);
11340b57cec5SDimitry Andric thumb_arch_name.insert(0, "thumb");
11350b57cec5SDimitry Andric }
11360b57cec5SDimitry Andric m_arch.SetTriple(thumb_arch_name.c_str());
11370b57cec5SDimitry Andric }
11380b57cec5SDimitry Andric }
11390b57cec5SDimitry Andric
11400b57cec5SDimitry Andric Disassembler::~Disassembler() = default;
11410b57cec5SDimitry Andric
GetInstructionList()11420b57cec5SDimitry Andric InstructionList &Disassembler::GetInstructionList() {
11430b57cec5SDimitry Andric return m_instruction_list;
11440b57cec5SDimitry Andric }
11450b57cec5SDimitry Andric
GetInstructionList() const11460b57cec5SDimitry Andric const InstructionList &Disassembler::GetInstructionList() const {
11470b57cec5SDimitry Andric return m_instruction_list;
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric
11500b57cec5SDimitry Andric // Class PseudoInstruction
11510b57cec5SDimitry Andric
PseudoInstruction()11520b57cec5SDimitry Andric PseudoInstruction::PseudoInstruction()
11530b57cec5SDimitry Andric : Instruction(Address(), AddressClass::eUnknown), m_description() {}
11540b57cec5SDimitry Andric
11550b57cec5SDimitry Andric PseudoInstruction::~PseudoInstruction() = default;
11560b57cec5SDimitry Andric
DoesBranch()11570b57cec5SDimitry Andric bool PseudoInstruction::DoesBranch() {
11580b57cec5SDimitry Andric // This is NOT a valid question for a pseudo instruction.
11590b57cec5SDimitry Andric return false;
11600b57cec5SDimitry Andric }
11610b57cec5SDimitry Andric
HasDelaySlot()11620b57cec5SDimitry Andric bool PseudoInstruction::HasDelaySlot() {
11630b57cec5SDimitry Andric // This is NOT a valid question for a pseudo instruction.
11640b57cec5SDimitry Andric return false;
11650b57cec5SDimitry Andric }
11660b57cec5SDimitry Andric
IsLoad()1167349cc55cSDimitry Andric bool PseudoInstruction::IsLoad() { return false; }
1168349cc55cSDimitry Andric
IsAuthenticated()1169349cc55cSDimitry Andric bool PseudoInstruction::IsAuthenticated() { return false; }
1170349cc55cSDimitry Andric
Decode(const lldb_private::Disassembler & disassembler,const lldb_private::DataExtractor & data,lldb::offset_t data_offset)11710b57cec5SDimitry Andric size_t PseudoInstruction::Decode(const lldb_private::Disassembler &disassembler,
11720b57cec5SDimitry Andric const lldb_private::DataExtractor &data,
11730b57cec5SDimitry Andric lldb::offset_t data_offset) {
11740b57cec5SDimitry Andric return m_opcode.GetByteSize();
11750b57cec5SDimitry Andric }
11760b57cec5SDimitry Andric
SetOpcode(size_t opcode_size,void * opcode_data)11770b57cec5SDimitry Andric void PseudoInstruction::SetOpcode(size_t opcode_size, void *opcode_data) {
11780b57cec5SDimitry Andric if (!opcode_data)
11790b57cec5SDimitry Andric return;
11800b57cec5SDimitry Andric
11810b57cec5SDimitry Andric switch (opcode_size) {
11820b57cec5SDimitry Andric case 8: {
11830b57cec5SDimitry Andric uint8_t value8 = *((uint8_t *)opcode_data);
11840b57cec5SDimitry Andric m_opcode.SetOpcode8(value8, eByteOrderInvalid);
11850b57cec5SDimitry Andric break;
11860b57cec5SDimitry Andric }
11870b57cec5SDimitry Andric case 16: {
11880b57cec5SDimitry Andric uint16_t value16 = *((uint16_t *)opcode_data);
11890b57cec5SDimitry Andric m_opcode.SetOpcode16(value16, eByteOrderInvalid);
11900b57cec5SDimitry Andric break;
11910b57cec5SDimitry Andric }
11920b57cec5SDimitry Andric case 32: {
11930b57cec5SDimitry Andric uint32_t value32 = *((uint32_t *)opcode_data);
11940b57cec5SDimitry Andric m_opcode.SetOpcode32(value32, eByteOrderInvalid);
11950b57cec5SDimitry Andric break;
11960b57cec5SDimitry Andric }
11970b57cec5SDimitry Andric case 64: {
11980b57cec5SDimitry Andric uint64_t value64 = *((uint64_t *)opcode_data);
11990b57cec5SDimitry Andric m_opcode.SetOpcode64(value64, eByteOrderInvalid);
12000b57cec5SDimitry Andric break;
12010b57cec5SDimitry Andric }
12020b57cec5SDimitry Andric default:
12030b57cec5SDimitry Andric break;
12040b57cec5SDimitry Andric }
12050b57cec5SDimitry Andric }
12060b57cec5SDimitry Andric
SetDescription(llvm::StringRef description)12070b57cec5SDimitry Andric void PseudoInstruction::SetDescription(llvm::StringRef description) {
12085ffd83dbSDimitry Andric m_description = std::string(description);
12090b57cec5SDimitry Andric }
12100b57cec5SDimitry Andric
BuildRegister(ConstString & r)12110b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildRegister(ConstString &r) {
12120b57cec5SDimitry Andric Operand ret;
12130b57cec5SDimitry Andric ret.m_type = Type::Register;
12140b57cec5SDimitry Andric ret.m_register = r;
12150b57cec5SDimitry Andric return ret;
12160b57cec5SDimitry Andric }
12170b57cec5SDimitry Andric
BuildImmediate(lldb::addr_t imm,bool neg)12180b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildImmediate(lldb::addr_t imm,
12190b57cec5SDimitry Andric bool neg) {
12200b57cec5SDimitry Andric Operand ret;
12210b57cec5SDimitry Andric ret.m_type = Type::Immediate;
12220b57cec5SDimitry Andric ret.m_immediate = imm;
12230b57cec5SDimitry Andric ret.m_negative = neg;
12240b57cec5SDimitry Andric return ret;
12250b57cec5SDimitry Andric }
12260b57cec5SDimitry Andric
BuildImmediate(int64_t imm)12270b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildImmediate(int64_t imm) {
12280b57cec5SDimitry Andric Operand ret;
12290b57cec5SDimitry Andric ret.m_type = Type::Immediate;
12300b57cec5SDimitry Andric if (imm < 0) {
12310b57cec5SDimitry Andric ret.m_immediate = -imm;
12320b57cec5SDimitry Andric ret.m_negative = true;
12330b57cec5SDimitry Andric } else {
12340b57cec5SDimitry Andric ret.m_immediate = imm;
12350b57cec5SDimitry Andric ret.m_negative = false;
12360b57cec5SDimitry Andric }
12370b57cec5SDimitry Andric return ret;
12380b57cec5SDimitry Andric }
12390b57cec5SDimitry Andric
12400b57cec5SDimitry Andric Instruction::Operand
BuildDereference(const Operand & ref)12410b57cec5SDimitry Andric Instruction::Operand::BuildDereference(const Operand &ref) {
12420b57cec5SDimitry Andric Operand ret;
12430b57cec5SDimitry Andric ret.m_type = Type::Dereference;
12440b57cec5SDimitry Andric ret.m_children = {ref};
12450b57cec5SDimitry Andric return ret;
12460b57cec5SDimitry Andric }
12470b57cec5SDimitry Andric
BuildSum(const Operand & lhs,const Operand & rhs)12480b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildSum(const Operand &lhs,
12490b57cec5SDimitry Andric const Operand &rhs) {
12500b57cec5SDimitry Andric Operand ret;
12510b57cec5SDimitry Andric ret.m_type = Type::Sum;
12520b57cec5SDimitry Andric ret.m_children = {lhs, rhs};
12530b57cec5SDimitry Andric return ret;
12540b57cec5SDimitry Andric }
12550b57cec5SDimitry Andric
BuildProduct(const Operand & lhs,const Operand & rhs)12560b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildProduct(const Operand &lhs,
12570b57cec5SDimitry Andric const Operand &rhs) {
12580b57cec5SDimitry Andric Operand ret;
12590b57cec5SDimitry Andric ret.m_type = Type::Product;
12600b57cec5SDimitry Andric ret.m_children = {lhs, rhs};
12610b57cec5SDimitry Andric return ret;
12620b57cec5SDimitry Andric }
12630b57cec5SDimitry Andric
12640b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchBinaryOp(std::function<bool (const Instruction::Operand &)> base,std::function<bool (const Instruction::Operand &)> left,std::function<bool (const Instruction::Operand &)> right)12650b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchBinaryOp(
12660b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> base,
12670b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> left,
12680b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> right) {
12690b57cec5SDimitry Andric return [base, left, right](const Instruction::Operand &op) -> bool {
12700b57cec5SDimitry Andric return (base(op) && op.m_children.size() == 2 &&
12710b57cec5SDimitry Andric ((left(op.m_children[0]) && right(op.m_children[1])) ||
12720b57cec5SDimitry Andric (left(op.m_children[1]) && right(op.m_children[0]))));
12730b57cec5SDimitry Andric };
12740b57cec5SDimitry Andric }
12750b57cec5SDimitry Andric
12760b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchUnaryOp(std::function<bool (const Instruction::Operand &)> base,std::function<bool (const Instruction::Operand &)> child)12770b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchUnaryOp(
12780b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> base,
12790b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> child) {
12800b57cec5SDimitry Andric return [base, child](const Instruction::Operand &op) -> bool {
12810b57cec5SDimitry Andric return (base(op) && op.m_children.size() == 1 && child(op.m_children[0]));
12820b57cec5SDimitry Andric };
12830b57cec5SDimitry Andric }
12840b57cec5SDimitry Andric
12850b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchRegOp(const RegisterInfo & info)12860b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchRegOp(const RegisterInfo &info) {
12870b57cec5SDimitry Andric return [&info](const Instruction::Operand &op) {
12880b57cec5SDimitry Andric return (op.m_type == Instruction::Operand::Type::Register &&
12890b57cec5SDimitry Andric (op.m_register == ConstString(info.name) ||
12900b57cec5SDimitry Andric op.m_register == ConstString(info.alt_name)));
12910b57cec5SDimitry Andric };
12920b57cec5SDimitry Andric }
12930b57cec5SDimitry Andric
12940b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
FetchRegOp(ConstString & reg)12950b57cec5SDimitry Andric lldb_private::OperandMatchers::FetchRegOp(ConstString ®) {
12960b57cec5SDimitry Andric return [®](const Instruction::Operand &op) {
12970b57cec5SDimitry Andric if (op.m_type != Instruction::Operand::Type::Register) {
12980b57cec5SDimitry Andric return false;
12990b57cec5SDimitry Andric }
13000b57cec5SDimitry Andric reg = op.m_register;
13010b57cec5SDimitry Andric return true;
13020b57cec5SDimitry Andric };
13030b57cec5SDimitry Andric }
13040b57cec5SDimitry Andric
13050b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchImmOp(int64_t imm)13060b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchImmOp(int64_t imm) {
13070b57cec5SDimitry Andric return [imm](const Instruction::Operand &op) {
13080b57cec5SDimitry Andric return (op.m_type == Instruction::Operand::Type::Immediate &&
13090b57cec5SDimitry Andric ((op.m_negative && op.m_immediate == (uint64_t)-imm) ||
13100b57cec5SDimitry Andric (!op.m_negative && op.m_immediate == (uint64_t)imm)));
13110b57cec5SDimitry Andric };
13120b57cec5SDimitry Andric }
13130b57cec5SDimitry Andric
13140b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
FetchImmOp(int64_t & imm)13150b57cec5SDimitry Andric lldb_private::OperandMatchers::FetchImmOp(int64_t &imm) {
13160b57cec5SDimitry Andric return [&imm](const Instruction::Operand &op) {
13170b57cec5SDimitry Andric if (op.m_type != Instruction::Operand::Type::Immediate) {
13180b57cec5SDimitry Andric return false;
13190b57cec5SDimitry Andric }
13200b57cec5SDimitry Andric if (op.m_negative) {
13210b57cec5SDimitry Andric imm = -((int64_t)op.m_immediate);
13220b57cec5SDimitry Andric } else {
13230b57cec5SDimitry Andric imm = ((int64_t)op.m_immediate);
13240b57cec5SDimitry Andric }
13250b57cec5SDimitry Andric return true;
13260b57cec5SDimitry Andric };
13270b57cec5SDimitry Andric }
13280b57cec5SDimitry Andric
13290b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchOpType(Instruction::Operand::Type type)13300b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchOpType(Instruction::Operand::Type type) {
13310b57cec5SDimitry Andric return [type](const Instruction::Operand &op) { return op.m_type == type; };
13320b57cec5SDimitry Andric }
1333