Skip to content

Commit 9a06a86

Browse files
jeffreytan81kusmour
authored andcommitted
Improve ProcessElfCore::GetLoadedModuleList() dealing with duplicate NT_FILE ranges
Summary: Currently ProcessElfCore::GetLoadedModuleList() assumes NT_FILE entries are mostly continuous, and if there are discontinuous ranges, it uses lower start address range base address and brutally merge all ranges. However, during real world testing, I discovered MySQL team's coredump has discontinuous ranges for many modules and some module's later ranges are the correct one. We have two options here: 1. Keep all duplicate ranges and create duplicate modules 2. Rate the ranges and select a best one. Since lldb does not support duplicate modules I chose option #2 above: * Merge continuous entries into one range. * Rate among duplicate ranges and select a "better" one. * "Better" range is defined to have more NT_FILE entry count; and have larger size if entry count equals. MySQL's coredump has zero mismatch modules after this change. Test Plan: Tested with MySQL's coredump. Reviewers: wanyi, hyubo, #lldb_team Reviewed By: wanyi Subscribers: generatedunixname89002005328444, #lldb_team Differential Revision: https://phabricator.intern.facebook.com/D45869549 [Easy] handling corner cases of NT_FILE in ProcessElfCore::GetLoadedModuleList Summary: This diff handles the corner cases of the algorithm added in D45869549: 1. When m_nt_file_entries is empty, we should simply return without adding any range 2. The first entry should simply record Test Plan: Found a coredumper triggering the corner cases and can be debugged fine. Reviewers: wanyi, hyubo, #lldb_team Reviewed By: wanyi Subscribers: #lldb_team Differential Revision: https://phabricator.intern.facebook.com/D46076584
1 parent e23c0ed commit 9a06a86

File tree

2 files changed

+96
-16
lines changed

2 files changed

+96
-16
lines changed

