Coverage Report

Created: 2022-01-25 06:29

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- ManualDWARFIndex.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/ManualDWARFIndex.h"
10
#include "Plugins/Language/ObjC/ObjCLanguage.h"
11
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
12
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
13
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
14
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
15
#include "lldb/Core/DataFileCache.h"
16
#include "lldb/Core/Module.h"
17
#include "lldb/Core/Progress.h"
18
#include "lldb/Symbol/ObjectFile.h"
19
#include "lldb/Utility/DataEncoder.h"
20
#include "lldb/Utility/DataExtractor.h"
21
#include "lldb/Utility/Stream.h"
22
#include "lldb/Utility/Timer.h"
23
#include "llvm/Support/FormatVariadic.h"
24
#include "llvm/Support/ThreadPool.h"
25
26
using namespace lldb_private;
27
using namespace lldb;
28
29
243k
void ManualDWARFIndex::Index() {
30
243k
  if (m_indexed)
31
238k
    return;
32
5.40k
  m_indexed = true;
33
34
5.40k
  ElapsedTime elapsed(m_index_time);
35
5.40k
  LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
36
5.40k
  if (LoadFromCache()) {
37
0
    m_dwarf->SetDebugInfoIndexWasLoadedFromCache();
38
0
    return;
39
0
  }
40
41
5.40k
  DWARFDebugInfo &main_info = m_dwarf->DebugInfo();
42
5.40k
  SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();
43
5.40k
  DWARFDebugInfo *dwp_info = dwp_dwarf ? 
&dwp_dwarf->DebugInfo()8
:
nullptr5.40k
;
44
45
5.40k
  std::vector<DWARFUnit *> units_to_index;
46
5.40k
  units_to_index.reserve(main_info.GetNumUnits() +
47
5.40k
                         (dwp_info ? 
dwp_info->GetNumUnits()8
:
05.40k
));
48
49
  // Process all units in the main file, as well as any type units in the dwp
50
  // file. Type units in dwo files are handled when we reach the dwo file in
51
  // IndexUnit.
52
11.0k
  for (size_t U = 0; U < main_info.GetNumUnits(); 
++U5.68k
) {
53
5.68k
    DWARFUnit *unit = main_info.GetUnitAtIndex(U);
54
5.68k
    if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0)
55
5.68k
      units_to_index.push_back(unit);
56
5.68k
  }
57
5.40k
  if (dwp_info && 
dwp_info->ContainsTypeUnits()8
) {
58
13
    for (size_t U = 0; U < dwp_info->GetNumUnits(); 
++U10
) {
59
10
      if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U)))
60
5
        units_to_index.push_back(tu);
61
10
    }
62
3
  }
63
64
5.40k
  if (units_to_index.empty())
65
4
    return;
66
67
5.40k
  StreamString module_desc;
68
5.40k
  m_module.GetDescription(module_desc.AsRawOstream(),
69
5.40k
                          lldb::eDescriptionLevelBrief);
70
71
  // Include 2 passes per unit to index for extracting DIEs from the unit and
72
  // indexing the unit, and then 8 extra entries for finalizing each index set.
73
5.40k
  const uint64_t total_progress = units_to_index.size() * 2 + 8;
74
5.40k
  Progress progress(
75
5.40k
      llvm::formatv("Manually indexing DWARF for {0}", module_desc.GetData()),
76
5.40k
      total_progress);
77
78
5.40k
  std::vector<IndexSet> sets(units_to_index.size());
79
80
  // Keep memory down by clearing DIEs for any units if indexing
81
  // caused us to load the unit's DIEs.
82
5.40k
  std::vector<llvm::Optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(
83
5.40k
      units_to_index.size());
84
5.68k
  auto parser_fn = [&](size_t cu_idx) {
85
5.68k
    IndexUnit(*units_to_index[cu_idx], dwp_dwarf, sets[cu_idx]);
86
5.68k
    progress.Increment();
87
5.68k
  };
88
89
5.68k
  auto extract_fn = [&](size_t cu_idx) {
90
5.68k
    clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped();
91
5.68k
    progress.Increment();
92
5.68k
  };
