diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp index d2111ce877ce5..6b371a151668d 100644 --- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -25,6 +25,8 @@ #include "lldb/Utility/ScriptedMetadata.h" #include "lldb/Utility/State.h" +#include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h" + #include LLDB_PLUGIN_DEFINE(ScriptedProcess) @@ -165,7 +167,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 @@ -444,7 +446,6 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() { return error_with_message("Couldn't cast image object into dictionary."); ModuleSpec module_spec; - llvm::StringRef value; bool has_path = dict->HasKey("path"); bool has_uuid = dict->HasKey("uuid"); @@ -453,22 +454,17 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() { if (!dict->HasKey("load_addr")) return error_with_message("Dictionary is missing key 'load_addr'"); + llvm::StringRef path = ""; if (has_path) { - dict->GetValueForKeyAsString("path", value); - module_spec.GetFileSpec().SetPath(value); + dict->GetValueForKeyAsString("path", path); + module_spec.GetFileSpec().SetPath(path); } + llvm::StringRef uuid = ""; if (has_uuid) { - dict->GetValueForKeyAsString("uuid", value); - module_spec.GetUUID().SetFromStringRef(value); + dict->GetValueForKeyAsString("uuid", uuid); + module_spec.GetUUID().SetFromStringRef(uuid); } - module_spec.GetArchitecture() = target.GetArchitecture(); - - ModuleSP module_sp = - target.GetOrCreateModule(module_spec, true /* notify */); - - if (!module_sp) - return error_with_message("Couldn't create or get module."); lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; lldb::offset_t slide = LLDB_INVALID_OFFSET; @@ -481,6 +477,27 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() { if (slide != LLDB_INVALID_OFFSET) load_addr += slide; + module_spec.GetArchitecture() = target.GetArchitecture(); + + ModuleSP module_sp = + target.GetOrCreateModule(module_spec, true /* notify */); + + bool is_placeholder_module = false; + + if (!module_sp) { + // Create a placeholder module + LLDB_LOGF( + GetLog(LLDBLog::Process), + "ScriptedProcess::%s unable to locate the matching " + "object file path %s, creating a placeholder module at 0x%" PRIx64, + __FUNCTION__, path.str().c_str(), load_addr); + + module_sp = Module::CreateModuleFromObjectFile( + module_spec, load_addr, module_spec.GetFileSpec().MemorySize()); + + is_placeholder_module = true; + } + bool changed = false; module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/, changed); @@ -488,16 +505,27 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() { if (!changed && !module_sp->GetObjectFile()) return error_with_message("Couldn't set the load address for module."); - dict->GetValueForKeyAsString("path", value); - FileSpec objfile(value); + FileSpec objfile(path); module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename()); + if (is_placeholder_module) { + target.GetImages().AppendIfNeeded(module_sp, true /*notify=*/); + return true; + } + return module_list.AppendIfNeeded(module_sp); }; - if (!loaded_images_sp->ForEach(reload_image)) - return ScriptedInterface::ErrorWithMessage( - LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error); + size_t loaded_images_size = loaded_images_sp->GetSize(); + bool print_error = true; + for (size_t idx = 0; idx < loaded_images_size; idx++) { + const auto &loaded_image = loaded_images_sp->GetItemAtIndex(idx); + if (!reload_image(loaded_image.get()) && print_error) { + print_error = false; + ScriptedInterface::ErrorWithMessage( + LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error); + } + } target.ModulesDidLoad(module_list); diff --git a/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py b/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py index a5c79378bab50..22b0d01c2c173 100644 --- a/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py +++ b/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py @@ -76,6 +76,12 @@ 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 +89,15 @@ 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, + }, + ], } ) ) 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..736bb69397f9b 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,63 @@ 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 + ): + continue + + module_path = module_path_arg.GetStringValue(100) + + # 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: + module_name = os.path.basename(module_path) + corefile_module = self.get_module_with_name( + self.corefile_target, module_name + ) - self.loaded_images.append({"path": module_path, "load_addr": module_load_addr}) + if not corefile_module or not corefile_module.IsValid(): + continue + + module_load_addr = ( + corefile_module.GetObjectFileHeaderAddress().GetLoadAddress( + self.corefile_target + ) + ) + + self.loaded_images.append( + { + "path": module_path, + "load_addr": module_load_addr, + } + ) def get_memory_region_containing_address( self, addr: int