Skip to content

Commit b5cf6ba

Browse files
committed
[lldb] Register reflection images with LLDBMemoryReader
1 parent 51a24b2 commit b5cf6ba

File tree

8 files changed

+310
-22
lines changed

8 files changed

+310
-22
lines changed

lldb/include/lldb/Target/Target.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ class TargetProperties : public Properties {
171171

172172
bool GetSwiftCreateModuleContextsInParallel() const;
173173

174+
bool GetSwiftReadMetadataFromFileCache() const;
175+
174176
bool GetEnableAutoImportClangModules() const;
175177

176178
bool GetUseAllCompilerFlags() const;

lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp

Lines changed: 145 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "lldb/Utility/Log.h"
44
#include "lldb/Utility/Logging.h"
55

6+
#include "llvm/Support/MathExtras.h"
7+
68
using namespace lldb;
79
using namespace lldb_private;
810

@@ -134,15 +136,26 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address,
134136
LLDB_LOGV(log, "[MemoryReader] asked to read {0} bytes at address {1:x}",
135137
size, address.getAddressData());
136138

139+
llvm::Optional<Address> maybeAddr =
140+
resolveRemoteAddress(address.getAddressData());
141+
if (!maybeAddr) {
142+
LLDB_LOGV(log, "[MemoryReader] could not resolve address {1:x}",
143+
address.getAddressData());
144+
return false;
145+
}
146+
auto addr = *maybeAddr;
147+
137148
if (size > m_max_read_amount) {
138149
LLDB_LOGV(log, "[MemoryReader] memory read exceeds maximum allowed size");
139150
return false;
140151
}
141-
142152
Target &target(m_process.GetTarget());
143-
Address addr(address.getAddressData());
144153
Status error;
145-
if (size > target.ReadMemory(addr, dest, size, error, true)) {
154+
// We only want to allow the file-cache optimization if we resolved the
155+
// address to section + offset.
156+
const bool force_live_memory =
157+
!readMetadataFromFileCacheEnabled() || !addr.IsSectionOffset();
158+
if (size > target.ReadMemory(addr, dest, size, error, force_live_memory)) {
146159
LLDB_LOGV(log,
147160
"[MemoryReader] memory read returned fewer bytes than asked for");
148161
return false;
@@ -171,11 +184,19 @@ bool LLDBMemoryReader::readString(swift::remote::RemoteAddress address,
171184
std::string &dest) {
172185
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
173186

174-
LLDB_LOGV(log, "[MemoryReader] asked to read string data at address {0:x}",
187+
LLDB_LOGV(log, "[MemoryReader] asked to read string data at address {0x}",
175188
address.getAddressData());
176189

190+
llvm::Optional<Address> maybeAddr =
191+
resolveRemoteAddress(address.getAddressData());
192+
if (!maybeAddr) {
193+
LLDB_LOGV(log, "[MemoryReader] could not resolve address {1:x}",
194+
address.getAddressData());
195+
return false;
196+
}
197+
auto addr = *maybeAddr;
198+
177199
Target &target(m_process.GetTarget());
178-
Address addr(address.getAddressData());
179200
Status error;
180201
target.ReadCStringFromMemory(addr, dest, error);
181202
if (error.Success()) {
@@ -194,11 +215,10 @@ bool LLDBMemoryReader::readString(swift::remote::RemoteAddress address,
194215
LLDB_LOGV(log, "[MemoryReader] memory read returned data: \"{0}\"",
195216
format_string(dest));
196217
return true;
197-
} else {
198-
LLDB_LOGV(log, "[MemoryReader] memory read returned error: {0}",
199-
error.AsCString());
200-
return false;
201218
}
219+
LLDB_LOGV(log, "[MemoryReader] memory read returned error: {0}",
220+
error.AsCString());
221+
return false;
202222
}
203223

204224
void LLDBMemoryReader::pushLocalBuffer(uint64_t local_buffer,
@@ -214,4 +234,120 @@ void LLDBMemoryReader::popLocalBuffer() {
214234
m_local_buffer_size = 0;
215235
}
216236

237+
llvm::Optional<std::pair<uint64_t, uint64_t>>
238+
LLDBMemoryReader::addModuleToAddressMap(ModuleSP module) {
239+
if (!readMetadataFromFileCacheEnabled())
240+
return {};
241+
242+
// The first available address is the mask, since subsequent images are mapped
243+
// in ascending order, all of them will contain this mask.
244+
uint64_t module_start_address = LLDB_FILE_ADDRESS_BIT;
245+
if (!m_range_module_map.empty())
246+
// We map the images contiguously one after the other, all with the tag bit
247+
// set.
248+
// The address that maps the last module is exactly the address the new
249+
// module should start at.
250+
module_start_address = m_range_module_map.back().first;
251+
252+
#ifndef NDEBUG
253+
static std::initializer_list<uint64_t> objc_bits = {
254+
SWIFT_ABI_ARM_IS_OBJC_BIT,
255+
SWIFT_ABI_X86_64_IS_OBJC_BIT,
256+
SWIFT_ABI_ARM64_IS_OBJC_BIT};
257+
258+
for (auto objc_bit : objc_bits)
259+
assert((module_start_address & objc_bit) != objc_bit &&
260+
"LLDB file address bit clashes with an obj-c bit!");
261+
#endif
262+
263+
SectionList *section_list = module->GetObjectFile()->GetSectionList();
264+
265+
auto section_list_size = section_list->GetSize();
266+
if (section_list_size == 0)
267+
return {};
268+
269+
auto last_section =
270+
section_list->GetSectionAtIndex(section_list->GetSize() - 1);
271+
// The virtual file address + the size of last section gives us the total size
272+
// of this image in memory.
273+
uint64_t size = last_section->GetFileAddress() + last_section->GetByteSize();
274+
auto module_end_address = module_start_address + size;
275+
276+
// The address for the next image is the next pointer aligned address
277+
// available after the end of the current image.
278+
uint64_t next_module_start_address = llvm::alignTo(module_end_address, 8);
279+
m_range_module_map.emplace_back(next_module_start_address, module);
280+
return {{module_start_address, module_end_address}};
281+
}
282+
283+
llvm::Optional<Address>
284+
LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const {
285+
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
286+
287+
if (!m_process.GetTarget().GetSwiftReadMetadataFromFileCache())
288+
return Address(address);
289+
290+
// If the address contains our mask, this is an image we registered.
291+
if (!(address & LLDB_FILE_ADDRESS_BIT))
292+
return Address(address);
293+
294+
// Dummy pair with the address we're looking for.
295+
auto comparison_pair = std::make_pair(address, ModuleSP());
296+
297+
// Explicitly compare only the addresses, never the modules in the pairs.
298+
auto pair_iterator = std::lower_bound(
299+
m_range_module_map.begin(), m_range_module_map.end(), comparison_pair,
300+
[](auto &a, auto &b) { return a.first < b.first; });
301+
302+
// If the address is larger than anything we have mapped the address is out
303+
if (pair_iterator == m_range_module_map.end()) {
304+
LLDB_LOG(log,
305+
"[MemoryReader] Address {1:x} is larger than the upper bound "
306+
"address of the mapped in modules",
307+
address);
308+
return {};
309+
}
310+
311+
ModuleSP module = pair_iterator->second;
312+
uint64_t file_address;
313+
if (pair_iterator == m_range_module_map.begin())
314+
// Since this is the first registered module,
315+
// clearing the tag bit will give the virtual file address.
316+
file_address = address & ~LLDB_FILE_ADDRESS_BIT;
317+
else
318+
// The end of the previous section is the start of the current one.
319+
file_address = address - std::prev(pair_iterator)->first;
320+
321+
LLDB_LOGV(log,
322+
"[MemoryReader] Successfully resolved mapped address {1:x} "
323+
"into file address {1:x}",
324+
address, file_address);
325+
auto *object_file = module->GetObjectFile();
326+
if (!object_file)
327+
return {};
328+
329+
Address resolved(file_address, object_file->GetSectionList());
330+
if (!resolved.IsValid()) {
331+
LLDB_LOG(log,
332+
"[MemoryReader] Could not make a real address out of file "
333+
"address {1:x} and object file {}",
334+
file_address, object_file->GetFileSpec().GetFilename());
335+
return {};
336+
}
337+
338+
LLDB_LOGV(log,
339+
"[MemoryReader] Unsuccessfully resolved mapped address {1:x} "
340+
"into file address {1:x}",
341+
address, address);
342+
return resolved;
343+
}
344+
345+
bool LLDBMemoryReader::readMetadataFromFileCacheEnabled() const {
346+
auto &triple = m_process.GetTarget().GetArchitecture().GetTriple();
347+
348+
// 32 doesn't have a flag bit we can reliably use, so reading from filecache
349+
// is disabled on it.
350+
return m_process.GetTarget().GetSwiftReadMetadataFromFileCache() &&
351+
triple.isArch64Bit();
352+
}
217353
} // namespace lldb_private

lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace lldb_private {
1111
class LLDBMemoryReader : public swift::remote::MemoryReader {
1212
public:
1313
LLDBMemoryReader(Process &p, size_t max_read_amount = INT32_MAX)
14-
: m_process(p) {
14+
: m_process(p), m_range_module_map() {
1515
m_max_read_amount = max_read_amount;
1616
}
1717

@@ -31,14 +31,53 @@ class LLDBMemoryReader : public swift::remote::MemoryReader {
3131

3232
void pushLocalBuffer(uint64_t local_buffer, uint64_t local_buffer_size);
3333

34-
void popLocalBuffer();
34+
void popLocalBuffer();
35+
36+
/// Adds the module to the list of modules we're tracking using tagged
37+
/// addresses, so we can read memory from the file cache whenever possible.
38+
/// \return a pair of addresses indicating the start and end of this image in
39+
/// the tagged address space. None on failure.
40+
llvm::Optional<std::pair<uint64_t, uint64_t>>
41+
addModuleToAddressMap(lldb::ModuleSP module);
42+
43+
/// Returns whether the filecache optimization is enabled or not.
44+
bool readMetadataFromFileCacheEnabled() const;
45+
46+
private:
47+
/// Resolves the address by either mapping a tagged address back to an LLDB
48+
/// Address with section + offset, or, in case the address is not tagged,
49+
/// constructing an LLDB address with just the offset.
50+
/// \return an Address with Section + offset if we succesfully converted a tagged
51+
/// address back, an Address with just an offset if the address was not tagged,
52+
/// and None if the address was tagged but we couldn't convert it back to an
53+
/// Address.
54+
llvm::Optional<Address> resolveRemoteAddress(uint64_t address) const;
3555

3656
private:
3757
Process &m_process;
3858
size_t m_max_read_amount;
3959

4060
llvm::Optional<uint64_t> m_local_buffer;
4161
uint64_t m_local_buffer_size = 0;
62+
63+
/// LLDBMemoryReader prefers to read reflection metadata from the
64+
/// binary on disk, which is faster than reading it out of process
65+
/// memory, especially when debugging remotely. To achieve this LLDB
66+
/// registers virtual addresses starting at (0x0 &
67+
/// LLDB_VIRTUAL_ADDRESS_BIT) with ReflectionContext. Sorted by
68+
/// virtual address, m_lldb_virtual_address_map stores each
69+
/// lldb::Module and the first virtual address after the end of that
70+
/// module's virtual address space.
71+
std::vector<std::pair<uint64_t, lldb::ModuleSP>> m_range_module_map;
72+
73+
/// The bit used to tag LLDB's virtual addresses as such. See \c
74+
/// m_range_module_map.
75+
const static uint64_t LLDB_FILE_ADDRESS_BIT = 0x2000000000000000;
76+
static_assert(LLDB_FILE_ADDRESS_BIT & SWIFT_ABI_X86_64_SWIFT_SPARE_BITS_MASK,
77+
"LLDB file address bit not in spare bits mask!");
78+
static_assert(LLDB_FILE_ADDRESS_BIT & SWIFT_ABI_ARM64_SWIFT_SPARE_BITS_MASK,
79+
"LLDB file address bit not in spare bits mask!");
80+
4281
};
4382
} // namespace lldb_private
4483
#endif

0 commit comments

Comments
 (0)