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