From nobody@FreeBSD.org  Thu Apr 19 18:02:21 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 50D55106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 19 Apr 2012 18:02:21 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 300698FC08
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 19 Apr 2012 18:02:21 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q3JI2KED038059
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 19 Apr 2012 18:02:20 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id q3JI2KtZ038058;
	Thu, 19 Apr 2012 18:02:20 GMT
	(envelope-from nobody)
Message-Id: <201204191802.q3JI2KtZ038058@red.freebsd.org>
Date: Thu, 19 Apr 2012 18:02:20 GMT
From: Steve Wills <swills@FreeBSD.org>
To: freebsd-gnats-submit@FreeBSD.org
Subject: dtrace generates core dump trying to build perl with dtrace enabled
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         167103
>Category:       bin
>Synopsis:       dtrace(1) generates core dump trying to build perl with dtrace enabled
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    markj
>State:          analyzed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Apr 19 18:10:08 UTC 2012
>Closed-Date:    
>Last-Modified:  Sun Feb 24 15:20:00 UTC 2013
>Originator:     Steve Wills
>Release:        
>Organization:
>Environment:
>Description:
Try to build perl with dtrace enabled. In this case, I am getting perl from their git repo:

  git clone git://perl5.git.perl.org/perl.git perl

then applying a small patch:


diff --git a/Makefile.SH b/Makefile.SHindex ba5ab79..d4f609d 100755
--- a/Makefile.SH
+++ b/Makefile.SH
@@ -225,7 +225,7 @@ minidtrace_o=''
 case "$usedtrace" in
 define|true)
        dtrace_h='perldtrace.h' 
-       $dtrace -G -s perldtrace.d -o perldtrace.tmp >/dev/null 2>&1 \
+       $dtrace -64 -G -s perldtrace.d -o perldtrace.tmp >/dev/null 2>&1 \
                && rm -f perldtrace.tmp && dtrace_o='perldtrace$(OBJ_EXT)' \
                && minidtrace_o='miniperldtrace$(OBJ_EXT)'        ;;
@@ -548,6 +548,7 @@ splintfiles = $(c1)
  .c$(OBJ_EXT):
         $(CCCMD) $(PLDLFLAGS) $*.c
+       ctfconvert -L DEFAULT $@  .c.i: 

        $(CCCMDSRC) -E $*.c > $*.i
diff --git a/hints/freebsd.sh b/hints/freebsd.sh
index a67c0bb..344a847 100644
--- a/hints/freebsd.sh
+++ b/hints/freebsd.sh
@@ -309,3 +309,7 @@ esac
 # Meanwhile, the following workaround should be safe on all versions
 # of FreeBSD.
 d_printf_format_null='undef'
+
+case "$usedtrace" in
+$define|true|[Yy]*) libswanted="$libswanted dtrace dwarf elf proc ctf rtld_db z pthread"
+esac

Note, the fact that the -64 is needed there may be another, separate
bug.

After this, I configure with:

/usr/bin/env CC="cc" CPP="cpp" CXX="c++"  CFLAGS="-O2 -pipe -g -fno-omit-frame-pointer -fno-strict-aliasing" CPPFLAGS="" CXXFLAGS="-O2 -pipe -g -fno-omit-frame-pointer -fno-strict-aliasing"  LDFLAGS=""  INSTALL="/usr/bin/install -c "  INSTALL_DATA="install   -m 444"  INSTALL_LIB="install    -m 444"  INSTALL_PROGRAM="install    -m 555"  INSTALL_SCRIPT="install   -m 555"  LANG="" LC_ALL="" LC_COLLATE="" LC_CTYPE=""  LC_MESSAGES="" LC_MONETARY="" LC_NUMERIC=""  LC_TIME="" UNAME_v="$(uname -v | sed 'y/=/ /')" SHELL=/bin/sh CONFIG_SHELL=/bin/sh ./Configure -sde -Dprefix=/usr/local  -Ui_malloc -Ui_iconv -Uinstallusrbinperl  -Dcc="cc" -Duseshrplib -Dinc_version_list=none  -Dccflags=-DAPPLLIB_EXP=\"/usr/local/lib/perl5/5.12.4/BSDPAN\" -Doptimize="-O2 -pipe -g -fno-omit-frame-pointer -fno-strict-aliasing" -Ui_gdbm -Dusedtrace=define -Dusethreads=n -Dusemymalloc=n -Duse64bitint -Dusedevel

Then build via make. This produces this error:

/usr/sbin/dtrace -G -s perldtrace.d -o miniperldtrace.o perlmini.o opmini.o miniperlmain.o   gv.o toke.o perly.o pad.o regcomp.o dump.o util.o mg.o reentr.o mro.o keywords.o hv.o av.o run.o pp_hot.o sv.o pp.o scope.o pp_ctl.o pp_sys.o doop.o doio.o regexec.o utf8.o taint.o deb.o universal.o globals.o perlio.o perlapi.o numeric.o mathoms.o locale.o pp_pack.o pp_sort.o  perlmini.o
dtrace: (malloc) /usr/src/lib/libc/stdlib/malloc.c:2644: Failed assertion: "(run->regs_mask[elm] & (1U << bit)) == 0"*** [miniperldtrace.o] Signal 6

Which shows a core dump in the dtrace command line utility. Backtrace
on that looks like this:

