Page MenuHomeFreeBSD

rtld: trace preloaded objects
ClosedPublic

Authored by kib on Mar 30 2022, 9:22 PM.
Tags
None
Referenced Files
Unknown Object (File)
Mon, Nov 18, 2:06 AM
Unknown Object (File)
Tue, Nov 5, 11:26 AM
Unknown Object (File)
Oct 13 2024, 2:40 AM
Unknown Object (File)
Oct 13 2024, 2:11 AM
Unknown Object (File)
Oct 13 2024, 2:11 AM
Unknown Object (File)
Oct 13 2024, 2:10 AM
Unknown Object (File)
Oct 3 2024, 5:42 AM
Unknown Object (File)
Oct 2 2024, 10:16 AM
Subscribers

Details

Summary
They are printed with the `[preloaded]` herald.  The list includes the
objects not listed explicitly as recursive dependencies of the main
object, effectively dsos loaded by LD_PRELOAD mechanism.  Also, vdso
is listed as well.

Since there is no DT_NEEDED entry for LD_PRELOADed objects, they are
printed using LD_TRACE_LOADED_OBJECTS_FTM2 format.

The per-commit view is available at https://kib.kiev.ua/git/gitweb.cgi?p=deviant3.git;a=shortlog;h=refs/heads/rtld, there are several refactoring and style adjustments that are easier to skip when reading the main change.

I was very annoying by this quirk (inability to see LD_PRELOADed objects), esp. when working on vdso.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

kib requested review of this revision.Mar 30 2022, 9:22 PM

Use bool type for list_containers.

Since there is no DT_NEEDED entry for LD_PRELOADed objects, they are printed using LD_TRACE_LOADED_OBJECTS_FTM2 format.

I don't really understand this.

Also this behaviour seems surprising:

$ LD_PRELOAD=/lib/libpcap.so.8:/lib/libibverbs.so.1 ldd $(which readelf)
/usr/bin/readelf:
        libdwarf.so.4 => /usr/lib/libdwarf.so.4 (0x16e2fa11c000)
        libelf.so.2 => /lib/libelf.so.2 (0x16e2fa11c000)
        libz.so.6 => /lib/libz.so.6 (0x16e2fa11c000)
        libcasper.so.1 => /lib/libcasper.so.1 (0x16e2fa11c000)
        libcap_fileargs.so.1 => /lib/casper/libcap_fileargs.so.1 (0x16e2fa11c000)
        libc.so.7 => /lib/libc.so.7 (0x16e2fa11c000)
        libibverbs.so.1 => /lib/libibverbs.so.1 (0x16eb1acd2000)
        libmlx5.so.1 => /lib/libmlx5.so.1 (0x16eb1acd2000)
        libnv.so.0 => /lib/libnv.so.0 (0x16eb1eb9f000)
        libthr.so.3 => /lib/libthr.so.3 (0x16eb20317000)
[preloaded]
        [vdso] (0x7ffffffff000)
        /lib/libpcap.so.8 (0x16eb1acd2000)

That is, libibverbs.so (a dependency of libpcap.so) is not listed as preloaded even though it is.

Since there is no DT_NEEDED entry for LD_PRELOADed objects, they are printed using LD_TRACE_LOADED_OBJECTS_FTM2 format.

I don't really understand this.

FTM1 is used when DT_NEEDED entry is present, so we know how somebody called our dso. Since for LD_PRELOAD there is no object referenced it, FMT2 is used. FMT1 prints "DT_NEEDED => <FMT2>". This quirk exists without my patch.

Also this behaviour seems surprising:

$ LD_PRELOAD=/lib/libpcap.so.8:/lib/libibverbs.so.1 ldd $(which readelf)
/usr/bin/readelf:
        libdwarf.so.4 => /usr/lib/libdwarf.so.4 (0x16e2fa11c000)
        libelf.so.2 => /lib/libelf.so.2 (0x16e2fa11c000)
        libz.so.6 => /lib/libz.so.6 (0x16e2fa11c000)
        libcasper.so.1 => /lib/libcasper.so.1 (0x16e2fa11c000)
        libcap_fileargs.so.1 => /lib/casper/libcap_fileargs.so.1 (0x16e2fa11c000)
        libc.so.7 => /lib/libc.so.7 (0x16e2fa11c000)
        libibverbs.so.1 => /lib/libibverbs.so.1 (0x16eb1acd2000)
        libmlx5.so.1 => /lib/libmlx5.so.1 (0x16eb1acd2000)
        libnv.so.0 => /lib/libnv.so.0 (0x16eb1eb9f000)
        libthr.so.3 => /lib/libthr.so.3 (0x16eb20317000)
[preloaded]
        [vdso] (0x7ffffffff000)
        /lib/libpcap.so.8 (0x16eb1acd2000)

That is, libibverbs.so (a dependency of libpcap.so) is not listed as preloaded even though it is.

