mirror of
https://github.com/opnsense/src.git
synced 2026-02-28 12:20:54 -05:00
485 lines
15 KiB
C++
485 lines
15 KiB
C++
//===-- Disassembler.h ------------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef liblldb_Disassembler_h_
|
|
#define liblldb_Disassembler_h_
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/lldb-private.h"
|
|
#include "lldb/Core/Address.h"
|
|
#include "lldb/Core/ArchSpec.h"
|
|
#include "lldb/Core/EmulateInstruction.h"
|
|
#include "lldb/Core/Opcode.h"
|
|
#include "lldb/Core/PluginInterface.h"
|
|
#include "lldb/Interpreter/OptionValue.h"
|
|
|
|
namespace lldb_private {
|
|
|
|
class Instruction
|
|
{
|
|
public:
|
|
Instruction (const Address &address,
|
|
lldb::AddressClass addr_class = lldb::eAddressClassInvalid);
|
|
|
|
virtual
|
|
~Instruction();
|
|
|
|
const Address &
|
|
GetAddress () const
|
|
{
|
|
return m_address;
|
|
}
|
|
|
|
const char *
|
|
GetMnemonic (const ExecutionContext* exe_ctx)
|
|
{
|
|
CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
|
|
return m_opcode_name.c_str();
|
|
}
|
|
|
|
const char *
|
|
GetOperands (const ExecutionContext* exe_ctx)
|
|
{
|
|
CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
|
|
return m_mnemonics.c_str();
|
|
}
|
|
|
|
const char *
|
|
GetComment (const ExecutionContext* exe_ctx)
|
|
{
|
|
CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
|
|
return m_comment.c_str();
|
|
}
|
|
|
|
virtual void
|
|
CalculateMnemonicOperandsAndComment (const ExecutionContext* exe_ctx) = 0;
|
|
|
|
lldb::AddressClass
|
|
GetAddressClass ();
|
|
|
|
void
|
|
SetAddress (const Address &addr)
|
|
{
|
|
// Invalidate the address class to lazily discover
|
|
// it if we need to.
|
|
m_address_class = lldb::eAddressClassInvalid;
|
|
m_address = addr;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
/// Dump the text representation of this Instruction to a Stream
|
|
///
|
|
/// Print the (optional) address, (optional) bytes, opcode,
|
|
/// operands, and instruction comments to a stream.
|
|
///
|
|
/// @param[in] s
|
|
/// The Stream to add the text to.
|
|
///
|
|
/// @param[in] show_address
|
|
/// Whether the address (using disassembly_addr_format_spec formatting)
|
|
/// should be printed.
|
|
///
|
|
/// @param[in] show_bytes
|
|
/// Whether the bytes of the assembly instruction should be printed.
|
|
///
|
|
/// @param[in] max_opcode_byte_size
|
|
/// The size (in bytes) of the largest instruction in the list that
|
|
/// we are printing (for text justification/alignment purposes)
|
|
/// Only needed if show_bytes is true.
|
|
///
|
|
/// @param[in] exe_ctx
|
|
/// The current execution context, if available. May be used in
|
|
/// the assembling of the operands+comments for this instruction.
|
|
/// Pass NULL if not applicable.
|
|
///
|
|
/// @param[in] sym_ctx
|
|
/// The SymbolContext for this instruction.
|
|
/// Pass NULL if not available/computed.
|
|
/// Only needed if show_address is true.
|
|
///
|
|
/// @param[in] prev_sym_ctx
|
|
/// The SymbolContext for the previous instruction. Depending on
|
|
/// the disassembly address format specification, a change in
|
|
/// Symbol / Function may mean that a line is printed with the new
|
|
/// symbol/function name.
|
|
/// Pass NULL if unavailable, or if this is the first instruction of
|
|
/// the InstructionList.
|
|
/// Only needed if show_address is true.
|
|
///
|
|
/// @param[in] disassembly_addr_format
|
|
/// The format specification for how addresses are printed.
|
|
/// Only needed if show_address is true.
|
|
///
|
|
/// @param[in] max_address_text_size
|
|
/// The length of the longest address string at the start of the
|
|
/// disassembly line that will be printed (the Debugger::FormatDisassemblerAddress() string)
|
|
/// so this method can properly align the instruction opcodes.
|
|
/// May be 0 to indicate no indentation/alignment of the opcodes.
|
|
//------------------------------------------------------------------
|
|
virtual void
|
|
Dump (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);
|
|
|
|
virtual bool
|
|
DoesBranch () = 0;
|
|
|
|
virtual bool
|
|
HasDelaySlot ();
|
|
|
|
virtual size_t
|
|
Decode (const Disassembler &disassembler,
|
|
const DataExtractor& data,
|
|
lldb::offset_t data_offset) = 0;
|
|
|
|
virtual void
|
|
SetDescription (const char *) {} // May be overridden in sub-classes that have descriptions.
|
|
|
|
lldb::OptionValueSP
|
|
ReadArray (FILE *in_file, Stream *out_stream, OptionValue::Type data_type);
|
|
|
|
lldb::OptionValueSP
|
|
ReadDictionary (FILE *in_file, Stream *out_stream);
|
|
|
|
bool
|
|
DumpEmulation (const ArchSpec &arch);
|
|
|
|
virtual bool
|
|
TestEmulation (Stream *stream, const char *test_file_name);
|
|
|
|
bool
|
|
Emulate (const ArchSpec &arch,
|
|
uint32_t evaluate_options,
|
|
void *baton,
|
|
EmulateInstruction::ReadMemoryCallback read_mem_callback,
|
|
EmulateInstruction::WriteMemoryCallback write_mem_calback,
|
|
EmulateInstruction::ReadRegisterCallback read_reg_callback,
|
|
EmulateInstruction::WriteRegisterCallback write_reg_callback);
|
|
|
|
const Opcode &
|
|
GetOpcode () const
|
|
{
|
|
return m_opcode;
|
|
}
|
|
|
|
uint32_t
|
|
GetData (DataExtractor &data);
|
|
|
|
protected:
|
|
Address m_address; // The section offset address of this instruction
|
|
// We include an address class in the Instruction class to
|
|
// allow the instruction specify the eAddressClassCodeAlternateISA
|
|
// (currently used for thumb), and also to specify data (eAddressClassData).
|
|
// The usual value will be eAddressClassCode, but often when
|
|
// disassembling memory, you might run into data. This can
|
|
// help us to disassemble appropriately.
|
|
private:
|
|
lldb::AddressClass m_address_class; // Use GetAddressClass () accessor function!
|
|
protected:
|
|
Opcode m_opcode; // The opcode for this instruction
|
|
std::string m_opcode_name;
|
|
std::string m_mnemonics;
|
|
std::string m_comment;
|
|
bool m_calculated_strings;
|
|
|
|
void
|
|
CalculateMnemonicOperandsAndCommentIfNeeded (const ExecutionContext* exe_ctx)
|
|
{
|
|
if (!m_calculated_strings)
|
|
{
|
|
m_calculated_strings = true;
|
|
CalculateMnemonicOperandsAndComment(exe_ctx);
|
|
}
|
|
}
|
|
};
|
|
|
|
class InstructionList
|
|
{
|
|
public:
|
|
InstructionList();
|
|
~InstructionList();
|
|
|
|
size_t
|
|
GetSize() const;
|
|
|
|
uint32_t
|
|
GetMaxOpcocdeByteSize () const;
|
|
|
|
lldb::InstructionSP
|
|
GetInstructionAtIndex (size_t idx) const;
|
|
|
|
uint32_t
|
|
GetIndexOfNextBranchInstruction(uint32_t start, Target &target) const;
|
|
|
|
uint32_t
|
|
GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target);
|
|
|
|
uint32_t
|
|
GetIndexOfInstructionAtAddress (const Address &addr);
|
|
|
|
void
|
|
Clear();
|
|
|
|
void
|
|
Append (lldb::InstructionSP &inst_sp);
|
|
|
|
void
|
|
Dump (Stream *s,
|
|
bool show_address,
|
|
bool show_bytes,
|
|
const ExecutionContext* exe_ctx);
|
|
|
|
private:
|
|
typedef std::vector<lldb::InstructionSP> collection;
|
|
typedef collection::iterator iterator;
|
|
typedef collection::const_iterator const_iterator;
|
|
|
|
collection m_instructions;
|
|
};
|
|
|
|
class PseudoInstruction :
|
|
public Instruction
|
|
{
|
|
public:
|
|
|
|
PseudoInstruction ();
|
|
|
|
~PseudoInstruction() override;
|
|
|
|
bool
|
|
DoesBranch() override;
|
|
|
|
bool
|
|
HasDelaySlot() override;
|
|
|
|
void
|
|
CalculateMnemonicOperandsAndComment(const ExecutionContext* exe_ctx) override
|
|
{
|
|
// TODO: fill this in and put opcode name into Instruction::m_opcode_name,
|
|
// mnemonic into Instruction::m_mnemonics, and any comment into
|
|
// Instruction::m_comment
|
|
}
|
|
|
|
size_t
|
|
Decode(const Disassembler &disassembler,
|
|
const DataExtractor &data,
|
|
lldb::offset_t data_offset) override;
|
|
|
|
void
|
|
SetOpcode (size_t opcode_size, void *opcode_data);
|
|
|
|
void
|
|
SetDescription(const char *description) override;
|
|
|
|
protected:
|
|
std::string m_description;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN (PseudoInstruction);
|
|
};
|
|
|
|
class Disassembler :
|
|
public std::enable_shared_from_this<Disassembler>,
|
|
public PluginInterface
|
|
{
|
|
public:
|
|
|
|
enum
|
|
{
|
|
eOptionNone = 0u,
|
|
eOptionShowBytes = (1u << 0),
|
|
eOptionRawOuput = (1u << 1),
|
|
eOptionMarkPCSourceLine = (1u << 2), // Mark the source line that contains the current PC (mixed mode only)
|
|
eOptionMarkPCAddress = (1u << 3) // Mark the disassembly line the contains the PC
|
|
};
|
|
|
|
enum HexImmediateStyle
|
|
{
|
|
eHexStyleC,
|
|
eHexStyleAsm,
|
|
};
|
|
|
|
// FindPlugin should be lax about the flavor string (it is too annoying to have various internal uses of the
|
|
// disassembler fail because the global flavor string gets set wrong. Instead, if you get a flavor string you
|
|
// don't understand, use the default. Folks who care to check can use the FlavorValidForArchSpec method on the
|
|
// disassembler they got back.
|
|
static lldb::DisassemblerSP
|
|
FindPlugin (const ArchSpec &arch, const char *flavor, const char *plugin_name);
|
|
|
|
// This version will use the value in the Target settings if flavor is NULL;
|
|
static lldb::DisassemblerSP
|
|
FindPluginForTarget(const lldb::TargetSP target_sp, const ArchSpec &arch, const char *flavor, const char *plugin_name);
|
|
|
|
static lldb::DisassemblerSP
|
|
DisassembleRange (const ArchSpec &arch,
|
|
const char *plugin_name,
|
|
const char *flavor,
|
|
const ExecutionContext &exe_ctx,
|
|
const AddressRange &disasm_range,
|
|
bool prefer_file_cache);
|
|
|
|
static lldb::DisassemblerSP
|
|
DisassembleBytes (const ArchSpec &arch,
|
|
const char *plugin_name,
|
|
const char *flavor,
|
|
const Address &start,
|
|
const void *bytes,
|
|
size_t length,
|
|
uint32_t max_num_instructions,
|
|
bool data_from_file);
|
|
|
|
static bool
|
|
Disassemble (Debugger &debugger,
|
|
const ArchSpec &arch,
|
|
const char *plugin_name,
|
|
const char *flavor,
|
|
const ExecutionContext &exe_ctx,
|
|
const AddressRange &range,
|
|
uint32_t num_instructions,
|
|
uint32_t num_mixed_context_lines,
|
|
uint32_t options,
|
|
Stream &strm);
|
|
|
|
static bool
|
|
Disassemble (Debugger &debugger,
|
|
const ArchSpec &arch,
|
|
const char *plugin_name,
|
|
const char *flavor,
|
|
const ExecutionContext &exe_ctx,
|
|
const Address &start,
|
|
uint32_t num_instructions,
|
|
uint32_t num_mixed_context_lines,
|
|
uint32_t options,
|
|
Stream &strm);
|
|
|
|
static size_t
|
|
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);
|
|
|
|
static bool
|
|
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);
|
|
|
|
static bool
|
|
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);
|
|
|
|
//------------------------------------------------------------------
|
|
// Constructors and Destructors
|
|
//------------------------------------------------------------------
|
|
Disassembler(const ArchSpec &arch, const char *flavor);
|
|
~Disassembler() override;
|
|
|
|
typedef const char * (*SummaryCallback)(const Instruction& inst, ExecutionContext *exe_context, void *user_data);
|
|
|
|
static bool
|
|
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);
|
|
|
|
size_t
|
|
ParseInstructions (const ExecutionContext *exe_ctx,
|
|
const AddressRange &range,
|
|
Stream *error_strm_ptr,
|
|
bool prefer_file_cache);
|
|
|
|
size_t
|
|
ParseInstructions (const ExecutionContext *exe_ctx,
|
|
const Address &range,
|
|
uint32_t num_instructions,
|
|
bool prefer_file_cache);
|
|
|
|
virtual size_t
|
|
DecodeInstructions (const Address &base_addr,
|
|
const DataExtractor& data,
|
|
lldb::offset_t data_offset,
|
|
size_t num_instructions,
|
|
bool append,
|
|
bool data_from_file) = 0;
|
|
|
|
InstructionList &
|
|
GetInstructionList ();
|
|
|
|
const InstructionList &
|
|
GetInstructionList () const;
|
|
|
|
const ArchSpec &
|
|
GetArchitecture () const
|
|
{
|
|
return m_arch;
|
|
}
|
|
|
|
const char *
|
|
GetFlavor () const
|
|
{
|
|
return m_flavor.c_str();
|
|
}
|
|
|
|
virtual bool
|
|
FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor) = 0;
|
|
|
|
protected:
|
|
//------------------------------------------------------------------
|
|
// Classes that inherit from Disassembler can see and modify these
|
|
//------------------------------------------------------------------
|
|
ArchSpec m_arch;
|
|
InstructionList m_instruction_list;
|
|
lldb::addr_t m_base_addr;
|
|
std::string m_flavor;
|
|
|
|
private:
|
|
//------------------------------------------------------------------
|
|
// For Disassembler only
|
|
//------------------------------------------------------------------
|
|
DISALLOW_COPY_AND_ASSIGN (Disassembler);
|
|
};
|
|
|
|
} // namespace lldb_private
|
|
|
|
#endif // liblldb_Disassembler_h_
|