diff options
| author | Tamas Berghammer <tberghammer@google.com> | 2015-10-02 11:58:26 +0000 |
|---|---|---|
| committer | Tamas Berghammer <tberghammer@google.com> | 2015-10-02 11:58:26 +0000 |
| commit | f5ead561b3e41c588235a536db2587557b2fc1c4 (patch) | |
| tree | 9c683396e5ca5325b9811841114d6c31c7bee076 | |
| parent | 8c205d5394eea36fe9426a31b3d0ee104bd0dc85 (diff) | |
| download | bcm5719-llvm-f5ead561b3e41c588235a536db2587557b2fc1c4.tar.gz bcm5719-llvm-f5ead561b3e41c588235a536db2587557b2fc1c4.zip | |
Fix several issues around .ARM.exidx section handling
* Use .ARM.exidx as a fallback unwind plan for non-call site when the
instruction emulation based unwind failed.
* Work around an old compiler issue where the compiler isn't sort the
entries in .ARM.exidx based on their address.
* Fix unwind info parsing when the virtual file address >= 0x80000000
* Fix bug in unwind info parsing when neither lr nor pc is explicitly
restored.
Differential revision: http://reviews.llvm.org/D13380
llvm-svn: 249119
| -rw-r--r-- | lldb/include/lldb/Symbol/ArmUnwindInfo.h | 13 | ||||
| -rw-r--r-- | lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp | 20 | ||||
| -rw-r--r-- | lldb/source/Symbol/ArmUnwindInfo.cpp | 84 |
3 files changed, 71 insertions, 46 deletions
diff --git a/lldb/include/lldb/Symbol/ArmUnwindInfo.h b/lldb/include/lldb/Symbol/ArmUnwindInfo.h index 8567d7ed1e6..b19af23744a 100644 --- a/lldb/include/lldb/Symbol/ArmUnwindInfo.h +++ b/lldb/include/lldb/Symbol/ArmUnwindInfo.h @@ -43,6 +43,18 @@ public: GetUnwindPlan(Target &target, const Address& addr, UnwindPlan& unwind_plan); private: + struct ArmExidxEntry + { + ArmExidxEntry(uint32_t f, lldb::addr_t a, uint32_t d); + + bool + operator<(const ArmExidxEntry& other) const; + + uint32_t file_address; + lldb::addr_t address; + uint32_t data; + }; + const uint8_t* GetExceptionHandlingTableEntry(const Address& addr); @@ -57,6 +69,7 @@ private: lldb::SectionSP m_arm_extab_sp; // .ARM.extab section DataExtractor m_arm_exidx_data; // .ARM.exidx section data DataExtractor m_arm_extab_data; // .ARM.extab section data + std::vector<ArmExidxEntry> m_exidx_entries; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 302f2034b94..278a1d5dabf 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -881,12 +881,12 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // then the architecture default plan and for hand written assembly code it is often // written in a way that it valid at all location what helps in the most common // cases when the instruction emulation fails. - UnwindPlanSP eh_frame_unwind_plan = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one); - if (eh_frame_unwind_plan && - eh_frame_unwind_plan.get() != unwind_plan_sp.get() && - eh_frame_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName()) + UnwindPlanSP call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(), m_current_offset_backed_up_one); + if (call_site_unwind_plan && + call_site_unwind_plan.get() != unwind_plan_sp.get() && + call_site_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName()) { - m_fallback_unwind_plan_sp = eh_frame_unwind_plan; + m_fallback_unwind_plan_sp = call_site_unwind_plan; } else { @@ -926,12 +926,12 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // more reliable even on non call sites then the architecture default plan and for hand // written assembly code it is often written in a way that it valid at all location what // helps in the most common cases when the instruction emulation fails. - UnwindPlanSP eh_frame_unwind_plan = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one); - if (eh_frame_unwind_plan && - eh_frame_unwind_plan.get() != unwind_plan_sp.get() && - eh_frame_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName()) + UnwindPlanSP call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(), m_current_offset_backed_up_one); + if (call_site_unwind_plan && + call_site_unwind_plan.get() != unwind_plan_sp.get() && + call_site_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName()) { - m_fallback_unwind_plan_sp = eh_frame_unwind_plan; + m_fallback_unwind_plan_sp = call_site_unwind_plan; } else { diff --git a/lldb/source/Symbol/ArmUnwindInfo.cpp b/lldb/source/Symbol/ArmUnwindInfo.cpp index 7290256dad7..0d3e974bebb 100644 --- a/lldb/source/Symbol/ArmUnwindInfo.cpp +++ b/lldb/source/Symbol/ArmUnwindInfo.cpp @@ -30,14 +30,26 @@ using namespace lldb; using namespace lldb_private; -namespace +// Converts a prel31 avlue to lldb::addr_t with sign extension +static addr_t +Prel31ToAddr(uint32_t prel31) { - struct ArmExidxEntry - { - uint32_t address; - uint32_t data; - }; -}; + addr_t res = prel31; + if (prel31 & (1<<30)) + res |= 0xffffffff80000000ULL; + return res; +} + +ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a, uint32_t d) : + file_address(f), address(a), data(d) +{ +} + +bool +ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry& other) const +{ + return address < other.address; +} ArmUnwindInfo::ArmUnwindInfo(const ObjectFile& objfile, SectionSP& arm_exidx, @@ -48,6 +60,23 @@ ArmUnwindInfo::ArmUnwindInfo(const ObjectFile& objfile, { objfile.ReadSectionData(arm_exidx.get(), m_arm_exidx_data); objfile.ReadSectionData(arm_extab.get(), m_arm_extab_data); + + addr_t exidx_base_addr = m_arm_exidx_sp->GetFileAddress(); + + offset_t offset = 0; + while (m_arm_exidx_data.ValidOffset(offset)) + { + lldb::addr_t file_addr = exidx_base_addr + offset; + lldb::addr_t addr = exidx_base_addr + + (addr_t)offset + + Prel31ToAddr(m_arm_exidx_data.GetU32(&offset)); + uint32_t data = m_arm_exidx_data.GetU32(&offset); + m_exidx_entries.emplace_back(file_addr, addr, data); + } + + // Sort the entries in the exidx section. The entries should be sorted inside the section but + // some old compiler isn't sorted them. + std::sort(m_exidx_entries.begin(), m_exidx_entries.end()); } ArmUnwindInfo::~ArmUnwindInfo() @@ -85,7 +114,7 @@ ArmUnwindInfo::GetULEB128(const uint32_t* data, uint16_t& offset, uint16_t max_o bool ArmUnwindInfo::GetUnwindPlan(Target &target, const Address& addr, UnwindPlan& unwind_plan) { - const uint32_t* data = (const uint32_t*)GetExceptionHandlingTableEntry(addr.GetFileAddress()); + const uint32_t* data = (const uint32_t*)GetExceptionHandlingTableEntry(addr); if (data == nullptr) return false; // No unwind information for the function @@ -382,6 +411,8 @@ ArmUnwindInfo::GetUnwindPlan(Target &target, const Address& addr, UnwindPlan& un UnwindPlan::Row::RegisterLocation lr_location; if (row->GetRegisterInfo(dwarf_lr, lr_location)) row->SetRegisterInfo(dwarf_pc, lr_location); + else + row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, false); } unwind_plan.AppendRow(row); @@ -396,38 +427,19 @@ ArmUnwindInfo::GetUnwindPlan(Target &target, const Address& addr, UnwindPlan& un const uint8_t* ArmUnwindInfo::GetExceptionHandlingTableEntry(const Address& addr) { - uint32_t file_addr = addr.GetFileAddress(); - uint32_t exidx_base_addr = m_arm_exidx_sp->GetFileAddress(); - - const ArmExidxEntry* exidx_start = (const ArmExidxEntry*)m_arm_exidx_data.GetDataStart(); - uint32_t bs_start = 0, bs_end = m_arm_exidx_data.GetByteSize() / sizeof(ArmExidxEntry); - while (bs_start + 1 < bs_end) - { - uint32_t mid = (bs_start + bs_end) / 2; - uint32_t mid_addr = exidx_base_addr + exidx_start[mid].address + mid * sizeof(ArmExidxEntry); - mid_addr &= 0x7fffffff; - if (mid_addr > file_addr) - bs_end = mid; - else - bs_start = mid; - } - - uint32_t exidx_addr = exidx_base_addr + - exidx_start[bs_start].address + - bs_start * sizeof(ArmExidxEntry); - exidx_addr &= 0x7fffffff; - if (exidx_addr > file_addr) + auto it = std::upper_bound(m_exidx_entries.begin(), + m_exidx_entries.end(), + ArmExidxEntry{0, addr.GetFileAddress(), 0}); + if (it == m_exidx_entries.begin()) return nullptr; + --it; - if (exidx_start[bs_start].data == 0x1) + if (it->data == 0x1) return nullptr; // EXIDX_CANTUNWIND - if (exidx_start[bs_start].data & 0x80000000) - return (const uint8_t*)&exidx_start[bs_start].data; + if (it->data & 0x80000000) + return (const uint8_t*)&it->data; - uint32_t data_file_addr = exidx_base_addr + - 8 * bs_start + 4 + - exidx_start[bs_start].data; - data_file_addr &= 0x7fffffff; + addr_t data_file_addr = it->file_address + 4 + Prel31ToAddr(it->data); return m_arm_extab_data.GetDataStart() + (data_file_addr - m_arm_extab_sp->GetFileAddress()); } |

