/*
 *  $Header: /paquetes/postgres/src/port/aix/RCS/dynloader.c,v 1.3 1993/06/10 17:33:26 postgres Exp postgres $
 */


/*
 * Dynamic loader for AIX 3.2.
 *
 * Rafael Morales Gamboa
 * ITESM Campus Morelos
 * Cuernavaca, Mor.
 * MEXICO
 *
 * INTERNET: mr370673@rs970.mor.itesm.mx
 */ 


#include <pwd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/file.h>

#include <a.out.h>
#include <ldfcn.h>
#include <sys/ldr.h>

#include "tmp/c.h"
#include "utils/fmgr.h"


static char *temp_file_name = NULL;
static char *path = "/usr/tmp/postgresXXXXXX";
char command[256];

DynamicFunctionList *
load_symbols(ldp, first_entry)
    LDFILE *ldp;
    char **first_entry;
{
    int text_id = 1;		/* Number of text section in object files. */
    DynamicFunctionList *head, *scanner;
    int entering = 1, func_addr;
    char *funcname;
    SYMENT simb;
    long i;

    for (i = 0; i < HEADER(ldp).f_nsyms; i++)
	if (ldtbread(ldp,i,&simb) != SUCCESS)
	    return NULL;
        else {
	    i += simb.n_numaux;		/* Skip auxiliary entries. */
	    if (simb.n_scnum == text_id	&& simb.n_sclass == C_EXT) {
		if (entering) {
		    head = (DynamicFunctionList *)
			malloc(sizeof(DynamicFunctionList));
		    scanner = head;
		    *first_entry = scanner->funcname;
		    entering = 0;
		}
		else {
		    scanner->next = (DynamicFunctionList *)
			malloc(sizeof(DynamicFunctionList));
		    scanner = scanner->next;
		}
		strncpy(scanner->funcname, ldgetname(ldp,&simb)+1, 16);
		scanner->func = (func_ptr) simb.n_value;
		scanner->next = NULL;
	    }
	}
    return(head);
}


adjust_addresses (list, entry_point)
    DynamicFunctionList *list;
    func_ptr	entry_point;
{
    int	step = 0xC;
    int	inc = 0;

    while (list != NULL) {
	list->func =  (char *) entry_point + inc;
	inc += step;
	list = list->next;
    }
}


DynamicFunctionList *
dynamic_file_load(err, filename, start_addr, size)
    char **err, *filename, **start_addr;
    long *size;
{
    extern char *mktemp();
    FILE *temp_file = NULL;
    DynamicFunctionList *retval = NULL;
    LDFILE	*ldp = NULL;
    int		*entry_point;
    char	*first_entry;

    *start_addr = 0;
    *size = 0;
    
    if ((ldp = ldopen(filename,ldp)) == NULL) {
	*err = "unable to open xcoff file";
	return retval;
    }

    /* Getting the list of functions. After it, the object file es no */
    /* longer examined. */
    retval = load_symbols(ldp, &first_entry);
    ldclose(ldp);

    /* Linking, with first_entry as the entry point. */
    if (temp_file_name == NULL)
       temp_file_name = (char *)malloc(strlen(path) + 1);
    strcpy(temp_file_name,path);
    mktemp(temp_file_name);

    sprintf(command,
	    "ld -e %s -H512 -T512 -bI:/usr/postgres/postgres.exp -bE:%s.exp -o %s  %s -lc -lm -ll",
	    first_entry, filename, temp_file_name, filename);
    if (system(command)) {
	*err = command;
	return retval;
    }

    /* Loading.  The load(3) function returns a pointer to the
       entry point of the loaded program. */

    if ((entry_point = load(temp_file_name,1,"")) != NULL)
	adjust_addresses(retval,entry_point);
    else {
	perror("dynloader");
	*err = "load failed!";
	retval = NULL;
    }
    unlink(temp_file_name);
    return retval;
}

