aboutsummaryrefslogtreecommitdiff
path: root/source/Core/Disassembler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core/Disassembler.cpp')
-rw-r--r--source/Core/Disassembler.cpp2363
1 files changed, 1249 insertions, 1114 deletions
diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp
index 1e6a245261bb..7cac29491c8c 100644
--- a/source/Core/Disassembler.cpp
+++ b/source/Core/Disassembler.cpp
@@ -29,6 +29,7 @@
#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Interpreter/OptionValueArray.h"
#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Interpreter/OptionValueRegex.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Interpreter/OptionValueUInt64.h"
#include "lldb/Symbol/Function.h"
@@ -45,1271 +46,1405 @@
using namespace lldb;
using namespace lldb_private;
-DisassemblerSP
-Disassembler::FindPlugin (const ArchSpec &arch, const char *flavor, const char *plugin_name)
-{
- Timer scoped_timer (__PRETTY_FUNCTION__,
- "Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
- arch.GetArchitectureName(),
- plugin_name);
-
- DisassemblerCreateInstance create_callback = nullptr;
-
- if (plugin_name)
- {
- ConstString const_plugin_name (plugin_name);
- create_callback = PluginManager::GetDisassemblerCreateCallbackForPluginName (const_plugin_name);
- if (create_callback)
- {
- DisassemblerSP disassembler_sp(create_callback(arch, flavor));
-
- if (disassembler_sp)
- return disassembler_sp;
- }
+DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,
+ const char *flavor,
+ const char *plugin_name) {
+ Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ "Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
+ arch.GetArchitectureName(), plugin_name);
+
+ DisassemblerCreateInstance create_callback = nullptr;
+
+ if (plugin_name) {
+ ConstString const_plugin_name(plugin_name);
+ create_callback = PluginManager::GetDisassemblerCreateCallbackForPluginName(
+ const_plugin_name);
+ if (create_callback) {
+ DisassemblerSP disassembler_sp(create_callback(arch, flavor));
+
+ if (disassembler_sp)
+ return disassembler_sp;
}
- else
- {
- for (uint32_t idx = 0; (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(idx)) != nullptr; ++idx)
- {
- DisassemblerSP disassembler_sp(create_callback(arch, flavor));
-
- if (disassembler_sp)
- return disassembler_sp;
- }
+ } else {
+ for (uint32_t idx = 0;
+ (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(
+ idx)) != nullptr;
+ ++idx) {
+ DisassemblerSP disassembler_sp(create_callback(arch, flavor));
+
+ if (disassembler_sp)
+ return disassembler_sp;
}
- return DisassemblerSP();
+ }
+ return DisassemblerSP();
}
-DisassemblerSP
-Disassembler::FindPluginForTarget(const TargetSP target_sp, const ArchSpec &arch, const char *flavor, const char *plugin_name)
-{
- if (target_sp && flavor == nullptr)
- {
- // FIXME - we don't have the mechanism in place to do per-architecture settings. But since we know that for now
- // we only support flavors on x86 & x86_64,
- if (arch.GetTriple().getArch() == llvm::Triple::x86
- || arch.GetTriple().getArch() == llvm::Triple::x86_64)
- flavor = target_sp->GetDisassemblyFlavor();
- }
- return FindPlugin(arch, flavor, plugin_name);
+DisassemblerSP Disassembler::FindPluginForTarget(const TargetSP target_sp,
+ const ArchSpec &arch,
+ const char *flavor,
+ const char *plugin_name) {
+ if (target_sp && flavor == nullptr) {
+ // FIXME - we don't have the mechanism in place to do per-architecture
+ // settings. But since we know that for now
+ // we only support flavors on x86 & x86_64,
+ if (arch.GetTriple().getArch() == llvm::Triple::x86 ||
+ arch.GetTriple().getArch() == llvm::Triple::x86_64)
+ flavor = target_sp->GetDisassemblyFlavor();
+ }
+ return FindPlugin(arch, flavor, plugin_name);
}
-static void
-ResolveAddress (const ExecutionContext &exe_ctx,
- const Address &addr,
- Address &resolved_addr)
-{
- if (!addr.IsSectionOffset())
- {
- // If we weren't passed in a section offset address range,
- // try and resolve it to something
- Target *target = exe_ctx.GetTargetPtr();
- if (target)
- {
- if (target->GetSectionLoadList().IsEmpty())
- {
- target->GetImages().ResolveFileAddress (addr.GetOffset(), resolved_addr);
- }
- else
- {
- target->GetSectionLoadList().ResolveLoadAddress (addr.GetOffset(), resolved_addr);
- }
- // We weren't able to resolve the address, just treat it as a
- // raw address
- if (resolved_addr.IsValid())
- return;
- }
+static void ResolveAddress(const ExecutionContext &exe_ctx, const Address &addr,
+ Address &resolved_addr) {
+ if (!addr.IsSectionOffset()) {
+ // If we weren't passed in a section offset address range,
+ // try and resolve it to something
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ if (target->GetSectionLoadList().IsEmpty()) {
+ target->GetImages().ResolveFileAddress(addr.GetOffset(), resolved_addr);
+ } else {
+ target->GetSectionLoadList().ResolveLoadAddress(addr.GetOffset(),
+ resolved_addr);
+ }
+ // We weren't able to resolve the address, just treat it as a
+ // raw address
+ if (resolved_addr.IsValid())
+ return;
}
- resolved_addr = addr;
+ }
+ resolved_addr = addr;
}
-size_t
-Disassembler::Disassemble(Debugger &debugger,
- const ArchSpec &arch,
- const char *plugin_name,
- const char *flavor,
- const ExecutionContext &exe_ctx,
- SymbolContextList &sc_list,
- uint32_t num_instructions,
- uint32_t num_mixed_context_lines,
- uint32_t options,
- Stream &strm)
-{
- size_t success_count = 0;
- const size_t count = sc_list.GetSize();
- SymbolContext sc;
- AddressRange range;
- const uint32_t scope = eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
- const bool use_inline_block_range = true;
- for (size_t i = 0; i < count; ++i)
- {
- if (!sc_list.GetContextAtIndex(i, sc))
- break;
- for (uint32_t range_idx = 0; sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); ++range_idx)
- {
- if (Disassemble (debugger,
- arch,
- plugin_name,
- flavor,
- exe_ctx,
- range,
- num_instructions,
- num_mixed_context_lines,
- options,
- strm))
- {
- ++success_count;
- strm.EOL();
- }
- }
+size_t Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
+ const char *plugin_name, const char *flavor,
+ const ExecutionContext &exe_ctx,
+ SymbolContextList &sc_list,
+ uint32_t num_instructions,
+ bool mixed_source_and_assembly,
+ uint32_t num_mixed_context_lines,
+ uint32_t options, Stream &strm) {
+ size_t success_count = 0;
+ const size_t count = sc_list.GetSize();
+ SymbolContext sc;
+ AddressRange range;
+ const uint32_t scope =
+ eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = true;
+ for (size_t i = 0; i < count; ++i) {
+ if (!sc_list.GetContextAtIndex(i, sc))
+ break;
+ for (uint32_t range_idx = 0;
+ sc.GetAddressRange(scope, range_idx, use_inline_block_range, range);
+ ++range_idx) {
+ if (Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, range,
+ num_instructions, mixed_source_and_assembly,
+ num_mixed_context_lines, options, strm)) {
+ ++success_count;
+ strm.EOL();
+ }
}
- return success_count;
+ }
+ return success_count;
}
-bool
-Disassembler::Disassemble(Debugger &debugger,
- const ArchSpec &arch,
- const char *plugin_name,
- const char *flavor,
- const ExecutionContext &exe_ctx,
- const ConstString &name,
- Module *module,
- uint32_t num_instructions,
- uint32_t num_mixed_context_lines,
- uint32_t options,
- Stream &strm)
-{
- SymbolContextList sc_list;
- if (name)
- {
- const bool include_symbols = true;
- const bool include_inlines = true;
- if (module)
- {
- module->FindFunctions(name,
- nullptr,
- eFunctionNameTypeAuto,
- include_symbols,
- include_inlines,
- true,
- sc_list);
- }
- else if (exe_ctx.GetTargetPtr())
- {
- exe_ctx.GetTargetPtr()->GetImages().FindFunctions (name,
- eFunctionNameTypeAuto,
- include_symbols,
- include_inlines,
- false,
- sc_list);
- }
+bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
+ const char *plugin_name, const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const ConstString &name, Module *module,
+ uint32_t num_instructions,
+ bool mixed_source_and_assembly,
+ uint32_t num_mixed_context_lines,
+ uint32_t options, Stream &strm) {
+ SymbolContextList sc_list;
+ if (name) {
+ const bool include_symbols = true;
+ const bool include_inlines = true;
+ if (module) {
+ module->FindFunctions(name, nullptr, eFunctionNameTypeAuto,
+ include_symbols, include_inlines, true, sc_list);
+ } else if (exe_ctx.GetTargetPtr()) {
+ exe_ctx.GetTargetPtr()->GetImages().FindFunctions(
+ name, eFunctionNameTypeAuto, include_symbols, include_inlines, false,
+ sc_list);
}
-
- if (sc_list.GetSize ())
- {
- return Disassemble (debugger,
- arch,
- plugin_name,
- flavor,
- exe_ctx,
- sc_list,
- num_instructions,
- num_mixed_context_lines,
- options,
- strm);
+ }
+
+ if (sc_list.GetSize()) {
+ return Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, sc_list,
+ num_instructions, mixed_source_and_assembly,
+ num_mixed_context_lines, options, strm);
+ }
+ return false;
+}
+
+lldb::DisassemblerSP Disassembler::DisassembleRange(
+ const ArchSpec &arch, const char *plugin_name, const char *flavor,
+ const ExecutionContext &exe_ctx, const AddressRange &range,
+ bool prefer_file_cache) {
+ lldb::DisassemblerSP disasm_sp;
+ if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid()) {
+ disasm_sp = Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch,
+ flavor, plugin_name);
+
+ if (disasm_sp) {
+ size_t bytes_disassembled = disasm_sp->ParseInstructions(
+ &exe_ctx, range, nullptr, prefer_file_cache);
+ if (bytes_disassembled == 0)
+ disasm_sp.reset();
}
- return false;
+ }
+ return disasm_sp;
}
lldb::DisassemblerSP
-Disassembler::DisassembleRange(const ArchSpec &arch,
- const char *plugin_name,
- const char *flavor,
- const ExecutionContext &exe_ctx,
- const AddressRange &range,
- bool prefer_file_cache)
-{
- lldb::DisassemblerSP disasm_sp;
- if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid())
- {
- disasm_sp = Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name);
-
- if (disasm_sp)
- {
- size_t bytes_disassembled = disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache);
- if (bytes_disassembled == 0)
- disasm_sp.reset();
- }
+Disassembler::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) {
+ lldb::DisassemblerSP disasm_sp;
+
+ if (src) {
+ disasm_sp = Disassembler::FindPlugin(arch, flavor, plugin_name);
+
+ if (disasm_sp) {
+ DataExtractor data(src, src_len, arch.GetByteOrder(),
+ arch.GetAddressByteSize());
+
+ (void)disasm_sp->DecodeInstructions(start, data, 0, num_instructions,
+ false, data_from_file);
}
- return disasm_sp;
+ }
+
+ return disasm_sp;
}
-lldb::DisassemblerSP
-Disassembler::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)
-{
- lldb::DisassemblerSP disasm_sp;
-
- if (src)
- {
- disasm_sp = Disassembler::FindPlugin(arch, flavor, plugin_name);
-
- if (disasm_sp)
- {
- DataExtractor data(src, src_len, arch.GetByteOrder(), arch.GetAddressByteSize());
-
- (void)disasm_sp->DecodeInstructions (start,
- data,
- 0,
- num_instructions,
- false,
- data_from_file);
- }
+bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
+ const char *plugin_name, const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const AddressRange &disasm_range,
+ uint32_t num_instructions,
+ bool mixed_source_and_assembly,
+ uint32_t num_mixed_context_lines,
+ uint32_t options, Stream &strm) {
+ if (disasm_range.GetByteSize()) {
+ lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget(
+ exe_ctx.GetTargetSP(), arch, flavor, plugin_name));
+
+ if (disasm_sp) {
+ AddressRange range;
+ ResolveAddress(exe_ctx, disasm_range.GetBaseAddress(),
+ range.GetBaseAddress());
+ range.SetByteSize(disasm_range.GetByteSize());
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions(
+ &exe_ctx, range, &strm, prefer_file_cache);
+ if (bytes_disassembled == 0)
+ return false;
+
+ return PrintInstructions(disasm_sp.get(), debugger, arch, exe_ctx,
+ num_instructions, mixed_source_and_assembly,
+ num_mixed_context_lines, options, strm);
}
-
- return disasm_sp;
+ }
+ return false;
}
-bool
-Disassembler::Disassemble(Debugger &debugger,
- const ArchSpec &arch,
- const char *plugin_name,
- const char *flavor,
- const ExecutionContext &exe_ctx,
- const AddressRange &disasm_range,
- uint32_t num_instructions,
- uint32_t num_mixed_context_lines,
- uint32_t options,
- Stream &strm)
-{
- if (disasm_range.GetByteSize())
- {
- lldb::DisassemblerSP disasm_sp (Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name));
-
- if (disasm_sp)
- {
- AddressRange range;
- ResolveAddress (exe_ctx, disasm_range.GetBaseAddress(), range.GetBaseAddress());
- range.SetByteSize (disasm_range.GetByteSize());
- const bool prefer_file_cache = false;
- size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, &strm, prefer_file_cache);
- if (bytes_disassembled == 0)
- return false;
-
- return PrintInstructions(disasm_sp.get(), debugger, arch, exe_ctx, num_instructions,
- num_mixed_context_lines, options, strm);
- }
+bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
+ const char *plugin_name, const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const Address &start_address,
+ uint32_t num_instructions,
+ bool mixed_source_and_assembly,
+ uint32_t num_mixed_context_lines,
+ uint32_t options, Stream &strm) {
+ if (num_instructions > 0) {
+ lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget(
+ exe_ctx.GetTargetSP(), arch, flavor, plugin_name));
+ if (disasm_sp) {
+ Address addr;
+ ResolveAddress(exe_ctx, start_address, addr);
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions(
+ &exe_ctx, addr, num_instructions, prefer_file_cache);
+ if (bytes_disassembled == 0)
+ return false;
+ return PrintInstructions(disasm_sp.get(), debugger, arch, exe_ctx,
+ num_instructions, mixed_source_and_assembly,
+ num_mixed_context_lines, options, strm);
}
- return false;
+ }
+ return false;
}
-
-bool
-Disassembler::Disassemble(Debugger &debugger,
- const ArchSpec &arch,
- const char *plugin_name,
- const char *flavor,
- const ExecutionContext &exe_ctx,
- const Address &start_address,
- uint32_t num_instructions,
- uint32_t num_mixed_context_lines,
- uint32_t options,
- Stream &strm)
-{
- if (num_instructions > 0)
- {
- lldb::DisassemblerSP disasm_sp (Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(),
- arch,
- flavor,
- plugin_name));
- if (disasm_sp)
- {
- Address addr;
- ResolveAddress (exe_ctx, start_address, addr);
- const bool prefer_file_cache = false;
- size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx,
- addr,
- num_instructions,
- prefer_file_cache);
- if (bytes_disassembled == 0)
- return false;
- return PrintInstructions(disasm_sp.get(), debugger, arch, exe_ctx, num_instructions,
- num_mixed_context_lines, options, strm);
- }
+
+Disassembler::SourceLine
+Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {
+ SourceLine decl_line;
+ if (sc.function && sc.line_entry.IsValid()) {
+ LineEntry prologue_end_line = sc.line_entry;
+ FileSpec func_decl_file;
+ uint32_t func_decl_line;
+ sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line);
+ if (func_decl_file == prologue_end_line.file ||
+ func_decl_file == prologue_end_line.original_file) {
+ decl_line.file = func_decl_file;
+ decl_line.line = func_decl_line;
+ // TODO do we care about column on these entries? If so, we need to
+ // plumb that through GetStartLineSourceInfo.
+ decl_line.column = 0;
}
- return false;
+ }
+ return decl_line;
}
-bool
-Disassembler::PrintInstructions(Disassembler *disasm_ptr, Debugger &debugger, const ArchSpec &arch,
- const ExecutionContext &exe_ctx, uint32_t num_instructions,
- uint32_t num_mixed_context_lines, uint32_t options, Stream &strm)
-{
- // We got some things disassembled...
- size_t num_instructions_found = disasm_ptr->GetInstructionList().GetSize();
-
- if (num_instructions > 0 && num_instructions < num_instructions_found)
- num_instructions_found = num_instructions;
-
- const uint32_t max_opcode_byte_size = disasm_ptr->GetInstructionList().GetMaxOpcocdeByteSize ();
- uint32_t offset = 0;
- SymbolContext sc;
- SymbolContext prev_sc;
- AddressRange sc_range;
- const Address *pc_addr_ptr = nullptr;
- StackFrame *frame = exe_ctx.GetFramePtr();
-
- TargetSP target_sp (exe_ctx.GetTargetSP());
- SourceManager &source_manager = target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
-
- if (frame)
- {
- pc_addr_ptr = &frame->GetFrameCodeAddress();
+void Disassembler::AddLineToSourceLineTables(
+ SourceLine &line,
+ std::map<FileSpec, std::set<uint32_t>> &source_lines_seen) {
+ if (line.IsValid()) {
+ auto source_lines_seen_pos = source_lines_seen.find(line.file);
+ if (source_lines_seen_pos == source_lines_seen.end()) {
+ std::set<uint32_t> lines;
+ lines.insert(line.line);
+ source_lines_seen.emplace(line.file, lines);
+ } else {
+ source_lines_seen_pos->second.insert(line.line);
}
- const uint32_t scope = eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
- const bool use_inline_block_range = false;
-
- const FormatEntity::Entry *disassembly_format = nullptr;
- FormatEntity::Entry format;
- if (exe_ctx.HasTargetScope())
- {
- disassembly_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat ();
+ }
+}
+
+bool Disassembler::ElideMixedSourceAndDisassemblyLine(
+ const ExecutionContext &exe_ctx, const SymbolContext &sc,
+ SourceLine &line) {
+
+ // TODO: should we also check target.process.thread.step-avoid-libraries ?
+
+ const RegularExpression *avoid_regex = nullptr;
+
+ // Skip any line #0 entries - they are implementation details
+ if (line.line == 0)
+ return false;
+
+ ThreadSP thread_sp = exe_ctx.GetThreadSP();
+ if (thread_sp) {
+ avoid_regex = thread_sp->GetSymbolsToAvoidRegexp();
+ } else {
+ TargetSP target_sp = exe_ctx.GetTargetSP();
+ if (target_sp) {
+ Error error;
+ OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue(
+ &exe_ctx, "target.process.thread.step-avoid-regexp", false, error);
+ if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) {
+ OptionValueRegex *re = value_sp->GetAsRegex();
+ if (re) {
+ avoid_regex = re->GetCurrentValue();
+ }
+ }
}
- else
- {
- FormatEntity::Parse("${addr}: ", format);
- disassembly_format = &format;
+ }
+ if (avoid_regex && sc.symbol != nullptr) {
+ const char *function_name =
+ sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
+ .GetCString();
+ if (function_name) {
+ RegularExpression::Match regex_match(1);
+ if (avoid_regex->Execute(function_name, &regex_match)) {
+ // skip this source line
+ return true;
+ }
}
+ }
+ // don't skip this source line
+ return false;
+}
- // First pass: step through the list of instructions,
- // find how long the initial addresses strings are, insert padding
- // in the second pass so the opcodes all line up nicely.
- size_t address_text_size = 0;
- for (size_t i = 0; i < num_instructions_found; ++i)
- {
- Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
- if (inst)
- {
- const Address &addr = inst->GetAddress();
- ModuleSP module_sp (addr.GetModule());
- if (module_sp)
- {
- const uint32_t resolve_mask = eSymbolContextFunction | eSymbolContextSymbol;
- uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);
- if (resolved_mask)
- {
- StreamString strmstr;
- Debugger::FormatDisassemblerAddress(disassembly_format, &sc, nullptr, &exe_ctx, &addr, strmstr);
- size_t cur_line = strmstr.GetSizeOfLastLine();
- if (cur_line > address_text_size)
- address_text_size = cur_line;
- }
- sc.Clear(false);
+bool Disassembler::PrintInstructions(Disassembler *disasm_ptr,
+ Debugger &debugger, const ArchSpec &arch,
+ const ExecutionContext &exe_ctx,
+ uint32_t num_instructions,
+ bool mixed_source_and_assembly,
+ uint32_t num_mixed_context_lines,
+ uint32_t options, Stream &strm) {
+ // We got some things disassembled...
+ size_t num_instructions_found = disasm_ptr->GetInstructionList().GetSize();
+
+ if (num_instructions > 0 && num_instructions < num_instructions_found)
+ num_instructions_found = num_instructions;
+
+ const uint32_t max_opcode_byte_size =
+ disasm_ptr->GetInstructionList().GetMaxOpcocdeByteSize();
+ SymbolContext sc;
+ SymbolContext prev_sc;
+ AddressRange current_source_line_range;
+ const Address *pc_addr_ptr = nullptr;
+ StackFrame *frame = exe_ctx.GetFramePtr();
+
+ TargetSP target_sp(exe_ctx.GetTargetSP());
+ SourceManager &source_manager =
+ target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
+
+ if (frame) {
+ pc_addr_ptr = &frame->GetFrameCodeAddress();
+ }
+ const uint32_t scope =
+ eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+
+ const FormatEntity::Entry *disassembly_format = nullptr;
+ FormatEntity::Entry format;
+ if (exe_ctx.HasTargetScope()) {
+ disassembly_format =
+ exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat();
+ } else {
+ FormatEntity::Parse("${addr}: ", format);
+ disassembly_format = &format;
+ }
+
+ // First pass: step through the list of instructions,
+ // find how long the initial addresses strings are, insert padding
+ // in the second pass so the opcodes all line up nicely.
+
+ // Also build up the source line mapping if this is mixed source & assembly
+ // mode.
+ // Calculate the source line for each assembly instruction (eliding inlined
+ // functions
+ // which the user wants to skip).
+
+ std::map<FileSpec, std::set<uint32_t>> source_lines_seen;
+ Symbol *previous_symbol = nullptr;
+
+ size_t address_text_size = 0;
+ for (size_t i = 0; i < num_instructions_found; ++i) {
+ Instruction *inst =
+ disasm_ptr->GetInstructionList().GetInstructionAtIndex(i).get();
+ if (inst) {
+ const Address &addr = inst->GetAddress();
+ ModuleSP module_sp(addr.GetModule());
+ if (module_sp) {
+ const uint32_t resolve_mask = eSymbolContextFunction |
+ eSymbolContextSymbol |
+ eSymbolContextLineEntry;
+ uint32_t resolved_mask =
+ module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);
+ if (resolved_mask) {
+ StreamString strmstr;
+ Debugger::FormatDisassemblerAddress(disassembly_format, &sc, nullptr,
+ &exe_ctx, &addr, strmstr);
+ size_t cur_line = strmstr.GetSizeOfLastLine();
+ if (cur_line > address_text_size)
+ address_text_size = cur_line;
+
+ // Add entries to our "source_lines_seen" map+set which list which
+ // sources lines occur in this disassembly session. We will print
+ // lines of context around a source line, but we don't want to print
+ // a source line that has a line table entry of its own - we'll leave
+ // that source line to be printed when it actually occurs in the
+ // disassembly.
+
+ if (mixed_source_and_assembly && sc.line_entry.IsValid()) {
+ if (sc.symbol != previous_symbol) {
+ SourceLine decl_line = GetFunctionDeclLineEntry(sc);
+ if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, decl_line) ==
+ false)
+ AddLineToSourceLineTables(decl_line, source_lines_seen);
+ }
+ if (sc.line_entry.IsValid()) {
+ SourceLine this_line;
+ this_line.file = sc.line_entry.file;
+ this_line.line = sc.line_entry.line;
+ this_line.column = sc.line_entry.column;
+ if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line) ==
+ false)
+ AddLineToSourceLineTables(this_line, source_lines_seen);
}
+ }
}
+ sc.Clear(false);
+ }
}
+ }
+
+ previous_symbol = nullptr;
+ SourceLine previous_line;
+ for (size_t i = 0; i < num_instructions_found; ++i) {
+ Instruction *inst =
+ disasm_ptr->GetInstructionList().GetInstructionAtIndex(i).get();
+
+ if (inst) {
+ const Address &addr = inst->GetAddress();
+ const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;
+ SourceLinesToDisplay source_lines_to_display;
+
+ prev_sc = sc;
+
+ ModuleSP module_sp(addr.GetModule());
+ if (module_sp) {
+ uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(
+ addr, eSymbolContextEverything, sc);
+ if (resolved_mask) {
+ if (mixed_source_and_assembly) {
+
+ // If we've started a new function (non-inlined), print all of the
+ // source lines from the
+ // function declaration until the first line table entry - typically
+ // the opening curly brace of
+ // the function.
+ if (previous_symbol != sc.symbol) {
+ // The default disassembly format puts an extra blank line between
+ // functions - so
+ // when we're displaying the source context for a function, we
+ // don't want to add
+ // a blank line after the source context or we'll end up with two
+ // of them.
+ if (previous_symbol != nullptr)
+ source_lines_to_display.print_source_context_end_eol = false;
+
+ previous_symbol = sc.symbol;
+ if (sc.function && sc.line_entry.IsValid()) {
+ LineEntry prologue_end_line = sc.line_entry;
+ if (ElideMixedSourceAndDisassemblyLine(
+ exe_ctx, sc, prologue_end_line) == false) {
+ FileSpec func_decl_file;
+ uint32_t func_decl_line;
+ sc.function->GetStartLineSourceInfo(func_decl_file,
+ func_decl_line);
+ if (func_decl_file == prologue_end_line.file ||
+ func_decl_file == prologue_end_line.original_file) {
+ // Add all the lines between the function declaration
+ // and the first non-prologue source line to the list
+ // of lines to print.
+ for (uint32_t lineno = func_decl_line;
+ lineno <= prologue_end_line.line; lineno++) {
+ SourceLine this_line;
+ this_line.file = func_decl_file;
+ this_line.line = lineno;
+ source_lines_to_display.lines.push_back(this_line);
+ }
+ // Mark the last line as the "current" one. Usually
+ // this is the open curly brace.
+ if (source_lines_to_display.lines.size() > 0)
+ source_lines_to_display.current_source_line =
+ source_lines_to_display.lines.size() - 1;
+ }
+ }
+ }
+ sc.GetAddressRange(scope, 0, use_inline_block_range,
+ current_source_line_range);
+ }
- for (size_t i = 0; i < num_instructions_found; ++i)
- {
- Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
- if (inst)
- {
- const Address &addr = inst->GetAddress();
- const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;
-
- prev_sc = sc;
-
- ModuleSP module_sp (addr.GetModule());
- if (module_sp)
- {
- uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
- if (resolved_mask)
- {
- if (num_mixed_context_lines)
- {
- if (!sc_range.ContainsFileAddress (addr))
- {
- sc.GetAddressRange (scope, 0, use_inline_block_range, sc_range);
-
- if (sc != prev_sc)
- {
- if (offset != 0)
- strm.EOL();
-
- sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false, true);
- strm.EOL();
-
- if (sc.comp_unit && sc.line_entry.IsValid())
- {
- source_manager.DisplaySourceLinesWithLineNumbers (sc.line_entry.file,
- sc.line_entry.line,
- num_mixed_context_lines,
- num_mixed_context_lines,
- ((inst_is_at_pc && (options & eOptionMarkPCSourceLine)) ? "->" : ""),
- &strm);
- }
- }
+ // If we've left a previous source line's address range, print a new
+ // source line
+ if (!current_source_line_range.ContainsFileAddress(addr)) {
+ sc.GetAddressRange(scope, 0, use_inline_block_range,
+ current_source_line_range);
+
+ if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) {
+ SourceLine this_line;
+ this_line.file = sc.line_entry.file;
+ this_line.line = sc.line_entry.line;
+
+ if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
+ this_line) == false) {
+ // Only print this source line if it is different from the
+ // last source line we printed. There may have been inlined
+ // functions between these lines that we elided, resulting in
+ // the same line being printed twice in a row for a contiguous
+ // block of assembly instructions.
+ if (this_line != previous_line) {
+
+ std::vector<uint32_t> previous_lines;
+ for (uint32_t i = 0;
+ i < num_mixed_context_lines &&
+ (this_line.line - num_mixed_context_lines) > 0;
+ i++) {
+ uint32_t line =
+ this_line.line - num_mixed_context_lines + i;
+ auto pos = source_lines_seen.find(this_line.file);
+ if (pos != source_lines_seen.end()) {
+ if (pos->second.count(line) == 1) {
+ previous_lines.clear();
+ } else {
+ previous_lines.push_back(line);
}
+ }
}
+ for (size_t i = 0; i < previous_lines.size(); i++) {
+ SourceLine previous_line;
+ previous_line.file = this_line.file;
+ previous_line.line = previous_lines[i];
+ auto pos = source_lines_seen.find(previous_line.file);
+ if (pos != source_lines_seen.end()) {
+ pos->second.insert(previous_line.line);
+ }
+ source_lines_to_display.lines.push_back(previous_line);
+ }
+
+ source_lines_to_display.lines.push_back(this_line);
+ source_lines_to_display.current_source_line =
+ source_lines_to_display.lines.size() - 1;
+
+ for (uint32_t i = 0; i < num_mixed_context_lines; i++) {
+ SourceLine next_line;
+ next_line.file = this_line.file;
+ next_line.line = this_line.line + i + 1;
+ auto pos = source_lines_seen.find(next_line.file);
+ if (pos != source_lines_seen.end()) {
+ if (pos->second.count(next_line.line) == 1)
+ break;
+ pos->second.insert(next_line.line);
+ }
+ source_lines_to_display.lines.push_back(next_line);
+ }
+ }
+ previous_line = this_line;
}
- else
- {
- sc.Clear(true);
- }
+ }
}
-
- const bool show_bytes = (options & eOptionShowBytes) != 0;
- inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, nullptr, address_text_size);
- strm.EOL();
+ }
+ } else {
+ sc.Clear(true);
}
- else
- {
- break;
+ }
+
+ if (source_lines_to_display.lines.size() > 0) {
+ strm.EOL();
+ for (size_t idx = 0; idx < source_lines_to_display.lines.size();
+ idx++) {
+ SourceLine ln = source_lines_to_display.lines[idx];
+ const char *line_highlight = "";
+ if (inst_is_at_pc && (options & eOptionMarkPCSourceLine)) {
+ line_highlight = "->";
+ } else if (idx == source_lines_to_display.current_source_line) {
+ line_highlight = "**";
+ }
+ source_manager.DisplaySourceLinesWithLineNumbers(
+ ln.file, ln.line, ln.column, 0, 0, line_highlight, &strm);
}
+ if (source_lines_to_display.print_source_context_end_eol)
+ strm.EOL();
+ }
+
+ const bool show_bytes = (options & eOptionShowBytes) != 0;
+ inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc,
+ &prev_sc, nullptr, address_text_size);
+ strm.EOL();
+ } else {
+ break;
}
-
- return true;
-}
+ }
-bool
-Disassembler::Disassemble(Debugger &debugger,
- const ArchSpec &arch,
- const char *plugin_name,
- const char *flavor,
- const ExecutionContext &exe_ctx,
- uint32_t num_instructions,
- uint32_t num_mixed_context_lines,
- uint32_t options,
- Stream &strm)
-{
- AddressRange range;
- StackFrame *frame = exe_ctx.GetFramePtr();
- if (frame)
- {
- SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
- if (sc.function)
- {
- range = sc.function->GetAddressRange();
- }
- else if (sc.symbol && sc.symbol->ValueIsAddress())
- {
- range.GetBaseAddress() = sc.symbol->GetAddressRef();
- range.SetByteSize (sc.symbol->GetByteSize());
- }
- else
- {
- range.GetBaseAddress() = frame->GetFrameCodeAddress();
- }
+ return true;
+}
- if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
- range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
+bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
+ const char *plugin_name, const char *flavor,
+ const ExecutionContext &exe_ctx,
+ uint32_t num_instructions,
+ bool mixed_source_and_assembly,
+ uint32_t num_mixed_context_lines,
+ uint32_t options, Stream &strm) {
+ AddressRange range;
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame) {
+ SymbolContext sc(
+ frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function) {
+ range = sc.function->GetAddressRange();
+ } else if (sc.symbol && sc.symbol->ValueIsAddress()) {
+ range.GetBaseAddress() = sc.symbol->GetAddressRef();
+ range.SetByteSize(sc.symbol->GetByteSize());
+ } else {
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
}
- return Disassemble (debugger,
- arch,
- plugin_name,
- flavor,
- exe_ctx,
- range,
- num_instructions,
- num_mixed_context_lines,
- options,
- strm);
-}
+ if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
+ range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
+ }
-Instruction::Instruction(const Address &address, AddressClass addr_class) :
- m_address (address),
- m_address_class (addr_class),
- m_opcode(),
- m_calculated_strings(false)
-{
+ return Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, range,
+ num_instructions, mixed_source_and_assembly,
+ num_mixed_context_lines, options, strm);
}
+Instruction::Instruction(const Address &address, AddressClass addr_class)
+ : m_address(address), m_address_class(addr_class), m_opcode(),
+ m_calculated_strings(false) {}
+
Instruction::~Instruction() = default;
-AddressClass
-Instruction::GetAddressClass ()
-{
- if (m_address_class == eAddressClassInvalid)
- m_address_class = m_address.GetAddressClass();
- return m_address_class;
+AddressClass Instruction::GetAddressClass() {
+ if (m_address_class == eAddressClassInvalid)
+ m_address_class = m_address.GetAddressClass();
+ return m_address_class;
}
-void
-Instruction::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)
-{
- size_t opcode_column_width = 7;
- const size_t operand_column_width = 25;
-
- CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
-
- StreamString ss;
-
- if (show_address)
- {
- Debugger::FormatDisassemblerAddress (disassembly_addr_format, sym_ctx, prev_sym_ctx, exe_ctx, &m_address, ss);
- ss.FillLastLineToColumn (max_address_text_size, ' ');
- }
-
- if (show_bytes)
- {
- if (m_opcode.GetType() == Opcode::eTypeBytes)
- {
- // x86_64 and i386 are the only ones that use bytes right now so
- // pad out the byte dump to be able to always show 15 bytes (3 chars each)
- // plus a space
- if (max_opcode_byte_size > 0)
- m_opcode.Dump (&ss, max_opcode_byte_size * 3 + 1);
- else
- m_opcode.Dump (&ss, 15 * 3 + 1);
- }
- else
- {
- // Else, we have ARM or MIPS which can show up to a uint32_t
- // 0x00000000 (10 spaces) plus two for padding...
- if (max_opcode_byte_size > 0)
- m_opcode.Dump (&ss, max_opcode_byte_size * 3 + 1);
- else
- m_opcode.Dump (&ss, 12);
- }
- }
-
- const size_t opcode_pos = ss.GetSizeOfLastLine();
-
- // The default opcode size of 7 characters is plenty for most architectures
- // but some like arm can pull out the occasional vqrshrun.s16. We won't get
- // consistent column spacing in these cases, unfortunately.
- if (m_opcode_name.length() >= opcode_column_width)
- {
- opcode_column_width = m_opcode_name.length() + 1;
- }
-
- ss.PutCString (m_opcode_name.c_str());
- ss.FillLastLineToColumn (opcode_pos + opcode_column_width, ' ');
- ss.PutCString (m_mnemonics.c_str());
-
- if (!m_comment.empty())
- {
- ss.FillLastLineToColumn (opcode_pos + opcode_column_width + operand_column_width, ' ');
- ss.PutCString (" ; ");
- ss.PutCString (m_comment.c_str());
+void Instruction::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) {
+ size_t opcode_column_width = 7;
+ const size_t operand_column_width = 25;
+
+ CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx);
+
+ StreamString ss;
+
+ if (show_address) {
+ Debugger::FormatDisassemblerAddress(disassembly_addr_format, sym_ctx,
+ prev_sym_ctx, exe_ctx, &m_address, ss);
+ ss.FillLastLineToColumn(max_address_text_size, ' ');
+ }
+
+ if (show_bytes) {
+ if (m_opcode.GetType() == Opcode::eTypeBytes) {
+ // x86_64 and i386 are the only ones that use bytes right now so
+ // pad out the byte dump to be able to always show 15 bytes (3 chars each)
+ // plus a space
+ if (max_opcode_byte_size > 0)
+ m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
+ else
+ m_opcode.Dump(&ss, 15 * 3 + 1);
+ } else {
+ // Else, we have ARM or MIPS which can show up to a uint32_t
+ // 0x00000000 (10 spaces) plus two for padding...
+ if (max_opcode_byte_size > 0)
+ m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
+ else
+ m_opcode.Dump(&ss, 12);
}
- s->Write (ss.GetData(), ss.GetSize());
+ }
+
+ const size_t opcode_pos = ss.GetSizeOfLastLine();
+
+ // The default opcode size of 7 characters is plenty for most architectures
+ // but some like arm can pull out the occasional vqrshrun.s16. We won't get
+ // consistent column spacing in these cases, unfortunately.
+ if (m_opcode_name.length() >= opcode_column_width) {
+ opcode_column_width = m_opcode_name.length() + 1;
+ }
+
+ ss.PutCString(m_opcode_name);
+ ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
+ ss.PutCString(m_mnemonics);
+
+ if (!m_comment.empty()) {
+ ss.FillLastLineToColumn(
+ opcode_pos + opcode_column_width + operand_column_width, ' ');
+ ss.PutCString(" ; ");
+ ss.PutCString(m_comment);
+ }
+ s->PutCString(ss.GetString());
}
-bool
-Instruction::DumpEmulation (const ArchSpec &arch)
-{
- std::unique_ptr<EmulateInstruction> insn_emulator_ap(EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
- if (insn_emulator_ap)
- {
- insn_emulator_ap->SetInstruction(GetOpcode(), GetAddress(), nullptr);
- return insn_emulator_ap->EvaluateInstruction (0);
- }
+bool Instruction::DumpEmulation(const ArchSpec &arch) {
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap(
+ EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
+ if (insn_emulator_ap) {
+ insn_emulator_ap->SetInstruction(GetOpcode(), GetAddress(), nullptr);
+ return insn_emulator_ap->EvaluateInstruction(0);
+ }
- return false;
+ return false;
}
-bool
-Instruction::HasDelaySlot ()
-{
- // Default is false.
- return false;
+bool Instruction::HasDelaySlot() {
+ // Default is false.
+ return false;
}
-OptionValueSP
-Instruction::ReadArray (FILE *in_file, Stream *out_stream, OptionValue::Type data_type)
-{
- bool done = false;
- char buffer[1024];
-
- OptionValueSP option_value_sp (new OptionValueArray (1u << data_type));
-
- int idx = 0;
- while (!done)
- {
- if (!fgets (buffer, 1023, in_file))
- {
- out_stream->Printf ("Instruction::ReadArray: Error reading file (fgets).\n");
- option_value_sp.reset ();
- return option_value_sp;
- }
+OptionValueSP Instruction::ReadArray(FILE *in_file, Stream *out_stream,
+ OptionValue::Type data_type) {
+ bool done = false;
+ char buffer[1024];
- std::string line (buffer);
-
- size_t len = line.size();
- if (line[len-1] == '\n')
- {
- line[len-1] = '\0';
- line.resize (len-1);
- }
+ OptionValueSP option_value_sp(new OptionValueArray(1u << data_type));
- if ((line.size() == 1) && line[0] == ']')
- {
- done = true;
- line.clear();
- }
+ int idx = 0;
+ while (!done) {
+ if (!fgets(buffer, 1023, in_file)) {
+ out_stream->Printf(
+ "Instruction::ReadArray: Error reading file (fgets).\n");
+ option_value_sp.reset();
+ return option_value_sp;
+ }
- if (!line.empty())
- {
- std::string value;
- static RegularExpression g_reg_exp ("^[ \t]*([^ \t]+)[ \t]*$");
- RegularExpression::Match regex_match(1);
- bool reg_exp_success = g_reg_exp.Execute (line.c_str(), &regex_match);
- if (reg_exp_success)
- regex_match.GetMatchAtIndex (line.c_str(), 1, value);
- else
- value = line;
-
- OptionValueSP data_value_sp;
- switch (data_type)
- {
- case OptionValue::eTypeUInt64:
- data_value_sp.reset (new OptionValueUInt64 (0, 0));
- data_value_sp->SetValueFromString (value);
- break;
- // Other types can be added later as needed.
- default:
- data_value_sp.reset (new OptionValueString (value.c_str(), ""));
- break;
- }
+ std::string line(buffer);
- option_value_sp->GetAsArray()->InsertValue (idx, data_value_sp);
- ++idx;
- }
+ size_t len = line.size();
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ line.resize(len - 1);
}
-
- return option_value_sp;
-}
-OptionValueSP
-Instruction::ReadDictionary (FILE *in_file, Stream *out_stream)
-{
- bool done = false;
- char buffer[1024];
-
- OptionValueSP option_value_sp (new OptionValueDictionary());
- static ConstString encoding_key ("data_encoding");
- OptionValue::Type data_type = OptionValue::eTypeInvalid;
-
-
- while (!done)
- {
- // Read the next line in the file
- if (!fgets (buffer, 1023, in_file))
- {
- out_stream->Printf ("Instruction::ReadDictionary: Error reading file (fgets).\n");
- option_value_sp.reset ();
- return option_value_sp;
- }
-
- // Check to see if the line contains the end-of-dictionary marker ("}")
- std::string line (buffer);
-
- size_t len = line.size();
- if (line[len-1] == '\n')
- {
- line[len-1] = '\0';
- line.resize (len-1);
- }
-
- if ((line.size() == 1) && (line[0] == '}'))
- {
- done = true;
- line.clear();
- }
-
- // Try to find a key-value pair in the current line and add it to the dictionary.
- if (!line.empty())
- {
- static RegularExpression g_reg_exp ("^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$");
- RegularExpression::Match regex_match(2);
-
- bool reg_exp_success = g_reg_exp.Execute (line.c_str(), &regex_match);
- std::string key;
- std::string value;
- if (reg_exp_success)
- {
- regex_match.GetMatchAtIndex (line.c_str(), 1, key);
- regex_match.GetMatchAtIndex (line.c_str(), 2, value);
- }
- else
- {
- out_stream->Printf ("Instruction::ReadDictionary: Failure executing regular expression.\n");
- option_value_sp.reset();
- return option_value_sp;
- }
-
- ConstString const_key (key.c_str());
- // Check value to see if it's the start of an array or dictionary.
-
- lldb::OptionValueSP value_sp;
- assert (value.empty() == false);
- assert (key.empty() == false);
-
- if (value[0] == '{')
- {
- assert (value.size() == 1);
- // value is a dictionary
- value_sp = ReadDictionary (in_file, out_stream);
- if (!value_sp)
- {
- option_value_sp.reset ();
- return option_value_sp;
- }
- }
- else if (value[0] == '[')
- {
- assert (value.size() == 1);
- // value is an array
- value_sp = ReadArray (in_file, out_stream, data_type);
- if (!value_sp)
- {
- option_value_sp.reset ();
- return option_value_sp;
- }
- // We've used the data_type to read an array; re-set the type to Invalid
- data_type = OptionValue::eTypeInvalid;
- }
- else if ((value[0] == '0') && (value[1] == 'x'))
- {
- value_sp.reset (new OptionValueUInt64 (0, 0));
- value_sp->SetValueFromString (value);
- }
- else
- {
- size_t len = value.size();
- if ((value[0] == '"') && (value[len-1] == '"'))
- value = value.substr (1, len-2);
- value_sp.reset (new OptionValueString (value.c_str(), ""));
- }
+ if ((line.size() == 1) && line[0] == ']') {
+ done = true;
+ line.clear();
+ }
- if (const_key == encoding_key)
- {
- // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data indicating the
- // data type of an upcoming array (usually the next bit of data to be read in).
- if (strcmp (value.c_str(), "uint32_t") == 0)
- data_type = OptionValue::eTypeUInt64;
- }
- else
- option_value_sp->GetAsDictionary()->SetValueForKey (const_key, value_sp, false);
- }
+ if (!line.empty()) {
+ std::string value;
+ static RegularExpression g_reg_exp(
+ llvm::StringRef("^[ \t]*([^ \t]+)[ \t]*$"));
+ RegularExpression::Match regex_match(1);
+ bool reg_exp_success = g_reg_exp.Execute(line, &regex_match);
+ if (reg_exp_success)
+ regex_match.GetMatchAtIndex(line.c_str(), 1, value);
+ else
+ value = line;
+
+ OptionValueSP data_value_sp;
+ switch (data_type) {
+ case OptionValue::eTypeUInt64:
+ data_value_sp.reset(new OptionValueUInt64(0, 0));
+ data_value_sp->SetValueFromString(value);
+ break;
+ // Other types can be added later as needed.
+ default:
+ data_value_sp.reset(new OptionValueString(value.c_str(), ""));
+ break;
+ }
+
+ option_value_sp->GetAsArray()->InsertValue(idx, data_value_sp);
+ ++idx;
}
-
- return option_value_sp;
-}
+ }
-bool
-Instruction::TestEmulation (Stream *out_stream, const char *file_name)
-{
- if (!out_stream)
- return false;
+ return option_value_sp;
+}
- if (!file_name)
- {
- out_stream->Printf ("Instruction::TestEmulation: Missing file_name.");
- return false;
+OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream *out_stream) {
+ bool done = false;
+ char buffer[1024];
+
+ OptionValueSP option_value_sp(new OptionValueDictionary());
+ static ConstString encoding_key("data_encoding");
+ OptionValue::Type data_type = OptionValue::eTypeInvalid;
+
+ while (!done) {
+ // Read the next line in the file
+ if (!fgets(buffer, 1023, in_file)) {
+ out_stream->Printf(
+ "Instruction::ReadDictionary: Error reading file (fgets).\n");
+ option_value_sp.reset();
+ return option_value_sp;
}
- FILE *test_file = FileSystem::Fopen(file_name, "r");
- if (!test_file)
- {
- out_stream->Printf ("Instruction::TestEmulation: Attempt to open test file failed.");
- return false;
+
+ // Check to see if the line contains the end-of-dictionary marker ("}")
+ std::string line(buffer);
+
+ size_t len = line.size();
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ line.resize(len - 1);
}
- char buffer[256];
- if (!fgets (buffer, 255, test_file))
- {
- out_stream->Printf ("Instruction::TestEmulation: Error reading first line of test file.\n");
- fclose (test_file);
- return false;
+ if ((line.size() == 1) && (line[0] == '}')) {
+ done = true;
+ line.clear();
}
-
- if (strncmp (buffer, "InstructionEmulationState={", 27) != 0)
- {
- out_stream->Printf ("Instructin::TestEmulation: Test file does not contain emulation state dictionary\n");
- fclose (test_file);
- return false;
+
+ // Try to find a key-value pair in the current line and add it to the
+ // dictionary.
+ if (!line.empty()) {
+ static RegularExpression g_reg_exp(llvm::StringRef(
+ "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$"));
+ RegularExpression::Match regex_match(2);
+
+ bool reg_exp_success = g_reg_exp.Execute(line, &regex_match);
+ std::string key;
+ std::string value;
+ if (reg_exp_success) {
+ regex_match.GetMatchAtIndex(line.c_str(), 1, key);
+ regex_match.GetMatchAtIndex(line.c_str(), 2, value);
+ } else {
+ out_stream->Printf("Instruction::ReadDictionary: Failure executing "
+ "regular expression.\n");
+ option_value_sp.reset();
+ return option_value_sp;
+ }
+
+ ConstString const_key(key.c_str());
+ // Check value to see if it's the start of an array or dictionary.
+
+ lldb::OptionValueSP value_sp;
+ assert(value.empty() == false);
+ assert(key.empty() == false);
+
+ if (value[0] == '{') {
+ assert(value.size() == 1);
+ // value is a dictionary
+ value_sp = ReadDictionary(in_file, out_stream);
+ if (!value_sp) {
+ option_value_sp.reset();
+ return option_value_sp;
+ }
+ } else if (value[0] == '[') {
+ assert(value.size() == 1);
+ // value is an array
+ value_sp = ReadArray(in_file, out_stream, data_type);
+ if (!value_sp) {
+ option_value_sp.reset();
+ return option_value_sp;
+ }
+ // We've used the data_type to read an array; re-set the type to Invalid
+ data_type = OptionValue::eTypeInvalid;
+ } else if ((value[0] == '0') && (value[1] == 'x')) {
+ value_sp.reset(new OptionValueUInt64(0, 0));
+ value_sp->SetValueFromString(value);
+ } else {
+ size_t len = value.size();
+ if ((value[0] == '"') && (value[len - 1] == '"'))
+ value = value.substr(1, len - 2);
+ value_sp.reset(new OptionValueString(value.c_str(), ""));
+ }
+
+ if (const_key == encoding_key) {
+ // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data
+ // indicating the
+ // data type of an upcoming array (usually the next bit of data to be
+ // read in).
+ if (strcmp(value.c_str(), "uint32_t") == 0)
+ data_type = OptionValue::eTypeUInt64;
+ } else
+ option_value_sp->GetAsDictionary()->SetValueForKey(const_key, value_sp,
+ false);
}
+ }
- // Read all the test information from the test file into an OptionValueDictionary.
+ return option_value_sp;
+}
- OptionValueSP data_dictionary_sp (ReadDictionary (test_file, out_stream));
- if (!data_dictionary_sp)
- {
- out_stream->Printf ("Instruction::TestEmulation: Error reading Dictionary Object.\n");
- fclose (test_file);
- return false;
- }
+bool Instruction::TestEmulation(Stream *out_stream, const char *file_name) {
+ if (!out_stream)
+ return false;
- fclose (test_file);
+ if (!file_name) {
+ out_stream->Printf("Instruction::TestEmulation: Missing file_name.");
+ return false;
+ }
+ FILE *test_file = FileSystem::Fopen(file_name, "r");
+ if (!test_file) {
+ out_stream->Printf(
+ "Instruction::TestEmulation: Attempt to open test file failed.");
+ return false;
+ }
- OptionValueDictionary *data_dictionary = data_dictionary_sp->GetAsDictionary();
- static ConstString description_key ("assembly_string");
- static ConstString triple_key ("triple");
+ char buffer[256];
+ if (!fgets(buffer, 255, test_file)) {
+ out_stream->Printf(
+ "Instruction::TestEmulation: Error reading first line of test file.\n");
+ fclose(test_file);
+ return false;
+ }
- OptionValueSP value_sp = data_dictionary->GetValueForKey (description_key);
-
- if (!value_sp)
- {
- out_stream->Printf ("Instruction::TestEmulation: Test file does not contain description string.\n");
- return false;
- }
+ if (strncmp(buffer, "InstructionEmulationState={", 27) != 0) {
+ out_stream->Printf("Instructin::TestEmulation: Test file does not contain "
+ "emulation state dictionary\n");
+ fclose(test_file);
+ return false;
+ }
- SetDescription (value_sp->GetStringValue());
+ // Read all the test information from the test file into an
+ // OptionValueDictionary.
- value_sp = data_dictionary->GetValueForKey (triple_key);
- if (!value_sp)
- {
- out_stream->Printf ("Instruction::TestEmulation: Test file does not contain triple.\n");
- return false;
- }
-
- ArchSpec arch;
- arch.SetTriple (llvm::Triple (value_sp->GetStringValue()));
-
- bool success = false;
- std::unique_ptr<EmulateInstruction> insn_emulator_ap(EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
- if (insn_emulator_ap)
- success = insn_emulator_ap->TestEmulation (out_stream, arch, data_dictionary);
-
- if (success)
- out_stream->Printf ("Emulation test succeeded.");
- else
- out_stream->Printf ("Emulation test failed.");
-
- return success;
-}
+ OptionValueSP data_dictionary_sp(ReadDictionary(test_file, out_stream));
+ if (!data_dictionary_sp) {
+ out_stream->Printf(
+ "Instruction::TestEmulation: Error reading Dictionary Object.\n");
+ fclose(test_file);
+ return false;
+ }
-bool
-Instruction::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)
-{
- std::unique_ptr<EmulateInstruction> insn_emulator_ap(EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
- if (insn_emulator_ap)
- {
- insn_emulator_ap->SetBaton(baton);
- insn_emulator_ap->SetCallbacks(read_mem_callback, write_mem_callback, read_reg_callback, write_reg_callback);
- insn_emulator_ap->SetInstruction(GetOpcode(), GetAddress(), nullptr);
- return insn_emulator_ap->EvaluateInstruction(evaluate_options);
- }
+ fclose(test_file);
+
+ OptionValueDictionary *data_dictionary =
+ data_dictionary_sp->GetAsDictionary();
+ static ConstString description_key("assembly_string");
+ static ConstString triple_key("triple");
+
+ OptionValueSP value_sp = data_dictionary->GetValueForKey(description_key);
+ if (!value_sp) {
+ out_stream->Printf("Instruction::TestEmulation: Test file does not "
+ "contain description string.\n");
return false;
-}
+ }
-uint32_t
-Instruction::GetData (DataExtractor &data)
-{
- return m_opcode.GetData(data);
-}
+ SetDescription(value_sp->GetStringValue());
-InstructionList::InstructionList() :
- m_instructions()
-{
-}
+ value_sp = data_dictionary->GetValueForKey(triple_key);
+ if (!value_sp) {
+ out_stream->Printf(
+ "Instruction::TestEmulation: Test file does not contain triple.\n");
+ return false;
+ }
-InstructionList::~InstructionList() = default;
+ ArchSpec arch;
+ arch.SetTriple(llvm::Triple(value_sp->GetStringValue()));
-size_t
-InstructionList::GetSize() const
-{
- return m_instructions.size();
+ bool success = false;
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap(
+ EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
+ if (insn_emulator_ap)
+ success =
+ insn_emulator_ap->TestEmulation(out_stream, arch, data_dictionary);
+
+ if (success)
+ out_stream->Printf("Emulation test succeeded.");
+ else
+ out_stream->Printf("Emulation test failed.");
+
+ return success;
}
-uint32_t
-InstructionList::GetMaxOpcocdeByteSize () const
-{
- uint32_t max_inst_size = 0;
- collection::const_iterator pos, end;
- for (pos = m_instructions.begin(), end = m_instructions.end();
- pos != end;
- ++pos)
- {
- uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();
- if (max_inst_size < inst_size)
- max_inst_size = inst_size;
- }
- return max_inst_size;
+bool Instruction::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) {
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap(
+ EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
+ if (insn_emulator_ap) {
+ insn_emulator_ap->SetBaton(baton);
+ insn_emulator_ap->SetCallbacks(read_mem_callback, write_mem_callback,
+ read_reg_callback, write_reg_callback);
+ insn_emulator_ap->SetInstruction(GetOpcode(), GetAddress(), nullptr);
+ return insn_emulator_ap->EvaluateInstruction(evaluate_options);
+ }
+
+ return false;
}
-InstructionSP
-InstructionList::GetInstructionAtIndex (size_t idx) const
-{
- InstructionSP inst_sp;
- if (idx < m_instructions.size())
- inst_sp = m_instructions[idx];
- return inst_sp;
+uint32_t Instruction::GetData(DataExtractor &data) {
+ return m_opcode.GetData(data);
}
-void
-InstructionList::Dump (Stream *s,
- bool show_address,
- bool show_bytes,
- const ExecutionContext* exe_ctx)
-{
- const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
- collection::const_iterator pos, begin, end;
-
- const FormatEntity::Entry *disassembly_format = nullptr;
- FormatEntity::Entry format;
- if (exe_ctx && exe_ctx->HasTargetScope())
- {
- disassembly_format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat ();
- }
- else
- {
- FormatEntity::Parse("${addr}: ", format);
- disassembly_format = &format;
- }
+InstructionList::InstructionList() : m_instructions() {}
- for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
- pos != end;
- ++pos)
- {
- if (pos != begin)
- s->EOL();
- (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, nullptr, nullptr, disassembly_format, 0);
- }
+InstructionList::~InstructionList() = default;
+
+size_t InstructionList::GetSize() const { return m_instructions.size(); }
+
+uint32_t InstructionList::GetMaxOpcocdeByteSize() const {
+ uint32_t max_inst_size = 0;
+ collection::const_iterator pos, end;
+ for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end;
+ ++pos) {
+ uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();
+ if (max_inst_size < inst_size)
+ max_inst_size = inst_size;
+ }
+ return max_inst_size;
}
-void
-InstructionList::Clear()
-{
- m_instructions.clear();
+InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const {
+ InstructionSP inst_sp;
+ if (idx < m_instructions.size())
+ inst_sp = m_instructions[idx];
+ return inst_sp;
}
-void
-InstructionList::Append (lldb::InstructionSP &inst_sp)
-{
- if (inst_sp)
- m_instructions.push_back(inst_sp);
+void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,
+ const ExecutionContext *exe_ctx) {
+ const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
+ collection::const_iterator pos, begin, end;
+
+ const FormatEntity::Entry *disassembly_format = nullptr;
+ FormatEntity::Entry format;
+ if (exe_ctx && exe_ctx->HasTargetScope()) {
+ disassembly_format =
+ exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
+ } else {
+ FormatEntity::Parse("${addr}: ", format);
+ disassembly_format = &format;
+ }
+
+ for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
+ pos != end; ++pos) {
+ if (pos != begin)
+ s->EOL();
+ (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx,
+ nullptr, nullptr, disassembly_format, 0);
+ }
+}
+
+void InstructionList::Clear() { m_instructions.clear(); }
+
+void InstructionList::Append(lldb::InstructionSP &inst_sp) {
+ if (inst_sp)
+ m_instructions.push_back(inst_sp);
}
uint32_t
-InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, Target &target) const
-{
- size_t num_instructions = m_instructions.size();
-
- uint32_t next_branch = UINT32_MAX;
- size_t i;
- for (i = start; i < num_instructions; i++)
- {
- if (m_instructions[i]->DoesBranch())
- {
- next_branch = i;
- break;
- }
+InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
+ Target &target) const {
+ size_t num_instructions = m_instructions.size();
+
+ uint32_t next_branch = UINT32_MAX;
+ size_t i;
+ for (i = start; i < num_instructions; i++) {
+ if (m_instructions[i]->DoesBranch()) {
+ next_branch = i;
+ break;
+ }
+ }
+
+ // Hexagon needs the first instruction of the packet with the branch.
+ // Go backwards until we find an instruction marked end-of-packet, or
+ // until we hit start.
+ if (target.GetArchitecture().GetTriple().getArch() == llvm::Triple::hexagon) {
+ // If we didn't find a branch, find the last packet start.
+ if (next_branch == UINT32_MAX) {
+ i = num_instructions - 1;
}
- // Hexagon needs the first instruction of the packet with the branch.
- // Go backwards until we find an instruction marked end-of-packet, or
- // until we hit start.
- if (target.GetArchitecture().GetTriple().getArch() == llvm::Triple::hexagon)
- {
- // If we didn't find a branch, find the last packet start.
- if (next_branch == UINT32_MAX)
- {
- i = num_instructions - 1;
- }
-
- while (i > start)
- {
- --i;
-
- Error error;
- uint32_t inst_bytes;
- bool prefer_file_cache = false; // Read from process if process is running
- lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
- target.ReadMemory(m_instructions[i]->GetAddress(),
- prefer_file_cache,
- &inst_bytes,
- sizeof(inst_bytes),
- error,
- &load_addr);
- // If we have an error reading memory, return start
- if (!error.Success())
- return start;
- // check if this is the last instruction in a packet
- // bits 15:14 will be 11b or 00b for a duplex
- if (((inst_bytes & 0xC000) == 0xC000) ||
- ((inst_bytes & 0xC000) == 0x0000))
- {
- // instruction after this should be the start of next packet
- next_branch = i + 1;
- break;
- }
- }
+ while (i > start) {
+ --i;
+
+ Error error;
+ uint32_t inst_bytes;
+ bool prefer_file_cache = false; // Read from process if process is running
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ target.ReadMemory(m_instructions[i]->GetAddress(), prefer_file_cache,
+ &inst_bytes, sizeof(inst_bytes), error, &load_addr);
+ // If we have an error reading memory, return start
+ if (!error.Success())
+ return start;
+ // check if this is the last instruction in a packet
+ // bits 15:14 will be 11b or 00b for a duplex
+ if (((inst_bytes & 0xC000) == 0xC000) ||
+ ((inst_bytes & 0xC000) == 0x0000)) {
+ // instruction after this should be the start of next packet
+ next_branch = i + 1;
+ break;
+ }
+ }
- if (next_branch == UINT32_MAX)
- {
- // We couldn't find the previous packet, so return start
- next_branch = start;
- }
+ if (next_branch == UINT32_MAX) {
+ // We couldn't find the previous packet, so return start
+ next_branch = start;
}
- return next_branch;
+ }
+ return next_branch;
}
uint32_t
-InstructionList::GetIndexOfInstructionAtAddress (const Address &address)
-{
- size_t num_instructions = m_instructions.size();
- uint32_t index = UINT32_MAX;
- for (size_t i = 0; i < num_instructions; i++)
- {
- if (m_instructions[i]->GetAddress() == address)
- {
- index = i;
- break;
- }
+InstructionList::GetIndexOfInstructionAtAddress(const Address &address) {
+ size_t num_instructions = m_instructions.size();
+ uint32_t index = UINT32_MAX;
+ for (size_t i = 0; i < num_instructions; i++) {
+ if (m_instructions[i]->GetAddress() == address) {
+ index = i;
+ break;
}
- return index;
+ }
+ return index;
}
uint32_t
-InstructionList::GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target)
-{
- Address address;
- address.SetLoadAddress(load_addr, &target);
- return GetIndexOfInstructionAtAddress(address);
+InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,
+ Target &target) {
+ Address address;
+ address.SetLoadAddress(load_addr, &target);
+ return GetIndexOfInstructionAtAddress(address);
}
-size_t
-Disassembler::ParseInstructions (const ExecutionContext *exe_ctx,
- const AddressRange &range,
- Stream *error_strm_ptr,
- bool prefer_file_cache)
-{
- if (exe_ctx)
- {
- Target *target = exe_ctx->GetTargetPtr();
- const addr_t byte_size = range.GetByteSize();
- if (target == nullptr || byte_size == 0 || !range.GetBaseAddress().IsValid())
- return 0;
-
- DataBufferHeap *heap_buffer = new DataBufferHeap (byte_size, '\0');
- DataBufferSP data_sp(heap_buffer);
-
- Error error;
- lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
- const size_t bytes_read = target->ReadMemory (range.GetBaseAddress(),
- prefer_file_cache,
- heap_buffer->GetBytes(),
- heap_buffer->GetByteSize(),
- error,
- &load_addr);
-
- if (bytes_read > 0)
- {
- if (bytes_read != heap_buffer->GetByteSize())
- heap_buffer->SetByteSize (bytes_read);
- DataExtractor data (data_sp,
- m_arch.GetByteOrder(),
- m_arch.GetAddressByteSize());
- const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
- return DecodeInstructions(range.GetBaseAddress(), data, 0, UINT32_MAX, false,
- data_from_file);
- }
- else if (error_strm_ptr)
- {
- const char *error_cstr = error.AsCString();
- if (error_cstr)
- {
- error_strm_ptr->Printf("error: %s\n", error_cstr);
- }
- }
- }
- else if (error_strm_ptr)
- {
- error_strm_ptr->PutCString("error: invalid execution context\n");
+size_t Disassembler::ParseInstructions(const ExecutionContext *exe_ctx,
+ const AddressRange &range,
+ Stream *error_strm_ptr,
+ bool prefer_file_cache) {
+ if (exe_ctx) {
+ Target *target = exe_ctx->GetTargetPtr();
+ const addr_t byte_size = range.GetByteSize();
+ if (target == nullptr || byte_size == 0 ||
+ !range.GetBaseAddress().IsValid())
+ return 0;
+
+ DataBufferHeap *heap_buffer = new DataBufferHeap(byte_size, '\0');
+ DataBufferSP data_sp(heap_buffer);
+
+ Error error;
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ const size_t bytes_read = target->ReadMemory(
+ range.GetBaseAddress(), prefer_file_cache, heap_buffer->GetBytes(),
+ heap_buffer->GetByteSize(), error, &load_addr);
+
+ if (bytes_read > 0) {
+ if (bytes_read != heap_buffer->GetByteSize())
+ heap_buffer->SetByteSize(bytes_read);
+ DataExtractor data(data_sp, m_arch.GetByteOrder(),
+ m_arch.GetAddressByteSize());
+ const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
+ return DecodeInstructions(range.GetBaseAddress(), data, 0, UINT32_MAX,
+ false, data_from_file);
+ } else if (error_strm_ptr) {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr) {
+ error_strm_ptr->Printf("error: %s\n", error_cstr);
+ }
}
- return 0;
+ } else if (error_strm_ptr) {
+ error_strm_ptr->PutCString("error: invalid execution context\n");
+ }
+ return 0;
}
-size_t
-Disassembler::ParseInstructions (const ExecutionContext *exe_ctx,
- const Address &start,
- uint32_t num_instructions,
- bool prefer_file_cache)
-{
- m_instruction_list.Clear();
+size_t Disassembler::ParseInstructions(const ExecutionContext *exe_ctx,
+ const Address &start,
+ uint32_t num_instructions,
+ bool prefer_file_cache) {
+ m_instruction_list.Clear();
- if (exe_ctx == nullptr || num_instructions == 0 || !start.IsValid())
- return 0;
-
- Target *target = exe_ctx->GetTargetPtr();
- // Calculate the max buffer size we will need in order to disassemble
- const addr_t byte_size = num_instructions * m_arch.GetMaximumOpcodeByteSize();
-
- if (target == nullptr || byte_size == 0)
- return 0;
+ if (exe_ctx == nullptr || num_instructions == 0 || !start.IsValid())
+ return 0;
- DataBufferHeap *heap_buffer = new DataBufferHeap (byte_size, '\0');
- DataBufferSP data_sp (heap_buffer);
+ Target *target = exe_ctx->GetTargetPtr();
+ // Calculate the max buffer size we will need in order to disassemble
+ const addr_t byte_size = num_instructions * m_arch.GetMaximumOpcodeByteSize();
- Error error;
- lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
- const size_t bytes_read = target->ReadMemory (start,
- prefer_file_cache,
- heap_buffer->GetBytes(),
- byte_size,
- error,
- &load_addr);
-
- const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
-
- if (bytes_read == 0)
- return 0;
- DataExtractor data (data_sp,
- m_arch.GetByteOrder(),
- m_arch.GetAddressByteSize());
-
- const bool append_instructions = true;
- DecodeInstructions (start,
- data,
- 0,
- num_instructions,
- append_instructions,
- data_from_file);
-
- return m_instruction_list.GetSize();
+ if (target == nullptr || byte_size == 0)
+ return 0;
+
+ DataBufferHeap *heap_buffer = new DataBufferHeap(byte_size, '\0');
+ DataBufferSP data_sp(heap_buffer);
+
+ Error error;
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ const size_t bytes_read =
+ target->ReadMemory(start, prefer_file_cache, heap_buffer->GetBytes(),
+ byte_size, error, &load_addr);
+
+ const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
+
+ if (bytes_read == 0)
+ return 0;
+ DataExtractor data(data_sp, m_arch.GetByteOrder(),
+ m_arch.GetAddressByteSize());
+
+ const bool append_instructions = true;
+ DecodeInstructions(start, data, 0, num_instructions, append_instructions,
+ data_from_file);
+
+ return m_instruction_list.GetSize();
}
//----------------------------------------------------------------------
// Disassembler copy constructor
//----------------------------------------------------------------------
-Disassembler::Disassembler(const ArchSpec& arch, const char *flavor) :
- m_arch (arch),
- m_instruction_list(),
- m_base_addr(LLDB_INVALID_ADDRESS),
- m_flavor ()
-{
- if (flavor == nullptr)
- m_flavor.assign("default");
- else
- m_flavor.assign(flavor);
-
- // If this is an arm variant that can only include thumb (T16, T32)
- // instructions, force the arch triple to be "thumbv.." instead of
- // "armv..."
- if (arch.IsAlwaysThumbInstructions())
- {
- std::string thumb_arch_name (arch.GetTriple().getArchName().str());
- // Replace "arm" with "thumb" so we get all thumb variants correct
- if (thumb_arch_name.size() > 3)
- {
- thumb_arch_name.erase(0, 3);
- thumb_arch_name.insert(0, "thumb");
- }
- m_arch.SetTriple (thumb_arch_name.c_str());
+Disassembler::Disassembler(const ArchSpec &arch, const char *flavor)
+ : m_arch(arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS),
+ m_flavor() {
+ if (flavor == nullptr)
+ m_flavor.assign("default");
+ else
+ m_flavor.assign(flavor);
+
+ // If this is an arm variant that can only include thumb (T16, T32)
+ // instructions, force the arch triple to be "thumbv.." instead of
+ // "armv..."
+ if (arch.IsAlwaysThumbInstructions()) {
+ std::string thumb_arch_name(arch.GetTriple().getArchName().str());
+ // Replace "arm" with "thumb" so we get all thumb variants correct
+ if (thumb_arch_name.size() > 3) {
+ thumb_arch_name.erase(0, 3);
+ thumb_arch_name.insert(0, "thumb");
}
+ m_arch.SetTriple(thumb_arch_name.c_str());
+ }
}
Disassembler::~Disassembler() = default;
-InstructionList &
-Disassembler::GetInstructionList ()
-{
- return m_instruction_list;
+InstructionList &Disassembler::GetInstructionList() {
+ return m_instruction_list;
}
-const InstructionList &
-Disassembler::GetInstructionList () const
-{
- return m_instruction_list;
+const InstructionList &Disassembler::GetInstructionList() const {
+ return m_instruction_list;
}
//----------------------------------------------------------------------
// Class PseudoInstruction
//----------------------------------------------------------------------
-PseudoInstruction::PseudoInstruction () :
- Instruction (Address(), eAddressClassUnknown),
- m_description ()
-{
-}
+PseudoInstruction::PseudoInstruction()
+ : Instruction(Address(), eAddressClassUnknown), m_description() {}
PseudoInstruction::~PseudoInstruction() = default;
-
-bool
-PseudoInstruction::DoesBranch ()
-{
- // This is NOT a valid question for a pseudo instruction.
- return false;
+
+bool PseudoInstruction::DoesBranch() {
+ // This is NOT a valid question for a pseudo instruction.
+ return false;
}
-
-bool
-PseudoInstruction::HasDelaySlot ()
-{
- // This is NOT a valid question for a pseudo instruction.
- return false;
+
+bool PseudoInstruction::HasDelaySlot() {
+ // This is NOT a valid question for a pseudo instruction.
+ return false;
}
-size_t
-PseudoInstruction::Decode (const lldb_private::Disassembler &disassembler,
- const lldb_private::DataExtractor &data,
- lldb::offset_t data_offset)
-{
- return m_opcode.GetByteSize();
+size_t PseudoInstruction::Decode(const lldb_private::Disassembler &disassembler,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t data_offset) {
+ return m_opcode.GetByteSize();
}
-void
-PseudoInstruction::SetOpcode (size_t opcode_size, void *opcode_data)
-{
- if (!opcode_data)
- return;
+void PseudoInstruction::SetOpcode(size_t opcode_size, void *opcode_data) {
+ if (!opcode_data)
+ return;
+
+ switch (opcode_size) {
+ case 8: {
+ uint8_t value8 = *((uint8_t *)opcode_data);
+ m_opcode.SetOpcode8(value8, eByteOrderInvalid);
+ break;
+ }
+ case 16: {
+ uint16_t value16 = *((uint16_t *)opcode_data);
+ m_opcode.SetOpcode16(value16, eByteOrderInvalid);
+ break;
+ }
+ case 32: {
+ uint32_t value32 = *((uint32_t *)opcode_data);
+ m_opcode.SetOpcode32(value32, eByteOrderInvalid);
+ break;
+ }
+ case 64: {
+ uint64_t value64 = *((uint64_t *)opcode_data);
+ m_opcode.SetOpcode64(value64, eByteOrderInvalid);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void PseudoInstruction::SetDescription(llvm::StringRef description) {
+ m_description = description;
+}
+
+Instruction::Operand Instruction::Operand::BuildRegister(ConstString &r) {
+ Operand ret;
+ ret.m_type = Type::Register;
+ ret.m_register = r;
+ return ret;
+}
+
+Instruction::Operand Instruction::Operand::BuildImmediate(lldb::addr_t imm,
+ bool neg) {
+ Operand ret;
+ ret.m_type = Type::Immediate;
+ ret.m_immediate = imm;
+ ret.m_negative = neg;
+ return ret;
+}
+
+Instruction::Operand Instruction::Operand::BuildImmediate(int64_t imm) {
+ Operand ret;
+ ret.m_type = Type::Immediate;
+ if (imm < 0) {
+ ret.m_immediate = -imm;
+ ret.m_negative = true;
+ } else {
+ ret.m_immediate = imm;
+ ret.m_negative = false;
+ }
+ return ret;
+}
+
+Instruction::Operand
+Instruction::Operand::BuildDereference(const Operand &ref) {
+ Operand ret;
+ ret.m_type = Type::Dereference;
+ ret.m_children = {ref};
+ return ret;
+}
+
+Instruction::Operand Instruction::Operand::BuildSum(const Operand &lhs,
+ const Operand &rhs) {
+ Operand ret;
+ ret.m_type = Type::Sum;
+ ret.m_children = {lhs, rhs};
+ return ret;
+}
+
+Instruction::Operand Instruction::Operand::BuildProduct(const Operand &lhs,
+ const Operand &rhs) {
+ Operand ret;
+ ret.m_type = Type::Product;
+ ret.m_children = {lhs, rhs};
+ return ret;
+}
+
+std::function<bool(const Instruction::Operand &)>
+lldb_private::OperandMatchers::MatchBinaryOp(
+ std::function<bool(const Instruction::Operand &)> base,
+ std::function<bool(const Instruction::Operand &)> left,
+ std::function<bool(const Instruction::Operand &)> right) {
+ return [base, left, right](const Instruction::Operand &op) -> bool {
+ return (base(op) && op.m_children.size() == 2 &&
+ ((left(op.m_children[0]) && right(op.m_children[1])) ||
+ (left(op.m_children[1]) && right(op.m_children[0]))));
+ };
+}
- switch (opcode_size)
- {
- case 8:
- {
- uint8_t value8 = *((uint8_t *) opcode_data);
- m_opcode.SetOpcode8 (value8, eByteOrderInvalid);
- break;
- }
- case 16:
- {
- uint16_t value16 = *((uint16_t *) opcode_data);
- m_opcode.SetOpcode16 (value16, eByteOrderInvalid);
- break;
- }
- case 32:
- {
- uint32_t value32 = *((uint32_t *) opcode_data);
- m_opcode.SetOpcode32 (value32, eByteOrderInvalid);
- break;
- }
- case 64:
- {
- uint64_t value64 = *((uint64_t *) opcode_data);
- m_opcode.SetOpcode64 (value64, eByteOrderInvalid);
- break;
- }
- default:
- break;
+std::function<bool(const Instruction::Operand &)>
+lldb_private::OperandMatchers::MatchUnaryOp(
+ std::function<bool(const Instruction::Operand &)> base,
+ std::function<bool(const Instruction::Operand &)> child) {
+ return [base, child](const Instruction::Operand &op) -> bool {
+ return (base(op) && op.m_children.size() == 1 && child(op.m_children[0]));
+ };
+}
+
+std::function<bool(const Instruction::Operand &)>
+lldb_private::OperandMatchers::MatchRegOp(const RegisterInfo &info) {
+ return [&info](const Instruction::Operand &op) {
+ return (op.m_type == Instruction::Operand::Type::Register &&
+ (op.m_register == ConstString(info.name) ||
+ op.m_register == ConstString(info.alt_name)));
+ };
+}
+
+std::function<bool(const Instruction::Operand &)>
+lldb_private::OperandMatchers::FetchRegOp(ConstString &reg) {
+ return [&reg](const Instruction::Operand &op) {
+ if (op.m_type != Instruction::Operand::Type::Register) {
+ return false;
}
+ reg = op.m_register;
+ return true;
+ };
}
-void
-PseudoInstruction::SetDescription (const char *description)
-{
- if (description && strlen (description) > 0)
- m_description = description;
+std::function<bool(const Instruction::Operand &)>
+lldb_private::OperandMatchers::MatchImmOp(int64_t imm) {
+ return [imm](const Instruction::Operand &op) {
+ return (op.m_type == Instruction::Operand::Type::Immediate &&
+ ((op.m_negative && op.m_immediate == (uint64_t)-imm) ||
+ (!op.m_negative && op.m_immediate == (uint64_t)imm)));
+ };
}
+
+std::function<bool(const Instruction::Operand &)>
+lldb_private::OperandMatchers::FetchImmOp(int64_t &imm) {
+ return [&imm](const Instruction::Operand &op) {
+ if (op.m_type != Instruction::Operand::Type::Immediate) {
+ return false;
+ }
+ if (op.m_negative) {
+ imm = -((int64_t)op.m_immediate);
+ } else {
+ imm = ((int64_t)op.m_immediate);
+ }
+ return true;
+ };
+}
+
+std::function<bool(const Instruction::Operand &)>
+lldb_private::OperandMatchers::MatchOpType(Instruction::Operand::Type type) {
+ return [type](const Instruction::Operand &op) { return op.m_type == type; };
+}
+