1 //===-- UnwindTable.cpp -----------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Symbol/UnwindTable.h" 10 11 #include <stdio.h> 12 13 #include "lldb/Core/Module.h" 14 #include "lldb/Core/Section.h" 15 #include "lldb/Symbol/ArmUnwindInfo.h" 16 #include "lldb/Symbol/CompactUnwindInfo.h" 17 #include "lldb/Symbol/DWARFCallFrameInfo.h" 18 #include "lldb/Symbol/FuncUnwinders.h" 19 #include "lldb/Symbol/ObjectFile.h" 20 #include "lldb/Symbol/SymbolContext.h" 21 22 // There is one UnwindTable object per ObjectFile. It contains a list of Unwind 23 // objects -- one per function, populated lazily -- for the ObjectFile. Each 24 // Unwind object has multiple UnwindPlans for different scenarios. 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 UnwindTable::UnwindTable(ObjectFile &objfile) 30 : m_object_file(objfile), m_unwinds(), m_initialized(false), m_mutex(), 31 m_eh_frame_up(), m_compact_unwind_up(), m_arm_unwind_up() {} 32 33 // We can't do some of this initialization when the ObjectFile is running its 34 // ctor; delay doing it until needed for something. 35 36 void UnwindTable::Initialize() { 37 if (m_initialized) 38 return; 39 40 std::lock_guard<std::mutex> guard(m_mutex); 41 42 if (m_initialized) // check again once we've acquired the lock 43 return; 44 m_initialized = true; 45 46 SectionList *sl = m_object_file.GetSectionList(); 47 if (!sl) 48 return; 49 50 SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true); 51 if (sect.get()) { 52 m_eh_frame_up.reset( 53 new DWARFCallFrameInfo(m_object_file, sect, DWARFCallFrameInfo::EH)); 54 } 55 56 sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true); 57 if (sect) { 58 m_debug_frame_up.reset( 59 new DWARFCallFrameInfo(m_object_file, sect, DWARFCallFrameInfo::DWARF)); 60 } 61 62 sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true); 63 if (sect) { 64 m_compact_unwind_up.reset(new CompactUnwindInfo(m_object_file, sect)); 65 } 66 67 sect = sl->FindSectionByType(eSectionTypeARMexidx, true); 68 if (sect) { 69 SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true); 70 if (sect_extab.get()) { 71 m_arm_unwind_up.reset(new ArmUnwindInfo(m_object_file, sect, sect_extab)); 72 } 73 } 74 } 75 76 UnwindTable::~UnwindTable() {} 77 78 llvm::Optional<AddressRange> UnwindTable::GetAddressRange(const Address &addr, 79 SymbolContext &sc) { 80 AddressRange range; 81 82 // First check the symbol context 83 if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, 84 false, range) && 85 range.GetBaseAddress().IsValid()) 86 return range; 87 88 // Does the eh_frame unwind info has a function bounds for this addr? 89 if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range)) 90 return range; 91 92 // Try debug_frame as well 93 if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range)) 94 return range; 95 96 return llvm::None; 97 } 98 99 FuncUnwindersSP 100 UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr, 101 SymbolContext &sc) { 102 Initialize(); 103 104 std::lock_guard<std::mutex> guard(m_mutex); 105 106 // There is an UnwindTable per object file, so we can safely use file handles 107 addr_t file_addr = addr.GetFileAddress(); 108 iterator end = m_unwinds.end(); 109 iterator insert_pos = end; 110 if (!m_unwinds.empty()) { 111 insert_pos = m_unwinds.lower_bound(file_addr); 112 iterator pos = insert_pos; 113 if ((pos == m_unwinds.end()) || 114 (pos != m_unwinds.begin() && 115 pos->second->GetFunctionStartAddress() != addr)) 116 --pos; 117 118 if (pos->second->ContainsAddress(addr)) 119 return pos->second; 120 } 121 122 auto range_or = GetAddressRange(addr, sc); 123 if (!range_or) 124 return nullptr; 125 126 FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or)); 127 m_unwinds.insert(insert_pos, 128 std::make_pair(range_or->GetBaseAddress().GetFileAddress(), 129 func_unwinder_sp)); 130 return func_unwinder_sp; 131 } 132 133 // Ignore any existing FuncUnwinders for this function, create a new one and 134 // don't add it to the UnwindTable. This is intended for use by target modules 135 // show-unwind where we want to create new UnwindPlans, not re-use existing 136 // ones. 137 FuncUnwindersSP 138 UnwindTable::GetUncachedFuncUnwindersContainingAddress(const Address &addr, 139 SymbolContext &sc) { 140 Initialize(); 141 142 auto range_or = GetAddressRange(addr, sc); 143 if (!range_or) 144 return nullptr; 145 146 return std::make_shared<FuncUnwinders>(*this, *range_or); 147 } 148 149 void UnwindTable::Dump(Stream &s) { 150 std::lock_guard<std::mutex> guard(m_mutex); 151 s.Printf("UnwindTable for '%s':\n", 152 m_object_file.GetFileSpec().GetPath().c_str()); 153 const_iterator begin = m_unwinds.begin(); 154 const_iterator end = m_unwinds.end(); 155 for (const_iterator pos = begin; pos != end; ++pos) { 156 s.Printf("[%u] 0x%16.16" PRIx64 "\n", (unsigned)std::distance(begin, pos), 157 pos->first); 158 } 159 s.EOL(); 160 } 161 162 DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() { 163 Initialize(); 164 return m_eh_frame_up.get(); 165 } 166 167 DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() { 168 Initialize(); 169 return m_debug_frame_up.get(); 170 } 171 172 CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() { 173 Initialize(); 174 return m_compact_unwind_up.get(); 175 } 176 177 ArmUnwindInfo *UnwindTable::GetArmUnwindInfo() { 178 Initialize(); 179 return m_arm_unwind_up.get(); 180 } 181 182 ArchSpec UnwindTable::GetArchitecture() { 183 return m_object_file.GetArchitecture(); 184 } 185 186 bool UnwindTable::GetAllowAssemblyEmulationUnwindPlans() { 187 return m_object_file.AllowAssemblyEmulationUnwindPlans(); 188 } 189