Files
clang-p2996/lldb/include/lldb/Core/Disassembler.h
Tatyana Krasnukha 9e1a117d4b Move AddressClass to private enums since API doesn't provide any functions to manage it.
This change allows to make AddressClass strongly typed enum and not to have issues with old versions of SWIG that don't support enum classes.

llvm-svn: 335710
2018-06-27 06:50:10 +00:00

557 lines
20 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_
#include "lldb/Core/Address.h"
#include "lldb/Core/EmulateInstruction.h"
#include "lldb/Core/FormatEntity.h" // for FormatEntity
#include "lldb/Core/Opcode.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Symbol/LineEntry.h"
#include "lldb/Target/ExecutionContext.h" // for ExecutionContext
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/ConstString.h" // for ConstString
#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
#include "lldb/lldb-forward.h" // for InstructionSP, DisassemblerSP
#include "lldb/lldb-private-enumerations.h" // for AddressClass
#include "lldb/lldb-types.h" // for addr_t, offset_t
#include "llvm/ADT/StringRef.h" // for StringRef
#include <functional> // for function
#include <map>
#include <memory> // for enable_shared_from_this
#include <set>
#include <string>
#include <vector>
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, int64_t
#include <stdio.h> // for FILE
namespace lldb_private {
class AddressRange;
}
namespace lldb_private {
class DataExtractor;
}
namespace lldb_private {
class Debugger;
}
namespace lldb_private {
class Disassembler;
}
namespace lldb_private {
class Module;
}
namespace lldb_private {
class Stream;
}
namespace lldb_private {
class SymbolContext;
}
namespace lldb_private {
class SymbolContextList;
}
namespace lldb_private {
class Target;
}
namespace lldb_private {
struct RegisterInfo;
}
namespace llvm {
template <typename T> class SmallVectorImpl;
}
namespace lldb_private {
class Instruction {
public:
Instruction(const Address &address,
AddressClass addr_class = AddressClass::eInvalid);
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;
AddressClass GetAddressClass();
void SetAddress(const Address &addr) {
// Invalidate the address class to lazily discover it if we need to.
m_address_class = AddressClass::eInvalid;
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();
bool CanSetBreakpoint ();
virtual size_t Decode(const Disassembler &disassembler,
const DataExtractor &data,
lldb::offset_t data_offset) = 0;
virtual void SetDescription(llvm::StringRef) {
} // 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);
struct Operand {
enum class Type {
Invalid = 0,
Register,
Immediate,
Dereference,
Sum,
Product
} m_type = Type::Invalid;
std::vector<Operand> m_children;
lldb::addr_t m_immediate = 0;
ConstString m_register;
bool m_negative = false;
bool m_clobbered = false;
bool IsValid() { return m_type != Type::Invalid; }
static Operand BuildRegister(ConstString &r);
static Operand BuildImmediate(lldb::addr_t imm, bool neg);
static Operand BuildImmediate(int64_t imm);
static Operand BuildDereference(const Operand &ref);
static Operand BuildSum(const Operand &lhs, const Operand &rhs);
static Operand BuildProduct(const Operand &lhs, const Operand &rhs);
};
virtual bool ParseOperands(llvm::SmallVectorImpl<Operand> &operands) {
return false;
}
virtual bool IsCall() { return false; }
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
// AddressClass::eCodeAlternateISA (currently used for
// thumb), and also to specify data (AddressClass::eData).
// The usual value will be AddressClass::eCode, but often
// when disassembling memory, you might run into data.
// This can help us to disassemble appropriately.
private:
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);
}
}
};
namespace OperandMatchers {
std::function<bool(const Instruction::Operand &)>
MatchBinaryOp(std::function<bool(const Instruction::Operand &)> base,
std::function<bool(const Instruction::Operand &)> left,
std::function<bool(const Instruction::Operand &)> right);
std::function<bool(const Instruction::Operand &)>
MatchUnaryOp(std::function<bool(const Instruction::Operand &)> base,
std::function<bool(const Instruction::Operand &)> child);
std::function<bool(const Instruction::Operand &)>
MatchRegOp(const RegisterInfo &info);
std::function<bool(const Instruction::Operand &)> FetchRegOp(ConstString &reg);
std::function<bool(const Instruction::Operand &)> MatchImmOp(int64_t imm);
std::function<bool(const Instruction::Operand &)> FetchImmOp(int64_t &imm);
std::function<bool(const Instruction::Operand &)>
MatchOpType(Instruction::Operand::Type type);
}
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(llvm::StringRef 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,
bool mixed_source_and_assembly,
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,
bool mixed_source_and_assembly,
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,
bool mixed_source_and_assembly, 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, bool mixed_source_and_assembly,
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, bool mixed_source_and_assembly,
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,
bool mixed_source_and_assembly,
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:
// SourceLine and SourceLinesToDisplay structures are only used in the mixed
// source and assembly display methods internal to this class.
struct SourceLine {
FileSpec file;
uint32_t line;
uint32_t column;
SourceLine() : file(), line(LLDB_INVALID_LINE_NUMBER), column(0) {}
bool operator==(const SourceLine &rhs) const {
return file == rhs.file && line == rhs.line && rhs.column == column;
}
bool operator!=(const SourceLine &rhs) const {
return file != rhs.file || line != rhs.line || column != rhs.column;
}
bool IsValid() const { return line != LLDB_INVALID_LINE_NUMBER; }
};
struct SourceLinesToDisplay {
std::vector<SourceLine> lines;
// index of the "current" source line, if we want to highlight that when
// displaying the source lines. (as opposed to the surrounding source
// lines provided to give context)
size_t current_source_line;
// Whether to print a blank line at the end of the source lines.
bool print_source_context_end_eol;
SourceLinesToDisplay()
: lines(), current_source_line(-1), print_source_context_end_eol(true) {
}
};
// Get the function's declaration line number, hopefully a line number
// earlier than the opening curly brace at the start of the function body.
static SourceLine GetFunctionDeclLineEntry(const SymbolContext &sc);
// Add the provided SourceLine to the map of filenames-to-source-lines-seen.
static void AddLineToSourceLineTables(
SourceLine &line,
std::map<FileSpec, std::set<uint32_t>> &source_lines_seen);
// Given a source line, determine if we should print it when we're doing
// mixed source & assembly output. We're currently using the
// target.process.thread.step-avoid-regexp setting (which is used for
// stepping over inlined STL functions by default) to determine what source
// lines to avoid showing.
//
// Returns true if this source line should be elided (if the source line
// should not be displayed).
static bool
ElideMixedSourceAndDisassemblyLine(const ExecutionContext &exe_ctx,
const SymbolContext &sc, SourceLine &line);
static bool
ElideMixedSourceAndDisassemblyLine(const ExecutionContext &exe_ctx,
const SymbolContext &sc, LineEntry &line) {
SourceLine sl;
sl.file = line.file;
sl.line = line.line;
sl.column = line.column;
return ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, sl);
};
//------------------------------------------------------------------
// 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_