Skip to content

Commit 0a01e8f

Browse files
authored
[lldb] Allow mapping object file paths (#101361)
This introduces a `target.object-map` which allows us to remap module locations, much in the same way as source mapping works today. This is useful, for instance, when debugging coredumps, so we can replace some of the locations where LLDB attempts to load shared libraries and executables from, without having to setup an entire sysroot.
1 parent 6aa723d commit 0a01e8f

File tree

4 files changed

+50
-2
lines changed

4 files changed

+50
-2
lines changed

lldb/include/lldb/Target/Target.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ class TargetProperties : public Properties {
141141

142142
PathMappingList &GetSourcePathMap() const;
143143

144+
PathMappingList &GetObjectPathMap() const;
145+
144146
bool GetAutoSourceMapRelative() const;
145147

146148
FileSpecList GetExecutableSearchPaths();

lldb/source/Target/Target.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2155,12 +2155,21 @@ bool Target::ReadPointerFromMemory(const Address &addr, Status &error,
21552155
return false;
21562156
}
21572157

2158-
ModuleSP Target::GetOrCreateModule(const ModuleSpec &module_spec, bool notify,
2159-
Status *error_ptr) {
2158+
ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
2159+
bool notify, Status *error_ptr) {
21602160
ModuleSP module_sp;
21612161

21622162
Status error;
21632163

2164+
// Apply any remappings specified in target.object-map:
2165+
ModuleSpec module_spec(orig_module_spec);
2166+
PathMappingList &obj_mapping = GetObjectPathMap();
2167+
if (std::optional<FileSpec> remapped_obj_file =
2168+
obj_mapping.RemapPath(orig_module_spec.GetFileSpec().GetPath(),
2169+
true /* only_if_exists */)) {
2170+
module_spec.GetFileSpec().SetPath(remapped_obj_file->GetPath());
2171+
}
2172+
21642173
// First see if we already have this module in our module list. If we do,
21652174
// then we're done, we don't need to consult the shared modules list. But
21662175
// only do this if we are passed a UUID.
@@ -4459,6 +4468,14 @@ PathMappingList &TargetProperties::GetSourcePathMap() const {
44594468
return option_value->GetCurrentValue();
44604469
}
44614470

4471+
PathMappingList &TargetProperties::GetObjectPathMap() const {
4472+
const uint32_t idx = ePropertyObjectMap;
4473+
OptionValuePathMappings *option_value =
4474+
m_collection_sp->GetPropertyAtIndexAsOptionValuePathMappings(idx);
4475+
assert(option_value);
4476+
return option_value->GetCurrentValue();
4477+
}
4478+
44624479
bool TargetProperties::GetAutoSourceMapRelative() const {
44634480
const uint32_t idx = ePropertyAutoSourceMapRelative;
44644481
return GetPropertyAtIndexAs<bool>(

lldb/source/Target/TargetProperties.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ let Definition = "target" in {
4646
def SourceMap: Property<"source-map", "PathMap">,
4747
DefaultStringValue<"">,
4848
Desc<"Source path remappings apply substitutions to the paths of source files, typically needed to debug from a different host than the one that built the target. The source-map property consists of an array of pairs, the first element is a path prefix, and the second is its replacement. The syntax is `prefix1 replacement1 prefix2 replacement2...`. The pairs are checked in order, the first prefix that matches is used, and that prefix is substituted with the replacement. A common pattern is to use source-map in conjunction with the clang -fdebug-prefix-map flag. In the build, use `-fdebug-prefix-map=/path/to/build_dir=.` to rewrite the host specific build directory to `.`. Then for debugging, use `settings set target.source-map . /path/to/local_dir` to convert `.` to a valid local path.">;
49+
def ObjectMap: Property<"object-map", "PathMap">,
50+
DefaultStringValue<"">,
51+
Desc<"Object path remappings apply substitutions to the paths of object files, typically needed to debug from a different host than the one that built the target. The object-map property consists of an array of pairs, the first element is a path prefix, and the second is its replacement. The syntax is `prefix1 replacement1 prefix2 replacement2...`. The pairs are checked in order, the first prefix that matches is used, and that prefix is substituted with the replacement.">;
4952
def AutoSourceMapRelative: Property<"auto-source-map-relative", "Boolean">,
5053
DefaultTrue,
5154
Desc<"Automatically deduce source path mappings based on source file breakpoint resolution. It only deduces source mapping if source file breakpoint request is using full path and if the debug info contains relative paths.">;

lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,32 @@ def test_i386_sysroot(self):
249249

250250
self.dbg.DeleteTarget(target)
251251

252+
def test_object_map(self):
253+
"""Test that lldb can find the exe for an i386 linux core file using the object map."""
254+
255+
# Copy linux-i386.out to lldb_i386_object_map/a.out
256+
tmp_object_map_root = os.path.join(self.getBuildDir(), "lldb_i386_object_map")
257+
executable = os.path.join(tmp_object_map_root, "a.out")
258+
lldbutil.mkdir_p(os.path.dirname(executable))
259+
shutil.copyfile("linux-i386.out", executable)
260+
261+
# Replace the original module path at /home/labath/test and load the core
262+
self.runCmd(
263+
"settings set target.object-map /home/labath/test {}".format(
264+
tmp_object_map_root
265+
)
266+
)
267+
268+
target = self.dbg.CreateTarget(None)
269+
process = target.LoadCore("linux-i386.core")
270+
271+
# Check that we did load the mapped executable
272+
exe_module_spec = process.GetTarget().GetModuleAtIndex(0).GetFileSpec()
273+
self.assertTrue(exe_module_spec.fullpath.startswith(tmp_object_map_root))
274+
275+
self.check_all(process, self._i386_pid, self._i386_regions, "a.out")
276+
self.dbg.DeleteTarget(target)
277+
252278
@skipIfLLVMTargetMissing("X86")
253279
@skipIfWindows
254280
def test_x86_64_sysroot(self):

0 commit comments

Comments
 (0)