Index: lldb/trunk/include/lldb/Core/EmulateInstruction.h =================================================================== --- lldb/trunk/include/lldb/Core/EmulateInstruction.h +++ lldb/trunk/include/lldb/Core/EmulateInstruction.h @@ -384,6 +384,11 @@ const RegisterInfo *reg_info, const RegisterValue ®_value); + // Type to represent the condition of an instruction. The UINT32 value is reserved for the + // unconditional case and all other value can be used in an architecture dependent way. + typedef uint32_t InstructionCondition; + static const InstructionCondition UnconditionalCondition = UINT32_MAX; + EmulateInstruction (const ArchSpec &arch); ~EmulateInstruction() override = default; @@ -403,8 +408,8 @@ virtual bool EvaluateInstruction (uint32_t evaluate_options) = 0; - virtual bool - IsInstructionConditional() { return false; } + virtual InstructionCondition + GetInstructionCondition() { return UnconditionalCondition; } virtual bool TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data) = 0; Index: lldb/trunk/include/lldb/Symbol/UnwindPlan.h =================================================================== --- lldb/trunk/include/lldb/Symbol/UnwindPlan.h +++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h @@ -539,7 +539,7 @@ AppendRow (const RowSP& row_sp); void - InsertRow (const RowSP& row_sp); + InsertRow (const RowSP& row_sp, bool replace_existing = false); // Returns a pointer to the best row for the given offset into the function's instructions. // If offset is -1 it indicates that the function start is unknown - the final row in the UnwindPlan is returned. Index: lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.h =================================================================== --- lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -166,8 +166,8 @@ bool EvaluateInstruction (uint32_t evaluate_options) override; - bool - IsInstructionConditional() override; + InstructionCondition + GetInstructionCondition() override; bool TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data) override; Index: lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp =================================================================== --- lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -13587,10 +13587,7 @@ opcode_data = GetThumbOpcodeForInstruction (m_opcode.GetOpcode32(), m_arm_isa); else if (m_opcode_mode == eModeARM) opcode_data = GetARMOpcodeForInstruction (m_opcode.GetOpcode32(), m_arm_isa); - - if (opcode_data == NULL) - return false; - + const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions; @@ -13614,16 +13611,19 @@ if (!success) return false; } - - // Call the Emulate... function. - success = (this->*opcode_data->callback) (m_opcode.GetOpcode32(), opcode_data->encoding); - if (!success) - return false; + + // Call the Emulate... function if we managed to decode the opcode. + if (opcode_data) + { + success = (this->*opcode_data->callback) (m_opcode.GetOpcode32(), opcode_data->encoding); + if (!success) + return false; + } // Advance the ITSTATE bits to their values for the next instruction if we haven't just executed // an IT instruction what initialized it. if (m_opcode_mode == eModeThumb && m_it_session.InITBlock() && - opcode_data->callback != &EmulateInstructionARM::EmulateIT) + (opcode_data == nullptr || opcode_data->callback != &EmulateInstructionARM::EmulateIT)) m_it_session.ITAdvance(); if (auto_advance_pc) @@ -13631,30 +13631,28 @@ uint32_t after_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc, 0, &success); if (!success) return false; - + if (auto_advance_pc && (after_pc_value == orig_pc_value)) { - if (opcode_data->size == eSize32) - after_pc_value += 4; - else if (opcode_data->size == eSize16) - after_pc_value += 2; - + after_pc_value += m_opcode.GetByteSize(); + EmulateInstruction::Context context; context.type = eContextAdvancePC; context.SetNoArgs(); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc, after_pc_value)) return false; - } } return true; } -bool -EmulateInstructionARM::IsInstructionConditional() +EmulateInstruction::InstructionCondition +EmulateInstructionARM::GetInstructionCondition() { const uint32_t cond = CurrentCond (m_opcode.GetOpcode32()); - return cond != 0xe && cond != 0xf && cond != UINT32_MAX; + if (cond == 0xe || cond == 0xf || cond == UINT32_MAX) + return EmulateInstruction::UnconditionalCondition; + return cond; } bool Index: lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp =================================================================== --- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -125,6 +125,10 @@ RegisterInfo ra_reg_info; m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info); + // The architecture dependent condition code of the last processed instruction. + EmulateInstruction::InstructionCondition last_condition = EmulateInstruction::UnconditionalCondition; + lldb::addr_t condition_block_start_offset = 0; + for (size_t idx=0; idxsecond.first; m_curr_row.reset(newrow); - m_register_values = it->second.second;; + m_register_values = it->second.second; + } + + m_inst_emulator_ap->SetInstruction (inst->GetOpcode(), + inst->GetAddress(), + exe_ctx.GetTargetPtr()); + + if (last_condition != m_inst_emulator_ap->GetInstructionCondition()) + { + if (m_inst_emulator_ap->GetInstructionCondition() != EmulateInstruction::UnconditionalCondition && + saved_unwind_states.count(current_offset) == 0) + { + // If we don't have a saved row for the current offset then save our + // current state because we will have to restore it after the + // conditional block. + auto new_row = std::make_shared(*m_curr_row.get()); + saved_unwind_states.insert({current_offset, {new_row, m_register_values}}); + } + + // If the last instruction was conditional with a different condition + // then the then current condition then restore the condition. + if (last_condition != EmulateInstruction::UnconditionalCondition) + { + const auto& saved_state = saved_unwind_states.at(condition_block_start_offset); + m_curr_row = std::make_shared(*saved_state.first); + m_curr_row->SetOffset(current_offset); + m_register_values = saved_state.second; + bool replace_existing = true; // The last instruction might already + // created a row for this offset and + // we want to overwrite it. + unwind_plan.InsertRow(std::make_shared(*m_curr_row), replace_existing); + } + + // We are starting a new conditional block at the catual offset + condition_block_start_offset = current_offset; } if (log && log->GetVerbose ()) @@ -158,9 +196,7 @@ log->PutCString (strm.GetData()); } - m_inst_emulator_ap->SetInstruction (inst->GetOpcode(), - inst->GetAddress(), - exe_ctx.GetTargetPtr()); + last_condition = m_inst_emulator_ap->GetInstructionCondition(); m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions); @@ -503,8 +539,7 @@ log->PutCString(strm.GetData()); } - if (!instruction->IsInstructionConditional()) - SetRegisterValue (*reg_info, reg_value); + SetRegisterValue (*reg_info, reg_value); switch (context.type) { @@ -566,45 +601,42 @@ case EmulateInstruction::eContextPopRegisterOffStack: { - if (!instruction->IsInstructionConditional()) + const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; + const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric]; + if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP) { - const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; - const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric]; - if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP) + switch (context.info_type) { - switch (context.info_type) - { - case EmulateInstruction::eInfoTypeAddress: - if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() && - context.info.address == m_pushed_regs[reg_num]) - { - m_curr_row->SetRegisterLocationToSame(reg_num, - false /*must_replace*/); - m_curr_row_modified = true; - } - break; - case EmulateInstruction::eInfoTypeISA: - assert((generic_regnum == LLDB_REGNUM_GENERIC_PC || - generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) && - "eInfoTypeISA used for poping a register other the the PC/FLAGS"); - if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) - { - m_curr_row->SetRegisterLocationToSame(reg_num, - false /*must_replace*/); - m_curr_row_modified = true; - } - break; - default: - assert(false && "unhandled case, add code to handle this!"); - break; - } + case EmulateInstruction::eInfoTypeAddress: + if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() && + context.info.address == m_pushed_regs[reg_num]) + { + m_curr_row->SetRegisterLocationToSame(reg_num, + false /*must_replace*/); + m_curr_row_modified = true; + } + break; + case EmulateInstruction::eInfoTypeISA: + assert((generic_regnum == LLDB_REGNUM_GENERIC_PC || + generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) && + "eInfoTypeISA used for poping a register other the the PC/FLAGS"); + if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) + { + m_curr_row->SetRegisterLocationToSame(reg_num, + false /*must_replace*/); + m_curr_row_modified = true; + } + break; + default: + assert(false && "unhandled case, add code to handle this!"); + break; } } } break; case EmulateInstruction::eContextSetFramePointer: - if (!m_fp_is_cfa && !instruction->IsInstructionConditional()) + if (!m_fp_is_cfa) { m_fp_is_cfa = true; m_cfa_reg_info = *reg_info; @@ -619,7 +651,7 @@ case EmulateInstruction::eContextAdjustStackPointer: // If we have created a frame using the frame pointer, don't follow // subsequent adjustments to the stack pointer. - if (!m_fp_is_cfa && !instruction->IsInstructionConditional()) + if (!m_fp_is_cfa) { m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( m_curr_row->GetCFAValue().GetRegisterNumber(), Index: lldb/trunk/source/Symbol/UnwindPlan.cpp =================================================================== --- lldb/trunk/source/Symbol/UnwindPlan.cpp +++ lldb/trunk/source/Symbol/UnwindPlan.cpp @@ -338,7 +338,7 @@ } void -UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp) +UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp, bool replace_existing) { collection::iterator it = m_row_list.begin(); while (it != m_row_list.end()) { @@ -349,6 +349,8 @@ } if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset()) m_row_list.insert(it, row_sp); + else if (replace_existing) + *it = row_sp; } UnwindPlan::RowSP