问题
Is it possible to (and, if so, how does one) determine the shared libraries of an application that are used by an application at runtime? Basically, can I programmatically obtain the the output of ldd
? Preferred C/C++ solution does not just jump to execute ldd on the command-line.
Consider the following:
I have a driver application that calls doAction()
from a shared library libfoo
. I compile the application once and then set LD_LIBRARY_PATH
to an appropriate directory containing a libfoo
with the doAction()
symbol defined. This way, I can have multiple implementations of doAction()
in different libfoo
s but only ever compile an application once.
A real world example would be a professor having a class of students implement doAction()
. Instead of compiling a test harness against each student's implementation of doAction()
, the students submit a shared library and the professor can simply change LD_LIBRARY_PATH
to evaluate each student.
My goal in obtaining the library currently being used is to perform an md5sum
on the library at runtime to ensure I'm calling the correct library. In the contrived example, all students would submit the md5sum
of their library and the professor could match the running executable + shared library (database lookup, log to file, ...) to the student, to prevent an accident in setting LD_LIBRARY_PATH
effecting another student's grade (forgot to change LD_LIBRARY_PATH
to David's directory and ran again with Bill's libfoo
).
回答1:
Since it looks like you're using something UNIX-y, just use dlopen
instead of dynamically linking your driver app against the missing symbol.
Full sequence is:
- iterate over all submitted .so library filenames somehow (maybe you have one directory with studentname.so or something)
- load each library
- get the entry point function
- call it
- unload library (optional, I guess)
like so:
void *lib = dlopen(filename, RTLD_LOCAL);
void *libfun = dlsym(lib, "doAction");
if (libfun == NULL)
cout << "student failed by not providing doAction() in " << filename << endl;
else {
void (*doAction)(void) = (void (*)(void)) libfun;
// no, I can't remember the correct syntax for casting to function pointer
cout << "calling " << filename << ":doAction()" << endl;
doAction();
// is there some way to tell if it succeeded?
cout << "unloading " << filename << endl;
dlclose(lib);
}
Notes:
- if the interface is the same in each case (ie,
void (*)()
), you could make this configurable by directory name and symbol name, and it'd work for more than one test - in fact, if the interface is NOT what you expect, the function pointer cast will do horrible things, so careful with this
- finally, if the student used C++, their function name symbol will be mangled. Tell them to declare the entry-point as
extern "C" void doAction()
to avoid that. - the
RTLD_LOCAL
flag should stop anything in one student's library interfering with another (if you don't unload), but there are other flags it may be sensible to add- specifically,
RTLD_NOW
will causedlopen
to fail if the student lib has an unresolved external reference it can't figure out (so you can handle it gracefully, by failing them): otherwise your program may just crash when you calldoAction
.
- specifically,
Although I think the above is better than the solution you're directly asking for help with, I did also find a reference to dl_iterate_phdr
while double-checking the docs. If you're on Linux specifically, and if the dl_phdr_info.dlpi_name
is actually the filename ... you might be able to get it that way.
I still think it's much uglier, though.
回答2:
If you're using Linux, you can use the dl_iterate_phdr
function:
The dl_iterate_phdr() function allows an application to inquire at run time to find out which shared objects it has loaded.
http://linux.die.net/man/3/dl_iterate_phdr
回答3:
At runtime, it is not an application, it is a process.
If the process has pid 1234, you can get its memory map by reading /proc/1234/maps
(or /proc/1234/smaps
which is more detailed). That map lists in particular mmap-ed files (notably shared libraries). From inside the application, read /proc/self/maps
Try
grep so /proc/self/maps
to have an idea of what I mean.
By the way, if you have an address, the dladdr function gives information about the nearest symbol and shared object...
addenda
And as Rob Mayoff answered, dl_iterate_phdr is probably the best solution on Linux
回答4:
If this is Linux (I doubt there's a generic POSIX way to do this but I could be wrong), you may be interested in the contents of /proc/(pid)/maps. This gives the mapped memory ranges for your process and you could search for which of the ranges your md5sum() function's address falls in.
回答5:
If you're in linux/unix, you could use strace like strace -o strace.log -f students_binary
. Strace traces all system calls, including the calls to open a library. Then you could parse strace.log
for all openings of any file and perform the md5sum
on all open files.
来源:https://stackoverflow.com/questions/9038303/programatically-determine-shared-libraries-in-use-by-running-application