1 //===-- DataFileCache.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_DATAFILECACHE_H 10 #define LLDB_CORE_DATAFILECACHE_H 11 12 #include "lldb/Utility/FileSpec.h" 13 #include "lldb/Utility/Status.h" 14 #include "lldb/Utility/UUID.h" 15 #include "lldb/lldb-forward.h" 16 #include "llvm/ADT/DenseMap.h" 17 #include "llvm/Support/Caching.h" 18 #include <mutex> 19 20 namespace lldb_private { 21 22 /// This class enables data to be cached into a directory using the llvm 23 /// caching code. Data can be stored and accessed using a unique string key. 24 /// The data will be stored in the directory that is specified in the 25 /// DataFileCache constructor. The data will be stored in files that start with 26 /// "llvmcache-<key>" where <key> is the key name specified when getting to 27 /// setting cached data. 28 /// 29 /// Sample code for how to use the cache: 30 /// 31 /// DataFileCache cache("/tmp/lldb-test-cache"); 32 /// StringRef key("Key1"); 33 /// auto mem_buffer_up = cache.GetCachedData(key); 34 /// if (mem_buffer_up) { 35 /// printf("cached data:\n%s", mem_buffer_up->getBufferStart()); 36 /// } else { 37 /// std::vector<uint8_t> data = { 'h', 'e', 'l', 'l', 'o', '\n' }; 38 /// cache.SetCachedData(key, data); 39 /// } 40 41 class DataFileCache { 42 public: 43 /// Create a data file cache in the directory path that is specified. 44 /// 45 /// Data will be cached in files created in this directory when clients call 46 /// DataFileCache::SetCacheData. 47 DataFileCache(llvm::StringRef path); 48 49 /// Get cached data from the cache directory for the specified key. 50 /// 51 /// Keys must be unique for any given data. This function attempts to see if 52 /// the data is available for the specified key and will return a valid memory 53 /// buffer is data is available. 54 /// 55 /// \param key 56 /// The unique string key that identifies data being cached. 57 /// 58 /// \return 59 /// A valid unique pointer to a memory buffer if the data is available, or 60 /// a unique pointer that contains NULL if the data is not available. 61 std::unique_ptr<llvm::MemoryBuffer> GetCachedData(llvm::StringRef key); 62 63 /// Set cached data for the specified key. 64 /// 65 /// Setting the cached data will save a file in the cache directory to contain 66 /// the specified data. 67 /// 68 /// \param key 69 /// The unique string key that identifies data being cached. 70 /// 71 /// \return 72 /// True if the data was successfully cached, false otherwise. 73 bool SetCachedData(llvm::StringRef key, llvm::ArrayRef<uint8_t> data); 74 75 /// Remove the cache file associated with the key. 76 Status RemoveCacheFile(llvm::StringRef key); 77 78 private: 79 /// Return the cache file that is associated with the key. 80 FileSpec GetCacheFilePath(llvm::StringRef key); 81 82 llvm::FileCache m_cache_callback; 83 FileSpec m_cache_dir; 84 std::mutex m_mutex; 85 std::unique_ptr<llvm::MemoryBuffer> m_mem_buff_up; 86 bool m_take_ownership = false; 87 }; 88 89 /// A signature for a given file on disk. 90 /// 91 /// Any files that are cached in the LLDB index cached need some data that 92 /// uniquely identifies a file on disk and this information should be written 93 /// into each cache file so we can validate if the cache file still matches 94 /// the file we are trying to load cached data for. Objects can fill out this 95 /// signature and then encode and decode them to validate the signatures 96 /// match. If they do not match, the cache file on disk should be removed as 97 /// it is out of date. 98 struct CacheSignature { 99 /// UUID of object file or module. 100 llvm::Optional<UUID> m_uuid = llvm::None; 101 /// Modification time of file on disk. 102 llvm::Optional<std::time_t> m_mod_time = llvm::None; 103 /// If this describes a .o file with a BSD archive, the BSD archive's 104 /// modification time will be in m_mod_time, and the .o file's modification 105 /// time will be in this m_obj_mod_time. 106 llvm::Optional<std::time_t> m_obj_mod_time = llvm::None; 107 108 CacheSignature() = default; 109 110 /// Create a signature from a module. 111 CacheSignature(lldb_private::Module *module); 112 113 /// Create a signature from an object file. 114 CacheSignature(lldb_private::ObjectFile *objfile); 115 116 void Clear() { 117 m_uuid = llvm::None; 118 m_mod_time = llvm::None; 119 m_obj_mod_time = llvm::None; 120 } 121 122 /// Return true only if the CacheSignature is valid. 123 /// 124 /// Cache signatures are considered valid only if there is a UUID in the file 125 /// that can uniquely identify the file. Some build systems play with 126 /// modification times of file so we can not trust them without using valid 127 /// unique idenifier like the UUID being valid. 128 bool IsValid() const { return m_uuid.has_value(); } 129 130 /// Check if two signatures are the same. 131 bool operator==(const CacheSignature &rhs) const { 132 return m_uuid == rhs.m_uuid && m_mod_time == rhs.m_mod_time && 133 m_obj_mod_time == rhs.m_obj_mod_time; 134 } 135 136 /// Check if two signatures differ. 137 bool operator!=(const CacheSignature &rhs) const { return !(*this == rhs); } 138 /// Encode this object into a data encoder object. 139 /// 140 /// This allows this object to be serialized to disk. The CacheSignature 141 /// object must have at least one member variable that has a value in order to 142 /// be serialized so that we can match this data to when the cached file is 143 /// loaded at a later time. 144 /// 145 /// \param encoder 146 /// A data encoder object that serialized bytes will be encoded into. 147 /// 148 /// \return 149 /// True if a signature was encoded, and false if there were no member 150 /// variables that had value. False indicates this data should not be 151 /// cached to disk because we were unable to encode a valid signature. 152 bool Encode(DataEncoder &encoder) const; 153 154 /// Decode a serialized version of this object from data. 155 /// 156 /// \param data 157 /// The decoder object that references the serialized data. 158 /// 159 /// \param offset_ptr 160 /// A pointer that contains the offset from which the data will be decoded 161 /// from that gets updated as data gets decoded. 162 /// 163 /// \return 164 /// True if the signature was successfully decoded, false otherwise. 165 bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr); 166 }; 167 168 /// Many cache files require string tables to store data efficiently. This 169 /// class helps create string tables. 170 class ConstStringTable { 171 public: 172 ConstStringTable() = default; 173 /// Add a string into the string table. 174 /// 175 /// Add a string to the string table will only add the same string one time 176 /// and will return the offset in the string table buffer to that string. 177 /// String tables are easy to build with ConstString objects since most LLDB 178 /// classes for symbol or debug info use them already and they provide 179 /// permanent storage for the string. 180 /// 181 /// \param s 182 /// The string to insert into the string table. 183 /// 184 /// \return 185 /// The byte offset from the start of the string table for the inserted 186 /// string. Duplicate strings that get inserted will return the same 187 /// byte offset. 188 uint32_t Add(ConstString s); 189 190 bool Encode(DataEncoder &encoder); 191 192 private: 193 std::vector<ConstString> m_strings; 194 llvm::DenseMap<ConstString, uint32_t> m_string_to_offset; 195 /// Skip one byte to start the string table off with an empty string. 196 uint32_t m_next_offset = 1; 197 }; 198 199 /// Many cache files require string tables to store data efficiently. This 200 /// class helps give out strings from a string table that was read from a 201 /// cache file. 202 class StringTableReader { 203 public: 204 StringTableReader() = default; 205 206 llvm::StringRef Get(uint32_t offset) const; 207 208 bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr); 209 210 protected: 211 /// All of the strings in the string table are contained in m_data. 212 llvm::StringRef m_data; 213 }; 214 215 } // namespace lldb_private 216 217 #endif // LLDB_CORE_DATAFILECACHE_H 218