llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Greg Clayton (clayborg)

<details>
<summary>Changes</summary>

This patch enables ELF core files to be loaded and still show executables and 
shared libraries. Functionality includes:
- Load executable and shared libraries from memory if ELF headers are available
- Create placeholder for missing shared libraries and executable. Previously 
you just wouldn't get anything in the "image list" if no executable was 
provided.

---
Full diff: https://github.com/llvm/llvm-project/pull/177289.diff


6 Files Affected:

- (modified) lldb/source/Core/DynamicLoader.cpp (+9-5) 
- (modified) 
lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp (+15-3) 
- (modified) lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp (+33-4) 
- (modified) lldb/source/Plugins/Process/elf-core/ProcessElfCore.h (+2-2) 
- (modified) lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py 
(+68) 
- (added) 
lldb/test/API/functionalities/postmortem/elf-core/linux-x86_64-no-exe.core () 


``````````diff
diff --git a/lldb/source/Core/DynamicLoader.cpp 
b/lldb/source/Core/DynamicLoader.cpp
index 31d277bc19681..563a81fb8239b 100644
--- a/lldb/source/Core/DynamicLoader.cpp
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -176,13 +176,17 @@ ModuleSP DynamicLoader::LoadModuleAtAddress(const 
FileSpec &file,
                                             addr_t link_map_addr,
                                             addr_t base_addr,
                                             bool base_addr_is_offset) {
-  if (ModuleSP module_sp = FindModuleViaTarget(file)) {
+  ModuleSP module_sp = FindModuleViaTarget(file);
+  // We have a core file, try to load the image from memory if we didn't find
+  // the module.
+  if (!module_sp && !m_process->IsLiveDebugSession()) {
+    module_sp = m_process->ReadModuleFromMemory(file, base_addr);
+    m_process->GetTarget().GetImages().AppendIfNeeded(module_sp, false);
+  }
+  if (module_sp)
     UpdateLoadedSections(module_sp, link_map_addr, base_addr,
                          base_addr_is_offset);
-    return module_sp;
-  }
-
-  return nullptr;
+  return module_sp;
 }
 
 static ModuleSP ReadUnnamedMemoryModule(Process *process, addr_t addr,
diff --git 
a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp 
b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 3605e7b2c6960..1a0ae9378fd80 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -27,6 +27,7 @@
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/ProcessInfo.h"
 #include "llvm/Support/ThreadPool.h"
+#include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h"
 
 #include <memory>
 #include <optional>
@@ -698,22 +699,33 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
   ModuleSP executable = GetTargetExecutable();
   SetLoadedModule(executable, m_rendezvous.GetLinkMapAddress());
 
+  Target &target = m_process->GetTarget();
   std::vector<FileSpec> module_names;
   for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
     module_names.push_back(I->file_spec);
   m_process->PrefetchModuleSpecs(
-      module_names, m_process->GetTarget().GetArchitecture().GetTriple());
+      module_names, target.GetArchitecture().GetTriple());
 