93
94
  // Share one thread pool across operations to avoid the overhead of
95
  // recreating the threads.
96
5.40k
  llvm::ThreadPool pool(llvm::optimal_concurrency(units_to_index.size()));
97
98
  // Create a task runner that extracts dies for each DWARF unit in a
99
  // separate thread.
100
  // First figure out which units didn't have their DIEs already
101
  // parsed and remember this.  If no DIEs were parsed prior to this index
102
  // function call, we are going to want to clear the CU dies after we are
103
  // done indexing to make sure we don't pull in all DWARF dies, but we need
104
  // to wait until all units have been indexed in case a DIE in one
105
  // unit refers to another and the indexes accesses those DIEs.
106
11.0k
  for (size_t i = 0; i < units_to_index.size(); 
++i5.68k
)
107
5.68k
    pool.async(extract_fn, i);
108
5.40k
  pool.wait();
109
110
  // Now create a task runner that can index each DWARF unit in a
111
  // separate thread so we can index quickly.
112
11.0k
  for (size_t i = 0; i < units_to_index.size(); 
++i5.68k
)
113
5.68k
    pool.async(parser_fn, i);
114
5.40k
  pool.wait();
115
116
43.2k
  auto finalize_fn = [this, &sets, &progress](NameToDIE(IndexSet::*index)) {
117
43.2k
    NameToDIE &result = m_set.*index;
118
43.2k
    for (auto &set : sets)
119
44.4k
      result.Append(set.*index);
120
43.2k
    result.Finalize();
121
43.2k
    progress.Increment();
122
43.2k
  };
123
124
5.40k
  pool.async(finalize_fn, &IndexSet::function_basenames);
125
5.40k
  pool.async(finalize_fn, &IndexSet::function_fullnames);
126
5.40k
  pool.async(finalize_fn, &IndexSet::function_methods);
127
5.40k
  pool.async(finalize_fn, &IndexSet::function_selectors);
128
5.40k
  pool.async(finalize_fn, &IndexSet::objc_class_selectors);
129
5.40k
  pool.async(finalize_fn, &IndexSet::globals);
130
5.40k
  pool.async(finalize_fn, &IndexSet::types);
131
5.40k
  pool.async(finalize_fn, &IndexSet::namespaces);
132
5.40k
  pool.wait();
133
134
5.40k
  SaveToCache();
135
5.40k
}
136
137
void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp,
138
5.68k
                                 IndexSet &set) {
139
5.68k
  Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS);
140
141
5.68k
  if (log) {
142
0
    m_module.LogMessage(
143
0
        log, "ManualDWARFIndex::IndexUnit for unit at .debug_info[0x%8.8x]",
144
0
        unit.GetOffset());
145
0
  }
146
147
5.68k
  const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit);
148
149
5.68k
  IndexUnitImpl(unit, cu_language, set);
150
151
5.68k
  if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) {
152
    // Type units in a dwp file are indexed separately, so we just need to
153
    // process the split unit here. However, if the split unit is in a dwo file,
154
    // then we need to process type units here.
155
21
    if (dwo_symbol_file == dwp) {
156
16
      IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set);
157
16
    } else {
158
5
      DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo();
159
10
      for (size_t i = 0; i < dwo_info.GetNumUnits(); 
++i5
)
160
5
        IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set);
161
5
    }
162
21
  }
163
5.68k
}
164
165
void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit,
166
                                     const LanguageType cu_language,
