Justicle
Justicle

Reputation: 15143

Is there a programmatic way to inspect the current rpath on Linux?

I'm aware that it is possible to use readelf -d <elf> | grep RPATH to inspect a given binary from the shell, but is it possible to do this within a process?

Something like (my completely made up system call):

  /* get a copy of current rpath into buffer */
  sys_get_current_rpath(&buffer);

I'm trying to diagnose some suspect SO linking issues in our codebase, and would like to inspect the RPATH this way if possible (I'd rather not have to spawn an external script).

Upvotes: 114

Views: 129939

Answers (6)

Osyotr
Osyotr

Reputation: 1152

If you have patchelf it can also print rpath in a pretty format:

> patchelf --print-rpath /path/to/elf
$ORIGIN:$ORIGIN/../../lib

Upvotes: 3

Employed Russian
Employed Russian

Reputation: 213516

The question is specifically about RPATH, but modern linkers use RUNPATH instead. See this answer -- there is a subtle semantic difference between the two.

The answer is updated to print either.

#include <assert.h>
#include <stdio.h>
#include <elf.h>
#include <link.h>

int main()
{
  const ElfW(Dyn) *dyn = _DYNAMIC;
  const ElfW(Dyn) *rpath = NULL;
  const ElfW(Dyn) *runpath = NULL;
  const char *strtab = NULL;
  for (; dyn->d_tag != DT_NULL; ++dyn) {
    if (dyn->d_tag == DT_RPATH) {
      rpath = dyn;
    } else if (dyn->d_tag == DT_RUNPATH) {
      runpath = dyn;
    } else if (dyn->d_tag == DT_STRTAB) {
      strtab = (const char *)dyn->d_un.d_val;
    }
  }

  assert(strtab != NULL);

  if (rpath != NULL) {
    printf("RPATH: %s\n", strtab + rpath->d_un.d_val);
  } else if (runpath != NULL) {
    printf("RUNPATH: %s\n", strtab + runpath->d_un.d_val);
  }
  return 0;
}

Upvotes: 69

Michael Dillon
Michael Dillon

Reputation: 32392

For the record, here are a couple of commands that will show the rpath / runpath header.

objdump -x binary-or-library |grep 'R.*PATH'

Maybe an even better way to do it is the following:

readelf -d binary-or-library |head -20

The second command also lists the direct dependencies on other libraries followed by rpath.

Upvotes: 199

Daniel
Daniel

Reputation: 307

There is a way. Follow the example code in man dlinfo [1], but use NULL as the first parameter of dlopen().

[1] https://man7.org/linux/man-pages/man3/dlinfo.3.html

Upvotes: 2

Craig Ringer
Craig Ringer

Reputation: 324445

Here's what I use for convenience, as a shell function:

function getrpath {
    eu-readelf -d "${1:?}" | sed -e '/RUNPATH/{s~.*\[\(.*\)\]~\1~;n};d'
}

This consumes eu-readelf output from elfutils like:

Type              Value
NEEDED            Shared library: [libpq.so.5]
NEEDED            Shared library: [libc.so.6]
RUNPATH           Library runpath: [/some/path/to/lib]
....

and emits

 /some/path/to/lib

It should work fine with binutils readelf instead of elfutils eu-readelf too.

Upvotes: 6

Oscar Andreasson
Oscar Andreasson

Reputation: 389

You can also use:

chrpath -l binary-or-library

Upvotes: 23

Related Questions