Skip to content

Commit 2ff3b18

Browse files
rchamalarchamala
andauthored
Allow option to ignore module load errors in ScriptedProcess (#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 whether the modules will be successfully downloaded before creating the scripted process. 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 when the scripted process is being created. The issue is that if one of the symbol is not found from the list specified in tombstone, none of the modules load in scripted process. Even if we ensure symbols are present in symbol server before creating the scripted process, if the load address is wrong or if the module is already appended, all module loads are skipped. **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 --------- Co-authored-by: rchamala <[email protected]>
1 parent 0968df9 commit 2ff3b18

File tree

3 files changed

+117
-34
lines changed

3 files changed

+117
-34
lines changed

lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "lldb/Utility/ScriptedMetadata.h"
2626
#include "lldb/Utility/State.h"
2727

28+
#include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h"
29+
2830
#include <mutex>
2931

3032
LLDB_PLUGIN_DEFINE(ScriptedProcess)
@@ -165,7 +167,7 @@ Status ScriptedProcess::DoLoadCore() {
165167
Status ScriptedProcess::DoLaunch(Module *exe_module,
166168
ProcessLaunchInfo &launch_info) {
167169
LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__);
168-
170+
169171
/* MARK: This doesn't reflect how lldb actually launches a process.
170172
In reality, it attaches to debugserver, then resume the process.
171173
That's not true in all cases. If debugserver is remote, lldb
@@ -444,7 +446,6 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
444446
return error_with_message("Couldn't cast image object into dictionary.");
445447

446448
ModuleSpec module_spec;
447-
llvm::StringRef value;
448449

449450
bool has_path = dict->HasKey("path");
450451
bool has_uuid = dict->HasKey("uuid");
@@ -453,22 +454,17 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
453454
if (!dict->HasKey("load_addr"))
454455
return error_with_message("Dictionary is missing key 'load_addr'");
455456

457+
llvm::StringRef path = "";
456458
if (has_path) {
457-
dict->GetValueForKeyAsString("path", value);
458-
module_spec.GetFileSpec().SetPath(value);
459+
dict->GetValueForKeyAsString("path", path);
460+
module_spec.GetFileSpec().SetPath(path);
459461
}
460462

463+
llvm::StringRef uuid = "";
461464
if (has_uuid) {
462-
dict->GetValueForKeyAsString("uuid", value);
463-
module_spec.GetUUID().SetFromStringRef(value);
465+
dict->GetValueForKeyAsString("uuid", uuid);
466+
module_spec.GetUUID().SetFromStringRef(uuid);
464467
}
465-
module_spec.GetArchitecture() = target.GetArchitecture();
466-
467-
ModuleSP module_sp =
468-
target.GetOrCreateModule(module_spec, true /* notify */);
469-
470-
if (!module_sp)
471-
return error_with_message("Couldn't create or get module.");
472468

473469
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
474470
lldb::offset_t slide = LLDB_INVALID_OFFSET;
@@ -481,23 +477,55 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
481477
if (slide != LLDB_INVALID_OFFSET)
482478
load_addr += slide;
483479

480+
module_spec.GetArchitecture() = target.GetArchitecture();
481+
482+
ModuleSP module_sp =
483+
target.GetOrCreateModule(module_spec, true /* notify */);
484+
485+
bool is_placeholder_module = false;
486+
487+
if (!module_sp) {
488+
// Create a placeholder module
489+
LLDB_LOGF(
490+
GetLog(LLDBLog::Process),
491+
"ScriptedProcess::%s unable to locate the matching "
492+
"object file path %s, creating a placeholder module at 0x%" PRIx64,
493+
__FUNCTION__, path.str().c_str(), load_addr);
494+
495+
module_sp = Module::CreateModuleFromObjectFile<ObjectFilePlaceholder>(
496+
module_spec, load_addr, module_spec.GetFileSpec().MemorySize());
497+
498+
is_placeholder_module = true;
499+
}
500+
484501
bool changed = false;
485502
module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/,
486503
changed);
487504

488505
if (!changed && !module_sp->GetObjectFile())
489506
return error_with_message("Couldn't set the load address for module.");
490507

491-
dict->GetValueForKeyAsString("path", value);
492-
FileSpec objfile(value);
508+
FileSpec objfile(path);
493509
module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());
494510

511+
if (is_placeholder_module) {
512+
target.GetImages().AppendIfNeeded(module_sp, true /*notify=*/);
513+
return true;
514+
}
515+
495516
return module_list.AppendIfNeeded(module_sp);
496517
};
497518

