Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- DebugNamesDWARFIndex.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 "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
10
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
11
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
12
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
13
#include "lldb/Core/Module.h"
14
#include "lldb/Utility/RegularExpression.h"
15
#include "lldb/Utility/Stream.h"
16
17
using namespace lldb_private;
18
using namespace lldb;
19
20
llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
21
DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
22
                             DWARFDataExtractor debug_str,
23
4
                             SymbolFileDWARF &dwarf) {
24
4
  auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVM(),
25
4
                                                debug_str.GetAsLLVM());
26
4
  if (llvm::Error E = index_up->extract())
27
1
    return std::move(E);
28
29
3
  return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
30
3
      module, std::move(index_up), debug_names, debug_str, dwarf));
31
4
}
32
33
llvm::DenseSet<dw_offset_t>
34
3
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
35
3
  llvm::DenseSet<dw_offset_t> result;
36
4
  for (const DebugNames::NameIndex &ni : debug_names) {
37
8
    for (uint32_t cu = 0; cu < ni.getCUCount(); 
++cu4
)
38
4
      result.insert(ni.getCUOffset(cu));
39
4
  }
40
3
  return result;
41
3
}
42
43
llvm::Optional<DIERef>
44
7
DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
45
7
  llvm::Optional<uint64_t> cu_offset = entry.getCUOffset();
46
7
  if (!cu_offset)
47
0
    return llvm::None;
48
49
7
  DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
50
7
  if (!cu)
51
0
    return llvm::None;
52
53
7
  cu = &cu->GetNonSkeletonUnit();
54
7
  if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset())
55
7
    return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(),
56
7
                  DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
57
58
0
  return llvm::None;
59
7
}
60
61
bool DebugNamesDWARFIndex::ProcessEntry(
62
    const DebugNames::Entry &entry,
63
0
    llvm::function_ref<bool(DWARFDIE die)> callback, llvm::StringRef name) {
64
0
  llvm::Optional<DIERef> ref = ToDIERef(entry);
65
0
  if (!ref)
66
0
    return true;
67
0
  SymbolFileDWARF &dwarf =
68
0
      *llvm::cast<SymbolFileDWARF>(m_module.GetSymbolFile());
69
0
  DWARFDIE die = dwarf.GetDIE(*ref);
70
0
  if (!die)
71
0
    return true;
72
0
  return callback(die);
73
0
}
74
75
void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
76
                                               const DebugNames::NameIndex &ni,
77
0
                                               llvm::StringRef name) {
78
  // Ignore SentinelErrors, log everything else.
79
0
  LLDB_LOG_ERROR(
80
0
      LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS),
81
0
      handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
82
0
      "Failed to parse index entries for index at {1:x}, name {2}: {0}",
83
0
      ni.getUnitOffset(), name);
84
0
}
85
86
void DebugNamesDWARFIndex::GetGlobalVariables(
87
0
    ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
88
0
  for (const DebugNames::Entry &entry :
89
0
       m_debug_names_up->equal_range(basename.GetStringRef())) {
90
0
    if (entry.tag() != DW_TAG_variable)
91
0
      continue;
92
93
0
    if (!ProcessEntry(entry, callback, basename.GetStringRef()))
94
0
      return;
95
0
  }
96
97
0
  m_fallback.GetGlobalVariables(basename, callback);
98
0
}
99
100
void DebugNamesDWARFIndex::GetGlobalVariables(
101
    const RegularExpression &regex,
102
0
    llvm::function_ref<bool(DWARFDIE die)> callback) {
103
0
  for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
104
0
    for (DebugNames::NameTableEntry nte: ni) {
105
0
      if (!regex.Execute(nte.getString()))
106
0
        continue;
107
108
0
      uint64_t entry_offset = nte.getEntryOffset();
109
0
      llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
110
0
      for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
111
0
        if (entry_or->tag() != DW_TAG_variable)
112
0
          continue;
113
114
0
        if (!ProcessEntry(*entry_or, callback,
115
0
                          llvm::StringRef(nte.getString())))
116
0
          return;
117
0
      }
118
0
      MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
119
0
    }
120
0
  }
121
122
0
  m_fallback.GetGlobalVariables(regex, callback);
123
0
}
124
125
void DebugNamesDWARFIndex::GetGlobalVariables(
126
0
    DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
127
0
  lldbassert(!cu.GetSymbolFileDWARF().GetDwoNum());
128
0
  uint64_t cu_offset = cu.GetOffset();
129
0
  bool found_entry_for_cu = false;
130
0
  for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
131
0
    for (DebugNames::NameTableEntry nte: ni) {
132
0
      uint64_t entry_offset = nte.getEntryOffset();
133
0
      llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
134
0
      for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
135
0
        if (entry_or->tag() != DW_TAG_variable)
136
0
          continue;
137
0
        if (entry_or->getCUOffset() != cu_offset)
138
0
          continue;
139
140
0
        found_entry_for_cu = true;
141
0
        if (!ProcessEntry(*entry_or, callback,
142
0
                          llvm::StringRef(nte.getString())))
143
0
          return;
144
0
      }
145
0
      MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
146
0
    }
147
0
  }
148
  // If no name index for that particular CU was found, fallback to
149
  // creating the manual index.
150
0
  if (!found_entry_for_cu)
151
0
    m_fallback.GetGlobalVariables(cu, callback);
