Hi jasonmolenda, clayborg,
This is initial implementation of assembly profiler which only scans
prologue/epilogue assembly instructions to create CFI instructions.
REPOSITORY
rL LLVM
http://reviews.llvm.org/D7696
Files:
cmake/LLDBDependencies.cmake
lib/Makefile
source/Plugins/Makefile
source/Plugins/UnwindAssembly/CMakeLists.txt
source/Plugins/UnwindAssembly/mips/CMakeLists.txt
source/Plugins/UnwindAssembly/mips/Makefile
source/Plugins/UnwindAssembly/mips/UnwindAssembly-mips.cpp
source/Plugins/UnwindAssembly/mips/UnwindAssembly-mips.h
source/lldb.cpp
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: lib/Makefile
===================================================================
--- lib/Makefile
+++ lib/Makefile
@@ -60,6 +60,7 @@
lldbPluginSymbolFileSymtab.a \
lldbPluginUnwindAssemblyInstEmulation.a \
lldbPluginUnwindAssemblyx86.a \
+ lldbPluginUnwindAssemblymips.a \
lldbPluginUtility.a \
lldbSymbol.a \
lldbTarget.a \
Index: cmake/LLDBDependencies.cmake
===================================================================
--- cmake/LLDBDependencies.cmake
+++ cmake/LLDBDependencies.cmake
@@ -38,6 +38,7 @@
lldbPluginDynamicLoaderMacOSXDYLD
lldbPluginUnwindAssemblyInstEmulation
lldbPluginUnwindAssemblyX86
+ lldbPluginUnwindAssemblymips
lldbPluginAppleObjCRuntime
lldbPluginCXXItaniumABI
lldbPluginABIMacOSX_arm
Index: source/lldb.cpp
===================================================================
--- source/lldb.cpp
+++ source/lldb.cpp
@@ -56,6 +56,7 @@
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
+#include "Plugins/UnwindAssembly/mips/UnwindAssembly-mips.h"
#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
#ifndef LLDB_DISABLE_PYTHON
@@ -166,6 +167,7 @@
SymbolFileSymtab::Initialize();
UnwindAssemblyInstEmulation::Initialize();
UnwindAssembly_x86::Initialize();
+ UnwindAssembly_mips::Initialize();
EmulateInstructionARM::Initialize ();
EmulateInstructionARM64::Initialize ();
ObjectFilePECOFF::Initialize ();
@@ -262,6 +264,7 @@
SymbolFileDWARF::Terminate();
SymbolFileSymtab::Terminate();
UnwindAssembly_x86::Terminate();
+ UnwindAssembly_mips::Terminate();
UnwindAssemblyInstEmulation::Terminate();
EmulateInstructionARM::Terminate ();
EmulateInstructionARM64::Terminate ();
Index: source/Plugins/UnwindAssembly/mips/UnwindAssembly-mips.cpp
===================================================================
--- source/Plugins/UnwindAssembly/mips/UnwindAssembly-mips.cpp
+++ source/Plugins/UnwindAssembly/mips/UnwindAssembly-mips.cpp
@@ -0,0 +1,724 @@
+//===-- UnwindAssembly-mips.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnwindAssembly-mips.h"
+
+#include "llvm-c/Disassembler.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum CPU
+{
+ k_mips64
+};
+
+
+enum mips_register_numbers
+{
+ k_machine_r0 = 0,
+ k_machine_r1 = 1,
+ k_machine_r2 = 2,
+ k_machine_r3 = 3,
+ k_machine_r4 = 4,
+ k_machine_r5 = 5,
+ k_machine_r6 = 6,
+ k_machine_r7 = 7,
+ k_machine_r8 = 8,
+ k_machine_r9 = 9,
+ k_machine_r10 = 10,
+ k_machine_r11 = 11,
+ k_machine_r12 = 12,
+ k_machine_r13 = 13,
+ k_machine_r14 = 14,
+ k_machine_r15 = 15,
+ k_machine_r16 = 16,
+ k_machine_r17 = 17,
+ k_machine_r18 = 18,
+ k_machine_r19 = 19,
+ k_machine_r20 = 20,
+ k_machine_r21 = 21,
+ k_machine_r22 = 22,
+ k_machine_r23 = 23,
+ k_machine_r24 = 24,
+ k_machine_r25 = 25,
+ k_machine_r26 = 26,
+ k_machine_r27 = 27,
+ k_machine_gp = 28,
+ k_machine_sp = 29,
+ k_machine_fp = 30,
+ k_machine_ra = 31
+
+};
+
+struct regmap_ent
+{
+ const char *name;
+ int machine_regno;
+ int lldb_regno;
+};
+
+static struct regmap_ent mips_register_map[] =
+{
+ {"r0", k_machine_r0 , -1},
+ {"r1", k_machine_r1 , -1},
+ {"r2", k_machine_r2 , -1},
+ {"r3", k_machine_r3 , -1},
+ {"r4", k_machine_r4 , -1},
+ {"r5", k_machine_r5 , -1},
+ {"r6", k_machine_r6 , -1},
+ {"r7", k_machine_r7 , -1},
+ {"r8", k_machine_r8 , -1},
+ {"r9", k_machine_r9 , -1},
+ {"r10", k_machine_r10 , -1},
+ {"r11", k_machine_r11 , -1},
+ {"r12", k_machine_r12 , -1},
+ {"r13", k_machine_r13 , -1},
+ {"r14", k_machine_r14 , -1},
+ {"r15", k_machine_r15 , -1},
+ {"r16", k_machine_r16 , -1},
+ {"r17", k_machine_r17 , -1},
+ {"r18", k_machine_r18 , -1},
+ {"r19", k_machine_r19 , -1},
+ {"r20", k_machine_r20 , -1},
+ {"r21", k_machine_r21 , -1},
+ {"r22", k_machine_r22 , -1},
+ {"r23", k_machine_r23 , -1},
+ {"r24", k_machine_r24 , -1},
+ {"r25", k_machine_r25 , -1},
+ {"r26", k_machine_r26 , -1},
+ {"r27", k_machine_r27 , -1},
+ {"gp", k_machine_gp , -1},
+ {"sp", k_machine_sp , -1},
+ {"fp", k_machine_fp , -1},
+ {"ra", k_machine_ra , -1}
+
+};
+
+const int size_of_mips_register_map = llvm::array_lengthof (mips_register_map);
+
+static int mips_register_map_initialized = 0;
+
+//-----------------------------------------------------------------------------------------------
+// AssemblyParse_mips local-file class definition & implementation functions
+//-----------------------------------------------------------------------------------------------
+
+class AssemblyParse_mips
+{
+public:
+
+ AssemblyParse_mips (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func);
+
+ ~AssemblyParse_mips ();
+
+ bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan);
+
+ bool augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan);
+
+ bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan);
+
+ bool find_first_non_prologue_insn (Address &address);
+
+private:
+ enum { kMaxInstructionByteSize = 4 };
+
+ uint32_t extract_4 (uint8_t *b);
+ int signed_extend(int num, int bit);
+ bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno);
+ bool instruction_length (Address addr, int &length);
+ bool nonvolatile_reg_p (int machine_regno);
+
+ bool add_imm_sp_pattern_p (int& amount); bool push_rbp_pattern_p ();
+ bool store_reg_pattern_p (uint32_t& regno, int& offset);
+ bool mov_sp_to_fp_pattern_p ();
+ bool mov_fp_to_sp_pattern_p ();
+ bool jr_ra_pattern_p ();
+
+ const ExecutionContext m_exe_ctx;
+
+ AddressRange m_func_bounds;
+
+ Address m_cur_insn;
+ uint32_t m_cur_insn_word;
+ uint8_t m_cur_insn_bytes[kMaxInstructionByteSize];
+ uint32_t m_machine_ra_regnum;
+ uint32_t m_machine_sp_regnum;
+ uint32_t m_machine_fp_regnum;
+
+ uint32_t m_lldb_ra_regnum;
+ uint32_t m_lldb_sp_regnum;
+ uint32_t m_lldb_fp_regnum;
+
+ int m_cpu;
+ ArchSpec m_arch;
+ ::LLVMDisasmContextRef m_disasm_context;
+
+ DISALLOW_COPY_AND_ASSIGN (AssemblyParse_mips);
+};
+
+AssemblyParse_mips::AssemblyParse_mips (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func) :
+ m_exe_ctx (exe_ctx),
+ m_func_bounds(func),
+ m_cur_insn (),
+ m_machine_ra_regnum (LLDB_INVALID_REGNUM),
+ m_machine_sp_regnum (LLDB_INVALID_REGNUM),
+ m_machine_fp_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_ra_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_sp_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_fp_regnum (LLDB_INVALID_REGNUM),
+ m_cpu(cpu),
+ m_arch(arch)
+{
+ int *initialized_flag = NULL;
+ if (cpu == k_mips64)
+ {
+ m_machine_ra_regnum = k_machine_ra;
+ m_machine_sp_regnum = k_machine_sp;
+ m_machine_fp_regnum = k_machine_fp;
+ initialized_flag = &mips_register_map_initialized;
+ }
+
+ // we only look at prologue - it will be complete earlier than 512 bytes into func
+ if (m_func_bounds.GetByteSize() == 0)
+ m_func_bounds.SetByteSize(512);
+
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (thread && *initialized_flag == 0)
+ {
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+ if (reg_ctx)
+ {
+ struct regmap_ent *ent;
+ int count, i;
+ if (cpu == k_mips64)
+ {
+ ent = mips_register_map;
+ count = size_of_mips_register_map;
+ }
+
+ for (i = 0; i < count; i++, ent++)
+ {
+ const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName (ent->name);
+ if (ri)
+ ent->lldb_regno = ri->kinds[eRegisterKindLLDB];
+ }
+ *initialized_flag = 1;
+ }
+ }
+
+ // on initial construction we may not have a Thread so these have to remain
+ // uninitialized until we can get a RegisterContext to set up the register map table
+ if (*initialized_flag == 1)
+ {
+ uint32_t lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_sp_regnum, lldb_regno))
+ m_lldb_sp_regnum = lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_fp_regnum, lldb_regno))
+ m_lldb_fp_regnum = lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_ra_regnum, lldb_regno))
+ m_lldb_ra_regnum = lldb_regno;
+ }
+
+ m_disasm_context = ::LLVMCreateDisasm(m_arch.GetTriple().getTriple().c_str(),
+ (void*)this,
+ /*TagType=*/0,
+ NULL,
+ NULL);
+}
+
+AssemblyParse_mips::~AssemblyParse_mips ()
+{
+ ::LLVMDisasmDispose(m_disasm_context);
+}
+
+uint32_t
+AssemblyParse_mips::extract_4 (uint8_t *b)
+{
+ uint32_t v = 0;
+ for (int i = 0; i <= 3; i++)
+ v = (v << 8) | b[i];
+ return v;
+}
+
+int
+AssemblyParse_mips::signed_extend(int num, int bit)
+{
+ int mask = (0x1)<<(bit-1);
+ return ( ( num ^ mask ) - mask );
+}
+
+bool
+AssemblyParse_mips::machine_regno_to_lldb_regno (int machine_regno, uint32_t &lldb_regno)
+{
+ struct regmap_ent *ent;
+ int count, i;
+ if (m_cpu == k_mips64)
+ {
+ ent = mips_register_map;
+ count = size_of_mips_register_map;
+ }
+ for (i = 0; i < count; i++, ent++)
+ {
+ if (ent->machine_regno == machine_regno)
+ if (ent->lldb_regno != -1)
+ {
+ lldb_regno = ent->lldb_regno;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+AssemblyParse_mips::instruction_length (Address addr, int &length)
+{
+ const uint32_t max_op_byte_size = m_arch.GetMaximumOpcodeByteSize();
+ llvm::SmallVector <uint8_t, 32> opcode_data;
+ opcode_data.resize (max_op_byte_size);
+
+ if (!addr.IsValid())
+ return false;
+
+ const bool prefer_file_cache = true;
+ Error error;
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (target->ReadMemory (addr, prefer_file_cache, opcode_data.data(),
+ max_op_byte_size, error) == static_cast<size_t>(-1))
+ {
+ return false;
+ }
+
+ char out_string[512];
+ const addr_t pc = addr.GetFileAddress();
+ const size_t inst_size = ::LLVMDisasmInstruction (m_disasm_context,
+ opcode_data.data(),
+ max_op_byte_size,
+ pc, // PC value
+ out_string,
+ sizeof(out_string));
+
+ length = inst_size;
+ return true;
+}
+
+
+// This function expects an mips native register number (i.e. the bits stripped out of the
+// actual instruction), not an lldb register number.
+
+bool
+AssemblyParse_mips::nonvolatile_reg_p (int machine_regno)
+{
+ if (m_cpu == k_mips64)
+ {
+ switch (machine_regno)
+ {
+ case k_machine_r16:
+ case k_machine_r17:
+ case k_machine_r18:
+ case k_machine_r19:
+ case k_machine_r20:
+ case k_machine_r21:
+ case k_machine_r22:
+ case k_machine_r23:
+ case k_machine_sp:
+ case k_machine_fp:
+ case k_machine_ra:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+
+#define OPCODEBITS 26
+#define OP_DADDIU 0x19
+#define OP_SD 0x3F
+#define OP_SPECIAL 0x0
+#define OP_RS 21
+#define OP_BASE 21
+#define OP_RT 16
+#define OP_RD 11
+#define RS_VAL(op) (((op) >> OP_RS) & 0x1f)
+#define RT_VAL(op) (((op) >> OP_RT) & 0x1f)
+#define RD_VAL(op) (((op) >> OP_RD) & 0x1f)
+#define BASE_VAL(op) (((op) >> OP_BASE) & 0x1f)
+
+// daddiu sp,sp,-X [01001 11101 11101 xxxxxxxxxxxxxxxx]
+bool AssemblyParse_mips::add_imm_sp_pattern_p (int& amount)
+{
+ uint32_t p = m_cur_insn_word;
+
+ if ((p >> OPCODEBITS) == OP_DADDIU)
+ {
+ if (m_machine_sp_regnum == RS_VAL(p))
+ {
+ if (m_machine_sp_regnum == RT_VAL(p))
+ {
+ /* Get the immediate operand */
+ amount = signed_extend (p & 0xFFFF, 16);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* sd ra/fp,xx(sp) */
+bool AssemblyParse_mips::store_reg_pattern_p (uint32_t& regnum, int& offset)
+{
+ uint32_t p = m_cur_insn_word;
+ uint32_t regno;
+
+ if ((p >> OPCODEBITS) == OP_SD)
+ {
+ if(m_machine_sp_regnum == BASE_VAL(p))
+ {
+ regno = RT_VAL(p);
+ if (nonvolatile_reg_p(regno))
+ {
+ offset = p & 0xFFFF;
+ regnum = regno;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/* move s8, sp is actually ADDU s8, sp, $0
+special rs rt rd 0 ADDU
+000000 11101 00000 11110 00000 100001 */
+bool AssemblyParse_mips::mov_sp_to_fp_pattern_p ()
+{
+ uint32_t p = m_cur_insn_word;
+
+ if(p == 0x03a0f02d)
+ return true;
+ return false;
+}
+
+/* move s8, sp is actually ADDU s8, sp, $0
+special rs rt rd 0 ADDU
+000000 11101 00000 11110 00000 100001 */
+bool AssemblyParse_mips::mov_fp_to_sp_pattern_p ()
+{
+ uint32_t p = m_cur_insn_word;
+
+ if(p == 0x03c0e82d)
+ return true;
+ return false;
+}
+
+bool
+AssemblyParse_mips::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
+{
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ m_cur_insn = m_func_bounds.GetBaseAddress ();
+ int current_func_text_offset = 0;
+ int bytes_from_initial_sp = 0;
+ UnwindPlan::Row::RegisterLocation initial_regloc;
+ Error error;
+
+ if (!m_cur_insn.IsValid())
+ {
+ return false;
+ }
+
+ unwind_plan.SetPlanValidAddressRange (m_func_bounds);
+ unwind_plan.SetRegisterKind (eRegisterKindLLDB);
+
+ // At the start of the function, CFA is previous SP register value
+ row->SetOffset (current_func_text_offset);
+ row->SetCFARegister (m_lldb_sp_regnum);
+ row->SetCFAOffset (0);
+
+ // stack pointer hasn't changed yet
+ initial_regloc.SetIsCFAPlusOffset (0);
+ row->SetRegisterInfo (m_lldb_sp_regnum, initial_regloc);
+
+ unwind_plan.AppendRow (row);
+
+ // Allocate a new Row, populate it with the existing Row contents.
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ const bool prefer_file_cache = true;
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+ while (m_func_bounds.ContainsFileAddress (m_cur_insn))
+ {
+ int stack_offset, insn_len;
+ uint32_t machine_regno; // register numbers extracted directly out of instructions
+ uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB numbering scheme
+
+ if (!instruction_length (m_cur_insn, insn_len) || insn_len == 0 || insn_len > kMaxInstructionByteSize)
+ {
+ // An unrecognized/junk instruction
+ break;
+ }
+
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
+ insn_len, error) == static_cast<size_t>(-1))
+ {
+ // Error reading the instruction out of the file, stop scanning
+ break;
+ }
+
+ /* Construct word from opcode bytes */
+ m_cur_insn_word = extract_4 (m_cur_insn_bytes);
+
+ /* check addiu sp,sp,XX */
+ if (add_imm_sp_pattern_p (stack_offset))
+ {
+ bytes_from_initial_sp += (-stack_offset); // The bytes allocated on stack
+ if (bytes_from_initial_sp == 0)
+ {
+ //SP is restored
+ //Create a fresh, empty Row and RegisterLocation - don't mention any other registers
+ UnwindPlan::RowSP last_row(new UnwindPlan::Row);
+ UnwindPlan::Row::RegisterLocation last_regloc;
+
+ last_row->SetOffset (current_func_text_offset + insn_len);
+ last_row->SetCFARegister (m_lldb_sp_regnum);
+ last_row->SetCFAOffset (0);
+
+ last_regloc.SetIsCFAPlusOffset (0);
+ last_row->SetRegisterInfo (m_lldb_sp_regnum, last_regloc);
+
+ unwind_plan.AppendRow (last_row);
+
+ break;
+ }
+ else if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetOffset (current_func_text_offset + insn_len); // Set offset of row in the function
+
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ regloc.SetIsCFAPlusOffset (bytes_from_initial_sp);
+ row->SetRegisterInfo (m_lldb_sp_regnum, regloc);
+
+ unwind_plan.AppendRow (row);
+
+ goto loopnext;
+ }
+ }
+
+ /* Check sw <ra/fp>,xx(sp) */
+ if (store_reg_pattern_p (machine_regno, stack_offset) && machine_regno_to_lldb_regno (machine_regno, lldb_regno))
+ {
+ row->SetOffset (current_func_text_offset + insn_len);
+
+ UnwindPlan::Row::RegisterLocation regloc;
+ regloc.SetAtCFAPlusOffset (stack_offset);
+
+ row->SetRegisterInfo (lldb_regno, regloc);
+
+ unwind_plan.AppendRow (row);
+
+ goto loopnext;
+ }
+
+loopnext:
+ m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+ current_func_text_offset += insn_len;
+ // Allocate a new Row, populate it with the existing Row contents.
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+ }
+
+ unwind_plan.SetSourceName ("assembly insn profiling");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetReturnAddressRegister(m_lldb_ra_regnum);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+
+ return true;
+}
+
+bool
+AssemblyParse_mips::augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan)
+{
+ return false;
+}
+
+bool
+AssemblyParse_mips::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan)
+{
+ return false;
+}
+
+bool
+AssemblyParse_mips::find_first_non_prologue_insn (Address &address)
+{
+ m_cur_insn = m_func_bounds.GetBaseAddress ();
+ if (!m_cur_insn.IsValid())
+ {
+ return false;
+ }
+
+ const bool prefer_file_cache = true;
+ Target *target = m_exe_ctx.GetTargetPtr();
+ while (m_func_bounds.ContainsFileAddress (m_cur_insn))
+ {
+ Error error;
+ int insn_len, offset;
+ uint32_t regno;
+ if (!instruction_length (m_cur_insn, insn_len) || insn_len > kMaxInstructionByteSize || insn_len == 0)
+ {
+ // An error parsing the instruction, i.e. probably data/garbage - stop scanning
+ break;
+ }
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
+ insn_len, error) == static_cast<size_t>(-1))
+ {
+ // Error reading the instruction out of the file, stop scanning
+ break;
+ }
+
+ /* Construct word from opcode bytes */
+ m_cur_insn_word = extract_4 (m_cur_insn_bytes);
+
+ if (add_imm_sp_pattern_p (offset)
+ || store_reg_pattern_p (regno, offset)
+ || mov_sp_to_fp_pattern_p ())
+
+ {
+ m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+ continue;
+ }
+
+ // Unknown non-prologue instruction - stop scanning
+ break;
+ }
+
+ address = m_cur_insn;
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------------------------
+// UnwindAssemblyParser_mips method definitions
+//-----------------------------------------------------------------------------------------------
+
+UnwindAssembly_mips::UnwindAssembly_mips (const ArchSpec &arch, int cpu) :
+ lldb_private::UnwindAssembly(arch),
+ m_cpu(cpu),
+ m_arch(arch)
+{
+}
+
+UnwindAssembly_mips::~UnwindAssembly_mips ()
+{
+}
+
+bool
+UnwindAssembly_mips::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ AssemblyParse_mips asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.get_non_call_site_unwind_plan (unwind_plan);
+}
+
+bool
+UnwindAssembly_mips::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ AssemblyParse_mips asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
+}
+
+bool
+UnwindAssembly_mips::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ AssemblyParse_mips asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.get_fast_unwind_plan (func, unwind_plan);
+}
+
+bool
+UnwindAssembly_mips::FirstNonPrologueInsn (AddressRange& func, const ExecutionContext &exe_ctx, Address& first_non_prologue_insn)
+{
+ AssemblyParse_mips asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.find_first_non_prologue_insn (first_non_prologue_insn);
+}
+
+UnwindAssembly *
+UnwindAssembly_mips::CreateInstance (const ArchSpec &arch)
+{
+ const llvm::Triple::ArchType cpu = arch.GetMachine ();
+ if (cpu == llvm::Triple::mips64)
+ return new UnwindAssembly_mips (arch, k_mips64);
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol in UnwindAssemblyParser_mips
+//------------------------------------------------------------------
+
+ConstString
+UnwindAssembly_mips::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+
+uint32_t
+UnwindAssembly_mips::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+UnwindAssembly_mips::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+UnwindAssembly_mips::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+UnwindAssembly_mips::GetPluginNameStatic()
+{
+ static ConstString g_name("mips");
+ return g_name;
+}
+
+const char *
+UnwindAssembly_mips::GetPluginDescriptionStatic()
+{
+ return "mips assembly language profiler plugin.";
+}
Index: source/Plugins/UnwindAssembly/mips/CMakeLists.txt
===================================================================
--- source/Plugins/UnwindAssembly/mips/CMakeLists.txt
+++ source/Plugins/UnwindAssembly/mips/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_NO_RTTI 1)
+
+add_lldb_library(lldbPluginUnwindAssemblymips
+ UnwindAssembly-mips.cpp
+ )
Index: source/Plugins/UnwindAssembly/mips/Makefile
===================================================================
--- source/Plugins/UnwindAssembly/mips/Makefile
+++ source/Plugins/UnwindAssembly/mips/Makefile
@@ -0,0 +1,14 @@
+##==-- source/Plugins/UnwindAssembly/mips/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginUnwindAssemblymips
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
Index: source/Plugins/UnwindAssembly/mips/UnwindAssembly-mips.h
===================================================================
--- source/Plugins/UnwindAssembly/mips/UnwindAssembly-mips.h
+++ source/Plugins/UnwindAssembly/mips/UnwindAssembly-mips.h
@@ -0,0 +1,78 @@
+//===-- UnwindAssembly-mips.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_UnwindAssembly_mips_h_
+#define liblldb_UnwindAssembly_mips_h_
+
+#include "llvm-c/Disassembler.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+class UnwindAssembly_mips : public lldb_private::UnwindAssembly
+{
+public:
+
+ ~UnwindAssembly_mips ();
+
+ virtual bool
+ GetNonCallSiteUnwindPlanFromAssembly (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan& unwind_plan);
+
+ virtual bool
+ AugmentUnwindPlanFromCallSite (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan& unwind_plan);
+
+ virtual bool
+ GetFastUnwindPlan (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan &unwind_plan);
+
+ // thread may be NULL in which case we only use the Target (e.g. if this is called pre-process-launch).
+ virtual bool
+ FirstNonPrologueInsn (lldb_private::AddressRange& func,
+ const lldb_private::ExecutionContext &exe_ctx,
+ lldb_private::Address& first_non_prologue_insn);
+
+ static lldb_private::UnwindAssembly *
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+ UnwindAssembly_mips (const lldb_private::ArchSpec &arch, int cpu);
+
+ int m_cpu;
+ lldb_private::ArchSpec m_arch;
+};
+
+
+#endif // liblldb_UnwindAssembly_x86_h_
Index: source/Plugins/UnwindAssembly/CMakeLists.txt
===================================================================
--- source/Plugins/UnwindAssembly/CMakeLists.txt
+++ source/Plugins/UnwindAssembly/CMakeLists.txt
@@ -1,2 +1,3 @@
add_subdirectory(InstEmulation)
add_subdirectory(x86)
+add_subdirectory(mips)
Index: source/Plugins/Makefile
===================================================================
--- source/Plugins/Makefile
+++ source/Plugins/Makefile
@@ -19,7 +19,7 @@
ObjectFile/JIT SymbolFile/DWARF SymbolFile/Symtab Process/Utility \
DynamicLoader/Static Platform Process/gdb-remote \
Instruction/ARM Instruction/ARM64 \
- UnwindAssembly/InstEmulation UnwindAssembly/x86 \
+ UnwindAssembly/InstEmulation UnwindAssembly/x86 UnwindAssembly/mips \
LanguageRuntime/CPlusPlus/ItaniumABI \
LanguageRuntime/ObjC/AppleObjCRuntime \
DynamicLoader/POSIX-DYLD \
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits