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