I’ve developed this little C++ program for Linux
#include <iostream>
#include <vector>
#include <string>
#include <link.h>
#include <climits>
#include <dlfcn.h>
using namespace std;
template<typename Fn>
requires requires( Fn fn, dl_phdr_info *image, size_t n ) { { fn( image, n ) } -> same_as<int>; }
int dlIteratePhdr( Fn &&fn )
{
return dl_iterate_phdr(
[]( dl_phdr_info *image, size_t size, void *pFn ) -> int
{
return (*(Fn *)pFn)( image, size );
}, &fn );
};
int main()
{
size_t nImages = 0;
dlIteratePhdr( [&]( dl_phdr_info *, size_t ) -> int { ++nImages; return 0; } );
vector<string> images;
images.reserve( nImages );
if( dlIteratePhdr(
[&]( dl_phdr_info *image, size_t ) -> int
{
try
{
images.emplace_back( image->dlpi_name );
return 0;
}
catch( ... )
{
return 1;
}
} ) )
return EXIT_FAILURE;
for( string const &image : images )
cout << """ << image << """ << endl;
}
For my Ubuntu machine this prints:
""
"linux-vdso.so.1"
"/lib/x86_64-linux-gnu/libstdc++.so.6"
"/lib/x86_64-linux-gnu/libgcc_s.so.1"
"/lib/x86_64-linux-gnu/libc.so.6"
"/lib/x86_64-linux-gnu/libm.so.6"
"/lib64/ld-linux-x86-64.so.2"
Why is the name of the first image empty ?
Is this reserved for the executable itself ?
And is it really necessary to copy the information given to the callback or would this be alive after dl_iterate_phdr ?
2
Answers
Because the name of the main executable is not known to the loader.
Unlike the shared libraries, which are
mmap
ed by the loader, the main executable is mapped by the kernel itself, and only the file descriptor is passed in to the loader.As Hasturkun commented, this behavior is documented in the man page.
Yes.
The
dl_phdr_info
that is passed in is stack-allocated, and will get overwritten after each step (in fact, it’s the same pointer every time; but this is an implementation detail).The strings pointed by
dlpi_name
are dynamically allocated by the loader.Strings corresponding to the libraries loaded during executable startup are likely to persist throughout the lifetime of the process, but strings corresponding to
dlopen()
ed libraries may getfree()
d ondlclose()
. This is also an implementation detail and you are better off not relying on it.I found a way to determine the executable path also, here’s the above program which also does that:
I don’t know why the dl_iterate_phdr doesn’t supply that path by itself if I can manage to get it otherwise.