1254721Semaste//===-- ModuleSpec.h --------------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#ifndef liblldb_ModuleSpec_h_
10254721Semaste#define liblldb_ModuleSpec_h_
11254721Semaste
12344779Sdim#include "lldb/Host/FileSystem.h"
13254721Semaste#include "lldb/Target/PathMappingList.h"
14327952Sdim#include "lldb/Utility/ArchSpec.h"
15321369Sdim#include "lldb/Utility/FileSpec.h"
16321369Sdim#include "lldb/Utility/Stream.h"
17321369Sdim#include "lldb/Utility/UUID.h"
18254721Semaste
19314564Sdim#include "llvm/Support/Chrono.h"
20314564Sdim
21314564Sdim#include <mutex>
22314564Sdim#include <vector>
23314564Sdim
24254721Semastenamespace lldb_private {
25254721Semaste
26314564Sdimclass ModuleSpec {
27254721Semastepublic:
28314564Sdim  ModuleSpec()
29314564Sdim      : m_file(), m_platform_file(), m_symbol_file(), m_arch(), m_uuid(),
30314564Sdim        m_object_name(), m_object_offset(0), m_object_size(0),
31314564Sdim        m_source_mappings() {}
32254721Semaste
33344779Sdim  ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID())
34314564Sdim      : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(),
35341825Sdim        m_uuid(uuid), m_object_name(), m_object_offset(0),
36344779Sdim        m_object_size(FileSystem::Instance().GetByteSize(file_spec)),
37344779Sdim        m_source_mappings() {}
38254721Semaste
39314564Sdim  ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch)
40314564Sdim      : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(arch),
41314564Sdim        m_uuid(), m_object_name(), m_object_offset(0),
42344779Sdim        m_object_size(FileSystem::Instance().GetByteSize(file_spec)),
43344779Sdim        m_source_mappings() {}
44254721Semaste
45314564Sdim  ModuleSpec(const ModuleSpec &rhs)
46314564Sdim      : m_file(rhs.m_file), m_platform_file(rhs.m_platform_file),
47314564Sdim        m_symbol_file(rhs.m_symbol_file), m_arch(rhs.m_arch),
48314564Sdim        m_uuid(rhs.m_uuid), m_object_name(rhs.m_object_name),
49314564Sdim        m_object_offset(rhs.m_object_offset), m_object_size(rhs.m_object_size),
50314564Sdim        m_object_mod_time(rhs.m_object_mod_time),
51314564Sdim        m_source_mappings(rhs.m_source_mappings) {}
52254721Semaste
53314564Sdim  ModuleSpec &operator=(const ModuleSpec &rhs) {
54314564Sdim    if (this != &rhs) {
55314564Sdim      m_file = rhs.m_file;
56314564Sdim      m_platform_file = rhs.m_platform_file;
57314564Sdim      m_symbol_file = rhs.m_symbol_file;
58314564Sdim      m_arch = rhs.m_arch;
59314564Sdim      m_uuid = rhs.m_uuid;
60314564Sdim      m_object_name = rhs.m_object_name;
61314564Sdim      m_object_offset = rhs.m_object_offset;
62314564Sdim      m_object_size = rhs.m_object_size;
63314564Sdim      m_object_mod_time = rhs.m_object_mod_time;
64314564Sdim      m_source_mappings = rhs.m_source_mappings;
65254721Semaste    }
66314564Sdim    return *this;
67314564Sdim  }
68254721Semaste
69314564Sdim  FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); }
70296417Sdim
71314564Sdim  const FileSpec *GetFileSpecPtr() const {
72314564Sdim    return (m_file ? &m_file : nullptr);
73314564Sdim  }
74254721Semaste
75314564Sdim  FileSpec &GetFileSpec() { return m_file; }
76254721Semaste
77314564Sdim  const FileSpec &GetFileSpec() const { return m_file; }
78254721Semaste
79314564Sdim  FileSpec *GetPlatformFileSpecPtr() {
80314564Sdim    return (m_platform_file ? &m_platform_file : nullptr);
81314564Sdim  }
82254721Semaste
83314564Sdim  const FileSpec *GetPlatformFileSpecPtr() const {
84314564Sdim    return (m_platform_file ? &m_platform_file : nullptr);
85314564Sdim  }
86254721Semaste
87314564Sdim  FileSpec &GetPlatformFileSpec() { return m_platform_file; }
88254721Semaste
89314564Sdim  const FileSpec &GetPlatformFileSpec() const { return m_platform_file; }
90254721Semaste
91314564Sdim  FileSpec *GetSymbolFileSpecPtr() {
92314564Sdim    return (m_symbol_file ? &m_symbol_file : nullptr);
93314564Sdim  }
94254721Semaste
95314564Sdim  const FileSpec *GetSymbolFileSpecPtr() const {
96314564Sdim    return (m_symbol_file ? &m_symbol_file : nullptr);
97314564Sdim  }
98254721Semaste
99314564Sdim  FileSpec &GetSymbolFileSpec() { return m_symbol_file; }
100254721Semaste
101314564Sdim  const FileSpec &GetSymbolFileSpec() const { return m_symbol_file; }
102254721Semaste
103314564Sdim  ArchSpec *GetArchitecturePtr() {
104314564Sdim    return (m_arch.IsValid() ? &m_arch : nullptr);
105314564Sdim  }
106288943Sdim
107314564Sdim  const ArchSpec *GetArchitecturePtr() const {
108314564Sdim    return (m_arch.IsValid() ? &m_arch : nullptr);
109314564Sdim  }
110288943Sdim
111314564Sdim  ArchSpec &GetArchitecture() { return m_arch; }
112288943Sdim
113314564Sdim  const ArchSpec &GetArchitecture() const { return m_arch; }
114314564Sdim
115314564Sdim  UUID *GetUUIDPtr() { return (m_uuid.IsValid() ? &m_uuid : nullptr); }
116314564Sdim
117314564Sdim  const UUID *GetUUIDPtr() const {
118314564Sdim    return (m_uuid.IsValid() ? &m_uuid : nullptr);
119314564Sdim  }
120314564Sdim
121314564Sdim  UUID &GetUUID() { return m_uuid; }
122314564Sdim
123314564Sdim  const UUID &GetUUID() const { return m_uuid; }
124314564Sdim
125314564Sdim  ConstString &GetObjectName() { return m_object_name; }
126314564Sdim
127353358Sdim  ConstString GetObjectName() const { return m_object_name; }
128314564Sdim
129314564Sdim  uint64_t GetObjectOffset() const { return m_object_offset; }
130314564Sdim
131314564Sdim  void SetObjectOffset(uint64_t object_offset) {
132314564Sdim    m_object_offset = object_offset;
133314564Sdim  }
134314564Sdim
135314564Sdim  uint64_t GetObjectSize() const { return m_object_size; }
136314564Sdim
137314564Sdim  void SetObjectSize(uint64_t object_size) { m_object_size = object_size; }
138314564Sdim
139314564Sdim  llvm::sys::TimePoint<> &GetObjectModificationTime() {
140314564Sdim    return m_object_mod_time;
141314564Sdim  }
142314564Sdim
143314564Sdim  const llvm::sys::TimePoint<> &GetObjectModificationTime() const {
144314564Sdim    return m_object_mod_time;
145314564Sdim  }
146314564Sdim
147314564Sdim  PathMappingList &GetSourceMappingList() const { return m_source_mappings; }
148314564Sdim
149314564Sdim  void Clear() {
150314564Sdim    m_file.Clear();
151314564Sdim    m_platform_file.Clear();
152314564Sdim    m_symbol_file.Clear();
153314564Sdim    m_arch.Clear();
154314564Sdim    m_uuid.Clear();
155314564Sdim    m_object_name.Clear();
156314564Sdim    m_object_offset = 0;
157314564Sdim    m_object_size = 0;
158314564Sdim    m_source_mappings.Clear(false);
159314564Sdim    m_object_mod_time = llvm::sys::TimePoint<>();
160314564Sdim  }
161314564Sdim
162314564Sdim  explicit operator bool() const {
163314564Sdim    if (m_file)
164314564Sdim      return true;
165314564Sdim    if (m_platform_file)
166314564Sdim      return true;
167314564Sdim    if (m_symbol_file)
168314564Sdim      return true;
169314564Sdim    if (m_arch.IsValid())
170314564Sdim      return true;
171314564Sdim    if (m_uuid.IsValid())
172314564Sdim      return true;
173314564Sdim    if (m_object_name)
174314564Sdim      return true;
175314564Sdim    if (m_object_size)
176314564Sdim      return true;
177314564Sdim    if (m_object_mod_time != llvm::sys::TimePoint<>())
178314564Sdim      return true;
179314564Sdim    return false;
180314564Sdim  }
181314564Sdim
182314564Sdim  void Dump(Stream &strm) const {
183314564Sdim    bool dumped_something = false;
184314564Sdim    if (m_file) {
185314564Sdim      strm.PutCString("file = '");
186314564Sdim      strm << m_file;
187314564Sdim      strm.PutCString("'");
188314564Sdim      dumped_something = true;
189254721Semaste    }
190314564Sdim    if (m_platform_file) {
191314564Sdim      if (dumped_something)
192314564Sdim        strm.PutCString(", ");
193314564Sdim      strm.PutCString("platform_file = '");
194314564Sdim      strm << m_platform_file;
195314564Sdim      strm.PutCString("'");
196314564Sdim      dumped_something = true;
197254721Semaste    }
198314564Sdim    if (m_symbol_file) {
199314564Sdim      if (dumped_something)
200314564Sdim        strm.PutCString(", ");
201314564Sdim      strm.PutCString("symbol_file = '");
202314564Sdim      strm << m_symbol_file;
203314564Sdim      strm.PutCString("'");
204314564Sdim      dumped_something = true;
205254721Semaste    }
206314564Sdim    if (m_arch.IsValid()) {
207314564Sdim      if (dumped_something)
208314564Sdim        strm.PutCString(", ");
209314564Sdim      strm.Printf("arch = ");
210360784Sdim      m_arch.DumpTriple(strm.AsRawOstream());
211314564Sdim      dumped_something = true;
212254721Semaste    }
213314564Sdim    if (m_uuid.IsValid()) {
214314564Sdim      if (dumped_something)
215314564Sdim        strm.PutCString(", ");
216314564Sdim      strm.PutCString("uuid = ");
217314564Sdim      m_uuid.Dump(&strm);
218314564Sdim      dumped_something = true;
219314564Sdim    }
220314564Sdim    if (m_object_name) {
221314564Sdim      if (dumped_something)
222314564Sdim        strm.PutCString(", ");
223314564Sdim      strm.Printf("object_name = %s", m_object_name.GetCString());
224314564Sdim      dumped_something = true;
225314564Sdim    }
226314564Sdim    if (m_object_offset > 0) {
227314564Sdim      if (dumped_something)
228314564Sdim        strm.PutCString(", ");
229314564Sdim      strm.Printf("object_offset = %" PRIu64, m_object_offset);
230314564Sdim      dumped_something = true;
231314564Sdim    }
232314564Sdim    if (m_object_size > 0) {
233314564Sdim      if (dumped_something)
234314564Sdim        strm.PutCString(", ");
235314564Sdim      strm.Printf("object size = %" PRIu64, m_object_size);
236314564Sdim      dumped_something = true;
237314564Sdim    }
238314564Sdim    if (m_object_mod_time != llvm::sys::TimePoint<>()) {
239314564Sdim      if (dumped_something)
240314564Sdim        strm.PutCString(", ");
241314564Sdim      strm.Format("object_mod_time = {0:x+}",
242314564Sdim                  uint64_t(llvm::sys::toTimeT(m_object_mod_time)));
243314564Sdim    }
244314564Sdim  }
245254721Semaste
246314564Sdim  bool Matches(const ModuleSpec &match_module_spec,
247314564Sdim               bool exact_arch_match) const {
248314564Sdim    if (match_module_spec.GetUUIDPtr() &&
249314564Sdim        match_module_spec.GetUUID() != GetUUID())
250314564Sdim      return false;
251314564Sdim    if (match_module_spec.GetObjectName() &&
252314564Sdim        match_module_spec.GetObjectName() != GetObjectName())
253314564Sdim      return false;
254360784Sdim    if (!FileSpec::Match(match_module_spec.GetFileSpec(), GetFileSpec()))
255360784Sdim      return false;
256360784Sdim    if (GetPlatformFileSpec() &&
257360784Sdim        !FileSpec::Match(match_module_spec.GetPlatformFileSpec(),
258360784Sdim                         GetPlatformFileSpec())) {
259360784Sdim      return false;
260254721Semaste    }
261314564Sdim    // Only match the symbol file spec if there is one in this ModuleSpec
262360784Sdim    if (GetSymbolFileSpec() &&
263360784Sdim        !FileSpec::Match(match_module_spec.GetSymbolFileSpec(),
264360784Sdim                         GetSymbolFileSpec())) {
265360784Sdim      return false;
266254721Semaste    }
267314564Sdim    if (match_module_spec.GetArchitecturePtr()) {
268314564Sdim      if (exact_arch_match) {
269314564Sdim        if (!GetArchitecture().IsExactMatch(
270314564Sdim                match_module_spec.GetArchitecture()))
271314564Sdim          return false;
272314564Sdim      } else {
273314564Sdim        if (!GetArchitecture().IsCompatibleMatch(
274314564Sdim                match_module_spec.GetArchitecture()))
275314564Sdim          return false;
276314564Sdim      }
277314564Sdim    }
278314564Sdim    return true;
279314564Sdim  }
280254721Semaste
281254721Semasteprotected:
282314564Sdim  FileSpec m_file;
283314564Sdim  FileSpec m_platform_file;
284314564Sdim  FileSpec m_symbol_file;
285314564Sdim  ArchSpec m_arch;
286314564Sdim  UUID m_uuid;
287314564Sdim  ConstString m_object_name;
288314564Sdim  uint64_t m_object_offset;
289314564Sdim  uint64_t m_object_size;
290314564Sdim  llvm::sys::TimePoint<> m_object_mod_time;
291314564Sdim  mutable PathMappingList m_source_mappings;
292254721Semaste};
293254721Semaste
294314564Sdimclass ModuleSpecList {
295254721Semastepublic:
296314564Sdim  ModuleSpecList() : m_specs(), m_mutex() {}
297254721Semaste
298314564Sdim  ModuleSpecList(const ModuleSpecList &rhs) : m_specs(), m_mutex() {
299314564Sdim    std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex);
300314564Sdim    std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex);
301314564Sdim    m_specs = rhs.m_specs;
302314564Sdim  }
303254721Semaste
304314564Sdim  ~ModuleSpecList() = default;
305254721Semaste
306314564Sdim  ModuleSpecList &operator=(const ModuleSpecList &rhs) {
307314564Sdim    if (this != &rhs) {
308353358Sdim      std::lock(m_mutex, rhs.m_mutex);
309353358Sdim      std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex, std::adopt_lock);
310353358Sdim      std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex,
311353358Sdim                                                      std::adopt_lock);
312314564Sdim      m_specs = rhs.m_specs;
313254721Semaste    }
314314564Sdim    return *this;
315314564Sdim  }
316254721Semaste
317314564Sdim  size_t GetSize() const {
318314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_mutex);
319314564Sdim    return m_specs.size();
320314564Sdim  }
321254721Semaste
322314564Sdim  void Clear() {
323314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_mutex);
324314564Sdim    m_specs.clear();
325314564Sdim  }
326254721Semaste
327314564Sdim  void Append(const ModuleSpec &spec) {
328314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_mutex);
329314564Sdim    m_specs.push_back(spec);
330314564Sdim  }
331254721Semaste
332314564Sdim  void Append(const ModuleSpecList &rhs) {
333314564Sdim    std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex);
334314564Sdim    std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex);
335314564Sdim    m_specs.insert(m_specs.end(), rhs.m_specs.begin(), rhs.m_specs.end());
336314564Sdim  }
337314564Sdim
338341825Sdim  // The index "i" must be valid and this can't be used in multi-threaded code
339341825Sdim  // as no mutex lock is taken.
340314564Sdim  ModuleSpec &GetModuleSpecRefAtIndex(size_t i) { return m_specs[i]; }
341314564Sdim
342314564Sdim  bool GetModuleSpecAtIndex(size_t i, ModuleSpec &module_spec) const {
343314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_mutex);
344314564Sdim    if (i < m_specs.size()) {
345314564Sdim      module_spec = m_specs[i];
346314564Sdim      return true;
347254721Semaste    }
348314564Sdim    module_spec.Clear();
349314564Sdim    return false;
350314564Sdim  }
351254721Semaste
352314564Sdim  bool FindMatchingModuleSpec(const ModuleSpec &module_spec,
353314564Sdim                              ModuleSpec &match_module_spec) const {
354314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_mutex);
355314564Sdim    bool exact_arch_match = true;
356314564Sdim    for (auto spec : m_specs) {
357314564Sdim      if (spec.Matches(module_spec, exact_arch_match)) {
358314564Sdim        match_module_spec = spec;
359314564Sdim        return true;
360314564Sdim      }
361254721Semaste    }
362296417Sdim
363314564Sdim    // If there was an architecture, retry with a compatible arch
364314564Sdim    if (module_spec.GetArchitecturePtr()) {
365314564Sdim      exact_arch_match = false;
366314564Sdim      for (auto spec : m_specs) {
367314564Sdim        if (spec.Matches(module_spec, exact_arch_match)) {
368314564Sdim          match_module_spec = spec;
369314564Sdim          return true;
370254721Semaste        }
371314564Sdim      }
372254721Semaste    }
373314564Sdim    match_module_spec.Clear();
374314564Sdim    return false;
375314564Sdim  }
376296417Sdim
377360784Sdim  void FindMatchingModuleSpecs(const ModuleSpec &module_spec,
378360784Sdim                               ModuleSpecList &matching_list) const {
379314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_mutex);
380314564Sdim    bool exact_arch_match = true;
381314564Sdim    const size_t initial_match_count = matching_list.GetSize();
382314564Sdim    for (auto spec : m_specs) {
383314564Sdim      if (spec.Matches(module_spec, exact_arch_match))
384314564Sdim        matching_list.Append(spec);
385254721Semaste    }
386309124Sdim
387314564Sdim    // If there was an architecture, retry with a compatible arch if no matches
388314564Sdim    // were found
389314564Sdim    if (module_spec.GetArchitecturePtr() &&
390314564Sdim        (initial_match_count == matching_list.GetSize())) {
391314564Sdim      exact_arch_match = false;
392314564Sdim      for (auto spec : m_specs) {
393314564Sdim        if (spec.Matches(module_spec, exact_arch_match))
394314564Sdim          matching_list.Append(spec);
395314564Sdim      }
396254721Semaste    }
397314564Sdim  }
398254721Semaste
399314564Sdim  void Dump(Stream &strm) {
400314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_mutex);
401314564Sdim    uint32_t idx = 0;
402314564Sdim    for (auto spec : m_specs) {
403314564Sdim      strm.Printf("[%u] ", idx);
404314564Sdim      spec.Dump(strm);
405314564Sdim      strm.EOL();
406314564Sdim      ++idx;
407254721Semaste    }
408314564Sdim  }
409254721Semaste
410254721Semasteprotected:
411314564Sdim  typedef std::vector<ModuleSpec> collection; ///< The module collection type.
412314564Sdim  collection m_specs;                         ///< The collection of modules.
413314564Sdim  mutable std::recursive_mutex m_mutex;
414254721Semaste};
415254721Semaste
416254721Semaste} // namespace lldb_private
417254721Semaste
418296417Sdim#endif // liblldb_ModuleSpec_h_
419