/*
 * Query soname of shared library.
 * Copyright © 2015 Peter Colberg.
 * Distributed under the MIT license.
 */

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

#define error(fmt, ...) fprintf(stderr, "%s: "fmt"\n", argv[0], ##__VA_ARGS__)

/*
 * For a given symbol name, this program prints the path relative to /
 * of the shared library containing that symbol. The program must be
 * linked against the shared libraries to be queried for symbols, and
 * compiled as a position-independent executable using -fPIE.
 */
int main(int argc, const char *const *argv)
{
  Dl_info info;
  void *sym;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s SYMBOL\n", argv[0]);
    return 1;
  }
  if (!(sym = dlsym(RTLD_DEFAULT, argv[1]))) {
    fprintf(stderr, "%s\n", dlerror());
    return 1;
  }
  if (dladdr(sym, &info) == 0) {
    fprintf(stderr, "%s\n", dlerror());
    return 1;
  }
  if (info.dli_saddr != sym) {
    error("mismatching symbol name: %s", info.dli_sname);
    return 1;
  }
  if (info.dli_fname[0] != '/') {
    error("library name not an absolute path: %s", info.dli_fname);
    return 1;
  }
  printf("%s", info.dli_fname + 1);
  return 0;
}
