1//===-- ModuleSpec.h --------------------------------------------*- 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#ifndef LLDB_CORE_MODULESPEC_H
10#define LLDB_CORE_MODULESPEC_H
11
12#include "lldb/Host/FileSystem.h"
13#include "lldb/Target/PathMappingList.h"
14#include "lldb/Utility/ArchSpec.h"
15#include "lldb/Utility/FileSpec.h"
16#include "lldb/Utility/Iterable.h"
17#include "lldb/Utility/Stream.h"
18#include "lldb/Utility/UUID.h"
19
20#include "llvm/Support/Chrono.h"
21
22#include <mutex>
23#include <vector>
24
25namespace lldb_private {
26
27class ModuleSpec {
28public:
29 ModuleSpec() = default;
30
31 /// If the \c data argument is passed, its contents will be used
32 /// as the module contents instead of trying to read them from
33 /// \c file_spec .
34 ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID(),
35 lldb::DataBufferSP data = lldb::DataBufferSP())
36 : m_file(file_spec), m_uuid(uuid), m_object_offset(0), m_data(data) {
37 if (data)
38 m_object_size = data->GetByteSize();
39 else if (m_file)
40 m_object_size = FileSystem::Instance().GetByteSize(file_spec);
41 }
42
43 ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch)
44 : m_file(file_spec), m_arch(arch), m_object_offset(0),
45 m_object_size(FileSystem::Instance().GetByteSize(file_spec)) {}
46
47 FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); }
48
49 const FileSpec *GetFileSpecPtr() const {
50 return (m_file ? &m_file : nullptr);
51 }
52
53 FileSpec &GetFileSpec() { return m_file; }
54
55 const FileSpec &GetFileSpec() const { return m_file; }
56
57 FileSpec *GetPlatformFileSpecPtr() {
58 return (m_platform_file ? &m_platform_file : nullptr);
59 }
60
61 const FileSpec *GetPlatformFileSpecPtr() const {
62 return (m_platform_file ? &m_platform_file : nullptr);
63 }
64
65 FileSpec &GetPlatformFileSpec() { return m_platform_file; }
66
67 const FileSpec &GetPlatformFileSpec() const { return m_platform_file; }
68
69 FileSpec *GetSymbolFileSpecPtr() {
70 return (m_symbol_file ? &m_symbol_file : nullptr);
71 }
72
73 const FileSpec *GetSymbolFileSpecPtr() const {
74 return (m_symbol_file ? &m_symbol_file : nullptr);
75 }
76
77 FileSpec &GetSymbolFileSpec() { return m_symbol_file; }
78
79 const FileSpec &GetSymbolFileSpec() const { return m_symbol_file; }
80
81 ArchSpec *GetArchitecturePtr() {
82 return (m_arch.IsValid() ? &m_arch : nullptr);
83 }
84
85 const ArchSpec *GetArchitecturePtr() const {
86 return (m_arch.IsValid() ? &m_arch : nullptr);
87 }
88
89 ArchSpec &GetArchitecture() { return m_arch; }
90
91 const ArchSpec &GetArchitecture() const { return m_arch; }
92
93 UUID *GetUUIDPtr() { return (m_uuid.IsValid() ? &m_uuid : nullptr); }
94
95 const UUID *GetUUIDPtr() const {
96 return (m_uuid.IsValid() ? &m_uuid : nullptr);
97 }
98
99 UUID &GetUUID() { return m_uuid; }
100
101 const UUID &GetUUID() const { return m_uuid; }
102
103 ConstString &GetObjectName() { return m_object_name; }
104
105 ConstString GetObjectName() const { return m_object_name; }
106
107 uint64_t GetObjectOffset() const { return m_object_offset; }
108
109 void SetObjectOffset(uint64_t object_offset) {
110 m_object_offset = object_offset;
111 }
112
113 uint64_t GetObjectSize() const { return m_object_size; }
114
115 void SetObjectSize(uint64_t object_size) { m_object_size = object_size; }
116
117 llvm::sys::TimePoint<> &GetObjectModificationTime() {
118 return m_object_mod_time;
119 }
120
121 const llvm::sys::TimePoint<> &GetObjectModificationTime() const {
122 return m_object_mod_time;
123 }
124
125 PathMappingList &GetSourceMappingList() const { return m_source_mappings; }
126
127 lldb::DataBufferSP GetData() const { return m_data; }
128
129 void Clear() {
130 m_file.Clear();
131 m_platform_file.Clear();
132 m_symbol_file.Clear();
133 m_arch.Clear();
134 m_uuid.Clear();
135 m_object_name.Clear();
136 m_object_offset = 0;
137 m_object_size = 0;
138 m_source_mappings.Clear(notify: false);
139 m_object_mod_time = llvm::sys::TimePoint<>();
140 }
141
142 explicit operator bool() const {
143 if (m_file)
144 return true;
145 if (m_platform_file)
146 return true;
147 if (m_symbol_file)
148 return true;
149 if (m_arch.IsValid())
150 return true;
151 if (m_uuid.IsValid())
152 return true;
153 if (m_object_name)
154 return true;
155 if (m_object_size)
156 return true;
157 if (m_object_mod_time != llvm::sys::TimePoint<>())
158 return true;
159 return false;
160 }
161
162 void Dump(Stream &strm) const {
163 bool dumped_something = false;
164 if (m_file) {
165 strm.PutCString(cstr: "file = '");
166 strm << m_file;
167 strm.PutCString(cstr: "'");
168 dumped_something = true;
169 }
170 if (m_platform_file) {
171 if (dumped_something)
172 strm.PutCString(cstr: ", ");
173 strm.PutCString(cstr: "platform_file = '");
174 strm << m_platform_file;
175 strm.PutCString(cstr: "'");
176 dumped_something = true;
177 }
178 if (m_symbol_file) {
179 if (dumped_something)
180 strm.PutCString(cstr: ", ");
181 strm.PutCString(cstr: "symbol_file = '");
182 strm << m_symbol_file;
183 strm.PutCString(cstr: "'");
184 dumped_something = true;
185 }
186 if (m_arch.IsValid()) {
187 if (dumped_something)
188 strm.PutCString(cstr: ", ");
189 strm.Printf(format: "arch = ");
190 m_arch.DumpTriple(s&: strm.AsRawOstream());
191 dumped_something = true;
192 }
193 if (m_uuid.IsValid()) {
194 if (dumped_something)
195 strm.PutCString(cstr: ", ");
196 strm.PutCString(cstr: "uuid = ");
197 m_uuid.Dump(s&: strm);
198 dumped_something = true;
199 }
200 if (m_object_name) {
201 if (dumped_something)
202 strm.PutCString(cstr: ", ");
203 strm.Printf(format: "object_name = %s", m_object_name.GetCString());
204 dumped_something = true;
205 }
206 if (m_object_offset > 0) {
207 if (dumped_something)
208 strm.PutCString(cstr: ", ");
209 strm.Printf(format: "object_offset = %" PRIu64, m_object_offset);
210 dumped_something = true;
211 }
212 if (m_object_size > 0) {
213 if (dumped_something)
214 strm.PutCString(cstr: ", ");
215 strm.Printf(format: "object size = %" PRIu64, m_object_size);
216 dumped_something = true;
217 }
218 if (m_object_mod_time != llvm::sys::TimePoint<>()) {
219 if (dumped_something)
220 strm.PutCString(cstr: ", ");
221 strm.Format(format: "object_mod_time = {0:x+}",
222 args: uint64_t(llvm::sys::toTimeT(TP: m_object_mod_time)));
223 }
224 }
225
226 bool Matches(const ModuleSpec &match_module_spec,
227 bool exact_arch_match) const {
228 if (match_module_spec.GetUUIDPtr() &&
229 match_module_spec.GetUUID() != GetUUID())
230 return false;
231 if (match_module_spec.GetObjectName() &&
232 match_module_spec.GetObjectName() != GetObjectName())
233 return false;
234 if (!FileSpec::Match(pattern: match_module_spec.GetFileSpec(), file: GetFileSpec()))
235 return false;
236 if (GetPlatformFileSpec() &&
237 !FileSpec::Match(pattern: match_module_spec.GetPlatformFileSpec(),
238 file: GetPlatformFileSpec())) {
239 return false;
240 }
241 // Only match the symbol file spec if there is one in this ModuleSpec
242 if (GetSymbolFileSpec() &&
243 !FileSpec::Match(pattern: match_module_spec.GetSymbolFileSpec(),
244 file: GetSymbolFileSpec())) {
245 return false;
246 }
247 if (match_module_spec.GetArchitecturePtr()) {
248 if (exact_arch_match) {
249 if (!GetArchitecture().IsExactMatch(
250 rhs: match_module_spec.GetArchitecture()))
251 return false;
252 } else {
253 if (!GetArchitecture().IsCompatibleMatch(
254 rhs: match_module_spec.GetArchitecture()))
255 return false;
256 }
257 }
258 return true;
259 }
260
261protected:
262 FileSpec m_file;
263 FileSpec m_platform_file;
264 FileSpec m_symbol_file;
265 ArchSpec m_arch;
266 UUID m_uuid;
267 ConstString m_object_name;
268 uint64_t m_object_offset = 0;
269 uint64_t m_object_size = 0;
270 llvm::sys::TimePoint<> m_object_mod_time;
271 mutable PathMappingList m_source_mappings;
272 lldb::DataBufferSP m_data = {};
273};
274
275class ModuleSpecList {
276public:
277 ModuleSpecList() = default;
278
279 ModuleSpecList(const ModuleSpecList &rhs) {
280 std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex);
281 std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex);
282 m_specs = rhs.m_specs;
283 }
284
285 ~ModuleSpecList() = default;
286
287 ModuleSpecList &operator=(const ModuleSpecList &rhs) {
288 if (this != &rhs) {
289 std::lock(l1&: m_mutex, l2&: rhs.m_mutex);
290 std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex, std::adopt_lock);
291 std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex,
292 std::adopt_lock);
293 m_specs = rhs.m_specs;
294 }
295 return *this;
296 }
297
298 size_t GetSize() const {
299 std::lock_guard<std::recursive_mutex> guard(m_mutex);
300 return m_specs.size();
301 }
302
303 void Clear() {
304 std::lock_guard<std::recursive_mutex> guard(m_mutex);
305 m_specs.clear();
306 }
307
308 void Append(const ModuleSpec &spec) {
309 std::lock_guard<std::recursive_mutex> guard(m_mutex);
310 m_specs.push_back(x: spec);
311 }
312
313 void Append(const ModuleSpecList &rhs) {
314 std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex);
315 std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex);
316 m_specs.insert(position: m_specs.end(), first: rhs.m_specs.begin(), last: rhs.m_specs.end());
317 }
318
319 // The index "i" must be valid and this can't be used in multi-threaded code
320 // as no mutex lock is taken.
321 ModuleSpec &GetModuleSpecRefAtIndex(size_t i) { return m_specs[i]; }
322
323 bool GetModuleSpecAtIndex(size_t i, ModuleSpec &module_spec) const {
324 std::lock_guard<std::recursive_mutex> guard(m_mutex);
325 if (i < m_specs.size()) {
326 module_spec = m_specs[i];
327 return true;
328 }
329 module_spec.Clear();
330 return false;
331 }
332
333 bool FindMatchingModuleSpec(const ModuleSpec &module_spec,
334 ModuleSpec &match_module_spec) const {
335 std::lock_guard<std::recursive_mutex> guard(m_mutex);
336 bool exact_arch_match = true;
337 for (auto spec : m_specs) {
338 if (spec.Matches(match_module_spec: module_spec, exact_arch_match)) {
339 match_module_spec = spec;
340 return true;
341 }
342 }
343
344 // If there was an architecture, retry with a compatible arch
345 if (module_spec.GetArchitecturePtr()) {
346 exact_arch_match = false;
347 for (auto spec : m_specs) {
348 if (spec.Matches(match_module_spec: module_spec, exact_arch_match)) {
349 match_module_spec = spec;
350 return true;
351 }
352 }
353 }
354 match_module_spec.Clear();
355 return false;
356 }
357
358 void FindMatchingModuleSpecs(const ModuleSpec &module_spec,
359 ModuleSpecList &matching_list) const {
360 std::lock_guard<std::recursive_mutex> guard(m_mutex);
361 bool exact_arch_match = true;
362 const size_t initial_match_count = matching_list.GetSize();
363 for (auto spec : m_specs) {
364 if (spec.Matches(match_module_spec: module_spec, exact_arch_match))
365 matching_list.Append(spec);
366 }
367
368 // If there was an architecture, retry with a compatible arch if no matches
369 // were found
370 if (module_spec.GetArchitecturePtr() &&
371 (initial_match_count == matching_list.GetSize())) {
372 exact_arch_match = false;
373 for (auto spec : m_specs) {
374 if (spec.Matches(match_module_spec: module_spec, exact_arch_match))
375 matching_list.Append(spec);
376 }
377 }
378 }
379
380 void Dump(Stream &strm) {
381 std::lock_guard<std::recursive_mutex> guard(m_mutex);
382 uint32_t idx = 0;
383 for (auto spec : m_specs) {
384 strm.Printf(format: "[%u] ", idx);
385 spec.Dump(strm);
386 strm.EOL();
387 ++idx;
388 }
389 }
390
391 typedef std::vector<ModuleSpec> collection;
392 typedef LockingAdaptedIterable<collection, ModuleSpec, vector_adapter,
393 std::recursive_mutex>
394 ModuleSpecIterable;
395
396 ModuleSpecIterable ModuleSpecs() {
397 return ModuleSpecIterable(m_specs, m_mutex);
398 }
399
400protected:
401 collection m_specs; ///< The collection of modules.
402 mutable std::recursive_mutex m_mutex;
403};
404
405} // namespace lldb_private
406
407#endif // LLDB_CORE_MODULESPEC_H
408

source code of lldb/include/lldb/Core/ModuleSpec.h