(I am focused on Linux, I believe that most of my answer is suitable for every POSIX system, but on MacOSX dlopen .dylib files are required dynamic libraries , not .so shared objects)
A program can even emit some C code in some temporary file /tmp/foo1234.c , fork compiling this /tmp/foo1234.c into the general library /tmp/foo1234.so with some command gcc -O -shared -fPIC /tmp/foo1234.c -o /tmp/foo1234.so - generated and executed during the execution of your program-, possibly delete the file /tmp/foo1234.c , since it is no longer needed, and dlopen that /tmp/foo1234.so ( and maybe even delete /tmp/foo1234.so after dlopen ), all in the same process. My GCC MELT plugin for gcc does just that, and so Bigloo , and the GCCJIT library , does something close.
Thus, your quest is impossible and does not even make sense.
Is there any reliable way to get this information without false positives?
No, there is no reliable way to get such information without false positives (you can prove that this is equivalent to a stop problem or some other insoluble problem ). See also Rice theorem .
In practice, most dlopen happens on plugins provided by some configuration. The configuration file cannot be exactly specified as such (for example, some Foo programs may have an agreement similar to a plugin with the name bar in some foo.conf configuration file provided by the foo-bar.so plugin).
However, you may find some heuristic approximation. Most programs running some dlopen have some kind of plugin convention requesting some specific symbol names in the plugin. You can search for common objects that define these names. Of course, you will get false positives.
For example, the zsh shell accepts plugins called zsh modules . example shows that enables_ , boot_ , features_ , etc. functions are expected in zsh modules. You can use nm -D to search for *.so files that support them (therefore, searching for plugins can probably be downloaded using zsh )
(I'm not sure that this approach is worth it, and in fact you should know which plugins are useful for your system, with which applications)
By the way, you can use strace (1) when executing any command to understand the system calls it makes, so plugins are loading. You can also use ltrace (1) or pmap (1) (in any given process) or just use process cat /proc/1234/maps for process cat /proc/1234/maps to understand its virtual address space , so the plugins are already loaded. See proc (5) .
Note that strace , ltrace , pmap exist on Linux, but many POSIX systems have similar programs.
In addition, the program can generate some machine code at runtime and execute it ( SBCL does this with every REPL interaction!). Your program can also use some JIT methods (e.g. libjit , llvm , asmjit , GCCJIT or with handwritten code ...) to do the same. Thus, plugin behavior can occur without dlopen (and you could imitate dlopen with mmap calls and some ELF move handling ).
Additions:
If you install firefox from its packaged version (for example, the iceweasel package on Debian), its package will most likely handle dependencies