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

Reply via email to