mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-11 17:10:58 +08:00
simple-object.h: New file.
include/: * simple-object.h: New file. libiberty/: * simple-object.c: New file. * simple-object-common.h: New file. * simple-object-elf.c: New file. * simple-object-mach-o.c: New file. * simple-object-coff.c: New file. * simple-object.txh: New file. * configure.ac: Add AC_TYPE_SSIZE_T. * Makefile.in: Rebuild dependencies. (CFILES): Add simple-object.c, simple-object-coff, simple-object-elf.c, and simple-object-mach-o.c. (REQUIRED_OFILES): Add corresponding object files. * configure: Rebuild. * config.in: Rebuild. * functions.texi: Rebuild. Co-Authored-By: Dave Korn <dave.korn.cygwin@gmail.com> Co-Authored-By: Iain Sandoe <iains@gcc.gnu.org> From-SVN: r166185
This commit is contained in:
parent
fee3eacd6f
commit
1cfabf34d8
@ -1,3 +1,7 @@
|
||||
2010-11-02 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* simple-object.h: New file.
|
||||
|
||||
2010-10-15 Dave Korn <dave.korn.cygwin@gmail.com>
|
||||
|
||||
Sync LD plugin patch series (part 1/6) with src/include/.
|
||||
|
203
include/simple-object.h
Normal file
203
include/simple-object.h
Normal file
@ -0,0 +1,203 @@
|
||||
/* simple-object.h -- simple routines to read and write object files
|
||||
Copyright 2010 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 51 Franklin Street - Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef SIMPLE_OBJECT_H
|
||||
#define SIMPLE_OBJECT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This header file provides four types with associated functions.
|
||||
They are used to read and write object files. This is a minimal
|
||||
interface, intended to support the needs of gcc without bringing in
|
||||
all the power and complexity of BFD. */
|
||||
|
||||
/* The type simple_object_read * is used to read an existing object
|
||||
file. */
|
||||
|
||||
typedef struct simple_object_read_struct simple_object_read;
|
||||
|
||||
/* Create an simple_object_read given DESCRIPTOR, an open file
|
||||
descriptor, and OFFSET, an offset within the file. The offset is
|
||||
for use with archives, and should be 0 for an ordinary object file.
|
||||
The descriptor must remain open until done with the returned
|
||||
simple_object_read. SEGMENT_NAME is used on Mach-O and is required
|
||||
on that platform: it means to only look at sections within the
|
||||
segment with that name. It is ignored for other object file
|
||||
formats. On error, this function returns NULL, and sets *ERRMSG to
|
||||
an error string and sets *ERR to an errno value or 0 if there is no
|
||||
relevant errno. */
|
||||
|
||||
extern simple_object_read *
|
||||
simple_object_start_read (int descriptor, off_t offset,
|
||||
const char *segment_name, const char **errmsg,
|
||||
int *err);
|
||||
|
||||
/* Call PFN for each section in SIMPLE_OBJECT, passing it the section
|
||||
name, offset within the file of the section contents, and length of
|
||||
the section contents. The offset within the file is relative to
|
||||
the offset passed to simple_object_start_read. The DATA argument
|
||||
to simple_object_find_sections is passed on to PFN. If PFN returns
|
||||
0, the loop is stopped and simple_object_find_sections returns. If
|
||||
PFN returns non-zero, the loop continues. On success this returns
|
||||
NULL. On error it returns an error string, and sets *ERR to an
|
||||
errno value or 0 if there is no relevant errno. */
|
||||
|
||||
extern const char *
|
||||
simple_object_find_sections (simple_object_read *simple_object,
|
||||
int (*pfn) (void *data, const char *,
|
||||
off_t offset, off_t length),
|
||||
void *data,
|
||||
int *err);
|
||||
|
||||
/* Look for the section NAME in SIMPLE_OBJECT. This returns
|
||||
information for the first section NAME in SIMPLE_OBJECT. Note that
|
||||
calling this multiple times is inefficient; use
|
||||
simple_object_find_sections instead.
|
||||
|
||||
If found, return 1 and set *OFFSET to the offset in the file of the
|
||||
section contents and set *LENGTH to the length of the section
|
||||
contents. *OFFSET will be relative to the offset passed to
|
||||
simple_object_start_read.
|
||||
|
||||
If the section is not found, and no error occurs, return 0 and set
|
||||
*ERRMSG to NULL.
|
||||
|
||||
If an error occurs, return 0, set *ERRMSG to an error message, and
|
||||
set *ERR to an errno value or 0 if there is no relevant errno. */
|
||||
|
||||
extern int
|
||||
simple_object_find_section (simple_object_read *simple_object,
|
||||
const char *name, off_t *offset, off_t *length,
|
||||
const char **errmsg, int *err);
|
||||
|
||||
/* Release all resources associated with SIMPLE_OBJECT. This does not
|
||||
close the file descriptor. */
|
||||
|
||||
extern void
|
||||
simple_object_release_read (simple_object_read *);
|
||||
|
||||
/* The type simple_object_attributes holds the attributes of an object
|
||||
file that matter for creating a file or ensuring that two files are
|
||||
compatible. This is a set of magic numbers. */
|
||||
|
||||
typedef struct simple_object_attributes_struct simple_object_attributes;
|
||||
|
||||
/* Fetch the attributes of SIMPLE_OBJECT. This information will
|
||||
persist until simple_object_attributes_release is called, even if
|
||||
SIMPLE_OBJECT is closed. On error this returns NULL, sets *ERRMSG
|
||||
to an error message, and sets *ERR to an errno value or 0 if there
|
||||
isn't one. */
|
||||
|
||||
extern simple_object_attributes *
|
||||
simple_object_fetch_attributes (simple_object_read *simple_object,
|
||||
const char **errmsg, int *err);
|
||||
|
||||
/* Compare ATTRS1 and ATTRS2. If they could be linked together
|
||||
without error, return NULL. Otherwise, return an error message,
|
||||
set *ERR to an errno value or 0 if there isn't one. */
|
||||
|
||||
extern const char *
|
||||
simple_object_attributes_compare (simple_object_attributes *attrs1,
|
||||
simple_object_attributes *attrs2,
|
||||
int *err);
|
||||
|
||||
/* Release all resources associated with ATTRS. */
|
||||
|
||||
extern void
|
||||
simple_object_release_attributes (simple_object_attributes *attrs);
|
||||
|
||||
/* The type simple_object_write is used to create a new object file. */
|
||||
|
||||
typedef struct simple_object_write_struct simple_object_write;
|
||||
|
||||
/* Start creating a new object file which is like ATTRS. You must
|
||||
fetch attribute information from an existing object file before you
|
||||
can create a new one. There is currently no support for creating
|
||||
an object file de novo. The segment name is only used on Mach-O,
|
||||
where it is required. It means that all sections are created
|
||||
within that segment. It is ignored for other object file formats.
|
||||
On error this function returns NULL, sets *ERRMSG to an error
|
||||
message, and sets *ERR to an errno value or 0 if there isn't
|
||||
one. */
|
||||
|
||||
extern simple_object_write *
|
||||
simple_object_start_write (simple_object_attributes *attrs,
|
||||
const char *segment_name,
|
||||
const char **errmsg, int *err);
|
||||
|
||||
/* The type simple_object_write_section is a handle for a section
|
||||
which is being written. */
|
||||
|
||||
typedef struct simple_object_write_section_struct simple_object_write_section;
|
||||
|
||||
/* Add a section to SIMPLE_OBJECT. NAME is the name of the new
|
||||
section. ALIGN is the required alignment expressed as the number
|
||||
of required low-order 0 bits (e.g., 2 for alignment to a 32-bit
|
||||
boundary). The section is created as containing data, readable,
|
||||
not writable, not executable, not loaded at runtime. On error this
|
||||
returns NULL, sets *ERRMSG to an error message, and sets *ERR to an
|
||||
errno value or 0 if there isn't one. */
|
||||
|
||||
extern simple_object_write_section *
|
||||
simple_object_write_create_section (simple_object_write *simple_object,
|
||||
const char *name, unsigned int align,
|
||||
const char **errmsg, int *err);
|
||||
|
||||
/* Add data BUFFER/SIZE to SECTION in SIMPLE_OBJECT. If COPY is
|
||||
non-zero, the data will be copied into memory if necessary. If
|
||||
COPY is zero, BUFFER must persist until SIMPLE_OBJECT is released.
|
||||
On success this returns NULL. On error this returns an error
|
||||
message, and sets *ERR to an errno value or 0 if there isn't
|
||||
one. */
|
||||
|
||||
extern const char *
|
||||
simple_object_write_add_data (simple_object_write *simple_object,
|
||||
simple_object_write_section *section,
|
||||
const void *buffer, size_t size,
|
||||
int copy, int *err);
|
||||
|
||||
/* Write the complete object file to DESCRIPTOR, an open file
|
||||
descriptor. This returns NULL on success. On error this returns
|
||||
an error message, and sets *ERR to an errno value or 0 if there
|
||||
isn't one. */
|
||||
|
||||
extern const char *
|
||||
simple_object_write_to_file (simple_object_write *simple_object,
|
||||
int descriptor, int *err);
|
||||
|
||||
/* Release all resources associated with SIMPLE_OBJECT, including any
|
||||
simple_object_write_section's that may have been created. */
|
||||
|
||||
extern void
|
||||
simple_object_release_write (simple_object_write *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,3 +1,22 @@
|
||||
2010-11-02 Ian Lance Taylor <iant@google.com>
|
||||
Dave Korn <dave.korn.cygwin@gmail.com>
|
||||
Iain Sandoe <iains@gcc.gnu.org>
|
||||
|
||||
* simple-object.c: New file.
|
||||
* simple-object-common.h: New file.
|
||||
* simple-object-elf.c: New file.
|
||||
* simple-object-mach-o.c: New file.
|
||||
* simple-object-coff.c: New file.
|
||||
* simple-object.txh: New file.
|
||||
* configure.ac: Add AC_TYPE_SSIZE_T.
|
||||
* Makefile.in: Rebuild dependencies.
|
||||
(CFILES): Add simple-object.c, simple-object-coff,
|
||||
simple-object-elf.c, and simple-object-mach-o.c.
|
||||
(REQUIRED_OFILES): Add corresponding object files.
|
||||
* configure: Rebuild.
|
||||
* config.in: Rebuild.
|
||||
* functions.texi: Rebuild.
|
||||
|
||||
2010-10-29 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* setproctitle.c: Add space after function name in @deftypefn
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Originally written by K. Richard Pixley <rich@cygnus.com>.
|
||||
#
|
||||
# Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
||||
# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
|
||||
# Foundation
|
||||
# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
# Free Software Foundation
|
||||
#
|
||||
# This file is part of the libiberty library.
|
||||
# Libiberty is free software; you can redistribute it and/or
|
||||
@ -145,6 +145,8 @@ CFILES = alloca.c argv.c asprintf.c atexit.c \
|
||||
physmem.c putenv.c \
|
||||
random.c regex.c rename.c rindex.c \
|
||||
safe-ctype.c setenv.c setproctitle.c sha1.c sigsetmask.c \
|
||||
simple-object.c simple-object-coff.c simple-object-elf.c \
|
||||
simple-object-mach-o.c \
|
||||
snprintf.c sort.c \
|
||||
spaces.c splay-tree.c stpcpy.c stpncpy.c strcasecmp.c \
|
||||
strchr.c strdup.c strerror.c strncasecmp.c strncmp.c \
|
||||
@ -172,11 +174,15 @@ REQUIRED_OFILES = \
|
||||
./getruntime.$(objext) ./hashtab.$(objext) ./hex.$(objext) \
|
||||
./lbasename.$(objext) ./lrealpath.$(objext) \
|
||||
./make-relative-prefix.$(objext) ./make-temp-file.$(objext) \
|
||||
./objalloc.$(objext) ./obstack.$(objext) \
|
||||
./objalloc.$(objext) \
|
||||
./obstack.$(objext) \
|
||||
./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext) \
|
||||
./pex-common.$(objext) ./pex-one.$(objext) \
|
||||
./@pexecute@.$(objext) \
|
||||
./safe-ctype.$(objext) ./sort.$(objext) ./spaces.$(objext) \
|
||||
./safe-ctype.$(objext) \
|
||||
./simple-object.$(objext) ./simple-object-coff.$(objext) \
|
||||
./simple-object-elf.$(objext) ./simple-object-mach-o.$(objext) \
|
||||
./sort.$(objext) ./spaces.$(objext) \
|
||||
./splay-tree.$(objext) ./strerror.$(objext) \
|
||||
./strsignal.$(objext) ./unlink-if-ordinary.$(objext) \
|
||||
./xatexit.$(objext) ./xexit.$(objext) ./xmalloc.$(objext) \
|
||||
@ -312,7 +318,7 @@ TEXISRC = \
|
||||
# Additional files that have texi snippets that need to be collected
|
||||
# and sorted. Some are here because the sources are imported from
|
||||
# elsewhere. Others represent headers in ../include.
|
||||
TEXIFILES = fnmatch.txh pexecute.txh
|
||||
TEXIFILES = fnmatch.txh pexecute.txh simple-object.txh
|
||||
|
||||
libiberty.info : $(srcdir)/libiberty.texi $(TEXISRC)
|
||||
$(MAKEINFO) -I$(srcdir) $(srcdir)/libiberty.texi
|
||||
@ -965,6 +971,38 @@ $(CONFIGURED_OFILES): stamp-picdir
|
||||
else true; fi
|
||||
$(COMPILE.c) $(srcdir)/sigsetmask.c $(OUTPUT_OPTION)
|
||||
|
||||
./simple-object-coff.$(objext): $(srcdir)/simple-object-coff.c config.h \
|
||||
$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
|
||||
$(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h
|
||||
if [ x"$(PICFLAG)" != x ]; then \
|
||||
$(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-coff.c -o pic/$@; \
|
||||
else true; fi
|
||||
$(COMPILE.c) $(srcdir)/simple-object-coff.c $(OUTPUT_OPTION)
|
||||
|
||||
./simple-object-elf.$(objext): $(srcdir)/simple-object-elf.c config.h \
|
||||
$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
|
||||
$(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h
|
||||
if [ x"$(PICFLAG)" != x ]; then \
|
||||
$(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-elf.c -o pic/$@; \
|
||||
else true; fi
|
||||
$(COMPILE.c) $(srcdir)/simple-object-elf.c $(OUTPUT_OPTION)
|
||||
|
||||
./simple-object-mach-o.$(objext): $(srcdir)/simple-object-mach-o.c config.h \
|
||||
$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
|
||||
$(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h
|
||||
if [ x"$(PICFLAG)" != x ]; then \
|
||||
$(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-mach-o.c -o pic/$@; \
|
||||
else true; fi
|
||||
$(COMPILE.c) $(srcdir)/simple-object-mach-o.c $(OUTPUT_OPTION)
|
||||
|
||||
./simple-object.$(objext): $(srcdir)/simple-object.c config.h \
|
||||
$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
|
||||
$(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h
|
||||
if [ x"$(PICFLAG)" != x ]; then \
|
||||
$(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object.c -o pic/$@; \
|
||||
else true; fi
|
||||
$(COMPILE.c) $(srcdir)/simple-object.c $(OUTPUT_OPTION)
|
||||
|
||||
./snprintf.$(objext): $(srcdir)/snprintf.c $(INCDIR)/ansidecl.h
|
||||
if [ x"$(PICFLAG)" != x ]; then \
|
||||
$(COMPILE.c) $(PICFLAG) $(srcdir)/snprintf.c -o pic/$@; \
|
||||
|
@ -467,6 +467,9 @@
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define to the type of an unsigned integer type wide enough to hold a
|
||||
pointer, if such a type exists, and if the system does not define it. */
|
||||
#undef uintptr_t
|
||||
|
11
libiberty/configure
vendored
11
libiberty/configure
vendored
@ -5203,6 +5203,17 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
|
||||
|
||||
ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default"
|
||||
if test "x$ac_cv_type_ssize_t" = x""yes; then :
|
||||
|
||||
else
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define ssize_t int
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Given the above check, we always have uintptr_t or a fallback
|
||||
# definition. So define HAVE_UINTPTR_T in case any imported code
|
||||
|
@ -290,6 +290,7 @@ fi
|
||||
|
||||
AC_TYPE_INTPTR_T
|
||||
AC_TYPE_UINTPTR_T
|
||||
AC_TYPE_SSIZE_T
|
||||
|
||||
# Given the above check, we always have uintptr_t or a fallback
|
||||
# definition. So define HAVE_UINTPTR_T in case any imported code
|
||||
|
@ -1181,6 +1181,186 @@ be the value @code{1}).
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:87
|
||||
@deftypefn Extension {const char *} simple_object_attributes_compare (simple_object_attributes *@var{attrs1}, simple_object_attributes *@var{attrs2}, int *@var{err})
|
||||
|
||||
Compare @var{attrs1} and @var{attrs2}. If they could be linked
|
||||
together without error, return @code{NULL}. Otherwise, return an
|
||||
error message and set @code{*@var{err}} to an errno value or @code{0}
|
||||
if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:73
|
||||
@deftypefn Extension {simple_object_attributes *} simple_object_fetch_attributes (simple_object_read *@var{simple_object}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Fetch the attributes of @var{simple_object}. The attributes are
|
||||
internal information such as the format of the object file, or the
|
||||
architecture it was compiled for. This information will persist until
|
||||
@code{simple_object_attributes_release} is called, even if
|
||||
@var{simple_object} itself is released.
|
||||
|
||||
On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an
|
||||
error message, and sets @code{*@var{err}} to an errno value or
|
||||
@code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:44
|
||||
@deftypefn Extension {int} simple_object_find_section (simple_object_read *@var{simple_object} off_t *@var{offset}, off_t *@var{length}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Look for the section @var{name} in @var{simple_object}. This returns
|
||||
information for the first section with that name.
|
||||
|
||||
If found, return 1 and set @code{*@var{offset}} to the offset in the
|
||||
file of the section contents and set @code{*@var{length}} to the
|
||||
length of the section contents. The value in @code{*@var{offset}}
|
||||
will be relative to the offset passed to
|
||||
@code{simple_object_open_read}.
|
||||
|
||||
If the section is not found, and no error occurs,
|
||||
@code{simple_object_find_section} returns @code{0} and set
|
||||
@code{*@var{errmsg}} to @code{NULL}.
|
||||
|
||||
If an error occurs, @code{simple_object_find_section} returns
|
||||
@code{0}, sets @code{*@var{errmsg}} to an error message, and sets
|
||||
@code{*@var{err}} to an errno value or @code{0} if there is no
|
||||
relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:25
|
||||
@deftypefn Extension {const char *} simple_object_find_sections (simple_object_read *@var{simple_object}, int (*@var{pfn}) (void *@var{data}, const char *@var{name}, off_t @var{offset}, off_t @var{length}), void *@var{data}, int *@var{err})
|
||||
|
||||
This function calls @var{pfn} for each section in @var{simple_object}.
|
||||
It calls @var{pfn} with the section name, the offset within the file
|
||||
of the section contents, and the length of the section contents. The
|
||||
offset within the file is relative to the offset passed to
|
||||
@code{simple_object_open_read}. The @var{data} argument to this
|
||||
function is passed along to @var{pfn}.
|
||||
|
||||
If @var{pfn} returns @code{0}, the loop over the sections stops and
|
||||
@code{simple_object_find_sections} returns. If @var{pfn} returns some
|
||||
other value, the loop continues.
|
||||
|
||||
On success @code{simple_object_find_sections} returns. On error it
|
||||
returns an error string, and sets @code{*@var{err}} to an errno value
|
||||
or @code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:2
|
||||
@deftypefn Extension {simple_object_read *} simple_object_open_read (int @var{descriptor}, off_t @var{offset}, const char *{segment_name}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Opens an object file for reading. Creates and returns an
|
||||
@code{simple_object_read} pointer which may be passed to other
|
||||
functions to extract data from the object file.
|
||||
|
||||
@var{descriptor} holds a file descriptor which permits reading.
|
||||
|
||||
@var{offset} is the offset into the file; this will be @code{0} in the
|
||||
normal case, but may be a different value when reading an object file
|
||||
in an archive file.
|
||||
|
||||
@var{segment_name} is only used with the Mach-O file format used on
|
||||
Darwin aka Mac OS X. It is required on that platform, and means to
|
||||
only look at sections within the segment with that name. The
|
||||
parameter is ignored on other systems.
|
||||
|
||||
If an error occurs, this functions returns @code{NULL} and sets
|
||||
@code{*@var{errmsg}} to an error string and sets @code{*@var{err}} to
|
||||
an errno value or @code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:96
|
||||
@deftypefn Extension {void} simple_object_release_attributes (simple_object_attributes *@var{attrs})
|
||||
|
||||
Release all resources associated with @var{attrs}.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:66
|
||||
@deftypefn Extension {void} simple_object_release_read (simple_object_read *@var{simple_object})
|
||||
|
||||
Release all resources associated with @var{simple_object}. This does
|
||||
not close the file descriptor.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:164
|
||||
@deftypefn Extension {void} simple_object_release_write (simple_object_write *@var{simple_object})
|
||||
|
||||
Release all resources associated with @var{simple_object}.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:102
|
||||
@deftypefn Extension {simple_object_write *} simple_object_start_write (simple_object_attributes @var{attrs}, const char *@var{segment_name}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Start creating a new object file using the object file format
|
||||
described in @var{attrs}. You must fetch attribute information from
|
||||
an existing object file before you can create a new one. There is
|
||||
currently no support for creating an object file de novo.
|
||||
|
||||
@var{segment_name} is only used with Mach-O as found on Darwin aka Mac
|
||||
OS X. The parameter is required on that target. It means that all
|
||||
sections are created within the named segment. It is ignored for
|
||||
other object file formats.
|
||||
|
||||
On error @code{simple_object_start_write} returns @code{NULL}, sets
|
||||
@code{*@var{ERRMSG}} to an error message, and sets @code{*@var{err}}
|
||||
to an errno value or @code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:137
|
||||
@deftypefn Extension {const char *} simple_object_write_add_data (simple_object_write *@var{simple_object}, simple_object_write_section *@var{section}, const void *@var{buffer}, size_t @var{size}, int @var{copy}, int *@var{err})
|
||||
|
||||
Add data @var{buffer}/@var{size} to @var{section} in
|
||||
@var{simple_object}. If @var{copy} is non-zero, the data will be
|
||||
copied into memory if necessary. If @var{copy} is zero, @var{buffer}
|
||||
must persist until @code{simple_object_write_to_file} is called. is
|
||||
released.
|
||||
|
||||
On success this returns @code{NULL}. On error this returns an error
|
||||
message, and sets @code{*@var{err}} to an errno value or 0 if there is
|
||||
no relevant erro.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:120
|
||||
@deftypefn Extension {simple_object_write_section *} simple_object_write_create_section (simple_object_write *@var{simple_object}, const char *@var{name}, unsigned int @var{align}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Add a section to @var{simple_object}. @var{name} is the name of the
|
||||
new section. @var{align} is the required alignment expressed as the
|
||||
number of required low-order 0 bits (e.g., 2 for alignment to a 32-bit
|
||||
boundary).
|
||||
|
||||
The section is created as containing data, readable, not writable, not
|
||||
executable, not loaded at runtime. The section is not written to the
|
||||
file until @code{simple_object_write_to_file} is called.
|
||||
|
||||
On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an
|
||||
error message, and sets @code{*@var{err}} to an errno value or
|
||||
@code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c simple-object.txh:151
|
||||
@deftypefn Extension {const char *} simple_object_write_to_file (simple_object_write *@var{simple_object}, int @var{descriptor}, int *@var{err})
|
||||
|
||||
Write the complete object file to @var{descriptor}, an open file
|
||||
descriptor. This writes out all the data accumulated by calls to
|
||||
@code{simple_object_write_create_section} and
|
||||
@var{simple_object_write_add_data}.
|
||||
|
||||
This returns @code{NULL} on success. On error this returns an error
|
||||
message and sets @code{*@var{err}} to an errno value or @code{0} if
|
||||
there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c snprintf.c:28
|
||||
@deftypefn Supplemental int snprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, ...)
|
||||
|
||||
|
804
libiberty/simple-object-coff.c
Normal file
804
libiberty/simple-object-coff.c
Normal file
@ -0,0 +1,804 @@
|
||||
/* simple-object-coff.c -- routines to manipulate COFF object files.
|
||||
Copyright 2010 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 51 Franklin Street - Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "libiberty.h"
|
||||
#include "simple-object.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#include "simple-object-common.h"
|
||||
|
||||
/* COFF structures and constants. */
|
||||
|
||||
/* COFF file header. */
|
||||
|
||||
struct external_filehdr
|
||||
{
|
||||
unsigned char f_magic[2]; /* magic number */
|
||||
unsigned char f_nscns[2]; /* number of sections */
|
||||
unsigned char f_timdat[4]; /* time & date stamp */
|
||||
unsigned char f_symptr[4]; /* file pointer to symtab */
|
||||
unsigned char f_nsyms[4]; /* number of symtab entries */
|
||||
unsigned char f_opthdr[2]; /* sizeof(optional hdr) */
|
||||
unsigned char f_flags[2]; /* flags */
|
||||
};
|
||||
|
||||
/* Bits for filehdr f_flags field. */
|
||||
|
||||
#define F_EXEC (0x0002)
|
||||
#define IMAGE_FILE_SYSTEM (0x1000)
|
||||
#define IMAGE_FILE_DLL (0x2000)
|
||||
|
||||
/* COFF section header. */
|
||||
|
||||
struct external_scnhdr
|
||||
{
|
||||
unsigned char s_name[8]; /* section name */
|
||||
unsigned char s_paddr[4]; /* physical address, aliased s_nlib */
|
||||
unsigned char s_vaddr[4]; /* virtual address */
|
||||
unsigned char s_size[4]; /* section size */
|
||||
unsigned char s_scnptr[4]; /* file ptr to raw data for section */
|
||||
unsigned char s_relptr[4]; /* file ptr to relocation */
|
||||
unsigned char s_lnnoptr[4]; /* file ptr to line numbers */
|
||||
unsigned char s_nreloc[2]; /* number of relocation entries */
|
||||
unsigned char s_nlnno[2]; /* number of line number entries */
|
||||
unsigned char s_flags[4]; /* flags */
|
||||
};
|
||||
|
||||
/* The length of the s_name field in struct external_scnhdr. */
|
||||
|
||||
#define SCNNMLEN (8)
|
||||
|
||||
/* Bits for scnhdr s_flags field. This includes some bits defined
|
||||
only for PE. This may need to be moved into coff_magic. */
|
||||
|
||||
#define STYP_DATA (1 << 6)
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE (1 << 25)
|
||||
#define IMAGE_SCN_MEM_SHARED (1 << 28)
|
||||
#define IMAGE_SCN_MEM_READ (1 << 30)
|
||||
|
||||
#define IMAGE_SCN_ALIGN_POWER_BIT_POS 20
|
||||
#define IMAGE_SCN_ALIGN_POWER_CONST(val) \
|
||||
(((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS)
|
||||
|
||||
/* COFF symbol table entry. */
|
||||
|
||||
#define E_SYMNMLEN 8 /* # characters in a symbol name */
|
||||
|
||||
struct external_syment
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char e_name[E_SYMNMLEN];
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned char e_zeroes[4];
|
||||
unsigned char e_offset[4];
|
||||
} e;
|
||||
} e;
|
||||
|
||||
unsigned char e_value[4];
|
||||
unsigned char e_scnum[2];
|
||||
unsigned char e_type[2];
|
||||
unsigned char e_sclass[1];
|
||||
unsigned char e_numaux[1];
|
||||
};
|
||||
|
||||
/* Length allowed for filename in aux sym format 4. */
|
||||
|
||||
#define E_FILNMLEN 18
|
||||
|
||||
/* Omits x_sym and other unused variants. */
|
||||
|
||||
union external_auxent
|
||||
{
|
||||
/* Aux sym format 4: file. */
|
||||
union
|
||||
{
|
||||
char x_fname[E_FILNMLEN];
|
||||
struct
|
||||
{
|
||||
unsigned char x_zeroes[4];
|
||||
unsigned char x_offset[4];
|
||||
} x_n;
|
||||
} x_file;
|
||||
/* Aux sym format 5: section. */
|
||||
struct
|
||||
{
|
||||
unsigned char x_scnlen[4]; /* section length */
|
||||
unsigned char x_nreloc[2]; /* # relocation entries */
|
||||
unsigned char x_nlinno[2]; /* # line numbers */
|
||||
unsigned char x_checksum[4]; /* section COMDAT checksum */
|
||||
unsigned char x_associated[2]; /* COMDAT assoc section index */
|
||||
unsigned char x_comdat[1]; /* COMDAT selection number */
|
||||
} x_scn;
|
||||
};
|
||||
|
||||
/* Symbol-related constants. */
|
||||
|
||||
#define IMAGE_SYM_DEBUG (-2)
|
||||
#define IMAGE_SYM_TYPE_NULL (0)
|
||||
#define IMAGE_SYM_DTYPE_NULL (0)
|
||||
#define IMAGE_SYM_CLASS_STATIC (3)
|
||||
#define IMAGE_SYM_CLASS_FILE (103)
|
||||
|
||||
#define IMAGE_SYM_TYPE \
|
||||
((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
|
||||
|
||||
/* Private data for an simple_object_read. */
|
||||
|
||||
struct simple_object_coff_read
|
||||
{
|
||||
/* Magic number. */
|
||||
unsigned short magic;
|
||||
/* Whether the file is big-endian. */
|
||||
unsigned char is_big_endian;
|
||||
/* Number of sections. */
|
||||
unsigned short nscns;
|
||||
/* File offset of symbol table. */
|
||||
off_t symptr;
|
||||
/* Number of symbol table entries. */
|
||||
unsigned int nsyms;
|
||||
/* Flags. */
|
||||
unsigned short flags;
|
||||
/* Offset of section headers in file. */
|
||||
off_t scnhdr_offset;
|
||||
};
|
||||
|
||||
/* Private data for an simple_object_attributes. */
|
||||
|
||||
struct simple_object_coff_attributes
|
||||
{
|
||||
/* Magic number. */
|
||||
unsigned short magic;
|
||||
/* Whether the file is big-endian. */
|
||||
unsigned char is_big_endian;
|
||||
/* Flags. */
|
||||
unsigned short flags;
|
||||
};
|
||||
|
||||
/* There is no magic number which indicates a COFF file as opposed to
|
||||
any other sort of file. Instead, each COFF file starts with a
|
||||
two-byte magic number which also indicates the type of the target.
|
||||
This struct holds a magic number as well as characteristics of that
|
||||
COFF format. */
|
||||
|
||||
struct coff_magic_struct
|
||||
{
|
||||
/* Magic number. */
|
||||
unsigned short magic;
|
||||
/* Whether this magic number is for a big-endian file. */
|
||||
unsigned char is_big_endian;
|
||||
/* Flag bits, in the f_flags fields, which indicates that this file
|
||||
is not a relocatable object file. There is no flag which
|
||||
specifically indicates a relocatable object file, it is only
|
||||
implied by the absence of these flags. */
|
||||
unsigned short non_object_flags;
|
||||
};
|
||||
|
||||
/* This is a list of the COFF magic numbers which we recognize, namely
|
||||
the ones used on Windows. More can be added as needed. */
|
||||
|
||||
static const struct coff_magic_struct coff_magic[] =
|
||||
{
|
||||
/* i386. */
|
||||
{ 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
|
||||
/* x86_64. */
|
||||
{ 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }
|
||||
};
|
||||
|
||||
/* See if we have a COFF file. */
|
||||
|
||||
static void *
|
||||
simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
|
||||
int descriptor, off_t offset,
|
||||
const char *segment_name ATTRIBUTE_UNUSED,
|
||||
const char **errmsg, int *err)
|
||||
{
|
||||
size_t c;
|
||||
unsigned short magic_big;
|
||||
unsigned short magic_little;
|
||||
unsigned short magic;
|
||||
size_t i;
|
||||
int is_big_endian;
|
||||
unsigned short (*fetch_16) (const unsigned char *);
|
||||
unsigned int (*fetch_32) (const unsigned char *);
|
||||
unsigned char hdrbuf[sizeof (struct external_filehdr)];
|
||||
unsigned short flags;
|
||||
struct simple_object_coff_read *ocr;
|
||||
|
||||
c = sizeof (coff_magic) / sizeof (coff_magic[0]);
|
||||
magic_big = simple_object_fetch_big_16 (header);
|
||||
magic_little = simple_object_fetch_little_16 (header);
|
||||
for (i = 0; i < c; ++i)
|
||||
{
|
||||
if (coff_magic[i].is_big_endian
|
||||
? coff_magic[i].magic == magic_big
|
||||
: coff_magic[i].magic == magic_little)
|
||||
break;
|
||||
}
|
||||
if (i >= c)
|
||||
{
|
||||
*errmsg = NULL;
|
||||
*err = 0;
|
||||
return NULL;
|
||||
}
|
||||
is_big_endian = coff_magic[i].is_big_endian;
|
||||
|
||||
magic = is_big_endian ? magic_big : magic_little;
|
||||
fetch_16 = (is_big_endian
|
||||
? simple_object_fetch_big_16
|
||||
: simple_object_fetch_little_16);
|
||||
fetch_32 = (is_big_endian
|
||||
? simple_object_fetch_big_32
|
||||
: simple_object_fetch_little_32);
|
||||
|
||||
if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
|
||||
errmsg, err))
|
||||
return NULL;
|
||||
|
||||
flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags));
|
||||
if ((flags & coff_magic[i].non_object_flags) != 0)
|
||||
{
|
||||
*errmsg = "not relocatable object file";
|
||||
*err = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ocr = XNEW (struct simple_object_coff_read);
|
||||
ocr->magic = magic;
|
||||
ocr->is_big_endian = is_big_endian;
|
||||
ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
|
||||
ocr->symptr = fetch_32 (hdrbuf
|
||||
+ offsetof (struct external_filehdr, f_symptr));
|
||||
ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms));
|
||||
ocr->flags = flags;
|
||||
ocr->scnhdr_offset = (sizeof (struct external_filehdr)
|
||||
+ fetch_16 (hdrbuf + offsetof (struct external_filehdr,
|
||||
f_opthdr)));
|
||||
|
||||
return (void *) ocr;
|
||||
}
|
||||
|
||||
/* Read the string table in a COFF file. */
|
||||
|
||||
static char *
|
||||
simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
|
||||
const char **errmsg, int *err)
|
||||
{
|
||||
struct simple_object_coff_read *ocr =
|
||||
(struct simple_object_coff_read *) sobj->data;
|
||||
off_t strtab_offset;
|
||||
unsigned char strsizebuf[4];
|
||||
size_t strsize;
|
||||
char *strtab;
|
||||
|
||||
strtab_offset = ocr->symptr + ocr->nsyms * sizeof (struct external_syment);
|
||||
if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
|
||||
strsizebuf, 4, errmsg, err))
|
||||
return NULL;
|
||||
strsize = (ocr->is_big_endian
|
||||
? simple_object_fetch_big_32 (strsizebuf)
|
||||
: simple_object_fetch_little_32 (strsizebuf));
|
||||
strtab = XNEWVEC (char, strsize);
|
||||
if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
|
||||
(unsigned char *) strtab, strsize, errmsg,
|
||||
err))
|
||||
{
|
||||
XDELETEVEC (strtab);
|
||||
return NULL;
|
||||
}
|
||||
*strtab_size = strsize;
|
||||
return strtab;
|
||||
}
|
||||
|
||||
/* Find all sections in a COFF file. */
|
||||
|
||||
static const char *
|
||||
simple_object_coff_find_sections (simple_object_read *sobj,
|
||||
int (*pfn) (void *, const char *,
|
||||
off_t offset, off_t length),
|
||||
void *data,
|
||||
int *err)
|
||||
{
|
||||
struct simple_object_coff_read *ocr =
|
||||
(struct simple_object_coff_read *) sobj->data;
|
||||
size_t scnhdr_size;
|
||||
unsigned char *scnbuf;
|
||||
const char *errmsg;
|
||||
unsigned int (*fetch_32) (const unsigned char *);
|
||||
unsigned int nscns;
|
||||
char *strtab;
|
||||
size_t strtab_size;
|
||||
unsigned int i;
|
||||
|
||||
scnhdr_size = sizeof (struct external_scnhdr);
|
||||
scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
|
||||
if (!simple_object_internal_read (sobj->descriptor,
|
||||
sobj->offset + ocr->scnhdr_offset,
|
||||
scnbuf, scnhdr_size * ocr->nscns, &errmsg,
|
||||
err))
|
||||
{
|
||||
XDELETEVEC (scnbuf);
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
fetch_32 = (ocr->is_big_endian
|
||||
? simple_object_fetch_big_32
|
||||
: simple_object_fetch_little_32);
|
||||
|
||||
nscns = ocr->nscns;
|
||||
strtab = NULL;
|
||||
strtab_size = 0;
|
||||
for (i = 0; i < nscns; ++i)
|
||||
{
|
||||
unsigned char *scnhdr;
|
||||
unsigned char *scnname;
|
||||
char namebuf[SCNNMLEN + 1];
|
||||
char *name;
|
||||
off_t scnptr;
|
||||
unsigned int size;
|
||||
|
||||
scnhdr = scnbuf + i * scnhdr_size;
|
||||
scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
|
||||
memcpy (namebuf, scnname, SCNNMLEN);
|
||||
namebuf[SCNNMLEN] = '\0';
|
||||
name = &namebuf[0];
|
||||
if (namebuf[0] == '/')
|
||||
{
|
||||
size_t strindex;
|
||||
char *end;
|
||||
|
||||
strindex = strtol (namebuf + 1, &end, 10);
|
||||
if (*end == '\0')
|
||||
{
|
||||
/* The real section name is found in the string
|
||||
table. */
|
||||
if (strtab == NULL)
|
||||
{
|
||||
strtab = simple_object_coff_read_strtab (sobj,
|
||||
&strtab_size,
|
||||
&errmsg, err);
|
||||
if (strtab == NULL)
|
||||
{
|
||||
XDELETEVEC (scnbuf);
|
||||
return errmsg;
|
||||
}
|
||||
}
|
||||
|
||||
if (strindex < 4 || strindex >= strtab_size)
|
||||
{
|
||||
XDELETEVEC (strtab);
|
||||
XDELETEVEC (scnbuf);
|
||||
*err = 0;
|
||||
return "section string index out of range";
|
||||
}
|
||||
|
||||
name = strtab + strindex;
|
||||
}
|
||||
}
|
||||
|
||||
scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr));
|
||||
size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size));
|
||||
|
||||
if (!(*pfn) (data, name, scnptr, size))
|
||||
break;
|
||||
}
|
||||
|
||||
if (strtab != NULL)
|
||||
XDELETEVEC (strtab);
|
||||
XDELETEVEC (scnbuf);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fetch the attributes for an simple_object_read. */
|
||||
|
||||
static void *
|
||||
simple_object_coff_fetch_attributes (simple_object_read *sobj,
|
||||
const char **errmsg ATTRIBUTE_UNUSED,
|
||||
int *err ATTRIBUTE_UNUSED)
|
||||
{
|
||||
struct simple_object_coff_read *ocr =
|
||||
(struct simple_object_coff_read *) sobj->data;
|
||||
struct simple_object_coff_attributes *ret;
|
||||
|
||||
ret = XNEW (struct simple_object_coff_attributes);
|
||||
ret->magic = ocr->magic;
|
||||
ret->is_big_endian = ocr->is_big_endian;
|
||||
ret->flags = ocr->flags;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Release the private data for an simple_object_read. */
|
||||
|
||||
static void
|
||||
simple_object_coff_release_read (void *data)
|
||||
{
|
||||
XDELETE (data);
|
||||
}
|
||||
|
||||
/* Compare two attributes structures. */
|
||||
|
||||
static const char *
|
||||
simple_object_coff_attributes_compare (void *data1, void *data2, int *err)
|
||||
{
|
||||
struct simple_object_coff_attributes *attrs1 =
|
||||
(struct simple_object_coff_attributes *) data1;
|
||||
struct simple_object_coff_attributes *attrs2 =
|
||||
(struct simple_object_coff_attributes *) data2;
|
||||
|
||||
if (attrs1->magic != attrs2->magic
|
||||
|| attrs1->is_big_endian != attrs2->is_big_endian)
|
||||
{
|
||||
*err = 0;
|
||||
return "COFF object format mismatch";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Release the private data for an attributes structure. */
|
||||
|
||||
static void
|
||||
simple_object_coff_release_attributes (void *data)
|
||||
{
|
||||
XDELETE (data);
|
||||
}
|
||||
|
||||
/* Prepare to write out a file. */
|
||||
|
||||
static void *
|
||||
simple_object_coff_start_write (void *attributes_data,
|
||||
const char **errmsg ATTRIBUTE_UNUSED,
|
||||
int *err ATTRIBUTE_UNUSED)
|
||||
{
|
||||
struct simple_object_coff_attributes *attrs =
|
||||
(struct simple_object_coff_attributes *) attributes_data;
|
||||
struct simple_object_coff_attributes *ret;
|
||||
|
||||
/* We're just going to record the attributes, but we need to make a
|
||||
copy because the user may delete them. */
|
||||
ret = XNEW (struct simple_object_coff_attributes);
|
||||
*ret = *attrs;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write out a COFF filehdr. */
|
||||
|
||||
static int
|
||||
simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor,
|
||||
unsigned int nscns, size_t symtab_offset,
|
||||
unsigned int nsyms, const char **errmsg,
|
||||
int *err)
|
||||
{
|
||||
struct simple_object_coff_attributes *attrs =
|
||||
(struct simple_object_coff_attributes *) sobj->data;
|
||||
unsigned char hdrbuf[sizeof (struct external_filehdr)];
|
||||
unsigned char *hdr;
|
||||
void (*set_16) (unsigned char *, unsigned short);
|
||||
void (*set_32) (unsigned char *, unsigned int);
|
||||
|
||||
hdr = &hdrbuf[0];
|
||||
|
||||
set_16 = (attrs->is_big_endian
|
||||
? simple_object_set_big_16
|
||||
: simple_object_set_little_16);
|
||||
set_32 = (attrs->is_big_endian
|
||||
? simple_object_set_big_32
|
||||
: simple_object_set_little_32);
|
||||
|
||||
memset (hdr, 0, sizeof (struct external_filehdr));
|
||||
|
||||
set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
|
||||
set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
|
||||
/* f_timdat left as zero. */
|
||||
set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset);
|
||||
set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms);
|
||||
/* f_opthdr left as zero. */
|
||||
set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);
|
||||
|
||||
return simple_object_internal_write (descriptor, 0, hdrbuf,
|
||||
sizeof (struct external_filehdr),
|
||||
errmsg, err);
|
||||
}
|
||||
|
||||
/* Write out a COFF section header. */
|
||||
|
||||
static int
|
||||
simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor,
|
||||
const char *name, size_t *name_offset,
|
||||
off_t scnhdr_offset, size_t scnsize,
|
||||
off_t offset, unsigned int align,
|
||||
const char **errmsg, int *err)
|
||||
{
|
||||
struct simple_object_coff_attributes *attrs =
|
||||
(struct simple_object_coff_attributes *) sobj->data;
|
||||
void (*set_32) (unsigned char *, unsigned int);
|
||||
unsigned char hdrbuf[sizeof (struct external_scnhdr)];
|
||||
unsigned char *hdr;
|
||||
size_t namelen;
|
||||
unsigned int flags;
|
||||
|
||||
set_32 = (attrs->is_big_endian
|
||||
? simple_object_set_big_32
|
||||
: simple_object_set_little_32);
|
||||
|
||||
memset (hdrbuf, 0, sizeof hdrbuf);
|
||||
hdr = &hdrbuf[0];
|
||||
|
||||
namelen = strlen (name);
|
||||
if (namelen <= SCNNMLEN)
|
||||
strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name,
|
||||
SCNNMLEN);
|
||||
else
|
||||
{
|
||||
snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
|
||||
SCNNMLEN, "/%lu", (unsigned long) *name_offset);
|
||||
*name_offset += namelen + 1;
|
||||
}
|
||||
|
||||
/* s_paddr left as zero. */
|
||||
/* s_vaddr left as zero. */
|
||||
set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
|
||||
set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
|
||||
/* s_relptr left as zero. */
|
||||
/* s_lnnoptr left as zero. */
|
||||
/* s_nreloc left as zero. */
|
||||
/* s_nlnno left as zero. */
|
||||
flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED
|
||||
| IMAGE_SCN_MEM_READ);
|
||||
/* PE can represent alignment up to 13. */
|
||||
if (align > 13)
|
||||
align = 13;
|
||||
flags |= IMAGE_SCN_ALIGN_POWER_CONST(align);
|
||||
set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags);
|
||||
|
||||
return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
|
||||
sizeof (struct external_scnhdr),
|
||||
errmsg, err);
|
||||
}
|
||||
|
||||
/* Write out a complete COFF file. */
|
||||
|
||||
static const char *
|
||||
simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor,
|
||||
int *err)
|
||||
{
|
||||
struct simple_object_coff_attributes *attrs =
|
||||
(struct simple_object_coff_attributes *) sobj->data;
|
||||
unsigned int nscns, secnum;
|
||||
simple_object_write_section *section;
|
||||
off_t scnhdr_offset;
|
||||
size_t symtab_offset;
|
||||
off_t secsym_offset;
|
||||
unsigned int nsyms;
|
||||
size_t offset;
|
||||
size_t name_offset;
|
||||
const char *errmsg;
|
||||
unsigned char strsizebuf[4];
|
||||
/* The interface doesn't give us access to the name of the input file
|
||||
yet. We want to use its basename for the FILE symbol. This is
|
||||
what 'gas' uses when told to assemble from stdin. */
|
||||
const char *source_filename = "fake";
|
||||
size_t sflen;
|
||||
union
|
||||
{
|
||||
struct external_syment sym;
|
||||
union external_auxent aux;
|
||||
} syms[2];
|
||||
void (*set_16) (unsigned char *, unsigned short);
|
||||
void (*set_32) (unsigned char *, unsigned int);
|
||||
|
||||
set_16 = (attrs->is_big_endian
|
||||
? simple_object_set_big_16
|
||||
: simple_object_set_little_16);
|
||||
set_32 = (attrs->is_big_endian
|
||||
? simple_object_set_big_32
|
||||
: simple_object_set_little_32);
|
||||
|
||||
nscns = 0;
|
||||
for (section = sobj->sections; section != NULL; section = section->next)
|
||||
++nscns;
|
||||
|
||||
scnhdr_offset = sizeof (struct external_filehdr);
|
||||
offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
|
||||
name_offset = 4;
|
||||
for (section = sobj->sections; section != NULL; section = section->next)
|
||||
{
|
||||
size_t mask;
|
||||
size_t new_offset;
|
||||
size_t scnsize;
|
||||
struct simple_object_write_section_buffer *buffer;
|
||||
|
||||
mask = (1U << section->align) - 1;
|
||||
new_offset = offset & mask;
|
||||
new_offset &= ~ mask;
|
||||
while (new_offset > offset)
|
||||
{
|
||||
unsigned char zeroes[16];
|
||||
size_t write;
|
||||
|
||||
memset (zeroes, 0, sizeof zeroes);
|
||||
write = new_offset - offset;
|
||||
if (write > sizeof zeroes)
|
||||
write = sizeof zeroes;
|
||||
if (!simple_object_internal_write (descriptor, offset, zeroes, write,
|
||||
&errmsg, err))
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
scnsize = 0;
|
||||
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
|
||||
{
|
||||
if (!simple_object_internal_write (descriptor, offset + scnsize,
|
||||
((const unsigned char *)
|
||||
buffer->buffer),
|
||||
buffer->size, &errmsg, err))
|
||||
return errmsg;
|
||||
scnsize += buffer->size;
|
||||
}
|
||||
|
||||
if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name,
|
||||
&name_offset, scnhdr_offset,
|
||||
scnsize, offset, section->align,
|
||||
&errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
scnhdr_offset += sizeof (struct external_scnhdr);
|
||||
offset += scnsize;
|
||||
}
|
||||
|
||||
/* Symbol table is always half-word aligned. */
|
||||
offset += (offset & 1);
|
||||
/* There is a file symbol and a section symbol per section,
|
||||
and each of these has a single auxiliary symbol following. */
|
||||
nsyms = 2 * (nscns + 1);
|
||||
symtab_offset = offset;
|
||||
/* Advance across space reserved for symbol table to locate
|
||||
start of string table. */
|
||||
offset += nsyms * sizeof (struct external_syment);
|
||||
|
||||
/* Write out file symbol. */
|
||||
memset (&syms[0], 0, sizeof (syms));
|
||||
strcpy ((char *)&syms[0].sym.e.e_name[0], ".file");
|
||||
set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG);
|
||||
set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
|
||||
syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE;
|
||||
syms[0].sym.e_numaux[0] = 1;
|
||||
/* The name need not be nul-terminated if it fits into the x_fname field
|
||||
directly, but must be if it has to be placed into the string table. */
|
||||
sflen = strlen (source_filename);
|
||||
if (sflen <= E_FILNMLEN)
|
||||
memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
|
||||
else
|
||||
{
|
||||
set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset);
|
||||
if (!simple_object_internal_write (descriptor, offset + name_offset,
|
||||
((const unsigned char *)
|
||||
source_filename),
|
||||
sflen + 1, &errmsg, err))
|
||||
return errmsg;
|
||||
name_offset += strlen (source_filename) + 1;
|
||||
}
|
||||
if (!simple_object_internal_write (descriptor, symtab_offset,
|
||||
(const unsigned char *) &syms[0],
|
||||
sizeof (syms), &errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
/* Write the string table length, followed by the strings and section
|
||||
symbols in step with each other. */
|
||||
set_32 (strsizebuf, name_offset);
|
||||
if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
|
||||
&errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
name_offset = 4;
|
||||
secsym_offset = symtab_offset + sizeof (syms);
|
||||
memset (&syms[0], 0, sizeof (syms));
|
||||
set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
|
||||
syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC;
|
||||
syms[0].sym.e_numaux[0] = 1;
|
||||
secnum = 1;
|
||||
|
||||
for (section = sobj->sections; section != NULL; section = section->next)
|
||||
{
|
||||
size_t namelen;
|
||||
size_t scnsize;
|
||||
struct simple_object_write_section_buffer *buffer;
|
||||
|
||||
namelen = strlen (section->name);
|
||||
set_16 (&syms[0].sym.e_scnum[0], secnum++);
|
||||
scnsize = 0;
|
||||
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
|
||||
scnsize += buffer->size;
|
||||
set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
|
||||
if (namelen > SCNNMLEN)
|
||||
{
|
||||
set_32 (&syms[0].sym.e.e.e_zeroes[0], 0);
|
||||
set_32 (&syms[0].sym.e.e.e_offset[0], name_offset);
|
||||
if (!simple_object_internal_write (descriptor, offset + name_offset,
|
||||
((const unsigned char *)
|
||||
section->name),
|
||||
namelen + 1, &errmsg, err))
|
||||
return errmsg;
|
||||
name_offset += namelen + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (&syms[0].sym.e.e_name[0], section->name,
|
||||
strlen (section->name));
|
||||
memset (&syms[0].sym.e.e_name[strlen (section->name)], 0,
|
||||
E_SYMNMLEN - strlen (section->name));
|
||||
}
|
||||
|
||||
if (!simple_object_internal_write (descriptor, secsym_offset,
|
||||
(const unsigned char *) &syms[0],
|
||||
sizeof (syms), &errmsg, err))
|
||||
return errmsg;
|
||||
secsym_offset += sizeof (syms);
|
||||
}
|
||||
|
||||
if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns,
|
||||
symtab_offset, nsyms, &errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Release the private data for an simple_object_write structure. */
|
||||
|
||||
static void
|
||||
simple_object_coff_release_write (void *data)
|
||||
{
|
||||
XDELETE (data);
|
||||
}
|
||||
|
||||
/* The COFF functions. */
|
||||
|
||||
const struct simple_object_functions simple_object_coff_functions =
|
||||
{
|
||||
simple_object_coff_match,
|
||||
simple_object_coff_find_sections,
|
||||
simple_object_coff_fetch_attributes,
|
||||
simple_object_coff_release_read,
|
||||
simple_object_coff_attributes_compare,
|
||||
simple_object_coff_release_attributes,
|
||||
simple_object_coff_start_write,
|
||||
simple_object_coff_write_to_file,
|
||||
simple_object_coff_release_write
|
||||
};
|
355
libiberty/simple-object-common.h
Normal file
355
libiberty/simple-object-common.h
Normal file
@ -0,0 +1,355 @@
|
||||
/* simple-object-common.h -- common structs for object file manipulation.
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the libiberty library.
|
||||
Libiberty is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
Libiberty is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with libiberty; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Forward reference. */
|
||||
struct simple_object_functions;
|
||||
|
||||
/* An object file opened for reading. */
|
||||
|
||||
struct simple_object_read_struct
|
||||
{
|
||||
/* The file descriptor. */
|
||||
int descriptor;
|
||||
/* The offset within the file. */
|
||||
off_t offset;
|
||||
/* The functions which do the actual work. */
|
||||
const struct simple_object_functions *functions;
|
||||
/* Private data for the object file format. */
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* Object file attributes. */
|
||||
|
||||
struct simple_object_attributes_struct
|
||||
{
|
||||
/* The functions which do the actual work. */
|
||||
const struct simple_object_functions *functions;
|
||||
/* Private data for the object file format. */
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* An object file being created. */
|
||||
|
||||
struct simple_object_write_struct
|
||||
{
|
||||
/* The functions which do the actual work. */
|
||||
const struct simple_object_functions *functions;
|
||||
/* The segment_name argument from the user. */
|
||||
char *segment_name;
|
||||
/* The start of the list of sections. */
|
||||
simple_object_write_section *sections;
|
||||
/* The last entry in the list of sections. */
|
||||
simple_object_write_section *last_section;
|
||||
/* Private data for the object file format. */
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* A section in an object file being created. */
|
||||
|
||||
struct simple_object_write_section_struct
|
||||
{
|
||||
/* Next in the list of sections attached to an
|
||||
simple_object_write. */
|
||||
simple_object_write_section *next;
|
||||
/* The name of this section. */
|
||||
char *name;
|
||||
/* The required alignment. */
|
||||
unsigned int align;
|
||||
/* The first data attached to this section. */
|
||||
struct simple_object_write_section_buffer *buffers;
|
||||
/* The last data attached to this section. */
|
||||
struct simple_object_write_section_buffer *last_buffer;
|
||||
};
|
||||
|
||||
/* Data attached to a section. */
|
||||
|
||||
struct simple_object_write_section_buffer
|
||||
{
|
||||
/* The next data for this section. */
|
||||
struct simple_object_write_section_buffer *next;
|
||||
/* The size of the buffer. */
|
||||
size_t size;
|
||||
/* The actual bytes. */
|
||||
const void *buffer;
|
||||
/* A buffer to free, or NULL. */
|
||||
void *free_buffer;
|
||||
};
|
||||
|
||||
/* The number of bytes we read from the start of the file to pass to
|
||||
the match function. */
|
||||
#define SIMPLE_OBJECT_MATCH_HEADER_LEN (16)
|
||||
|
||||
/* Format-specific object file functions. */
|
||||
|
||||
struct simple_object_functions
|
||||
{
|
||||
/* If this file matches these functions, return a new value for the
|
||||
private data for an simple_object_read. HEADER is the first 16
|
||||
bytes of the file. DESCRIPTOR, OFFSET, SEGMENT_NAME, ERRMSG, and
|
||||
ERR are as for simple_object_open_read. If this file does not
|
||||
match, this function should return NULL with *ERRMSG set to
|
||||
NULL. */
|
||||
void *(*match) (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
|
||||
int descriptor, off_t offset, const char *segment_name,
|
||||
const char **errmsg, int *err);
|
||||
|
||||
/* Implement simple_object_find_sections. */
|
||||
const char *(*find_sections) (simple_object_read *,
|
||||
int (*pfn) (void *, const char *,
|
||||
off_t offset, off_t length),
|
||||
void *data,
|
||||
int *err);
|
||||
|
||||
/* Return the private data for the attributes for SOBJ. */
|
||||
void *(*fetch_attributes) (simple_object_read *sobj, const char **errmsg,
|
||||
int *err);
|
||||
|
||||
/* Release the private data for an simple_object_read. */
|
||||
void (*release_read) (void *);
|
||||
|
||||
/* Compare the private data for the attributes of two files. If
|
||||
they are the same, in the sense that they could be linked
|
||||
together, return NULL. Otherwise return an error message. */
|
||||
const char *(*attributes_compare) (void *, void *, int *err);
|
||||
|
||||
/* Release the private data for an simple_object_attributes. */
|
||||
void (*release_attributes) (void *);
|
||||
|
||||
/* Start creating an object file. */
|
||||
void *(*start_write) (void *attributes_data, const char **errmsg,
|
||||
int *err);
|
||||
|
||||
/* Write the complete object file. */
|
||||
const char *(*write_to_file) (simple_object_write *sobj, int descriptor,
|
||||
int *err);
|
||||
|
||||
/* Release the private data for an simple_object_write. */
|
||||
void (*release_write) (void *);
|
||||
};
|
||||
|
||||
/* The known object file formats. */
|
||||
|
||||
extern const struct simple_object_functions simple_object_coff_functions;
|
||||
extern const struct simple_object_functions simple_object_elf_functions;
|
||||
extern const struct simple_object_functions simple_object_mach_o_functions;
|
||||
|
||||
/* Read SIZE bytes from DESCRIPTOR at file offset OFFSET into BUFFER.
|
||||
Return non-zero on success. On failure return 0 and set *ERRMSG
|
||||
and *ERR. */
|
||||
|
||||
extern int
|
||||
simple_object_internal_read (int descriptor, off_t offset,
|
||||
unsigned char *buffer, size_t size,
|
||||
const char **errmsg, int *err);
|
||||
|
||||
/* Write SIZE bytes from BUFFER to DESCRIPTOR at file offset OFFSET.
|
||||
Return non-zero on success. On failure return 0 and set *ERRMSG
|
||||
and *ERR. */
|
||||
|
||||
extern int
|
||||
simple_object_internal_write (int descriptor, off_t offset,
|
||||
const unsigned char *buffer, size_t size,
|
||||
const char **errmsg, int *err);
|
||||
|
||||
/* Define ulong_type as an unsigned 64-bit type if available.
|
||||
Otherwise just make it unsigned long. */
|
||||
|
||||
#ifdef UNSIGNED_64BIT_TYPE
|
||||
__extension__ typedef UNSIGNED_64BIT_TYPE ulong_type;
|
||||
#else
|
||||
typedef unsigned long ulong_type;
|
||||
#endif
|
||||
|
||||
/* Fetch a big-endian 16-bit value. */
|
||||
|
||||
static inline unsigned short
|
||||
simple_object_fetch_big_16 (const unsigned char *buf)
|
||||
{
|
||||
return ((unsigned short) buf[0] << 8) | (unsigned short) buf[1];
|
||||
}
|
||||
|
||||
/* Fetch a little-endian 16-bit value. */
|
||||
|
||||
static inline unsigned short
|
||||
simple_object_fetch_little_16 (const unsigned char *buf)
|
||||
{
|
||||
return ((unsigned short) buf[1] << 8) | (unsigned short) buf[0];
|
||||
}
|
||||
|
||||
/* Fetch a big-endian 32-bit value. */
|
||||
|
||||
static inline unsigned int
|
||||
simple_object_fetch_big_32 (const unsigned char *buf)
|
||||
{
|
||||
return (((unsigned int) buf[0] << 24)
|
||||
| ((unsigned int) buf[1] << 16)
|
||||
| ((unsigned int) buf[2] << 8)
|
||||
| (unsigned int) buf[3]);
|
||||
}
|
||||
|
||||
/* Fetch a little-endian 32-bit value. */
|
||||
|
||||
static inline unsigned int
|
||||
simple_object_fetch_little_32 (const unsigned char *buf)
|
||||
{
|
||||
return (((unsigned int) buf[3] << 24)
|
||||
| ((unsigned int) buf[2] << 16)
|
||||
| ((unsigned int) buf[1] << 8)
|
||||
| (unsigned int) buf[0]);
|
||||
}
|
||||
|
||||
/* Fetch a big-endian 32-bit value as a ulong_type. */
|
||||
|
||||
static inline ulong_type
|
||||
simple_object_fetch_big_32_ulong (const unsigned char *buf)
|
||||
{
|
||||
return (ulong_type) simple_object_fetch_big_32 (buf);
|
||||
}
|
||||
|
||||
/* Fetch a little-endian 32-bit value as a ulong_type. */
|
||||
|
||||
static inline ulong_type
|
||||
simple_object_fetch_little_32_ulong (const unsigned char *buf)
|
||||
{
|
||||
return (ulong_type) simple_object_fetch_little_32 (buf);
|
||||
}
|
||||
|
||||
#ifdef UNSIGNED_64BIT_TYPE
|
||||
|
||||
/* Fetch a big-endian 64-bit value. */
|
||||
|
||||
static inline ulong_type
|
||||
simple_object_fetch_big_64 (const unsigned char *buf)
|
||||
{
|
||||
return (((ulong_type) buf[0] << 56)
|
||||
| ((ulong_type) buf[1] << 48)
|
||||
| ((ulong_type) buf[2] << 40)
|
||||
| ((ulong_type) buf[3] << 32)
|
||||
| ((ulong_type) buf[4] << 24)
|
||||
| ((ulong_type) buf[5] << 16)
|
||||
| ((ulong_type) buf[6] << 8)
|
||||
| (ulong_type) buf[7]);
|
||||
}
|
||||
|
||||
/* Fetch a little-endian 64-bit value. */
|
||||
|
||||
static inline ulong_type
|
||||
simple_object_fetch_little_64 (const unsigned char *buf)
|
||||
{
|
||||
return (((ulong_type) buf[7] << 56)
|
||||
| ((ulong_type) buf[6] << 48)
|
||||
| ((ulong_type) buf[5] << 40)
|
||||
| ((ulong_type) buf[4] << 32)
|
||||
| ((ulong_type) buf[3] << 24)
|
||||
| ((ulong_type) buf[2] << 16)
|
||||
| ((ulong_type) buf[1] << 8)
|
||||
| (ulong_type) buf[0]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Store a big-endian 16-bit value. */
|
||||
|
||||
static inline void
|
||||
simple_object_set_big_16 (unsigned char *buf, unsigned short val)
|
||||
{
|
||||
buf[0] = (val >> 8) & 0xff;
|
||||
buf[1] = val & 0xff;
|
||||
}
|
||||
|
||||
/* Store a little-endian 16-bit value. */
|
||||
|
||||
static inline void
|
||||
simple_object_set_little_16 (unsigned char *buf, unsigned short val)
|
||||
{
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
buf[0] = val & 0xff;
|
||||
}
|
||||
|
||||
/* Store a big-endian 32-bit value. */
|
||||
|
||||
static inline void
|
||||
simple_object_set_big_32 (unsigned char *buf, unsigned int val)
|
||||
{
|
||||
buf[0] = (val >> 24) & 0xff;
|
||||
buf[1] = (val >> 16) & 0xff;
|
||||
buf[2] = (val >> 8) & 0xff;
|
||||
buf[3] = val & 0xff;
|
||||
}
|
||||
|
||||
/* Store a little-endian 32-bit value. */
|
||||
|
||||
static inline void
|
||||
simple_object_set_little_32 (unsigned char *buf, unsigned int val)
|
||||
{
|
||||
buf[3] = (val >> 24) & 0xff;
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
buf[0] = val & 0xff;
|
||||
}
|
||||
|
||||
/* Store a big-endian 32-bit value coming in as a ulong_type. */
|
||||
|
||||
static inline void
|
||||
simple_object_set_big_32_ulong (unsigned char *buf, ulong_type val)
|
||||
{
|
||||
simple_object_set_big_32 (buf, val);
|
||||
}
|
||||
|
||||
/* Store a little-endian 32-bit value coming in as a ulong_type. */
|
||||
|
||||
static inline void
|
||||
simple_object_set_little_32_ulong (unsigned char *buf, ulong_type val)
|
||||
{
|
||||
simple_object_set_little_32 (buf, val);
|
||||
}
|
||||
|
||||
#ifdef UNSIGNED_64BIT_TYPE
|
||||
|
||||
/* Store a big-endian 64-bit value. */
|
||||
|
||||
static inline void
|
||||
simple_object_set_big_64 (unsigned char *buf, ulong_type val)
|
||||
{
|
||||
buf[0] = (val >> 56) & 0xff;
|
||||
buf[1] = (val >> 48) & 0xff;
|
||||
buf[2] = (val >> 40) & 0xff;
|
||||
buf[3] = (val >> 32) & 0xff;
|
||||
buf[4] = (val >> 24) & 0xff;
|
||||
buf[5] = (val >> 16) & 0xff;
|
||||
buf[6] = (val >> 8) & 0xff;
|
||||
buf[7] = val & 0xff;
|
||||
}
|
||||
|
||||
/* Store a little-endian 64-bit value. */
|
||||
|
||||
static inline void
|
||||
simple_object_set_little_64 (unsigned char *buf, ulong_type val)
|
||||
{
|
||||
buf[7] = (val >> 56) & 0xff;
|
||||
buf[6] = (val >> 48) & 0xff;
|
||||
buf[5] = (val >> 40) & 0xff;
|
||||
buf[4] = (val >> 32) & 0xff;
|
||||
buf[3] = (val >> 24) & 0xff;
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
buf[0] = val & 0xff;
|
||||
}
|
||||
|
||||
#endif
|
916
libiberty/simple-object-elf.c
Normal file
916
libiberty/simple-object-elf.c
Normal file
@ -0,0 +1,916 @@
|
||||
/* simple-object-elf.c -- routines to manipulate ELF object files.
|
||||
Copyright 2010 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 51 Franklin Street - Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "libiberty.h"
|
||||
#include "simple-object.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#include "simple-object-common.h"
|
||||
|
||||
/* ELF structures and constants. */
|
||||
|
||||
/* 32-bit ELF file header. */
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[16]; /* ELF "magic number" */
|
||||
unsigned char e_type[2]; /* Identifies object file type */
|
||||
unsigned char e_machine[2]; /* Specifies required architecture */
|
||||
unsigned char e_version[4]; /* Identifies object file version */
|
||||
unsigned char e_entry[4]; /* Entry point virtual address */
|
||||
unsigned char e_phoff[4]; /* Program header table file offset */
|
||||
unsigned char e_shoff[4]; /* Section header table file offset */
|
||||
unsigned char e_flags[4]; /* Processor-specific flags */
|
||||
unsigned char e_ehsize[2]; /* ELF header size in bytes */
|
||||
unsigned char e_phentsize[2]; /* Program header table entry size */
|
||||
unsigned char e_phnum[2]; /* Program header table entry count */
|
||||
unsigned char e_shentsize[2]; /* Section header table entry size */
|
||||
unsigned char e_shnum[2]; /* Section header table entry count */
|
||||
unsigned char e_shstrndx[2]; /* Section header string table index */
|
||||
} Elf32_External_Ehdr;
|
||||
|
||||
/* 64-bit ELF file header. */
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[16]; /* ELF "magic number" */
|
||||
unsigned char e_type[2]; /* Identifies object file type */
|
||||
unsigned char e_machine[2]; /* Specifies required architecture */
|
||||
unsigned char e_version[4]; /* Identifies object file version */
|
||||
unsigned char e_entry[8]; /* Entry point virtual address */
|
||||
unsigned char e_phoff[8]; /* Program header table file offset */
|
||||
unsigned char e_shoff[8]; /* Section header table file offset */
|
||||
unsigned char e_flags[4]; /* Processor-specific flags */
|
||||
unsigned char e_ehsize[2]; /* ELF header size in bytes */
|
||||
unsigned char e_phentsize[2]; /* Program header table entry size */
|
||||
unsigned char e_phnum[2]; /* Program header table entry count */
|
||||
unsigned char e_shentsize[2]; /* Section header table entry size */
|
||||
unsigned char e_shnum[2]; /* Section header table entry count */
|
||||
unsigned char e_shstrndx[2]; /* Section header string table index */
|
||||
} Elf64_External_Ehdr;
|
||||
|
||||
/* Indexes and values in e_ident field of Ehdr. */
|
||||
|
||||
#define EI_MAG0 0 /* File identification byte 0 index */
|
||||
#define ELFMAG0 0x7F /* Magic number byte 0 */
|
||||
|
||||
#define EI_MAG1 1 /* File identification byte 1 index */
|
||||
#define ELFMAG1 'E' /* Magic number byte 1 */
|
||||
|
||||
#define EI_MAG2 2 /* File identification byte 2 index */
|
||||
#define ELFMAG2 'L' /* Magic number byte 2 */
|
||||
|
||||
#define EI_MAG3 3 /* File identification byte 3 index */
|
||||
#define ELFMAG3 'F' /* Magic number byte 3 */
|
||||
|
||||
#define EI_CLASS 4 /* File class */
|
||||
#define ELFCLASSNONE 0 /* Invalid class */
|
||||
#define ELFCLASS32 1 /* 32-bit objects */
|
||||
#define ELFCLASS64 2 /* 64-bit objects */
|
||||
|
||||
#define EI_DATA 5 /* Data encoding */
|
||||
#define ELFDATANONE 0 /* Invalid data encoding */
|
||||
#define ELFDATA2LSB 1 /* 2's complement, little endian */
|
||||
#define ELFDATA2MSB 2 /* 2's complement, big endian */
|
||||
|
||||
#define EI_VERSION 6 /* File version */
|
||||
#define EV_CURRENT 1 /* Current version */
|
||||
|
||||
#define EI_OSABI 7 /* Operating System/ABI indication */
|
||||
|
||||
/* Values for e_type field of Ehdr. */
|
||||
|
||||
#define ET_REL 1 /* Relocatable file */
|
||||
|
||||
/* Special section index values. */
|
||||
|
||||
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
|
||||
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
|
||||
|
||||
/* 32-bit ELF program header. */
|
||||
|
||||
typedef struct {
|
||||
unsigned char p_type[4]; /* Identifies program segment type */
|
||||
unsigned char p_offset[4]; /* Segment file offset */
|
||||
unsigned char p_vaddr[4]; /* Segment virtual address */
|
||||
unsigned char p_paddr[4]; /* Segment physical address */
|
||||
unsigned char p_filesz[4]; /* Segment size in file */
|
||||
unsigned char p_memsz[4]; /* Segment size in memory */
|
||||
unsigned char p_flags[4]; /* Segment flags */
|
||||
unsigned char p_align[4]; /* Segment alignment, file & memory */
|
||||
} Elf32_External_Phdr;
|
||||
|
||||
/* 64-bit ELF program header. */
|
||||
|
||||
typedef struct {
|
||||
unsigned char p_type[4]; /* Identifies program segment type */
|
||||
unsigned char p_flags[4]; /* Segment flags */
|
||||
unsigned char p_offset[8]; /* Segment file offset */
|
||||
unsigned char p_vaddr[8]; /* Segment virtual address */
|
||||
unsigned char p_paddr[8]; /* Segment physical address */
|
||||
unsigned char p_filesz[8]; /* Segment size in file */
|
||||
unsigned char p_memsz[8]; /* Segment size in memory */
|
||||
unsigned char p_align[8]; /* Segment alignment, file & memory */
|
||||
} Elf64_External_Phdr;
|
||||
|
||||
/* 32-bit ELF section header */
|
||||
|
||||
typedef struct {
|
||||
unsigned char sh_name[4]; /* Section name, index in string tbl */
|
||||
unsigned char sh_type[4]; /* Type of section */
|
||||
unsigned char sh_flags[4]; /* Miscellaneous section attributes */
|
||||
unsigned char sh_addr[4]; /* Section virtual addr at execution */
|
||||
unsigned char sh_offset[4]; /* Section file offset */
|
||||
unsigned char sh_size[4]; /* Size of section in bytes */
|
||||
unsigned char sh_link[4]; /* Index of another section */
|
||||
unsigned char sh_info[4]; /* Additional section information */
|
||||
unsigned char sh_addralign[4]; /* Section alignment */
|
||||
unsigned char sh_entsize[4]; /* Entry size if section holds table */
|
||||
} Elf32_External_Shdr;
|
||||
|
||||
/* 64-bit ELF section header. */
|
||||
|
||||
typedef struct {
|
||||
unsigned char sh_name[4]; /* Section name, index in string tbl */
|
||||
unsigned char sh_type[4]; /* Type of section */
|
||||
unsigned char sh_flags[8]; /* Miscellaneous section attributes */
|
||||
unsigned char sh_addr[8]; /* Section virtual addr at execution */
|
||||
unsigned char sh_offset[8]; /* Section file offset */
|
||||
unsigned char sh_size[8]; /* Size of section in bytes */
|
||||
unsigned char sh_link[4]; /* Index of another section */
|
||||
unsigned char sh_info[4]; /* Additional section information */
|
||||
unsigned char sh_addralign[8]; /* Section alignment */
|
||||
unsigned char sh_entsize[8]; /* Entry size if section holds table */
|
||||
} Elf64_External_Shdr;
|
||||
|
||||
/* Values for sh_type field. */
|
||||
|
||||
#define SHT_PROGBITS 1 /* Program data */
|
||||
#define SHT_STRTAB 3 /* A string table */
|
||||
|
||||
/* Functions to fetch and store different ELF types, depending on the
|
||||
endianness and size. */
|
||||
|
||||
struct elf_type_functions
|
||||
{
|
||||
unsigned short (*fetch_Elf_Half) (const unsigned char *);
|
||||
unsigned int (*fetch_Elf_Word) (const unsigned char *);
|
||||
ulong_type (*fetch_Elf_Addr) (const unsigned char *);
|
||||
void (*set_Elf_Half) (unsigned char *, unsigned short);
|
||||
void (*set_Elf_Word) (unsigned char *, unsigned int);
|
||||
void (*set_Elf_Addr) (unsigned char *, ulong_type);
|
||||
};
|
||||
|
||||
static const struct elf_type_functions elf_big_32_functions =
|
||||
{
|
||||
simple_object_fetch_big_16,
|
||||
simple_object_fetch_big_32,
|
||||
simple_object_fetch_big_32_ulong,
|
||||
simple_object_set_big_16,
|
||||
simple_object_set_big_32,
|
||||
simple_object_set_big_32_ulong
|
||||
};
|
||||
|
||||
static const struct elf_type_functions elf_little_32_functions =
|
||||
{
|
||||
simple_object_fetch_little_16,
|
||||
simple_object_fetch_little_32,
|
||||
simple_object_fetch_little_32_ulong,
|
||||
simple_object_set_little_16,
|
||||
simple_object_set_little_32,
|
||||
simple_object_set_little_32_ulong
|
||||
};
|
||||
|
||||
#ifdef UNSIGNED_64BIT_TYPE
|
||||
|
||||
static const struct elf_type_functions elf_big_64_functions =
|
||||
{
|
||||
simple_object_fetch_big_16,
|
||||
simple_object_fetch_big_32,
|
||||
simple_object_fetch_big_64,
|
||||
simple_object_set_big_16,
|
||||
simple_object_set_big_32,
|
||||
simple_object_set_big_64
|
||||
};
|
||||
|
||||
static const struct elf_type_functions elf_little_64_functions =
|
||||
{
|
||||
simple_object_fetch_little_16,
|
||||
simple_object_fetch_little_32,
|
||||
simple_object_fetch_little_64,
|
||||
simple_object_set_little_16,
|
||||
simple_object_set_little_32,
|
||||
simple_object_set_little_64
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* Hideous macro to fetch the value of a field from an external ELF
|
||||
struct of some sort. TYPEFUNCS is the set of type functions.
|
||||
BUFFER points to the external data. STRUCTTYPE is the appropriate
|
||||
struct type. FIELD is a field within the struct. TYPE is the type
|
||||
of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr. */
|
||||
|
||||
#define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
|
||||
((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
|
||||
|
||||
/* Even more hideous macro to fetch the value of FIELD from BUFFER.
|
||||
SIZE is 32 or 64. STRUCTTYPE is the name of the struct from
|
||||
elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in
|
||||
the struct. TYPE is the type of the field in the struct: Elf_Half,
|
||||
Elf_Word, or Elf_Addr. */
|
||||
|
||||
#define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, \
|
||||
FIELD, TYPE) \
|
||||
ELF_FETCH_STRUCT_FIELD (TYPEFUNCS, \
|
||||
Elf ## SIZE ## _External_ ## STRUCTTYPE, \
|
||||
FIELD, BUFFER, TYPE)
|
||||
|
||||
/* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value. */
|
||||
|
||||
#define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, \
|
||||
FIELD, TYPE) \
|
||||
((CLASS) == ELFCLASS32 \
|
||||
? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \
|
||||
TYPE) \
|
||||
: ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \
|
||||
TYPE))
|
||||
|
||||
/* Hideous macro to set the value of a field in an external ELF
|
||||
structure to VAL. TYPEFUNCS is the set of type functions. BUFFER
|
||||
points to the external data. STRUCTTYPE is the appropriate
|
||||
structure type. FIELD is a field within the struct. TYPE is the
|
||||
type of the field in the struct: Elf_Half, Elf_Word, or
|
||||
Elf_Addr. */
|
||||
|
||||
#define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
|
||||
(TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
|
||||
|
||||
/* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
|
||||
SIZE is 32 or 64. STRUCTTYPE is the name of the struct from
|
||||
elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in
|
||||
the struct. TYPE is the type of the field in the struct: Elf_Half,
|
||||
Elf_Word, or Elf_Addr. */
|
||||
|
||||
#define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
|
||||
TYPE, VAL) \
|
||||
ELF_SET_STRUCT_FIELD (TYPEFUNCS, \
|
||||
Elf ## SIZE ## _External_ ## STRUCTTYPE, \
|
||||
FIELD, BUFFER, TYPE, VAL)
|
||||
|
||||
/* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value. */
|
||||
|
||||
#define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD, \
|
||||
TYPE, VAL) \
|
||||
((CLASS) == ELFCLASS32 \
|
||||
? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \
|
||||
TYPE, VAL) \
|
||||
: ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \
|
||||
TYPE, VAL))
|
||||
|
||||
/* Private data for an simple_object_read. */
|
||||
|
||||
struct simple_object_elf_read
|
||||
{
|
||||
/* Type functions. */
|
||||
const struct elf_type_functions* type_functions;
|
||||
/* Elf data. */
|
||||
unsigned char ei_data;
|
||||
/* Elf class. */
|
||||
unsigned char ei_class;
|
||||
/* ELF OS ABI. */
|
||||
unsigned char ei_osabi;
|
||||
/* Elf machine number. */
|
||||
unsigned short machine;
|
||||
/* Processor specific flags. */
|
||||
unsigned int flags;
|
||||
/* File offset of section headers. */
|
||||
ulong_type shoff;
|
||||
/* Number of sections. */
|
||||
unsigned int shnum;
|
||||
/* Index of string table section header. */
|
||||
unsigned int shstrndx;
|
||||
};
|
||||
|
||||
/* Private data for an simple_object_attributes. */
|
||||
|
||||
struct simple_object_elf_attributes
|
||||
{
|
||||
/* Type functions. */
|
||||
const struct elf_type_functions* type_functions;
|
||||
/* Elf data. */
|
||||
unsigned char ei_data;
|
||||
/* Elf class. */
|
||||
unsigned char ei_class;
|
||||
/* ELF OS ABI. */
|
||||
unsigned char ei_osabi;
|
||||
/* Elf machine number. */
|
||||
unsigned short machine;
|
||||
/* Processor specific flags. */
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* See if we have an ELF file. */
|
||||
|
||||
static void *
|
||||
simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
|
||||
int descriptor, off_t offset,
|
||||
const char *segment_name ATTRIBUTE_UNUSED,
|
||||
const char **errmsg, int *err)
|
||||
{
|
||||
unsigned char ei_data;
|
||||
unsigned char ei_class;
|
||||
const struct elf_type_functions *type_functions;
|
||||
unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
|
||||
struct simple_object_elf_read *eor;
|
||||
|
||||
if (header[EI_MAG0] != ELFMAG0
|
||||
|| header[EI_MAG1] != ELFMAG1
|
||||
|| header[EI_MAG2] != ELFMAG2
|
||||
|| header[EI_MAG3] != ELFMAG3
|
||||
|| header[EI_VERSION] != EV_CURRENT)
|
||||
{
|
||||
*errmsg = NULL;
|
||||
*err = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ei_data = header[EI_DATA];
|
||||
if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
|
||||
{
|
||||
*errmsg = "unknown ELF endianness";
|
||||
*err = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ei_class = header[EI_CLASS];
|
||||
switch (ei_class)
|
||||
{
|
||||
case ELFCLASS32:
|
||||
type_functions = (ei_data == ELFDATA2LSB
|
||||
? &elf_little_32_functions
|
||||
: &elf_big_32_functions);
|
||||
break;
|
||||
|
||||
case ELFCLASS64:
|
||||
#ifndef UNSIGNED_64BIT_TYPE
|
||||
*errmsg = "64-bit ELF objects not supported";
|
||||
*err = 0;
|
||||
return NULL;
|
||||
#else
|
||||
type_functions = (ei_data == ELFDATA2LSB
|
||||
? &elf_little_64_functions
|
||||
: &elf_big_64_functions);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
*errmsg = "unrecognized ELF size";
|
||||
*err = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr,
|
||||
errmsg, err))
|
||||
return NULL;
|
||||
|
||||
eor = XNEW (struct simple_object_elf_read);
|
||||
eor->type_functions = type_functions;
|
||||
eor->ei_data = ei_data;
|
||||
eor->ei_class = ei_class;
|
||||
eor->ei_osabi = header[EI_OSABI];
|
||||
eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
|
||||
e_machine, Elf_Half);
|
||||
eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
|
||||
e_flags, Elf_Word);
|
||||
eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
|
||||
e_shoff, Elf_Addr);
|
||||
eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
|
||||
e_shnum, Elf_Half);
|
||||
eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
|
||||
e_shstrndx, Elf_Half);
|
||||
|
||||
if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
|
||||
&& eor->shoff != 0)
|
||||
{
|
||||
unsigned char shdr[sizeof (Elf64_External_Shdr)];
|
||||
|
||||
/* Object file has more than 0xffff sections. */
|
||||
|
||||
if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr,
|
||||
(ei_class == ELFCLASS32
|
||||
? sizeof (Elf32_External_Shdr)
|
||||
: sizeof (Elf64_External_Shdr)),
|
||||
errmsg, err))
|
||||
{
|
||||
XDELETE (eor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (eor->shnum == 0)
|
||||
eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
|
||||
shdr, sh_size, Elf_Addr);
|
||||
|
||||
if (eor->shstrndx == SHN_XINDEX)
|
||||
{
|
||||
eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
|
||||
shdr, sh_link, Elf_Word);
|
||||
|
||||
/* Versions of the GNU binutils between 2.12 and 2.18 did
|
||||
not handle objects with more than SHN_LORESERVE sections
|
||||
correctly. All large section indexes were offset by
|
||||
0x100. There is more information at
|
||||
http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
|
||||
Fortunately these object files are easy to detect, as the
|
||||
GNU binutils always put the section header string table
|
||||
near the end of the list of sections. Thus if the
|
||||
section header string table index is larger than the
|
||||
number of sections, then we know we have to subtract
|
||||
0x100 to get the real section index. */
|
||||
if (eor->shstrndx >= eor->shnum
|
||||
&& eor->shstrndx >= SHN_LORESERVE + 0x100)
|
||||
eor->shstrndx -= 0x100;
|
||||
}
|
||||
}
|
||||
|
||||
if (eor->shstrndx >= eor->shnum)
|
||||
{
|
||||
*errmsg = "invalid ELF shstrndx >= shnum";
|
||||
*err = 0;
|
||||
XDELETE (eor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *) eor;
|
||||
}
|
||||
|
||||
/* Find all sections in an ELF file. */
|
||||
|
||||
static const char *
|
||||
simple_object_elf_find_sections (simple_object_read *sobj,
|
||||
int (*pfn) (void *, const char *,
|
||||
off_t offset, off_t length),
|
||||
void *data,
|
||||
int *err)
|
||||
{
|
||||
struct simple_object_elf_read *eor =
|
||||
(struct simple_object_elf_read *) sobj->data;
|
||||
const struct elf_type_functions *type_functions = eor->type_functions;
|
||||
unsigned char ei_class = eor->ei_class;
|
||||
size_t shdr_size;
|
||||
unsigned int shnum;
|
||||
unsigned char *shdrs;
|
||||
const char *errmsg;
|
||||
unsigned char *shstrhdr;
|
||||
size_t name_size;
|
||||
off_t shstroff;
|
||||
unsigned char *names;
|
||||
unsigned int i;
|
||||
|
||||
shdr_size = (ei_class == ELFCLASS32
|
||||
? sizeof (Elf32_External_Shdr)
|
||||
: sizeof (Elf64_External_Shdr));
|
||||
|
||||
/* Read the section headers. We skip section 0, which is not a
|
||||
useful section. */
|
||||
|
||||
shnum = eor->shnum;
|
||||
shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
|
||||
|
||||
if (!simple_object_internal_read (sobj->descriptor,
|
||||
sobj->offset + eor->shoff + shdr_size,
|
||||
shdrs,
|
||||
shdr_size * (shnum - 1),
|
||||
&errmsg, err))
|
||||
{
|
||||
XDELETEVEC (shdrs);
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
/* Read the section names. */
|
||||
|
||||
shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
|
||||
name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
|
||||
shstrhdr, sh_size, Elf_Addr);
|
||||
shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
|
||||
shstrhdr, sh_offset, Elf_Addr);
|
||||
names = XNEWVEC (unsigned char, name_size);
|
||||
if (!simple_object_internal_read (sobj->descriptor,
|
||||
sobj->offset + shstroff,
|
||||
names, name_size, &errmsg, err))
|
||||
{
|
||||
XDELETEVEC (names);
|
||||
XDELETEVEC (shdrs);
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
for (i = 1; i < shnum; ++i)
|
||||
{
|
||||
unsigned char *shdr;
|
||||
unsigned int sh_name;
|
||||
const char *name;
|
||||
off_t offset;
|
||||
off_t length;
|
||||
|
||||
shdr = shdrs + (i - 1) * shdr_size;
|
||||
sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
|
||||
shdr, sh_name, Elf_Word);
|
||||
if (sh_name >= name_size)
|
||||
{
|
||||
*err = 0;
|
||||
XDELETEVEC (names);
|
||||
XDELETEVEC (shdrs);
|
||||
return "ELF section name out of range";
|
||||
}
|
||||
|
||||
name = (const char *) names + sh_name;
|
||||
offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
|
||||
shdr, sh_offset, Elf_Addr);
|
||||
length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
|
||||
shdr, sh_size, Elf_Addr);
|
||||
|
||||
if (!(*pfn) (data, name, offset, length))
|
||||
break;
|
||||
}
|
||||
|
||||
XDELETEVEC (names);
|
||||
XDELETEVEC (shdrs);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fetch the attributes for an simple_object_read. */
|
||||
|
||||
static void *
|
||||
simple_object_elf_fetch_attributes (simple_object_read *sobj,
|
||||
const char **errmsg ATTRIBUTE_UNUSED,
|
||||
int *err ATTRIBUTE_UNUSED)
|
||||
{
|
||||
struct simple_object_elf_read *eor =
|
||||
(struct simple_object_elf_read *) sobj->data;
|
||||
struct simple_object_elf_attributes *ret;
|
||||
|
||||
ret = XNEW (struct simple_object_elf_attributes);
|
||||
ret->type_functions = eor->type_functions;
|
||||
ret->ei_data = eor->ei_data;
|
||||
ret->ei_class = eor->ei_class;
|
||||
ret->ei_osabi = eor->ei_osabi;
|
||||
ret->machine = eor->machine;
|
||||
ret->flags = eor->flags;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Release the privata data for an simple_object_read. */
|
||||
|
||||
static void
|
||||
simple_object_elf_release_read (void *data)
|
||||
{
|
||||
XDELETE (data);
|
||||
}
|
||||
|
||||
/* Compare two attributes structures. */
|
||||
|
||||
static const char *
|
||||
simple_object_elf_attributes_compare (void *data1, void *data2, int *err)
|
||||
{
|
||||
struct simple_object_elf_attributes *attrs1 =
|
||||
(struct simple_object_elf_attributes *) data1;
|
||||
struct simple_object_elf_attributes *attrs2 =
|
||||
(struct simple_object_elf_attributes *) data2;
|
||||
|
||||
if (attrs1->ei_data != attrs2->ei_data
|
||||
|| attrs1->ei_class != attrs2->ei_class
|
||||
|| attrs1->machine != attrs2->machine)
|
||||
{
|
||||
*err = 0;
|
||||
return "ELF object format mismatch";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Release the private data for an attributes structure. */
|
||||
|
||||
static void
|
||||
simple_object_elf_release_attributes (void *data)
|
||||
{
|
||||
XDELETE (data);
|
||||
}
|
||||
|
||||
/* Prepare to write out a file. */
|
||||
|
||||
static void *
|
||||
simple_object_elf_start_write (void *attributes_data,
|
||||
const char **errmsg ATTRIBUTE_UNUSED,
|
||||
int *err ATTRIBUTE_UNUSED)
|
||||
{
|
||||
struct simple_object_elf_attributes *attrs =
|
||||
(struct simple_object_elf_attributes *) attributes_data;
|
||||
struct simple_object_elf_attributes *ret;
|
||||
|
||||
/* We're just going to record the attributes, but we need to make a
|
||||
copy because the user may delete them. */
|
||||
ret = XNEW (struct simple_object_elf_attributes);
|
||||
*ret = *attrs;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write out an ELF ehdr. */
|
||||
|
||||
static int
|
||||
simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
|
||||
const char **errmsg, int *err)
|
||||
{
|
||||
struct simple_object_elf_attributes *attrs =
|
||||
(struct simple_object_elf_attributes *) sobj->data;
|
||||
const struct elf_type_functions* fns;
|
||||
unsigned char cl;
|
||||
size_t ehdr_size;
|
||||
unsigned char buf[sizeof (Elf64_External_Ehdr)];
|
||||
simple_object_write_section *section;
|
||||
unsigned int shnum;
|
||||
|
||||
fns = attrs->type_functions;
|
||||
cl = attrs->ei_class;
|
||||
|
||||
shnum = 0;
|
||||
for (section = sobj->sections; section != NULL; section = section->next)
|
||||
++shnum;
|
||||
if (shnum > 0)
|
||||
{
|
||||
/* Add a section header for the dummy section and one for
|
||||
.shstrtab. */
|
||||
shnum += 2;
|
||||
}
|
||||
|
||||
ehdr_size = (cl == ELFCLASS32
|
||||
? sizeof (Elf32_External_Ehdr)
|
||||
: sizeof (Elf64_External_Ehdr));
|
||||
memset (buf, 0, sizeof (Elf64_External_Ehdr));
|
||||
|
||||
buf[EI_MAG0] = ELFMAG0;
|
||||
buf[EI_MAG1] = ELFMAG1;
|
||||
buf[EI_MAG2] = ELFMAG2;
|
||||
buf[EI_MAG3] = ELFMAG3;
|
||||
buf[EI_CLASS] = cl;
|
||||
buf[EI_DATA] = attrs->ei_data;
|
||||
buf[EI_VERSION] = EV_CURRENT;
|
||||
buf[EI_OSABI] = attrs->ei_osabi;
|
||||
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
|
||||
/* e_entry left as zero. */
|
||||
/* e_phoff left as zero. */
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
|
||||
(cl == ELFCLASS32
|
||||
? sizeof (Elf32_External_Phdr)
|
||||
: sizeof (Elf64_External_Phdr)));
|
||||
/* e_phnum left as zero. */
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
|
||||
(cl == ELFCLASS32
|
||||
? sizeof (Elf32_External_Shdr)
|
||||
: sizeof (Elf64_External_Shdr)));
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum);
|
||||
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half,
|
||||
shnum == 0 ? 0 : shnum - 1);
|
||||
|
||||
return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
|
||||
errmsg, err);
|
||||
}
|
||||
|
||||
/* Write out an ELF shdr. */
|
||||
|
||||
static int
|
||||
simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
|
||||
off_t offset, unsigned int sh_name,
|
||||
unsigned int sh_type, unsigned int sh_flags,
|
||||
unsigned int sh_offset, unsigned int sh_size,
|
||||
unsigned int sh_addralign, const char **errmsg,
|
||||
int *err)
|
||||
{
|
||||
struct simple_object_elf_attributes *attrs =
|
||||
(struct simple_object_elf_attributes *) sobj->data;
|
||||
const struct elf_type_functions* fns;
|
||||
unsigned char cl;
|
||||
size_t shdr_size;
|
||||
unsigned char buf[sizeof (Elf64_External_Shdr)];
|
||||
|
||||
fns = attrs->type_functions;
|
||||
cl = attrs->ei_class;
|
||||
|
||||
shdr_size = (cl == ELFCLASS32
|
||||
? sizeof (Elf32_External_Shdr)
|
||||
: sizeof (Elf64_External_Shdr));
|
||||
memset (buf, 0, sizeof (Elf64_External_Shdr));
|
||||
|
||||
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
|
||||
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
|
||||
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
|
||||
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
|
||||
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
|
||||
/* sh_link left as zero. */
|
||||
/* sh_info left as zero. */
|
||||
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
|
||||
/* sh_entsize left as zero. */
|
||||
|
||||
return simple_object_internal_write (descriptor, offset, buf, shdr_size,
|
||||
errmsg, err);
|
||||
}
|
||||
|
||||
/* Write out a complete ELF file.
|
||||
Ehdr
|
||||
initial dummy Shdr
|
||||
user-created Shdrs
|
||||
.shstrtab Shdr
|
||||
user-created section data
|
||||
.shstrtab data */
|
||||
|
||||
static const char *
|
||||
simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
|
||||
int *err)
|
||||
{
|
||||
struct simple_object_elf_attributes *attrs =
|
||||
(struct simple_object_elf_attributes *) sobj->data;
|
||||
unsigned char cl;
|
||||
size_t ehdr_size;
|
||||
size_t shdr_size;
|
||||
const char *errmsg;
|
||||
simple_object_write_section *section;
|
||||
unsigned int shnum;
|
||||
size_t shdr_offset;
|
||||
size_t sh_offset;
|
||||
size_t sh_name;
|
||||
unsigned char zero;
|
||||
|
||||
if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
cl = attrs->ei_class;
|
||||
if (cl == ELFCLASS32)
|
||||
{
|
||||
ehdr_size = sizeof (Elf32_External_Ehdr);
|
||||
shdr_size = sizeof (Elf32_External_Shdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ehdr_size = sizeof (Elf64_External_Ehdr);
|
||||
shdr_size = sizeof (Elf64_External_Shdr);
|
||||
}
|
||||
|
||||
shnum = 0;
|
||||
for (section = sobj->sections; section != NULL; section = section->next)
|
||||
++shnum;
|
||||
if (shnum == 0)
|
||||
return NULL;
|
||||
|
||||
/* Add initial dummy Shdr and .shstrtab. */
|
||||
shnum += 2;
|
||||
|
||||
shdr_offset = ehdr_size;
|
||||
sh_offset = shdr_offset + shnum * shdr_size;
|
||||
|
||||
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
|
||||
0, 0, 0, 0, 0, 0, &errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
shdr_offset += shdr_size;
|
||||
|
||||
sh_name = 1;
|
||||
for (section = sobj->sections; section != NULL; section = section->next)
|
||||
{
|
||||
size_t mask;
|
||||
size_t new_sh_offset;
|
||||
size_t sh_size;
|
||||
struct simple_object_write_section_buffer *buffer;
|
||||
|
||||
mask = (1U << section->align) - 1;
|
||||
new_sh_offset = sh_offset + mask;
|
||||
new_sh_offset &= ~ mask;
|
||||
while (new_sh_offset > sh_offset)
|
||||
{
|
||||
unsigned char zeroes[16];
|
||||
size_t write;
|
||||
|
||||
memset (zeroes, 0, sizeof zeroes);
|
||||
write = new_sh_offset - sh_offset;
|
||||
if (write > sizeof zeroes)
|
||||
write = sizeof zeroes;
|
||||
if (!simple_object_internal_write (descriptor, sh_offset, zeroes,
|
||||
write, &errmsg, err))
|
||||
return errmsg;
|
||||
sh_offset += write;
|
||||
}
|
||||
|
||||
sh_size = 0;
|
||||
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
|
||||
{
|
||||
if (!simple_object_internal_write (descriptor, sh_offset + sh_size,
|
||||
((const unsigned char *)
|
||||
buffer->buffer),
|
||||
buffer->size, &errmsg, err))
|
||||
return errmsg;
|
||||
sh_size += buffer->size;
|
||||
}
|
||||
|
||||
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
|
||||
sh_name, SHT_PROGBITS, 0, sh_offset,
|
||||
sh_size, 1U << section->align,
|
||||
&errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
shdr_offset += shdr_size;
|
||||
sh_name += strlen (section->name) + 1;
|
||||
sh_offset += sh_size;
|
||||
}
|
||||
|
||||
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
|
||||
sh_name, SHT_STRTAB, 0, sh_offset,
|
||||
sh_name + strlen (".shstrtab") + 1,
|
||||
1, &errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
/* .shstrtab has a leading zero byte. */
|
||||
zero = 0;
|
||||
if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1,
|
||||
&errmsg, err))
|
||||
return errmsg;
|
||||
++sh_offset;
|
||||
|
||||
for (section = sobj->sections; section != NULL; section = section->next)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen (section->name) + 1;
|
||||
if (!simple_object_internal_write (descriptor, sh_offset,
|
||||
(const unsigned char *) section->name,
|
||||
len, &errmsg, err))
|
||||
return errmsg;
|
||||
sh_offset += len;
|
||||
}
|
||||
|
||||
if (!simple_object_internal_write (descriptor, sh_offset,
|
||||
(const unsigned char *) ".shstrtab",
|
||||
strlen (".shstrtab") + 1, &errmsg, err))
|
||||
return errmsg;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Release the private data for an simple_object_write structure. */
|
||||
|
||||
static void
|
||||
simple_object_elf_release_write (void *data)
|
||||
{
|
||||
XDELETE (data);
|
||||
}
|
||||
|
||||
/* The ELF functions. */
|
||||
|
||||
const struct simple_object_functions simple_object_elf_functions =
|
||||
{
|
||||
simple_object_elf_match,
|
||||
simple_object_elf_find_sections,
|
||||
simple_object_elf_fetch_attributes,
|
||||
simple_object_elf_release_read,
|
||||
simple_object_elf_attributes_compare,
|
||||
simple_object_elf_release_attributes,
|
||||
simple_object_elf_start_write,
|
||||
simple_object_elf_write_to_file,
|
||||
simple_object_elf_release_write
|
||||
};
|
1022
libiberty/simple-object-mach-o.c
Normal file
1022
libiberty/simple-object-mach-o.c
Normal file
File diff suppressed because it is too large
Load Diff
423
libiberty/simple-object.c
Normal file
423
libiberty/simple-object.c
Normal file
@ -0,0 +1,423 @@
|
||||
/* simple-object.c -- simple routines to read and write object files.
|
||||
Copyright 2010 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 51 Franklin Street - Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "libiberty.h"
|
||||
#include "simple-object.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
|
||||
#include "simple-object-common.h"
|
||||
|
||||
/* The known object file formats. */
|
||||
|
||||
static const struct simple_object_functions * const format_functions[] =
|
||||
{
|
||||
&simple_object_elf_functions,
|
||||
&simple_object_mach_o_functions,
|
||||
&simple_object_coff_functions
|
||||
};
|
||||
|
||||
/* Read data from a file using the simple_object error reporting
|
||||
conventions. */
|
||||
|
||||
int
|
||||
simple_object_internal_read (int descriptor, off_t offset,
|
||||
unsigned char *buffer, size_t size,
|
||||
const char **errmsg, int *err)
|
||||
{
|
||||
ssize_t got;
|
||||
|
||||
if (lseek (descriptor, offset, SEEK_SET) < 0)
|
||||
{
|
||||
*errmsg = "lseek";
|
||||
*err = errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
got = read (descriptor, buffer, size);
|
||||
if (got < 0)
|
||||
{
|
||||
*errmsg = "read";
|
||||
*err = errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((size_t) got < size)
|
||||
{
|
||||
*errmsg = "file too short";
|
||||
*err = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write data to a file using the simple_object error reporting
|
||||
conventions. */
|
||||
|
||||
int
|
||||
simple_object_internal_write (int descriptor, off_t offset,
|
||||
const unsigned char *buffer, size_t size,
|
||||
const char **errmsg, int *err)
|
||||
{
|
||||
ssize_t wrote;
|
||||
|
||||
if (lseek (descriptor, offset, SEEK_SET) < 0)
|
||||
{
|
||||
*errmsg = "lseek";
|
||||
*err = errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
wrote = write (descriptor, buffer, size);
|
||||
if (wrote < 0)
|
||||
{
|
||||
*errmsg = "write";
|
||||
*err = errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((size_t) wrote < size)
|
||||
{
|
||||
*errmsg = "short write";
|
||||
*err = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open for read. */
|
||||
|
||||
simple_object_read *
|
||||
simple_object_start_read (int descriptor, off_t offset,
|
||||
const char *segment_name, const char **errmsg,
|
||||
int *err)
|
||||
{
|
||||
unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
|
||||
size_t len, i;
|
||||
|
||||
if (!simple_object_internal_read (descriptor, offset, header,
|
||||
SIMPLE_OBJECT_MATCH_HEADER_LEN,
|
||||
errmsg, err))
|
||||
return NULL;
|
||||
|
||||
len = sizeof (format_functions) / sizeof (format_functions[0]);
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
void *data;
|
||||
|
||||
data = format_functions[i]->match (header, descriptor, offset,
|
||||
segment_name, errmsg, err);
|
||||
if (data != NULL)
|
||||
{
|
||||
simple_object_read *ret;
|
||||
|
||||
ret = XNEW (simple_object_read);
|
||||
ret->descriptor = descriptor;
|
||||
ret->offset = offset;
|
||||
ret->functions = format_functions[i];
|
||||
ret->data = data;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*errmsg = "file not recognized";
|
||||
*err = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find all sections. */
|
||||
|
||||
const char *
|
||||
simple_object_find_sections (simple_object_read *sobj,
|
||||
int (*pfn) (void *, const char *, off_t, off_t),
|
||||
void *data,
|
||||
int *err)
|
||||
{
|
||||
return sobj->functions->find_sections (sobj, pfn, data, err);
|
||||
}
|
||||
|
||||
/* Internal data passed to find_one_section. */
|
||||
|
||||
struct find_one_section_data
|
||||
{
|
||||
/* The section we are looking for. */
|
||||
const char *name;
|
||||
/* Where to store the section offset. */
|
||||
off_t *offset;
|
||||
/* Where to store the section length. */
|
||||
off_t *length;
|
||||
/* Set if the name is found. */
|
||||
int found;
|
||||
};
|
||||
|
||||
/* Internal function passed to find_sections. */
|
||||
|
||||
static int
|
||||
find_one_section (void *data, const char *name, off_t offset, off_t length)
|
||||
{
|
||||
struct find_one_section_data *fosd = (struct find_one_section_data *) data;
|
||||
|
||||
if (strcmp (name, fosd->name) != 0)
|
||||
return 1;
|
||||
|
||||
*fosd->offset = offset;
|
||||
*fosd->length = length;
|
||||
fosd->found = 1;
|
||||
|
||||
/* Stop iteration. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find a section. */
|
||||
|
||||
int
|
||||
simple_object_find_section (simple_object_read *sobj, const char *name,
|
||||
off_t *offset, off_t *length,
|
||||
const char **errmsg, int *err)
|
||||
{
|
||||
struct find_one_section_data fosd;
|
||||
|
||||
fosd.name = name;
|
||||
fosd.offset = offset;
|
||||
fosd.length = length;
|
||||
fosd.found = 0;
|
||||
|
||||
*errmsg = simple_object_find_sections (sobj, find_one_section,
|
||||
(void *) &fosd, err);
|
||||
if (*errmsg != NULL)
|
||||
return 0;
|
||||
if (!fosd.found)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Fetch attributes. */
|
||||
|
||||
simple_object_attributes *
|
||||
simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
|
||||
int *err)
|
||||
{
|
||||
void *data;
|
||||
simple_object_attributes *ret;
|
||||
|
||||
data = sobj->functions->fetch_attributes (sobj, errmsg, err);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
ret = XNEW (simple_object_attributes);
|
||||
ret->functions = sobj->functions;
|
||||
ret->data = data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Release an simple_object_read. */
|
||||
|
||||
void
|
||||
simple_object_release_read (simple_object_read *sobj)
|
||||
{
|
||||
sobj->functions->release_read (sobj->data);
|
||||
XDELETE (sobj);
|
||||
}
|
||||
|
||||
/* Compare attributes. */
|
||||
|
||||
const char *
|
||||
simple_object_attributes_compare (simple_object_attributes *attrs1,
|
||||
simple_object_attributes *attrs2,
|
||||
int *err)
|
||||
{
|
||||
if (attrs1->functions != attrs2->functions)
|
||||
{
|
||||
*err = 0;
|
||||
return "different object file format";
|
||||
}
|
||||
return attrs1->functions->attributes_compare (attrs1->data, attrs2->data,
|
||||
err);
|
||||
}
|
||||
|
||||
/* Release an attributes structure. */
|
||||
|
||||
void
|
||||
simple_object_release_attributes (simple_object_attributes *attrs)
|
||||
{
|
||||
attrs->functions->release_attributes (attrs->data);
|
||||
XDELETE (attrs);
|
||||
}
|
||||
|
||||
/* Start creating an object file. */
|
||||
|
||||
simple_object_write *
|
||||
simple_object_start_write (simple_object_attributes *attrs,
|
||||
const char *segment_name, const char **errmsg,
|
||||
int *err)
|
||||
{
|
||||
void *data;
|
||||
simple_object_write *ret;
|
||||
|
||||
data = attrs->functions->start_write (attrs->data, errmsg, err);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
ret = XNEW (simple_object_write);
|
||||
ret->functions = attrs->functions;
|
||||
ret->segment_name = xstrdup (segment_name);
|
||||
ret->sections = NULL;
|
||||
ret->last_section = NULL;
|
||||
ret->data = data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Start creating a section. */
|
||||
|
||||
simple_object_write_section *
|
||||
simple_object_write_create_section (simple_object_write *sobj, const char *name,
|
||||
unsigned int align,
|
||||
const char **errmsg ATTRIBUTE_UNUSED,
|
||||
int *err ATTRIBUTE_UNUSED)
|
||||
{
|
||||
simple_object_write_section *ret;
|
||||
|
||||
ret = XNEW (simple_object_write_section);
|
||||
ret->next = NULL;
|
||||
ret->name = xstrdup (name);
|
||||
ret->align = align;
|
||||
ret->buffers = NULL;
|
||||
ret->last_buffer = NULL;
|
||||
|
||||
if (sobj->last_section == NULL)
|
||||
{
|
||||
sobj->sections = ret;
|
||||
sobj->last_section = ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
sobj->last_section->next = ret;
|
||||
sobj->last_section = ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Add data to a section. */
|
||||
|
||||
const char *
|
||||
simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
|
||||
simple_object_write_section *section,
|
||||
const void *buffer,
|
||||
size_t size, int copy,
|
||||
int *err ATTRIBUTE_UNUSED)
|
||||
{
|
||||
struct simple_object_write_section_buffer *wsb;
|
||||
|
||||
wsb = XNEW (struct simple_object_write_section_buffer);
|
||||
wsb->next = NULL;
|
||||
wsb->size = size;
|
||||
|
||||
if (!copy)
|
||||
{
|
||||
wsb->buffer = buffer;
|
||||
wsb->free_buffer = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
wsb->free_buffer = (void *) XNEWVEC (char, size);
|
||||
memcpy (wsb->free_buffer, buffer, size);
|
||||
wsb->buffer = wsb->free_buffer;
|
||||
}
|
||||
|
||||
if (section->last_buffer == NULL)
|
||||
{
|
||||
section->buffers = wsb;
|
||||
section->last_buffer = wsb;
|
||||
}
|
||||
else
|
||||
{
|
||||
section->last_buffer->next = wsb;
|
||||
section->last_buffer = wsb;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Write the complete object file. */
|
||||
|
||||
const char *
|
||||
simple_object_write_to_file (simple_object_write *sobj, int descriptor,
|
||||
int *err)
|
||||
{
|
||||
return sobj->functions->write_to_file (sobj, descriptor, err);
|
||||
}
|
||||
|
||||
/* Release an simple_object_write. */
|
||||
|
||||
void
|
||||
simple_object_release_write (simple_object_write *sobj)
|
||||
{
|
||||
simple_object_write_section *section;
|
||||
|
||||
free (sobj->segment_name);
|
||||
|
||||
section = sobj->sections;
|
||||
while (section != NULL)
|
||||
{
|
||||
struct simple_object_write_section_buffer *buffer;
|
||||
simple_object_write_section *next_section;
|
||||
|
||||
buffer = section->buffers;
|
||||
while (buffer != NULL)
|
||||
{
|
||||
struct simple_object_write_section_buffer *next_buffer;
|
||||
|
||||
if (buffer->free_buffer != NULL)
|
||||
XDELETEVEC (buffer->free_buffer);
|
||||
next_buffer = buffer->next;
|
||||
XDELETE (buffer);
|
||||
buffer = next_buffer;
|
||||
}
|
||||
|
||||
next_section = section->next;
|
||||
free (section->name);
|
||||
XDELETE (section);
|
||||
section = next_section;
|
||||
}
|
||||
|
||||
sobj->functions->release_write (sobj->data);
|
||||
XDELETE (sobj);
|
||||
}
|
168
libiberty/simple-object.txh
Normal file
168
libiberty/simple-object.txh
Normal file
@ -0,0 +1,168 @@
|
||||
@c -*- mode: texinfo -*-
|
||||
@deftypefn Extension {simple_object_read *} simple_object_open_read (int @var{descriptor}, off_t @var{offset}, const char *{segment_name}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Opens an object file for reading. Creates and returns an
|
||||
@code{simple_object_read} pointer which may be passed to other
|
||||
functions to extract data from the object file.
|
||||
|
||||
@var{descriptor} holds a file descriptor which permits reading.
|
||||
|
||||
@var{offset} is the offset into the file; this will be @code{0} in the
|
||||
normal case, but may be a different value when reading an object file
|
||||
in an archive file.
|
||||
|
||||
@var{segment_name} is only used with the Mach-O file format used on
|
||||
Darwin aka Mac OS X. It is required on that platform, and means to
|
||||
only look at sections within the segment with that name. The
|
||||
parameter is ignored on other systems.
|
||||
|
||||
If an error occurs, this functions returns @code{NULL} and sets
|
||||
@code{*@var{errmsg}} to an error string and sets @code{*@var{err}} to
|
||||
an errno value or @code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {const char *} simple_object_find_sections (simple_object_read *@var{simple_object}, int (*@var{pfn}) (void *@var{data}, const char *@var{name}, off_t @var{offset}, off_t @var{length}), void *@var{data}, int *@var{err})
|
||||
|
||||
This function calls @var{pfn} for each section in @var{simple_object}.
|
||||
It calls @var{pfn} with the section name, the offset within the file
|
||||
of the section contents, and the length of the section contents. The
|
||||
offset within the file is relative to the offset passed to
|
||||
@code{simple_object_open_read}. The @var{data} argument to this
|
||||
function is passed along to @var{pfn}.
|
||||
|
||||
If @var{pfn} returns @code{0}, the loop over the sections stops and
|
||||
@code{simple_object_find_sections} returns. If @var{pfn} returns some
|
||||
other value, the loop continues.
|
||||
|
||||
On success @code{simple_object_find_sections} returns. On error it
|
||||
returns an error string, and sets @code{*@var{err}} to an errno value
|
||||
or @code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {int} simple_object_find_section (simple_object_read *@var{simple_object} off_t *@var{offset}, off_t *@var{length}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Look for the section @var{name} in @var{simple_object}. This returns
|
||||
information for the first section with that name.
|
||||
|
||||
If found, return 1 and set @code{*@var{offset}} to the offset in the
|
||||
file of the section contents and set @code{*@var{length}} to the
|
||||
length of the section contents. The value in @code{*@var{offset}}
|
||||
will be relative to the offset passed to
|
||||
@code{simple_object_open_read}.
|
||||
|
||||
If the section is not found, and no error occurs,
|
||||
@code{simple_object_find_section} returns @code{0} and set
|
||||
@code{*@var{errmsg}} to @code{NULL}.
|
||||
|
||||
If an error occurs, @code{simple_object_find_section} returns
|
||||
@code{0}, sets @code{*@var{errmsg}} to an error message, and sets
|
||||
@code{*@var{err}} to an errno value or @code{0} if there is no
|
||||
relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {void} simple_object_release_read (simple_object_read *@var{simple_object})
|
||||
|
||||
Release all resources associated with @var{simple_object}. This does
|
||||
not close the file descriptor.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {simple_object_attributes *} simple_object_fetch_attributes (simple_object_read *@var{simple_object}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Fetch the attributes of @var{simple_object}. The attributes are
|
||||
internal information such as the format of the object file, or the
|
||||
architecture it was compiled for. This information will persist until
|
||||
@code{simple_object_attributes_release} is called, even if
|
||||
@var{simple_object} itself is released.
|
||||
|
||||
On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an
|
||||
error message, and sets @code{*@var{err}} to an errno value or
|
||||
@code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {const char *} simple_object_attributes_compare (simple_object_attributes *@var{attrs1}, simple_object_attributes *@var{attrs2}, int *@var{err})
|
||||
|
||||
Compare @var{attrs1} and @var{attrs2}. If they could be linked
|
||||
together without error, return @code{NULL}. Otherwise, return an
|
||||
error message and set @code{*@var{err}} to an errno value or @code{0}
|
||||
if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {void} simple_object_release_attributes (simple_object_attributes *@var{attrs})
|
||||
|
||||
Release all resources associated with @var{attrs}.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {simple_object_write *} simple_object_start_write (simple_object_attributes @var{attrs}, const char *@var{segment_name}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Start creating a new object file using the object file format
|
||||
described in @var{attrs}. You must fetch attribute information from
|
||||
an existing object file before you can create a new one. There is
|
||||
currently no support for creating an object file de novo.
|
||||
|
||||
@var{segment_name} is only used with Mach-O as found on Darwin aka Mac
|
||||
OS X. The parameter is required on that target. It means that all
|
||||
sections are created within the named segment. It is ignored for
|
||||
other object file formats.
|
||||
|
||||
On error @code{simple_object_start_write} returns @code{NULL}, sets
|
||||
@code{*@var{ERRMSG}} to an error message, and sets @code{*@var{err}}
|
||||
to an errno value or @code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {simple_object_write_section *} simple_object_write_create_section (simple_object_write *@var{simple_object}, const char *@var{name}, unsigned int @var{align}, const char **@var{errmsg}, int *@var{err})
|
||||
|
||||
Add a section to @var{simple_object}. @var{name} is the name of the
|
||||
new section. @var{align} is the required alignment expressed as the
|
||||
number of required low-order 0 bits (e.g., 2 for alignment to a 32-bit
|
||||
boundary).
|
||||
|
||||
The section is created as containing data, readable, not writable, not
|
||||
executable, not loaded at runtime. The section is not written to the
|
||||
file until @code{simple_object_write_to_file} is called.
|
||||
|
||||
On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an
|
||||
error message, and sets @code{*@var{err}} to an errno value or
|
||||
@code{0} if there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {const char *} simple_object_write_add_data (simple_object_write *@var{simple_object}, simple_object_write_section *@var{section}, const void *@var{buffer}, size_t @var{size}, int @var{copy}, int *@var{err})
|
||||
|
||||
Add data @var{buffer}/@var{size} to @var{section} in
|
||||
@var{simple_object}. If @var{copy} is non-zero, the data will be
|
||||
copied into memory if necessary. If @var{copy} is zero, @var{buffer}
|
||||
must persist until @code{simple_object_write_to_file} is called. is
|
||||
released.
|
||||
|
||||
On success this returns @code{NULL}. On error this returns an error
|
||||
message, and sets @code{*@var{err}} to an errno value or 0 if there is
|
||||
no relevant erro.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {const char *} simple_object_write_to_file (simple_object_write *@var{simple_object}, int @var{descriptor}, int *@var{err})
|
||||
|
||||
Write the complete object file to @var{descriptor}, an open file
|
||||
descriptor. This writes out all the data accumulated by calls to
|
||||
@code{simple_object_write_create_section} and
|
||||
@var{simple_object_write_add_data}.
|
||||
|
||||
This returns @code{NULL} on success. On error this returns an error
|
||||
message and sets @code{*@var{err}} to an errno value or @code{0} if
|
||||
there is no relevant errno.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {void} simple_object_release_write (simple_object_write *@var{simple_object})
|
||||
|
||||
Release all resources associated with @var{simple_object}.
|
||||
|
||||
@end deftypefn
|
Loading…
Reference in New Issue
Block a user