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/ADT/Triple.h"
450b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric #include <cstdint>
480b57cec5SDimitry Andric #include <cstring>
490b57cec5SDimitry Andric #include <utility>
500b57cec5SDimitry Andric
51*5f7ddb14SDimitry 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) {
61af732203SDimitry 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) {
670b57cec5SDimitry Andric ConstString const_plugin_name(plugin_name);
680b57cec5SDimitry Andric create_callback = PluginManager::GetDisassemblerCreateCallbackForPluginName(
690b57cec5SDimitry Andric const_plugin_name);
700b57cec5SDimitry Andric if (create_callback) {
710b57cec5SDimitry Andric DisassemblerSP disassembler_sp(create_callback(arch, flavor));
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric if (disassembler_sp)
740b57cec5SDimitry Andric return disassembler_sp;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric } else {
770b57cec5SDimitry Andric for (uint32_t idx = 0;
780b57cec5SDimitry Andric (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(
790b57cec5SDimitry Andric idx)) != nullptr;
800b57cec5SDimitry Andric ++idx) {
810b57cec5SDimitry Andric DisassemblerSP disassembler_sp(create_callback(arch, flavor));
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric if (disassembler_sp)
840b57cec5SDimitry Andric return disassembler_sp;
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric return DisassemblerSP();
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric
FindPluginForTarget(const Target & target,const ArchSpec & arch,const char * flavor,const char * plugin_name)905ffd83dbSDimitry Andric DisassemblerSP Disassembler::FindPluginForTarget(const Target &target,
910b57cec5SDimitry Andric const ArchSpec &arch,
920b57cec5SDimitry Andric const char *flavor,
930b57cec5SDimitry Andric const char *plugin_name) {
945ffd83dbSDimitry Andric if (flavor == nullptr) {
950b57cec5SDimitry Andric // FIXME - we don't have the mechanism in place to do per-architecture
960b57cec5SDimitry Andric // settings. But since we know that for now we only support flavors on x86
970b57cec5SDimitry Andric // & x86_64,
980b57cec5SDimitry Andric if (arch.GetTriple().getArch() == llvm::Triple::x86 ||
990b57cec5SDimitry Andric arch.GetTriple().getArch() == llvm::Triple::x86_64)
1005ffd83dbSDimitry Andric flavor = target.GetDisassemblyFlavor();
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric return FindPlugin(arch, flavor, plugin_name);
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric
ResolveAddress(Target & target,const Address & addr)1055ffd83dbSDimitry Andric static Address ResolveAddress(Target &target, const Address &addr) {
1060b57cec5SDimitry Andric if (!addr.IsSectionOffset()) {
1075ffd83dbSDimitry Andric Address resolved_addr;
1080b57cec5SDimitry Andric // If we weren't passed in a section offset address range, try and resolve
1090b57cec5SDimitry Andric // it to something
1105ffd83dbSDimitry Andric bool is_resolved = target.GetSectionLoadList().IsEmpty()
1115ffd83dbSDimitry Andric ? target.GetImages().ResolveFileAddress(
1125ffd83dbSDimitry Andric addr.GetOffset(), resolved_addr)
1135ffd83dbSDimitry Andric : target.GetSectionLoadList().ResolveLoadAddress(
1145ffd83dbSDimitry Andric addr.GetOffset(), resolved_addr);
1150b57cec5SDimitry Andric
1160b57cec5SDimitry Andric // We weren't able to resolve the address, just treat it as a raw address
1170b57cec5SDimitry Andric if (is_resolved && resolved_addr.IsValid())
1185ffd83dbSDimitry Andric return resolved_addr;
1190b57cec5SDimitry Andric }
1205ffd83dbSDimitry Andric return addr;
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric
DisassembleRange(const ArchSpec & arch,const char * plugin_name,const char * flavor,Target & target,const AddressRange & range,bool force_live_memory)1230b57cec5SDimitry Andric lldb::DisassemblerSP Disassembler::DisassembleRange(
1240b57cec5SDimitry Andric const ArchSpec &arch, const char *plugin_name, const char *flavor,
125*5f7ddb14SDimitry Andric Target &target, const AddressRange &range, bool force_live_memory) {
1269dba64beSDimitry Andric if (range.GetByteSize() <= 0)
1279dba64beSDimitry Andric return {};
1280b57cec5SDimitry Andric
1299dba64beSDimitry Andric if (!range.GetBaseAddress().IsValid())
1309dba64beSDimitry Andric return {};
1319dba64beSDimitry Andric
1325ffd83dbSDimitry Andric lldb::DisassemblerSP disasm_sp =
1335ffd83dbSDimitry Andric Disassembler::FindPluginForTarget(target, arch, flavor, plugin_name);
1349dba64beSDimitry Andric
1359dba64beSDimitry Andric if (!disasm_sp)
1369dba64beSDimitry Andric return {};
1379dba64beSDimitry Andric
1385ffd83dbSDimitry Andric const size_t bytes_disassembled = disasm_sp->ParseInstructions(
1395ffd83dbSDimitry Andric target, range.GetBaseAddress(), {Limit::Bytes, range.GetByteSize()},
140*5f7ddb14SDimitry Andric nullptr, force_live_memory);
1410b57cec5SDimitry Andric if (bytes_disassembled == 0)
1429dba64beSDimitry Andric return {};
1439dba64beSDimitry Andric
1440b57cec5SDimitry Andric return disasm_sp;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric
1470b57cec5SDimitry 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)1480b57cec5SDimitry Andric Disassembler::DisassembleBytes(const ArchSpec &arch, const char *plugin_name,
1490b57cec5SDimitry Andric const char *flavor, const Address &start,
1500b57cec5SDimitry Andric const void *src, size_t src_len,
1510b57cec5SDimitry Andric uint32_t num_instructions, bool data_from_file) {
1529dba64beSDimitry Andric if (!src)
1539dba64beSDimitry Andric return {};
1540b57cec5SDimitry Andric
1559dba64beSDimitry Andric lldb::DisassemblerSP disasm_sp =
1569dba64beSDimitry Andric Disassembler::FindPlugin(arch, flavor, plugin_name);
1570b57cec5SDimitry Andric
1589dba64beSDimitry Andric if (!disasm_sp)
1599dba64beSDimitry Andric return {};
1609dba64beSDimitry Andric
1610b57cec5SDimitry Andric DataExtractor data(src, src_len, arch.GetByteOrder(),
1620b57cec5SDimitry Andric arch.GetAddressByteSize());
1630b57cec5SDimitry Andric
1649dba64beSDimitry Andric (void)disasm_sp->DecodeInstructions(start, data, 0, num_instructions, false,
1659dba64beSDimitry Andric data_from_file);
1660b57cec5SDimitry Andric return disasm_sp;
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry 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)1690b57cec5SDimitry Andric bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
1700b57cec5SDimitry Andric const char *plugin_name, const char *flavor,
1710b57cec5SDimitry Andric const ExecutionContext &exe_ctx,
1725ffd83dbSDimitry Andric const Address &address, Limit limit,
1730b57cec5SDimitry Andric bool mixed_source_and_assembly,
1740b57cec5SDimitry Andric uint32_t num_mixed_context_lines,
1750b57cec5SDimitry Andric uint32_t options, Stream &strm) {
1765ffd83dbSDimitry Andric if (!exe_ctx.GetTargetPtr())
1779dba64beSDimitry Andric return false;
1789dba64beSDimitry Andric
1790b57cec5SDimitry Andric lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget(
1805ffd83dbSDimitry Andric exe_ctx.GetTargetRef(), arch, flavor, plugin_name));
1819dba64beSDimitry Andric if (!disasm_sp)
1829dba64beSDimitry Andric return false;
1839dba64beSDimitry Andric
184*5f7ddb14SDimitry Andric const bool force_live_memory = true;
1850b57cec5SDimitry Andric size_t bytes_disassembled = disasm_sp->ParseInstructions(
186*5f7ddb14SDimitry Andric exe_ctx.GetTargetRef(), address, limit, &strm, force_live_memory);
1870b57cec5SDimitry Andric if (bytes_disassembled == 0)
1880b57cec5SDimitry Andric return false;
1899dba64beSDimitry Andric
1905ffd83dbSDimitry Andric disasm_sp->PrintInstructions(debugger, arch, exe_ctx,
1915ffd83dbSDimitry Andric mixed_source_and_assembly,
1920b57cec5SDimitry Andric num_mixed_context_lines, options, strm);
1935ffd83dbSDimitry Andric return true;
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric
1960b57cec5SDimitry Andric Disassembler::SourceLine
GetFunctionDeclLineEntry(const SymbolContext & sc)1970b57cec5SDimitry Andric Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {
1989dba64beSDimitry Andric if (!sc.function)
1999dba64beSDimitry Andric return {};
2009dba64beSDimitry Andric
2019dba64beSDimitry Andric if (!sc.line_entry.IsValid())
2029dba64beSDimitry Andric return {};
2039dba64beSDimitry Andric
2040b57cec5SDimitry Andric LineEntry prologue_end_line = sc.line_entry;
2050b57cec5SDimitry Andric FileSpec func_decl_file;
2060b57cec5SDimitry Andric uint32_t func_decl_line;
2070b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line);
2089dba64beSDimitry Andric
2099dba64beSDimitry Andric if (func_decl_file != prologue_end_line.file &&
2109dba64beSDimitry Andric func_decl_file != prologue_end_line.original_file)
2119dba64beSDimitry Andric return {};
2129dba64beSDimitry Andric
2139dba64beSDimitry Andric SourceLine decl_line;
2140b57cec5SDimitry Andric decl_line.file = func_decl_file;
2150b57cec5SDimitry Andric decl_line.line = func_decl_line;
2169dba64beSDimitry Andric // TODO: Do we care about column on these entries? If so, we need to plumb
2179dba64beSDimitry Andric // that through GetStartLineSourceInfo.
2180b57cec5SDimitry Andric decl_line.column = 0;
2190b57cec5SDimitry Andric return decl_line;
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric
AddLineToSourceLineTables(SourceLine & line,std::map<FileSpec,std::set<uint32_t>> & source_lines_seen)2220b57cec5SDimitry Andric void Disassembler::AddLineToSourceLineTables(
2230b57cec5SDimitry Andric SourceLine &line,
2240b57cec5SDimitry Andric std::map<FileSpec, std::set<uint32_t>> &source_lines_seen) {
2250b57cec5SDimitry Andric if (line.IsValid()) {
2260b57cec5SDimitry Andric auto source_lines_seen_pos = source_lines_seen.find(line.file);
2270b57cec5SDimitry Andric if (source_lines_seen_pos == source_lines_seen.end()) {
2280b57cec5SDimitry Andric std::set<uint32_t> lines;
2290b57cec5SDimitry Andric lines.insert(line.line);
2300b57cec5SDimitry Andric source_lines_seen.emplace(line.file, lines);
2310b57cec5SDimitry Andric } else {
2320b57cec5SDimitry Andric source_lines_seen_pos->second.insert(line.line);
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric
ElideMixedSourceAndDisassemblyLine(const ExecutionContext & exe_ctx,const SymbolContext & sc,SourceLine & line)2370b57cec5SDimitry Andric bool Disassembler::ElideMixedSourceAndDisassemblyLine(
2380b57cec5SDimitry Andric const ExecutionContext &exe_ctx, const SymbolContext &sc,
2390b57cec5SDimitry Andric SourceLine &line) {
2400b57cec5SDimitry Andric
2410b57cec5SDimitry Andric // TODO: should we also check target.process.thread.step-avoid-libraries ?
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric const RegularExpression *avoid_regex = nullptr;
2440b57cec5SDimitry Andric
2450b57cec5SDimitry Andric // Skip any line #0 entries - they are implementation details
2460b57cec5SDimitry Andric if (line.line == 0)
2470b57cec5SDimitry Andric return false;
2480b57cec5SDimitry Andric
2490b57cec5SDimitry Andric ThreadSP thread_sp = exe_ctx.GetThreadSP();
2500b57cec5SDimitry Andric if (thread_sp) {
2510b57cec5SDimitry Andric avoid_regex = thread_sp->GetSymbolsToAvoidRegexp();
2520b57cec5SDimitry Andric } else {
2530b57cec5SDimitry Andric TargetSP target_sp = exe_ctx.GetTargetSP();
2540b57cec5SDimitry Andric if (target_sp) {
2550b57cec5SDimitry Andric Status error;
2560b57cec5SDimitry Andric OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue(
2570b57cec5SDimitry Andric &exe_ctx, "target.process.thread.step-avoid-regexp", false, error);
2580b57cec5SDimitry Andric if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) {
2590b57cec5SDimitry Andric OptionValueRegex *re = value_sp->GetAsRegex();
2600b57cec5SDimitry Andric if (re) {
2610b57cec5SDimitry Andric avoid_regex = re->GetCurrentValue();
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric if (avoid_regex && sc.symbol != nullptr) {
2670b57cec5SDimitry Andric const char *function_name =
2680b57cec5SDimitry Andric sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
2690b57cec5SDimitry Andric .GetCString();
2709dba64beSDimitry Andric if (function_name && avoid_regex->Execute(function_name)) {
2710b57cec5SDimitry Andric // skip this source line
2720b57cec5SDimitry Andric return true;
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric // don't skip this source line
2760b57cec5SDimitry Andric return false;
2770b57cec5SDimitry Andric }
2780b57cec5SDimitry 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)2795ffd83dbSDimitry Andric void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
2800b57cec5SDimitry Andric const ExecutionContext &exe_ctx,
2810b57cec5SDimitry Andric bool mixed_source_and_assembly,
2820b57cec5SDimitry Andric uint32_t num_mixed_context_lines,
2830b57cec5SDimitry Andric uint32_t options, Stream &strm) {
2840b57cec5SDimitry Andric // We got some things disassembled...
2855ffd83dbSDimitry Andric size_t num_instructions_found = GetInstructionList().GetSize();
2860b57cec5SDimitry Andric
2870b57cec5SDimitry Andric const uint32_t max_opcode_byte_size =
2885ffd83dbSDimitry Andric GetInstructionList().GetMaxOpcocdeByteSize();
2890b57cec5SDimitry Andric SymbolContext sc;
2900b57cec5SDimitry Andric SymbolContext prev_sc;
2910b57cec5SDimitry Andric AddressRange current_source_line_range;
2920b57cec5SDimitry Andric const Address *pc_addr_ptr = nullptr;
2930b57cec5SDimitry Andric StackFrame *frame = exe_ctx.GetFramePtr();
2940b57cec5SDimitry Andric
2950b57cec5SDimitry Andric TargetSP target_sp(exe_ctx.GetTargetSP());
2960b57cec5SDimitry Andric SourceManager &source_manager =
2970b57cec5SDimitry Andric target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
2980b57cec5SDimitry Andric
2990b57cec5SDimitry Andric if (frame) {
3000b57cec5SDimitry Andric pc_addr_ptr = &frame->GetFrameCodeAddress();
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric const uint32_t scope =
3030b57cec5SDimitry Andric eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
3040b57cec5SDimitry Andric const bool use_inline_block_range = false;
3050b57cec5SDimitry Andric
3060b57cec5SDimitry Andric const FormatEntity::Entry *disassembly_format = nullptr;
3070b57cec5SDimitry Andric FormatEntity::Entry format;
3080b57cec5SDimitry Andric if (exe_ctx.HasTargetScope()) {
3090b57cec5SDimitry Andric disassembly_format =
3100b57cec5SDimitry Andric exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat();
3110b57cec5SDimitry Andric } else {
3120b57cec5SDimitry Andric FormatEntity::Parse("${addr}: ", format);
3130b57cec5SDimitry Andric disassembly_format = &format;
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric
3160b57cec5SDimitry Andric // First pass: step through the list of instructions, find how long the
3170b57cec5SDimitry Andric // initial addresses strings are, insert padding in the second pass so the
3180b57cec5SDimitry Andric // opcodes all line up nicely.
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric // Also build up the source line mapping if this is mixed source & assembly
3210b57cec5SDimitry Andric // mode. Calculate the source line for each assembly instruction (eliding
3220b57cec5SDimitry Andric // inlined functions which the user wants to skip).
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric std::map<FileSpec, std::set<uint32_t>> source_lines_seen;
3250b57cec5SDimitry Andric Symbol *previous_symbol = nullptr;
3260b57cec5SDimitry Andric
3270b57cec5SDimitry Andric size_t address_text_size = 0;
3280b57cec5SDimitry Andric for (size_t i = 0; i < num_instructions_found; ++i) {
3295ffd83dbSDimitry Andric Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();
3300b57cec5SDimitry Andric if (inst) {
3310b57cec5SDimitry Andric const Address &addr = inst->GetAddress();
3320b57cec5SDimitry Andric ModuleSP module_sp(addr.GetModule());
3330b57cec5SDimitry Andric if (module_sp) {
3340b57cec5SDimitry Andric const SymbolContextItem resolve_mask = eSymbolContextFunction |
3350b57cec5SDimitry Andric eSymbolContextSymbol |
3360b57cec5SDimitry Andric eSymbolContextLineEntry;
3370b57cec5SDimitry Andric uint32_t resolved_mask =
3380b57cec5SDimitry Andric module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);
3390b57cec5SDimitry Andric if (resolved_mask) {
3400b57cec5SDimitry Andric StreamString strmstr;
3410b57cec5SDimitry Andric Debugger::FormatDisassemblerAddress(disassembly_format, &sc, nullptr,
3420b57cec5SDimitry Andric &exe_ctx, &addr, strmstr);
3430b57cec5SDimitry Andric size_t cur_line = strmstr.GetSizeOfLastLine();
3440b57cec5SDimitry Andric if (cur_line > address_text_size)
3450b57cec5SDimitry Andric address_text_size = cur_line;
3460b57cec5SDimitry Andric
3470b57cec5SDimitry Andric // Add entries to our "source_lines_seen" map+set which list which
3480b57cec5SDimitry Andric // sources lines occur in this disassembly session. We will print
3490b57cec5SDimitry Andric // lines of context around a source line, but we don't want to print
3500b57cec5SDimitry Andric // a source line that has a line table entry of its own - we'll leave
3510b57cec5SDimitry Andric // that source line to be printed when it actually occurs in the
3520b57cec5SDimitry Andric // disassembly.
3530b57cec5SDimitry Andric
3540b57cec5SDimitry Andric if (mixed_source_and_assembly && sc.line_entry.IsValid()) {
3550b57cec5SDimitry Andric if (sc.symbol != previous_symbol) {
3560b57cec5SDimitry Andric SourceLine decl_line = GetFunctionDeclLineEntry(sc);
3570b57cec5SDimitry Andric if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, decl_line))
3580b57cec5SDimitry Andric AddLineToSourceLineTables(decl_line, source_lines_seen);
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric if (sc.line_entry.IsValid()) {
3610b57cec5SDimitry Andric SourceLine this_line;
3620b57cec5SDimitry Andric this_line.file = sc.line_entry.file;
3630b57cec5SDimitry Andric this_line.line = sc.line_entry.line;
3640b57cec5SDimitry Andric this_line.column = sc.line_entry.column;
3650b57cec5SDimitry Andric if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line))
3660b57cec5SDimitry Andric AddLineToSourceLineTables(this_line, source_lines_seen);
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric sc.Clear(false);
3710b57cec5SDimitry Andric }
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric }
3740b57cec5SDimitry Andric
3750b57cec5SDimitry Andric previous_symbol = nullptr;
3760b57cec5SDimitry Andric SourceLine previous_line;
3770b57cec5SDimitry Andric for (size_t i = 0; i < num_instructions_found; ++i) {
3785ffd83dbSDimitry Andric Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();
3790b57cec5SDimitry Andric
3800b57cec5SDimitry Andric if (inst) {
3810b57cec5SDimitry Andric const Address &addr = inst->GetAddress();
3820b57cec5SDimitry Andric const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;
3830b57cec5SDimitry Andric SourceLinesToDisplay source_lines_to_display;
3840b57cec5SDimitry Andric
3850b57cec5SDimitry Andric prev_sc = sc;
3860b57cec5SDimitry Andric
3870b57cec5SDimitry Andric ModuleSP module_sp(addr.GetModule());
3880b57cec5SDimitry Andric if (module_sp) {
3890b57cec5SDimitry Andric uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(
3900b57cec5SDimitry Andric addr, eSymbolContextEverything, sc);
3910b57cec5SDimitry Andric if (resolved_mask) {
3920b57cec5SDimitry Andric if (mixed_source_and_assembly) {
3930b57cec5SDimitry Andric
3940b57cec5SDimitry Andric // If we've started a new function (non-inlined), print all of the
3950b57cec5SDimitry Andric // source lines from the function declaration until the first line
3960b57cec5SDimitry Andric // table entry - typically the opening curly brace of the function.
3970b57cec5SDimitry Andric if (previous_symbol != sc.symbol) {
3980b57cec5SDimitry Andric // The default disassembly format puts an extra blank line
3990b57cec5SDimitry Andric // between functions - so when we're displaying the source
4000b57cec5SDimitry Andric // context for a function, we don't want to add a blank line
4010b57cec5SDimitry Andric // after the source context or we'll end up with two of them.
4020b57cec5SDimitry Andric if (previous_symbol != nullptr)
4030b57cec5SDimitry Andric source_lines_to_display.print_source_context_end_eol = false;
4040b57cec5SDimitry Andric
4050b57cec5SDimitry Andric previous_symbol = sc.symbol;
4060b57cec5SDimitry Andric if (sc.function && sc.line_entry.IsValid()) {
4070b57cec5SDimitry Andric LineEntry prologue_end_line = sc.line_entry;
4080b57cec5SDimitry Andric if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
4090b57cec5SDimitry Andric prologue_end_line)) {
4100b57cec5SDimitry Andric FileSpec func_decl_file;
4110b57cec5SDimitry Andric uint32_t func_decl_line;
4120b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(func_decl_file,
4130b57cec5SDimitry Andric func_decl_line);
4140b57cec5SDimitry Andric if (func_decl_file == prologue_end_line.file ||
4150b57cec5SDimitry Andric func_decl_file == prologue_end_line.original_file) {
4160b57cec5SDimitry Andric // Add all the lines between the function declaration and
4170b57cec5SDimitry Andric // the first non-prologue source line to the list of lines
4180b57cec5SDimitry Andric // to print.
4190b57cec5SDimitry Andric for (uint32_t lineno = func_decl_line;
4200b57cec5SDimitry Andric lineno <= prologue_end_line.line; lineno++) {
4210b57cec5SDimitry Andric SourceLine this_line;
4220b57cec5SDimitry Andric this_line.file = func_decl_file;
4230b57cec5SDimitry Andric this_line.line = lineno;
4240b57cec5SDimitry Andric source_lines_to_display.lines.push_back(this_line);
4250b57cec5SDimitry Andric }
4260b57cec5SDimitry Andric // Mark the last line as the "current" one. Usually this
4270b57cec5SDimitry Andric // is the open curly brace.
4280b57cec5SDimitry Andric if (source_lines_to_display.lines.size() > 0)
4290b57cec5SDimitry Andric source_lines_to_display.current_source_line =
4300b57cec5SDimitry Andric source_lines_to_display.lines.size() - 1;
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric }
4330b57cec5SDimitry Andric }
4340b57cec5SDimitry Andric sc.GetAddressRange(scope, 0, use_inline_block_range,
4350b57cec5SDimitry Andric current_source_line_range);
4360b57cec5SDimitry Andric }
4370b57cec5SDimitry Andric
4380b57cec5SDimitry Andric // If we've left a previous source line's address range, print a
4390b57cec5SDimitry Andric // new source line
4400b57cec5SDimitry Andric if (!current_source_line_range.ContainsFileAddress(addr)) {
4410b57cec5SDimitry Andric sc.GetAddressRange(scope, 0, use_inline_block_range,
4420b57cec5SDimitry Andric current_source_line_range);
4430b57cec5SDimitry Andric
4440b57cec5SDimitry Andric if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) {
4450b57cec5SDimitry Andric SourceLine this_line;
4460b57cec5SDimitry Andric this_line.file = sc.line_entry.file;
4470b57cec5SDimitry Andric this_line.line = sc.line_entry.line;
4480b57cec5SDimitry Andric
4490b57cec5SDimitry Andric if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
4500b57cec5SDimitry Andric this_line)) {
4510b57cec5SDimitry Andric // Only print this source line if it is different from the
4520b57cec5SDimitry Andric // last source line we printed. There may have been inlined
4530b57cec5SDimitry Andric // functions between these lines that we elided, resulting in
4540b57cec5SDimitry Andric // the same line being printed twice in a row for a
4550b57cec5SDimitry Andric // contiguous block of assembly instructions.
4560b57cec5SDimitry Andric if (this_line != previous_line) {
4570b57cec5SDimitry Andric
4580b57cec5SDimitry Andric std::vector<uint32_t> previous_lines;
4590b57cec5SDimitry Andric for (uint32_t i = 0;
4600b57cec5SDimitry Andric i < num_mixed_context_lines &&
4610b57cec5SDimitry Andric (this_line.line - num_mixed_context_lines) > 0;
4620b57cec5SDimitry Andric i++) {
4630b57cec5SDimitry Andric uint32_t line =
4640b57cec5SDimitry Andric this_line.line - num_mixed_context_lines + i;
4650b57cec5SDimitry Andric auto pos = source_lines_seen.find(this_line.file);
4660b57cec5SDimitry Andric if (pos != source_lines_seen.end()) {
4670b57cec5SDimitry Andric if (pos->second.count(line) == 1) {
4680b57cec5SDimitry Andric previous_lines.clear();
4690b57cec5SDimitry Andric } else {
4700b57cec5SDimitry Andric previous_lines.push_back(line);
4710b57cec5SDimitry Andric }
4720b57cec5SDimitry Andric }
4730b57cec5SDimitry Andric }
4740b57cec5SDimitry Andric for (size_t i = 0; i < previous_lines.size(); i++) {
4750b57cec5SDimitry Andric SourceLine previous_line;
4760b57cec5SDimitry Andric previous_line.file = this_line.file;
4770b57cec5SDimitry Andric previous_line.line = previous_lines[i];
4780b57cec5SDimitry Andric auto pos = source_lines_seen.find(previous_line.file);
4790b57cec5SDimitry Andric if (pos != source_lines_seen.end()) {
4800b57cec5SDimitry Andric pos->second.insert(previous_line.line);
4810b57cec5SDimitry Andric }
4820b57cec5SDimitry Andric source_lines_to_display.lines.push_back(previous_line);
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric
4850b57cec5SDimitry Andric source_lines_to_display.lines.push_back(this_line);
4860b57cec5SDimitry Andric source_lines_to_display.current_source_line =
4870b57cec5SDimitry Andric source_lines_to_display.lines.size() - 1;
4880b57cec5SDimitry Andric
4890b57cec5SDimitry Andric for (uint32_t i = 0; i < num_mixed_context_lines; i++) {
4900b57cec5SDimitry Andric SourceLine next_line;
4910b57cec5SDimitry Andric next_line.file = this_line.file;
4920b57cec5SDimitry Andric next_line.line = this_line.line + i + 1;
4930b57cec5SDimitry Andric auto pos = source_lines_seen.find(next_line.file);
4940b57cec5SDimitry Andric if (pos != source_lines_seen.end()) {
4950b57cec5SDimitry Andric if (pos->second.count(next_line.line) == 1)
4960b57cec5SDimitry Andric break;
4970b57cec5SDimitry Andric pos->second.insert(next_line.line);
4980b57cec5SDimitry Andric }
4990b57cec5SDimitry Andric source_lines_to_display.lines.push_back(next_line);
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric }
5020b57cec5SDimitry Andric previous_line = this_line;
5030b57cec5SDimitry Andric }
5040b57cec5SDimitry Andric }
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric }
5070b57cec5SDimitry Andric } else {
5080b57cec5SDimitry Andric sc.Clear(true);
5090b57cec5SDimitry Andric }
5100b57cec5SDimitry Andric }
5110b57cec5SDimitry Andric
5120b57cec5SDimitry Andric if (source_lines_to_display.lines.size() > 0) {
5130b57cec5SDimitry Andric strm.EOL();
5140b57cec5SDimitry Andric for (size_t idx = 0; idx < source_lines_to_display.lines.size();
5150b57cec5SDimitry Andric idx++) {
5160b57cec5SDimitry Andric SourceLine ln = source_lines_to_display.lines[idx];
5170b57cec5SDimitry Andric const char *line_highlight = "";
5180b57cec5SDimitry Andric if (inst_is_at_pc && (options & eOptionMarkPCSourceLine)) {
5190b57cec5SDimitry Andric line_highlight = "->";
5200b57cec5SDimitry Andric } else if (idx == source_lines_to_display.current_source_line) {
5210b57cec5SDimitry Andric line_highlight = "**";
5220b57cec5SDimitry Andric }
5230b57cec5SDimitry Andric source_manager.DisplaySourceLinesWithLineNumbers(
5240b57cec5SDimitry Andric ln.file, ln.line, ln.column, 0, 0, line_highlight, &strm);
5250b57cec5SDimitry Andric }
5260b57cec5SDimitry Andric if (source_lines_to_display.print_source_context_end_eol)
5270b57cec5SDimitry Andric strm.EOL();
5280b57cec5SDimitry Andric }
5290b57cec5SDimitry Andric
5300b57cec5SDimitry Andric const bool show_bytes = (options & eOptionShowBytes) != 0;
5310b57cec5SDimitry Andric inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc,
5320b57cec5SDimitry Andric &prev_sc, nullptr, address_text_size);
5330b57cec5SDimitry Andric strm.EOL();
5340b57cec5SDimitry Andric } else {
5350b57cec5SDimitry Andric break;
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric }
5390b57cec5SDimitry Andric
Disassemble(Debugger & debugger,const ArchSpec & arch,StackFrame & frame,Stream & strm)5400b57cec5SDimitry Andric bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
541af732203SDimitry Andric StackFrame &frame, Stream &strm) {
5420b57cec5SDimitry Andric AddressRange range;
5430b57cec5SDimitry Andric SymbolContext sc(
544af732203SDimitry Andric frame.GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
5450b57cec5SDimitry Andric if (sc.function) {
5460b57cec5SDimitry Andric range = sc.function->GetAddressRange();
5470b57cec5SDimitry Andric } else if (sc.symbol && sc.symbol->ValueIsAddress()) {
5480b57cec5SDimitry Andric range.GetBaseAddress() = sc.symbol->GetAddressRef();
5490b57cec5SDimitry Andric range.SetByteSize(sc.symbol->GetByteSize());
5500b57cec5SDimitry Andric } else {
551af732203SDimitry Andric range.GetBaseAddress() = frame.GetFrameCodeAddress();
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric
5540b57cec5SDimitry Andric if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
5550b57cec5SDimitry Andric range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
5560b57cec5SDimitry Andric
557af732203SDimitry Andric Disassembler::Limit limit = {Disassembler::Limit::Bytes,
558af732203SDimitry Andric range.GetByteSize()};
559af732203SDimitry Andric if (limit.value == 0)
560af732203SDimitry Andric limit.value = DEFAULT_DISASM_BYTE_SIZE;
561af732203SDimitry Andric
562af732203SDimitry Andric return Disassemble(debugger, arch, nullptr, nullptr, frame,
563af732203SDimitry Andric range.GetBaseAddress(), limit, false, 0, 0, strm);
5640b57cec5SDimitry Andric }
5650b57cec5SDimitry Andric
Instruction(const Address & address,AddressClass addr_class)5660b57cec5SDimitry Andric Instruction::Instruction(const Address &address, AddressClass addr_class)
5670b57cec5SDimitry Andric : m_address(address), m_address_class(addr_class), m_opcode(),
5680b57cec5SDimitry Andric m_calculated_strings(false) {}
5690b57cec5SDimitry Andric
5700b57cec5SDimitry Andric Instruction::~Instruction() = default;
5710b57cec5SDimitry Andric
GetAddressClass()5720b57cec5SDimitry Andric AddressClass Instruction::GetAddressClass() {
5730b57cec5SDimitry Andric if (m_address_class == AddressClass::eInvalid)
5740b57cec5SDimitry Andric m_address_class = m_address.GetAddressClass();
5750b57cec5SDimitry Andric return m_address_class;
5760b57cec5SDimitry Andric }
5770b57cec5SDimitry Andric
Dump(lldb_private::Stream * s,uint32_t max_opcode_byte_size,bool show_address,bool show_bytes,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)5780b57cec5SDimitry Andric void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
5790b57cec5SDimitry Andric bool show_address, bool show_bytes,
5800b57cec5SDimitry Andric const ExecutionContext *exe_ctx,
5810b57cec5SDimitry Andric const SymbolContext *sym_ctx,
5820b57cec5SDimitry Andric const SymbolContext *prev_sym_ctx,
5830b57cec5SDimitry Andric const FormatEntity::Entry *disassembly_addr_format,
5840b57cec5SDimitry Andric size_t max_address_text_size) {
5850b57cec5SDimitry Andric size_t opcode_column_width = 7;
5860b57cec5SDimitry Andric const size_t operand_column_width = 25;
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx);
5890b57cec5SDimitry Andric
5900b57cec5SDimitry Andric StreamString ss;
5910b57cec5SDimitry Andric
5920b57cec5SDimitry Andric if (show_address) {
5930b57cec5SDimitry Andric Debugger::FormatDisassemblerAddress(disassembly_addr_format, sym_ctx,
5940b57cec5SDimitry Andric prev_sym_ctx, exe_ctx, &m_address, ss);
5950b57cec5SDimitry Andric ss.FillLastLineToColumn(max_address_text_size, ' ');
5960b57cec5SDimitry Andric }
5970b57cec5SDimitry Andric
5980b57cec5SDimitry Andric if (show_bytes) {
5990b57cec5SDimitry Andric if (m_opcode.GetType() == Opcode::eTypeBytes) {
6000b57cec5SDimitry Andric // x86_64 and i386 are the only ones that use bytes right now so pad out
6010b57cec5SDimitry Andric // the byte dump to be able to always show 15 bytes (3 chars each) plus a
6020b57cec5SDimitry Andric // space
6030b57cec5SDimitry Andric if (max_opcode_byte_size > 0)
6040b57cec5SDimitry Andric m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
6050b57cec5SDimitry Andric else
6060b57cec5SDimitry Andric m_opcode.Dump(&ss, 15 * 3 + 1);
6070b57cec5SDimitry Andric } else {
6080b57cec5SDimitry Andric // Else, we have ARM or MIPS which can show up to a uint32_t 0x00000000
6090b57cec5SDimitry Andric // (10 spaces) plus two for padding...
6100b57cec5SDimitry Andric if (max_opcode_byte_size > 0)
6110b57cec5SDimitry Andric m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
6120b57cec5SDimitry Andric else
6130b57cec5SDimitry Andric m_opcode.Dump(&ss, 12);
6140b57cec5SDimitry Andric }
6150b57cec5SDimitry Andric }
6160b57cec5SDimitry Andric
6170b57cec5SDimitry Andric const size_t opcode_pos = ss.GetSizeOfLastLine();
6180b57cec5SDimitry Andric
6190b57cec5SDimitry Andric // The default opcode size of 7 characters is plenty for most architectures
6200b57cec5SDimitry Andric // but some like arm can pull out the occasional vqrshrun.s16. We won't get
6210b57cec5SDimitry Andric // consistent column spacing in these cases, unfortunately.
6220b57cec5SDimitry Andric if (m_opcode_name.length() >= opcode_column_width) {
6230b57cec5SDimitry Andric opcode_column_width = m_opcode_name.length() + 1;
6240b57cec5SDimitry Andric }
6250b57cec5SDimitry Andric
6260b57cec5SDimitry Andric ss.PutCString(m_opcode_name);
6270b57cec5SDimitry Andric ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
6280b57cec5SDimitry Andric ss.PutCString(m_mnemonics);
6290b57cec5SDimitry Andric
6300b57cec5SDimitry Andric if (!m_comment.empty()) {
6310b57cec5SDimitry Andric ss.FillLastLineToColumn(
6320b57cec5SDimitry Andric opcode_pos + opcode_column_width + operand_column_width, ' ');
6330b57cec5SDimitry Andric ss.PutCString(" ; ");
6340b57cec5SDimitry Andric ss.PutCString(m_comment);
6350b57cec5SDimitry Andric }
6360b57cec5SDimitry Andric s->PutCString(ss.GetString());
6370b57cec5SDimitry Andric }
6380b57cec5SDimitry Andric
DumpEmulation(const ArchSpec & arch)6390b57cec5SDimitry Andric bool Instruction::DumpEmulation(const ArchSpec &arch) {
6400b57cec5SDimitry Andric std::unique_ptr<EmulateInstruction> insn_emulator_up(
6410b57cec5SDimitry Andric EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
6420b57cec5SDimitry Andric if (insn_emulator_up) {
6430b57cec5SDimitry Andric insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);
6440b57cec5SDimitry Andric return insn_emulator_up->EvaluateInstruction(0);
6450b57cec5SDimitry Andric }
6460b57cec5SDimitry Andric
6470b57cec5SDimitry Andric return false;
6480b57cec5SDimitry Andric }
6490b57cec5SDimitry Andric
CanSetBreakpoint()6500b57cec5SDimitry Andric bool Instruction::CanSetBreakpoint () {
6510b57cec5SDimitry Andric return !HasDelaySlot();
6520b57cec5SDimitry Andric }
6530b57cec5SDimitry Andric
HasDelaySlot()6540b57cec5SDimitry Andric bool Instruction::HasDelaySlot() {
6550b57cec5SDimitry Andric // Default is false.
6560b57cec5SDimitry Andric return false;
6570b57cec5SDimitry Andric }
6580b57cec5SDimitry Andric
ReadArray(FILE * in_file,Stream * out_stream,OptionValue::Type data_type)6590b57cec5SDimitry Andric OptionValueSP Instruction::ReadArray(FILE *in_file, Stream *out_stream,
6600b57cec5SDimitry Andric OptionValue::Type data_type) {
6610b57cec5SDimitry Andric bool done = false;
6620b57cec5SDimitry Andric char buffer[1024];
6630b57cec5SDimitry Andric
6640b57cec5SDimitry Andric auto option_value_sp = std::make_shared<OptionValueArray>(1u << data_type);
6650b57cec5SDimitry Andric
6660b57cec5SDimitry Andric int idx = 0;
6670b57cec5SDimitry Andric while (!done) {
6680b57cec5SDimitry Andric if (!fgets(buffer, 1023, in_file)) {
6690b57cec5SDimitry Andric out_stream->Printf(
6700b57cec5SDimitry Andric "Instruction::ReadArray: Error reading file (fgets).\n");
6710b57cec5SDimitry Andric option_value_sp.reset();
6720b57cec5SDimitry Andric return option_value_sp;
6730b57cec5SDimitry Andric }
6740b57cec5SDimitry Andric
6750b57cec5SDimitry Andric std::string line(buffer);
6760b57cec5SDimitry Andric
6770b57cec5SDimitry Andric size_t len = line.size();
6780b57cec5SDimitry Andric if (line[len - 1] == '\n') {
6790b57cec5SDimitry Andric line[len - 1] = '\0';
6800b57cec5SDimitry Andric line.resize(len - 1);
6810b57cec5SDimitry Andric }
6820b57cec5SDimitry Andric
6830b57cec5SDimitry Andric if ((line.size() == 1) && line[0] == ']') {
6840b57cec5SDimitry Andric done = true;
6850b57cec5SDimitry Andric line.clear();
6860b57cec5SDimitry Andric }
6870b57cec5SDimitry Andric
6880b57cec5SDimitry Andric if (!line.empty()) {
6890b57cec5SDimitry Andric std::string value;
6900b57cec5SDimitry Andric static RegularExpression g_reg_exp(
6910b57cec5SDimitry Andric llvm::StringRef("^[ \t]*([^ \t]+)[ \t]*$"));
6929dba64beSDimitry Andric llvm::SmallVector<llvm::StringRef, 2> matches;
6939dba64beSDimitry Andric if (g_reg_exp.Execute(line, &matches))
6949dba64beSDimitry Andric value = matches[1].str();
6950b57cec5SDimitry Andric else
6960b57cec5SDimitry Andric value = line;
6970b57cec5SDimitry Andric
6980b57cec5SDimitry Andric OptionValueSP data_value_sp;
6990b57cec5SDimitry Andric switch (data_type) {
7000b57cec5SDimitry Andric case OptionValue::eTypeUInt64:
7010b57cec5SDimitry Andric data_value_sp = std::make_shared<OptionValueUInt64>(0, 0);
7020b57cec5SDimitry Andric data_value_sp->SetValueFromString(value);
7030b57cec5SDimitry Andric break;
7040b57cec5SDimitry Andric // Other types can be added later as needed.
7050b57cec5SDimitry Andric default:
7060b57cec5SDimitry Andric data_value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
7070b57cec5SDimitry Andric break;
7080b57cec5SDimitry Andric }
7090b57cec5SDimitry Andric
7100b57cec5SDimitry Andric option_value_sp->GetAsArray()->InsertValue(idx, data_value_sp);
7110b57cec5SDimitry Andric ++idx;
7120b57cec5SDimitry Andric }
7130b57cec5SDimitry Andric }
7140b57cec5SDimitry Andric
7150b57cec5SDimitry Andric return option_value_sp;
7160b57cec5SDimitry Andric }
7170b57cec5SDimitry Andric
ReadDictionary(FILE * in_file,Stream * out_stream)7180b57cec5SDimitry Andric OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream *out_stream) {
7190b57cec5SDimitry Andric bool done = false;
7200b57cec5SDimitry Andric char buffer[1024];
7210b57cec5SDimitry Andric
7220b57cec5SDimitry Andric auto option_value_sp = std::make_shared<OptionValueDictionary>();
7230b57cec5SDimitry Andric static ConstString encoding_key("data_encoding");
7240b57cec5SDimitry Andric OptionValue::Type data_type = OptionValue::eTypeInvalid;
7250b57cec5SDimitry Andric
7260b57cec5SDimitry Andric while (!done) {
7270b57cec5SDimitry Andric // Read the next line in the file
7280b57cec5SDimitry Andric if (!fgets(buffer, 1023, in_file)) {
7290b57cec5SDimitry Andric out_stream->Printf(
7300b57cec5SDimitry Andric "Instruction::ReadDictionary: Error reading file (fgets).\n");
7310b57cec5SDimitry Andric option_value_sp.reset();
7320b57cec5SDimitry Andric return option_value_sp;
7330b57cec5SDimitry Andric }
7340b57cec5SDimitry Andric
7350b57cec5SDimitry Andric // Check to see if the line contains the end-of-dictionary marker ("}")
7360b57cec5SDimitry Andric std::string line(buffer);
7370b57cec5SDimitry Andric
7380b57cec5SDimitry Andric size_t len = line.size();
7390b57cec5SDimitry Andric if (line[len - 1] == '\n') {
7400b57cec5SDimitry Andric line[len - 1] = '\0';
7410b57cec5SDimitry Andric line.resize(len - 1);
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric
7440b57cec5SDimitry Andric if ((line.size() == 1) && (line[0] == '}')) {
7450b57cec5SDimitry Andric done = true;
7460b57cec5SDimitry Andric line.clear();
7470b57cec5SDimitry Andric }
7480b57cec5SDimitry Andric
7490b57cec5SDimitry Andric // Try to find a key-value pair in the current line and add it to the
7500b57cec5SDimitry Andric // dictionary.
7510b57cec5SDimitry Andric if (!line.empty()) {
7520b57cec5SDimitry Andric static RegularExpression g_reg_exp(llvm::StringRef(
7530b57cec5SDimitry Andric "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$"));
7540b57cec5SDimitry Andric
7559dba64beSDimitry Andric llvm::SmallVector<llvm::StringRef, 3> matches;
7569dba64beSDimitry Andric
7579dba64beSDimitry Andric bool reg_exp_success = g_reg_exp.Execute(line, &matches);
7580b57cec5SDimitry Andric std::string key;
7590b57cec5SDimitry Andric std::string value;
7600b57cec5SDimitry Andric if (reg_exp_success) {
7619dba64beSDimitry Andric key = matches[1].str();
7629dba64beSDimitry Andric value = matches[2].str();
7630b57cec5SDimitry Andric } else {
7640b57cec5SDimitry Andric out_stream->Printf("Instruction::ReadDictionary: Failure executing "
7650b57cec5SDimitry Andric "regular expression.\n");
7660b57cec5SDimitry Andric option_value_sp.reset();
7670b57cec5SDimitry Andric return option_value_sp;
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric
7700b57cec5SDimitry Andric ConstString const_key(key.c_str());
7710b57cec5SDimitry Andric // Check value to see if it's the start of an array or dictionary.
7720b57cec5SDimitry Andric
7730b57cec5SDimitry Andric lldb::OptionValueSP value_sp;
7740b57cec5SDimitry Andric assert(value.empty() == false);
7750b57cec5SDimitry Andric assert(key.empty() == false);
7760b57cec5SDimitry Andric
7770b57cec5SDimitry Andric if (value[0] == '{') {
7780b57cec5SDimitry Andric assert(value.size() == 1);
7790b57cec5SDimitry Andric // value is a dictionary
7800b57cec5SDimitry Andric value_sp = ReadDictionary(in_file, out_stream);
7810b57cec5SDimitry Andric if (!value_sp) {
7820b57cec5SDimitry Andric option_value_sp.reset();
7830b57cec5SDimitry Andric return option_value_sp;
7840b57cec5SDimitry Andric }
7850b57cec5SDimitry Andric } else if (value[0] == '[') {
7860b57cec5SDimitry Andric assert(value.size() == 1);
7870b57cec5SDimitry Andric // value is an array
7880b57cec5SDimitry Andric value_sp = ReadArray(in_file, out_stream, data_type);
7890b57cec5SDimitry Andric if (!value_sp) {
7900b57cec5SDimitry Andric option_value_sp.reset();
7910b57cec5SDimitry Andric return option_value_sp;
7920b57cec5SDimitry Andric }
7930b57cec5SDimitry Andric // We've used the data_type to read an array; re-set the type to
7940b57cec5SDimitry Andric // Invalid
7950b57cec5SDimitry Andric data_type = OptionValue::eTypeInvalid;
7960b57cec5SDimitry Andric } else if ((value[0] == '0') && (value[1] == 'x')) {
7970b57cec5SDimitry Andric value_sp = std::make_shared<OptionValueUInt64>(0, 0);
7980b57cec5SDimitry Andric value_sp->SetValueFromString(value);
7990b57cec5SDimitry Andric } else {
8000b57cec5SDimitry Andric size_t len = value.size();
8010b57cec5SDimitry Andric if ((value[0] == '"') && (value[len - 1] == '"'))
8020b57cec5SDimitry Andric value = value.substr(1, len - 2);
8030b57cec5SDimitry Andric value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
8040b57cec5SDimitry Andric }
8050b57cec5SDimitry Andric
8060b57cec5SDimitry Andric if (const_key == encoding_key) {
8070b57cec5SDimitry Andric // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data
8080b57cec5SDimitry Andric // indicating the
8090b57cec5SDimitry Andric // data type of an upcoming array (usually the next bit of data to be
8100b57cec5SDimitry Andric // read in).
8110b57cec5SDimitry Andric if (strcmp(value.c_str(), "uint32_t") == 0)
8120b57cec5SDimitry Andric data_type = OptionValue::eTypeUInt64;
8130b57cec5SDimitry Andric } else
8140b57cec5SDimitry Andric option_value_sp->GetAsDictionary()->SetValueForKey(const_key, value_sp,
8150b57cec5SDimitry Andric false);
8160b57cec5SDimitry Andric }
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric
8190b57cec5SDimitry Andric return option_value_sp;
8200b57cec5SDimitry Andric }
8210b57cec5SDimitry Andric
TestEmulation(Stream * out_stream,const char * file_name)8220b57cec5SDimitry Andric bool Instruction::TestEmulation(Stream *out_stream, const char *file_name) {
8230b57cec5SDimitry Andric if (!out_stream)
8240b57cec5SDimitry Andric return false;
8250b57cec5SDimitry Andric
8260b57cec5SDimitry Andric if (!file_name) {
8270b57cec5SDimitry Andric out_stream->Printf("Instruction::TestEmulation: Missing file_name.");
8280b57cec5SDimitry Andric return false;
8290b57cec5SDimitry Andric }
8300b57cec5SDimitry Andric FILE *test_file = FileSystem::Instance().Fopen(file_name, "r");
8310b57cec5SDimitry Andric if (!test_file) {
8320b57cec5SDimitry Andric out_stream->Printf(
8330b57cec5SDimitry Andric "Instruction::TestEmulation: Attempt to open test file failed.");
8340b57cec5SDimitry Andric return false;
8350b57cec5SDimitry Andric }
8360b57cec5SDimitry Andric
8370b57cec5SDimitry Andric char buffer[256];
8380b57cec5SDimitry Andric if (!fgets(buffer, 255, test_file)) {
8390b57cec5SDimitry Andric out_stream->Printf(
8400b57cec5SDimitry Andric "Instruction::TestEmulation: Error reading first line of test file.\n");
8410b57cec5SDimitry Andric fclose(test_file);
8420b57cec5SDimitry Andric return false;
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric
8450b57cec5SDimitry Andric if (strncmp(buffer, "InstructionEmulationState={", 27) != 0) {
8460b57cec5SDimitry Andric out_stream->Printf("Instructin::TestEmulation: Test file does not contain "
8470b57cec5SDimitry Andric "emulation state dictionary\n");
8480b57cec5SDimitry Andric fclose(test_file);
8490b57cec5SDimitry Andric return false;
8500b57cec5SDimitry Andric }
8510b57cec5SDimitry Andric
8520b57cec5SDimitry Andric // Read all the test information from the test file into an
8530b57cec5SDimitry Andric // OptionValueDictionary.
8540b57cec5SDimitry Andric
8550b57cec5SDimitry Andric OptionValueSP data_dictionary_sp(ReadDictionary(test_file, out_stream));
8560b57cec5SDimitry Andric if (!data_dictionary_sp) {
8570b57cec5SDimitry Andric out_stream->Printf(
8580b57cec5SDimitry Andric "Instruction::TestEmulation: Error reading Dictionary Object.\n");
8590b57cec5SDimitry Andric fclose(test_file);
8600b57cec5SDimitry Andric return false;
8610b57cec5SDimitry Andric }
8620b57cec5SDimitry Andric
8630b57cec5SDimitry Andric fclose(test_file);
8640b57cec5SDimitry Andric
8650b57cec5SDimitry Andric OptionValueDictionary *data_dictionary =
8660b57cec5SDimitry Andric data_dictionary_sp->GetAsDictionary();
8670b57cec5SDimitry Andric static ConstString description_key("assembly_string");
8680b57cec5SDimitry Andric static ConstString triple_key("triple");
8690b57cec5SDimitry Andric
8700b57cec5SDimitry Andric OptionValueSP value_sp = data_dictionary->GetValueForKey(description_key);
8710b57cec5SDimitry Andric
8720b57cec5SDimitry Andric if (!value_sp) {
8730b57cec5SDimitry Andric out_stream->Printf("Instruction::TestEmulation: Test file does not "
8740b57cec5SDimitry Andric "contain description string.\n");
8750b57cec5SDimitry Andric return false;
8760b57cec5SDimitry Andric }
8770b57cec5SDimitry Andric
8780b57cec5SDimitry Andric SetDescription(value_sp->GetStringValue());
8790b57cec5SDimitry Andric
8800b57cec5SDimitry Andric value_sp = data_dictionary->GetValueForKey(triple_key);
8810b57cec5SDimitry Andric if (!value_sp) {
8820b57cec5SDimitry Andric out_stream->Printf(
8830b57cec5SDimitry Andric "Instruction::TestEmulation: Test file does not contain triple.\n");
8840b57cec5SDimitry Andric return false;
8850b57cec5SDimitry Andric }
8860b57cec5SDimitry Andric
8870b57cec5SDimitry Andric ArchSpec arch;
8880b57cec5SDimitry Andric arch.SetTriple(llvm::Triple(value_sp->GetStringValue()));
8890b57cec5SDimitry Andric
8900b57cec5SDimitry Andric bool success = false;
8910b57cec5SDimitry Andric std::unique_ptr<EmulateInstruction> insn_emulator_up(
8920b57cec5SDimitry Andric EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
8930b57cec5SDimitry Andric if (insn_emulator_up)
8940b57cec5SDimitry Andric success =
8950b57cec5SDimitry Andric insn_emulator_up->TestEmulation(out_stream, arch, data_dictionary);
8960b57cec5SDimitry Andric
8970b57cec5SDimitry Andric if (success)
8980b57cec5SDimitry Andric out_stream->Printf("Emulation test succeeded.");
8990b57cec5SDimitry Andric else
9000b57cec5SDimitry Andric out_stream->Printf("Emulation test failed.");
9010b57cec5SDimitry Andric
9020b57cec5SDimitry Andric return success;
9030b57cec5SDimitry Andric }
9040b57cec5SDimitry 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)9050b57cec5SDimitry Andric bool Instruction::Emulate(
9060b57cec5SDimitry Andric const ArchSpec &arch, uint32_t evaluate_options, void *baton,
9070b57cec5SDimitry Andric EmulateInstruction::ReadMemoryCallback read_mem_callback,
9080b57cec5SDimitry Andric EmulateInstruction::WriteMemoryCallback write_mem_callback,
9090b57cec5SDimitry Andric EmulateInstruction::ReadRegisterCallback read_reg_callback,
9100b57cec5SDimitry Andric EmulateInstruction::WriteRegisterCallback write_reg_callback) {
9110b57cec5SDimitry Andric std::unique_ptr<EmulateInstruction> insn_emulator_up(
9120b57cec5SDimitry Andric EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
9130b57cec5SDimitry Andric if (insn_emulator_up) {
9140b57cec5SDimitry Andric insn_emulator_up->SetBaton(baton);
9150b57cec5SDimitry Andric insn_emulator_up->SetCallbacks(read_mem_callback, write_mem_callback,
9160b57cec5SDimitry Andric read_reg_callback, write_reg_callback);
9170b57cec5SDimitry Andric insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);
9180b57cec5SDimitry Andric return insn_emulator_up->EvaluateInstruction(evaluate_options);
9190b57cec5SDimitry Andric }
9200b57cec5SDimitry Andric
9210b57cec5SDimitry Andric return false;
9220b57cec5SDimitry Andric }
9230b57cec5SDimitry Andric
GetData(DataExtractor & data)9240b57cec5SDimitry Andric uint32_t Instruction::GetData(DataExtractor &data) {
9250b57cec5SDimitry Andric return m_opcode.GetData(data);
9260b57cec5SDimitry Andric }
9270b57cec5SDimitry Andric
InstructionList()9280b57cec5SDimitry Andric InstructionList::InstructionList() : m_instructions() {}
9290b57cec5SDimitry Andric
9300b57cec5SDimitry Andric InstructionList::~InstructionList() = default;
9310b57cec5SDimitry Andric
GetSize() const9320b57cec5SDimitry Andric size_t InstructionList::GetSize() const { return m_instructions.size(); }
9330b57cec5SDimitry Andric
GetMaxOpcocdeByteSize() const9340b57cec5SDimitry Andric uint32_t InstructionList::GetMaxOpcocdeByteSize() const {
9350b57cec5SDimitry Andric uint32_t max_inst_size = 0;
9360b57cec5SDimitry Andric collection::const_iterator pos, end;
9370b57cec5SDimitry Andric for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end;
9380b57cec5SDimitry Andric ++pos) {
9390b57cec5SDimitry Andric uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();
9400b57cec5SDimitry Andric if (max_inst_size < inst_size)
9410b57cec5SDimitry Andric max_inst_size = inst_size;
9420b57cec5SDimitry Andric }
9430b57cec5SDimitry Andric return max_inst_size;
9440b57cec5SDimitry Andric }
9450b57cec5SDimitry Andric
GetInstructionAtIndex(size_t idx) const9460b57cec5SDimitry Andric InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const {
9470b57cec5SDimitry Andric InstructionSP inst_sp;
9480b57cec5SDimitry Andric if (idx < m_instructions.size())
9490b57cec5SDimitry Andric inst_sp = m_instructions[idx];
9500b57cec5SDimitry Andric return inst_sp;
9510b57cec5SDimitry Andric }
9520b57cec5SDimitry Andric
GetInstructionAtAddress(const Address & address)953af732203SDimitry Andric InstructionSP InstructionList::GetInstructionAtAddress(const Address &address) {
954af732203SDimitry Andric uint32_t index = GetIndexOfInstructionAtAddress(address);
955af732203SDimitry Andric if (index != UINT32_MAX)
956af732203SDimitry Andric return GetInstructionAtIndex(index);
957af732203SDimitry Andric return nullptr;
958af732203SDimitry Andric }
959af732203SDimitry Andric
Dump(Stream * s,bool show_address,bool show_bytes,const ExecutionContext * exe_ctx)9600b57cec5SDimitry Andric void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,
9610b57cec5SDimitry Andric const ExecutionContext *exe_ctx) {
9620b57cec5SDimitry Andric const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
9630b57cec5SDimitry Andric collection::const_iterator pos, begin, end;
9640b57cec5SDimitry Andric
9650b57cec5SDimitry Andric const FormatEntity::Entry *disassembly_format = nullptr;
9660b57cec5SDimitry Andric FormatEntity::Entry format;
9670b57cec5SDimitry Andric if (exe_ctx && exe_ctx->HasTargetScope()) {
9680b57cec5SDimitry Andric disassembly_format =
9690b57cec5SDimitry Andric exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
9700b57cec5SDimitry Andric } else {
9710b57cec5SDimitry Andric FormatEntity::Parse("${addr}: ", format);
9720b57cec5SDimitry Andric disassembly_format = &format;
9730b57cec5SDimitry Andric }
9740b57cec5SDimitry Andric
9750b57cec5SDimitry Andric for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
9760b57cec5SDimitry Andric pos != end; ++pos) {
9770b57cec5SDimitry Andric if (pos != begin)
9780b57cec5SDimitry Andric s->EOL();
9790b57cec5SDimitry Andric (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx,
9800b57cec5SDimitry Andric nullptr, nullptr, disassembly_format, 0);
9810b57cec5SDimitry Andric }
9820b57cec5SDimitry Andric }
9830b57cec5SDimitry Andric
Clear()9840b57cec5SDimitry Andric void InstructionList::Clear() { m_instructions.clear(); }
9850b57cec5SDimitry Andric
Append(lldb::InstructionSP & inst_sp)9860b57cec5SDimitry Andric void InstructionList::Append(lldb::InstructionSP &inst_sp) {
9870b57cec5SDimitry Andric if (inst_sp)
9880b57cec5SDimitry Andric m_instructions.push_back(inst_sp);
9890b57cec5SDimitry Andric }
9900b57cec5SDimitry Andric
9910b57cec5SDimitry Andric uint32_t
GetIndexOfNextBranchInstruction(uint32_t start,bool ignore_calls,bool * found_calls) const9920b57cec5SDimitry Andric InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
993480093f4SDimitry Andric bool ignore_calls,
994480093f4SDimitry Andric bool *found_calls) const {
9950b57cec5SDimitry Andric size_t num_instructions = m_instructions.size();
9960b57cec5SDimitry Andric
9970b57cec5SDimitry Andric uint32_t next_branch = UINT32_MAX;
998480093f4SDimitry Andric
999480093f4SDimitry Andric if (found_calls)
1000480093f4SDimitry Andric *found_calls = false;
1001af732203SDimitry Andric for (size_t i = start; i < num_instructions; i++) {
10020b57cec5SDimitry Andric if (m_instructions[i]->DoesBranch()) {
1003480093f4SDimitry Andric if (ignore_calls && m_instructions[i]->IsCall()) {
1004480093f4SDimitry Andric if (found_calls)
1005480093f4SDimitry Andric *found_calls = true;
10060b57cec5SDimitry Andric continue;
1007480093f4SDimitry Andric }
10080b57cec5SDimitry Andric next_branch = i;
10090b57cec5SDimitry Andric break;
10100b57cec5SDimitry Andric }
10110b57cec5SDimitry Andric }
10120b57cec5SDimitry Andric
10130b57cec5SDimitry Andric return next_branch;
10140b57cec5SDimitry Andric }
10150b57cec5SDimitry Andric
10160b57cec5SDimitry Andric uint32_t
GetIndexOfInstructionAtAddress(const Address & address)10170b57cec5SDimitry Andric InstructionList::GetIndexOfInstructionAtAddress(const Address &address) {
10180b57cec5SDimitry Andric size_t num_instructions = m_instructions.size();
10190b57cec5SDimitry Andric uint32_t index = UINT32_MAX;
10200b57cec5SDimitry Andric for (size_t i = 0; i < num_instructions; i++) {
10210b57cec5SDimitry Andric if (m_instructions[i]->GetAddress() == address) {
10220b57cec5SDimitry Andric index = i;
10230b57cec5SDimitry Andric break;
10240b57cec5SDimitry Andric }
10250b57cec5SDimitry Andric }
10260b57cec5SDimitry Andric return index;
10270b57cec5SDimitry Andric }
10280b57cec5SDimitry Andric
10290b57cec5SDimitry Andric uint32_t
GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,Target & target)10300b57cec5SDimitry Andric InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,
10310b57cec5SDimitry Andric Target &target) {
10320b57cec5SDimitry Andric Address address;
10330b57cec5SDimitry Andric address.SetLoadAddress(load_addr, &target);
10340b57cec5SDimitry Andric return GetIndexOfInstructionAtAddress(address);
10350b57cec5SDimitry Andric }
10360b57cec5SDimitry Andric
ParseInstructions(Target & target,Address start,Limit limit,Stream * error_strm_ptr,bool force_live_memory)10375ffd83dbSDimitry Andric size_t Disassembler::ParseInstructions(Target &target, Address start,
10385ffd83dbSDimitry Andric Limit limit, Stream *error_strm_ptr,
1039*5f7ddb14SDimitry Andric bool force_live_memory) {
10405ffd83dbSDimitry Andric m_instruction_list.Clear();
10415ffd83dbSDimitry Andric
10425ffd83dbSDimitry Andric if (!start.IsValid())
10430b57cec5SDimitry Andric return 0;
10440b57cec5SDimitry Andric
10455ffd83dbSDimitry Andric start = ResolveAddress(target, start);
10465ffd83dbSDimitry Andric
10475ffd83dbSDimitry Andric addr_t byte_size = limit.value;
10485ffd83dbSDimitry Andric if (limit.kind == Limit::Instructions)
10495ffd83dbSDimitry Andric byte_size *= m_arch.GetMaximumOpcodeByteSize();
10500b57cec5SDimitry Andric auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0');
10510b57cec5SDimitry Andric
10520b57cec5SDimitry Andric Status error;
10530b57cec5SDimitry Andric lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
10545ffd83dbSDimitry Andric const size_t bytes_read =
1055*5f7ddb14SDimitry Andric target.ReadMemory(start, data_sp->GetBytes(), data_sp->GetByteSize(),
1056*5f7ddb14SDimitry Andric error, force_live_memory, &load_addr);
10575ffd83dbSDimitry Andric const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
10580b57cec5SDimitry Andric
10595ffd83dbSDimitry Andric if (bytes_read == 0) {
10605ffd83dbSDimitry Andric if (error_strm_ptr) {
10615ffd83dbSDimitry Andric if (const char *error_cstr = error.AsCString())
10625ffd83dbSDimitry Andric error_strm_ptr->Printf("error: %s\n", error_cstr);
10635ffd83dbSDimitry Andric }
10645ffd83dbSDimitry Andric return 0;
10655ffd83dbSDimitry Andric }
10665ffd83dbSDimitry Andric
10670b57cec5SDimitry Andric if (bytes_read != data_sp->GetByteSize())
10680b57cec5SDimitry Andric data_sp->SetByteSize(bytes_read);
10690b57cec5SDimitry Andric DataExtractor data(data_sp, m_arch.GetByteOrder(),
10700b57cec5SDimitry Andric m_arch.GetAddressByteSize());
10715ffd83dbSDimitry Andric return DecodeInstructions(start, data, 0,
10725ffd83dbSDimitry Andric limit.kind == Limit::Instructions ? limit.value
10735ffd83dbSDimitry Andric : UINT32_MAX,
10740b57cec5SDimitry Andric false, data_from_file);
10750b57cec5SDimitry Andric }
10760b57cec5SDimitry Andric
10770b57cec5SDimitry Andric // Disassembler copy constructor
Disassembler(const ArchSpec & arch,const char * flavor)10780b57cec5SDimitry Andric Disassembler::Disassembler(const ArchSpec &arch, const char *flavor)
10790b57cec5SDimitry Andric : m_arch(arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS),
10800b57cec5SDimitry Andric m_flavor() {
10810b57cec5SDimitry Andric if (flavor == nullptr)
10820b57cec5SDimitry Andric m_flavor.assign("default");
10830b57cec5SDimitry Andric else
10840b57cec5SDimitry Andric m_flavor.assign(flavor);
10850b57cec5SDimitry Andric
10860b57cec5SDimitry Andric // If this is an arm variant that can only include thumb (T16, T32)
10870b57cec5SDimitry Andric // instructions, force the arch triple to be "thumbv.." instead of "armv..."
10880b57cec5SDimitry Andric if (arch.IsAlwaysThumbInstructions()) {
10890b57cec5SDimitry Andric std::string thumb_arch_name(arch.GetTriple().getArchName().str());
10900b57cec5SDimitry Andric // Replace "arm" with "thumb" so we get all thumb variants correct
10910b57cec5SDimitry Andric if (thumb_arch_name.size() > 3) {
10920b57cec5SDimitry Andric thumb_arch_name.erase(0, 3);
10930b57cec5SDimitry Andric thumb_arch_name.insert(0, "thumb");
10940b57cec5SDimitry Andric }
10950b57cec5SDimitry Andric m_arch.SetTriple(thumb_arch_name.c_str());
10960b57cec5SDimitry Andric }
10970b57cec5SDimitry Andric }
10980b57cec5SDimitry Andric
10990b57cec5SDimitry Andric Disassembler::~Disassembler() = default;
11000b57cec5SDimitry Andric
GetInstructionList()11010b57cec5SDimitry Andric InstructionList &Disassembler::GetInstructionList() {
11020b57cec5SDimitry Andric return m_instruction_list;
11030b57cec5SDimitry Andric }
11040b57cec5SDimitry Andric
GetInstructionList() const11050b57cec5SDimitry Andric const InstructionList &Disassembler::GetInstructionList() const {
11060b57cec5SDimitry Andric return m_instruction_list;
11070b57cec5SDimitry Andric }
11080b57cec5SDimitry Andric
11090b57cec5SDimitry Andric // Class PseudoInstruction
11100b57cec5SDimitry Andric
PseudoInstruction()11110b57cec5SDimitry Andric PseudoInstruction::PseudoInstruction()
11120b57cec5SDimitry Andric : Instruction(Address(), AddressClass::eUnknown), m_description() {}
11130b57cec5SDimitry Andric
11140b57cec5SDimitry Andric PseudoInstruction::~PseudoInstruction() = default;
11150b57cec5SDimitry Andric
DoesBranch()11160b57cec5SDimitry Andric bool PseudoInstruction::DoesBranch() {
11170b57cec5SDimitry Andric // This is NOT a valid question for a pseudo instruction.
11180b57cec5SDimitry Andric return false;
11190b57cec5SDimitry Andric }
11200b57cec5SDimitry Andric
HasDelaySlot()11210b57cec5SDimitry Andric bool PseudoInstruction::HasDelaySlot() {
11220b57cec5SDimitry Andric // This is NOT a valid question for a pseudo instruction.
11230b57cec5SDimitry Andric return false;
11240b57cec5SDimitry Andric }
11250b57cec5SDimitry Andric
Decode(const lldb_private::Disassembler & disassembler,const lldb_private::DataExtractor & data,lldb::offset_t data_offset)11260b57cec5SDimitry Andric size_t PseudoInstruction::Decode(const lldb_private::Disassembler &disassembler,
11270b57cec5SDimitry Andric const lldb_private::DataExtractor &data,
11280b57cec5SDimitry Andric lldb::offset_t data_offset) {
11290b57cec5SDimitry Andric return m_opcode.GetByteSize();
11300b57cec5SDimitry Andric }
11310b57cec5SDimitry Andric
SetOpcode(size_t opcode_size,void * opcode_data)11320b57cec5SDimitry Andric void PseudoInstruction::SetOpcode(size_t opcode_size, void *opcode_data) {
11330b57cec5SDimitry Andric if (!opcode_data)
11340b57cec5SDimitry Andric return;
11350b57cec5SDimitry Andric
11360b57cec5SDimitry Andric switch (opcode_size) {
11370b57cec5SDimitry Andric case 8: {
11380b57cec5SDimitry Andric uint8_t value8 = *((uint8_t *)opcode_data);
11390b57cec5SDimitry Andric m_opcode.SetOpcode8(value8, eByteOrderInvalid);
11400b57cec5SDimitry Andric break;
11410b57cec5SDimitry Andric }
11420b57cec5SDimitry Andric case 16: {
11430b57cec5SDimitry Andric uint16_t value16 = *((uint16_t *)opcode_data);
11440b57cec5SDimitry Andric m_opcode.SetOpcode16(value16, eByteOrderInvalid);
11450b57cec5SDimitry Andric break;
11460b57cec5SDimitry Andric }
11470b57cec5SDimitry Andric case 32: {
11480b57cec5SDimitry Andric uint32_t value32 = *((uint32_t *)opcode_data);
11490b57cec5SDimitry Andric m_opcode.SetOpcode32(value32, eByteOrderInvalid);
11500b57cec5SDimitry Andric break;
11510b57cec5SDimitry Andric }
11520b57cec5SDimitry Andric case 64: {
11530b57cec5SDimitry Andric uint64_t value64 = *((uint64_t *)opcode_data);
11540b57cec5SDimitry Andric m_opcode.SetOpcode64(value64, eByteOrderInvalid);
11550b57cec5SDimitry Andric break;
11560b57cec5SDimitry Andric }
11570b57cec5SDimitry Andric default:
11580b57cec5SDimitry Andric break;
11590b57cec5SDimitry Andric }
11600b57cec5SDimitry Andric }
11610b57cec5SDimitry Andric
SetDescription(llvm::StringRef description)11620b57cec5SDimitry Andric void PseudoInstruction::SetDescription(llvm::StringRef description) {
11635ffd83dbSDimitry Andric m_description = std::string(description);
11640b57cec5SDimitry Andric }
11650b57cec5SDimitry Andric
BuildRegister(ConstString & r)11660b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildRegister(ConstString &r) {
11670b57cec5SDimitry Andric Operand ret;
11680b57cec5SDimitry Andric ret.m_type = Type::Register;
11690b57cec5SDimitry Andric ret.m_register = r;
11700b57cec5SDimitry Andric return ret;
11710b57cec5SDimitry Andric }
11720b57cec5SDimitry Andric
BuildImmediate(lldb::addr_t imm,bool neg)11730b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildImmediate(lldb::addr_t imm,
11740b57cec5SDimitry Andric bool neg) {
11750b57cec5SDimitry Andric Operand ret;
11760b57cec5SDimitry Andric ret.m_type = Type::Immediate;
11770b57cec5SDimitry Andric ret.m_immediate = imm;
11780b57cec5SDimitry Andric ret.m_negative = neg;
11790b57cec5SDimitry Andric return ret;
11800b57cec5SDimitry Andric }
11810b57cec5SDimitry Andric
BuildImmediate(int64_t imm)11820b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildImmediate(int64_t imm) {
11830b57cec5SDimitry Andric Operand ret;
11840b57cec5SDimitry Andric ret.m_type = Type::Immediate;
11850b57cec5SDimitry Andric if (imm < 0) {
11860b57cec5SDimitry Andric ret.m_immediate = -imm;
11870b57cec5SDimitry Andric ret.m_negative = true;
11880b57cec5SDimitry Andric } else {
11890b57cec5SDimitry Andric ret.m_immediate = imm;
11900b57cec5SDimitry Andric ret.m_negative = false;
11910b57cec5SDimitry Andric }
11920b57cec5SDimitry Andric return ret;
11930b57cec5SDimitry Andric }
11940b57cec5SDimitry Andric
11950b57cec5SDimitry Andric Instruction::Operand
BuildDereference(const Operand & ref)11960b57cec5SDimitry Andric Instruction::Operand::BuildDereference(const Operand &ref) {
11970b57cec5SDimitry Andric Operand ret;
11980b57cec5SDimitry Andric ret.m_type = Type::Dereference;
11990b57cec5SDimitry Andric ret.m_children = {ref};
12000b57cec5SDimitry Andric return ret;
12010b57cec5SDimitry Andric }
12020b57cec5SDimitry Andric
BuildSum(const Operand & lhs,const Operand & rhs)12030b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildSum(const Operand &lhs,
12040b57cec5SDimitry Andric const Operand &rhs) {
12050b57cec5SDimitry Andric Operand ret;
12060b57cec5SDimitry Andric ret.m_type = Type::Sum;
12070b57cec5SDimitry Andric ret.m_children = {lhs, rhs};
12080b57cec5SDimitry Andric return ret;
12090b57cec5SDimitry Andric }
12100b57cec5SDimitry Andric
BuildProduct(const Operand & lhs,const Operand & rhs)12110b57cec5SDimitry Andric Instruction::Operand Instruction::Operand::BuildProduct(const Operand &lhs,
12120b57cec5SDimitry Andric const Operand &rhs) {
12130b57cec5SDimitry Andric Operand ret;
12140b57cec5SDimitry Andric ret.m_type = Type::Product;
12150b57cec5SDimitry Andric ret.m_children = {lhs, rhs};
12160b57cec5SDimitry Andric return ret;
12170b57cec5SDimitry Andric }
12180b57cec5SDimitry Andric
12190b57cec5SDimitry 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)12200b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchBinaryOp(
12210b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> base,
12220b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> left,
12230b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> right) {
12240b57cec5SDimitry Andric return [base, left, right](const Instruction::Operand &op) -> bool {
12250b57cec5SDimitry Andric return (base(op) && op.m_children.size() == 2 &&
12260b57cec5SDimitry Andric ((left(op.m_children[0]) && right(op.m_children[1])) ||
12270b57cec5SDimitry Andric (left(op.m_children[1]) && right(op.m_children[0]))));
12280b57cec5SDimitry Andric };
12290b57cec5SDimitry Andric }
12300b57cec5SDimitry Andric
12310b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchUnaryOp(std::function<bool (const Instruction::Operand &)> base,std::function<bool (const Instruction::Operand &)> child)12320b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchUnaryOp(
12330b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> base,
12340b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)> child) {
12350b57cec5SDimitry Andric return [base, child](const Instruction::Operand &op) -> bool {
12360b57cec5SDimitry Andric return (base(op) && op.m_children.size() == 1 && child(op.m_children[0]));
12370b57cec5SDimitry Andric };
12380b57cec5SDimitry Andric }
12390b57cec5SDimitry Andric
12400b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchRegOp(const RegisterInfo & info)12410b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchRegOp(const RegisterInfo &info) {
12420b57cec5SDimitry Andric return [&info](const Instruction::Operand &op) {
12430b57cec5SDimitry Andric return (op.m_type == Instruction::Operand::Type::Register &&
12440b57cec5SDimitry Andric (op.m_register == ConstString(info.name) ||
12450b57cec5SDimitry Andric op.m_register == ConstString(info.alt_name)));
12460b57cec5SDimitry Andric };
12470b57cec5SDimitry Andric }
12480b57cec5SDimitry Andric
12490b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
FetchRegOp(ConstString & reg)12500b57cec5SDimitry Andric lldb_private::OperandMatchers::FetchRegOp(ConstString ®) {
12510b57cec5SDimitry Andric return [®](const Instruction::Operand &op) {
12520b57cec5SDimitry Andric if (op.m_type != Instruction::Operand::Type::Register) {
12530b57cec5SDimitry Andric return false;
12540b57cec5SDimitry Andric }
12550b57cec5SDimitry Andric reg = op.m_register;
12560b57cec5SDimitry Andric return true;
12570b57cec5SDimitry Andric };
12580b57cec5SDimitry Andric }
12590b57cec5SDimitry Andric
12600b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchImmOp(int64_t imm)12610b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchImmOp(int64_t imm) {
12620b57cec5SDimitry Andric return [imm](const Instruction::Operand &op) {
12630b57cec5SDimitry Andric return (op.m_type == Instruction::Operand::Type::Immediate &&
12640b57cec5SDimitry Andric ((op.m_negative && op.m_immediate == (uint64_t)-imm) ||
12650b57cec5SDimitry Andric (!op.m_negative && op.m_immediate == (uint64_t)imm)));
12660b57cec5SDimitry Andric };
12670b57cec5SDimitry Andric }
12680b57cec5SDimitry Andric
12690b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
FetchImmOp(int64_t & imm)12700b57cec5SDimitry Andric lldb_private::OperandMatchers::FetchImmOp(int64_t &imm) {
12710b57cec5SDimitry Andric return [&imm](const Instruction::Operand &op) {
12720b57cec5SDimitry Andric if (op.m_type != Instruction::Operand::Type::Immediate) {
12730b57cec5SDimitry Andric return false;
12740b57cec5SDimitry Andric }
12750b57cec5SDimitry Andric if (op.m_negative) {
12760b57cec5SDimitry Andric imm = -((int64_t)op.m_immediate);
12770b57cec5SDimitry Andric } else {
12780b57cec5SDimitry Andric imm = ((int64_t)op.m_immediate);
12790b57cec5SDimitry Andric }
12800b57cec5SDimitry Andric return true;
12810b57cec5SDimitry Andric };
12820b57cec5SDimitry Andric }
12830b57cec5SDimitry Andric
12840b57cec5SDimitry Andric std::function<bool(const Instruction::Operand &)>
MatchOpType(Instruction::Operand::Type type)12850b57cec5SDimitry Andric lldb_private::OperandMatchers::MatchOpType(Instruction::Operand::Type type) {
12860b57cec5SDimitry Andric return [type](const Instruction::Operand &op) { return op.m_type == type; };
12870b57cec5SDimitry Andric }
1288