167
5.70k
                                     IndexSet &set) {
168
285k
  for (const DWARFDebugInfoEntry &die : unit.dies()) {
169
285k
    const dw_tag_t tag = die.Tag();
170
171
285k
    switch (tag) {
172
1.97k
    case DW_TAG_array_type:
173
18.4k
    case DW_TAG_base_type:
174
18.4k
    case DW_TAG_class_type:
175
18.4k
    case DW_TAG_constant:
176
18.4k
    case DW_TAG_enumeration_type:
177
18.4k
    case DW_TAG_inlined_subroutine:
178
18.4k
    case DW_TAG_namespace:
179
18.4k
    case DW_TAG_string_type:
180
32.8k
    case DW_TAG_structure_type:
181
38.3k
    case DW_TAG_subprogram:
182
41.5k
    case DW_TAG_subroutine_type:
183
51.4k
    case DW_TAG_typedef:
184
51.4k
    case DW_TAG_union_type:
185
51.4k
    case DW_TAG_unspecified_type:
186
114k
    case DW_TAG_variable:
187
114k
      break;
188
189
170k
    default:
190
170k
      continue;
191
285k
    }
192
193
114k
    DWARFAttributes attributes;
194
114k
    const char *name = nullptr;
195
114k
    const char *mangled_cstr = nullptr;
196
114k
    bool is_declaration = false;
197
    // bool is_artificial = false;
198
114k
    bool has_address = false;
199
114k
    bool has_location_or_const_value = false;
200
114k
    bool is_global_or_static_variable = false;
201
202
114k
    DWARFFormValue specification_die_form;
203
114k
    const size_t num_attributes = die.GetAttributes(&unit, attributes);
204
114k
    if (num_attributes > 0) {
205
627k
      for (uint32_t i = 0; i < num_attributes; 
++i512k
) {
206
512k
        dw_attr_t attr = attributes.AttributeAtIndex(i);
207
512k
        DWARFFormValue form_value;
208
512k
        switch (attr) {
209
109k
        case DW_AT_name:
210
109k
          if (attributes.ExtractFormValueAtIndex(i, form_value))
211
109k
            name = form_value.AsCString();
212
109k
          break;
213
214
2.68k
        case DW_AT_declaration:
215
2.68k
          if (attributes.ExtractFormValueAtIndex(i, form_value))
216
2.68k
            is_declaration = form_value.Unsigned() != 0;
217
2.68k
          break;
218
219
16
        case DW_AT_MIPS_linkage_name:
220
2.29k
        case DW_AT_linkage_name:
221
2.29k
          if (attributes.ExtractFormValueAtIndex(i, form_value))
222
2.29k
            mangled_cstr = form_value.AsCString();
223
2.29k
          break;
224
225
5.51k
        case DW_AT_low_pc:
226
11.0k
        case DW_AT_high_pc:
227
11.0k
        case DW_AT_ranges:
228
11.0k
          has_address = true;
229
11.0k
          break;
230
231
0
        case DW_AT_entry_pc:
232
0
          has_address = true;
233
0
          break;
234
235
63.4k
        case DW_AT_location:
236
63.4k
        case DW_AT_const_value:
237
63.4k
          has_location_or_const_value = true;
238
63.4k
          is_global_or_static_variable = die.IsGlobalOrStaticScopeVariable();
239
240
63.4k
          break;
241
242
27
        case DW_AT_specification:
243
27
          if (attributes.ExtractFormValueAtIndex(i, form_value))
244
27
            specification_die_form = form_value;
245
27
          break;
246
512k
        }
247
512k
      }
248
114k
    }
249
250
114k
    DIERef ref = *DWARFDIE(&unit, &die).GetDIERef();
251
114k
    switch (tag) {
252
19
    case DW_TAG_inlined_subroutine:
253
5.54k
    case DW_TAG_subprogram:
254
5.54k
      if (has_address) {
255
5.51k
        if (name) {
256
5.51k
          bool is_objc_method = false;
257
5.51k
          if (cu_language == eLanguageTypeObjC ||
258
5.51k
              cu_language == eLanguageTypeObjC_plus_plus) {
259
5.31k
            ObjCLanguage::MethodName objc_method(name, true);
260
5.31k
            if (objc_method.IsValid(true)) {
261
2
              is_objc_method = true;
262
2
              ConstString class_name_with_category(
263
2
                  objc_method.GetClassNameWithCategory());
264
2
              ConstString objc_selector_name(objc_method.GetSelector());
265
2
              ConstString objc_fullname_no_category_name(
266
2
                  objc_method.GetFullNameWithoutCategory(true));
267
2
              ConstString class_name_no_category(objc_method.GetClassName());
268
2
              set.function_fullnames.Insert(ConstString(name), ref);
269
2
              if (class_name_with_category)
270
2
                set.objc_class_selectors.Insert(class_name_with_category, ref);
271
2
              if (class_name_no_category &&
272
2
                  class_name_no_category != class_name_with_category)
273
0
                set.objc_class_selectors.Insert(class_name_no_category, ref);
274
2
              if (objc_selector_name)
275
2
                set.function_selectors.Insert(objc_selector_name, ref);
276
2
              if (objc_fullname_no_category_name)
277
0
                set.function_fullnames.Insert(objc_fullname_no_category_name,
278
0
                                              ref);
279
2
            }
280
5.31k
          }
281
          // If we have a mangled name, then the DW_AT_name attribute is
282
          // usually the method name without the class or any parameters
283
5.51k
          bool is_method = DWARFDIE(&unit, &die).IsMethod();
284
285
5.51k
          if (is_method)
286
16
            set.function_methods.Insert(ConstString(name), ref);
287
5.50k
          else
288
5.50k
            set.function_basenames.Insert(ConstString(name), ref);
289
290
5.51k
          if (!is_method && 
!mangled_cstr5.50k
&&
!is_objc_method3.25k
)
291
3.25k
            set.function_fullnames.Insert(ConstString(name), ref);
292
5.51k
        }
293
5.51k
        if (mangled_cstr) {
294
          // Make sure our mangled name isn't the same string table entry as
295
          // our name. If it starts with '_', then it is ok, else compare the
296
          // string to make sure it isn't the same and we don't end up with
297
          // duplicate entries
298
2.25k
          if (name && name != mangled_cstr &&
299
2.25k
              ((mangled_cstr[0] == '_') ||
300
2.25k
               
(::strcmp(name, mangled_cstr) != 0)0
)) {
301
2.25k
            set.function_fullnames.Insert(ConstString(mangled_cstr), ref);
302
2.25k
          }
303
2.25k
        }
304
5.51k
      }
305
5.54k
      break;
306
307
1.97k
    case DW_TAG_array_type:
308
18.4k
    case DW_TAG_base_type:
309
18.4k
    case DW_TAG_class_type:
310
18.4k
    case DW_TAG_constant:
311
18.4k
    case DW_TAG_enumeration_type:
312
18.4k
    case DW_TAG_string_type:
313
32.7k
    case DW_TAG_structure_type:
314
36.0k
    case DW_TAG_subroutine_type:
315
45.9k
    case DW_TAG_typedef:
316
45.9k
    case DW_TAG_union_type:
317
45.9k
    case DW_TAG_unspecified_type:
318
45.9k
      if (name && 
!is_declaration40.6k
)
319
38.0k
        set.types.Insert(ConstString(name), ref);
320
45.9k
      if (mangled_cstr && 
!is_declaration0
)
321
0
        set.types.Insert(ConstString(mangled_cstr), ref);
322
45.9k
      break;
323
324
2
    case DW_TAG_namespace:
325
2
      if (name)
326
2
        set.namespaces.Insert(ConstString(name), ref);
327
2
      break;
328
329
63.4k
    case DW_TAG_variable:
330
63.4k
      if (name && has_location_or_const_value && 
is_global_or_static_variable63.4k
) {
331
1.31k
        set.globals.Insert(ConstString(name), ref);
332
        // Be sure to include variables by their mangled and demangled names if
333
        // they have any since a variable can have a basename "i", a mangled
334
        // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name
335
        // "(anonymous namespace)::i"...
336
337
        // Make sure our mangled name isn't the same string table entry as our
338
        // name. If it starts with '_', then it is ok, else compare the string
339
        // to make sure it isn't the same and we don't end up with duplicate
340
        // entries
341
1.31k
        if (mangled_cstr && 
name != mangled_cstr5
&&
342
1.31k
            
(5
(mangled_cstr[0] == '_')5
||
(::strcmp(name, mangled_cstr) != 0)0
)) {
343
5
          set.globals.Insert(ConstString(mangled_cstr), ref);
344
5
        }
345
1.31k
      }
346
63.4k
      break;
347
348
0
    default:
349
0
      continue;
350
114k
    }
351
114k
  }
352
5.70k
}
353
354
void ManualDWARFIndex::GetGlobalVariables(
355
13.8k
    ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
356
13.8k
  Index();
357
13.8k
  m_set.globals.Find(basename,
358
13.8k
                     DIERefCallback(callback, basename.GetStringRef()));
359
13.8k
}
360
361
void ManualDWARFIndex::GetGlobalVariables(
362
    const RegularExpression &regex,
363
0
    llvm::function_ref<bool(DWARFDIE die)> callback) {
364
0
  Index();
365
0
  m_set.globals.Find(regex, DIERefCallback(callback, regex.GetText()));
366
0
}
367
368
void ManualDWARFIndex::GetGlobalVariables(
369
31
    DWARFUnit &unit, llvm::function_ref<bool(DWARFDIE die)> callback) {
370
31
  lldbassert(!unit.GetSymbolFileDWARF().GetDwoNum());
371
31
  Index();
372
31
  m_set.globals.FindAllEntriesForUnit(unit, DIERefCallback(callback));
373
31
}
374
375
void ManualDWARFIndex::GetObjCMethods(
376
0
    ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) {
377
0
  Index();
378
0
  m_set.objc_class_selectors.Find(
379
0
      class_name, DIERefCallback(callback, class_name.GetStringRef()));
380
0
}
381
382
void ManualDWARFIndex::GetCompleteObjCClass(
383
    ConstString class_name, bool must_be_implementation,
384
0
    llvm::function_ref<bool(DWARFDIE die)> callback) {
385
0
  Index();
386
0
  m_set.types.Find(class_name,
387
0
                   DIERefCallback(callback, class_name.GetStringRef()));
388
0
}
389
390
void ManualDWARFIndex::GetTypes(
391
47.9k
    ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
392
47.9k
  Index();
393
47.9k
  m_set.types.Find(name, DIERefCallback(callback, name.GetStringRef()));
394
47.9k
}
395
396
void ManualDWARFIndex::GetTypes(
397
    const DWARFDeclContext &context,
398
4
    llvm::function_ref<bool(DWARFDIE die)> callback) {
399
4
  Index();
400
4
  auto name = context[0].name;
401
4
  m_set.types.Find(ConstString(name),
402
4
                   DIERefCallback(callback, llvm::StringRef(name)));
403
4
}
404
405
void ManualDWARFIndex::GetNamespaces(
406
146k
    ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
407
146k
  Index();
408
146k
  m_set.namespaces.Find(name, DIERefCallback(callback, name.GetStringRef()));
409
146k
}
410
411
void ManualDWARFIndex::GetFunctions(
412
    ConstString name, SymbolFileDWARF &dwarf,
413
    const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
414
35.1k
    llvm::function_ref<bool(DWARFDIE die)> callback) {
415
35.1k
  Index();
416
417
35.1k
  if (name_type_mask & eFunctionNameTypeFull) {
418
34.2k
    if (!m_set.function_fullnames.Find(
419
34.2k
            name, DIERefCallback(
420
34.2k
                      [&](DWARFDIE die) {
421
0
                        if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx,
422
0
                                                               die))
423
0
                          return true;
424
0
                        return callback(die);
425
0
                      },
426
34.2k
                      name.GetStringRef())))
