llvm-project

Форк
0
/
UnwindTable.cpp 
254 строки · 7.7 Кб
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
#include <optional>
13

14
#include "lldb/Core/Module.h"
15
#include "lldb/Core/Section.h"
16
#include "lldb/Symbol/ArmUnwindInfo.h"
17
#include "lldb/Symbol/CallFrameInfo.h"
18
#include "lldb/Symbol/CompactUnwindInfo.h"
19
#include "lldb/Symbol/DWARFCallFrameInfo.h"
20
#include "lldb/Symbol/FuncUnwinders.h"
21
#include "lldb/Symbol/ObjectFile.h"
22
#include "lldb/Symbol/SymbolContext.h"
23
#include "lldb/Symbol/SymbolVendor.h"
24

25
// There is one UnwindTable object per ObjectFile. It contains a list of Unwind
26
// objects -- one per function, populated lazily -- for the ObjectFile. Each
27
// Unwind object has multiple UnwindPlans for different scenarios.
28

29
using namespace lldb;
30
using namespace lldb_private;
31

32
UnwindTable::UnwindTable(Module &module)
33
    : m_module(module), m_unwinds(), m_initialized(false), m_mutex(),
34
      m_object_file_unwind_up(), m_eh_frame_up(), m_compact_unwind_up(),
35
      m_arm_unwind_up() {}
36

37
// We can't do some of this initialization when the ObjectFile is running its
38
// ctor; delay doing it until needed for something.
39

40
void UnwindTable::Initialize() {
41
  if (m_initialized)
42
    return;
43

44
  std::lock_guard<std::mutex> guard(m_mutex);
45

46
  if (m_initialized) // check again once we've acquired the lock
47
    return;
48
  m_initialized = true;
49
  ObjectFile *object_file = m_module.GetObjectFile();
50
  if (!object_file)
51
    return;
52

53
  m_object_file_unwind_up = object_file->CreateCallFrameInfo();
54

55
  SectionList *sl = m_module.GetSectionList();
56
  if (!sl)
57
    return;
58

59
  SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);
60
  if (sect.get()) {
61
    m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>(
62
        *object_file, sect, DWARFCallFrameInfo::EH);
63
  }
64

65
  sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);
66
  if (sect) {
67
    m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>(
68
        *object_file, sect, DWARFCallFrameInfo::DWARF);
69
  }
70

71
  sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);
72
  if (sect) {
73
    m_compact_unwind_up =
74
        std::make_unique<CompactUnwindInfo>(*object_file, sect);
75
  }
76

77
  sect = sl->FindSectionByType(eSectionTypeARMexidx, true);
78
  if (sect) {
79
    SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);
80
    if (sect_extab.get()) {
81
      m_arm_unwind_up =
82
          std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab);
83
    }
84
  }
85
}
86

87
void UnwindTable::Update() {
88
  if (!m_initialized)
89
    return Initialize();
90

91
  std::lock_guard<std::mutex> guard(m_mutex);
92

93
  ObjectFile *object_file = m_module.GetObjectFile();
94
  if (!object_file)
95
    return;
96

97
  if (!m_object_file_unwind_up)
98
    m_object_file_unwind_up = object_file->CreateCallFrameInfo();
99

100
  SectionList *sl = m_module.GetSectionList();
101
  if (!sl)
102
    return;
103

104
  SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);
105
  if (!m_eh_frame_up && sect) {
106
    m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>(
107
        *object_file, sect, DWARFCallFrameInfo::EH);
108
  }
109

110
  sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);
111
  if (!m_debug_frame_up && sect) {
112
    m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>(
113
        *object_file, sect, DWARFCallFrameInfo::DWARF);
114
  }
115

116
  sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);
117
  if (!m_compact_unwind_up && sect) {
118
    m_compact_unwind_up =
119
        std::make_unique<CompactUnwindInfo>(*object_file, sect);
120
  }
121

122
  sect = sl->FindSectionByType(eSectionTypeARMexidx, true);
123
  if (!m_arm_unwind_up && sect) {
124
    SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);
125
    if (sect_extab.get()) {
126
      m_arm_unwind_up =
127
          std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab);
128
    }
129
  }
130
}
131

132
UnwindTable::~UnwindTable() = default;
133

