UnwindTable.cpp revision 360784
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/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
28using namespace lldb;
29using namespace lldb_private;
30
31UnwindTable::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
39void 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.reset(
61        new DWARFCallFrameInfo(*object_file, sect, DWARFCallFrameInfo::EH));
62  }
63
64  sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);
65  if (sect) {
66    m_debug_frame_up.reset(
67        new DWARFCallFrameInfo(*object_file, sect, DWARFCallFrameInfo::DWARF));
68  }
69
70  sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);
71  if (sect) {
72    m_compact_unwind_up.reset(new CompactUnwindInfo(*object_file, sect));
73  }
74
75  sect = sl->FindSectionByType(eSectionTypeARMexidx, true);
76  if (sect) {
77    SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);
78    if (sect_extab.get()) {
79      m_arm_unwind_up.reset(new ArmUnwindInfo(*object_file, sect, sect_extab));
80    }
81  }
82}
83
84UnwindTable::~UnwindTable() {}
85
86llvm::Optional<AddressRange> UnwindTable::GetAddressRange(const Address &addr,
87                                                          SymbolContext &sc) {
88  AddressRange range;
89
90  // First check the unwind info from the object file plugin
91  if (m_object_file_unwind_up &&
92      m_object_file_unwind_up->GetAddressRange(addr, range))
93    return range;
94
95  // Check the symbol context
96  if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
97                         false, range) &&
98      range.GetBaseAddress().IsValid())
99    return range;
100
101  // Does the eh_frame unwind info has a function bounds for this addr?
102  if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))
103    return range;
104
105  // Try debug_frame as well
106  if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))
107    return range;
108
109  return llvm::None;
110}
111
112FuncUnwindersSP
113UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
114                                               SymbolContext &sc) {
115  Initialize();
116
117  std::lock_guard<std::mutex> guard(m_mutex);
118
119  // There is an UnwindTable per object file, so we can safely use file handles
120  addr_t file_addr = addr.GetFileAddress();
121  iterator end = m_unwinds.end();
122  iterator insert_pos = end;
123  if (!m_unwinds.empty()) {
124    insert_pos = m_unwinds.lower_bound(file_addr);
125    iterator pos = insert_pos;
126    if ((pos == m_unwinds.end()) ||
127        (pos != m_unwinds.begin() &&
128         pos->second->GetFunctionStartAddress() != addr))
129      --pos;
130
131    if (pos->second->ContainsAddress(addr))
132      return pos->second;
133  }
134
135  auto range_or = GetAddressRange(addr, sc);
136  if (!range_or)
137    return nullptr;
138
139  FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or));
140  m_unwinds.insert(insert_pos,
141                   std::make_pair(range_or->GetBaseAddress().GetFileAddress(),
142                                  func_unwinder_sp));
143  return func_unwinder_sp;
144}
145
146// Ignore any existing FuncUnwinders for this function, create a new one and
147// don't add it to the UnwindTable.  This is intended for use by target modules
148// show-unwind where we want to create new UnwindPlans, not re-use existing
149// ones.
150FuncUnwindersSP
151UnwindTable::GetUncachedFuncUnwindersContainingAddress(const Address &addr,
152                                                       SymbolContext &sc) {
153  Initialize();
154
155  auto range_or = GetAddressRange(addr, sc);
156  if (!range_or)
157    return nullptr;
158
159  return std::make_shared<FuncUnwinders>(*this, *range_or);
160}
161
162void UnwindTable::Dump(Stream &s) {
163  std::lock_guard<std::mutex> guard(m_mutex);
164  s.Format("UnwindTable for '{0}':\n", m_module.GetFileSpec());
165  const_iterator begin = m_unwinds.begin();
166  const_iterator end = m_unwinds.end();
167  for (const_iterator pos = begin; pos != end; ++pos) {
168    s.Printf("[%u] 0x%16.16" PRIx64 "\n", (unsigned)std::distance(begin, pos),
169             pos->first);
170  }
171  s.EOL();
172}
173
174lldb_private::CallFrameInfo *UnwindTable::GetObjectFileUnwindInfo() {
175  Initialize();
176  return m_object_file_unwind_up.get();
177}
178
179DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() {
180  Initialize();
181  return m_eh_frame_up.get();
182}
183
184DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() {
185  Initialize();
186  return m_debug_frame_up.get();
187}
188
189CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() {
190  Initialize();
191  return m_compact_unwind_up.get();
192}
193
194ArmUnwindInfo *UnwindTable::GetArmUnwindInfo() {
195  Initialize();
196  return m_arm_unwind_up.get();
197}
198
199SymbolFile *UnwindTable::GetSymbolFile() { return m_module.GetSymbolFile(); }
200
201ArchSpec UnwindTable::GetArchitecture() { return m_module.GetArchitecture(); }
202
203bool UnwindTable::GetAllowAssemblyEmulationUnwindPlans() {
204  if (ObjectFile *object_file = m_module.GetObjectFile())
205    return object_file->AllowAssemblyEmulationUnwindPlans();
206  return false;
207}
208