Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Oct 2006 00:43:42 GMT
From:      John Birrell <jb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 107386 for review
Message-ID:  <200610070043.k970hgEB092061@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=107386

Change 107386 by jb@jb_freebsd7 on 2006/10/07 00:43:31

	IFlibbsdelf

Affected files ...

.. //depot/projects/dtrace/src/lib/libelf/elf_strptr.c#2 integrate
.. //depot/projects/dtrace/src/lib/libelf/elf_update.c#2 integrate
.. //depot/projects/dtrace/src/lib/libelf/gelf_getshdr.c#3 integrate
.. //depot/projects/dtrace/src/lib/libelf/gelf_rel.c#2 integrate
.. //depot/projects/dtrace/src/lib/libelf/gelf_rela.c#2 integrate

Differences ...

==== //depot/projects/dtrace/src/lib/libelf/elf_strptr.c#2 (text+ko) ====


==== //depot/projects/dtrace/src/lib/libelf/elf_update.c#2 (text+ko) ====

@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2006 John Birrell jb@freebsd.org
+ * Copyright (c) 2006 Joseph Koshy
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,14 +27,797 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/mman.h>
+#include <sys/param.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <gelf.h>
 #include <libelf.h>
-#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 #include "_libelf.h"
 
+/*
+ * Update the internal data structures associated with an ELF object.
+ * Returns the size in bytes the ELF object would occupy in its file
+ * representation.
+ *
+ * After a successful call to this function, the following structures
+ * are updated:
+ *
+ * - The ELF header is updated.
+ * - All sections are sorted in order of ascending addresses and their
+ *   section header table entries updated.   An error is signalled
+ *   if an overlap was detected among sections.
+ * - All data descriptors associated with a section are sorted in order
+ *   of ascending addresses.  Overlaps, if detected, are signalled as
+ *   errors.  Other sanity checks for alignments, section types etc. are
+ *   made.
+ *
+ * After a resync_elf() successfully returns, the ELF descriptor is
+ * ready for being handed over to _libelf_write_elf().
+ *
+ * File alignments:
+ * PHDR - Addr
+ * SHDR - Addr
+ *
+ * XXX: how do we handle 'flags'.
+ */
+
+/*
+ * Compute the extents of a section, by looking at the.
+ */
+static int
+_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc)
+{
+	int ec;
+	Elf_Data *d, *td;
+	unsigned int elftype;
+	uint64_t sh_align, sh_offset, sh_size;
+	uint64_t scn_size, scn_alignment;
+
+	/*
+	 * We need to recompute library private data structures if one
+	 * or more of the following is true:
+	 * - The underlying Shdr structure has been marked `dirty'.  Significant
+	 *   fields include: `sh_offset', `sh_type', `sh_size', `sh_addralign'.
+	 * - The Elf_Data structures part of this section have been marked
+	 *   `dirty'.  Affected members include `d_align', `d_offset', `d_type',
+	 *   and `d_size'.
+	 * - The section as a whole is `dirty', e.g., it has been allocated
+	 *   using elf_newscn().
+	 *
+	 * Each of these conditions would result in the ELF_F_DIRTY bit being
+	 * set on the section descriptor's `s_flags' field.
+	 */
+
+	if ((s->s_flags & ELF_F_DIRTY) == 0)
+		return (1);
+
+	ec = e->e_class;
+
+	if (ec == ELFCLASS32) {
+		elftype   = _libelf_xlate_shtype(s->s_shdr.s_shdr32.sh_type);
+		sh_align  = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
+		sh_size   = (uint64_t) s->s_shdr.s_shdr32.sh_size;
+		sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
+	} else {
+		elftype   = _libelf_xlate_shtype(s->s_shdr.s_shdr64.sh_type);
+		sh_align  = s->s_shdr.s_shdr64.sh_addralign;
+		sh_size   = s->s_shdr.s_shdr64.sh_size;
+		sh_offset = s->s_shdr.s_shdr64.sh_offset;
+	}
+
+	if (elftype > ELF_T_LAST) {
+		LIBELF_SET_ERROR(SECTION, 0);
+		return (0);
+	}
+
+	/*
+	 * Compute the extent of the data descriptors associated with
+	 * this section.
+	 */
+	scn_size = 0L;
+	scn_alignment = 0;
+
+	if (sh_align == 0)
+		sh_align = _libelf_malign(elftype, ec);
+
+	STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) {
+		if (d->d_type != elftype) {
+			LIBELF_SET_ERROR(DATA, 0);
+			return (0);
+		}
+		if (d->d_version != e->e_version) {
+			LIBELF_SET_ERROR(VERSION, 0);
+			return (0);
+		}
+		if (d->d_align % sh_align) {
+			LIBELF_SET_ERROR(DATA, 0);
+			return (0);
+		}
+
+		if ((uint64_t) d->d_off + d->d_size > scn_size)
+			scn_size = d->d_off + d->d_size;
+		if (d->d_align > scn_alignment)
+			scn_alignment = d->d_align;
+	}
+
+	/*
+	 * If the application is requesting full control over the layout
+	 * of the section, check its values for sanity.
+	 */
+	if (e->e_flags & ELF_F_LAYOUT) {
+		if (scn_alignment > sh_align || sh_offset % sh_align ||
+		    sh_size < scn_size) {
+			LIBELF_SET_ERROR(LAYOUT, 0);
+			return (0);
+		}
+	} else {
+		/*
+		 * Otherwise compute the values in the section header.
+		 */
+
+		if (scn_alignment > sh_align)
+			sh_align = scn_alignment;
+
+		sh_size = scn_size;
+		sh_offset = roundup(*rc, sh_align);
+
+		if (ec == ELFCLASS32) {
+			s->s_shdr.s_shdr32.sh_offset    = (uint32_t) sh_offset;
+			s->s_shdr.s_shdr32.sh_size      = (uint32_t) sh_size;
+			s->s_shdr.s_shdr32.sh_addralign = (uint32_t) sh_align;
+		} else {
+			s->s_shdr.s_shdr64.sh_offset    = sh_offset;
+			s->s_shdr.s_shdr64.sh_size      = sh_size;
+			s->s_shdr.s_shdr64.sh_addralign = sh_align;
+		}
+	}
+
+	*rc = sh_offset + sh_size;
+
+	s->s_size = sh_size;
+	s->s_offset = sh_offset;
+	return (1);
+}
+
+
+/*
+ * Insert a section in ascending order in the list
+ */
+
+static int
+_libelf_insert_section(Elf *e, Elf_Scn *s)
+{
+	Elf_Scn *t, *prevt;
+	uint64_t smax, smin, tmax, tmin;
+
+	smin = s->s_offset;
+	smax = smin + s->s_size;
+
+	prevt = NULL;
+	STAILQ_FOREACH(t, &e->e_u.e_elf.e_scn, s_next) {
+		tmin = t->s_offset;
+		tmax = tmin + t->s_size;
+
+		/* check if there is an overlap */
+		if (tmax < smin) {
+			prevt = t;
+			continue;
+		} else if (smax < tmin)
+			break;
+		else {
+			LIBELF_SET_ERROR(LAYOUT, 0);
+			return (0);
+		}
+	}
+
+	if (prevt)
+		STAILQ_INSERT_AFTER(&e->e_u.e_elf.e_scn, prevt, s, s_next);
+	else
+		STAILQ_INSERT_HEAD(&e->e_u.e_elf.e_scn, s, s_next);
+	return (1);
+}
+
+static off_t
+_libelf_resync_sections(Elf *e, off_t rc)
+{
+	int ec;
+	off_t nrc;
+	size_t sh_type;
+	Elf_Scn *s, *ts;
+
+	ec = e->e_class;
+
+	/*
+	 * Make a pass through sections, computing the extent of each
+	 * section. Order in increasing order of addresses.
+	 */
+
+	nrc = rc;
+	STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next)
+		if (_libelf_compute_section_extents(e, s, &nrc) == 0)
+			return ((off_t) -1);
+
+	STAILQ_FOREACH_SAFE(s, &e->e_u.e_elf.e_scn, s_next, ts) {
+		if (ec == ELFCLASS32)
+			sh_type = s->s_shdr.s_shdr32.sh_type;
+		else
+			sh_type = s->s_shdr.s_shdr64.sh_type;
+
+		/* XXX Do we need the 'size' field of an SHT_NOBITS section */
+		if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
+			continue;
+
+		if (s->s_offset < (uint64_t) rc) {
+			if (s->s_offset + s->s_size < (uint64_t) rc) {
+				/*
+				 * Try insert this section in the
+				 * correct place in the list,
+				 * detecting overlaps if any.
+				 */
+				STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn,
+				    s_next);
+				if (_libelf_insert_section(e, s) == 0)
+					return ((off_t) -1);
+			} else {
+				LIBELF_SET_ERROR(LAYOUT, 0);
+				return ((off_t) -1);
+			}
+		} else
+			rc = s->s_offset + s->s_size;
+	}
+
+	assert(nrc == rc);
+
+	return (rc);
+}
+
+static off_t
+_libelf_resync_elf(Elf *e)
+{
+	int ec, eh_class, eh_type;
+	unsigned int eh_byteorder, eh_version;
+	size_t align, fsz;
+	uint16_t phnum, shnum;
+	off_t rc, phoff, shoff;
+	void *ehdr;
+	Elf32_Ehdr *eh32;
+	Elf64_Ehdr *eh64;
+
+	rc = 0;
+
+	ec = e->e_class;
+
+	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+	/*
+	 * Prepare the EHDR.
+	 */
+	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
+		return ((off_t) -1);
+
+	eh32 = ehdr;
+	eh64 = ehdr;
+
+	if (ec == ELFCLASS32) {
+		eh_byteorder = eh32->e_ident[EI_DATA];
+		eh_class     = eh32->e_ident[EI_CLASS];
+		phnum        = eh32->e_phnum;
+		phoff        = (uint64_t) eh32->e_phoff;
+		shnum        = eh32->e_shnum;
+		shoff        = (uint64_t) eh32->e_shoff;
+		eh_type      = eh32->e_type;
+		eh_version   = eh32->e_version;
+	} else {
+		eh_byteorder = eh64->e_ident[EI_DATA];
+		eh_class     = eh64->e_ident[EI_CLASS];
+		phnum        = eh64->e_phnum;
+		phoff        = eh64->e_phoff;
+		shnum        = eh64->e_shnum;
+		shoff        = eh64->e_shoff;
+		eh_type      = eh64->e_type;
+		eh_version   = eh64->e_version;
+	}
+
+	if (eh_version == EV_NONE)
+		eh_version = EV_CURRENT;
+
+	if (eh_version != e->e_version) {	/* always EV_CURRENT */
+		LIBELF_SET_ERROR(VERSION, 0);
+		return ((off_t) -1);
+	}
+
+	if (eh_class != e->e_class) {
+		LIBELF_SET_ERROR(CLASS, 0);
+		return ((off_t) -1);
+	}
+
+	if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) {
+		LIBELF_SET_ERROR(HEADER, 0);
+		return ((off_t) -1);
+	}
+
+#define	INITIALIZE_EHDR(E,EC,V)	do {					\
+		(E)->e_ident[EI_MAG0] = ELFMAG0;			\
+		(E)->e_ident[EI_MAG1] = ELFMAG1;			\
+		(E)->e_ident[EI_MAG2] = ELFMAG2;			\
+		(E)->e_ident[EI_MAG3] = ELFMAG3;			\
+		(E)->e_ident[EI_CLASS] = (EC);				\
+		(E)->e_ident[EI_VERSION] = (V);				\
+		(E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V), 1);\
+		(E)->e_phentsize = _libelf_fsize(ELF_T_PHDR, (EC), (V),	\
+		    1);							\
+		(E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V),	\
+		    1);							\
+	} while (0)
+
+	if (ec == ELFCLASS32)
+		INITIALIZE_EHDR(eh32, ec, eh_version);
+	else
+		INITIALIZE_EHDR(eh64, ec, eh_version);
+
+	(void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
+
+	rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, 1);
+
+	/*
+	 * Compute the layout the program header table, if one is
+	 * present.  The program header table needs to be aligned to a
+	 * `natural' boundary.
+	 */
+	if (phnum) {
+		fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum);
+		align = _libelf_malign(ELF_T_PHDR, ec);
+
+		if (e->e_flags & ELF_F_LAYOUT) {
+			/*
+			 * Check offsets for sanity.
+			 */
+			if (rc > phoff) {
+				LIBELF_SET_ERROR(HEADER, 0);
+				return ((off_t) -1);
+			}
+
+			if (phoff % align) {
+				LIBELF_SET_ERROR(LAYOUT, 0);
+				return ((off_t) -1);
+			}
+
+		} else
+			phoff = roundup(rc, align);
+
+		rc = phoff + fsz * phnum;
+	}
+
+	/*
+	 * Compute the layout of the sections associated with the
+	 * file.
+	 */
+
+	if ((rc = _libelf_resync_sections(e, rc)) < 0)
+		return ((off_t) -1);
+
+	/*
+	 * Compute the space taken up by the section header table, if
+	 * one is needed.
+	 */
+	if (shnum) {
+		fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, 1);
+		align = _libelf_malign(ELF_T_SHDR, ec);
+
+		if (e->e_flags & ELF_F_LAYOUT) {
+			if (rc < shoff) {
+				LIBELF_SET_ERROR(HEADER, 0);
+				return ((off_t) -1);
+			}
+
+			if (shoff % align) {
+				LIBELF_SET_ERROR(LAYOUT, 0);
+				return ((off_t) -1);
+			}
+		} else
+			shoff = roundup(rc, align);
+
+		rc = shoff + fsz * shnum;
+	}
+
+	/*
+	 * Update the `e_phoff' and `e_shoff' fields if the library is
+	 * doing the layout.
+	 */
+	if ((e->e_flags & ELF_F_LAYOUT) == 0) {
+		if (ec == ELFCLASS32) {
+			eh32->e_phoff = phoff;
+			eh32->e_shoff = shoff;
+		} else {
+			eh64->e_phoff = phoff;
+			eh64->e_shoff = shoff;
+		}
+	}
+
+	return (rc);
+}
+
+/*
+ * Write out the contents of a section.
+ */
+
+static off_t
+_libelf_write_scn(Elf *e, char *nf, Elf_Scn *s, off_t rc)
+{
+	int ec;
+	size_t fsz, msz, nobjects, sh_type;
+	uint64_t sh_off;
+	int elftype;
+	Elf_Data *d, dst;
+
+	if ((ec = e->e_class) == ELFCLASS32)
+		sh_type = s->s_shdr.s_shdr32.sh_type;
+	else
+		sh_type = s->s_shdr.s_shdr64.sh_type;
+
+	/*
+	 * Ignore sections that do not allocate space in the file.
+	 */
+	if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
+		return (rc);
+
+
+	elftype = _libelf_xlate_shtype(sh_type);
+	assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);
+
+	msz = _libelf_msize(elftype, ec, e->e_version);
+
+	sh_off = s->s_offset;
+	assert(sh_off % _libelf_malign(elftype, ec) == 0);
+
+	/*
+	 * If the section has a `rawdata' descriptor, and the section
+	 * contents have not been modified, use its contents directly.
+	 * The `s_rawoff' member contains the offset into the original
+	 * file, while `s_offset' contains its new location in the
+	 * destination.
+	 */
+
+	if (STAILQ_EMPTY(&s->s_data)) {
+
+		if ((d = elf_rawdata(s, NULL)) == NULL)
+			return ((off_t) -1);
+
+		STAILQ_FOREACH(d, &s->s_rawdata, d_next) {
+			if ((uint64_t) rc < sh_off + d->d_off)
+				(void) memset(nf + rc,
+				    LIBELF_PRIVATE(fillchar), sh_off +
+				    d->d_off - rc);
+			rc = sh_off + d->d_off;
+
+			assert(d->d_buf != NULL);
+			assert(d->d_type == ELF_T_BYTE);
+			assert(d->d_version == e->e_version);
+
+			(void) memcpy(nf + rc,
+			    e->e_rawfile + s->s_rawoff + d->d_off, d->d_size);
+
+			rc += d->d_size;
+		}
+
+		return (rc);
+	}
+
+	/*
+	 * Iterate over the set of data descriptors for this section.
+	 * The prior call to _libelf_resync_elf() would have setup the
+	 * descriptors for this step.
+	 */
+
+	dst.d_version = e->e_version;
+
+	STAILQ_FOREACH(d, &s->s_data, d_next) {
+
+		if ((uint64_t) rc < sh_off + d->d_off)
+			(void) memset(nf + rc,
+			    LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc);
+
+		rc = sh_off + d->d_off;
+
+		assert(d->d_buf != NULL);
+		assert(d->d_type == (Elf_Type) elftype);
+		assert(d->d_version == e->e_version);
+		assert(d->d_size % msz == 0);
+
+		nobjects = d->d_size / msz;
+
+		fsz = _libelf_fsize(elftype, ec, e->e_version, nobjects);
+
+		dst.d_buf    = nf + rc;
+		dst.d_size   = fsz * nobjects;
+
+		if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) ==
+		    NULL)
+			return ((off_t) -1);
+
+		rc += fsz * nobjects;
+	}
+
+	return ((off_t) rc);
+}
+
+/*
+ * Write out the file image.
+ *
+ * The original file could have been mapped in with an ELF_C_RDWR
+ * command and the application could have added new content or
+ * re-arranged its sections before calling elf_update().  Consequently
+ * its not safe to work `in place' on the original file.  So we
+ * malloc() the required space for the updated ELF object and build
+ * the object there and write it out to the underlying file at the
+ * end.  Note that the application may have opened the underlying file
+ * in ELF_C_RDWR and only retrieved/modified a few sections.  We take
+ * care to avoid translating file sections unnecessarily.
+ *
+ * Gaps in the coverage of the file by the file's sections will be
+ * filled with the fill character set by elf_fill(3).
+ */
+
+static off_t
+_libelf_write_elf(Elf *e, off_t newsize)
+{
+	int ec;
+	off_t rc;
+	size_t fsz, msz, phnum, shnum;
+	uint64_t phoff, shoff;
+	void *ehdr;
+	char *newfile;
+	Elf_Data dst, src;
+	Elf_Scn *scn, *tscn;
+	Elf32_Ehdr *eh32;
+	Elf64_Ehdr *eh64;
+
+	assert(e->e_kind == ELF_K_ELF);
+	assert(e->e_cmd != ELF_C_READ);
+	assert(e->e_fd >= 0);
+
+	if ((newfile = malloc(newsize)) == NULL) {
+		LIBELF_SET_ERROR(RESOURCE, errno);
+		return ((off_t) -1);
+	}
+
+	ec = e->e_class;
+
+	ehdr = _libelf_ehdr(e, ec, 0);
+	assert(ehdr != NULL);
+
+	if (ec == ELFCLASS32) {
+		eh32 = (Elf32_Ehdr *) ehdr;
+
+		phnum = eh32->e_phnum;
+		phoff = (uint64_t) eh32->e_phoff;
+		shnum = eh32->e_shnum;
+		shoff = (uint64_t) eh32->e_shoff;
+
+	} else {
+		eh64 = (Elf64_Ehdr *) ehdr;
+
+		phnum = eh64->e_phnum;
+		phoff = eh64->e_phoff;
+		shnum = eh64->e_shnum;
+		shoff = eh64->e_shoff;
+	}
+
+	fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, 1);
+	msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version);
+
+	(void) memset(&dst, 0, sizeof(dst));
+	(void) memset(&src, 0, sizeof(src));
+
+	src.d_buf     = ehdr;
+	src.d_size    = msz;
+	src.d_type    = ELF_T_EHDR;
+	src.d_version = dst.d_version = e->e_version;
+
+	rc = 0;
+
+	dst.d_buf     = newfile + rc;
+	dst.d_size    = fsz;
+
+	if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
+	    NULL)
+		goto error;
+
+	rc += fsz;
+
+	/*
+	 * Write the program header table if present.
+	 */
+
+	if (phnum != 0 && phoff != 0) {
+		assert((unsigned) rc <= phoff);
+
+		fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, 1);
+
+		assert(phoff % _libelf_malign(ELF_T_PHDR, ec) == 0);
+		assert(fsz > 0);
+
+		src.d_version = dst.d_version = e->e_version;
+		src.d_type = ELF_T_PHDR;
+
+		if (ec == ELFCLASS32)
+			src.d_buf = e->e_u.e_elf.e_phdr.e_phdr32;
+		else
+			src.d_buf = e->e_u.e_elf.e_phdr.e_phdr64;
+
+		src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec,
+		    e->e_version);
+
+		dst.d_size = fsz;
+
+		if ((uint64_t) rc < phoff)
+			(void) memset(newfile + rc,
+			    LIBELF_PRIVATE(fillchar), phoff - rc);
+
+		rc = phoff;
+		dst.d_buf = newfile + rc;
+
+		if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
+		    NULL)
+			goto error;
+	}
+
+	/*
+	 * Write out individual sections.
+	 */
+
+	STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next)
+ 		if ((rc = _libelf_write_scn(e, newfile, scn, rc)) < 0)
+			goto error;
+
+	/*
+	 * Write out the section header table, if required.
+	 */
+
+	if (shnum != 0 && shoff != 0) {
+		assert((unsigned) rc <= shoff);
+
+		if ((uint64_t) rc < shoff)
+			(void) memset(newfile + rc,
+			    LIBELF_PRIVATE(fillchar), shoff - rc);
+
+		rc = shoff;
+
+		assert(rc % _libelf_malign(ELF_T_SHDR, ec) == 0);
+
+		src.d_type = ELF_T_SHDR;
+		src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version);
+		src.d_version = dst.d_version = e->e_version;
+
+		fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1);
+
+		STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) {
+			if (ec == ELFCLASS32)
+				src.d_buf = &scn->s_shdr.s_shdr32;
+			else
+				src.d_buf = &scn->s_shdr.s_shdr64;
+
+			dst.d_size = fsz;
+			dst.d_buf = newfile + rc;
+
+			if (_libelf_xlate(&dst, &src, e->e_byteorder, ec,
+				ELF_TOFILE) != &dst)
+				goto error;
+
+			rc += fsz;
+		}
+	}
+
+	/*
+	 */
+
+	assert(rc == newsize);
+
+	/*
+	 * Write out the constructed contents and remap the file in
+	 * read-only.
+	 */
+
+	if (munmap(e->e_rawfile, e->e_rawsize) < 0 ||
+	    write(e->e_fd, newfile, newsize) != newsize ||
+	    lseek(e->e_fd, 0, SEEK_SET) < 0 ||
+	    (e->e_rawfile = mmap(NULL, e->e_rawsize, PROT_READ, MAP_PRIVATE,
+		e->e_fd, (off_t) 0)) == MAP_FAILED) {
+		LIBELF_SET_ERROR(IO, errno);
+		goto error;
+	}
+	e->e_rawsize = newsize;
+
+	/*
+	 * Reset flags, remove existing section descriptors and
+	 * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()
+	 * and elf_getscn() will function correctly.
+	 */
+
+	e->e_flags &= ~ELF_F_DIRTY;
+
+	STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn)
+		_libelf_release_scn(scn);
+
+	if (ec == ELFCLASS32) {
+		free(e->e_u.e_elf.e_ehdr.e_ehdr32);
+		if (e->e_u.e_elf.e_phdr.e_phdr32)
+			free(e->e_u.e_elf.e_phdr.e_phdr32);
+
+		e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;
+		e->e_u.e_elf.e_phdr.e_phdr32 = NULL;
+	} else {
+		free(e->e_u.e_elf.e_ehdr.e_ehdr64);
+		if (e->e_u.e_elf.e_phdr.e_phdr64)
+			free(e->e_u.e_elf.e_phdr.e_phdr64);
+
+		e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;
+		e->e_u.e_elf.e_phdr.e_phdr64 = NULL;
+	}
+
+	return (rc);
+
+ error:
+	if (newfile)
+		free(newfile);
+	return ((off_t) -1);
+}
+
 off_t