134
std::optional<AddressRange>
135
UnwindTable::GetAddressRange(const Address &addr, const SymbolContext &sc) {
136
  AddressRange range;
137

138
  // First check the unwind info from the object file plugin
139
  if (m_object_file_unwind_up &&
140
      m_object_file_unwind_up->GetAddressRange(addr, range))
141
    return range;
142

143
  // Check the symbol context
144
  if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
145
                         false, range) &&
146
      range.GetBaseAddress().IsValid())
147
    return range;
148

149
  // Does the eh_frame unwind info has a function bounds for this addr?
150
  if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))
151
    return range;
152

153
  // Try debug_frame as well
154
  if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))
155
    return range;
156

157
  return std::nullopt;
158
}
159

160
FuncUnwindersSP
161
UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
162
                                               SymbolContext &sc) {
163
  Initialize();
164

165
  std::lock_guard<std::mutex> guard(m_mutex);
166

167
  // There is an UnwindTable per object file, so we can safely use file handles
168
  addr_t file_addr = addr.GetFileAddress();
169
  iterator end = m_unwinds.end();
170
  iterator insert_pos = end;
171
  if (!m_unwinds.empty()) {
172
    insert_pos = m_unwinds.lower_bound(file_addr);
173
    iterator pos = insert_pos;
174
    if ((pos == m_unwinds.end()) ||
175
        (pos != m_unwinds.begin() &&
176
         pos->second->GetFunctionStartAddress() != addr))
177
      --pos;
178

179
    if (pos->second->ContainsAddress(addr))
180
      return pos->second;
181
  }
182

183
  auto range_or = GetAddressRange(addr, sc);
184
  if (!range_or)
185
    return nullptr;
186

187
  FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or));
188
  m_unwinds.insert(insert_pos,
189
                   std::make_pair(range_or->GetBaseAddress().GetFileAddress(),
190
                                  func_unwinder_sp));
191
  return func_unwinder_sp;
192
}
193

194
// Ignore any existing FuncUnwinders for this function, create a new one and
195
// don't add it to the UnwindTable.  This is intended for use by target modules
196
// show-unwind where we want to create new UnwindPlans, not re-use existing
197
// ones.
198
FuncUnwindersSP UnwindTable::GetUncachedFuncUnwindersContainingAddress(
199
    const Address &addr, const SymbolContext &sc) {
200
  Initialize();
201

202
  auto range_or = GetAddressRange(addr, sc);
203
  if (!range_or)
204
    return nullptr;
205

206
  return std::make_shared<FuncUnwinders>(*this, *range_or);
207
}
208

209
void UnwindTable::Dump(Stream &s) {
210
  std::lock_guard<std::mutex> guard(m_mutex);
211
  s.Format("UnwindTable for '{0}':\n", m_module.GetFileSpec());
212
  const_iterator begin = m_unwinds.begin();
213
  const_iterator end = m_unwinds.end();
214
  for (const_iterator pos = begin; pos != end; ++pos) {
215
    s.Printf("[%u] 0x%16.16" PRIx64 "\n", (unsigned)std::distance(begin, pos),
216
             pos->first);
217
  }
218
  s.EOL();
219
}
220

221
lldb_private::CallFrameInfo *UnwindTable::GetObjectFileUnwindInfo() {
222
  Initialize();
223
  return m_object_file_unwind_up.get();
224
}
225

226
DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() {
227
  Initialize();
228
  return m_eh_frame_up.get();
229
}
230

231
DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() {
232
  Initialize();
233
  return m_debug_frame_up.get();
234
}
235

236
CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() {
237
  Initialize();
238
  return m_compact_unwind_up.get();
239
}
240

241
ArmUnwindInfo *UnwindTable::GetArmUnwindInfo() {
242
  Initialize();
243
  return m_arm_unwind_up.get();
244
}
245

246
SymbolFile *UnwindTable::GetSymbolFile() { return m_module.GetSymbolFile(); }
247

248
ArchSpec UnwindTable::GetArchitecture() { return m_module.GetArchitecture(); }
249

250
bool UnwindTable::GetAllowAssemblyEmulationUnwindPlans() {
251
  if (ObjectFile *object_file = m_module.GetObjectFile())
252
    return object_file->AllowAssemblyEmulationUnwindPlans();
253
  return false;
254
}
255

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.