https://github.com/rchamala created 
https://github.com/llvm/llvm-project/pull/127153

Current state in scripted process expects [_all the 
modules_](https://github.com/llvm/llvm-project/blob/912b154f3a3f8c3cebf5cc5731fd8b0749762da5/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp#L498)
 passed into "get_loaded_images" to load successfully else none of them load. 
Even if a module loads fine, [but has already been 
appended](https://github.com/llvm/llvm-project/blob/912b154f3a3f8c3cebf5cc5731fd8b0749762da5/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp#L495)
 it still fails. This is restrictive and does not help our usecase. 

**Usecase**: We have a parent scripted process using coredump + tombstone. 

1) Scripted process uses child elf-core process to read memory dump

2) Uses tombstones to pass thread names and modules.

We do not know at load time, whether the modules will be successfully 
downloaded. We use [python module 
callbacks](https://github.com/llvm/llvm-project/blob/a57e58dbfaae0e86eb5cafeddf8b598f14b96e36/lldb/source/Target/Platform.cpp#L1593)
 to download a module from symbol server at LLDB load time. If one of the 
symbol is not found from the list specified in tombstone, none of the modules 
load in scripted process.

**Solution**: Pass in a custom boolean option arg for every module from python 
scripted process plugin which will indicate whether to ignore the module load 
error. This will provide the flexibility to user for loading the successfully 
fetched modules into target while ignoring the failed ones

>From a4fdb2d54e76aefb771fe8ad8399494bb5fa8b70 Mon Sep 17 00:00:00 2001
From: rchamala <racha...@fb.com>
Date: Thu, 13 Feb 2025 15:00:37 -0800
Subject: [PATCH] Allow option to ignore module load errors in ScriptedProcess

---
 .../Process/scripted/ScriptedProcess.cpp      | 39 ++++++++----
 .../TestStackCoreScriptedProcess.py           | 15 ++++-
 .../stack_core_scripted_process.py            | 60 ++++++++++++++-----
 3 files changed, 85 insertions(+), 29 deletions(-)

diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp 
b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
index d2111ce877ce5..79d0bc51bc18c 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -165,7 +165,7 @@ Status ScriptedProcess::DoLoadCore() {
 Status ScriptedProcess::DoLaunch(Module *exe_module,
                                  ProcessLaunchInfo &launch_info) {
   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", 
__FUNCTION__);
-  
+
   /* MARK: This doesn't reflect how lldb actually launches a process.
            In reality, it attaches to debugserver, then resume the process.
            That's not true in all cases.  If debugserver is remote, lldb
@@ -422,9 +422,11 @@ bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo 
&info) {
 lldb_private::StructuredData::ObjectSP
 ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
   Status error;
-  auto error_with_message = [&error](llvm::StringRef message) {
-    return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
-                                                     message.data(), error);
+  auto handle_error_with_message = [&error](llvm::StringRef message,
+                                            bool ignore_error) {
+    ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
+                                              message.data(), error);
+    return ignore_error;
   };
 
   StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages();
@@ -436,12 +438,13 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
   ModuleList module_list;
   Target &target = GetTarget();
 
-  auto reload_image = [&target, &module_list, &error_with_message](
+  auto reload_image = [&target, &module_list, &handle_error_with_message](
                           StructuredData::Object *obj) -> bool {
     StructuredData::Dictionary *dict = obj->GetAsDictionary();
 
     if (!dict)
-      return error_with_message("Couldn't cast image object into dictionary.");
+      return handle_error_with_message(
+          "Couldn't cast image object into dictionary.", false);
 
     ModuleSpec module_spec;
     llvm::StringRef value;
@@ -449,9 +452,11 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
     bool has_path = dict->HasKey("path");
     bool has_uuid = dict->HasKey("uuid");
     if (!has_path && !has_uuid)
-      return error_with_message("Dictionary should have key 'path' or 'uuid'");
+      return handle_error_with_message(
+          "Dictionary should have key 'path' or 'uuid'", false);
     if (!dict->HasKey("load_addr"))
-      return error_with_message("Dictionary is missing key 'load_addr'");
+      return handle_error_with_message("Dictionary is missing key 'load_addr'",
+                                       false);
 
     if (has_path) {
       dict->GetValueForKeyAsString("path", value);
@@ -467,16 +472,21 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
     ModuleSP module_sp =
         target.GetOrCreateModule(module_spec, true /* notify */);
 
+    bool ignore_module_load_error = false;
+    dict->GetValueForKeyAsBoolean("ignore_module_load_error",
+                                  ignore_module_load_error);
     if (!module_sp)
-      return error_with_message("Couldn't create or get module.");
+      return handle_error_with_message("Couldn't create or get module.",
+                                       ignore_module_load_error);
 
     lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
     lldb::offset_t slide = LLDB_INVALID_OFFSET;
     dict->GetValueForKeyAsInteger("load_addr", load_addr);
     dict->GetValueForKeyAsInteger("slide", slide);
     if (load_addr == LLDB_INVALID_ADDRESS)
-      return error_with_message(
-          "Couldn't get valid load address or slide offset.");
+      return handle_error_with_message(
+          "Couldn't get valid load address or slide offset.",
+          ignore_module_load_error);
 
     if (slide != LLDB_INVALID_OFFSET)
       load_addr += slide;
@@ -486,13 +496,16 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
                               changed);
 
     if (!changed && !module_sp->GetObjectFile())
