You can do it with dl_iterate_phdr
.
Example script (for building an example project; run in an empty directory):
#!/bin/sh -eu
cat > main.c <<EOF
void pr_libnm(void);
int main()
{
pr_libnm();
return 0;
}
EOF
cat > pr_libnm.c <<'EOF'
#define _GNU_SOURCE
#include <link.h>
#include <stdio.h>
#include <stdint.h>
static int cb_(struct dl_phdr_info *Info, size_t Sz, void *Data)
{
//printf("Name=%s\n",Info->dlpi_name);
uintptr_t a = (uintptr_t)cb_;
//for each elf-header, iterate thru program headers
for(size_t i=0; i<Info->dlpi_phnum; i++){
// [b,e) is the corresponding segment
uintptr_t b = Info->dlpi_addr + Info->dlpi_phdr[i].p_paddr;
uintptr_t e = b + Info->dlpi_phdr[i].p_memsz;
if(a>=b && a<e){
//if this is cb_'s segment, we're done
printf("NAME=%s\n", Info->dlpi_name);
//nonzero signals end of iteration
return 1;
}
}
return 0;
}
void pr_libnm(void)
{
//iterate thru elf-headers
dl_iterate_phdr(cb_ ,(void*)0);
}
EOF
: ${CC:=gcc}
for c in *.c; do $CC -fpic -c $c; done
$CC -shared -o libpr.so pr_libnm.o
$CC main.o $PWD/libpr.so
./a.out #prints NAME=$PWD/libpr.so
(Naturally, on Unix, a file can have multiple names. You'll just get the name of the shared object that was used to map it.)
dl_iterate_phdr
iterates through the elf headers of the mapped object.
Each elf header contains a pointer to the name of the object.
The program goes through each elf-object's segments and when it finds a segment that a function from the calling shared object maps to, it prints the name from the elf header and exits the iteration.