lldb/source/Plugins/DynamicLoader/ModuleList-DYLD/DynamicLoaderDumpWithModuleList.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ void DynamicLoaderDumpWithModuleList::DidAttach() {
192192
ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress(
193193
file, link_map_addr, base_addr, base_addr_is_offset);
194194
if (module_sp.get()) {
195-
LLDB_LOG(log, "LoadAllCurrentModules loading module: {0}", name.c_str());
195+
LLDB_LOGF(log, "LoadAllCurrentModules loading module at 0x%lX: %s",
196+
base_addr, name.c_str());
196197
module_list.Append(module_sp);
197198
} else {
198199
LLDB_LOGF(

lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp

Lines changed: 94 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -302,29 +302,108 @@ lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
302302

303303
llvm::Expected<lldb_private::LoadedModuleInfoList>
304304
ProcessElfCore::GetLoadedModuleList() {
305-
if (m_module_info_list.m_list.empty()) {
306-
std::unordered_map<std::string, std::pair<lldb::addr_t, lldb::addr_t>>
305+
if (m_module_info_list.m_list.empty() && !m_nt_file_entries.empty()) {
306+
307+
// Map from module_path => <range_start, range_end, entry_count>
308+
// Since lldb does not support duplicate modules 'entry_count' field is
309+
// required to heuristically rate amoung duplicate ranges.
310+
std::unordered_map<std::string,
311+
std::tuple<lldb::addr_t, lldb::addr_t, uint8_t>>
307312
module_range_map;
313+
// Helper function to add a new module range.
314+
// It takes care of duplication module ranges.
315+
auto add_module_range =
316+
[&module_range_map](const std::string &module_path, lldb::addr_t start,
317+
lldb::addr_t end, uint32_t entry_count) {
318+
// To add a range, we check any duplication ranges and only
319+
// store a "better" one. See below for the definition of "better".
320+
auto module_iter = module_range_map.find(module_path);
321+
if (module_iter == module_range_map.end())
322+
// Unique range, simply add it.
323+
module_range_map[module_path] = {start, end, entry_count};
324+
else {
325+
// Found a duplication let's check which is better.
326+
//
327+
// A range is considered better if:
328+
// 1. if the range has more entries, or
329+
// 2. the same number of range entries but larger in range size
330+
331+
auto &existing_module_range = module_iter->second;
332+
auto &existing_range_start = std::get<0>(existing_module_range);
333+
auto &existing_range_end = std::get<1>(existing_module_range);
334+
auto &existing_entry_count = std::get<2>(existing_module_range);
335+
336+
assert(end > start);
337+
assert(existing_range_end > existing_range_start);
338+
if (entry_count > existing_entry_count ||
339+
(entry_count == existing_entry_count &&
340+
end - start > existing_range_end - existing_range_start)) {
341+
existing_range_start = start;
342+
existing_range_end = end;
343+
existing_entry_count = entry_count;
344+
}
345+
}
346+
};
347+
348+
// Range adding algorithm works by checking continuous file entries and
349+
// merge them into large range. To do that each for loop merges curent file
350+
// entry with previous one if they have the same file path; otherwise we
351+
// know previous range is done merging and simply add it. The last range is
352+
// always added after the for loop.
353+
std::string last_entry_path;
354+
lldb::addr_t last_module_start = LLDB_INVALID_ADDRESS, last_module_end = 0;
355+
uint32_t entry_count = 1;
308356
for (const NT_FILE_Entry &file_entry : m_nt_file_entries) {
309-
std::string module_path = file_entry.path.GetCString();
310-
auto module_iter = module_range_map.find(module_path);
311-
if (module_iter == module_range_map.end() ||
312-
module_iter->second.first > file_entry.start)
313-
module_range_map[module_path] =
314-
std::make_pair(file_entry.start, file_entry.end - file_entry.start);
315-
else {
316-
// Expand module's range to include later sections.
317-
auto &module_range = module_range_map[module_path];
318-
assert(file_entry.end >= module_range.first);
319-
module_range.second = file_entry.end - module_range.first;
357+
if (file_entry.start <= file_entry.file_ofs) {
358+
m_core_module_sp->ReportWarning(
359+
"Found invalid NT_FILE entry with start(0x%lx) <= file_ofs(0x%lx)",
360+
file_entry.start, file_entry.file_ofs);
361+
continue;
320362
}
363+
if (file_entry.end <= file_entry.start) {
364+
m_core_module_sp->ReportWarning(
365+
"Found invalid NT_FILE entry with end(0x%lx) <= start(0x%lx)",
366+
file_entry.end, file_entry.start);
367+
continue;
368+
}
369+
370+
// Merge continuous entries or add last merged range.
371+
auto new_module_start = file_entry.start - file_entry.file_ofs;
372+
if (file_entry.path == last_entry_path) {
373+
// continuous entries, merge into a larger range.
374+
last_module_start = std::min(last_module_start, new_module_start);
375+
last_module_end = std::max(last_module_end, file_entry.end);
376+
++entry_count;
377+
} else if (last_module_start == LLDB_INVALID_ADDRESS ||
378+
last_module_end == 0) {
379+
// First entry simply record it.
380+
last_module_start = new_module_start;
381+
last_module_end = file_entry.end;
382+
} else {
383+
// Encounter a new range starts, let's add last merged range.
384+
add_module_range(last_entry_path, last_module_start, last_module_end,
385+
entry_count);
386+
387+
last_module_start = new_module_start;
388+
last_module_end = file_entry.end;
389+
entry_count = 1;
390+
}
391+
last_entry_path = file_entry.path;
321392
}
393+
// Still have to add the last range.
394+
add_module_range(last_entry_path, last_module_start, last_module_end,
395+
entry_count);
322396

323397
for (const auto &module_range_entry : module_range_map) {
324398
LoadedModuleInfoList::LoadedModuleInfo module;
399+
400+
lldb::addr_t start = std::get<0>(module_range_entry.second);
401+
lldb::addr_t end = std::get<1>(module_range_entry.second);
402+
325403
module.set_name(module_range_entry.first);
326-
module.set_base(module_range_entry.second.first);
327-
module.set_size(module_range_entry.second.second);
404+
module.set_base(start);
405+
assert(end >= start);
406+
module.set_size(end - start);
328407
m_module_info_list.add(module);
329408
}
330409
}

0 commit comments

Comments
 (0)