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