427
0
      return;
428
34.2k
  }
429
35.1k
  if (name_type_mask & eFunctionNameTypeBase) {
430
13.8k
    if (!m_set.function_basenames.Find(
431
13.8k
            name, DIERefCallback(
432
13.8k
                      [&](DWARFDIE die) {
433
24
                        if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx,
434
24
                                                               die))
435
0
                          return true;
436
24
                        return callback(die);
437
24
                      },
438
13.8k
                      name.GetStringRef())))
439
0
      return;
440
13.8k
  }
441
442
35.1k
  if (name_type_mask & eFunctionNameTypeMethod && 
!parent_decl_ctx.IsValid()273
) {
443
273
    if (!m_set.function_methods.Find(
444
273
            name, DIERefCallback(callback, name.GetStringRef())))
445
0
      return;
446
273
  }
447
448
35.1k
  if (name_type_mask & eFunctionNameTypeSelector &&
449
35.1k
      
!parent_decl_ctx.IsValid()904
) {
450
904
    if (!m_set.function_selectors.Find(
451
904
            name, DIERefCallback(callback, name.GetStringRef())))
452
0
      return;
453
904
  }
454
35.1k
}
455
456
void ManualDWARFIndex::GetFunctions(
457
    const RegularExpression &regex,
458
12
    llvm::function_ref<bool(DWARFDIE die)> callback) {
459
12
  Index();
460
461
12
  if (!m_set.function_basenames.Find(regex,
462
12
                                     DIERefCallback(callback, regex.GetText())))
463
0
    return;
464
12
  if (!m_set.function_fullnames.Find(regex,
465
12
                                     DIERefCallback(callback, regex.GetText())))
466
0
    return;
467
12
}
468
469
7
void ManualDWARFIndex::Dump(Stream &s) {
470
7
  s.Format("Manual DWARF index for ({0}) '{1:F}':",
471
7
           m_module.GetArchitecture().GetArchitectureName(),
472
7
           m_module.GetObjectFile()->GetFileSpec());
473
7
  s.Printf("\nFunction basenames:\n");
474
7
  m_set.function_basenames.Dump(&s);
475
7
  s.Printf("\nFunction fullnames:\n");
476
7
  m_set.function_fullnames.Dump(&s);
477
7
  s.Printf("\nFunction methods:\n");
478
7
  m_set.function_methods.Dump(&s);
479
7
  s.Printf("\nFunction selectors:\n");
480
7
  m_set.function_selectors.Dump(&s);
481
7
  s.Printf("\nObjective-C class selectors:\n");
482
7
  m_set.objc_class_selectors.Dump(&s);
483
7
  s.Printf("\nGlobals and statics:\n");
484
7
  m_set.globals.Dump(&s);
485
7
  s.Printf("\nTypes:\n");
486
7
  m_set.types.Dump(&s);
487
7
  s.Printf("\nNamespaces:\n");
488
7
  m_set.namespaces.Dump(&s);
489
7
}
490
491
constexpr llvm::StringLiteral kIdentifierManualDWARFIndex("DIDX");
492
// Define IDs for the different tables when encoding and decoding the
493
// ManualDWARFIndex NameToDIE objects so we can avoid saving any empty maps.
494
enum DataID {
495
  kDataIDFunctionBasenames = 1u,
496
  kDataIDFunctionFullnames,
497
  kDataIDFunctionMethods,
498
  kDataIDFunctionSelectors,
499
  kDataIDFunctionObjcClassSelectors,
500
  kDataIDGlobals,
501
  kDataIDTypes,
502
  kDataIDNamespaces,
503
  kDataIDEnd = 255u,
504
505
};
506
constexpr uint32_t CURRENT_CACHE_VERSION = 1;
507
508
bool ManualDWARFIndex::IndexSet::Decode(const DataExtractor &data,
509
20
                                        lldb::offset_t *offset_ptr) {
510
20
  StringTableReader strtab;
511
  // We now decode the string table for all strings in the data cache file.
512
20
  if (!strtab.Decode(data, offset_ptr))
513
0
    return false;
514
515
20
  llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4);