152
0
}
153
154
void DebugNamesDWARFIndex::GetCompleteObjCClass(
155
    ConstString class_name, bool must_be_implementation,
156
0
    llvm::function_ref<bool(DWARFDIE die)> callback) {
157
  // Keep a list of incomplete types as fallback for when we don't find the
158
  // complete type.
159
0
  DIEArray incomplete_types;
160
161
0
  for (const DebugNames::Entry &entry :
162
0
       m_debug_names_up->equal_range(class_name.GetStringRef())) {
163
0
    if (entry.tag() != DW_TAG_structure_type &&
164
0
        entry.tag() != DW_TAG_class_type)
165
0
      continue;
166
167
0
    llvm::Optional<DIERef> ref = ToDIERef(entry);
168
0
    if (!ref)
169
0
      continue;
170
171
0
    DWARFUnit *cu = m_debug_info.GetUnit(*ref);
172
0
    if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
173
0
      incomplete_types.push_back(*ref);
174
0
      continue;
175
0
    }
176
177
0
    DWARFDIE die = m_debug_info.GetDIE(*ref);
178
0
    if (!die) {
179
0
      ReportInvalidDIERef(*ref, class_name.GetStringRef());
180
0
      continue;
181
0
    }
182
183
0
    if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
184
      // If we find the complete version we're done.
185
0
      callback(die);
186
0
      return;
187
0
    }
188
0
    incomplete_types.push_back(*ref);
189
0
  }
190
191
0
  auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef());
192
0
  for (DIERef ref : incomplete_types)
193
0
    if (!dierefcallback(ref))
194
0
      return;
195
196
0
  m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
197
0
}
198
199
void DebugNamesDWARFIndex::GetTypes(
200
0
    ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
201
0
  for (const DebugNames::Entry &entry :
202
0
       m_debug_names_up->equal_range(name.GetStringRef())) {
203
0
    if (isType(entry.tag())) {
204
0
      if (!ProcessEntry(entry, callback, name.GetStringRef()))
205
0
        return;
206
0
    }
207
0
  }
208
209
0
  m_fallback.GetTypes(name, callback);
210
0
}
211
212
void DebugNamesDWARFIndex::GetTypes(
213
    const DWARFDeclContext &context,
214
0
    llvm::function_ref<bool(DWARFDIE die)> callback) {
215
0
  auto name = context[0].name;
216
0
  for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
217
0
    if (entry.tag() == context[0].tag) {
218
0
      if (!ProcessEntry(entry, callback, name))
219
0
        return;
220
0
    }
221
0
  }
222
223
0
  m_fallback.GetTypes(context, callback);
224
0
}
225
226
void DebugNamesDWARFIndex::GetNamespaces(
227
0
    ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
228
0
  for (const DebugNames::Entry &entry :
229
0
       m_debug_names_up->equal_range(name.GetStringRef())) {
230
0
    if (entry.tag() == DW_TAG_namespace) {
231
0
      if (!ProcessEntry(entry, callback, name.GetStringRef()))
232
0
        return;
233
0
    }
234
0
  }
235
236
0
  m_fallback.GetNamespaces(name, callback);
237
0
}
238
239
void DebugNamesDWARFIndex::GetFunctions(
240
    ConstString name, SymbolFileDWARF &dwarf,
241
    const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
242
5
    llvm::function_ref<bool(DWARFDIE die)> callback) {
243
244
5
  std::set<DWARFDebugInfoEntry *> seen;
245
5
  for (const DebugNames::Entry &entry :
246
7
       m_debug_names_up->equal_range(name.GetStringRef())) {
247
7
    Tag tag = entry.tag();
248
7
    if (tag != DW_TAG_subprogram && 
tag != DW_TAG_inlined_subroutine0
)
249
0
      continue;
250
251
7
    if (llvm::Optional<DIERef> ref = ToDIERef(entry)) {
252
7
      if (!ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx,
253
7
                              name_type_mask, [&](DWARFDIE die) {
254
7
                                if (!seen.insert(die.GetDIE()).second)
255
0
                                  return true;
256
7
                                return callback(die);
257
7
                              }))
258
0
        return;
259
7
    }
260
7
  }
261
262
5
  m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask,
263
5
                          callback);
264
5
}
265
266
void DebugNamesDWARFIndex::GetFunctions(
267
    const RegularExpression &regex,
268
0
    llvm::function_ref<bool(DWARFDIE die)> callback) {
269
0
  for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
270
0
    for (DebugNames::NameTableEntry nte: ni) {
271
0
      if (!regex.Execute(nte.getString()))
272
0
        continue;
273
274
0
      uint64_t entry_offset = nte.getEntryOffset();
275
0
      llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
276
0
      for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
277
0
        Tag tag = entry_or->tag();
278
0
        if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
279
0
          continue;
280
281
0
        if (!ProcessEntry(*entry_or, callback,
282
0
                          llvm::StringRef(nte.getString())))
283
0
          return;
284
0
      }
285
0
      MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
286
0
    }
287
0
  }
288
289
0
  m_fallback.GetFunctions(regex, callback);
290
0
}
291
292
0
void DebugNamesDWARFIndex::Dump(Stream &s) {
293
0
  m_fallback.Dump(s);
294
295
0
  std::string data;
296
0
  llvm::raw_string_ostream os(data);
297
0
  m_debug_names_up->dump(os);
298
0
  s.PutCString(os.str());
299
0
}