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