498-
if (!loaded_images_sp->ForEach(reload_image))
499-
return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
500-
LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);
519+
size_t loaded_images_size = loaded_images_sp->GetSize();
520+
bool print_error = true;
521+
for (size_t idx = 0; idx < loaded_images_size; idx++) {
522+
const auto &loaded_image = loaded_images_sp->GetItemAtIndex(idx);
523+
if (!reload_image(loaded_image.get()) && print_error) {
524+
print_error = false;
525+
ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
526+
LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);
527+
}
528+
}
501529

502530
target.ModulesDidLoad(module_list);
503531

lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,28 @@ def cleanup():
7676
)
7777
self.assertTrue(corefile_process, PROCESS_IS_VALID)
7878

79+
# Create a random lib which does not exist in the corefile.
80+
random_dylib = self.get_module_with_name(corefile_target, "random.dylib")
81+
self.assertFalse(
82+
random_dylib, "Dynamic library random.dylib should not be found."
83+
)
84+
7985
structured_data = lldb.SBStructuredData()
8086
structured_data.SetFromJSON(
8187
json.dumps(
8288
{
8389
"backing_target_idx": self.dbg.GetIndexOfTarget(
8490
corefile_process.GetTarget()
8591
),
86-
"libbaz_path": self.getBuildArtifact("libbaz.dylib"),
92+
"custom_modules": [
93+
{
94+
"path": self.getBuildArtifact("libbaz.dylib"),
95+
},
96+
{
97+
"path": "/random/path/random.dylib",
98+
"load_addr": 12345678,
99+
},
100+
],
87101
}
88102
)
89103
)

lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,63 @@ def __init__(self, exe_ctx: lldb.SBExecutionContext, args: lldb.SBStructuredData
4646
if len(self.threads) == 2:
4747
self.threads[len(self.threads) - 1].is_stopped = True
4848

49-
corefile_module = self.get_module_with_name(
50-
self.corefile_target, "libbaz.dylib"
51-
)
52-
if not corefile_module or not corefile_module.IsValid():
53-
return
54-
module_path = os.path.join(
55-
corefile_module.GetFileSpec().GetDirectory(),
56-
corefile_module.GetFileSpec().GetFilename(),
57-
)
58-
if not os.path.exists(module_path):
59-
return
60-
module_load_addr = corefile_module.GetObjectFileHeaderAddress().GetLoadAddress(
61-
self.corefile_target
62-
)
49+
custom_modules = args.GetValueForKey("custom_modules")
50+
if custom_modules.GetType() == lldb.eStructuredDataTypeArray:
51+
for id in range(custom_modules.GetSize()):
52+
53+
custom_module = custom_modules.GetItemAtIndex(id)
54+
if (
55+
not custom_module
56+
or not custom_module.IsValid()
57+
or not custom_module.GetType() == lldb.eStructuredDataTypeDictionary
58+
):
59+
continue
60+
61+
# Get custom module path from args
62+
module_path_arg = custom_module.GetValueForKey("path")
63+
module_path = None
64+
if (
65+
not module_path_arg
66+
or not module_path_arg.IsValid()
67+
or not module_path_arg.GetType() == lldb.eStructuredDataTypeString
68+
):
69+
continue
70+
71+
module_path = module_path_arg.GetStringValue(100)
72+
73+
# Get custom module load address from args
74+
module_load_addr = None
75+
module_load_addr_arg = custom_module.GetValueForKey("load_addr")
76+
if (
77+
module_load_addr_arg
78+
and module_load_addr_arg.IsValid()
79+
and module_load_addr_arg.GetType()
80+
== lldb.eStructuredDataTypeInteger
81+
):
82+
module_load_addr = module_load_addr_arg.GetIntegerValue()
83+
84+
# If module load address is not specified/valid, try to find it from corefile module
85+
if module_load_addr is None:
86+
module_name = os.path.basename(module_path)
87+
corefile_module = self.get_module_with_name(
88+
self.corefile_target, module_name
89+
)
6390

64-
self.loaded_images.append({"path": module_path, "load_addr": module_load_addr})
91+
if not corefile_module or not corefile_module.IsValid():
92+
continue
93+
94+
module_load_addr = (
95+
corefile_module.GetObjectFileHeaderAddress().GetLoadAddress(
96+
self.corefile_target
97+
)
98+
)
99+
100+
self.loaded_images.append(
101+
{
102+
"path": module_path,
103+
"load_addr": module_load_addr,
104+
}
105+
)
65106

66107
def get_memory_region_containing_address(
67108
self, addr: int

0 commit comments

Comments
 (0)