-elf_update(__unused Elf *elf, __unused Elf_Cmd cmd)
+elf_update(Elf *e, Elf_Cmd c)
 {
-	printf("%s: not implemented\n", __FUNCTION__);
-	return (0);
+	int ec;
+	off_t rc;
+
+	rc = (off_t) -1;
+
+	if (e == NULL || e->e_kind != ELF_K_ELF ||
+	    (c != ELF_C_NULL && c != ELF_C_WRITE)) {
+		LIBELF_SET_ERROR(ARGUMENT, 0);
+		return (rc);
+	}
+
+	if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
+		LIBELF_SET_ERROR(CLASS, 0);
+		return (rc);
+	}
+
+	if (e->e_version == EV_NONE)
+		e->e_version = EV_CURRENT;
+
+	if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {
+		LIBELF_SET_ERROR(MODE, 0);
+		return (rc);
+	}
+
+	if ((rc = _libelf_resync_elf(e)) < 0)
+		return (rc);
+
+	if (c == ELF_C_NULL)
+		return (rc);
+
+	if (e->e_cmd == ELF_C_READ) {
+		/*
+		 * This descriptor was opened in read-only mode or by
+		 * elf_memory().
+		 */
+		if (e->e_fd)
+			LIBELF_SET_ERROR(MODE, 0);
+		else
+			LIBELF_SET_ERROR(ARGUMENT, 0);
+		return ((off_t) -1);
+	}
+
+	if (e->e_fd < 0) {
+		LIBELF_SET_ERROR(SEQUENCE, 0);
+		return ((off_t) -1);
+	}
+
+	return (_libelf_write_elf(e, rc));
 }