-  auto load_module_fn = [this, &module_list,
+  auto load_module_fn = [this, &module_list, &target,
                          &log](const DYLDRendezvous::SOEntry &so_entry) {
     ModuleSP module_sp = LoadModuleAtAddress(
         so_entry.file_spec, so_entry.link_addr, so_entry.base_addr, true);
+    if (!module_sp && !m_process->IsLiveDebugSession()) {
+      ModuleSpec module_spec(so_entry.file_spec, target.GetArchitecture());
+      if (UUID uuid = m_process->FindModuleUUID(so_entry.file_spec.GetPath()))
+        module_spec.GetUUID() = uuid;
+      module_sp = Module::CreateModuleFromObjectFile<ObjectFilePlaceholder>(
+          module_spec, so_entry.base_addr, 512);
+      bool load_addr_changed = false;
+      target.GetImages().Append(module_sp, false);
+      module_sp->SetLoadAddress(target, so_entry.base_addr,
+                                false, load_addr_changed);
+    }
     if (module_sp.get()) {
       LLDB_LOG(log, "LoadAllCurrentModules loading module: {0}",
                so_entry.file_spec.GetFilename());
       module_list.Append(module_sp);
     } else {
-      Log *log = GetLog(LLDBLog::DynamicLoader);
       LLDB_LOGF(
           log,
           "DynamicLoaderPOSIXDYLD::%s failed loading module %s at 0x%" PRIx64,
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp 
b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index f8e33eac614a4..5e4c67af059db 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -259,7 +259,7 @@ Status ProcessElfCore::DoLoadCore() {
   lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
   if (!exe_module_sp) {
     if (!m_nt_file_entries.empty()) {
-      llvm::StringRef executable_path = GetMainExecutablePath();
+      std::string executable_path = GetMainExecutablePath();
       ModuleSpec exe_module_spec;
       exe_module_spec.GetArchitecture() = arch;
       exe_module_spec.GetUUID() = FindModuleUUID(executable_path);
@@ -268,6 +268,24 @@ Status ProcessElfCore::DoLoadCore() {
       if (exe_module_spec.GetFileSpec()) {
         exe_module_sp =
             GetTarget().GetOrCreateModule(exe_module_spec, true /* notify */);
+        if (!exe_module_sp) {
+          // Create an ELF file from memory for the main executable. The 
dynamic
+          // loader requires the main executable so that it can extract the
+          // DT_DEBUG key/value pair from the dynamic section and get the list
+          // of shared libraries.
+          std::optional<lldb::addr_t> exe_header_addr;
+
+          // We need to find its load address
+          for (const NT_FILE_Entry &file_entry : m_nt_file_entries) {
+            if (file_entry.path == executable_path) {
+              exe_header_addr = file_entry.start;
+              break;
+            }
+          }
+          if (exe_header_addr.has_value())
+            exe_module_sp = ReadModuleFromMemory(exe_module_spec.GetFileSpec(),
+                                                 *exe_header_addr);
+        }
         if (exe_module_sp)
           GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo);
       }
@@ -293,12 +311,23 @@ void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
   }
 }
 
-llvm::StringRef ProcessElfCore::GetMainExecutablePath() {
+std::string ProcessElfCore::GetMainExecutablePath() {
+  // Always try to read the program name from core file memory first via the
+  // AUXV_AT_EXECFN entry. This value is the address of a null terminated C
+  // string that contains the program path.
+  AuxVector aux_vector(m_auxv);
+  std::string execfn_str;
+  if (auto execfn = aux_vector.GetAuxValue(AuxVector::AUXV_AT_EXECFN)) {
+    Status error;
+    if (ReadCStringFromMemory(*execfn, execfn_str, error))
+      return execfn_str;
+  }
+
   if (m_nt_file_entries.empty())
-    return "";
+    return {};
 
   // The first entry in the NT_FILE might be our executable
-  llvm::StringRef executable_path = m_nt_file_entries[0].path;
+  std::string executable_path = m_nt_file_entries[0].path;
   // Prefer the NT_FILE entry matching m_executable_name as main executable.
   for (const NT_FILE_Entry &file_entry : m_nt_file_entries)
     if (llvm::StringRef(file_entry.path).ends_with("/" + m_executable_name)) {
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h 
b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index 576c6858477a6..7eda33be8634c 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -168,8 +168,8 @@ class ProcessElfCore : public 
lldb_private::PostMortemProcess {
 
   lldb_private::UUID FindModuleUUID(const llvm::StringRef path) override;
 
-  // Returns the main executable path
-  llvm::StringRef GetMainExecutablePath();
+  // Returns the main executable path.
+  std::string GetMainExecutablePath();
 
   // Returns the value of certain type of note of a given start address
   lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address);
diff --git a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py 
b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
index e9403b56ae195..84c20f4c5a4e1 100644
--- a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
+++ b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
@@ -1042,6 +1042,74 @@ def test_read_only_cstring(self):
         cstr = var.GetSummary()
         self.assertEqual(cstr, '"_start"')
 
+    @skipIfLLVMTargetMissing("X86")
+    @skipIfWindows
+    def test_linux_no_exe(self):
+        """
+        Test that we are able to get the shared library list when loading a
+        linux core file without an executable. This tests LLDB's ability to
+        create memory object files when the ELF header is available for the
+        binary in the shared library list, and to create place holder object
+        files for any files we weren't able to locate or load from memory. It
+        also tests the dynamic loader's ability to find the list of shared
+        libraries from the PT_DYNAMIC section's DT_DEBUG entry. The core file
+        used in this test has the ELF header for the main executable 
"elf-crash"
+        and for "/lib64/libm.so.6". This test will verify that all shared
+        libraries are available. The "image list" output should look like:
+
+        (lldb) image list
+        [  0] 7BCC1101 0x000055bb04288000 /data/users/gclayton/args/elf-crash 
(0x000055bb04288000)
+        [  1]                                      0x00007f27db200000 
/lib64/libstdc++.so.6
+        [  2] AF275675-4671-8B49-24C8-A9A657D74115-C80DEE65 0x00007f27db51b000 
/lib64/libm.so.6 (0x00007f27db51b000)
+        [  3]                                      0x00007f27db4fe000 
/lib64/libgcc_s.so.1
+        [  4]                                      0x00007f27dae00000 
/lib64/libc.so.6
+        [  5]                                      0x00007f27db606000 
/lib64/ld-linux-x86-64.so.2
+        """
+        target = self.dbg.CreateTarget(None)
+        process = target.LoadCore("linux-x86_64-no-exe.core")
+        self.assertTrue(process, PROCESS_IS_VALID)
+        num_modules = target.GetNumModules()
+        self.assertEqual(num_modules, 6)
+
+        m = target.module["/data/users/gclayton/args/elf-crash"]
+        self.assertTrue(m.IsValid())
+        self.assertEqual(m.GetObjectFileHeaderAddress().GetLoadAddress(target),
+                         0x000055bb04288000)
+        self.assertEqual(m.GetUUIDString(), "7BCC1101")
+
+        m = target.module["/lib64/libstdc++.so.6"]
+        self.assertTrue(m.IsValid())
+        self.assertEqual(m.GetObjectFileHeaderAddress().GetLoadAddress(target),
+                         0x00007f27db200000)
+        self.assertEqual(m.GetUUIDString(), None)
+
+        m = target.module["/lib64/libm.so.6"]
+        self.assertTrue(m.IsValid())
+        self.assertEqual(m.GetObjectFileHeaderAddress().GetLoadAddress(target),
+                         0x00007f27db51b000)
+        self.assertEqual(m.GetUUIDString(),
+                         "AF275675-4671-8B49-24C8-A9A657D74115-C80DEE65")
+
+        m = target.module["/lib64/libgcc_s.so.1"]
+        self.assertTrue(m.IsValid())
+        self.assertEqual(m.GetObjectFileHeaderAddress().GetLoadAddress(target),
+                         0x00007f27db4fe000)
+        self.assertEqual(m.GetUUIDString(), None)
+
+        m = target.module["/lib64/libc.so.6"]
+        self.assertTrue(m.IsValid())
+        self.assertEqual(m.GetObjectFileHeaderAddress().GetLoadAddress(target),
+                         0x00007f27dae00000)
+        self.assertEqual(m.GetUUIDString(), None)
+
+        m = target.module["/lib64/ld-linux-x86-64.so.2"]
+        self.assertTrue(m.IsValid())
+        self.assertEqual(m.GetObjectFileHeaderAddress().GetLoadAddress(target),
+                         0x00007f27db606000)
+        self.assertEqual(m.GetUUIDString(), None)
+
+        self.dbg.DeleteTarget(target)
+
     def check_memory_regions(self, process, region_count):
         region_list = process.GetMemoryRegions()
         self.assertEqual(region_list.GetSize(), region_count)
diff --git 
a/lldb/test/API/functionalities/postmortem/elf-core/linux-x86_64-no-exe.core 
b/lldb/test/API/functionalities/postmortem/elf-core/linux-x86_64-no-exe.core
new file mode 100644
index 0000000000000..74e84b0631033
Binary files /dev/null and 
b/lldb/test/API/functionalities/postmortem/elf-core/linux-x86_64-no-exe.core 
differ

``````````

</details>


https://github.com/llvm/llvm-project/pull/177289
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to