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_initialized(false), m_mutex(), 34 m_object_file_unwind_up(), m_eh_frame_up(), m_compact_unwind_up(), 35 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 40 void UnwindTable::Initialize() { 41 if (m_initialized) 42 return; 43 44 std::lock_guard<std::mutex> guard(m_mutex); 45 46 if (m_initialized) // check again once we've acquired the lock 47 return; 48 m_initialized = true; 49 ObjectFile *object_file = m_module.GetObjectFile(); 50 if (!object_file) 51 return; 52 53 m_object_file_unwind_up = object_file->CreateCallFrameInfo(); 54 55 SectionList *sl = m_module.GetSectionList(); 56 if (!sl) 57 return; 58 59 SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true); 60 if (sect.get()) { 61 m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>( 62 *object_file, sect, DWARFCallFrameInfo::EH); 63 } 64 65 sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true); 66 if (sect) { 67 m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>( 68 *object_file, sect, DWARFCallFrameInfo::DWARF); 69 } 70 71 sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true); 72 if (sect) { 73 m_compact_unwind_up = 74 std::make_unique<CompactUnwindInfo>(*object_file, sect); 75 } 76 77 sect = sl->FindSectionByType(eSectionTypeARMexidx, true); 78 if (sect) { 79 SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true); 80 if (sect_extab.get()) { 81 m_arm_unwind_up = 82 std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab); 83 } 84 } 85 } 86 87 void UnwindTable::Update() { 88 if (!m_initialized) 89 return Initialize(); 90 91 std::lock_guard<std::mutex> guard(m_mutex); 92 93 ObjectFile *object_file = m_module.GetObjectFile(); 94 if (!object_file) 95 return; 96 97 if (!m_object_file_unwind_up) 98 m_object_file_unwind_up = object_file->CreateCallFrameInfo(); 99 100 SectionList *sl = m_module.GetSectionList(); 101 if (!sl) 102 return; 103 104 SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true); 105 if (!m_eh_frame_up && sect) { 106 m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>( 107 *object_file, sect, DWARFCallFrameInfo::EH); 108 } 109 110 sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true); 111 if (!m_debug_frame_up && sect) { 112 m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>( 113 *object_file, sect, DWARFCallFrameInfo::DWARF); 114 } 115 116 sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true); 117 if (!m_compact_unwind_up && sect) { 118 m_compact_unwind_up = 119 std::make_unique<CompactUnwindInfo>(*object_file, sect); 120 } 121 122 sect = sl->FindSectionByType(eSectionTypeARMexidx, true); 123 if (!m_arm_unwind_up && sect) { 124 SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true); 125 if (sect_extab.get()) { 126 m_arm_unwind_up = 127 std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab); 128 } 129 } 130 } 131 132 UnwindTable::~UnwindTable() = default; 133 134 std::optional<AddressRange> 135 UnwindTable::GetAddressRange(const Address &addr, const SymbolContext &sc) { 136 AddressRange range; 137 138 // First check the unwind info from the object file plugin 139 if (m_object_file_unwind_up && 140 m_object_file_unwind_up->GetAddressRange(addr, range)) 141 return range; 142 143 // Check the symbol context 144 if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, 145 false, range) && 146 range.GetBaseAddress().IsValid()) 147 return range; 148 149 // Does the eh_frame unwind info has a function bounds for this addr? 150 if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range)) 151 return range; 152 153 // Try debug_frame as well 154 if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range)) 155 return range; 156 157 return std::nullopt; 158 } 159 160 FuncUnwindersSP 161 UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr, 162 SymbolContext &sc) { 163 Initialize(); 164 165 std::lock_guard<std::mutex> guard(m_mutex); 166 167 // There is an UnwindTable per object file, so we can safely use file handles 168 addr_t file_addr = addr.GetFileAddress(); 169 iterator end = m_unwinds.end(); 170 iterator insert_pos = end; 171 if (!m_unwinds.empty()) { 172 insert_pos = m_unwinds.lower_bound(file_addr); 173 iterator pos = insert_pos; 174 if ((pos == m_unwinds.end()) || 175 (pos != m_unwinds.begin() && 176 pos->second->GetFunctionStartAddress() != addr)) 177 --pos; 178 179 if (pos->second->ContainsAddress(addr)) 180 return pos->second; 181 } 182 183 auto range_or = GetAddressRange(addr, sc); 184 if (!range_or) 185 return nullptr; 186 187 FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or)); 188 m_unwinds.insert(insert_pos, 189 std::make_pair(range_or->GetBaseAddress().GetFileAddress(), 190 func_unwinder_sp)); 191 return func_unwinder_sp; 192 } 193 194 // Ignore any existing FuncUnwinders for this function, create a new one and 195 // don't add it to the UnwindTable. This is intended for use by target modules 196 // show-unwind where we want to create new UnwindPlans, not re-use existing 197 // ones. 198 FuncUnwindersSP UnwindTable::GetUncachedFuncUnwindersContainingAddress( 199 const Address &addr, const SymbolContext &sc) { 200 Initialize(); 201 202 auto range_or = GetAddressRange(addr, sc); 203 if (!range_or) 204 return nullptr; 205 206 return std::make_shared<FuncUnwinders>(*this, *range_or); 207 } 208 209 void UnwindTable::Dump(Stream &s) { 210 std::lock_guard<std::mutex> guard(m_mutex); 211 s.Format("UnwindTable for '{0}':\n", m_module.GetFileSpec()); 212 const_iterator begin = m_unwinds.begin(); 213 const_iterator end = m_unwinds.end(); 214 for (const_iterator pos = begin; pos != end; ++pos) { 215 s.Printf("[%u] 0x%16.16" PRIx64 "\n", (unsigned)std::distance(begin, pos), 216 pos->first); 217 } 218 s.EOL(); 219 } 220 221 lldb_private::CallFrameInfo *UnwindTable::GetObjectFileUnwindInfo() { 222 Initialize(); 223 return m_object_file_unwind_up.get(); 224 } 225 226 DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() { 227 Initialize(); 228 return m_eh_frame_up.get(); 229 } 230 231 DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() { 232 Initialize(); 233 return m_debug_frame_up.get(); 234 } 235 236 CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() { 237 Initialize(); 238 return m_compact_unwind_up.get(); 239 } 240 241 ArmUnwindInfo *UnwindTable::GetArmUnwindInfo() { 242 Initialize(); 243 return m_arm_unwind_up.get(); 244 } 245 246 SymbolFile *UnwindTable::GetSymbolFile() { return m_module.GetSymbolFile(); } 247 248 ArchSpec UnwindTable::GetArchitecture() { return m_module.GetArchitecture(); } 249 250 bool UnwindTable::GetAllowAssemblyEmulationUnwindPlans() { 251 if (ObjectFile *object_file = m_module.GetObjectFile()) 252 return object_file->AllowAssemblyEmulationUnwindPlans(); 253 return false; 254 } 255