% gdb /usr/sbin/dtrace dtrace.core [GDB will not be able to debug user-mode threads: Undefined symbol "td_thr_getxmmregs"]GNU gdb 6.1.1 [FreeBSD]Copyright 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB.  Type "show warranty" for details.This GDB was configured as "amd64-marcel-freebsd"...Core was generated by `dtrace'.Program terminated with signal 6, Aborted.Reading symbols from /lib/libthr.so.3...done.
Loaded symbols for /lib/libthr.so.3Reading symbols from /lib/libdtrace.so.2...done.Loaded symbols for /lib/libdtrace.so.2
Reading symbols from /usr/lib/libproc.so.2...done.
Loaded symbols for /usr/lib/libproc.so.2
Reading symbols from /lib/libctf.so.2...done.
Loaded symbols for /lib/libctf.so.2Reading symbols from /usr/lib/libelf.so.1...done.
Loaded symbols for /usr/lib/libelf.so.1
Reading symbols from /lib/libz.so.6...done.
Loaded symbols for /lib/libz.so.6
Reading symbols from /lib/libutil.so.9...done.
Loaded symbols for /lib/libutil.so.9
Reading symbols from /usr/lib/librtld_db.so.2...done.
Loaded symbols for /usr/lib/librtld_db.so.2
Reading symbols from /lib/libc.so.7...done.
Loaded symbols for /lib/libc.so.7
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
#0  0x000000080198be7c in thr_kill () at thr_kill.S:3
3       RSYSCALL(thr_kill)
(gdb) bt
#0  0x000000080198be7c in thr_kill () at thr_kill.S:3
#1  0x0000000801a2f72b in abort () at /usr/src/lib/libc/stdlib/abort.c:65
#2  0x00000008019af43c in arena_dalloc_bin (arena=0x607f30, chunk=0x802000000, ptr=0x802066800, mapelm=Variable "mapelm" is not available.
) at /usr/src/lib/libc/stdlib/malloc.c:2586
#3  0x00000008019b0f13 in idalloc (ptr=0x802066800) at /usr/src/lib/libc/stdlib/malloc.c:4318
#4  0x00000008019b1cf5 in free (ptr=0x802066800) at /usr/src/lib/libc/stdlib/malloc.c:6168
#5  0x0000000800a5d244 in dt_link_error (dtp=0x80202c000, elf=Variable "elf" is not available.
) at /usr/src/cddl/lib/libdtrace/../../../cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c:1095
#6  0x0000000800a5d34f in process_obj (dtp=0x80202c000, obj=0x7fffffffd6a3 "pp_ctl.o", eprobesp=0x7fffffffc4e8)
    at /usr/src/cddl/lib/libdtrace/../../../cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c:1587
#7  0x0000000800a5e4f5 in dtrace_program_link (dtp=0x80202c000, pgp=0x8042f1a00, dflags=2, file=0x80201e030 "miniperldtrace.o", objc=39, objv=0x802018188)
    at /usr/src/cddl/lib/libdtrace/../../../cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c:1682
#8  0x0000000000404789 in main (argc=Variable "argc" is not available.
) at /usr/src/cddl/usr.sbin/dtrace/../../../cddl/contrib/opensolaris/cmd/dtrace/dtrace.c:682
Current language:  auto; currently asm
(gdb)
>How-To-Repeat:
See above
>Fix:
no idea

>Release-Note:
>Audit-Trail:

From: Mark Johnston <markjdb@gmail.com>
To: bug-followup@FreeBSD.org, swills@FreeBSD.org
Cc:  
Subject: Re: bin/167103: dtrace(1) generates core dump trying to build perl
 with dtrace enabled
Date: Thu, 22 Nov 2012 16:22:54 -0500

 --9amGYk9869ThD9tj
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 The assertion failure is the result of a double free in
 dt_link.c:process_obj, and it's basically happening because libdtrace is
 dependant on some internal behaviour of Solaris' libelf.
 
 In the block between lines 1358 and 1415, some buffers are injected into
 a couple of libelf structures (data_str and data_sym). On Solaris, it
 looks like the overwritten pointers are just pointers into a larger
 buffer; on FreeBSD, they're allocated on their own and then freed in
 elf_close(3). Thus the injected buffers get freed by both libdtrace and
 libelf.
 
 I think the right fix is to just #ifdef the free()s out. One could
 implement a portable fix by saving pointers to the original buffers
 somewhere (probably in the struct dt_link_pair) and restore them before
 calling elf_close(). But I don't think fixes to FreeBSD's dtrace port
 are going to go back upstream anyway, so I've attached a patch with the
 simple fix.
 
 To reproduce this on a recent CURRENT, it'll be necessary to follow one
 of the workarounds described in bin/171678 first.
 
 Now, in the case of perl, we immediately run into another problem after
 my patch. The build then fails with:
 
 	dtrace: failed to link script perldtrace.d: an error was
 	encountered while processing pp_ctl.o
 
 It looks like this is caused by an unrelated dependance on Solaris
 libelf's behaviour, but I haven't pinned it down yet.
 
 Thanks,
 -Mark
 
 --9amGYk9869ThD9tj
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="dtrace_double_free.patch.txt"
 
 diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
 index 2d0428a..00c52ab 100644
 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
 +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
 @@ -1092,8 +1092,10 @@ dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs,
  
  	while ((pair = bufs) != NULL) {
  		bufs = pair->dlp_next;
 +#if !defined(__FreeBSD__)
  		dt_free(dtp, pair->dlp_str);
  		dt_free(dtp, pair->dlp_sym);
 +#endif
  		dt_free(dtp, pair);
  	}
  
 @@ -1385,6 +1387,9 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  			bufs = pair;
  
  			bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size);
 +#if defined( __FreeBSD__)
 +			free(data_str->d_buf);
 +#endif
  			data_str->d_buf = pair->dlp_str;
  			data_str->d_size += len;
  			(void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY);
 @@ -1393,6 +1398,9 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  			(void) gelf_update_shdr(scn_str, &shdr_str);
  
  			bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size);
 +#if defined(__FreeBSD__)
 +			free(data_sym->d_buf);
 +#endif
  			data_sym->d_buf = pair->dlp_sym;
  			data_sym->d_size += nsym * symsize;
  			(void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY);
 @@ -1576,8 +1584,10 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  #endif
  	while ((pair = bufs) != NULL) {
  		bufs = pair->dlp_next;
 +#if !defined(__FreeBSD__)
  		dt_free(dtp, pair->dlp_str);
  		dt_free(dtp, pair->dlp_sym);
 +#endif
  		dt_free(dtp, pair);
  	}
  
 
 --9amGYk9869ThD9tj--

From: Mark Johnston <markjdb@gmail.com>
To: bug-followup@FreeBSD.org, swills@FreeBSD.org
Cc:  
Subject: Re: bin/167103: dtrace(1) generates core dump trying to build perl
 with dtrace enabled
Date: Tue, 8 Jan 2013 19:27:29 -0500

 I've spent some more time digging into this and found a simple way to
 reproduce it. The problem only seems to occur when a probe is located in
 a static function. Some comments in dt_link.c indicate that there's some
 special handling that's needed in this case, but I still don't quite
 understand what's causing the problem.
 
 I've placed a simple provider definition and sample program that
 reproduce the issue here:
 http://people.freebsd.org/~markj/dtrace/bin167103/
 
 When the repro program is built, dtrace(1) will segfault when processing
 the object file. When the patch attached to the PR is applied, dtrace
 will just exit with a generic error:
 
 dtrace -G -s provider.d repro.o
 provider: failed to link script provider: an error was encountered while processing repro.o
 *** [beforelinking] Error code 1
 
 I'm still working on figuring this out.
 
 Thanks,
 -Mark
State-Changed-From-To: open->analyzed 
State-Changed-By: markj 
State-Changed-When: Thu Jan 10 22:45:48 UTC 2013 
State-Changed-Why:  
I understand the problems now and am working on some patches. The second 
problem described in my replies is due to a bug in libelf which has been 
fixed upstream (in elftoolchain). 


Responsible-Changed-From-To: freebsd-bugs->markj 
Responsible-Changed-By: markj 
Responsible-Changed-When: Thu Jan 10 22:45:48 UTC 2013 
Responsible-Changed-Why:  
I understand the problems now and am working on some patches. The second 
problem described in my replies is due to a bug in libelf which has been 
fixed upstream (in elftoolchain). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=167103 

From: Mark Johnston <markjdb@gmail.com>
To: bug-followup@FreeBSD.org, swills@FreeBSD.org
Cc:  
Subject: Re: bin/167103: dtrace(1) generates core dump trying to build perl
 with dtrace enabled
Date: Sun, 27 Jan 2013 12:02:25 -0500

 --f+W+jCU1fRNres8c
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 I've managed to come up with proper fixes for the problems here. With
 them, the dtrace step completes properly, but the perl build fails later
 on for an unrelated reason which I haven't looked into. However, my
 little test program (which just has a probe in a static function) works
 properly now.
 
 I've attached two patches. The first one changes libdtrace to do the
 work in process_obj() using offical libelf APIs; it supersedes the
 earlier patch attached to this PR. Currently, dtrace adds new symbol
 table entries by copying the old symbol table into a larger buffer,
 adding symbols at the end, and reinserting it into a libelf data
 structure. This approach works, but it's not clear who's responsible for
 freeing the new buffer. This patch changes things so that dtrace
 allocates a new data descriptor for the symbol table and adds new
 symbols there. It's a bit more code than the previous patch, but it has
 the benefit of not depending on libelf internals.
 
 The second patch is a partial merge of r1712 from elftoolchain. Without
 this, libelf doesn't seem to handle section size changes when
 recomputing the section extents and elf_update() will fail. It looks
 like FreeBSD's libelf hasn't been kept in sync with upstream libelf; I'm
 not sure why that is.
 
 Thanks,
 -Mark
 
 --f+W+jCU1fRNres8c
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="libdtrace_data_desc.diff"
 
 diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
 index 2d0428a..abafb3b 100644
 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
 +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
 @@ -1124,6 +1124,10 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  	key_t objkey;
  	dt_link_pair_t *pair, *bufs = NULL;
  	dt_strtab_t *strtab;
 +#if defined(__FreeBSD__)
 +	Elf_Data *data_newsym, *data_newstr;
 +	size_t newsym = 0;
 +#endif
  
  	if ((fd = open64(obj, O_RDWR)) == -1) {
  		return (dt_link_error(dtp, elf, fd, bufs,
 @@ -1352,6 +1356,11 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  		 * newly allocated buffers into the libelf data structures, but
  		 * are still responsible for freeing them once we're done with
  		 * the elf handle.
 +		 *
 +		 * On FreeBSD, we instead use a new data descriptor to add to
 +		 * the symbol table. This approach also works and doesn't depend
 +		 * on the internal memory management details of libelf (which
 +		 * apparently differ between Solaris and FreeBSD).
  		 */
  		if (nsym > 0) {
  			/*
 @@ -1368,6 +1377,32 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  			if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL)
  				goto err;
  
 +#if defined(__FreeBSD__)
 +			if ((pair->dlp_str = dt_alloc(dtp, len)) == NULL) {
 +				dt_free(dtp, pair);
 +				goto err;
 +			}
 +
 +			if ((pair->dlp_sym =
 +			    dt_alloc(dtp, nsym * symsize)) == NULL) {
 +				dt_free(dtp, pair->dlp_str);
 +				dt_free(dtp, pair);
 +				goto err;
 +			}
 +
 +			pair->dlp_next = bufs;
 +			bufs = pair;
 +
 +			if ((data_newstr = elf_newdata(scn_str)) == NULL)
 +				goto err;
 +			data_newstr->d_size = len;
 +			data_newstr->d_buf = pair->dlp_str;
 +
 +			if ((data_newsym = elf_newdata(scn_sym)) == NULL)
 +				goto err;
 +			data_newsym->d_size = nsym * symsize;
 +			data_newsym->d_buf = pair->dlp_sym;
 +#else
  			if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size +
  			    len)) == NULL) {
  				dt_free(dtp, pair);
 @@ -1399,6 +1434,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  
  			shdr_sym.sh_size += nsym * symsize;
  			(void) gelf_update_shdr(scn_sym, &shdr_sym);
 +#endif /* !defined(__FreeBSD__) */
  
  			nsym += isym;
  		} else {
 @@ -1463,9 +1499,17 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  
  			p = strhyphenate(p + 3); /* strlen("___") */
  
 +#if defined(__FreeBSD__)
 +			if (dt_symtab_lookup(data_newsym, newsym, rela.r_offset,
 +			    shdr_rel.sh_info, &fsym) != 0 &&
 +			    dt_symtab_lookup(data_sym, isym, rela.r_offset,
 +			    shdr_rel.sh_info, &fsym) != 0)
 +				goto err;
 +#else
  			if (dt_symtab_lookup(data_sym, isym, rela.r_offset,
  			    shdr_rel.sh_info, &fsym) != 0)
  				goto err;
 +#endif
  
  			if (fsym.st_name > data_str->d_size)
  				goto err;
 @@ -1491,12 +1535,23 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
  				    STT_FUNC);
  				dsym.st_other =
  				    ELF64_ST_VISIBILITY(STV_ELIMINATE);
 +#if defined(__FreeBSD__)
 +				(void)gelf_update_sym(data_newsym, newsym,
 +				    &dsym);
 +
 +				r = (char *)data_newstr->d_buf +
 +				    (istr - data_str->d_size);
 +#else
  				(void) gelf_update_sym(data_sym, isym, &dsym);
  
  				r = (char *)data_str->d_buf + istr;
 +#endif
  				istr += 1 + sprintf(r, dt_symfmt,
  				    dt_symprefix, objkey, s);
  				isym++;
 +#if defined(__FreeBSD__)
 +				newsym++;
 +#endif
  				assert(isym <= nsym);
  
  			} else if (strncmp(s, dt_symprefix,
 
 --f+W+jCU1fRNres8c
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="libelf_r1712_merge.diff"
 
 diff --git a/lib/libelf/elf_update.c b/lib/libelf/elf_update.c
 index 5880c07..813d2bc 100644
 --- a/lib/libelf/elf_update.c
 +++ b/lib/libelf/elf_update.c
 @@ -41,89 +41,79 @@ __FBSDID("$FreeBSD$");
  #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.
 + * Layout strategy:
   *
 - * After a successful call to this function, the following structures
 - * are updated:
 + * - Case 1: ELF_F_LAYOUT is asserted
 + *     In this case the application has full control over where the
 + *     section header table, program header table, and section data
 + *     will reside.   The library only perform error checks.
   *
 - * - 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.
 + * - Case 2: ELF_F_LAYOUT is not asserted
   *
 - * After a resync_elf() successfully returns, the ELF descriptor is
 - * ready for being handed over to _libelf_write_elf().
 + *     The library will do the object layout using the following
 + *     ordering:
 + *     - The executable header is placed first, are required by the
 + *     	 ELF specification.
 + *     - The program header table is placed immediately following the
 + *       executable header.
 + *     - Section data, if any, is placed after the program header
 + *       table, aligned appropriately.
 + *     - The section header table, if needed, is placed last.
   *
 - * File alignments:
 - * PHDR - Addr
 - * SHDR - Addr
 + *     There are two sub-cases to be taken care of:
   *
 - * XXX: how do we handle 'flags'.
 + *     - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR
 + *
 + *       In this sub-case, the underlying ELF object may already have
 + *       content in it, which the application may have modified.  The
 + *       library will retrieve content from the existing object as
 + *       needed.
 + *
 + *     - Case 2b: e->e_cmd == ELF_C_WRITE
 + *
 + *       The ELF object is being created afresh in this sub-case;
 + *       there is no pre-existing content in the underlying ELF
 + *       object.
   */
  
  /*
   * Compute the extents of a section, by looking at the data
 - * descriptors associated with it.  The function returns zero if an
 - * error was detected.  `*rc' holds the maximum file extent seen so
 - * far.
 + * descriptors associated with it.  The function returns 1 if
 + * successful, or zero if an error was detected.
   */
  static int
 -_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc)
 +_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc)
  {
  	int ec;
 -	Elf_Data *d, *td;
 +	size_t fsz, msz;
 +	Elf_Data *d;
 +	Elf32_Shdr *shdr32;
 +	Elf64_Shdr *shdr64;
  	unsigned int elftype;
  	uint32_t sh_type;
  	uint64_t d_align;
  	uint64_t sh_align, sh_entsize, 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(), or if a new Elf_Data structure was added using
 -	 *   elf_newdata().
 -	 *
 -	 * Each of these conditions would result in the ELF_F_DIRTY bit being
 -	 * set on the section descriptor's `s_flags' field.
 -	 */
 -
  	ec = e->e_class;
  
 +	shdr32 = &s->s_shdr.s_shdr32;
 +	shdr64 = &s->s_shdr.s_shdr64;
  	if (ec == ELFCLASS32) {
 -		sh_type    = s->s_shdr.s_shdr32.sh_type;
 -		sh_align   = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
 -		sh_entsize = (uint64_t) s->s_shdr.s_shdr32.sh_entsize;
 -		sh_offset  = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
 -		sh_size    = (uint64_t) s->s_shdr.s_shdr32.sh_size;
 +		sh_type    = shdr32->sh_type;
 +		sh_align   = (uint64_t) shdr32->sh_addralign;
 +		sh_entsize = (uint64_t) shdr32->sh_entsize;
 +		sh_offset  = (uint64_t) shdr32->sh_offset;
 +		sh_size    = (uint64_t) shdr32->sh_size;
  	} else {
 -		sh_type    = s->s_shdr.s_shdr64.sh_type;
 -		sh_align   = s->s_shdr.s_shdr64.sh_addralign;
 -		sh_entsize = s->s_shdr.s_shdr64.sh_entsize;
 -		sh_offset  = s->s_shdr.s_shdr64.sh_offset;
 -		sh_size    = s->s_shdr.s_shdr64.sh_size;
 +		sh_type    = shdr64->sh_type;
 +		sh_align   = shdr64->sh_addralign;
 +		sh_entsize = shdr64->sh_entsize;
 +		sh_offset  = shdr64->sh_offset;
 +		sh_size    = shdr64->sh_size;
  	}
  
 -	if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
 -		return (1);
 -
 -	if ((s->s_flags & ELF_F_DIRTY) == 0) {
 -		if ((size_t) *rc < sh_offset + sh_size)
 -			*rc = sh_offset + sh_size;
 -		return (1);
 -	}
 +	assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS);
  
  	elftype = _libelf_xlate_shtype(sh_type);
  	if (elftype > ELF_T_LAST) {
 @@ -131,15 +121,52 @@ _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc)
  		return (0);
  	}
  
 -	/*
 -	 * Compute the extent of the data descriptors associated with
 -	 * this section.
 -	 */
 -	scn_alignment = 0;
  	if (sh_align == 0)
  		sh_align = _libelf_falign(elftype, ec);
  
 -	/* Compute the section alignment. */
 +	/*
 +	 * Check the section's data buffers for sanity and compute the
 +	 * section's alignment.
 +	 * Compute the section's size and alignment using the data
 +	 * descriptors associated with the section.
 +	 */
 +	if (STAILQ_EMPTY(&s->s_data)) {
 +		/*
 +		 * The section's content (if any) has not been read in
 +		 * yet.  If section is not dirty marked dirty, we can
 +		 * reuse the values in the 'sh_size' and 'sh_offset'
 +		 * fields of the section header.
 +		 */
 +		if ((s->s_flags & ELF_F_DIRTY) == 0) {
 +			/*
 +			 * If the library is doing the layout, then we
 +			 * compute the new start offset for the
 +			 * section based on the current offset and the
 +			 * section's alignment needs.
 +			 *
 +			 * If the application is doing the layout, we
 +			 * can use the value in the 'sh_offset' field
 +			 * in the section header directly.
 +			 */
 +			if (e->e_flags & ELF_F_LAYOUT)
 +				goto updatedescriptor;
 +			else
 +				goto computeoffset;
 +		}
 +
 +		/*
 +		 * Otherwise, we need to bring in the section's data
 +		 * from the underlying ELF object.
 +		 */
 +		if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL)
 +			return (0);
 +	}
 +
 +	/*
 +	 * Loop through the section's data descriptors.
 +	 */
 +	scn_size = 0L;
 +	scn_alignment = 0L;
  	STAILQ_FOREACH(d, &s->s_data, d_next)  {
  		if (d->d_type > ELF_T_LAST) {
  			LIBELF_SET_ERROR(DATA, 0);
 @@ -153,23 +180,40 @@ _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc)
  			LIBELF_SET_ERROR(DATA, 0);
  			return (0);
  		}
 -		if (d_align > scn_alignment)
 -			scn_alignment = d_align;
 -	}
  
 -	scn_size = 0L;
 +		/*
 +		 * The buffer's size should be a multiple of the
 +		 * memory size of the underlying type.
 +		 */
 +		msz = _libelf_msize(d->d_type, ec, e->e_version);
 +		if (d->d_size % msz) {
 +			LIBELF_SET_ERROR(DATA, 0);
 +			return (0);
 +		}
  
 -	STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) {
 +		/*
 +		 * Compute the section's size.
 +		 */
  		if (e->e_flags & ELF_F_LAYOUT) {
  			if ((uint64_t) d->d_off + d->d_size > scn_size)
  				scn_size = d->d_off + d->d_size;
  		} else {
  			scn_size = roundup2(scn_size, d->d_align);
  			d->d_off = scn_size;
 -			scn_size += d->d_size;
 +			fsz = _libelf_fsize(d->d_type, ec, d->d_version,
 +			    d->d_size / msz);
 +			scn_size += fsz;
  		}
 +
 +		/*
 +		 * The section's alignment is the maximum alignment
 +		 * needed for its data buffers.
 +		 */
 +		if (d_align > scn_alignment)
 +			scn_alignment = d_align;
  	}
  
 +
  	/*
  	 * If the application is requesting full control over the layout
  	 * of the section, check its values for sanity.
 @@ -180,46 +224,60 @@ _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc)
  			LIBELF_SET_ERROR(LAYOUT, 0);
  			return (0);
  		}
 -	} else {
 -		/*
 -		 * Otherwise compute the values in the section header.
 -		 */
 +		goto updatedescriptor;
 +	}
  
 -		if (scn_alignment > sh_align)
 -			sh_align = scn_alignment;
 +	/*
 +	 * Otherwise compute the values in the section header.
 +	 *
 +	 * The section alignment is the maximum alignment for any of
 +	 * its contained data descriptors.
 +	 */
 +	if (scn_alignment > sh_align)
 +		sh_align = scn_alignment;
  
 -		/*
 -		 * If the section entry size is zero, try and fill in an
 -		 * appropriate entry size.  Per the elf(5) manual page
 -		 * sections without fixed-size entries should have their
 -		 * 'sh_entsize' field set to zero.
 -		 */
 -		if (sh_entsize == 0 &&
 -		    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
 -		    (size_t) 1)) == 1)
 -			sh_entsize = 0;
 +	/*
 +	 * If the section entry size is zero, try and fill in an
 +	 * appropriate entry size.  Per the elf(5) manual page
 +	 * sections without fixed-size entries should have their
 +	 * 'sh_entsize' field set to zero.
 +	 */
 +	if (sh_entsize == 0 &&
 +	    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
 +	    (size_t) 1)) == 1)
 +		sh_entsize = 0;
  
 -		sh_size = scn_size;
 -		sh_offset = roundup(*rc, sh_align);
 +	sh_size = scn_size;
  
 -		if (ec == ELFCLASS32) {
 -			s->s_shdr.s_shdr32.sh_addralign = (uint32_t) sh_align;
 -			s->s_shdr.s_shdr32.sh_entsize   = (uint32_t) sh_entsize;
 -			s->s_shdr.s_shdr32.sh_offset    = (uint32_t) sh_offset;
 -			s->s_shdr.s_shdr32.sh_size      = (uint32_t) sh_size;
 -		} else {
 -			s->s_shdr.s_shdr64.sh_addralign = sh_align;
 -			s->s_shdr.s_shdr64.sh_entsize   = sh_entsize;
 -			s->s_shdr.s_shdr64.sh_offset    = sh_offset;
 -			s->s_shdr.s_shdr64.sh_size      = sh_size;
 -		}
 -	}
 +computeoffset:
 +	/*
 +	 * Compute the new offset for the section based on
 +	 * the section's alignment needs.
 +	 */
 +	sh_offset = roundup(rc, sh_align);
  
 -	if ((size_t) *rc < sh_offset + sh_size)
 -		*rc = sh_offset + sh_size;
 +	/*
 +	 * Update the section header.
 +	 */
 +	if (ec == ELFCLASS32) {
 +		shdr32->sh_addralign = (uint32_t) sh_align;
 +		shdr32->sh_entsize   = (uint32_t) sh_entsize;
 +		shdr32->sh_offset    = (uint32_t) sh_offset;
 +		shdr32->sh_size      = (uint32_t) sh_size;
 +	} else {
 +		shdr64->sh_addralign = sh_align;
 +		shdr64->sh_entsize   = sh_entsize;
 +		shdr64->sh_offset    = sh_offset;
 +		shdr64->sh_size      = sh_size;
 +	}
  
 +updatedescriptor:
 +	/*
 +	 * Update the section descriptor.
 +	 */
  	s->s_size = sh_size;
  	s->s_offset = sh_offset;
 +
  	return (1);
  }
  
 @@ -267,13 +325,16 @@ _libelf_insert_section(Elf *e, Elf_Scn *s)
  	return (1);
  }
  
 +/*
 + * Recompute section layout.
 + */
 +
  static off_t
  _libelf_resync_sections(Elf *e, off_t rc)
  {
  	int ec;
 -	off_t nrc;
 +	Elf_Scn *s;
  	size_t sh_type, shdr_start, shdr_end;
 -	Elf_Scn *s, *ts;
  
  	ec = e->e_class;
  
 @@ -281,13 +342,7 @@ _libelf_resync_sections(Elf *e, off_t rc)
  	 * 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) {
 +	STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) {
  		if (ec == ELFCLASS32)
  			sh_type = s->s_shdr.s_shdr32.sh_type;
  		else
 @@ -296,21 +351,22 @@ _libelf_resync_sections(Elf *e, off_t rc)
  		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);
 +		if (_libelf_compute_section_extents(e, s, rc) == 0)
 +			return ((off_t) -1);
 +
 +		if (s->s_size == 0)
 +			continue;
 +
 +		if (s->s_offset + s->s_size < (size_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
  			rc = s->s_offset + s->s_size;
  	}
 @@ -338,8 +394,6 @@ _libelf_resync_sections(Elf *e, off_t rc)
  		}
  	}
  
 -	assert(nrc == rc);
 -
  	return (rc);
  }
  
 
 --f+W+jCU1fRNres8c--

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/167103: commit references a PR
Date: Sun, 24 Feb 2013 15:15:59 +0000 (UTC)

 Author: markj
 Date: Sun Feb 24 15:15:50 2013
 New Revision: 247221
 URL: http://svnweb.freebsd.org/changeset/base/247221
 
 Log:
   Merge part of r1712 from elftoolchain, making it possible to resize ELF
   sections and indirectly change the layout of an ELF file when
   ELF_F_LAYOUT is not set.
   
   PR:		bin/167103
   Approved by:	rstone (co-mentor)
   Obtained from:	elftoolchain
   MFC after:	2 weeks
 
 Modified:
   head/lib/libelf/elf_update.c
 
 Modified: head/lib/libelf/elf_update.c
 ==============================================================================
 --- head/lib/libelf/elf_update.c	Sun Feb 24 11:32:45 2013	(r247220)
 +++ head/lib/libelf/elf_update.c	Sun Feb 24 15:15:50 2013	(r247221)
 @@ -41,89 +41,79 @@ __FBSDID("$FreeBSD$");
  #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.
 + * Layout strategy:
   *
 - * After a successful call to this function, the following structures
 - * are updated:
 + * - Case 1: ELF_F_LAYOUT is asserted
 + *     In this case the application has full control over where the
 + *     section header table, program header table, and section data
 + *     will reside.   The library only perform error checks.
   *
 - * - 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.
 + * - Case 2: ELF_F_LAYOUT is not asserted
   *
 - * After a resync_elf() successfully returns, the ELF descriptor is
 - * ready for being handed over to _libelf_write_elf().
 + *     The library will do the object layout using the following
 + *     ordering:
 + *     - The executable header is placed first, are required by the
 + *     	 ELF specification.
 + *     - The program header table is placed immediately following the
 + *       executable header.
 + *     - Section data, if any, is placed after the program header
 + *       table, aligned appropriately.
 + *     - The section header table, if needed, is placed last.
   *
 - * File alignments:
 - * PHDR - Addr
 - * SHDR - Addr
 + *     There are two sub-cases to be taken care of:
   *
 - * XXX: how do we handle 'flags'.
 + *     - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR
 + *
 + *       In this sub-case, the underlying ELF object may already have
 + *       content in it, which the application may have modified.  The
 + *       library will retrieve content from the existing object as
 + *       needed.
 + *
 + *     - Case 2b: e->e_cmd == ELF_C_WRITE
 + *
 + *       The ELF object is being created afresh in this sub-case;
 + *       there is no pre-existing content in the underlying ELF
 + *       object.
   */
  
  /*
   * Compute the extents of a section, by looking at the data
 - * descriptors associated with it.  The function returns zero if an
 - * error was detected.  `*rc' holds the maximum file extent seen so
 - * far.
 + * descriptors associated with it.  The function returns 1 if
 + * successful, or zero if an error was detected.
   */
  static int
 -_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc)
 +_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc)
  {
  	int ec;
 -	Elf_Data *d, *td;
 +	size_t fsz, msz;
 +	Elf_Data *d;
 +	Elf32_Shdr *shdr32;
 +	Elf64_Shdr *shdr64;
  	unsigned int elftype;
  	uint32_t sh_type;
  	uint64_t d_align;
  	uint64_t sh_align, sh_entsize, 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(), or if a new Elf_Data structure was added using
 -	 *   elf_newdata().
 -	 *
 -	 * Each of these conditions would result in the ELF_F_DIRTY bit being
 -	 * set on the section descriptor's `s_flags' field.
 -	 */
 -
  	ec = e->e_class;
  
 +	shdr32 = &s->s_shdr.s_shdr32;
 +	shdr64 = &s->s_shdr.s_shdr64;
  	if (ec == ELFCLASS32) {
 -		sh_type    = s->s_shdr.s_shdr32.sh_type;
 -		sh_align   = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
 -		sh_entsize = (uint64_t) s->s_shdr.s_shdr32.sh_entsize;
 -		sh_offset  = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
 -		sh_size    = (uint64_t) s->s_shdr.s_shdr32.sh_size;
 +		sh_type    = shdr32->sh_type;
 +		sh_align   = (uint64_t) shdr32->sh_addralign;
 +		sh_entsize = (uint64_t) shdr32->sh_entsize;
 +		sh_offset  = (uint64_t) shdr32->sh_offset;
 +		sh_size    = (uint64_t) shdr32->sh_size;
  	} else {
 -		sh_type    = s->s_shdr.s_shdr64.sh_type;
 -		sh_align   = s->s_shdr.s_shdr64.sh_addralign;
 -		sh_entsize = s->s_shdr.s_shdr64.sh_entsize;
 -		sh_offset  = s->s_shdr.s_shdr64.sh_offset;
 -		sh_size    = s->s_shdr.s_shdr64.sh_size;
 +		sh_type    = shdr64->sh_type;
 +		sh_align   = shdr64->sh_addralign;
 +		sh_entsize = shdr64->sh_entsize;
 +		sh_offset  = shdr64->sh_offset;
 +		sh_size    = shdr64->sh_size;
  	}
  
 -	if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
 -		return (1);
 -
 -	if ((s->s_flags & ELF_F_DIRTY) == 0) {
 -		if ((size_t) *rc < sh_offset + sh_size)
 -			*rc = sh_offset + sh_size;
 -		return (1);
 -	}
 +	assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS);
  
  	elftype = _libelf_xlate_shtype(sh_type);
  	if (elftype > ELF_T_LAST) {
 @@ -131,15 +121,52 @@ _libelf_compute_section_extents(Elf *e, 
  		return (0);
  	}
  
 -	/*
 -	 * Compute the extent of the data descriptors associated with
 -	 * this section.
 -	 */
 -	scn_alignment = 0;
  	if (sh_align == 0)
  		sh_align = _libelf_falign(elftype, ec);
  
 -	/* Compute the section alignment. */
 +	/*
 +	 * Check the section's data buffers for sanity and compute the
 +	 * section's alignment.
 +	 * Compute the section's size and alignment using the data
 +	 * descriptors associated with the section.
 +	 */
 +	if (STAILQ_EMPTY(&s->s_data)) {
 +		/*
 +		 * The section's content (if any) has not been read in
 +		 * yet.  If section is not dirty marked dirty, we can
 +		 * reuse the values in the 'sh_size' and 'sh_offset'
 +		 * fields of the section header.
 +		 */
 +		if ((s->s_flags & ELF_F_DIRTY) == 0) {
 +			/*
 +			 * If the library is doing the layout, then we
 +			 * compute the new start offset for the
 +			 * section based on the current offset and the
 +			 * section's alignment needs.
 +			 *
 +			 * If the application is doing the layout, we
 +			 * can use the value in the 'sh_offset' field
 +			 * in the section header directly.
 +			 */
 +			if (e->e_flags & ELF_F_LAYOUT)
 +				goto updatedescriptor;
 +			else
 +				goto computeoffset;
 +		}
 +
 +		/*
 +		 * Otherwise, we need to bring in the section's data
 +		 * from the underlying ELF object.
 +		 */
 +		if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL)
 +			return (0);
 +	}
 +
 +	/*
 +	 * Loop through the section's data descriptors.
 +	 */
 +	scn_size = 0L;
 +	scn_alignment = 0L;
  	STAILQ_FOREACH(d, &s->s_data, d_next)  {
  		if (d->d_type > ELF_T_LAST) {
  			LIBELF_SET_ERROR(DATA, 0);
 @@ -153,23 +180,40 @@ _libelf_compute_section_extents(Elf *e, 
  			LIBELF_SET_ERROR(DATA, 0);
  			return (0);
  		}
 -		if (d_align > scn_alignment)
 -			scn_alignment = d_align;
 -	}
  
 -	scn_size = 0L;
 +		/*
 +		 * The buffer's size should be a multiple of the
 +		 * memory size of the underlying type.
 +		 */
 +		msz = _libelf_msize(d->d_type, ec, e->e_version);
 +		if (d->d_size % msz) {
 +			LIBELF_SET_ERROR(DATA, 0);
 +			return (0);
 +		}
  
 -	STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) {
 +		/*
 +		 * Compute the section's size.
 +		 */
  		if (e->e_flags & ELF_F_LAYOUT) {
  			if ((uint64_t) d->d_off + d->d_size > scn_size)
  				scn_size = d->d_off + d->d_size;
  		} else {
  			scn_size = roundup2(scn_size, d->d_align);
  			d->d_off = scn_size;
 -			scn_size += d->d_size;
 +			fsz = _libelf_fsize(d->d_type, ec, d->d_version,
 +			    d->d_size / msz);
 +			scn_size += fsz;
  		}
 +
 +		/*
 +		 * The section's alignment is the maximum alignment
 +		 * needed for its data buffers.
 +		 */
 +		if (d_align > scn_alignment)
 +			scn_alignment = d_align;
  	}
  
 +
  	/*
  	 * If the application is requesting full control over the layout
  	 * of the section, check its values for sanity.
 @@ -180,46 +224,60 @@ _libelf_compute_section_extents(Elf *e, 
  			LIBELF_SET_ERROR(LAYOUT, 0);
  			return (0);
  		}
 -	} else {
 -		/*
 -		 * Otherwise compute the values in the section header.
 -		 */
 +		goto updatedescriptor;
 +	}
  
 -		if (scn_alignment > sh_align)
 -			sh_align = scn_alignment;
 +	/*
 +	 * Otherwise compute the values in the section header.
 +	 *
 +	 * The section alignment is the maximum alignment for any of
 +	 * its contained data descriptors.
 +	 */
 +	if (scn_alignment > sh_align)
 +		sh_align = scn_alignment;
  
 -		/*
 -		 * If the section entry size is zero, try and fill in an
 -		 * appropriate entry size.  Per the elf(5) manual page
 -		 * sections without fixed-size entries should have their
 -		 * 'sh_entsize' field set to zero.
 -		 */
 -		if (sh_entsize == 0 &&
 -		    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
 -		    (size_t) 1)) == 1)
 -			sh_entsize = 0;
 +	/*
 +	 * If the section entry size is zero, try and fill in an
 +	 * appropriate entry size.  Per the elf(5) manual page
 +	 * sections without fixed-size entries should have their
 +	 * 'sh_entsize' field set to zero.
 +	 */
 +	if (sh_entsize == 0 &&
 +	    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
 +	    (size_t) 1)) == 1)
 +		sh_entsize = 0;
  
 -		sh_size = scn_size;
 -		sh_offset = roundup(*rc, sh_align);
 +	sh_size = scn_size;
  
 -		if (ec == ELFCLASS32) {
 -			s->s_shdr.s_shdr32.sh_addralign = (uint32_t) sh_align;
 -			s->s_shdr.s_shdr32.sh_entsize   = (uint32_t) sh_entsize;
 -			s->s_shdr.s_shdr32.sh_offset    = (uint32_t) sh_offset;
 -			s->s_shdr.s_shdr32.sh_size      = (uint32_t) sh_size;
 -		} else {
 -			s->s_shdr.s_shdr64.sh_addralign = sh_align;
 -			s->s_shdr.s_shdr64.sh_entsize   = sh_entsize;
 -			s->s_shdr.s_shdr64.sh_offset    = sh_offset;
 -			s->s_shdr.s_shdr64.sh_size      = sh_size;
 -		}
 -	}
 +computeoffset:
 +	/*
 +	 * Compute the new offset for the section based on
 +	 * the section's alignment needs.
 +	 */
 +	sh_offset = roundup(rc, sh_align);
  
 -	if ((size_t) *rc < sh_offset + sh_size)
 -		*rc = sh_offset + sh_size;
 +	/*
 +	 * Update the section header.
 +	 */
 +	if (ec == ELFCLASS32) {
 +		shdr32->sh_addralign = (uint32_t) sh_align;
 +		shdr32->sh_entsize   = (uint32_t) sh_entsize;
 +		shdr32->sh_offset    = (uint32_t) sh_offset;
 +		shdr32->sh_size      = (uint32_t) sh_size;
 +	} else {
 +		shdr64->sh_addralign = sh_align;
 +		shdr64->sh_entsize   = sh_entsize;
 +		shdr64->sh_offset    = sh_offset;
 +		shdr64->sh_size      = sh_size;
 +	}
  
 +updatedescriptor:
 +	/*
 +	 * Update the section descriptor.
 +	 */
  	s->s_size = sh_size;
  	s->s_offset = sh_offset;
 +
  	return (1);
  }
  
 @@ -267,13 +325,16 @@ _libelf_insert_section(Elf *e, Elf_Scn *
  	return (1);
  }
  
 +/*
 + * Recompute section layout.
 + */
 +
  static off_t
  _libelf_resync_sections(Elf *e, off_t rc)
  {
  	int ec;
 -	off_t nrc;
 +	Elf_Scn *s;
  	size_t sh_type, shdr_start, shdr_end;
 -	Elf_Scn *s, *ts;
  
  	ec = e->e_class;
  
 @@ -281,13 +342,7 @@ _libelf_resync_sections(Elf *e, off_t rc
  	 * 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) {
 +	STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) {
  		if (ec == ELFCLASS32)
  			sh_type = s->s_shdr.s_shdr32.sh_type;
  		else
 @@ -296,21 +351,22 @@ _libelf_resync_sections(Elf *e, off_t rc
  		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);
 +		if (_libelf_compute_section_extents(e, s, rc) == 0)
 +			return ((off_t) -1);
 +
 +		if (s->s_size == 0)
 +			continue;
 +
 +		if (s->s_offset + s->s_size < (size_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
  			rc = s->s_offset + s->s_size;
  	}
 @@ -338,8 +394,6 @@ _libelf_resync_sections(Elf *e, off_t rc
  		}
  	}
  
 -	assert(nrc == rc);
 -
  	return (rc);
  }
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
