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