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