-      return error_with_message("Couldn't set the load address for module.");
+      return handle_error_with_message(
+          "Couldn't set the load address for module.",
+          ignore_module_load_error);
 
     dict->GetValueForKeyAsString("path", value);
     FileSpec objfile(value);
     module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());
 
-    return module_list.AppendIfNeeded(module_sp);
+    return ignore_module_load_error ? true
+                                    : module_list.AppendIfNeeded(module_sp);
   };
 
   if (!loaded_images_sp->ForEach(reload_image))
diff --git 
a/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py
 
b/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py
index a5c79378bab50..ca6b0fa5229a3 100644
--- 
a/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py
+++ 
b/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py
@@ -76,6 +76,10 @@ def cleanup():
             )
         self.assertTrue(corefile_process, PROCESS_IS_VALID)
 
+        # Create a random lib which does not exist in the corefile.
+        random_dylib = self.get_module_with_name(corefile_target, 
"random.dylib")
+        self.assertFalse(random_dylib, "Dynamic library random.dylib should 
not be found.")
+
         structured_data = lldb.SBStructuredData()
         structured_data.SetFromJSON(
             json.dumps(
@@ -83,7 +87,16 @@ def cleanup():
                     "backing_target_idx": self.dbg.GetIndexOfTarget(
                         corefile_process.GetTarget()
                     ),
-                    "libbaz_path": self.getBuildArtifact("libbaz.dylib"),
+                    "custom_modules": [
+                        {
+                            "path": self.getBuildArtifact("libbaz.dylib"),
+                        },
+                        {
+                            "path": "/random/path/random.dylib",
+                            "load_addr": 12345678,
+                            "ignore_module_load_error": True
+                        }
+                    ]
                 }
             )
         )
diff --git 
a/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py 
b/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
index 8641d9a7ced35..86e5feb49e6cf 100644
--- 
a/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
+++ 
b/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
@@ -46,22 +46,52 @@ def __init__(self, exe_ctx: lldb.SBExecutionContext, args: 
lldb.SBStructuredData
         if len(self.threads) == 2:
             self.threads[len(self.threads) - 1].is_stopped = True
 
-        corefile_module = self.get_module_with_name(
-            self.corefile_target, "libbaz.dylib"
-        )
-        if not corefile_module or not corefile_module.IsValid():
-            return
-        module_path = os.path.join(
-            corefile_module.GetFileSpec().GetDirectory(),
-            corefile_module.GetFileSpec().GetFilename(),
-        )
-        if not os.path.exists(module_path):
-            return
-        module_load_addr = 
corefile_module.GetObjectFileHeaderAddress().GetLoadAddress(
-            self.corefile_target
-        )
+        custom_modules = args.GetValueForKey("custom_modules")
+        if custom_modules.GetType() == lldb.eStructuredDataTypeArray:
+            for id in range(custom_modules.GetSize()):
+
+                custom_module = custom_modules.GetItemAtIndex(id)
+                if not custom_module or not custom_module.IsValid() or not 
custom_module.GetType() == lldb.eStructuredDataTypeDictionary:
+                    continue
+
+                # Get custom module path from args
+                module_path_arg = custom_module.GetValueForKey("path")
+                module_path = None
+                if not module_path_arg or not module_path_arg.IsValid() or not 
module_path_arg.GetType() == lldb.eStructuredDataTypeString:
+                    return
+
+                module_path = module_path_arg.GetStringValue(100)
+                module_name = os.path.basename(module_path)
+
+                # Get ignore_module_load_error boolean from args
+                ignore_module_load_error = False
+                ignore_module_load_error_arg = 
custom_module.GetValueForKey("ignore_module_load_error")
+                if ignore_module_load_error_arg and 
ignore_module_load_error_arg.IsValid() and 
ignore_module_load_error_arg.GetType() == lldb.eStructuredDataTypeBoolean:
+                    ignore_module_load_error = 
ignore_module_load_error_arg.GetBooleanValue()
+
+                if not os.path.exists(module_path) and not 
ignore_module_load_error:
+                    return
+
+                # Get custom module load address from args
+                module_load_addr = None
+                module_load_addr_arg = 
custom_module.GetValueForKey("load_addr")
+                if module_load_addr_arg and module_load_addr_arg.IsValid() and 
module_load_addr_arg.GetType() == lldb.eStructuredDataTypeInteger:
+                    module_load_addr = module_load_addr_arg.GetIntegerValue()
+
+                # If module load address is not specified/valid, try to find 
it from corefile module
+                if module_load_addr is None:
+                    corefile_module = self.get_module_with_name(
+                        self.corefile_target, module_name
+                    )
+
+                    if not corefile_module or not corefile_module.IsValid():
+                        return
+
+                    module_load_addr = 
corefile_module.GetObjectFileHeaderAddress().GetLoadAddress(
+                        self.corefile_target
+                    )
 
-        self.loaded_images.append({"path": module_path, "load_addr": 
module_load_addr})
+                self.loaded_images.append({"path": module_path, "load_addr": 
module_load_addr, "ignore_module_load_error": ignore_module_load_error})
 
     def get_memory_region_containing_address(
         self, addr: int

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to