#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>

#define LDSO_CACHE_MAGIC "ld.so-"
#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
#define LDSO_CACHE_VER "1.7.0"
#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)

typedef struct {
	char magic[LDSO_CACHE_MAGIC_LEN];
	char version[LDSO_CACHE_VER_LEN];
	int nlibs;
} header_t;

typedef struct {
	int flags;
	int sooffset;
	int liboffset;
} libentry_t;

void cache_lookup(char *, char *);
void cache_lookup(char *cachefile, char *fname)
{
	caddr_t addr;
	struct stat st;
	int fd = 0;
	char *strs;
	header_t *header;
	libentry_t *libent;
    
	if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) < 0)
		return;

	if ((addr = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (caddr_t) - 1)
		return;
    
	close(fd);

	if (memcmp(((header_t *) addr)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
		return;

	if (memcmp (((header_t *) addr)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
		return;

	header = (header_t *) addr;
	libent = (libentry_t *) (addr + sizeof(header_t));
	strs = (char *) &libent[header->nlibs];

	for (fd = 0; fd < header->nlibs; fd++) {
		if (fname != NULL)
			if (strcmp(fname, strs + libent[fd].sooffset) != 0)
				continue;
		printf("%s %s\n", strs + libent[fd].sooffset, strs + libent[fd].liboffset);
	}
	munmap(addr, st.st_size);
}


int main(int argc, char **argv) {
	cache_lookup("/etc/ld.so.cache", (argc > 1 ? argv[1] : NULL));
	return 0;
}
