file.c revision d2d5cf7c5d909b74a88d499283e24750a9a52c5d
/*
* 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.
*/
/*
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
*/
#include "gelf.h"
#include "inc.h"
#include "extern.h"
static char *str_base; /* start of string table for names */
static char *str_top; /* pointer to next available location */
static int pad_symtab; /* # of bytes by which to pad symbol table */
/*
* The ar file format requires objects to be padded to an even size.
* We do that, but it turns out to be beneficial to go farther.
*
* ld(1) accesses archives by mmapping them into memory. If the mapped
* objects have the proper alignment, we can access them directly. If the
* alignment is wrong, libelf "slides" them so that they are also accessible.
* This is expensive in time (to copy memory) and space (it causes swap
* to be allocated by the system to back the now-modified pages). Hence, we
* really want to ensure that the alignment is right.
*
* We used to align 32-bit objects at 4-byte boundaries, and 64-bit objects
* at 8-byte. More recently, an elf section type has appeared that has
* 8-byte alignment requirements (SUNW_move) even in 32-bit objects. So,
* the current strategy is to align all objects to 8-bytes.
*
* There are two important things to consider when setting this value:
* 1) If a new elf section that ld(1) accesses in memory appears
* with a greater than 8-byte alignment requirement, this value
* will need to be raised. Or, alternatively, the entire approach may
* need reconsideration.
* 2) The size of this padding must be smaller than the size of the
* smallest possible ELF section. Otherwise, the logic contained
* in recover_padding() can be tricked.
*/
#define PADSZ 8
/*
* Function Prototypes
*/
static long mklong_tab(int *);
static char *trimslash(char *s);
static int writesymtab(char *, long, ARFILEP *);
static void savename(char *);
static void savelongname(ARFILE *, char *);
static void sputl(long, char *);
int new_archive);
static int sizeofmembers();
static int sizeofnewarchive(int, int);
long *, ARFILEP **, int *);
int
{
int fd;
exit(1);
}
/* archive does not exist yet, may have to create one */
return (fd);
} else {
/* problem other than "does not exist" */
exit(1);
}
}
cmd = ELF_C_READ;
PLAIN_ERROR, (char *)0, arnam);
exit(1);
}
return (fd);
}
/*
* Given a size, return the number of bytes required to round it
* up to the next PADSZ boundary.
*/
static int
pad(int n)
{
int r;
r = n % PADSZ;
if (r)
r = PADSZ - r;
return (r);
}
/*
* If the current archive item is an object, then ar(1) may have added
* newline padding at the end in order to bring the following object
* into PADSZ alignment within the file. This padding cannot be
* distinguished from data using the information kept in the ar headers.
* This routine examines the objects, using knowledge of
* ELF and how our tools lay out objects to determine whether padding was
* added to an archive item. If so, it adjusts the st_size and
* st_padding fields of the file argument to reflect it.
*/
static void
{
long extent;
long padding;
/* ar(1) only pads objects, so bail if not looking at one */
return;
/*
* libelf always puts the section header array at the end
* of the object, and all of our compilers and other tools
* use libelf or follow this convention. So, it is extremely
* likely that the section header array is at the end of this
* object: Find the address at the end of the array and compare
* it to the archive ar_size. If they are within PADSZ bytes, then
* we've found the end, and the difference is padding (We assume
* that no ELF section can fit into PADSZ bytes).
*/
/*
* The section header array is not at the end of the object.
* Traverse the section headers and look for the one with
* the highest used address. If this address is within
* PADSZ bytes of ar_size, then this is the end of the object.
*/
do {
if (scn) {
if (t > extent)
extent = t;
}
}
} while (scn);
}
/*
* Now, test the padding. We only act on padding in the range
* (0 < pad < PADSZ) (ar(1) will never add more than this). A pad
* of 0 requires no action, and any other size above (PADSZ-1) means
* that we don't understand the layout of this object, and as such,
* cannot do anything.
*
* If the padding is in range, and the raw data for the
* object is available, then we perform one additional sanity
* check before moving forward: ar(1) always pads with newline
* characters. If anything else is seen, it is not padding so
* leave it alone.
*/
if (file->ar_contents) {
while (cnt--) {
if (*p++ != '\n') { /* No padding */
padding = 0;
break;
}
}
}
/* Remove the padding from the size */
}
}
ARFILE *
{
char *tmp_rawname, *file_rawname;
if (fd == -1)
return (NULL); /* the archive doesn't exist */
return (NULL); /* the archive is empty or have hit the end */
exit(1);
}
/* zip past special members like the symbol and string table members */
return (NULL);
/* the archive is empty or have hit the end */
exit(0);
}
}
/*
* NOTE:
* The mem_header->ar_name[] is set to a NULL string
* if the archive member header has some error.
* (See elf_getarhdr() man page.)
* It is set to NULL for example, the ar command reads
* the archive files created by SunOS 4.1 system.
* See c block comment in cmd.c, "Incompatible Archive Header".
*/
if ((file->ar_longname
== NULL) {
PLAIN_ERROR, (char *)0);
exit(1);
}
if ((file->ar_rawname
== NULL) {
PLAIN_ERROR, (char *)0);
exit(1);
}
while (!isspace(*tmp_rawname) &&
file_rawname++;
tmp_rawname++;
}
if (!(*tmp_rawname == '\0'))
*file_rawname = '\0';
/* reverse logic */
== NULL) {
if (ptr != 0) {
exit(1);
}
}
}
return (file);
}
ARFILE *
newfile(void)
{
static int count = 0;
if (count == 0) {
== NULL) {
PLAIN_ERROR, (char *)0);
exit(1);
}
}
count--;
if (listhead)
else
return (fileptr);
}
static char *
trimslash(char *s)
{
}
char *
trim(char *s)
{
;
while (p1 > s) {
if (*--p1 != '/')
break;
*p1 = 0;
}
p2 = s;
if (*p1 == '/')
return (p2);
}
static long
{
long mem_offset = 0;
int newfd;
long nsyms = 0;
int class = 0;
int num_errs = 0;
newfd = 0;
/* determine if file is coming from the archive or not */
/*
* I can use the saved elf descriptor.
*/
if ((newfd =
fptr->ar_pathname);
num_errs++;
continue;
}
ELF_C_READ, (Elf *)0)) == 0) {
fptr->ar_pathname);
else
newfd = 0;
num_errs++;
continue;
}
PLAIN_ERROR, (char *)0,
fptr->ar_pathname);
else
PLAIN_ERROR, (char *)0);
if (newfd) {
newfd = 0;
}
continue;
}
} else {
PLAIN_ERROR, (char *)0);
exit(1);
}
} else if (class == ELFCLASS32)
fptr->ar_pathname);
else
num_errs++;
if (newfd) {
newfd = 0;
}
continue;
}
data = 0;
fptr->ar_pathname);
else
num_errs++;
if (newfd) {
newfd = 0;
}
continue;
}
PLAIN_ERROR, (char *)0,
fptr->ar_pathname);
else
PLAIN_ERROR, (char *)0);
if (newfd) {
newfd = 0;
}
num_errs++;
continue;
}
/* loop through sections to find symbol table */
scn = 0;
elf_errmsg(-1),
fptr->ar_pathname);
else
elf_errmsg(-1));
if (newfd) {
newfd = 0;
}
num_errs++;
continue;
}
*found_obj = 1;
&num_errs) == -1) {
if (newfd) {
newfd = 0;
}
continue;
}
}
}
mem_offset++;
if (newfd) {
newfd = 0;
}
} /* for */
if (num_errs)
exit(1);
return (nsyms);
}
/*
* This routine writes an archive symbol table for the
* output archive file. The symbol table is built if
* there was at least one object file specified.
* In rare case, there could be no symbol.
* In this case, str_top and str_base can not be used to
* make the string table. So the routine adjust the size
* and make a dummy string table. String table is needed
* by elf_getarsym().
*/
static int
{
int i, j;
long sym_tab_size = 0;
int sum = 0;
/*
* patch up archive pointers and write the symbol entries
*/
*str_top++ = '\0';
if (nsyms == 0)
sym_tab_size += 4;
(unsigned)0, (unsigned)0, (long)sym_tab_size, ARFMAG);
exit(1);
}
exit(1);
}
if (!j) {
j = SYMCHUNK;
}
bptr += 4;
}
if (nsyms != 0) {
} else {
/*
* Writing a dummy string table.
*/
int i;
for (i = 0; i < 4; i++)
*dst++ = 0;
sum += 4;
}
/*
* The first member file is an ELF object. We need to make
* sure it will be placed at the PADSZ byte boundary.
*/
if (pad_symtab) {
int i;
for (i = 0; i < pad_symtab; i++)
*dst++ = 0;
sum += pad_symtab;
}
return (sum);
}
static void
{
char *p, *s;
unsigned int i;
int diff;
diff = 0;
if (str_base == (char *)0) {
/* no space allocated yet */
PLAIN_ERROR, (char *)0);
exit(1);
}
}
p = str_top;
do
;
NULL) {
PLAIN_ERROR, (char *)0);
exit(1);
}
/*
* Re-adjust other pointers
*/
p += diff;
}
*p++ = *s++;
}
*p++ = '\0';
str_top = p;
}
static void
{
char *p, *s;
unsigned int i;
int diff;
static int bytes_used;
int index;
diff = 0;
if (str_base1 == (char *)0) {
/* no space allocated yet */
== NULL) {
PLAIN_ERROR, (char *)0);
exit(1);
}
}
p = str_top1;
index = bytes_used;
do
;
== NULL) {
PLAIN_ERROR, (char *)0);
exit(1);
}
/*
* Re-adjust other pointers
*/
p += diff;
}
for (i = 0, s = fptr->ar_longname;
*p++ = *s++;
}
*p++ = '/';
*p++ = '\n';
str_top1 = p;
}
char *
{
int i;
int longnames = 0;
long long_tab_size = 0;
long nsyms;
int new_archive = 0;
int arsize;
char *dst;
char *tmp_dst;
int nfd;
int found_obj = 0;
for (i = 0; signum[i]; i++)
/* started writing, cannot interrupt */
/* Is this a new archive? */
new_archive = 1;
}
} else
new_archive = 0;
/*
* Calculate the size of the new archive
*/
/*
* Dummy symtab ?
*/
/*
* 4 + 4 = First 4 bytes to keep the number of symbols.
* The second 4 bytes for string table.
*/
if (arsize > AR_MAX_BYTES_IN_MEM) {
} else {
}
}
int diff;
}
if (longnames) {
(unsigned)0, (unsigned)0, (unsigned)0,
(long)long_tab_size, ARFMAG);
}
/*
* NOTE:
* The mem_header->ar_name[] is set to a NULL string
* if the archive member header has some error.
* (See elf_getarhdr() man page.)
* It is set to NULL for example, the ar command reads
* the archive files created by SunOS 4.1 system.
* See c block comment in cmd.c, "Incompatible Archive Header".
*/
}
else
ARFMAG);
/* file was not read in fptr->ar_contents during 'cmd' */
/* do it now */
FILE *f;
if (f == NULL) {
fptr->ar_longname);
exit(1);
} else {
fptr->ar_longname);
exit(1);
}
}
(void) fclose(f);
} else {
}
}
tmp_dst++;
}
if (fptr->ar_padding) {
int i = fptr->ar_padding;
while (i) {
*tmp_dst++ = '\n';
--i;
}
}
}
/*
* All preparation for writing is done.
*/
/*
* Write out to the file
*/
if (new_archive) {
/*
* create a new file
*/
if (nfd == -1) {
exit(1);
}
} else {
/*
* Open the new file
*/
if (nfd == -1) {
exit(1);
}
}
#ifndef XPG4
}
#endif
if (!new_archive)
PLAIN_ERROR, (char *)0);
exit(2);
}
return (dst);
}
static long
mklong_tab(int *longnames)
{
long ret = 0;
(*longnames)++;
}
}
if (*longnames) {
/* round up table that keeps the long filenames */
*str_top1++ = '\n';
}
return (ret);
}
/* Put bytes in archive header in machine independent order. */
static void
{
*cp++ = n >> 24;
*cp++ = n >> 16;
*cp++ = n >> 8;
*cp++ = n & 255;
}
static int
{
int counter;
int str_shtype;
char *symname;
static int syms_left = 0;
fname);
else
(*num_errs)++;
return (-1);
}
if (no_of_symbols == -1) {
PLAIN_ERROR, (char *)0);
return (-1);
}
if (str_shtype == -1) {
else
(*num_errs)++;
return (-1);
}
/* This test must happen before testing the string table. */
if (no_of_symbols == 1)
return (0); /* no symbols; 0th symbol is the non-symbol */
if (str_shtype != SHT_STRTAB) {
PLAIN_ERROR, (char *)0,
fname);
else
PLAIN_ERROR, (char *)0);
return (0);
}
str_data = 0;
PLAIN_ERROR, (char *)0,
fname);
else
PLAIN_ERROR, (char *)0);
return (0);
}
PLAIN_ERROR, (char *)0,
fname);
else
PLAIN_ERROR, (char *)0);
return (0);
}
sym_data = 0;
else
elf_errmsg(-1));
return (0);
}
/* start at 1, first symbol entry is ignored */
if (!syms_left) {
* sizeof (ARFILEP));
PLAIN_ERROR, (char *)0);
exit(1);
}
if (nextsym)
else
}
nextsym++;
syms_left--;
(*nsyms)++;
/* symbol table string table */
}
}
return (0);
}
/*
* Get the output file size
*/
static int
sizeofmembers(int psum)
{
int sum = 0;
sum++;
/*
* If the current item, and the next item are both ELF
* objects, then add padding to current item so that the
* next item will have PADSZ alignment.
*
* In any other case, set the padding to 0. If the
* item comes from another archive, it may be carrying
* a non-zero padding value from that archive that does
* not apply to the one we are about to build.
*/
} else {
fptr->ar_padding = 0;
}
}
return (sum);
}
static int
{
int sum = 0;
if (nsyms) {
top++;
}
if (longnames) {
}
/*
* If the first member file is an ELF object,
* we have to ensure the member contents will align
* on PADSZ byte boundary.
*/
sum += pad_symtab;
}
return (sum);
}
static int
{
int sum;
return (sum);
}
static void
exit(2);
}
}
static char *
make_tmpname(char *filename) {
static char template[] = "arXXXXXX";
char *tmpname;
char c;
c = *slash;
*slash = 0;
sizeof (template) + 2);
*slash = c;
} else {
}
return (tmpname);
}
static int
int saved;
char buf[8192];
if (fromfd < 0)
return (-1);
if (tofd < 0) {
return (-1);
}
return (-1);
}
}
if (nread < 0) {
return (-1);
}
return (0);
}
static int
{
int exists;
struct stat s;
int ret = 0;
if (ret == 0) {
if (exists) {
}
} else {
}
} else {
}
return (ret);
}
static char *
{
int arsize;
char *dst;
char *tmp_dst;
int nfd;
char *new_name;
FILE *f;
if (new_archive) {
if (nfd == -1) {
exit(1);
}
} else {
if (nfd == -1) {
exit(1);
}
}
if (arsize < 2048) {
arsize = 2048;
}
int diff;
}
if (longnames) {
(unsigned)0, (unsigned)0, (unsigned)0,
(long)long_tab_size, ARFMAG);
}
#ifndef XPG4
PLAIN_ERROR, (char *)0,
}
#endif
}
else
ARFMAG);
(void) fclose(f);
f = NULL;
}
if (f == NULL) {
fptr->ar_longname);
exit(1);
} else {
if ((fptr->ar_contents = (char *)
PLAIN_ERROR, (char *)0);
exit(1);
}
sizeof (char),
fptr->ar_longname);
exit(1);
}
}
(void) fclose(f);
} else {
}
}
}
if (fptr->ar_padding) {
int i = fptr->ar_padding;
while (i) {
--i;
}
}
}
/*
* All preparation for writing is done.
*/
if (!new_archive) {
}
return (dst);
}