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