516
20
  if (identifier != kIdentifierManualDWARFIndex)
517
0
    return false;
518
20
  const uint32_t version = data.GetU32(offset_ptr);
519
20
  if (version != CURRENT_CACHE_VERSION)
520
0
    return false;
521
522
20
  bool done = false;
523
72
  while (!done) {
524
52
    switch (data.GetU8(offset_ptr)) {
525
0
    default:
526
      // If we got here, this is not expected, we expect the data IDs to match
527
      // one of the values from the DataID enumeration.
528
0
      return false;
529
4
    case kDataIDFunctionBasenames:
530
4
      if (!function_basenames.Decode(data, offset_ptr, strtab))
531
0
        return false;
532
4
      break;
533
4
    case kDataIDFunctionFullnames:
534
4
      if (!function_fullnames.Decode(data, offset_ptr, strtab))
535
0
        return false;
536
4
      break;
537
4
    case kDataIDFunctionMethods:
538
4
      if (!function_methods.Decode(data, offset_ptr, strtab))
539
0
        return false;
540
4
      break;
541
4
    case kDataIDFunctionSelectors:
542
4
      if (!function_selectors.Decode(data, offset_ptr, strtab))
543
0
        return false;
544
4
      break;
545
4
    case kDataIDFunctionObjcClassSelectors:
546
4
      if (!objc_class_selectors.Decode(data, offset_ptr, strtab))
547
0
        return false;
548
4
      break;
549
4
    case kDataIDGlobals:
550
4
      if (!globals.Decode(data, offset_ptr, strtab))
551
0
        return false;
552
4
      break;
553
4
    case kDataIDTypes:
554
4
      if (!types.Decode(data, offset_ptr, strtab))
555
0
        return false;
556
4
      break;
557
4
    case kDataIDNamespaces:
558
4
      if (!namespaces.Decode(data, offset_ptr, strtab))
559
0
        return false;
560
4
      break;
561
20
    case kDataIDEnd:
562
      // We got to the end of our NameToDIE encodings.
563
20
      done = true;
564
20
      break;
565
52
    }
566
52
  }
