diff options
author | Tamas Berghammer <tberghammer@google.com> | 2016-02-10 10:42:13 +0000 |
---|---|---|
committer | Tamas Berghammer <tberghammer@google.com> | 2016-02-10 10:42:13 +0000 |
commit | 10e9923841a993978e3acf13bb7b0f893a118b81 (patch) | |
tree | bc8268b825902b200c110e814f3fa65b1f87d314 /lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp | |
parent | 1b6dacbb86d9c426bd3cb009a446e7da441fd97c (diff) | |
download | bcm5719-llvm-10e9923841a993978e3acf13bb7b0f893a118b81.tar.gz bcm5719-llvm-10e9923841a993978e3acf13bb7b0f893a118b81.zip |
Fix handling of the arm IT instruction in the unwinder
The IT instruction can specify condition code for up to 4 consecutive
instruction and it is used quite often by clang in epilogues causing
an issue when trying to unwind from locations covered by the IT
instruction and for locatins inmediately after the IT instruction.
Changes made to fix it:
* Introduce the concept of conditional instruction block what is a list
of consecutive instructions with the same condition. We update the
unwind information during the conditional instruction block and when
we reach the end of it (first instruction with a differemt condition)
then we restore the unwind information we had before the condition.
* Fix a bug in the ARM instruction emulator where neither PC nor the
ITSTATE was advanced when we reached an instruction what we can't
decode.
After the change we have no regression on android-arm running the
regular test suit and TestStandardUnwind also passes when running it
with clang as the compiler (previously it failed on an IT instruction).
Differential revision: http://reviews.llvm.org/D16814
llvm-svn: 260368
Diffstat (limited to 'lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp')
-rw-r--r-- | lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp | 108 |
1 files changed, 70 insertions, 38 deletions
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index eb5fec34fc2..28e411e62c2 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -125,6 +125,10 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& 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; idx<num_instructions; ++idx) { m_curr_row_modified = false; @@ -146,7 +150,41 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *it->second.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<UnwindPlan::Row>(*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<UnwindPlan::Row>(*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<UnwindPlan::Row>(*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 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& 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 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction, log->PutCString(strm.GetData()); } - if (!instruction->IsInstructionConditional()) - SetRegisterValue (*reg_info, reg_value); + SetRegisterValue (*reg_info, reg_value); switch (context.type) { @@ -566,45 +601,42 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction, 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 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction, 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(), |