1 | //===-- DataFileCache.cpp -------------------------------------------------===// |
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 | #include "lldb/Core/DataFileCache.h" |
10 | #include "lldb/Core/Module.h" |
11 | #include "lldb/Core/ModuleList.h" |
12 | #include "lldb/Host/FileSystem.h" |
13 | #include "lldb/Symbol/ObjectFile.h" |
14 | #include "lldb/Utility/DataEncoder.h" |
15 | #include "lldb/Utility/LLDBLog.h" |
16 | #include "lldb/Utility/Log.h" |
17 | #include "llvm/Support/CachePruning.h" |
18 | |
19 | using namespace lldb_private; |
20 | |
21 | |
22 | llvm::CachePruningPolicy DataFileCache::GetLLDBIndexCachePolicy() { |
23 | static llvm::CachePruningPolicy policy; |
24 | static llvm::once_flag once_flag; |
25 | |
26 | llvm::call_once(flag&: once_flag, F: []() { |
27 | // Prune the cache based off of the LLDB settings each time we create a |
28 | // cache object. |
29 | ModuleListProperties &properties = |
30 | ModuleList::GetGlobalModuleListProperties(); |
31 | // Only scan once an hour. If we have lots of debug sessions we don't want |
32 | // to scan this directory too often. A timestamp file is written to the |
33 | // directory to ensure different processes don't scan the directory too |
34 | // often. This setting doesn't mean that a thread will continually scan the |
35 | // cache directory within this process. |
36 | policy.Interval = std::chrono::hours(1); |
37 | // Get the user settings for pruning. |
38 | policy.MaxSizeBytes = properties.GetLLDBIndexCacheMaxByteSize(); |
39 | policy.MaxSizePercentageOfAvailableSpace = |
40 | properties.GetLLDBIndexCacheMaxPercent(); |
41 | policy.Expiration = |
42 | std::chrono::hours(properties.GetLLDBIndexCacheExpirationDays() * 24); |
43 | }); |
44 | return policy; |
45 | } |
46 | |
47 | DataFileCache::DataFileCache(llvm::StringRef path, llvm::CachePruningPolicy policy) { |
48 | m_cache_dir.SetPath(path); |
49 | pruneCache(Path: path, Policy: policy); |
50 | |
51 | // This lambda will get called when the data is gotten from the cache and |
52 | // also after the data was set for a given key. We only need to take |
53 | // ownership of the data if we are geting the data, so we use the |
54 | // m_take_ownership member variable to indicate if we need to take |
55 | // ownership. |
56 | |
57 | auto add_buffer = [this](unsigned task, const llvm::Twine &moduleName, |
58 | std::unique_ptr<llvm::MemoryBuffer> m) { |
59 | if (m_take_ownership) |
60 | m_mem_buff_up = std::move(m); |
61 | }; |
62 | llvm::Expected<llvm::FileCache> cache_or_err = |
63 | llvm::localCache(CacheNameRef: "LLDBModuleCache" , TempFilePrefixRef: "lldb-module" , CacheDirectoryPathRef: path, AddBuffer: add_buffer); |
64 | if (cache_or_err) |
65 | m_cache_callback = std::move(*cache_or_err); |
66 | else { |
67 | Log *log = GetLog(mask: LLDBLog::Modules); |
68 | LLDB_LOG_ERROR(log, cache_or_err.takeError(), |
69 | "failed to create lldb index cache directory: {0}" ); |
70 | } |
71 | } |
72 | |
73 | std::unique_ptr<llvm::MemoryBuffer> |
74 | DataFileCache::GetCachedData(llvm::StringRef key) { |
75 | std::lock_guard<std::mutex> guard(m_mutex); |
76 | |
77 | const unsigned task = 1; |
78 | m_take_ownership = true; |
79 | // If we call the "m_cache_callback" function and the data is cached, it will |
80 | // call the "add_buffer" lambda function from the constructor which will in |
81 | // turn take ownership of the member buffer that is passed to the callback and |
82 | // put it into a member variable. |
83 | llvm::Expected<llvm::AddStreamFn> add_stream_or_err = |
84 | m_cache_callback(task, key, "" ); |
85 | m_take_ownership = false; |
86 | // At this point we either already called the "add_buffer" lambda with |
87 | // the data or we haven't. We can tell if we got the cached data by checking |
88 | // the add_stream function pointer value below. |
89 | if (add_stream_or_err) { |
90 | llvm::AddStreamFn &add_stream = *add_stream_or_err; |
91 | // If the "add_stream" is nullptr, then the data was cached and we already |
92 | // called the "add_buffer" lambda. If it is valid, then if we were to call |
93 | // the add_stream function it would cause a cache file to get generated |
94 | // and we would be expected to fill in the data. In this function we only |
95 | // want to check if the data was cached, so we don't want to call |
96 | // "add_stream" in this function. |
97 | if (!add_stream) |
98 | return std::move(m_mem_buff_up); |
99 | } else { |
100 | Log *log = GetLog(mask: LLDBLog::Modules); |
101 | LLDB_LOG_ERROR(log, add_stream_or_err.takeError(), |
102 | "failed to get the cache add stream callback for key: {0}" ); |
103 | } |
104 | // Data was not cached. |
105 | return std::unique_ptr<llvm::MemoryBuffer>(); |
106 | } |
107 | |
108 | bool DataFileCache::SetCachedData(llvm::StringRef key, |
109 | llvm::ArrayRef<uint8_t> data) { |
110 | std::lock_guard<std::mutex> guard(m_mutex); |
111 | const unsigned task = 2; |
112 | // If we call this function and the data is cached, it will call the |
113 | // add_buffer lambda function from the constructor which will ignore the |
114 | // data. |
115 | llvm::Expected<llvm::AddStreamFn> add_stream_or_err = |
116 | m_cache_callback(task, key, "" ); |
117 | // If we reach this code then we either already called the callback with |
118 | // the data or we haven't. We can tell if we had the cached data by checking |
119 | // the CacheAddStream function pointer value below. |
120 | if (add_stream_or_err) { |
121 | llvm::AddStreamFn &add_stream = *add_stream_or_err; |
122 | // If the "add_stream" is nullptr, then the data was cached. If it is |
123 | // valid, then if we call the add_stream function with a task it will |
124 | // cause the file to get generated, but we only want to check if the data |
125 | // is cached here, so we don't want to call it here. Note that the |
126 | // add_buffer will also get called in this case after the data has been |
127 | // provided, but we won't take ownership of the memory buffer as we just |
128 | // want to write the data. |
129 | if (add_stream) { |
130 | llvm::Expected<std::unique_ptr<llvm::CachedFileStream>> file_or_err = |
131 | add_stream(task, "" ); |
132 | if (file_or_err) { |
133 | llvm::CachedFileStream *cfs = file_or_err->get(); |
134 | cfs->OS->write(Ptr: (const char *)data.data(), Size: data.size()); |
135 | if (llvm::Error err = cfs->commit()) { |
136 | Log *log = GetLog(mask: LLDBLog::Modules); |
137 | LLDB_LOG_ERROR(log, std::move(err), |
138 | "failed to commit to the cache for key: {0}" ); |
139 | } |
140 | return true; |
141 | } else { |
142 | Log *log = GetLog(mask: LLDBLog::Modules); |
143 | LLDB_LOG_ERROR(log, file_or_err.takeError(), |
144 | "failed to get the cache file stream for key: {0}" ); |
145 | } |
146 | } |
147 | } else { |
148 | Log *log = GetLog(mask: LLDBLog::Modules); |
149 | LLDB_LOG_ERROR(log, add_stream_or_err.takeError(), |
150 | "failed to get the cache add stream callback for key: {0}" ); |
151 | } |
152 | return false; |
153 | } |
154 | |
155 | FileSpec DataFileCache::GetCacheFilePath(llvm::StringRef key) { |
156 | FileSpec cache_file(m_cache_dir); |
157 | std::string filename("llvmcache-" ); |
158 | filename += key.str(); |
159 | cache_file.AppendPathComponent(component: filename); |
160 | return cache_file; |
161 | } |
162 | |
163 | Status DataFileCache::RemoveCacheFile(llvm::StringRef key) { |
164 | FileSpec cache_file = GetCacheFilePath(key); |
165 | FileSystem &fs = FileSystem::Instance(); |
166 | if (!fs.Exists(file_spec: cache_file)) |
167 | return Status(); |
168 | return fs.RemoveFile(file_spec: cache_file); |
169 | } |
170 | |
171 | CacheSignature::CacheSignature(lldb_private::Module *module) { |
172 | Clear(); |
173 | UUID uuid = module->GetUUID(); |
174 | if (uuid.IsValid()) |
175 | m_uuid = uuid; |
176 | |
177 | std::time_t mod_time = 0; |
178 | mod_time = llvm::sys::toTimeT(TP: module->GetModificationTime()); |
179 | if (mod_time != 0) |
180 | m_mod_time = mod_time; |
181 | |
182 | mod_time = llvm::sys::toTimeT(TP: module->GetObjectModificationTime()); |
183 | if (mod_time != 0) |
184 | m_obj_mod_time = mod_time; |
185 | } |
186 | |
187 | CacheSignature::CacheSignature(lldb_private::ObjectFile *objfile) { |
188 | Clear(); |
189 | UUID uuid = objfile->GetUUID(); |
190 | if (uuid.IsValid()) |
191 | m_uuid = uuid; |
192 | |
193 | std::time_t mod_time = 0; |
194 | // Grab the modification time of the object file's file. It isn't always the |
195 | // same as the module's file when you have a executable file as the main |
196 | // executable, and you have a object file for a symbol file. |
197 | FileSystem &fs = FileSystem::Instance(); |
198 | mod_time = llvm::sys::toTimeT(TP: fs.GetModificationTime(file_spec: objfile->GetFileSpec())); |
199 | if (mod_time != 0) |
200 | m_mod_time = mod_time; |
201 | |
202 | mod_time = |
203 | llvm::sys::toTimeT(TP: objfile->GetModule()->GetObjectModificationTime()); |
204 | if (mod_time != 0) |
205 | m_obj_mod_time = mod_time; |
206 | } |
207 | |
208 | enum SignatureEncoding { |
209 | eSignatureUUID = 1u, |
210 | eSignatureModTime = 2u, |
211 | eSignatureObjectModTime = 3u, |
212 | eSignatureEnd = 255u, |
213 | }; |
214 | |
215 | bool CacheSignature::Encode(DataEncoder &encoder) const { |
216 | if (!IsValid()) |
217 | return false; // Invalid signature, return false! |
218 | |
219 | if (m_uuid) { |
220 | llvm::ArrayRef<uint8_t> uuid_bytes = m_uuid->GetBytes(); |
221 | encoder.AppendU8(value: eSignatureUUID); |
222 | encoder.AppendU8(value: uuid_bytes.size()); |
223 | encoder.AppendData(data: uuid_bytes); |
224 | } |
225 | if (m_mod_time) { |
226 | encoder.AppendU8(value: eSignatureModTime); |
227 | encoder.AppendU32(value: *m_mod_time); |
228 | } |
229 | if (m_obj_mod_time) { |
230 | encoder.AppendU8(value: eSignatureObjectModTime); |
231 | encoder.AppendU32(value: *m_obj_mod_time); |
232 | } |
233 | encoder.AppendU8(value: eSignatureEnd); |
234 | return true; |
235 | } |
236 | |
237 | bool CacheSignature::(const lldb_private::DataExtractor &data, |
238 | lldb::offset_t *offset_ptr) { |
239 | Clear(); |
240 | while (uint8_t sig_encoding = data.GetU8(offset_ptr)) { |
241 | switch (sig_encoding) { |
242 | case eSignatureUUID: { |
243 | const uint8_t length = data.GetU8(offset_ptr); |
244 | const uint8_t *bytes = (const uint8_t *)data.GetData(offset_ptr, length); |
245 | if (bytes != nullptr && length > 0) |
246 | m_uuid = UUID(llvm::ArrayRef<uint8_t>(bytes, length)); |
247 | } break; |
248 | case eSignatureModTime: { |
249 | uint32_t mod_time = data.GetU32(offset_ptr); |
250 | if (mod_time > 0) |
251 | m_mod_time = mod_time; |
252 | } break; |
253 | case eSignatureObjectModTime: { |
254 | uint32_t mod_time = data.GetU32(offset_ptr); |
255 | if (mod_time > 0) |
256 | m_obj_mod_time = mod_time; |
257 | } break; |
258 | case eSignatureEnd: |
259 | // The definition of is valid changed to only be valid if the UUID is |
260 | // valid so make sure that if we attempt to decode an old cache file |
261 | // that we will fail to decode the cache file if the signature isn't |
262 | // considered valid. |
263 | return IsValid(); |
264 | default: |
265 | break; |
266 | } |
267 | } |
268 | return false; |
269 | } |
270 | |
271 | uint32_t ConstStringTable::Add(ConstString s) { |
272 | auto [pos, inserted] = m_string_to_offset.try_emplace(Key: s, Args&: m_next_offset); |
273 | if (inserted) { |
274 | m_strings.push_back(x: s); |
275 | m_next_offset += s.GetLength() + 1; |
276 | } |
277 | return pos->second; |
278 | } |
279 | |
280 | static const llvm::StringRef kStringTableIdentifier("STAB" ); |
281 | |
282 | bool ConstStringTable::Encode(DataEncoder &encoder) { |
283 | // Write an 4 character code into the stream. This will help us when decoding |
284 | // to make sure we find this identifier when decoding the string table to make |
285 | // sure we have the rigth data. It also helps to identify the string table |
286 | // when dumping the hex bytes in a cache file. |
287 | encoder.AppendData(data: kStringTableIdentifier); |
288 | size_t length_offset = encoder.GetByteSize(); |
289 | encoder.AppendU32(value: 0); // Total length of all strings which will be fixed up. |
290 | size_t strtab_offset = encoder.GetByteSize(); |
291 | encoder.AppendU8(value: 0); // Start the string table with an empty string. |
292 | for (auto s: m_strings) { |
293 | // Make sure all of the offsets match up with what we handed out! |
294 | assert(m_string_to_offset.find(s)->second == |
295 | encoder.GetByteSize() - strtab_offset); |
296 | // Append the C string into the encoder |
297 | encoder.AppendCString(data: s.GetStringRef()); |
298 | } |
299 | // Fixup the string table length. |
300 | encoder.PutU32(offset: length_offset, value: encoder.GetByteSize() - strtab_offset); |
301 | return true; |
302 | } |
303 | |
304 | bool StringTableReader::(const lldb_private::DataExtractor &data, |
305 | lldb::offset_t *offset_ptr) { |
306 | llvm::StringRef identifier((const char *)data.GetData(offset_ptr, length: 4), 4); |
307 | if (identifier != kStringTableIdentifier) |
308 | return false; |
309 | const uint32_t length = data.GetU32(offset_ptr); |
310 | // We always have at least one byte for the empty string at offset zero. |
311 | if (length == 0) |
312 | return false; |
313 | const char *bytes = (const char *)data.GetData(offset_ptr, length); |
314 | if (bytes == nullptr) |
315 | return false; |
316 | m_data = llvm::StringRef(bytes, length); |
317 | return true; |
318 | } |
319 | |
320 | llvm::StringRef StringTableReader::Get(uint32_t offset) const { |
321 | if (offset >= m_data.size()) |
322 | return llvm::StringRef(); |
323 | return llvm::StringRef(m_data.data() + offset); |
324 | } |
325 | |
326 | |