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