==== //depot/projects/dtrace/src/lib/libelf/gelf_getshdr.c#3 (text+ko) ====

@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2006 John Birrell jb@freebsd.org
+ * Copyright (c) 2006 Joseph Koshy
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,36 +27,91 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <assert.h>
 #include <gelf.h>
 #include <libelf.h>
-#include <stdio.h>
 
 #include "_libelf.h"
 
 Elf32_Shdr *
-elf32_getshdr(__unused Elf_Scn *scn)
+elf32_getshdr(Elf_Scn *s)
 {
-	printf("%s: not implemented\n", __FUNCTION__);
-	return (0);
+	int ec;
+	Elf *e;
+
+	if (s == NULL || (e = s->s_elf) == NULL ||
+	    e->e_kind != ELF_K_ELF) {
+		LIBELF_SET_ERROR(ARGUMENT, 0);
+		return (NULL);
+	}
+
+	ec = e->e_class;
+
+	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+	if (ec != ELFCLASS32) {
+		LIBELF_SET_ERROR(CLASS, 0);
+		return (NULL);
+	}
+
+	return (&s->s_shdr.s_shdr32);
 }
 
 Elf64_Shdr *
-elf64_getshdr(__unused Elf_Scn *scn)
+elf64_getshdr(Elf_Scn *s)
 {
-	printf("%s: not implemented\n", __FUNCTION__);
-	return (0);
+	int ec;
+	Elf *e;
+
+	if (s == NULL || (e = s->s_elf) == NULL ||
+	    e->e_kind != ELF_K_ELF) {
+		LIBELF_SET_ERROR(ARGUMENT, 0);
+		return (NULL);
+	}
+
+	ec = e->e_class;
+
+	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+	if (ec != ELFCLASS64) {
+		LIBELF_SET_ERROR(CLASS, 0);
+		return (NULL);
+	}
+
+	return (&s->s_shdr.s_shdr64);
 }
 
 GElf_Shdr *