Well, exactly because libibverbs was loaded as dependency, it is not listed as preloaded. ldd -a would show more details.

The fact that the library is listed in LD_PRELOAD does not make it factually preloaded if it is loaded as needed dependency of another preloaded library. It is somewhat messy, but I do not see it useful to add even more state to try to unwind the situation. Good enough answer is to use ldd -a.

In D34716#786757, @kib wrote:

Since there is no DT_NEEDED entry for LD_PRELOADed objects, they are printed using LD_TRACE_LOADED_OBJECTS_FTM2 format.

I don't really understand this.

FTM1 is used when DT_NEEDED entry is present, so we know how somebody called our dso. Since for LD_PRELOAD there is no object referenced it, FMT2 is used. FMT1 prints "DT_NEEDED => <FMT2>". This quirk exists without my patch.

Sorry, I don't see how this is true. It looks like FMT2 is used iff the object name does not start with "lib". With LD_PRELOAD=libpcap.so.8 we use FMT1 and with LD_PRELOAD=/lib/libpcap.so.8 we use FMT2.

Also this behaviour seems surprising:

$ LD_PRELOAD=/lib/libpcap.so.8:/lib/libibverbs.so.1 ldd $(which readelf)
/usr/bin/readelf:
        libdwarf.so.4 => /usr/lib/libdwarf.so.4 (0x16e2fa11c000)
        libelf.so.2 => /lib/libelf.so.2 (0x16e2fa11c000)
        libz.so.6 => /lib/libz.so.6 (0x16e2fa11c000)
        libcasper.so.1 => /lib/libcasper.so.1 (0x16e2fa11c000)
        libcap_fileargs.so.1 => /lib/casper/libcap_fileargs.so.1 (0x16e2fa11c000)
        libc.so.7 => /lib/libc.so.7 (0x16e2fa11c000)
        libibverbs.so.1 => /lib/libibverbs.so.1 (0x16eb1acd2000)
        libmlx5.so.1 => /lib/libmlx5.so.1 (0x16eb1acd2000)
        libnv.so.0 => /lib/libnv.so.0 (0x16eb1eb9f000)
        libthr.so.3 => /lib/libthr.so.3 (0x16eb20317000)
[preloaded]
        [vdso] (0x7ffffffff000)
        /lib/libpcap.so.8 (0x16eb1acd2000)

That is, libibverbs.so (a dependency of libpcap.so) is not listed as preloaded even though it is.

Well, exactly because libibverbs was loaded as dependency, it is not listed as preloaded. ldd -a would show more details.

The fact that the library is listed in LD_PRELOAD does not make it factually preloaded if it is loaded as needed dependency of another preloaded library. It is somewhat messy, but I do not see it useful to add even more state to try to unwind the situation. Good enough answer is to use ldd -a.

Ok, fair enough.

This revision is now accepted and ready to land.Mar 31 2022, 4:57 PM
In D34716#786757, @kib wrote:

Since there is no DT_NEEDED entry for LD_PRELOADed objects, they are printed using LD_TRACE_LOADED_OBJECTS_FTM2 format.

I don't really understand this.

FTM1 is used when DT_NEEDED entry is present, so we know how somebody called our dso. Since for LD_PRELOAD there is no object referenced it, FMT2 is used. FMT1 prints "DT_NEEDED => <FMT2>". This quirk exists without my patch.

Sorry, I don't see how this is true. It looks like FMT2 is used iff the object name does not start with "lib". With LD_PRELOAD=libpcap.so.8 we use FMT1 and with LD_PRELOAD=/lib/libpcap.so.8 we use FMT2.

Not some object name, but the DT_NEEDED name from the object that referenced our. If there is no that referencing object, as is in case of preloaded object, a random name from object 'names' stailq is used, which typically does not start with the "lib".

In D34716#786923, @kib wrote:
In D34716#786757, @kib wrote:

Since there is no DT_NEEDED entry for LD_PRELOADed objects, they are printed using LD_TRACE_LOADED_OBJECTS_FTM2 format.

I don't really understand this.

FTM1 is used when DT_NEEDED entry is present, so we know how somebody called our dso. Since for LD_PRELOAD there is no object referenced it, FMT2 is used. FMT1 prints "DT_NEEDED => <FMT2>". This quirk exists without my patch.

Sorry, I don't see how this is true. It looks like FMT2 is used iff the object name does not start with "lib". With LD_PRELOAD=libpcap.so.8 we use FMT1 and with LD_PRELOAD=/lib/libpcap.so.8 we use FMT2.

Not some object name, but the DT_NEEDED name from the object that referenced our. If there is no that referencing object, as is in case of preloaded object, a random name from object 'names' stailq is used, which typically does not start with the "lib".

Ok, but then we cannot say with certainty that FMT2 will be used for preloaded objects.