/*
 * %W% revision of %E%  %U%
 * This is an unpublished work copyright (c) 1993 HELIOS Software GmbH
 * 30827 Garbsen, Germany
 */

/*
 * ldd.c - List dynamic dependencies. Performs a similar function as the
 *	   SunOS or System V.4 ldd command. This one works by loading the
 *	   target program through load() and then printing all loaded
 *	   modules as returned by loadquery().
 *
 * To compile:
 * 	xlc -D_ALL_SOURCE -o ldd -O ldd.c -bnoso -bI:/usr/lib/syscalls.exp
 */

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ldr.h>

void errxit(char *);

int main(int argc, char **argv)
{
	struct ld_info *lp;
	char *buf;
	int size = 4*1024;
	int i;
	
	if (argc != 2) {
		fprintf(stderr, "Usage: %s program\n", argv[0]);
		exit(1);
	}
	if (load(argv[1], 0, NULL) == NULL) {
		char *buffer[1024];
		if (errno != ENOEXEC)
			errxit(argv[1]);
		buffer[0] = "execerror";
		buffer[1] = argv[1];
		loadquery(L_GETMESSAGES, &buffer[2], sizeof(buffer)-8);
		execvp("/usr/sbin/execerror", buffer);
		errxit("execerror");
	}
	if ((buf = malloc(size)) == NULL)
		errxit("malloc");
	while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
		free(buf);
		size += 4*1024;
		if ((buf = malloc(size)) == NULL)
			errxit("malloc");
	}
	if (i == -1)
		errxit("loadquery");
	lp = (struct ld_info *)buf;
	while (lp) {
		/*
		 * Skip over ourselves. The main part is always the first
		 * in the list of loaded modules.
		 */
		if (lp != (struct ld_info *)buf) {
			char *fileName = lp->ldinfo_filename;
			char *memberName = fileName + strlen(fileName) + 1;
			printf("%s", fileName);
			if (*memberName)
				printf("(%s)", memberName);
			printf("\n");
		}
		if (lp->ldinfo_next == 0)
			lp = NULL;
		else
			lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
	}
	free(buf);
	return 0;
}

void errxit(char *s)
{
	perror(s);
	exit(1);
}