-gelf_getshdr(__unused Elf_Scn *scn, __unused GElf_Shdr *dst)
+gelf_getshdr(Elf_Scn *s, GElf_Shdr *d)
 {
-	printf("%s: not implemented\n", __FUNCTION__);
-	return (0);
-}
+	int ec;
+	Elf *e;
+	Elf32_Shdr *sh32;
+
+	if (s == NULL || d == NULL ||
+	    (e = s->s_elf) || e->e_kind != ELF_K_ELF) {
+		LIBELF_SET_ERROR(ARGUMENT, 0);
+		return (NULL);
+	}
+
+	ec = e->e_class;
+	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
+
+	if (ec == ELFCLASS32) {
+		sh32 = &s->s_shdr.s_shdr32;
+
+		d->sh_name      = sh32->sh_name;
+		d->sh_type      = sh32->sh_type;
+		d->sh_flags     = (Elf64_Xword) sh32->sh_flags;
+		d->sh_addr      = (Elf64_Addr) sh32->sh_addr;
+		d->sh_offset    = (Elf64_Off) sh32->sh_offset;
+		d->sh_size      = (Elf64_Xword) sh32->sh_size;
+		d->sh_link      = sh32->sh_link;
+		d->sh_info      = sh32->sh_info;
+		d->sh_addralign = (Elf64_Xword) sh32->sh_addralign;
+		d->sh_entsize   = (Elf64_Xword) sh32->sh_entsize;
+	} else
+		*d = s->s_shdr.s_shdr64;
 
-int
-elf_getshstrndx(__unused Elf *elf, __unused size_t *dst)
-{
-	printf("%s: not implemented\n", __FUNCTION__);
-	return (0);
+	return (d);
 }

==== //depot/projects/dtrace/src/lib/libelf/gelf_rel.c#2 (text+ko) ====


==== //depot/projects/dtrace/src/lib/libelf/gelf_rela.c#2 (text+ko) ====




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200610070043.k970hgEB092061>