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