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