180814287SRaphael Isemann //===-- UnwindTable.cpp ---------------------------------------------------===//
2fbcb7f2cSJason Molenda //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fbcb7f2cSJason Molenda //
7fbcb7f2cSJason Molenda //===----------------------------------------------------------------------===//
8fbcb7f2cSJason Molenda 
9a51ed9bbSGreg Clayton #include "lldb/Symbol/UnwindTable.h"
10fbcb7f2cSJason Molenda 
1176e47d48SRaphael Isemann #include <cstdio>
12a51ed9bbSGreg Clayton 
13a51ed9bbSGreg Clayton #include "lldb/Core/Module.h"
14a51ed9bbSGreg Clayton #include "lldb/Core/Section.h"
15648f3c7eSTamas Berghammer #include "lldb/Symbol/ArmUnwindInfo.h"
1630c2441aSAleksandr Urakov #include "lldb/Symbol/CallFrameInfo.h"
17e589e7e3SJason Molenda #include "lldb/Symbol/CompactUnwindInfo.h"
18b9c1b51eSKate Stone #include "lldb/Symbol/DWARFCallFrameInfo.h"
19b9c1b51eSKate Stone #include "lldb/Symbol/FuncUnwinders.h"
20b9c1b51eSKate Stone #include "lldb/Symbol/ObjectFile.h"
21b9c1b51eSKate Stone #include "lldb/Symbol/SymbolContext.h"
2222bbd7d6SPavel Labath #include "lldb/Symbol/SymbolVendor.h"
23fbcb7f2cSJason Molenda 
2405097246SAdrian Prantl // There is one UnwindTable object per ObjectFile. It contains a list of Unwind
2505097246SAdrian Prantl // objects -- one per function, populated lazily -- for the ObjectFile. Each
2605097246SAdrian Prantl // Unwind object has multiple UnwindPlans for different scenarios.
27fbcb7f2cSJason Molenda 
28fbcb7f2cSJason Molenda using namespace lldb;
29fbcb7f2cSJason Molenda using namespace lldb_private;
30fbcb7f2cSJason Molenda 
UnwindTable(Module & module)3166d88326SPavel Labath UnwindTable::UnwindTable(Module &module)
3266d88326SPavel Labath     : m_module(module), m_unwinds(), m_initialized(false), m_mutex(),
3330c2441aSAleksandr Urakov       m_object_file_unwind_up(), m_eh_frame_up(), m_compact_unwind_up(),
3430c2441aSAleksandr Urakov       m_arm_unwind_up() {}
35fbcb7f2cSJason Molenda 
36b9c1b51eSKate Stone // We can't do some of this initialization when the ObjectFile is running its
3705097246SAdrian Prantl // ctor; delay doing it until needed for something.
38fbcb7f2cSJason Molenda 
Initialize()39b9c1b51eSKate Stone void UnwindTable::Initialize() {
40fbcb7f2cSJason Molenda   if (m_initialized)
41fbcb7f2cSJason Molenda     return;
42fbcb7f2cSJason Molenda 
43bb19a13cSSaleem Abdulrasool   std::lock_guard<std::mutex> guard(m_mutex);
445cba569cSJason Molenda 
455cba569cSJason Molenda   if (m_initialized) // check again once we've acquired the lock
465cba569cSJason Molenda     return;
47cdda23ebSPavel Labath   m_initialized = true;
4866d88326SPavel Labath   ObjectFile *object_file = m_module.GetObjectFile();
4966d88326SPavel Labath   if (!object_file)
5066d88326SPavel Labath     return;
515cba569cSJason Molenda 
5230c2441aSAleksandr Urakov   m_object_file_unwind_up = object_file->CreateCallFrameInfo();
5330c2441aSAleksandr Urakov 
54dec96392SPavel Labath   SectionList *sl = m_module.GetSectionList();
55cdda23ebSPavel Labath   if (!sl)
56cdda23ebSPavel Labath     return;
57cdda23ebSPavel Labath 
58fbcb7f2cSJason Molenda   SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);
59b9c1b51eSKate Stone   if (sect.get()) {
6006412daeSJonas Devlieghere     m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>(
6106412daeSJonas Devlieghere         *object_file, sect, DWARFCallFrameInfo::EH);
62fbcb7f2cSJason Molenda   }
63cdda23ebSPavel Labath 
64cdda23ebSPavel Labath   sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);
65cdda23ebSPavel Labath   if (sect) {
6606412daeSJonas Devlieghere     m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>(
6706412daeSJonas Devlieghere         *object_file, sect, DWARFCallFrameInfo::DWARF);
68fbcb7f2cSJason Molenda   }
69fbcb7f2cSJason Molenda 
70cdda23ebSPavel Labath   sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);
71cdda23ebSPavel Labath   if (sect) {
7206412daeSJonas Devlieghere     m_compact_unwind_up =
7306412daeSJonas Devlieghere         std::make_unique<CompactUnwindInfo>(*object_file, sect);
74cdda23ebSPavel Labath   }
75cdda23ebSPavel Labath 
76cdda23ebSPavel Labath   sect = sl->FindSectionByType(eSectionTypeARMexidx, true);
77cdda23ebSPavel Labath   if (sect) {
78cdda23ebSPavel Labath     SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);
79cdda23ebSPavel Labath     if (sect_extab.get()) {
8006412daeSJonas Devlieghere       m_arm_unwind_up =
8106412daeSJonas Devlieghere           std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab);
82cdda23ebSPavel Labath     }
83cdda23ebSPavel Labath   }
84fbcb7f2cSJason Molenda }
85fbcb7f2cSJason Molenda 
86*fd2433e1SJonas Devlieghere UnwindTable::~UnwindTable() = default;
87fbcb7f2cSJason Molenda 
GetAddressRange(const Address & addr,SymbolContext & sc)88cdda23ebSPavel Labath llvm::Optional<AddressRange> UnwindTable::GetAddressRange(const Address &addr,
89cdda23ebSPavel Labath                                                           SymbolContext &sc) {
90cdda23ebSPavel Labath   AddressRange range;
91cdda23ebSPavel Labath 
9230c2441aSAleksandr Urakov   // First check the unwind info from the object file plugin
9330c2441aSAleksandr Urakov   if (m_object_file_unwind_up &&
9430c2441aSAleksandr Urakov       m_object_file_unwind_up->GetAddressRange(addr, range))
9530c2441aSAleksandr Urakov     return range;
9630c2441aSAleksandr Urakov 
9730c2441aSAleksandr Urakov   // Check the symbol context
98cdda23ebSPavel Labath   if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
99cdda23ebSPavel Labath                          false, range) &&
100cdda23ebSPavel Labath       range.GetBaseAddress().IsValid())
101cdda23ebSPavel Labath     return range;
102cdda23ebSPavel Labath 
103cdda23ebSPavel Labath   // Does the eh_frame unwind info has a function bounds for this addr?
104cdda23ebSPavel Labath   if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))
105cdda23ebSPavel Labath     return range;
106cdda23ebSPavel Labath 
107cdda23ebSPavel Labath   // Try debug_frame as well
108cdda23ebSPavel Labath   if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))
109cdda23ebSPavel Labath     return range;
110cdda23ebSPavel Labath 
111cdda23ebSPavel Labath   return llvm::None;
112cdda23ebSPavel Labath }
113cdda23ebSPavel Labath 
114fbcb7f2cSJason Molenda FuncUnwindersSP
GetFuncUnwindersContainingAddress(const Address & addr,SymbolContext & sc)115b9c1b51eSKate Stone UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
116b9c1b51eSKate Stone                                                SymbolContext &sc) {
117b0848c5dSGreg Clayton   Initialize();
118fbcb7f2cSJason Molenda 
119bb19a13cSSaleem Abdulrasool   std::lock_guard<std::mutex> guard(m_mutex);
1205cba569cSJason Molenda 
121b0848c5dSGreg Clayton   // There is an UnwindTable per object file, so we can safely use file handles
122b0848c5dSGreg Clayton   addr_t file_addr = addr.GetFileAddress();
123b0848c5dSGreg Clayton   iterator end = m_unwinds.end();
124b0848c5dSGreg Clayton   iterator insert_pos = end;
125b9c1b51eSKate Stone   if (!m_unwinds.empty()) {
126b0848c5dSGreg Clayton     insert_pos = m_unwinds.lower_bound(file_addr);
127b0848c5dSGreg Clayton     iterator pos = insert_pos;
128b9c1b51eSKate Stone     if ((pos == m_unwinds.end()) ||
129b9c1b51eSKate Stone         (pos != m_unwinds.begin() &&
130b9c1b51eSKate Stone          pos->second->GetFunctionStartAddress() != addr))
131b0848c5dSGreg Clayton       --pos;
132fbcb7f2cSJason Molenda 
133b0848c5dSGreg Clayton     if (pos->second->ContainsAddress(addr))
134b0848c5dSGreg Clayton       return pos->second;
135fbcb7f2cSJason Molenda   }
136fbcb7f2cSJason Molenda 
137cdda23ebSPavel Labath   auto range_or = GetAddressRange(addr, sc);
138cdda23ebSPavel Labath   if (!range_or)
139cdda23ebSPavel Labath     return nullptr;
1405976200dSJason Molenda 
141cdda23ebSPavel Labath   FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or));
142b9c1b51eSKate Stone   m_unwinds.insert(insert_pos,
143cdda23ebSPavel Labath                    std::make_pair(range_or->GetBaseAddress().GetFileAddress(),
144b9c1b51eSKate Stone                                   func_unwinder_sp));
145b0848c5dSGreg Clayton   return func_unwinder_sp;
146b0848c5dSGreg Clayton }
147b0848c5dSGreg Clayton 
148b9c1b51eSKate Stone // Ignore any existing FuncUnwinders for this function, create a new one and
14905097246SAdrian Prantl // don't add it to the UnwindTable.  This is intended for use by target modules
15005097246SAdrian Prantl // show-unwind where we want to create new UnwindPlans, not re-use existing
15105097246SAdrian Prantl // ones.
152380241a8SJason Molenda FuncUnwindersSP
GetUncachedFuncUnwindersContainingAddress(const Address & addr,SymbolContext & sc)153b9c1b51eSKate Stone UnwindTable::GetUncachedFuncUnwindersContainingAddress(const Address &addr,
154b9c1b51eSKate Stone                                                        SymbolContext &sc) {
155380241a8SJason Molenda   Initialize();
156380241a8SJason Molenda 
157cdda23ebSPavel Labath   auto range_or = GetAddressRange(addr, sc);
158cdda23ebSPavel Labath   if (!range_or)
159cdda23ebSPavel Labath     return nullptr;
160380241a8SJason Molenda 
161cdda23ebSPavel Labath   return std::make_shared<FuncUnwinders>(*this, *range_or);
162380241a8SJason Molenda }
163380241a8SJason Molenda 
Dump(Stream & s)164b9c1b51eSKate Stone void UnwindTable::Dump(Stream &s) {
165bb19a13cSSaleem Abdulrasool   std::lock_guard<std::mutex> guard(m_mutex);
16666d88326SPavel Labath   s.Format("UnwindTable for '{0}':\n", m_module.GetFileSpec());
167b0848c5dSGreg Clayton   const_iterator begin = m_unwinds.begin();
168b0848c5dSGreg Clayton   const_iterator end = m_unwinds.end();
169b9c1b51eSKate Stone   for (const_iterator pos = begin; pos != end; ++pos) {
170b9c1b51eSKate Stone     s.Printf("[%u] 0x%16.16" PRIx64 "\n", (unsigned)std::distance(begin, pos),
171b9c1b51eSKate Stone              pos->first);
172b0848c5dSGreg Clayton   }
173b0848c5dSGreg Clayton   s.EOL();
1745976200dSJason Molenda }
175fbcb7f2cSJason Molenda 
GetObjectFileUnwindInfo()17630c2441aSAleksandr Urakov lldb_private::CallFrameInfo *UnwindTable::GetObjectFileUnwindInfo() {
17730c2441aSAleksandr Urakov   Initialize();
17830c2441aSAleksandr Urakov   return m_object_file_unwind_up.get();
17930c2441aSAleksandr Urakov }
18030c2441aSAleksandr Urakov 
GetEHFrameInfo()181b9c1b51eSKate Stone DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() {
182b0848c5dSGreg Clayton   Initialize();
183648f3c7eSTamas Berghammer   return m_eh_frame_up.get();
184fbcb7f2cSJason Molenda }
185ab35aa92SJason Molenda 
GetDebugFrameInfo()186cdda23ebSPavel Labath DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() {
187cdda23ebSPavel Labath   Initialize();
188cdda23ebSPavel Labath   return m_debug_frame_up.get();
189cdda23ebSPavel Labath }
190cdda23ebSPavel Labath 
GetCompactUnwindInfo()191b9c1b51eSKate Stone CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() {
192e589e7e3SJason Molenda   Initialize();
193648f3c7eSTamas Berghammer   return m_compact_unwind_up.get();
194648f3c7eSTamas Berghammer }
195648f3c7eSTamas Berghammer 
GetArmUnwindInfo()196b9c1b51eSKate Stone ArmUnwindInfo *UnwindTable::GetArmUnwindInfo() {
197648f3c7eSTamas Berghammer   Initialize();
198648f3c7eSTamas Berghammer   return m_arm_unwind_up.get();
199e589e7e3SJason Molenda }
200e589e7e3SJason Molenda 
GetSymbolFile()20123f70e83SPavel Labath SymbolFile *UnwindTable::GetSymbolFile() { return m_module.GetSymbolFile(); }
20222bbd7d6SPavel Labath 
GetArchitecture()20366d88326SPavel Labath ArchSpec UnwindTable::GetArchitecture() { return m_module.GetArchitecture(); }
204955dcf2dSJason Molenda 
GetAllowAssemblyEmulationUnwindPlans()205b9c1b51eSKate Stone bool UnwindTable::GetAllowAssemblyEmulationUnwindPlans() {
20666d88326SPavel Labath   if (ObjectFile *object_file = m_module.GetObjectFile())
20766d88326SPavel Labath     return object_file->AllowAssemblyEmulationUnwindPlans();
20866d88326SPavel Labath   return false;
209955dcf2dSJason Molenda }
210