567
  // Success!
568
20
  return true;
569
20
}
570
571
21
void ManualDWARFIndex::IndexSet::Encode(DataEncoder &encoder) const {
572
21
  ConstStringTable strtab;
573
574
  // Encoder the DWARF index into a separate encoder first. This allows us
575
  // gather all of the strings we willl need in "strtab" as we will need to
576
  // write the string table out before the symbol table.
577
21
  DataEncoder index_encoder(encoder.GetByteOrder(),
578
21
                            encoder.GetAddressByteSize());
579
580
21
  index_encoder.AppendData(kIdentifierManualDWARFIndex);
581
  // Encode the data version.
582
21
  index_encoder.AppendU32(CURRENT_CACHE_VERSION);
583
584
21
  if (!function_basenames.IsEmpty()) {
585
5
    index_encoder.AppendU8(kDataIDFunctionBasenames);
586
5
    function_basenames.Encode(index_encoder, strtab);
587
5
  }
588
21
  if (!function_fullnames.IsEmpty()) {
589
5
    index_encoder.AppendU8(kDataIDFunctionFullnames);
590
5
    function_fullnames.Encode(index_encoder, strtab);
591
5
  }
592
21
  if (!function_methods.IsEmpty()) {
593
5
    index_encoder.AppendU8(kDataIDFunctionMethods);
594
5
    function_methods.Encode(index_encoder, strtab);
595
5
  }
596
21
  if (!function_selectors.IsEmpty()) {
597
5
    index_encoder.AppendU8(kDataIDFunctionSelectors);
598
5
    function_selectors.Encode(index_encoder, strtab);
599
5
  }
600
21
  if (!objc_class_selectors.IsEmpty()) {
601
5
    index_encoder.AppendU8(kDataIDFunctionObjcClassSelectors);
602
5
    objc_class_selectors.Encode(index_encoder, strtab);
603
5
  }
604
21
  if (!globals.IsEmpty()) {
605
5
    index_encoder.AppendU8(kDataIDGlobals);
606
5
    globals.Encode(index_encoder, strtab);
607
5
  }
608
21
  if (!types.IsEmpty()) {
609
5
    index_encoder.AppendU8(kDataIDTypes);
610
5
    types.Encode(index_encoder, strtab);
611
5
  }
612
21
  if (!namespaces.IsEmpty()) {
613
5
    index_encoder.AppendU8(kDataIDNamespaces);
614
5
    namespaces.Encode(index_encoder, strtab);
615
5
  }
616
21
  index_encoder.AppendU8(kDataIDEnd);
617
618
  // Now that all strings have been gathered, we will emit the string table.
619
21
  strtab.Encode(encoder);
620
  // Followed the the symbol table data.
621
21
  encoder.AppendData(index_encoder.GetData());
622
21
}
623
624
bool ManualDWARFIndex::Decode(const DataExtractor &data,
625
                              lldb::offset_t *offset_ptr,
626
0
                              bool &signature_mismatch) {
627
0
  signature_mismatch = false;
628
0
  CacheSignature signature;
629
0
  if (!signature.Decode(data, offset_ptr))
630
0
    return false;
631
0
  if (CacheSignature(m_dwarf->GetObjectFile()) != signature) {
632
0
    signature_mismatch = true;
633
0
    return false;
634
0
  }
635
0
  IndexSet set;
636
0
  if (!set.Decode(data, offset_ptr))
637
0
    return false;
638
0
  m_set = std::move(set);
639
0
  return true;
640
0
}
641
642
1
bool ManualDWARFIndex::Encode(DataEncoder &encoder) const {
643
1
  CacheSignature signature(m_dwarf->GetObjectFile());
644
1
  if (!signature.Encode(encoder))
645
0
    return false;
646
1
  m_set.Encode(encoder);
647
1
  return true;
648
1
}
649
650
2
std::string ManualDWARFIndex::GetCacheKey() {
651
2
  std::string key;
652
2
  llvm::raw_string_ostream strm(key);
653
  // DWARF Index can come from different object files for the same module. A
654
  // module can have one object file as the main executable and might have
655
  // another object file in a separate symbol file, or we might have a .dwo file
656
  // that claims its module is the main executable.
657
2
  ObjectFile *objfile = m_dwarf->GetObjectFile();
658
2
  strm << objfile->GetModule()->GetCacheKey() << "-dwarf-index-"
659
2
      << llvm::format_hex(objfile->GetCacheHash(), 10);
660
2
  return strm.str();
661
2
}
662
663
5.40k
bool ManualDWARFIndex::LoadFromCache() {
664
5.40k
  DataFileCache *cache = Module::GetIndexCache();
665
5.40k
  if (!cache)
666
5.40k
    return false;
667
1
  ObjectFile *objfile = m_dwarf->GetObjectFile();
668
1
  if (!objfile)
669
0
    return false;
670
1
  std::unique_ptr<llvm::MemoryBuffer> mem_buffer_up =
671
1
      cache->GetCachedData(GetCacheKey());
672
1
  if (!mem_buffer_up)
673
1
    return false;
674
0
  DataExtractor data(mem_buffer_up->getBufferStart(),
675
0
                     mem_buffer_up->getBufferSize(),
676
0
                     endian::InlHostByteOrder(),
677
0
                     objfile->GetAddressByteSize());
678
0
  bool signature_mismatch = false;
679
0
  lldb::offset_t offset = 0;
680
0
  const bool result = Decode(data, &offset, signature_mismatch);
681
0
  if (signature_mismatch)
682
0
    cache->RemoveCacheFile(GetCacheKey());
683
0
  return result;
684
1
}
685
686
5.40k
void ManualDWARFIndex::SaveToCache() {
687
5.40k
  DataFileCache *cache = Module::GetIndexCache();
688
5.40k
  if (!cache)
689
5.40k
    return; // Caching is not enabled.
690
1
  ObjectFile *objfile = m_dwarf->GetObjectFile();
691
1
  if (!objfile)
692
0
    return;
693
1
  DataEncoder file(endian::InlHostByteOrder(), objfile->GetAddressByteSize());
694
  // Encode will return false if the object file doesn't have anything to make
695
  // a signature from.
696
1
  if (Encode(file)) {
697
1
    if (cache->SetCachedData(GetCacheKey(), file.GetData()))
698
1
      m_dwarf->SetDebugInfoIndexWasSavedToCache();
699
1
  }
700
1
}