File dynamic_load.c¶
File List > base > dynamic_load.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* dynamic_load.c - Dynamic loader for run-time inclusion of object code
*/
#ident "$Id$"
#include "config.h"
#if !defined(SOLARIS) && !defined(LINUX)
#include <a.out.h>
#if defined(sun) || defined(sparc)
#include <sys/mman.h> /* for mprotect() */
#include <malloc.h> /* for valloc() */
#endif /* defined(sun) || defined(sparc) */
#endif /* !(SOLARIS) && !(LINUX) */
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <ar.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#ifdef HAVE_VFORK
#include <vfork.h>
#endif /* HAVE_VFORK */
#include <assert.h>
#include "porting.h"
#include "intl_support.h"
#include "dynamic_load.h"
#include "error_manager.h"
#include "memory_alloc.h"
#include "environment_variable.h"
#include "system_parameter.h"
#include "util_func.h"
#if defined(_AIX)
#define N_BADMAG(x) \
((x).magic != 0x107 && (x).magic != 0x108 && (x).magic != 0x10b)
#elif defined(HPUX)
#define N_BADMAG(x) \
((x).a_magic != RELOC_MAGIC && /* relocatable only */ \
(x).a_magic != EXEC_MAGIC && /* normal executable */ \
(x).a_magic != SHARE_MAGIC && /* shared executable */ \
(x).a_magic != DL_MAGIC) /* dynamic load library */
#endif /* _AIX */
#define FNAME_TBL_SIZE 127
#define DEBUG
#ifdef DEBUG
#define TEMPNAM(d,p) dl_get_temporary_name((d), (p), __LINE__)
#define OPEN(fn, m) dl_open_object_file((fn), (m), __LINE__)
#define CLOSE(fd) dl_close_object_file((fd), __LINE__)
#define PIPE(fd) dl_open_pipe((fd), __LINE__)
#endif /* DEBUG */
#ifndef TEMPNAM
#define TEMPNAM tempnam
#endif /* TEMPNAM */
#ifndef OPEN
#define OPEN open
#endif /* OPEN */
#ifndef CLOSE
#define CLOSE close
#endif /* CLOSE */
#ifndef PIPE
#define PIPE pipe
#endif /* PIPE */
#ifndef FORK
#ifdef HAVE_VFORK
#define FORK vfork
#else /* HAVE_VFORK */
#define FORK fork
#endif /* HAVE_VFORK */
#endif /* FORK */
#define DL_SET_ERROR_WITH_CODE(code) \
er_set(ER_ERROR_SEVERITY, \
ARG_FILE_LINE, \
dl_Errno = (code), \
0)
#define DL_SET_ERROR_WITH_CODE_ONE_ARG(code, arg) \
er_set(ER_ERROR_SEVERITY, \
ARG_FILE_LINE, \
dl_Errno = (code), \
1, \
(arg))
#define DL_SET_ERROR_SYSTEM_MSG() \
er_set(ER_ERROR_SEVERITY, \
ARG_FILE_LINE, \
dl_Errno = ER_DL_ESYS, \
1, \
dl_get_system_error_message(errno))
#define DL_SET_ERROR_SYSTEM_FILENAME(fn) \
er_set(ER_ERROR_SEVERITY, \
ARG_FILE_LINE, \
dl_Errno = ER_DL_EFILE, \
2, \
(fn), \
dl_get_system_error_message(errno))
typedef void (*FUNCTION_POINTER_TYPE) (void);
typedef struct tbl_link TBL_LINK;
typedef struct file_entry FILE_ENTRY;
typedef struct dynamic_loader DYNAMIC_LOADER;
struct tbl_link
{
char *filename;
const TBL_LINK *link;
};
struct file_entry
{
char *filename;
bool valid;
bool archive;
bool duplicate;
size_t size;
};
struct dynamic_loader
{
bool virgin; /* true if the loader has ever been used */
struct
{
FILE_ENTRY *entries; /* descriptors for each file to be loaded */
int num; /* size of candidates */
} candidates;
int num_need_load; /* files that haven't already been loaded */
TBL_LINK *loaded[FNAME_TBL_SIZE]; /* names of loaded object files. */
pid_t (*fork_function_p) (); /* forking function to use (fork or vfork) */
struct
{
int daemon_fd; /* The file descriptor of the pipe used to communicate with the daemon. -1 for
* unspawned daemon, -2 for broken daemon, greater than 0 for operating daemon. */
char daemon_name[PATH_MAX]; /* The name of the process to be exec'ed as the daemon to scavenge tmpfiles. */
} daemon;
#if defined (SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
struct
{
void **handles; /* An array of handles to the shared objects */
int top; /* the next handle to be allocated */
int num; /* the total number of handles in the array */
} handler;
#endif /* SOLARIS || HPUX || LINUX */
struct
{
const char *cmd; /* The pathname of the ld command to be used to link the object files. */
caddr_t *ptr; /* pointers to chunks VALLOC'ed to hold the text and data loaded int num; */
int num;
} loader;
const char *image_file; /* The name of the file that holds the up-to-date symbol table info */
};
int dl_Errno = NO_ERROR;
/* There should only be one loader extant at any one time; */
static DYNAMIC_LOADER *dl_Loader = NULL;
/* set DL_DEBUG for debugging actions. */
static int dl_Debug = 0;
#if (defined(sun) || defined(sparc))&& !defined(SOLARIS)
static const char *dl_Default_libs[] = {
"-lm",
"-lc",
NULL
};
#endif /* ((sun) || (sparc))&& !(SOLARIS) */
static const int MAX_UNLINK_RETRY = 15;
static const int DAEMON_NOT_SPAWNED = -1;
static const int DAEMON_NOT_AVAILABLE = -2;
static const char DAEMON_NAME[] = "dl_daemon";
/* number of handles to allocate per extent */
static const int HANDLES_PER_EXTENT = 10;
#if defined(sun) || defined(sparc)
static const char DEFAULT_LD_NAME[] = "/bin/ld";
#elif defined(_AIX)
/* this space intentionally blank */
#elif defined(HPUX)
/* this space intentionally blank */
#elif defined(SOLARIS)
/* this space intentionally blank */
#elif defined(LINUX)
/* this space intentionally blank */
#endif /* (sun) || (sparc) */
#ifdef DEBUG
static int dl_open_object_file (const char *filename, int mode, int lineno);
static int dl_close_object_file (int fd, int lineno);
#endif /* DEBUG */
static void dl_destroy_candidates (DYNAMIC_LOADER *);
static int dl_validate_file_entry (FILE_ENTRY *, const char *);
static int dl_initiate_dynamic_loader (DYNAMIC_LOADER *, const char *);
static void dl_destroy_dynamic_loader (DYNAMIC_LOADER *);
static int dl_validate_candidates (DYNAMIC_LOADER *, const char **);
static void dl_find_daemon (DYNAMIC_LOADER *);
static void dl_record_files (DYNAMIC_LOADER *);
static int dl_is_valid_image_file (DYNAMIC_LOADER *);
static int dl_resolve_symbol (DYNAMIC_LOADER *, struct nlist *);
#if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
static void dl_notify_daemon (DYNAMIC_LOADER *);
static void dl_spawn_daemon (DYNAMIC_LOADER *);
static void dl_set_pipe_handler (void);
static void dl_set_new_image_file (DYNAMIC_LOADER *, const char *);
static int dl_set_new_load_points (DYNAMIC_LOADER * this_, const caddr_t);
static int dl_load_object_image (caddr_t, const char *);
static const char **dl_parse_extra_options (int *num_options, char *option_string);
static void dl_decipher_waitval (int waitval);
#ifdef DEBUG
static char *dl_get_temporary_name (const char *dir, const char *prefix, int lineno);
static int dl_open_pipe (int *fd, int lineno);
#endif /* DEBUG */
#endif /* !(SOLARIS) && !(HPUX) && !(LINUX) && !(AIX) */
#if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
static size_t dl_get_image_file_size (const char *);
static int dl_link_file (DYNAMIC_LOADER *, const char *, caddr_t, const char **);
static int dl_load_objects (DYNAMIC_LOADER *, size_t *, const char **, const char **, const size_t,
enum dl_estimate_mode);
#elif defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
static int dl_load_objects (DYNAMIC_LOADER *, const char **);
#else /* ((sun) || (sparc)) && !(SOLARIS) */
#error "Unknown machine type."
#endif /* ((sun) || (sparc)) && !(SOLARIS) */
static const char *
dl_get_system_error_message (int n)
{
return (strerror (n));
}
#ifdef DEBUG
#if ((defined(sun) || defined(sparc))&& !defined(SOLARIS))
static char *
dl_get_temporary_name (const char *dir, const char *prefix, int lineno)
{
char *result;
result = tempnam (dir, prefix);
if (dl_Debug)
{
fprintf (stderr, "%s[%d]: tempnam(", __FILE__, lineno);
if (dir)
{
fprintf (stderr, "\"%s\", ", dir);
}
else
{
fputs ("NULL, ", stderr);
}
if (prefix)
{
fprintf (stderr, "\"%s\") => ", prefix);
}
else
{
fputs ("NULL) => ", stderr);
}
fprintf (stderr, "\"%s\" (0x%p)\n", result, result);
fflush (stderr);
}
return result;
}
#endif /* (((sun) || (sparc))&& !(SOLARIS)) */
static int
dl_open_object_file (const char *filename, int mode, int lineno)
{
int fd;
if (dl_Debug)
{
fprintf (stderr, "%s[%d]: attempting to open %s...", __FILE__, lineno, filename);
}
fd = open (filename, mode, 0111);
if (dl_Debug)
{
if (fd == -1)
{
fputs ("failed\n", stderr);
}
else
{
fprintf (stderr, "succeeded on fd %d\n", fd);
}
}
return fd;
}
static int
dl_close_object_file (int fd, int lineno)
{
if (dl_Debug)
{
fprintf (stderr, "%s[%d]: closing fd %d\n", __FILE__, lineno, fd);
}
return close (fd);
}
#endif /* DEBUG */
#if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
/*
* dl_decipher_waitval() - decipher exit status
* return: none
* waitval(in): exit status
*/
static void
dl_decipher_waitval (int waitval)
{
#ifdef __GNUG__
/* Because of some idiocy in the GNU header files, we have to recreate some stupid overriding #define before
* WIFEXITED and friends will work. Who thinks of this stuff? */
#define wait WaitStatus
#endif /* __GNUG__ */
if (WIFEXITED (waitval))
{
if (WEXITSTATUS (waitval))
{
DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_LDEXIT, WEXITSTATUS (waitval));
}
else
{
dl_Errno = NO_ERROR;
}
}
else if (WIFSIGNALED (waitval))
{
/*
* Child terminated by signal.
*/
DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_LDTERM, WTERMSIG (waitval));
}
else
{
if (dl_Debug)
{
fprintf (stderr, "dynamic loader: unknown wait status = 0x%x\n", waitval);
}
DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_LDWAIT, waitval);
}
#ifdef __GNUG__
#undef wait
#endif /* __GNUG__ */
}
#endif /* !SOLARIS && !HPUX && !LINUX && !AIX */
/*
* dl_destroy_candidates()
* return: none
* this_(in): DYNAMIC_LOADER structure pointer
*
* Note: If it has been put in the FILE_ENTRY table, we leave the responsibility
* of freeing the string to the table.
*/
static void
dl_destroy_candidates (DYNAMIC_LOADER * this_)
{
int i;
assert (this_ != NULL);
for (i = 0; i < this_->candidates.num; ++i)
{
FILE_ENTRY *fe = &this_->candidates.entries[i];
if (fe->filename)
{
if (!fe->valid || fe->duplicate || fe->archive)
{
free_and_init (fe->filename);
}
}
}
if (this_->candidates.entries)
{
free_and_init (this_->candidates.entries);
}
this_->candidates.entries = NULL;
this_->candidates.num = 0;
this_->num_need_load = 0;
}
/*
* dl_validate_file_entry() - Make sure that the file is usable
* return: Zero on valid, non-zero on invalid
* this_(out): save validation result
* filename(in): file name to validate
*/
static int
dl_validate_file_entry (FILE_ENTRY * this_, const char *filename)
{
char pathbuf[PATH_MAX];
#if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
#define AR_MAGIC_STR ARMAG
#define AR_MAGIC_STR_SIZ SARMAG
char ar_magic[AR_MAGIC_STRING_SIZ];
struct exec hdr;
#elif defined(_AIX)
#define AR_MAGIC_STR AIAMAG
#define AR_MAGIC_STR_SIZ SAIAMAG
char ar_magic[AR_MAGIC_STR_SIZ];
struct aouthdr hdr;
#endif /* ((sun) || (sparc)) && !(SOLARIS) */
int fd;
assert (this_ != NULL);
dl_Errno = NO_ERROR;
fd = OPEN (filename, O_RDONLY);
if (fd == -1)
{
DL_SET_ERROR_SYSTEM_FILENAME (filename);
}
else
{
if (realpath ((char *) filename, pathbuf) == NULL)
{
DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_PATH, filename);
}
else if ((this_->filename = strdup ((char *) filename)) == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
}
else
{
#if defined (SOLARIS) || defined (HPUX) || defined(LINUX)
this_->archive = false;
this_->size = 0; /* we rely on dlopen to catch any errors. */
#else /* SOLARIS || HPUX || LINUX */
#if defined(sun) || defined(sparc) || defined(_AIX)
#if defined(_AIX)
if (lseek (fd, sizeof (struct filehdr), SEEK_SET) < 0)
{ /* See <xcoff.h> for the layout of the file. */
DL_SET_ERROR_SYSTEM_MSG ();
}
else
#endif /* _AIX */
if (read (fd, (char *) &hdr, sizeof (hdr)) == sizeof (hdr) && !N_BADMAG (hdr))
{
this_->archive = false;
#if defined(sun) || defined(sparc)
this_->size = hdr.a_text + hdr.a_data + hdr.a_bss;
#endif /* sun || sparc */
}
else
{
(void) lseek (fd, 0, 0);
if (read (fd, ar_magic, AR_MAGIC_STR_SIZ) == AR_MAGIC_STR_SIZ)
{
if (strncmp (ar_magic, AR_MAGIC_STR, AR_MAGIC_STR_SIZ) == 0)
{
this_->archive = true;
this_->size = 0;
}
}
else
{
#if defined(_AIX) && defined(gcc)
this_->archive = false;
#else
DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_BADHDR, this_->filename);
#endif /* _AIX && gcc */
}
}
#endif /* sun || sparc || _AIX */
#endif /* SOLARIS || HPUX || LINUX || _AIX */
}
CLOSE (fd);
}
this_->valid = (dl_Errno == NO_ERROR);
if (this_->valid)
return NO_ERROR;
return ER_FAILED;
}
/*
* dl_initiate_dynamic_loader() - builds up dynamic loader
* return: Zero on success, non-zero on failure
* this_(out): information structure of dynamic loader
* original(in): original image file
*/
static int
dl_initiate_dynamic_loader (DYNAMIC_LOADER * this_, const char *original)
{
int i;
assert (this_ != NULL);
if (dl_Debug)
{
fprintf (stderr, "%s[%d]: dynamic loader being built\n", __FILE__, __LINE__);
}
this_->virgin = true;
this_->candidates.entries = NULL;
this_->candidates.num = 0;
this_->num_need_load = 0;
for (i = 0; i < FNAME_TBL_SIZE; i++)
{
this_->loaded[i] = NULL;
}
if (prm_get_string_value (PRM_ID_DL_FORK))
{
if (strcmp (prm_get_string_value (PRM_ID_DL_FORK), "fork") == 0)
{
this_->fork_function_p = ⋔
}
#if defined(HAVE_VFORK)
else if (strcmp (prm_get_string_value (PRM_ID_DL_FORK), "vfork") == 0)
{
this_->fork_function_p = &vfork;
}
#endif /* HAVE_VFORK */
else
{
this_->fork_function_p = (pid_t (*)())NULL;
}
}
else
{
this_->fork_function_p = &FORK;
}
this_->daemon.daemon_fd = DAEMON_NOT_SPAWNED;
#if defined (SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
this_->handler.handles = (void **) malloc (HANDLES_PER_EXTENT * sizeof (void *));
if (this_->handler.handles == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
return ER_FAILED;
}
this_->handler.top = 0;
this_->handler.num = HANDLES_PER_EXTENT;
for (i = 0; i < this_->handler.num; i++)
{
this_->handler.handles[i] = 0;
}
#endif /* SOLARIS || HPUX || LINUX || AIX */
this_->loader.cmd = NULL;
this_->loader.ptr = NULL;
this_->loader.num = 0;
this_->image_file = original;
#if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
this_->loader.cmd = DEFAULT_LD_NAME; /* use the default name. */
#endif /* !(SOLARIS) && !(HPUX) && !(LINUX) && !(AIX) */
if (dl_Errno == NO_ERROR)
{
dl_find_daemon (this_);
}
return dl_Errno;
}
static void
dl_destroy_dynamic_loader (DYNAMIC_LOADER * this_)
{
int i, tbl_size;
assert (this_ != NULL);
#if defined (SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
for (i = 0; i < this_->handler.top; i++)
{
#if defined(HPUX)
shl_unload (this_->handler.handles[i]);
#else /* HPUX */
(void) dlclose (this_->handler.handles[i]);
#endif /* HPUX */
}
free_and_init (this_->handler.handles);
this_->handler.top = this_->handler.num = 0;
#endif /* SOLARIS || HPUX || LINUX */
for (i = 0, tbl_size = FNAME_TBL_SIZE; i < tbl_size; i++)
{
TBL_LINK *tp, *next_tp;
for (tp = this_->loaded[i]; tp; tp = next_tp)
{
next_tp = (TBL_LINK *) tp->link;
free_and_init (tp->filename);
free_and_init (tp);
}
}
if (this_->loader.ptr)
{
for (i = 0, tbl_size = this_->loader.num; i < tbl_size; ++i)
{
#if (defined(sun) || defined(sparc) ) && !defined(SOLARIS)
free (this_->loader.ptr[i]); /* Use free because the storage was allocated by VALLOC */
#endif /* ((sun) || (sparc)) && !(SOLARIS) */
}
free_and_init (this_->loader.ptr);
}
#if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
if (!this_->virgin)
{
(void) unlink (this_->image_file);
}
free ((char *) this_->image_file); /* Don't use free_and_init(), image_file came from exec_path */
#endif /* !SOLARIS && !HPUX && !LINUX && !AIX */
if (this_->daemon.daemon_fd >= 0)
{
CLOSE (this_->daemon.daemon_fd);
}
if (dl_Debug)
{
fprintf (stderr, "%s[%d]: dynamic loader torn down\n", __FILE__, __LINE__);
}
}
/*
* dl_validate_candidates() - initiate and validate file entry
* return: Zero on success, non-zero on failure
* filenames(in): file names of candidates
* this_(in): DYNAMIC_LOADER structure pointer
*/
static int
dl_validate_candidates (DYNAMIC_LOADER * this_, const char **filenames)
{
int i;
const char **fname;
assert (filenames != NULL);
this_->num_need_load = 0;
for (fname = filenames, this_->candidates.num = 0; *fname; ++fname)
{
/* how many candidates we're considering. */
++this_->candidates.num;
}
if (dl_Debug)
{
fprintf (stderr, "Number of candidates = %d\n", this_->candidates.num);
}
if (this_->candidates.num == 0)
{
return NO_ERROR;
}
this_->candidates.entries = (FILE_ENTRY *) malloc (this_->candidates.num * sizeof (FILE_ENTRY));
if (this_->candidates.entries == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
goto cleanup;
}
for (i = 0; i < this_->candidates.num; i++)
{
memset (&this_->candidates.entries[i], 0, sizeof (FILE_ENTRY));
}
for (i = 0; i < this_->candidates.num; ++i)
{
if (dl_validate_file_entry (&this_->candidates.entries[i], filenames[i]))
{
/* Perform individual validation on each. Give up if any fail. */
if (dl_Debug)
{
fprintf (stderr, "dl_validate_file_entry failed on %s\n", filenames[i]);
}
goto cleanup;
}
}
for (i = 0; i < this_->candidates.num; ++i)
{
if (!this_->candidates.entries[i].archive)
{
const char *path;
const TBL_LINK *tbl_p;
int j;
path = this_->candidates.entries[i].filename;
tbl_p = this_->loaded[hashpjw (path) % FNAME_TBL_SIZE];
for (; tbl_p; tbl_p = tbl_p->link)
{
/* look in the table of already-loaded files */
if (strcmp (tbl_p->filename, path) == 0)
{
this_->candidates.entries[i].duplicate = true;
if (dl_Debug)
{
fprintf (stderr, "Duplicate: %s\n", path);
}
continue;
}
}
for (j = 0; j < i; ++j)
{
/* make sure that it hasn't already appeared in the current list of candidates */
if (strcmp (this_->candidates.entries[j].filename, path) == 0)
{
this_->candidates.entries[i].duplicate = true;
if (dl_Debug)
{
fprintf (stderr, "Duplicate: %s\n", path);
}
continue;
}
}
/* we record the fact that we need to load it. */
++this_->num_need_load;
}
}
cleanup:
if (dl_Debug)
{
fprintf (stderr, "Number needed to load (nneed) = %d\n", this_->num_need_load);
}
if (dl_Errno == NO_ERROR)
return NO_ERROR;
return ER_FAILED;
}
#if (defined(sun) || defined(sparc) ) && !defined(SOLARIS)
/*
* dl_get_image_file_size() - get static size requirements
* return: Returns -1 if anything goes wrong.
* filename(in): image file name
*/
static size_t
dl_get_image_file_size (const char *filename)
{
struct exec hdr;
int fd;
size_t size = (size_t) - 1;
assert (filename != NULL);
fd = OPEN (filename, O_RDONLY);
if (fd == -1)
{
DL_SET_ERROR_SYSTEM_FILENAME (filename);
}
else
{
if (read (fd, (char *) &hdr, sizeof (hdr)) != sizeof (hdr) || N_BADMAG (hdr))
{
DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_BADHDR, filename);
}
else
{
size = hdr.a_text + hdr.a_data + hdr.a_bss;
}
if (dl_Debug)
{
fprintf (stderr, "%s[%d]: closing fd %d\n", __FILE__, __LINE__, fd);
}
CLOSE (fd);
}
return size;
}
#endif /* ((sun) || (sparc)) && !(SOLARIS) */
/*
* dl_find_daemon() - Discover the pathname for the daemon process.
* return: none
*
* Note: DL_DAEMON env-variable is used.
* If we can't find the daemon, we simply set daemon_fd to DAEMON_NOT_AVAILABLE.
*/
static void
dl_find_daemon (DYNAMIC_LOADER * this_)
{
char *path;
assert (this_ != NULL);
path = this_->daemon.daemon_name;
if (path != NULL)
{
envvar_bindir_file (path, PATH_MAX, DAEMON_NAME);
if (path[0] != '\0')
{
if (access (path, X_OK) == 0)
{
return;
}
}
this_->daemon.daemon_name[0] = '\0';
}
this_->daemon.daemon_fd = DAEMON_NOT_AVAILABLE;
if (dl_Debug)
{
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_DL_DAEMON_MISSING, 0);
}
}
#if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
/*
* dl_parse_extra_options() - Break up a string of options into a vector
* return: options vector
* returns a NULL pointer and sets *noptions to -1 if a problem arises
* num_options(out): number of options
* option_string(in): string of options
*/
static const char **
dl_parse_extra_options (int *num_options, char *option_string)
{
const char **option_vec = NULL;
const char *option = NULL;
char *save;
int i = 0, opt_cnt = 0;
for (option = (const char *) strtok_r (option_string, " \t", &save); option;
option = (const char *) strtok_r ((char *) NULL, " \t", &save))
{
const char **new_vec = NULL;
opt_cnt += sizeof (const char *);
if (option_vec)
{
new_vec = realloc (option_vec, opt_cnt);
}
else
{
new_vec = malloc (opt_cnt);
}
if (new_vec == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
if (option_vec)
{
free_and_init (option_vec);
}
*num_options = -1;
return NULL;
}
option_vec = new_vec;
option_vec[i++] = option;
}
*num_options = i;
return option_vec;
}
#endif /* !SOLARIS && !HPUX && !LINUX && !AIX */
#if !defined (SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(AIX)
/*
* dl_link_file() - Builds up a "command line" which is then forked via execv()
* return: Zero on success, non-zero on failure
* this_(in): DYNAMIC_LOADER structure pointer
* tmp_file(in): temporary file name to be passed to ld
* load_point(in): load point to be passed to ld
* syms(in): symbols to be used as Export and Import lists(AIX)
* libs(in): array of arguments to be passed to ld
* Note : You can pass extra parameters to ld with DL_LD_OPTIONS env-variable
*/
#if defined(sun) || defined(sparc)
static int
dl_link_file (DYNAMIC_LOADER * this_, const char *tmp_file, caddr_t load_point, const char **libs)
#endif /* (sun) || (sparc) */
{
int num_libs = 0;
const char **p;
char *extra_options;
const char **option_vec = (const char **) NULL;
int num_options = 0;
int argc = 0;
const char **argv, **argvp;
char load_point_buf[16];
int i;
pid_t pid = 0;
extra_options = (char *) getenv ("DL_LD_OPTIONS"); /* to be passed to ld */
if (extra_options)
{
extra_options = strdup (extra_options);
if (extra_options == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
}
option_vec = dl_parse_extra_options (&num_options, extra_options);
}
for (p = libs; *p; p++)
{
num_libs++; /* count libray parameters */
}
#if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
/* ld -N -A <image_file> -T <load_point> -o <tmp_file> <...obj_files...> <...libs...> */
argc = 8 + this_->candidates.num + num_libs + num_options;
#endif /* ((sun) || (sparc)) && !(SOLARIS) */
argv = malloc (sizeof (const char *) * (argc + 1));
if (argv == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
goto end_link_file;
}
argvp = argv;
*argvp++ = this_->loader.cmd;
#if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
*argvp++ = "-N";
*argvp++ = "-A";
*argvp++ = this_->image_file;
*argvp++ = "-T";
/* TODO : consider LP64 */
(void) sprintf (load_point_buf, "%p", load_point);
*argvp++ = load_point_buf;
*argvp++ = "-o";
*argvp++ = tmp_file;
#endif /* ((sun) || (sparc)) && !(SOLARIS) */
for (i = 0; i < this_->candidates.num; ++i)
{
if (this_->candidates.entries[i].valid && !this_->candidates.entries[i].duplicate)
{
*argvp++ = this_->candidates.entries[i].filename;
}
}
for (i = 0; i < num_options; ++i)
{
*argvp++ = option_vec[i];
}
for (p = libs; *p;)
{
*argvp++ = *p++;
}
*argvp++ = NULL;
if (dl_Debug)
{
const char **p;
fprintf (stderr, "%s[%d]: ", __FILE__, __LINE__);
for (p = argv; *p; ++p)
{
fputs (*p, stderr);
fputc (' ', stderr);
}
fputc ('\n', stderr);
fflush (stderr);
}
pid = (pid_t) (*this_->fork_function_p) ();
if (pid)
{
/* This is the parent process, pid is the child */
int waitval;
if (pid == -1 || waitpid (pid, &waitval, 0) == -1)
{
DL_SET_ERROR_SYSTEM_MSG ();
}
else
{
dl_decipher_waitval (waitval);
}
}
else
{
/* This is the child process - do the exec */
execv ((char *) argv[0], (char **) &argv[0]);
DL_SET_ERROR_SYSTEM_MSG ();
_exit (1);
}
end_link_file:
if (extra_options)
free_and_init (extra_options);
if (option_vec)
free_and_init (option_vec);
free_and_init (argv);
return dl_Errno;
}
#endif /* !SOLARIS && !HPUX && !LINUX && !AIX */
#if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
/*
* dl_load_object_image()
* return: Zero on success, non-zero on failure
* load_point(out): buffer to receive object image
* image_file(in): image file name
*/
static int
dl_load_object_image (caddr_t load_point, const char *image_file)
{
struct exec hdr;
size_t size = 0;
int fd = OPEN (image_file, O_RDONLY);
dl_Errno = NO_ERROR;
if (fd == -1)
{
DL_SET_ERROR_SYSTEM_FILENAME (image_file);
goto cleanup;
}
if (read (fd, (char *) &hdr, sizeof (hdr)) != sizeof (hdr))
{
DL_SET_ERROR_SYSTEM_FILENAME (image_file);
goto cleanup;
}
if (N_BADMAG (hdr))
{
DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_BADHDR, image_file);
goto cleanup;
}
if (lseek (fd, N_TXTOFF (hdr), 0) == -1)
{
DL_SET_ERROR_SYSTEM_FILENAME (image_file);
goto cleanup;
}
size = hdr.a_text + hdr.a_data;
if (read (fd, load_point, size) != size)
{
DL_SET_ERROR_SYSTEM_FILENAME (image_file);
goto cleanup;
}
cleanup:
if (fd != -1)
{
CLOSE (fd);
}
if (dl_Errno == NO_ERROR)
return NO_ERROR;
return ER_FAILED;
}
#endif /* ((sun) || (sparc)) && !(SOLARIS) */
#if ((defined(sun) || defined(sparc)) && !defined(SOLARIS))
#if defined(DEBUG)
static int
dl_open_pipe (int *fd, int lineno)
{
int result = pipe (fd);
if (dl_Debug)
{
if (result == -1)
{
fprintf (stderr, "%s[%d]: pipe creation failed\n", __FILE__, lineno);
}
else
{
fprintf (stderr, "%s[%d]: pipe created on fds %d and %d\n", __FILE__, lineno, fd[0], fd[1]);
}
}
return result;
}
#endif /* DEBUG */
static void
dl_set_pipe_handler (void)
{
void (*old_handler) () = signal (SIGPIPE, SIG_IGN);
if (old_handler != SIG_DFL && old_handler != SIG_IGN)
{
signal (SIGPIPE, old_handler); /* restore old handler */
}
}
/*
* dl_spawn_daemon() - Forks a separate process that waits around to clean up
* any tmpfiles that we fail to close(because we abort, for example)
*/
static void
dl_spawn_daemon (DYNAMIC_LOADER * this_)
{
int fd[2];
int daemon_pid;
assert (this_ != NULL);
if (this_->daemon.daemon_fd != DAEMON_NOT_SPAWNED)
{
return;
}
if (PIPE (fd) == -1)
{ /* pipe creation failed */
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_DL_DAEMON_MISSING, 0);
this_->daemon.daemon_fd = DAEMON_NOT_AVAILABLE;
return;
}
if (dl_Debug)
{
fprintf (stderr, "%s[%d]: spawning %s on fds %d and %d\n", __FILE__, __LINE__, this_->daemon.daemon_name, fd[0],
fd[1]);
fflush (stderr);
}
daemon_pid = (*this_->fork_function_p) ();
if (daemon_pid)
{
/* This is the parent process. */
if (daemon_pid == -1)
{
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_DL_DAEMON_MISSING, 0);
CLOSE (fd[0]);
CLOSE (fd[1]);
this_->daemon.daemon_fd = DAEMON_NOT_AVAILABLE;
return;
}
dl_set_pipe_handler ();
CLOSE (fd[0]);
this_->daemon.daemon_fd = fd[1]; /* write side of the pipe */
}
else
{
/* This is the child process. */
int i;
if (dup2 (fd[0], 0) == -1) /* read side of the pipe */
{
_exit (1);
}
for (i = 1; i < NOFILE; ++i)
{
close (i); /* Close all file descriptors except stdin */
}
execl (this_->daemon.daemon_name, (char *) 0);
_exit (1);
}
}
/*
* dl_notify_daemon() - Let the daemon know that we have let loose of
* the current tmpfile and are now using a new one.
*/
static void
dl_notify_daemon (DYNAMIC_LOADER * this_)
{
int num_chars;
assert (this_ != NULL);
num_chars = strlen (this_->image_file) + 1; /* include null */
if (this_->daemon.daemon_fd == DAEMON_NOT_SPAWNED)
{
/* Start a daemon if we haven't tried already. */
dl_spawn_daemon (this_);
}
if (this_->daemon.daemon_fd >= 0)
{
if (write (this_->daemon.daemon_fd, this_->image_file, num_chars) != num_chars)
{
if (dl_Debug)
{
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_DL_DAEMON_DISAPPEARED, 0);
}
this_->daemon.daemon_fd = DAEMON_NOT_AVAILABLE;
}
}
}
/*
* dl_set_new_image_file()
* return: none
* this_(in): DYNAMIC_LOADER * structure pointer
* new_image(in): Short description of the param3
*/
static void
dl_set_new_image_file (DYNAMIC_LOADER * this_, const char *new_image)
{
if (!this_->virgin)
{
(void) unlink (this_->image_file); /* temporary old one */
}
/* don't use free_and_init(), it came from exec_path() */
free ((char *) this_->image_file);
this_->image_file = new_image;
this_->virgin = false;
dl_notify_daemon (this_);
}
/*
* dl_set_new_load_points() - Add new load point
* return: Zero on success, non-zero on failure
* this_(in): DYNAMIC_LOADER structure pointer
* load_point(in): load point to be added
*/
static int
dl_set_new_load_points (DYNAMIC_LOADER * this_, const caddr_t load_point)
{
caddr_t *new_load_points;
if (this_->loader.ptr)
{
new_load_points = (caddr_t *) realloc (this_->loader.ptr, (this_->loader.num + 1) * sizeof (caddr_t));
}
else
{
new_load_points = (caddr_t *) malloc (sizeof (caddr_t));
}
if (new_load_points)
{
this_->loader.ptr = new_load_points;
this_->loader.ptr[this_->loader.num++] = load_point;
}
else
{
DL_SET_ERROR_SYSTEM_MSG ();
return ER_FAILED;
}
}
#endif /* ((sun || sparc) && !SOLARIS) || _AIX */
/*
* dl_record_files() - Record the names of the files that we have loaded.
* this_(in): DYNAMIC_LOADER * structure pointer
*/
static void
dl_record_files (DYNAMIC_LOADER * this_)
{
int i;
for (i = 0; i < this_->candidates.num; ++i)
{
FILE_ENTRY *fe = &this_->candidates.entries[i];
if (fe->valid && !fe->archive && !fe->duplicate)
{
TBL_LINK *tl;
int index = hashpjw (fe->filename) % FNAME_TBL_SIZE;
tl = (TBL_LINK *) malloc (sizeof (TBL_LINK));
if (tl)
{
tl->filename = fe->filename;
tl->link = this_->loaded[index];
this_->loaded[index] = tl;
}
else
{
fe->valid = false;
}
}
}
}
static int
dl_is_valid_image_file (DYNAMIC_LOADER * this_)
{
#if defined (SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
return 1;
#else /* SOLARIS || HPUX || LINUX || AIX */
assert (this_ != NULL);
return this_->image_file != NULL;
#endif /* SOLARIS || HPUX || LINUX || AIX */
}
#if (defined(sun) || defined(sparc)) && !defined(SOLARIS)
/*
* dl_load_objects() - Validate and load object files
* return: Zero on success, non-zero on failure
* this_(in): DYNAMIC_LOADER structure pointer
* actual(out): pointer to receive information
* obj_files(in): array of object file names
* libs(in): array of library
* estimate(in): fudge factor for modifying estimate of size required
* to load files
* mode(in) : if mode == DL_RELATIVE, estimated_size is an extra value to be
* added to the loader's estimate;
* if mode == DL_ABSOLUTE, estimated_size is used as the estimate.
*/
static int
dl_load_objects (DYNAMIC_LOADER * this_, size_t * actual, const char **obj_files, const char **libs,
const size_t estimate, enum dl_estimate_mode mode)
{
size_t estimated_size = 0;
size_t actual_size = 0;
caddr_t load_point = NULL, old_load_point = NULL;
const char *tmp_file = NULL;
int first_time = true;
int i;
dl_Errno = NO_ERROR;
if (dl_validate_candidates (this_, obj_files) || (this_->num_need_load == 0))
goto cleanup;
tmp_file = TEMPNAM (NULL, "dynld");
if (tmp_file == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
goto cleanup;
}
if (mode == DL_RELATIVE || (mode == DL_ABSOLUTE && estimate == 0))
{
for (i = 0; i < this_->candidates.num; ++i)
{
if (this_->candidates.entries[i].valid && !this_->candidates.entries[i].duplicate)
{
estimated_size += this_->candidates.entries[i].size;
}
}
}
else
{
estimated_size = estimate;
}
if (mode == DL_RELATIVE)
{
estimated_size += estimate;
}
for (first_time = true;; first_time = false)
{
/* allocate > link > check estimated size > free the space and try again. */
load_point = VALLOC (estimated_size);
if (load_point == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
goto cleanup;
}
if (load_point != old_load_point)
{
if (dl_link_file (tmp_file, load_point, libs == NULL ? dl_Default_libs : libs))
goto cleanup;
actual_size = dl_get_image_file_size (tmp_file);
if (actual_size == -1)
goto cleanup;
if (first_time && actual)
{
if (mode == DL_RELATIVE)
{
*actual = actual_size - estimated_size;
}
else
{
*actual = actual_size;
}
}
}
if (estimated_size >= actual_size)
{
break;
}
estimated_size = actual_size; /* update the estimate and try again. */
old_load_point = load_point;
free (load_point); /* don't use free_and_init, they come from VALLOC() */
}
if (dl_load_object_image (load_point, tmp_file))
goto cleanup;
if (mprotect (load_point, actual_size, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) /* Add all permissions to this
* new chunk of memory */
{
DL_SET_ERROR_SYSTEM_MSG ();
goto cleanup;
}
dl_set_new_image_file (this_, tmp_file);
tmp_file = NULL;
if (dl_set_new_load_points (this_, load_point))
goto cleanup;
dl_record_files (this_);
cleanup:
if (dl_Errno)
{
for (i = 0; i < this_->candidates.num; ++i)
{
this_->candidates.entries[i].valid = false;
}
if (load_point)
free (load_point); /* don't use free_and_init, they come from VALLOC() */
if (tmp_file)
{
int rc;
int max_retry = 0;
while (((rc = unlink (tmp_file)) != 0) && (max_retry < MAX_UNLINK_RETRY))
{
if (rc < 0)
{
if (dl_Debug)
{
fprintf (stderr, "%s[%d]: retrying unlink: errno = %d\n", __FILE__, __LINE__, errno);
}
max_retry++;
(void) sleep (3);
continue;
}
}
if (dl_Debug)
{
if (max_retry < MAX_UNLINK_RETRY)
{
fprintf (stderr, "%s[%d]: successful unlink: %s\n", __FILE__, __LINE__, tmp_file);
}
else
{
fprintf (stderr, "%s[%d]: hit retry max for unlink: %s\n", __FILE__, __LINE__, tmp_file);
}
}
/*
* Don't use free_and_init on tmp_file; it came to us via tempnam().
*/
free ((char *) tmp_file);
}
}
dl_destroy_candidates (this_);
if (dl_Errno == NO_ERROR)
return NO_ERROR;
return ER_FAILED;
}
#elif defined(SOLARIS) || defined(HPUX) || defined(LINUX) || defined(AIX)
/*
* dl_load_objects() - Validate and load object files
* return: Zero on success, non-zero on failure
* this_(in): DYNAMIC_LOADER * structure pointer
* obj_files(in): array of object file names
*/
static int
dl_load_objects (DYNAMIC_LOADER * this_, const char **obj_files)
{
int i;
dl_Errno = NO_ERROR;
if (dl_validate_candidates (this_, obj_files) || (this_->num_need_load == 0))
{
/* validation failed or All of the candidates were already loaded */
goto cleanup;
}
for (i = 0; i < this_->candidates.num; i++)
{
if (!this_->candidates.entries[i].duplicate)
{
if (dl_Debug)
{
fprintf (stderr, "Opening file: %s as handle: %d\n", obj_files[i], this_->handler.top);
}
/* first see if we need to extend the handle array */
if (this_->handler.top == this_->handler.num)
{
int new_handles_num;
void **new_handles;
new_handles_num = this_->handler.num + HANDLES_PER_EXTENT;
if (dl_Debug)
{
fprintf (stderr, "Extending handle arrary to %d handles\n", new_handles_num);
}
new_handles = (void **) malloc (new_handles_num * sizeof (void *));
if (new_handles == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_DL_LOAD_ERR, 1,
"Memory allocation failed for handle extension");
dl_Errno = ER_FAILED;
goto cleanup;
}
memcpy (new_handles, this_->handler.handles, (this_->handler.num * sizeof (void *)));
free_and_init (this_->handler.handles);
this_->handler.handles = new_handles;
this_->handler.num = new_handles_num;
}
#if defined(HPUX)
this_->handler.handles[this_->handler.top] =
(void *) shl_load (obj_files[i], BIND_IMMEDIATE | BIND_NONFATAL, 0);
#else /* HPUX */
this_->handler.handles[this_->handler.top] = dlopen (obj_files[i], RTLD_LAZY);
#endif /* HPUX */
if (this_->handler.handles[this_->handler.top] == NULL)
{
#if defined(HPUX)
char dl_msg[1024];
sprintf (dl_msg, "Error shl_load'ing file: %s, with error code: %d", obj_files[i], errno);
if (dl_Debug)
{
fprintf (stderr, "%s\n", dl_msg);
}
#else /* HPUX */
char *dl_msg;
dl_msg = dlerror ();
if (dl_Debug)
{
fprintf (stderr, "Error opening file: %s, with error \"%s\"\n", obj_files[i], dl_msg);
}
#endif /* HPUX */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_DL_LOAD_ERR, 1, dl_msg);
dl_Errno = ER_FAILED;
goto cleanup;
}
else
{
if (dl_Debug)
{
fprintf (stderr, "dl_open for handle: %d succeeded, value = %p\n", this_->handler.top,
this_->handler.handles[this_->handler.top]);
}
this_->handler.top++;
}
}
}
dl_record_files (this_); /* Record the names of the files that we have loaded, so that we don't ever load them
* again. */
cleanup:
if (dl_Errno)
{
for (i = 0; i < this_->candidates.num; ++i)
{
this_->candidates.entries[i].valid = false; /* to free filename */
}
}
dl_destroy_candidates (this_);
if (dl_Errno == NO_ERROR)
return NO_ERROR;
return ER_FAILED;
}
#endif /* (SOLARIS) || (HPUX) || (LINUX) || (AIX) */
/*
* dl_resolve_symbol() - obtain the address of a symbol from a object
* return: Zero on success, non-zero on failure
* this_(in): DYNAMIC_LOADER * structure pointer
* syms(in): symbols to resolve
*/
static int
dl_resolve_symbol (DYNAMIC_LOADER * this_, struct nlist *syms)
{
#if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
#if defined(HPUX)
#define SYMS_NTYPE_NULL ST_NULL
#define SYMS_NTYPE_ENTRY ST_ENTRY
#else /* HPUX */ /* LINUX code is same with SOLARIS */
#define SYMS_NTYPE_NULL N_UNDF
#define SYMS_NTYPE_ENTRY (N_TEXT | N_EXT)
#endif
int i, j, num_resolutions;
void *resolution;
for (i = 0; syms[i].n_name != NULL; i++)
{
syms[i].n_type = SYMS_NTYPE_NULL;
if (dl_Debug)
{
fprintf (stderr, "Resolving symbol: %s\n", syms[i].n_name);
}
for (j = 0, num_resolutions = 0; j < this_->handler.top; j++)
{
if (dl_Debug)
{
fprintf (stderr, "resolving symbols with handle: %d, value = %p\n", j, this_->handler.handles[j]);
}
#if defined(HPUX)
if (shl_findsym ((shl_t *) (&this_->handler.handles[j]), syms[i].n_name, TYPE_PROCEDURE, &resolution) ==
NO_ERROR)
#else /* HPUX */
if ((resolution = dlsym (this_->handler.handles[j], syms[i].n_name)))
#endif
{
num_resolutions++;
syms[i].n_value = (long) resolution; /* TODO: consider: LP64 */
syms[i].n_type = SYMS_NTYPE_ENTRY;
}
else if (dl_Debug)
{
fprintf (stderr, "Error resolving: %s, from handle: %d: Error code %d\n", syms[i].n_name, j, errno);
}
}
if (dl_Debug)
{
fprintf (stderr, "Number of resolutions found for symbol: %s is: %d\n", syms[i].n_name, num_resolutions);
}
if (num_resolutions > 1)
{
/* set an error and return */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_DL_MULTIPLY_DEFINED, 1, syms[i].n_name);
syms[i].n_type = SYMS_NTYPE_NULL;
return -1;
}
}
return NO_ERROR;
#else /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
return nlist ((char *) this_->image_file, syms);
#endif /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
}
/*
* dl_initiate_module() - initialize the dynamic loader
* return: Zero on success, non-zero on failure.
* module_name(in): name of the file whose symbol table should be used
* as the starting point for dynamic loading
*/
#if !defined (SOLARIS) && !defined(LINUX) && !defined(AIX)
int
dl_initiate_module (const char *module_name)
#else /* !(SOLARIS) && !(LINUX) && !(AIX) */
int
dl_initiate_module (void)
#endif /* !(SOLARIS) && !(LINUX) && !(AIX) */
{
const char *image_name = NULL;
if (dl_Loader)
{
DL_SET_ERROR_WITH_CODE (ER_DL_EXISTS);
return ER_FAILED;
}
#if !defined (SOLARIS) && !defined(LINUX) && !defined(AIX)
image_name = exec_path (module_name);
if (image_name == NULL)
{
DL_SET_ERROR_WITH_CODE_ONE_ARG (ER_DL_IMAGE, module_name);
return ER_FAILED;
}
#endif /* !SOLARIS && !LINUX && !AIX */
dl_Debug = (getenv ("DL_DEBUG") != NULL);
dl_Loader = (DYNAMIC_LOADER *) malloc (sizeof (DYNAMIC_LOADER));
if (dl_Loader == NULL)
{
DL_SET_ERROR_SYSTEM_MSG ();
return ER_FAILED;
}
if (dl_initiate_dynamic_loader (dl_Loader, image_name))
{
return ER_FAILED;
}
if (!dl_is_valid_image_file (dl_Loader))
{
DL_SET_ERROR_WITH_CODE (ER_DL_INVALID);
return ER_FAILED;
}
return NO_ERROR;
}
/*
* dl_destroy_module() - ear down the dynamic loader
* return: Zero on success, non-zero on failure.
*/
int
dl_destroy_module (void)
{
dl_Errno = NO_ERROR;
if (dl_Loader == NULL)
{
DL_SET_ERROR_WITH_CODE (ER_DL_ABSENT);
return ER_FAILED;
}
if (!dl_is_valid_image_file (dl_Loader))
{
DL_SET_ERROR_WITH_CODE (ER_DL_INVALID);
return ER_FAILED;
}
dl_destroy_dynamic_loader (dl_Loader);
free_and_init (dl_Loader);
dl_Debug = false;
return dl_Errno;
}
#if defined(sun) || defined(sparc) || defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
/*
* dl_load_object_module() - loads the named files
* return: Zero on success, non-zero on failure.
* obj_files(in): array of filenames to be loaded
* msgp(in): not used
* libs(in): array of arguments to be passed to ld
*
* Note: If you feel the need
*/
#if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
int
dl_load_object_module (const char **obj_files, const char **msgp)
#else /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
int
dl_load_object_module (const char **obj_files, const char **msgp, const char **libs)
#endif /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
{
dl_Errno = NO_ERROR;
if (msgp)
{
*msgp = "obsolete interface; use standard error interface instead";
}
if (dl_Loader == NULL)
{
DL_SET_ERROR_WITH_CODE (ER_DL_ABSENT);
return ER_FAILED;
}
if (!dl_is_valid_image_file (dl_Loader))
{
DL_SET_ERROR_WITH_CODE (ER_DL_INVALID);
return ER_FAILED;
}
#if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
return dl_load_objects (dl_Loader, obj_files);
#else /* HPUX */
return dl_load_objects (dl_Loader, obj_files, libs, 0, NULL, DL_RELATIVE);
#endif /* HPUX */
}
/*
* dl_resolve_object_symbol() - obtain the address of a symbol from a object
* return: Zero on success, non-zero on failure
* syms(in): symbols to resolve
*
* Note: For each entry in syms, if the named symbol is present in the
* process's current symbol table, its value and type are placed
* in the n_value and n_type fields.
*/
int
dl_resolve_object_symbol (struct nlist *syms)
{
if (dl_Loader == NULL)
{
DL_SET_ERROR_WITH_CODE (ER_DL_ABSENT);
return ER_FAILED;
}
if (!dl_is_valid_image_file (dl_Loader))
{
DL_SET_ERROR_WITH_CODE (ER_DL_INVALID);
return ER_FAILED;
}
return dl_resolve_symbol (dl_Loader, syms);
}
#if defined (ENABLE_UNUSED_FUNCTION)
/*
* dl_load_object_with_estimate() - run dl_load_object_module and accepts extra
* information to try to refine size estimates for loading the files
* return: Zero on success, non-zero on failure
* actual_size(out): pointer to receive information
* obj_files(in): array of object file names
* libs(in): array of arguments to be passed to ld
* msgp(in): not used
* estimated_size(in): fudge factor for modifying estimate of size required
* to load files
* mode(in) : if mode == DL_RELATIVE, estimated_size is an extra value to be
* added to the loader's estimate;
* if mode == DL_ABSOLUTE, estimated_size is used as the estimate.
*/
#if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
int
dl_load_object_with_estimate (const char **obj_files, const char **msgp)
#elif (defined(sun) || defined(sparc)) && !defined(SOLARIS)
int
dl_load_object_with_estimate (size_t * actual_size, const char **obj_files, const char **msgp, const char **libs,
const size_t estimated_size, enum dl_estimate_mode mode)
#endif /* (HPUX) || (SOLARIS) || (LINUX) || (AIX) */
{
dl_Errno = NO_ERROR;
if (msgp)
{
*msgp = "obsolete interface; use standard error interface instead";
}
if (dl_Loader == NULL)
{
DL_SET_ERROR_WITH_CODE (ER_DL_ABSENT);
return ER_FAILED;
}
if (!dl_is_valid_image_file (dl_Loader))
{
DL_SET_ERROR_WITH_CODE (ER_DL_INVALID);
return ER_FAILED;
}
#if defined(HPUX) || defined(SOLARIS) || defined(LINUX) || defined(AIX)
return dl_load_objects (dl_Loader, obj_files);
#else /* HPUX || SOLARIS || LINUX || AIX */
return dl_load_objects (dl_Loader, obj_files, libs, estimated_size, actual_size, mode);
#endif /* HPUX || SOLARIS || LINUX || AIX */
}
#endif /* ENABLE_UNUSED_FUNCTION */
#endif