summaryrefslogtreecommitdiffstats
path: root/source/Core/Disassembler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core/Disassembler.cpp')
-rw-r--r--source/Core/Disassembler.cpp1269
1 files changed, 1269 insertions, 0 deletions
diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp
new file mode 100644
index 0000000..e80e92c
--- /dev/null
+++ b/source/Core/Disassembler.cpp
@@ -0,0 +1,1269 @@
+//===-- Disassembler.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Core/Disassembler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+#define DEFAULT_DISASM_BYTE_SIZE 32
+
+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 = NULL;
+
+ 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.get())
+ return disassembler_sp;
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ DisassemblerSP disassembler_sp(create_callback(arch, flavor));
+
+ if (disassembler_sp.get())
+ return disassembler_sp;
+ }
+ }
+ return DisassemblerSP();
+}
+
+DisassemblerSP
+Disassembler::FindPluginForTarget(const TargetSP target_sp, const ArchSpec &arch, const char *flavor, const char *plugin_name)
+{
+ if (target_sp && flavor == NULL)
+ {
+ // 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;
+ }
+ }
+ 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) == false)
+ 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();
+ }
+ }
+ }
+ 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,
+ NULL,
+ 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);
+ }
+ return false;
+}
+
+
+lldb::DisassemblerSP
+Disassembler::DisassembleRange
+(
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const AddressRange &range
+)
+{
+ 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)
+ {
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, NULL, prefer_file_cache);
+ if (bytes_disassembled == 0)
+ disasm_sp.reset();
+ }
+ }
+ 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);
+ }
+ }
+
+ return disasm_sp;
+}
+
+
+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.get())
+ {
+ 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;
+
+ bool result = PrintInstructions (disasm_sp.get(),
+ debugger,
+ arch,
+ exe_ctx,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disasm_sp->GetInstructionList().Clear();
+ return result;
+ }
+ }
+ 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.get())
+ {
+ 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;
+ bool result = PrintInstructions (disasm_sp.get(),
+ debugger,
+ arch,
+ exe_ctx,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disasm_sp->GetInstructionList().Clear();
+ return result;
+ }
+ }
+ return false;
+}
+
+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 = NULL;
+ ExecutionContextScope *exe_scope = exe_ctx.GetBestExecutionContextScope();
+ 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;
+ 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);
+ 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);
+ }
+ }
+ }
+ }
+ else if ((sc.function || sc.symbol) && (sc.function != prev_sc.function || sc.symbol != prev_sc.symbol))
+ {
+ if (prev_sc.function || prev_sc.symbol)
+ strm.EOL();
+
+ bool show_fullpaths = false;
+ bool show_module = true;
+ bool show_inlined_frames = true;
+ sc.DumpStopContext (&strm,
+ exe_scope,
+ addr,
+ show_fullpaths,
+ show_module,
+ show_inlined_frames);
+
+ strm << ":\n";
+ }
+ }
+ else
+ {
+ sc.Clear(true);
+ }
+ }
+
+ if ((options & eOptionMarkPCAddress) && pc_addr_ptr)
+ {
+ strm.PutCString(inst_is_at_pc ? "-> " : " ");
+ }
+ const bool show_bytes = (options & eOptionShowBytes) != 0;
+ inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx);
+ 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->GetAddress();
+ range.SetByteSize (sc.symbol->GetByteSize());
+ }
+ else
+ {
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ }
+
+ if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
+ range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
+ }
+
+ return Disassemble (debugger,
+ arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ range,
+ num_instructions,
+ 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()
+{
+}
+
+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)
+{
+ size_t opcode_column_width = 7;
+ const size_t operand_column_width = 25;
+
+ CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
+
+ StreamString ss;
+
+ if (show_address)
+ {
+ m_address.Dump(&ss,
+ exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL,
+ Address::DumpStyleLoadAddress,
+ Address::DumpStyleModuleWithFileAddress,
+ 0);
+
+ ss.PutCString(": ");
+ }
+
+ 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 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.GetSize();
+
+ // 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());
+ }
+ s->Write (ss.GetData(), ss.GetSize());
+}
+
+bool
+Instruction::DumpEmulation (const ArchSpec &arch)
+{
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypeAny, NULL));
+ if (insn_emulator_ap.get())
+ {
+ insn_emulator_ap->SetInstruction (GetOpcode(), GetAddress(), NULL);
+ return insn_emulator_ap->EvaluateInstruction (0);
+ }
+
+ 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;
+ }
+
+ 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();
+ }
+
+ if (line.size() > 0)
+ {
+ 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->SetValueFromCString (value.c_str());
+ 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;
+}
+
+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.size() > 0)
+ {
+ 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.get() == NULL)
+ {
+ 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.get() == NULL)
+ {
+ 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->SetValueFromCString (value.c_str());
+ }
+ 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);
+ }
+ }
+
+ return option_value_sp;
+}
+
+bool
+Instruction::TestEmulation (Stream *out_stream, const char *file_name)
+{
+ if (!out_stream)
+ return false;
+
+ if (!file_name)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Missing file_name.");
+ return false;
+ }
+
+ FILE *test_file = fopen (file_name, "r");
+ if (!test_file)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Attempt to open test file failed.");
+ return false;
+ }
+
+ 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 (strncmp (buffer, "InstructionEmulationState={", 27) != 0)
+ {
+ out_stream->Printf ("Instructin::TestEmulation: Test file does not contain emulation state dictionary\n");
+ fclose (test_file);
+ return false;
+ }
+
+ // Read all the test information from the test file into an OptionValueDictionary.
+
+ OptionValueSP data_dictionary_sp (ReadDictionary (test_file, out_stream));
+ if (data_dictionary_sp.get() == NULL)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Error reading Dictionary Object.\n");
+ fclose (test_file);
+ return false;
+ }
+
+ 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.get() == NULL)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Test file does not contain description string.\n");
+ return false;
+ }
+
+ SetDescription (value_sp->GetStringValue());
+
+
+ value_sp = data_dictionary->GetValueForKey (triple_key);
+ if (value_sp.get() == NULL)
+ {
+ 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, NULL));
+ if (insn_emulator_ap.get())
+ 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;
+}
+
+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, NULL));
+ if (insn_emulator_ap.get())
+ {
+ 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(), NULL);
+ return insn_emulator_ap->EvaluateInstruction (evaluate_options);
+ }
+
+ return false;
+}
+
+
+uint32_t
+Instruction::GetData (DataExtractor &data)
+{
+ return m_opcode.GetData(data);
+}
+
+InstructionList::InstructionList() :
+ m_instructions()
+{
+}
+
+InstructionList::~InstructionList()
+{
+}
+
+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;
+}
+
+
+
+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::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;
+ 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);
+ }
+}
+
+
+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) const
+{
+ size_t num_instructions = m_instructions.size();
+
+ uint32_t next_branch = UINT32_MAX;
+ for (size_t i = start; i < num_instructions; i++)
+ {
+ if (m_instructions[i]->DoesBranch())
+ {
+ next_branch = i;
+ break;
+ }
+ }
+ return next_branch;
+}
+
+uint32_t
+InstructionList::GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target)
+{
+ Address address;
+ address.SetLoadAddress(load_addr, &target);
+ 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;
+}
+
+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 == NULL || 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");
+ }
+ 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();
+
+ if (exe_ctx == NULL || 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 == NULL || 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 == NULL)
+ m_flavor.assign("default");
+ else
+ m_flavor.assign(flavor);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Disassembler::~Disassembler()
+{
+}
+
+InstructionList &
+Disassembler::GetInstructionList ()
+{
+ return m_instruction_list;
+}
+
+const InstructionList &
+Disassembler::GetInstructionList () const
+{
+ return m_instruction_list;
+}
+
+//----------------------------------------------------------------------
+// Class PseudoInstruction
+//----------------------------------------------------------------------
+PseudoInstruction::PseudoInstruction () :
+ Instruction (Address(), eAddressClassUnknown),
+ m_description ()
+{
+}
+
+PseudoInstruction::~PseudoInstruction ()
+{
+}
+
+bool
+PseudoInstruction::DoesBranch ()
+{
+ // 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();
+}
+
+
+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);
+ break;
+ }
+ case 16:
+ {
+ uint16_t value16 = *((uint16_t *) opcode_data);
+ m_opcode.SetOpcode16 (value16);
+ break;
+ }
+ case 32:
+ {
+ uint32_t value32 = *((uint32_t *) opcode_data);
+ m_opcode.SetOpcode32 (value32);
+ break;
+ }
+ case 64:
+ {
+ uint64_t value64 = *((uint64_t *) opcode_data);
+ m_opcode.SetOpcode64 (value64);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void
+PseudoInstruction::SetDescription (const char *description)
+{
+ if (description && strlen (description) > 0)
+ m_description = description;
+}
OpenPOWER on IntegriCloud