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 | return true; |
136 | } else { |
137 | Log *log = GetLog(mask: LLDBLog::Modules); |
138 | LLDB_LOG_ERROR(log, file_or_err.takeError(), |
139 | "failed to get the cache file stream for key: {0}" ); |
140 | } |
141 | } |
142 | } else { |
143 | Log *log = GetLog(mask: LLDBLog::Modules); |
144 | LLDB_LOG_ERROR(log, add_stream_or_err.takeError(), |
145 | "failed to get the cache add stream callback for key: {0}" ); |
146 | } |
147 | return false; |
148 | } |
149 | |
150 | FileSpec DataFileCache::GetCacheFilePath(llvm::StringRef key) { |
151 | FileSpec cache_file(m_cache_dir); |
152 | std::string filename("llvmcache-" ); |
153 | filename += key.str(); |
154 | cache_file.AppendPathComponent(component: filename); |
155 | return cache_file; |
156 | } |
157 | |
158 | Status DataFileCache::RemoveCacheFile(llvm::StringRef key) { |
159 | FileSpec cache_file = GetCacheFilePath(key); |
160 | FileSystem &fs = FileSystem::Instance(); |
161 | if (!fs.Exists(file_spec: cache_file)) |
162 | return Status(); |
163 | return fs.RemoveFile(file_spec: cache_file); |
164 | } |
165 | |
166 | CacheSignature::CacheSignature(lldb_private::Module *module) { |
167 | Clear(); |
168 | UUID uuid = module->GetUUID(); |
169 | if (uuid.IsValid()) |
170 | m_uuid = uuid; |
171 | |
172 | std::time_t mod_time = 0; |
173 | mod_time = llvm::sys::toTimeT(TP: module->GetModificationTime()); |
174 | if (mod_time != 0) |
175 | m_mod_time = mod_time; |
176 | |
177 | mod_time = llvm::sys::toTimeT(TP: module->GetObjectModificationTime()); |
178 | if (mod_time != 0) |
179 | m_obj_mod_time = mod_time; |
180 | } |
181 | |
182 | CacheSignature::CacheSignature(lldb_private::ObjectFile *objfile) { |
183 | Clear(); |
184 | UUID uuid = objfile->GetUUID(); |
185 | if (uuid.IsValid()) |
186 | m_uuid = uuid; |
187 | |
188 | std::time_t mod_time = 0; |
189 | // Grab the modification time of the object file's file. It isn't always the |
190 | // same as the module's file when you have a executable file as the main |
191 | // executable, and you have a object file for a symbol file. |
192 | FileSystem &fs = FileSystem::Instance(); |
193 | mod_time = llvm::sys::toTimeT(TP: fs.GetModificationTime(file_spec: objfile->GetFileSpec())); |
194 | if (mod_time != 0) |
195 | m_mod_time = mod_time; |
196 | |
197 | mod_time = |
198 | llvm::sys::toTimeT(TP: objfile->GetModule()->GetObjectModificationTime()); |
199 | if (mod_time != 0) |
200 | m_obj_mod_time = mod_time; |
201 | } |
202 | |
203 | enum SignatureEncoding { |
204 | eSignatureUUID = 1u, |
205 | eSignatureModTime = 2u, |
206 | eSignatureObjectModTime = 3u, |
207 | eSignatureEnd = 255u, |
208 | }; |
209 | |
210 | bool CacheSignature::Encode(DataEncoder &encoder) const { |
211 | if (!IsValid()) |
212 | return false; // Invalid signature, return false! |
213 | |
214 | if (m_uuid) { |
215 | llvm::ArrayRef<uint8_t> uuid_bytes = m_uuid->GetBytes(); |
216 | encoder.AppendU8(value: eSignatureUUID); |
217 | encoder.AppendU8(value: uuid_bytes.size()); |
218 | encoder.AppendData(data: uuid_bytes); |
219 | } |
220 | if (m_mod_time) { |
221 | encoder.AppendU8(value: eSignatureModTime); |
222 | encoder.AppendU32(value: *m_mod_time); |
223 | } |
224 | if (m_obj_mod_time) { |
225 | encoder.AppendU8(value: eSignatureObjectModTime); |
226 | encoder.AppendU32(value: *m_obj_mod_time); |
227 | } |
228 | encoder.AppendU8(value: eSignatureEnd); |
229 | return true; |
230 | } |
231 | |
232 | bool CacheSignature::(const lldb_private::DataExtractor &data, |
233 | lldb::offset_t *offset_ptr) { |
234 | Clear(); |
235 | while (uint8_t sig_encoding = data.GetU8(offset_ptr)) { |
236 | switch (sig_encoding) { |
237 | case eSignatureUUID: { |
238 | const uint8_t length = data.GetU8(offset_ptr); |
239 | const uint8_t *bytes = (const uint8_t *)data.GetData(offset_ptr, length); |
240 | if (bytes != nullptr && length > 0) |
241 | m_uuid = UUID(llvm::ArrayRef<uint8_t>(bytes, length)); |
242 | } break; |
243 | case eSignatureModTime: { |
244 | uint32_t mod_time = data.GetU32(offset_ptr); |
245 | if (mod_time > 0) |
246 | m_mod_time = mod_time; |
247 | } break; |
248 | case eSignatureObjectModTime: { |
249 | uint32_t mod_time = data.GetU32(offset_ptr); |
250 | if (mod_time > 0) |
251 | m_obj_mod_time = mod_time; |
252 | } break; |
253 | case eSignatureEnd: |
254 | // The definition of is valid changed to only be valid if the UUID is |
255 | // valid so make sure that if we attempt to decode an old cache file |
256 | // that we will fail to decode the cache file if the signature isn't |
257 | // considered valid. |
258 | return IsValid(); |
259 | default: |
260 | break; |
261 | } |
262 | } |
263 | return false; |
264 | } |
265 | |
266 | uint32_t ConstStringTable::Add(ConstString s) { |
267 | auto pos = m_string_to_offset.find(Val: s); |
268 | if (pos != m_string_to_offset.end()) |
269 | return pos->second; |
270 | const uint32_t offset = m_next_offset; |
271 | m_strings.push_back(x: s); |
272 | m_string_to_offset[s] = offset; |
273 | m_next_offset += s.GetLength() + 1; |
274 | return offset; |
275 | } |
276 | |
277 | static const llvm::StringRef kStringTableIdentifier("STAB" ); |
278 | |
279 | bool ConstStringTable::Encode(DataEncoder &encoder) { |
280 | // Write an 4 character code into the stream. This will help us when decoding |
281 | // to make sure we find this identifier when decoding the string table to make |
282 | // sure we have the rigth data. It also helps to identify the string table |
283 | // when dumping the hex bytes in a cache file. |
284 | encoder.AppendData(data: kStringTableIdentifier); |
285 | size_t length_offset = encoder.GetByteSize(); |
286 | encoder.AppendU32(value: 0); // Total length of all strings which will be fixed up. |
287 | size_t strtab_offset = encoder.GetByteSize(); |
288 | encoder.AppendU8(value: 0); // Start the string table with an empty string. |
289 | for (auto s: m_strings) { |
290 | // Make sure all of the offsets match up with what we handed out! |
291 | assert(m_string_to_offset.find(s)->second == |
292 | encoder.GetByteSize() - strtab_offset); |
293 | // Append the C string into the encoder |
294 | encoder.AppendCString(data: s.GetStringRef()); |
295 | } |
296 | // Fixup the string table length. |
297 | encoder.PutU32(offset: length_offset, value: encoder.GetByteSize() - strtab_offset); |
298 | return true; |
299 | } |
300 | |
301 | bool StringTableReader::(const lldb_private::DataExtractor &data, |
302 | lldb::offset_t *offset_ptr) { |
303 | llvm::StringRef identifier((const char *)data.GetData(offset_ptr, length: 4), 4); |
304 | if (identifier != kStringTableIdentifier) |
305 | return false; |
306 | const uint32_t length = data.GetU32(offset_ptr); |
307 | // We always have at least one byte for the empty string at offset zero. |
308 | if (length == 0) |
309 | return false; |
310 | const char *bytes = (const char *)data.GetData(offset_ptr, length); |
311 | if (bytes == nullptr) |
312 | return false; |
313 | m_data = llvm::StringRef(bytes, length); |
314 | return true; |
315 | } |
316 | |
317 | llvm::StringRef StringTableReader::Get(uint32_t offset) const { |
318 | if (offset >= m_data.size()) |
319 | return llvm::StringRef(); |
320 | return llvm::StringRef(m_data.data() + offset); |
321 | } |
322 | |
323 | |