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