1

I am trying to use dlopen() and dlinfo() to get the path my executable. I am able to get the path to a .so by using the handle returned by dlopen() but when I use the handle returned by dlopen(NULL,RTLD_LAZY); then the path I get back is empty.

void* executable_handle = dlopen(0, RTLD_LAZY);
if (nullptr != executable_handle) 
{
    char pp_linkmap[sizeof(link_map)];
    int r = dlinfo(executable_handle, RTLD_DI_LINKMAP, pp_linkmap);
    if (0 == r)
    {
        link_map* plink = *(link_map**)pp_linkmap;
        printf("path: %s\n", plink->l_name);
    }
}

Am I wrong in my assumption that the handle for the executable can be used in the dlinfo functions the same way a .so handle can be used?

tleblanc
  • 13
  • 2
  • 1
    I don't know how to get the path to the actual executable, but I think you complicate it a bit by using a `char[]` as an argument to `dlinfo`. [suggested fix](https://godbolt.org/z/Khvrncd9h) – Ted Lyngmo Jun 07 '21 at 15:14
  • Why not use `argv[0]`? – eerorika Jun 07 '21 at 15:27
  • [related question](https://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe) – Ingo Leonhardt Jun 07 '21 at 15:28
  • This will be called in a library and not from the executable itself. I don't have access to argv[0]. You could argue that argv[0] should be used by the executable if they expect to want the path but I have no control over that. I'm trying to replicate some of the functionality of GetModuleFileName() on linux. – tleblanc Jun 07 '21 at 15:37

2 Answers2

2

Am I wrong in my assumption that the handle for the executable can be used in the dlinfo functions the same way a .so handle can be used?

Yes, you are.

The dynamic linker has no idea which file the main executable was loaded from. That's because the kernel performs all mmaps for the main executable, and only passes a file descriptor to the dynamic loader (who's job it is to load other required libraries and star the executable running).

I'm trying to replicate some of the functionality of GetModuleFileName() on linux

There is no reliable way to do that. In fact the executable may no longer exist anywhere on disk at all -- it's perfectly fine to run the executable and remove the executable file while the program is still running.

Also hard links mean that there could be multiple correct answers -- if a.out and b.out are hard linked, there isn't an easy way to tell whether a.out or b.out was used to start the program running.

Your best options probably are reading /proc/self/exe, or parsing /proc/self/cmdline and/or /proc/self/maps.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • My code currently uses /proc/self/exe but I've seen a lot of places saying that it is unreliable. I guess I will stick with that for now and see if there are ever any problems. Thank you. – tleblanc Jun 07 '21 at 19:08
  • `/proc/self/exe` is indeed the best bet but note that this is *Linux specific* — it won’t work on macOS, nor (I believe) on Mingw. It definitely makes the code unportable. – Konrad Rudolph Jun 07 '21 at 19:10
  • I only need it to work on Linux so that is not a problem for me. Thank you. – tleblanc Jun 08 '21 at 13:48
  • One nit: unlink is not the same as remove. You can certainly unlink an executable while it's running, and the mmap'd pages will remain on disk until they are unmapped. However, you can't remove those pages from the disk unless you load the executable into main memory (either via swapping or simply streaming into memory) without causing problems (Linux AFAIK doesn't allow you to do this anyway). You're right, just potentially confusing if you're not used to how filesystems work. – Qix - MONICA WAS MISTREATED Jun 08 '21 at 16:12
0

The BSD utility library has a function getprogname(3) that does exactly what you want. I'd suggest that is more portable and easier to use than procfs in this case.

James K. Lowden
  • 7,574
  • 1
  • 16
  • 31