Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -38,6 +38,7 @@ lldbPluginDynamicLoaderMacOSXDYLD lldbPluginUnwindAssemblyInstEmulation lldbPluginUnwindAssemblyX86 + lldbPluginUnwindAssemblymips lldbPluginAppleObjCRuntime lldbPluginCXXItaniumABI lldbPluginABIMacOSX_arm 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: 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 \ 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/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/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 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(-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(-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 ,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(-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/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 ();