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/ManualDWARFIndexSet.h"
10#include "lldb/Core/DataFileCache.h"
11#include "lldb/Utility/DataEncoder.h"
12#include "lldb/Utility/DataExtractor.h"
13#include <cstdint>
14
15using namespace lldb_private;
16using namespace lldb_private::plugin::dwarf;
17
18namespace {
19// Define IDs for the different tables when encoding and decoding the
20// ManualDWARFIndex NameToDIE objects so we can avoid saving any empty maps.
21enum DataID {
22 kDataIDFunctionBasenames = 1u,
23 kDataIDFunctionFullnames,
24 kDataIDFunctionMethods,
25 kDataIDFunctionSelectors,
26 kDataIDFunctionObjcClassSelectors,
27 kDataIDGlobals,
28 kDataIDTypes,
29 kDataIDNamespaces,
30 kDataIDEnd = 255u,
31};
32} // namespace
33
34// Version 2 changes the encoding of DIERef objects used in the DWARF manual
35// index name tables. See DIERef class for details.
36static constexpr uint32_t CURRENT_CACHE_VERSION = 2;
37
38static constexpr llvm::StringLiteral kIdentifierManualDWARFIndex("DIDX");
39
40std::optional<IndexSet<NameToDIE>>
41plugin::dwarf::DecodeIndexSet(const DataExtractor &data,
42 lldb::offset_t *offset_ptr) {
43 StringTableReader strtab;
44 // We now decode the string table for all strings in the data cache file.
45 if (!strtab.Decode(data, offset_ptr))
46 return std::nullopt;
47
48 llvm::StringRef identifier((const char *)data.GetData(offset_ptr, length: 4), 4);
49 if (identifier != kIdentifierManualDWARFIndex)
50 return std::nullopt;
51 const uint32_t version = data.GetU32(offset_ptr);
52 if (version != CURRENT_CACHE_VERSION)
53 return std::nullopt;
54
55 IndexSet<NameToDIE> result;
56 while (true) {
57 switch (data.GetU8(offset_ptr)) {
58 default:
59 // If we got here, this is not expected, we expect the data IDs to match
60 // one of the values from the DataID enumeration.
61 return std::nullopt;
62 case kDataIDFunctionBasenames:
63 if (!result.function_basenames.Decode(data, offset_ptr, strtab))
64 return std::nullopt;
65 break;
66 case kDataIDFunctionFullnames:
67 if (!result.function_fullnames.Decode(data, offset_ptr, strtab))
68 return std::nullopt;
69 break;
70 case kDataIDFunctionMethods:
71 if (!result.function_methods.Decode(data, offset_ptr, strtab))
72 return std::nullopt;
73 break;
74 case kDataIDFunctionSelectors:
75 if (!result.function_selectors.Decode(data, offset_ptr, strtab))
76 return std::nullopt;
77 break;
78 case kDataIDFunctionObjcClassSelectors:
79 if (!result.objc_class_selectors.Decode(data, offset_ptr, strtab))
80 return std::nullopt;
81 break;
82 case kDataIDGlobals:
83 if (!result.globals.Decode(data, offset_ptr, strtab))
84 return std::nullopt;
85 break;
86 case kDataIDTypes:
87 if (!result.types.Decode(data, offset_ptr, strtab))
88 return std::nullopt;
89 break;
90 case kDataIDNamespaces:
91 if (!result.namespaces.Decode(data, offset_ptr, strtab))
92 return std::nullopt;
93 break;
94 case kDataIDEnd:
95 // We got to the end of our NameToDIE encodings.
96 return std::move(result);
97 break;
98 }
99 }
100}
101
102void plugin::dwarf::EncodeIndexSet(const IndexSet<NameToDIE> &set,
103 DataEncoder &encoder) {
104 ConstStringTable strtab;
105
106 // Encoder the DWARF index into a separate encoder first. This allows us
107 // gather all of the strings we willl need in "strtab" as we will need to
108 // write the string table out before the symbol table.
109 DataEncoder index_encoder(encoder.GetByteOrder(),
110 encoder.GetAddressByteSize());
111
112 index_encoder.AppendData(data: kIdentifierManualDWARFIndex);
113 // Encode the data version.
114 index_encoder.AppendU32(value: CURRENT_CACHE_VERSION);
115
116 if (!set.function_basenames.IsEmpty()) {
117 index_encoder.AppendU8(value: kDataIDFunctionBasenames);
118 set.function_basenames.Encode(encoder&: index_encoder, strtab);
119 }
120 if (!set.function_fullnames.IsEmpty()) {
121 index_encoder.AppendU8(value: kDataIDFunctionFullnames);
122 set.function_fullnames.Encode(encoder&: index_encoder, strtab);
123 }
124 if (!set.function_methods.IsEmpty()) {
125 index_encoder.AppendU8(value: kDataIDFunctionMethods);
126 set.function_methods.Encode(encoder&: index_encoder, strtab);
127 }
128 if (!set.function_selectors.IsEmpty()) {
129 index_encoder.AppendU8(value: kDataIDFunctionSelectors);
130 set.function_selectors.Encode(encoder&: index_encoder, strtab);
131 }
132 if (!set.objc_class_selectors.IsEmpty()) {
133 index_encoder.AppendU8(value: kDataIDFunctionObjcClassSelectors);
134 set.objc_class_selectors.Encode(encoder&: index_encoder, strtab);
135 }
136 if (!set.globals.IsEmpty()) {
137 index_encoder.AppendU8(value: kDataIDGlobals);
138 set.globals.Encode(encoder&: index_encoder, strtab);
139 }
140 if (!set.types.IsEmpty()) {
141 index_encoder.AppendU8(value: kDataIDTypes);
142 set.types.Encode(encoder&: index_encoder, strtab);
143 }
144 if (!set.namespaces.IsEmpty()) {
145 index_encoder.AppendU8(value: kDataIDNamespaces);
146 set.namespaces.Encode(encoder&: index_encoder, strtab);
147 }
148 index_encoder.AppendU8(value: kDataIDEnd);
149
150 // Now that all strings have been gathered, we will emit the string table.
151 strtab.Encode(encoder);
152 // Followed by the symbol table data.
153 encoder.AppendData(data: index_encoder.GetData());
154}
155

source code of lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndexSet.cpp