How to check what shared libraries are loaded at run time for a given process?
Asked Answered
G

9

75

Is there a way to check which libraries is a running process using?

To be more specific, if a program loads some shared libraries using dlopen, then readelf or ldd is not going to show it. Is it possible at all to get that information from a running process? If yes, how?

Guddle answered 24/2, 2011 at 10:36 Comment(1)
superuser.com/questions/310199/…Realism
D
101

Other people are on the right track. Here are a couple ways.

cat /proc/NNNN/maps | awk '{print $6}' | grep '\.so' | sort | uniq

Or, with strace:

strace CMD.... 2>&1 | grep -E '^open(at)?\(.*\.so'

Both of these assume that shared libraries have ".so" somewhere in their paths, but you can modify that. The first one gives fairly pretty output as just a list of libraries, one per line. The second one will keep on listing libraries as they are opened, so that's nice.

And of course lsof...

lsof -p NNNN | awk '{print $9}' | grep '\.so'
Derrick answered 24/2, 2011 at 11:4 Comment(7)
Also, strace -f is best when child process might be spawnedSawtelle
You can use the /proc/self/maps path where self is a symlink to the current process.Infusive
Some improvements for your strace snippet ... (1) Some systems use the openat() syscall instead of open(), (2) people probably want to see versioned DSOs in addition to the unversioned ones, and (3) bash4 syntax is pretty safe to recommend at this point. strace CMD ... |& grep '^open.*\.so'Ladd
@LukeYeager: Not everyone uses Bash, so I like to keep bashisms out of shell snippets.Derrick
nice answer, fyi, you need to escape the second open paren ( in your strace grep.Dardanus
strace can't show when you open a library via dlopenRealism
@PersianGulf: How does dlopen work, if not by opening the library?Derrick
F
20

May be lsof - the swiss army knife of linux will help?

edit: to run, lsof -p <pid>, lists all sorts of useful information, for example, if the process is java, lists all the open jars - very cool...

Fustanella answered 24/2, 2011 at 10:41 Comment(1)
lsof seams to be the solution. Can you add an example how to call lsof on a process that is already running?Helgoland
T
15

Actually, you can do this in your code in the following way:

#include <link.h>

using UnknownStruct = struct unknown_struct {
   void*  pointers[3];
   struct unknown_struct* ptr;
};
using LinkMap = struct link_map;

auto* handle = dlopen(NULL, RTLD_NOW);
auto* p = reinterpret_cast<UnknownStruct*>(handle)->ptr;
auto* map = reinterpret_cast<LinkMap*>(p->ptr);

while (map) {
  std::cout << map->l_name << std::endl;
  // do something with |map| like with handle, returned by |dlopen()|.
  map = map->l_next;
}

The link_map structure contains at least the base address and the absolute file name. It's the structure that is actually returned by dlopen() with non-NULL first argument. For more details see here.

Trafalgar answered 17/12, 2014 at 9:25 Comment(3)
Ha! So ugly, but it works. Would there be any documentation about the so called "unknown_struct"?Corrida
The same should work with dlinfo() called with RTLD_DI_LINKMAP (see "man dlinfo")Armandinaarmando
This works for me without using the "unknown_struct" #include <link.h> #include <iostream> int main(int argc, char argv[]) { struct link_map map = reinterpret_cast<struct link_map*>(dlopen(NULL, RTLD_NOW)); map = map->l_next->l_next; while (map) { std::cout << map->l_name << std::endl; map = map->l_next; } }Acetabulum
K
12

ltrace seems to be your friend.

From ltrace manual:

ltrace is a program that simply runs the specified command until it exits. It intercepts and records the dynamic library calls which are called by the executed process and the signals which are received by that process. It can also intercept and print the system calls exe‐ cuted by the program.

       Its use is very similar to strace(1).
Kremlin answered 24/2, 2011 at 10:49 Comment(0)
T
7

On Linux, /proc/<processid>/maps contains a list of all the files mapped into memory, which I believe should include any loaded by dlopen().

Trudey answered 24/2, 2011 at 10:54 Comment(0)
O
4

On solaris there is also the pldd command.

Ovipositor answered 24/2, 2011 at 11:18 Comment(2)
Exists on Linux too. Really seems a lot easier than the other proposed commands.Kelwin
On Linux, pldd is part of the glibc package so should be everywhere. But according to its man page it didn't actually work until a few years ago.Boggers
T
3

You can do so programmatically on Linux. You can use the function dl_iterate_phdr.

Here is a small example taken from the man page :

#define _GNU_SOURCE
#include <link.h>
#include <stdlib.h>
#include <stdio.h>

static int
callback(struct dl_phdr_info *info, size_t size, void *data)
{
    int j;

   printf("name=%s (%d segments)\n", info->dlpi_name,
        info->dlpi_phnum);

   for (j = 0; j < info->dlpi_phnum; j++)
         printf("\t\t header %2d: address=%10p\n", j,
             (void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr));
    return 0;
}

int
main(int argc, char *argv[])
{
    dl_iterate_phdr(callback, NULL);

   exit(EXIT_SUCCESS);
}
Tow answered 18/9, 2019 at 13:55 Comment(0)
E
2

Would strace trace the library file being opened?

Enamour answered 24/2, 2011 at 10:43 Comment(0)
D
0

The question is whether you want to know it about a foreign process:

$ sleep 1h&p=$!;sleep 0.1;gdb -p $p -batch -ex 'info shared'
[1] 637756
...
From                To                  Syms Read   Shared Object Library
0x00007f795ffc4700  0x00007f7960135aed  Yes         /lib64/libc.so.6
0x00007f79601cc0a0  0x00007f79601f2d35  Yes         /lib64/ld-linux-x86-64.so.2
[Inferior 1 (process 637756) detached]

Or about your own process:

#include <iostream>
#include <link.h>
#include <cassert>
#include <dlfcn.h>
int main() {
  // prevent R_X86_64_COPY and r_state inconsistency if we accessed "_r_debug" directly.
  r_debug *debug = (r_debug *) dlsym(RTLD_DEFAULT, "_r_debug");
  assert(debug);
  assert(debug->r_version == 1);
  assert(debug->r_state == r_debug::RT_CONSISTENT);
  link_map *prev = NULL;
  for (link_map *map = debug->r_map; map; prev = map, map = map->l_next) {
    assert(map->l_prev == prev);
    std::cout << map << " " << (!map->l_name[0] ? "<empty>" : map->l_name) << std::endl;
  }
}
Disgruntle answered 2/6, 2022 at 8:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.