a.out.c revision ba7962c0250fa58d6c360c01c4866d394aae57b8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Object file dependent support for a.out format objects.
*/
#include <a.out.h> /* Explicitly override M_SEGSIZE */
#include <machdep.h> /* used in M_SROUND */
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
#include <debug.h>
#include "_a.out.h"
#include "cache_a.out.h"
#include "msg.h"
#include "_rtld.h"
/*
* Default and secure dependency search paths.
*/
static Pnode aout_dflt_dirs[] = {
LA_SER_DEFAULT, 0, 0 }
};
static Pnode aout_secure_dirs[] = {
#ifndef SGS_PRE_UNIFIED_PROCESS
#endif
LA_SER_SECURE, 0, 0 }
};
/*
* Defines for local functions.
*/
static int aout_are_u();
static ulong_t aout_entry_pt();
static Rt_map *aout_map_so();
static void aout_unmap_so();
static int aout_needed();
extern Sym *aout_lookup_sym();
static Sym *aout_find_sym();
static char *aout_get_so();
static Pnode *aout_fix_name();
static void aout_dladdr();
static Sym *aout_dlsym_handle();
static int aout_verify_vers();
/*
* Functions and data accessed through indirect pointers.
*/
};
/*
* In 4.x, a needed file or a dlopened file that was a simple file name implied
* that the file be found in the present working directory. To simulate this
* lookup within the elf rules it is necessary to add a proceeding `./' to the
* filename.
*/
static Pnode *
{
return (0);
/*
* Check for slash in name, if none, prepend "./", otherwise just
* return name given.
*/
} else {
}
return (pnp);
}
return (0);
}
/*
* Determine if we have been given an A_OUT file. Returns 1 if true.
*/
static int
{
/* LINTED */
return (0);
}
return (1);
}
/*
* Return the entry point the A_OUT executable. This is always zero.
*/
static ulong_t
{
return (0);
}
/*
* Unmap a given A_OUT shared object from the address space.
*/
static void
{
}
/*
* Dummy versioning interface - real functionality is only applicable to elf.
*/
static int
{
return (1);
}
/*
* Search through the dynamic section for DT_NEEDED entries and perform one
* of two functions. If only the first argument is specified then load the
* defined shared object, otherwise add the link map representing the
* defined link map the the dlopen list.
*/
static int
{
void *need;
char *name;
/*
* If lo_library field is not NULL then this needed
* library was linked in using the "-l" option.
* Thus we need to rebuild the library name before
* trying to load it.
*/
char *file;
/*
* Allocate name length plus 20 for full library name.
* lib.so.. = 7 + (2 * short) + NULL = 7 + 12 + 1 = 20
*/
return (0);
/*
* We need to determine what filename will match the
* the filename specified (ie, a libc.so.1.2 may match
* to a libc.so.1.3). It's the real pathname that is
* recorded in the link maps. If we are presently
* being traced, skip this pathname generation so
* that we fall through into load_so() to print the
* appropriate diagnostics. I don't like this at all.
*/
else {
char *path = (char *)0;
continue;
if (path =
break;
}
if (!path) {
return (0);
}
}
return (0);
} else {
/*
* If the library is specified as a pathname, see if
* it must be fixed to specify the current working
*/
return (0);
}
in_nfavl);
return (0);
}
return (1);
}
static Sym *
{
break;
case N_COMM:
break;
break;
default:
break;
}
return (&sym);
}
/*
* Process a.out format commons.
*/
static struct nlist *
{
const char *sl;
char *cp;
/*
* See if common is already allocated.
*/
while (trs) {
if (*sl++ == '\0')
}
/*
* If we got here, common is not already allocated so allocate it.
*/
return (0);
return (0);
return (0);
return (0);
}
/*
* Find a.out format symbol in the specified link map. Unlike the sister
* elf routine we re-calculate the symbols hash value for each link map
* we're looking at.
*/
static struct nlist *
{
char *cp;
struct fshash *p;
int i;
#define HASHMASK 0x7fffffff
#define RTHS 126
/*
* The name passed to us is in ELF format, thus it is necessary to
* map this back to the A_OUT format to compute the hash value (see
* mapping rules in aout_lookup_sym()). Basically the symbols are
* mapped according to whether a leading `.' exists.
*
* elf symbol a.out symbol
* i. .bar -> .bar (LKUP_LDOT)
* ii. .nuts -> nuts
* iii. foo -> _foo
*/
if (*name == '.') {
name++;
} else
hval = '_';
while (*name)
if (p->fssymbno != -1)
do {
if (*name == '.') {
name++;
} else {
cp++;
}
if (*name++ == '\0')
return (sp); /* found */
}
if (p->next == 0)
return (0); /* not found */
else
continue;
return (0);
}
/*
* The symbol name we have been asked to look up is in A_OUT format, this
* symbol is mapped to the appropriate ELF format which is the standard by
* which symbols are passed around ld.so.1. The symbols are mapped
* according to whether a leading `_' or `.' exists.
*
* a.out symbol elf symbol
* i. _foo -> foo
* ii. .bar -> .bar (LKUP_LDOT)
* iii. nuts -> .nuts
*/
Sym *
{
else {
name[0] = '.';
}
/*
* Call the generic lookup routine to cycle through the specified
* link maps.
*/
}
/*
* Symbol lookup for an a.out format module.
*/
/* ARGSUSED3 */
static Sym *
{
/*
* is it a common?
*/
return ((Sym *)0);
}
*binfo |= DBG_BINFO_FOUND;
return (aout_symconvert(sp));
}
}
return ((Sym *)0);
}
/*
* Map in an a.out format object.
* Takes an open file descriptor for the object to map and
* its pathname; returns a pointer to a Rt_map structure
* for this object, or 0 on error.
*/
static Rt_map *
int fd)
{
int err;
/*
* Map text and allocate enough address space to fit the whole
* library. Note that we map enough to catch the first symbol
* in the symbol table and thereby avoid an "lseek" & "read"
* pair to pick it up.
*/
/* LINTED */
fd, 0)) == MAP_FAILED) {
return (0);
}
/*
* Grab the first symbol entry while we've got it mapped aligned
* to file addresses. We assume that this symbol describes the
* object's link_dynamic.
*/
/* LINTED */
/* LINTED */
/*
* Map the initialized data portion of the file to the correct
* point in the range of allocated addresses. This will leave
* some portion of the data segment "doubly mapped" on machines
* boundaries. However, leaving the file mapped has the double
* advantage of both saving the munmap system call and of leaving
* us a contiguous chunk of address space devoted to the object --
* in case we need to unmap it all later.
*/
return (0);
}
/*
* Allocate pages for the object's bss, if necessary.
*/
goto error;
}
/*
* Create link map structure for newly mapped shared object.
*/
goto error;
return (lmp);
/*
* Error returns: close off file and free address space.
*/
return (0);
}
/*
* Create a new Rt_map structure for an a.out format object and
* initializes all values.
*/
Rt_map *
{
/*
* Allocate space for the link-map and private a.out information. Once
* these are allocated and initialized, we can use remove_so(0, lmp) to
* tear down the link-map should any failures occur.
*/
return (0);
return (0);
}
return (0);
}
/*
* All fields not filled in were set to 0 by calloc.
*/
/*
* Specific settings for a.out format.
*/
} else
/*
* Create a mapping descriptor to describe the whole object as a single
* mapping.
*/
return (0);
/* LINTED */
/*
* Fill in all AOUT information.
*/
/* LINTED */
/* LINTED */
/* LINTED */
/* LINTED */
if (rtld_flags & RT_FL_RELATIVE)
return (0);
}
return (0);
}
/*
* Add the mapped object to the end of the link map list.
*/
return (lmp);
}
/*
* Function to correct protection settings.
* Segments are all mapped initially with permissions as given in
* the segment header, but we need to turn on write permissions
* on a text segment if there are any relocations against that segment,
* and them turn write permission back off again before returning control
* to the program. This function turns the permission on or off depending
* on the value of the argument.
*/
int
{
int prot; /* protection setting */
return (0);
}
return (1);
}
/*
* Build full pathname of shared object from the given directory name and
* filename.
*/
static char *
{
}
return (path);
}
/*
* Determine the symbol location of an address within a link-map. Look for
* the nearest symbol (whoes value is less than or equal to the required
* address). This is the object specific part of dladdr().
*/
static void
int flags)
{
sizeof (struct nlist);
base = 0;
else
continue;
continue;
continue;
break;
}
if (_sym) {
/*
* The only way we can create a symbol entry is to use
* aout_symconvert(), however this results in us pointing to
* static data that could be overridden. In addition the AOUT
* symbol format doesn't give us everything an ELF symbol does.
* So, unless we get convinced otherwise, don't bother returning
* a symbol entry for AOUT's.
*/
if (_flags == RTLD_DL_SYMENT)
*info = 0;
else if (_flags == RTLD_DL_LINKMAP)
}
}
/*
* Continue processing a dlsym request. Lookup the required symbol in each
* link-map specified by the handle. Note, that because this lookup is against
* individual link-maps we don't need to supply a starting link-map to the
* lookup routine (see lookup_sym():analyze.c).
*/
Sym *
int *in_nfavl)
{
buffer[0] = '_';
return (sym);
/*
* Symbol not found as supplied. However, most of our symbols will
* be in the "C" name space, where the implementation prepends a "_"
* to the symbol as it emits it. Therefore, attempt to find the
* symbol with the "_" prepend.
*/
}