Skip to content

Commit bb7be81

Browse files
jeffreytan81George Hu
authored andcommitted
Support thread local storage in module list dyld plugin
Summary: llvm#67470 added TLS support for live debugging and coredump debugging with posix dyld. This diff adds TLS support for module list dyld for coredump debugging. To support TLS we have to: * Capture main executable from `prpsinfo.pr_fname` so that use it to successfully resolve m_rendezvous. * Implement `DynamicLoaderDumpWithModuleList::GetThreadLocalData()` similar to posix dyld Test Plan: Can examine TLS variable in coredump without specifying the main executable. Reviewers: gclayton, wanyi, hyubo, #lldb_team Reviewed By: wanyi Subscribers: #lldb_team Differential Revision: https://phabricator.intern.facebook.com/D49889758 Tasks: T161060329
1 parent b73389a commit bb7be81

File tree

5 files changed

+117
-14
lines changed

5 files changed

+117
-14
lines changed

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

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ void DynamicLoaderDumpWithModuleList::LoadAllModules(
118118
LoadModuleCallback callback) {
119119

120120
if (m_rendezvous.Resolve()) {
121+
// The rendezvous class doesn't enumerate the main module, so track that
122+
// ourselves here.
123+
ModuleSP executable = GetTargetExecutable();
124+
if (executable)
125+
m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
126+
121127
DYLDRendezvous::iterator I;
122128
DYLDRendezvous::iterator E;
123129
for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) {
@@ -127,7 +133,7 @@ void DynamicLoaderDumpWithModuleList::LoadAllModules(
127133
GetModuleInfo(I->base_addr);
128134
if (mod_info_opt.has_value())
129135
(*mod_info_opt).get_size(module_size);
130-
callback(I->file_spec.GetPath(), I->base_addr, module_size);
136+
callback(I->file_spec.GetPath(), I->base_addr, module_size, I->link_addr);
131137
}
132138

133139
DetectModuleListMismatch();
@@ -159,7 +165,7 @@ void DynamicLoaderDumpWithModuleList::LoadAllModules(
159165
!mod_info.get_size(module_size) || !ShouldLoadModule(name))
160166
continue;
161167

162-
callback(SanitizeName(name), base_addr, module_size);
168+
callback(SanitizeName(name), base_addr, module_size, /*link_map_addr=*/0);
163169
}
164170
}
165171
}
@@ -196,12 +202,11 @@ void DynamicLoaderDumpWithModuleList::DidAttach() {
196202

197203
ModuleList module_list;
198204
LoadAllModules([&](const std::string &name, addr_t base_addr,
199-
addr_t module_size) {
205+
addr_t module_size, addr_t link_map_addr) {
200206
// vdso module has already been loaded.
201207
if (base_addr == m_vdso_base)
202208
return;
203209

204-
addr_t link_map_addr = 0;
205210
FileSpec file(name, m_process->GetTarget().GetArchitecture().GetTriple());
206211
const bool base_addr_is_offset = false;
207212
ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress(
@@ -224,6 +229,7 @@ void DynamicLoaderDumpWithModuleList::DidAttach() {
224229
base_addr_is_offset);
225230
m_process->GetTarget().GetImages().Append(module_sp, /*notify*/ true);
226231
}
232+
m_loaded_modules[module_sp] = link_map_addr;
227233
});
228234

229235
m_process->GetTarget().ModulesDidLoad(module_list);
@@ -260,3 +266,82 @@ void DynamicLoaderDumpWithModuleList::LoadVDSO() {
260266
lldb_private::Status DynamicLoaderDumpWithModuleList::CanLoadImage() {
261267
return Status();
262268
}
269+
270+
// TODO: refactor and merge this implementation with
271+
// DynamicLoaderPOSIXDYLD::GetThreadLocalData
272+
lldb::addr_t DynamicLoaderDumpWithModuleList::GetThreadLocalData(
273+
const lldb::ModuleSP module_sp, const lldb::ThreadSP thread,
274+
lldb::addr_t tls_file_addr) {
275+
Log *log = GetLog(LLDBLog::DynamicLoader);
276+
auto it = m_loaded_modules.find(module_sp);
277+
if (it == m_loaded_modules.end()) {
278+
LLDB_LOGF(
279+
log, "GetThreadLocalData error: module(%s) not found in loaded modules",
280+
module_sp->GetObjectName().AsCString());
281+
return LLDB_INVALID_ADDRESS;
282+
}
283+
284+
addr_t link_map = it->second;
285+
if (link_map == LLDB_INVALID_ADDRESS || link_map == 0) {
286+
LLDB_LOGF(log,
287+
"GetThreadLocalData error: invalid link map address=0x%" PRIx64,
288+
link_map);
289+
return LLDB_INVALID_ADDRESS;
290+
}
291+
292+
const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo();
293+
if (!metadata.valid) {
294+
LLDB_LOGF(log,
295+
"GetThreadLocalData error: fail to read thread info metadata");
296+
return LLDB_INVALID_ADDRESS;
297+
}
298+
299+
LLDB_LOGF(log,
300+
"GetThreadLocalData info: link_map=0x%" PRIx64
301+
", thread info metadata: "
302+
"modid_offset=0x%" PRIx32 ", dtv_offset=0x%" PRIx32
303+
", tls_offset=0x%" PRIx32 ", dtv_slot_size=%" PRIx32 "\n",
304+
link_map, metadata.modid_offset, metadata.dtv_offset,
305+
metadata.tls_offset, metadata.dtv_slot_size);
306+
307+
// Get the thread pointer.
308+
addr_t tp = thread->GetThreadPointer();
309+
if (tp == LLDB_INVALID_ADDRESS) {
310+
LLDB_LOGF(log, "GetThreadLocalData error: fail to read thread pointer");
311+
return LLDB_INVALID_ADDRESS;
312+
}
313+
314+
// Find the module's modid.
315+
int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit
316+
int64_t modid = ReadUnsignedIntWithSizeInBytes(
317+
link_map + metadata.modid_offset, modid_size);
318+
if (modid == -1) {
319+
LLDB_LOGF(log, "GetThreadLocalData error: fail to read modid");
320+
return LLDB_INVALID_ADDRESS;
321+
}
322+
323+
// Lookup the DTV structure for this thread.
324+
addr_t dtv_ptr = tp + metadata.dtv_offset;
325+
addr_t dtv = ReadPointer(dtv_ptr);
326+
if (dtv == LLDB_INVALID_ADDRESS) {
327+
LLDB_LOGF(log, "GetThreadLocalData error: fail to read dtv");
328+
return LLDB_INVALID_ADDRESS;
329+
}
330+
331+
// Find the TLS block for this module.
332+
addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid;
333+
addr_t tls_block = ReadPointer(dtv_slot + metadata.tls_offset);
334+
335+
LLDB_LOGF(log,
336+
"DynamicLoaderDumpWithModuleList::Performed TLS lookup: "
337+
"module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64
338+
", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n",
339+
module_sp->GetObjectName().AsCString(""), link_map, tp,
340+
(int64_t)modid, tls_block);
341+
342+
if (tls_block == LLDB_INVALID_ADDRESS) {
343+
LLDB_LOGF(log, "GetThreadLocalData error: fail to read tls_block");
344+
return LLDB_INVALID_ADDRESS;
345+
} else
346+
return tls_block + tls_file_addr;
347+
}

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,7 @@ class DynamicLoaderDumpWithModuleList : public lldb_private::DynamicLoader {
5959

6060
lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module,
6161
const lldb::ThreadSP thread,
62-
lldb::addr_t tls_file_addr) override {
63-
// TODO: how to implement this?
64-
return LLDB_INVALID_ADDRESS;
65-
}
62+
lldb::addr_t tls_file_addr) override;
6663

6764
// PluginInterface protocol
6865
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
@@ -73,7 +70,8 @@ class DynamicLoaderDumpWithModuleList : public lldb_private::DynamicLoader {
7370
const DynamicLoaderDumpWithModuleList &
7471
operator=(const DynamicLoaderDumpWithModuleList &) = delete;
7572

76-
typedef std::function<void(const std::string &, lldb::addr_t, lldb::addr_t)>
73+
typedef std::function<void(const std::string &, lldb::addr_t, lldb::addr_t,
74+
lldb::addr_t)>
7775
LoadModuleCallback;
7876
void LoadAllModules(LoadModuleCallback callback);
7977

@@ -107,6 +105,12 @@ class DynamicLoaderDumpWithModuleList : public lldb_private::DynamicLoader {
107105
/// It can be used to cross check with posix r_debug link map.
108106
std::unordered_map<lldb::addr_t, const LoadedModuleInfoList::LoadedModuleInfo>
109107
m_module_addr_to_info_map;
108+
109+
// TODO: merge with DynamicLoaderPOSIXDYLD::m_loaded_modules
110+
// The same as DynamicLoaderPOSIXDYLD::m_loaded_modules to track all loaded
111+
// module's link map addresses. It is used by TLS to get DTV data structure.
112+
std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
113+
m_loaded_modules;
110114
};
111115

112116
#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MODULELIST_DYLD_DYNAMICLOADERDUMPWITHMODULELIST_H

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,12 +259,23 @@ Status ProcessElfCore::DoLoadCore() {
259259
// the main executable using data we found in the core file notes.
260260
lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
261261
if (!exe_module_sp) {
262-
// The first entry in the NT_FILE might be our executable
263262
if (!m_nt_file_entries.empty()) {
263+
// The first entry in the NT_FILE might be our executable
264+
llvm::StringRef executable_path = m_nt_file_entries[0].path;
265+
lldb_private::UUID executable_uuid = m_nt_file_entries[0].uuid;
266+
// Prefer the NT_FILE entry matching m_executable_name as main executable.
267+
for (const NT_FILE_Entry &file_entry : m_nt_file_entries)
268+
if (llvm::StringRef(file_entry.path)
269+
.ends_with("/" + m_executable_name)) {
270+
executable_path = file_entry.path;
271+
executable_uuid = file_entry.uuid;
272+
break;
273+
}
274+
264275
ModuleSpec exe_module_spec;
265276
exe_module_spec.GetArchitecture() = arch;
266-
exe_module_spec.GetUUID() = m_nt_file_entries[0].uuid;
267-
exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path,
277+
exe_module_spec.GetUUID() = executable_uuid;
278+
exe_module_spec.GetFileSpec().SetFile(executable_path,
268279
FileSpec::Style::native);
269280
if (exe_module_spec.GetFileSpec()) {
270281
exe_module_sp =
@@ -1060,6 +1071,7 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) {
10601071
prpsinfo.pr_fname,
10611072
strnlen(prpsinfo.pr_fname, sizeof(prpsinfo.pr_fname)));
10621073
SetID(prpsinfo.pr_pid);
1074+
m_executable_name = prpsinfo.pr_fname;
10631075
break;
10641076
}
10651077
case ELF::NT_SIGINFO: {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
153153
// Memory tag ranges found in the core
154154
VMRangeToFileOffset m_core_tag_ranges;
155155

156+
std::string m_executable_name;
157+
156158
// NT_FILE entries found from the NOTE segment
157159
std::vector<NT_FILE_Entry> m_nt_file_entries;
158160

lldb/source/Plugins/Process/elf-core/ThreadElfCore.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ struct ELFLinuxPrPsInfo {
105105
int32_t pr_ppid;
106106
int32_t pr_pgrp;
107107
int32_t pr_sid;
108-
char pr_fname[16];
109-
char pr_psargs[80];
108+
char pr_fname[16]; // Filename of executable
109+
char pr_psargs[80]; // Initial part of arg list
110110

111111
ELFLinuxPrPsInfo();
112112

0 commit comments

Comments
 (0)