aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2019-06-29 15:27:18 +0000
committerEd Maste <emaste@FreeBSD.org>2019-06-29 15:27:18 +0000
commita5b08c1484eac2c6a65e726f550b3189ff84c6c8 (patch)
tree01cd9d6d76e2c378b391422460c6f233ead08179
parent2b92b30119ed91ed88f102ba9ecc40cd1c046a65 (diff)
downloadsrc-vendor/elftoolchain.tar.gz
src-vendor/elftoolchain.zip
Import ELF Tool Chain snapshot at r3769vendor/elftoolchain/elftoolchain-r3769vendor/elftoolchain
Notes
Notes: svn path=/vendor/elftoolchain/dist/; revision=349544 svn path=/vendor/elftoolchain/elftoolchain-r3769/; revision=349545; tag=vendor/elftoolchain/elftoolchain-r3769
-rw-r--r--.cirrus.yml22
-rw-r--r--README.rst10
-rw-r--r--addr2line/addr2line.c2
-rw-r--r--common/elfdefinitions.h44
-rwxr-xr-xcommon/native-elf-format4
-rw-r--r--documentation/libelf-by-example/libelf-by-example.tex8
-rw-r--r--documentation/libelf-by-example/prog3.txt3
-rw-r--r--documentation/libelf-by-example/prog4.txt4
-rw-r--r--documentation/libelf-by-example/prog6.txt8
-rw-r--r--elfcopy/ascii.c8
-rw-r--r--elfcopy/binary.c7
-rw-r--r--elfcopy/elfcopy.h7
-rw-r--r--elfcopy/main.c9
-rw-r--r--elfcopy/sections.c168
-rw-r--r--elfdump/elfdump.c27
-rw-r--r--libdwarf/dwarf.h20
-rw-r--r--libdwarf/dwarf_dump.c40
-rw-r--r--libdwarf/libdwarf_attr.c7
-rw-r--r--libdwarf/libdwarf_reloc.c10
-rw-r--r--libelf/_libelf.h6
-rw-r--r--libelf/_libelf_config.h8
-rw-r--r--libelf/elf.354
-rw-r--r--libelf/elf_data.c18
-rw-r--r--libelf/elf_end.c6
-rw-r--r--libelf/elf_flagdata.314
-rw-r--r--libelf/elf_getdata.311
-rw-r--r--libelf/elf_getident.c4
-rw-r--r--libelf/elf_next.37
-rw-r--r--libelf/elf_next.c16
-rw-r--r--libelf/elf_open.312
-rw-r--r--libelf/elf_rand.c13
-rw-r--r--libelf/elf_rawfile.c6
-rw-r--r--libelf/elf_scn.c7
-rw-r--r--libelf/elf_update.38
-rw-r--r--libelf/elf_update.c46
-rw-r--r--libelf/gelf.311
-rw-r--r--libelf/gelf_cap.c11
-rw-r--r--libelf/gelf_dyn.c10
-rw-r--r--libelf/gelf_getcap.310
-rw-r--r--libelf/gelf_getdyn.311
-rw-r--r--libelf/gelf_getmove.310
-rw-r--r--libelf/gelf_getrel.310
-rw-r--r--libelf/gelf_getrela.310
-rw-r--r--libelf/gelf_getsym.310
-rw-r--r--libelf/gelf_getsyminfo.310
-rw-r--r--libelf/gelf_getsymshndx.312
-rw-r--r--libelf/gelf_move.c10
-rw-r--r--libelf/gelf_newehdr.38
-rw-r--r--libelf/gelf_newphdr.38
-rw-r--r--libelf/gelf_rel.c12
-rw-r--r--libelf/gelf_rela.c12
-rw-r--r--libelf/gelf_sym.c10
-rw-r--r--libelf/gelf_syminfo.c10
-rw-r--r--libelf/gelf_symshndx.c10
-rw-r--r--libelf/libelf_allocate.c35
-rw-r--r--libelf/libelf_ar.c43
-rw-r--r--libelf/libelf_convert.m413
-rw-r--r--libelf/libelf_data.c10
-rw-r--r--libelf/libelf_ehdr.c16
-rw-r--r--libelf/libelf_extended.c12
-rw-r--r--libelf/libelf_memory.c6
-rw-r--r--libelf/libelf_msize.m415
-rw-r--r--libelf/libelf_phdr.c17
-rw-r--r--libelf/libelf_xlate.c7
-rw-r--r--libelf/os.Linux.mk31
-rw-r--r--libelftc/elftc_bfd_find_target.37
-rw-r--r--libelftc/elftc_reloc_type_str.c2
-rw-r--r--libelftc/elftc_string_table.c45
-rw-r--r--libelftc/elftc_string_table_create.312
-rw-r--r--libelftc/libelftc.h6
-rw-r--r--libelftc/libelftc_bfdtarget.c27
-rwxr-xr-xlibelftc/make-toolchain-version61
-rw-r--r--mk/elftoolchain.subdir.mk4
-rw-r--r--mk/elftoolchain.test.mk9
-rw-r--r--nm/nm.c5
-rw-r--r--readelf/readelf.16
-rw-r--r--readelf/readelf.c143
-rw-r--r--test/ar/tc/add-nonexistent/out/archive.a1
-rw-r--r--test/libelf/tset/Makefile3
-rwxr-xr-xtest/libelf/tset/bin/elfc16
-rw-r--r--test/libelf/tset/common/Makefile3
-rw-r--r--test/libelf/tset/common/ehdr-malformed-1.yaml23
-rw-r--r--test/libelf/tset/common/ehdr_template.m450
-rw-r--r--test/libelf/tset/elf32_getehdr/Makefile4
-rw-r--r--test/libelf/tset/elf32_newehdr/Makefile3
-rw-r--r--test/libelf/tset/elf64_getehdr/Makefile4
-rw-r--r--test/libelf/tset/elf64_newehdr/Makefile3
-rw-r--r--test/libelf/tset/elf_begin/Makefile3
-rw-r--r--test/libelf/tset/elf_begin/begin.m443
-rw-r--r--test/libelf/tset/elf_begin/entry-too-large.ar3
-rw-r--r--test/libelf/tset/elf_getdata/getdata.m4176
-rw-r--r--test/libelf/tset/elf_rand/Makefile18
-rw-r--r--test/libelf/tset/elf_rand/empty-file.ar2
-rw-r--r--test/libelf/tset/elf_rand/missing-file.ar2
-rw-r--r--test/libelf/tset/elf_rand/rand.m4415
-rw-r--r--test/libtest/Makefile5
-rw-r--r--test/libtest/README.rst6
-rwxr-xr-xtest/libtest/bin/make-test-scaffolding29
-rw-r--r--test/libtest/driver/Makefile7
-rw-r--r--test/libtest/driver/driver.c216
-rw-r--r--test/libtest/driver/driver.h206
-rw-r--r--test/libtest/driver/driver_main.c726
-rw-r--r--test/libtest/driver/test_driver.1308
-rw-r--r--test/libtest/examples/minimal_example.c8
-rw-r--r--test/libtest/examples/simple_example.c48
-rw-r--r--test/libtest/lib/Makefile5
-rw-r--r--test/libtest/lib/test.320
-rw-r--r--test/libtest/lib/test.h54
-rw-r--r--test/libtest/lib/test_case.h (renamed from test/libtest/driver/test_main.c)43
-rw-r--r--test/libtest/lib/test_runner.c31
-rw-r--r--test/libtest/lib/test_runner.h118
-rw-r--r--test/nm/ts/Makefile.tset4
-rw-r--r--test/tet/patches/configure.patch10
113 files changed, 3250 insertions, 737 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 000000000000..89834644fea3
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,22 @@
+freebsd_11_task:
+ freebsd_instance:
+ image: freebsd-11-2-release-amd64
+ install_script: pkg install -y git py27-yaml
+ script:
+ - fetch http://tetworks.opengroup.org/downloads/38/software/Sources/3.8/tet3.8-src.tar.gz
+ - tar -x -C test/tet -f tet3.8-src.tar.gz
+ - make
+
+debian_stable_task:
+ container:
+ image: debian:stable
+ setup_script:
+ - apt-get update
+ - apt-get install -y
+ binutils bison bmake curl flex g++ gcc git
+ libarchive-dev libbsd-dev libc6-dev libexpat1-dev lsb-release
+ m4 perl python-yaml sharutils zlib1g-dev
+ script:
+ - curl -O http://tetworks.opengroup.org/downloads/38/software/Sources/3.8/tet3.8-src.tar.gz
+ - tar -x -C test/tet -z -f tet3.8-src.tar.gz
+ - bmake
diff --git a/README.rst b/README.rst
index 75e4bd671540..7610fc627164 100644
--- a/README.rst
+++ b/README.rst
@@ -62,12 +62,12 @@ The project uses subversion_ for its version control system.
The subversion branch for the current set of sources may be accessed
at the following URL::
- https://elftoolchain.svn.sourceforge.net/svnroot/elftoolchain/trunk
+ https://sourceforge.net/p/elftoolchain/code/HEAD/tree/trunk/
The project's source tree may be checked out from its repository by
using the ``svn checkout`` command::
- % svn checkout https://elftoolchain.svn.sourceforge.net/svnroot/elftoolchain/trunk
+ % svn checkout https://svn.code.sf.net/p/elftoolchain/code/trunk
Checked-out sources may be kept upto-date by running ``svn update``
inside the source directory::
@@ -105,10 +105,10 @@ The project's developers may be contacted using the mailing list:
Reporting Bugs
--------------
-Please use our `Trac instance`_ for viewing existing bug reports and
+Please use our `bug tracker`_ for viewing existing bug reports and
for submitting new bug reports.
-.. _`Trac instance`: http://sourceforge.net/apps/trac/elftoolchain/report
+.. _`bug tracker`: https://sourceforge.net/p/elftoolchain/tickets/
Additional Information
@@ -119,7 +119,7 @@ website`_.
.. _project website: http://elftoolchain.sourceforge.net/
-.. $Id: README.rst 3656 2018-12-26 09:46:24Z jkoshy $
+.. $Id: README.rst 3677 2019-02-11 09:37:09Z jkoshy $
.. Local Variables:
.. mode: rst
diff --git a/addr2line/addr2line.c b/addr2line/addr2line.c
index 619214fb0fae..9c3a764fcd0d 100644
--- a/addr2line/addr2line.c
+++ b/addr2line/addr2line.c
@@ -40,7 +40,7 @@
#include "uthash.h"
#include "_elftc.h"
-ELFTC_VCSID("$Id: addr2line.c 3544 2017-06-05 14:51:44Z emaste $");
+ELFTC_VCSID("$Id: addr2line.c 3499 2016-11-25 16:06:29Z emaste $");
struct Func {
char *name;
diff --git a/common/elfdefinitions.h b/common/elfdefinitions.h
index 810da8d4951a..2646833fb6c1 100644
--- a/common/elfdefinitions.h
+++ b/common/elfdefinitions.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: elfdefinitions.h 3515 2017-01-24 22:04:22Z emaste $
+ * $Id: elfdefinitions.h 3769 2019-06-29 15:15:02Z emaste $
*/
/*
@@ -72,7 +72,39 @@ _ELF_DEFINE_DF(DF_TEXTREL, 0x4, \
_ELF_DEFINE_DF(DF_BIND_NOW, 0x8, \
"process relocation entries at load time") \
_ELF_DEFINE_DF(DF_STATIC_TLS, 0x10, \
- "uses static thread-local storage")
+ "uses static thread-local storage") \
+_ELF_DEFINE_DF(DF_1_BIND_NOW, 0x1, \
+ "process relocation entries at load time") \
+_ELF_DEFINE_DF(DF_1_GLOBAL, 0x2, \
+ "unused") \
+_ELF_DEFINE_DF(DF_1_GROUP, 0x4, \
+ "object is a member of a group") \
+_ELF_DEFINE_DF(DF_1_NODELETE, 0x8, \
+ "object cannot be deleted from a process") \
+_ELF_DEFINE_DF(DF_1_LOADFLTR, 0x10, \
+ "immediate load filtees") \
+_ELF_DEFINE_DF(DF_1_INITFIRST, 0x20, \
+ "initialize object first") \
+_ELF_DEFINE_DF(DF_1_NOOPEN, 0x40, \
+ "disallow dlopen()") \
+_ELF_DEFINE_DF(DF_1_ORIGIN, 0x80, \
+ "object being loaded may refer to $ORIGIN") \
+_ELF_DEFINE_DF(DF_1_DIRECT, 0x100, \
+ "direct bindings enabled") \
+_ELF_DEFINE_DF(DF_1_INTERPOSE, 0x400, \
+ "object is interposer") \
+_ELF_DEFINE_DF(DF_1_NODEFLIB, 0x800, \
+ "ignore default library search path") \
+_ELF_DEFINE_DF(DF_1_NODUMP, 0x1000, \
+ "disallow dldump()") \
+_ELF_DEFINE_DF(DF_1_CONFALT, 0x2000, \
+ "object is a configuration alternative") \
+_ELF_DEFINE_DF(DF_1_ENDFILTEE, 0x4000, \
+ "filtee terminates filter search") \
+_ELF_DEFINE_DF(DF_1_DISPRELDNE, 0x8000, \
+ "displacement relocation done") \
+_ELF_DEFINE_DF(DF_1_DISPRELPND, 0x10000, \
+ "displacement relocation pending")
#undef _ELF_DEFINE_DF
#define _ELF_DEFINE_DF(N, V, DESCR) N = V ,
enum {
@@ -2448,7 +2480,10 @@ _ELF_DEFINE_NT(NT_PSTATUS, 10, "Linux process status") \
_ELF_DEFINE_NT(NT_FPREGS, 12, "Linux floating point regset") \
_ELF_DEFINE_NT(NT_PSINFO, 13, "Linux process information") \
_ELF_DEFINE_NT(NT_LWPSTATUS, 16, "Linux lwpstatus_t type") \
-_ELF_DEFINE_NT(NT_LWPSINFO, 17, "Linux lwpinfo_t type")
+_ELF_DEFINE_NT(NT_LWPSINFO, 17, "Linux lwpinfo_t type") \
+_ELF_DEFINE_NT(NT_FREEBSD_NOINIT_TAG, 2, "FreeBSD no .init tag") \
+_ELF_DEFINE_NT(NT_FREEBSD_ARCH_TAG, 3, "FreeBSD arch tag") \
+_ELF_DEFINE_NT(NT_FREEBSD_FEATURE_CTL, 4, "FreeBSD feature control")
#undef _ELF_DEFINE_NT
#define _ELF_DEFINE_NT(N, V, DESCR) N = V ,
@@ -2806,7 +2841,8 @@ typedef struct {
#define ELF64_R_SYM(I) ((I) >> 32)
#define ELF64_R_TYPE(I) ((I) & 0xFFFFFFFFUL)
-#define ELF64_R_INFO(S,T) (((S) << 32) + ((T) & 0xFFFFFFFFUL))
+#define ELF64_R_INFO(S,T) \
+ (((Elf64_Xword) (S) << 32) + ((T) & 0xFFFFFFFFUL))
/*
* Symbol versioning structures.
diff --git a/common/native-elf-format b/common/native-elf-format
index f29bcb16716b..cef29e75111e 100755
--- a/common/native-elf-format
+++ b/common/native-elf-format
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# $Id: native-elf-format 3650 2018-11-25 12:06:28Z jkoshy $
+# $Id: native-elf-format 3735 2019-04-25 19:44:47Z jkoshy $
#
# Find the native ELF format for a host platform by compiling a
# test object and examining the resulting object.
@@ -37,6 +37,8 @@ $1 ~ "Machine:" {
elfarch = "EM_MIPS";
} else if (match($0, ".*[xX]86[-_]64")) {
elfarch = "EM_X86_64";
+ } else if (match($0, "PowerPC64")) {
+ elfarch = "EM_PPC64";
} else {
elfarch = "unknown";
}
diff --git a/documentation/libelf-by-example/libelf-by-example.tex b/documentation/libelf-by-example/libelf-by-example.tex
index 2183465bb52b..2389c6c80393 100644
--- a/documentation/libelf-by-example/libelf-by-example.tex
+++ b/documentation/libelf-by-example/libelf-by-example.tex
@@ -24,7 +24,7 @@
% out of the use of this software, even if advised of the possibility of
% such damage.
%
-% $Id: libelf-by-example.tex 2457 2012-03-09 14:38:10Z jkoshy $
+% $Id: libelf-by-example.tex 3699 2019-02-28 06:34:53Z jkoshy $
%
\documentclass[a4paper,pdftex]{book}
@@ -2700,6 +2700,12 @@ typedef struct {
\emph{parent} archive descriptor (referenced by
variable \parameter{ar} in this example) to return the next
archive member on the next call to function \function{elf\_begin}.
+
+ The \function{elf\_next} function ordinarily returns the value
+ \constant{ELF\_C\_READ}, allowing the traversal of the archive to
+ continue normally. In the event of an error the function
+ returns the value \constant{ELF\_C\_NULL}, which causes the function
+ \function{elf\_begin} to stop archive traversal.
\item[\coref{6}] It is good programming practice to call
\function{elf\_end} on descriptors that are no longer needed.
\end{description}
diff --git a/documentation/libelf-by-example/prog3.txt b/documentation/libelf-by-example/prog3.txt
index 8d1b350bce68..0b49555ec5e1 100644
--- a/documentation/libelf-by-example/prog3.txt
+++ b/documentation/libelf-by-example/prog3.txt
@@ -1,7 +1,7 @@
/*
* Print the ELF Program Header Table in an ELF object.
*
- * $Id: prog3.txt 2133 2011-11-10 08:28:22Z jkoshy $
+ * $Id: prog3.txt 3686 2019-02-22 07:54:47Z jkoshy $
*/
#include <err.h>
@@ -11,7 +11,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
-#include <vis.h>
void
print_ptype(size_t pt) @\co{7}@
diff --git a/documentation/libelf-by-example/prog4.txt b/documentation/libelf-by-example/prog4.txt
index 465f9df595d7..919e4f5dc1aa 100644
--- a/documentation/libelf-by-example/prog4.txt
+++ b/documentation/libelf-by-example/prog4.txt
@@ -1,7 +1,7 @@
/*
* Print the names of ELF sections.
*
- * $Id: prog4.txt 2133 2011-11-10 08:28:22Z jkoshy $
+ * $Id: prog4.txt 3687 2019-02-22 07:55:09Z jkoshy $
*/
#include <err.h>
@@ -18,11 +18,11 @@ main(int argc, char **argv)
{
int fd;
Elf *e;
- char *name, *p, pc[4*sizeof(char)];
Elf_Scn *scn;
Elf_Data *data;
GElf_Shdr shdr;
size_t n, shstrndx, sz;
+ char *name, *p, pc[(4 * sizeof(char)) + 1];
if (argc != 2)
errx(EXIT_FAILURE, "usage: %s file-name", argv[0]);
diff --git a/documentation/libelf-by-example/prog6.txt b/documentation/libelf-by-example/prog6.txt
index d895d3681e78..f2ad3388bc85 100644
--- a/documentation/libelf-by-example/prog6.txt
+++ b/documentation/libelf-by-example/prog6.txt
@@ -1,7 +1,7 @@
/*
* Iterate through an ar(1) archive.
*
- * $Id: prog6.txt 2135 2011-11-10 08:59:47Z jkoshy $
+ * $Id: prog6.txt 3699 2019-02-28 06:34:53Z jkoshy $
*/
#include <err.h>
@@ -16,6 +16,7 @@ main(int argc, char **argv)
{
int fd;
Elf *ar, *e;
+ Elf_Cmd cmd;
Elf_Arhdr *arh;
if (argc != 2)
@@ -39,7 +40,8 @@ main(int argc, char **argv)
errx(EXIT_FAILURE, "%s is not an ar(1) archive.",
argv[1]);
- while ((e = elf_begin(fd, ELF_C_READ, ar)) != NULL) { @\co{3}@
+ cmd = ELF_C_READ;
+ while ((e = elf_begin(fd, cmd, ar)) != NULL) { @\co{3}@
if ((arh = elf_getarhdr(e)) == NULL) @\co{4}@
errx(EXIT_FAILURE, "elf_getarhdr() failed: %s.",
elf_errmsg(-1));
@@ -47,7 +49,7 @@ main(int argc, char **argv)
(void) printf("%20s %zd\n", arh->ar_name,
arh->ar_size);
- (void) elf_next(e); @\co{5}@
+ cmd = elf_next(e); @\co{5}@
(void) elf_end(e); @\co{6}@
}
diff --git a/elfcopy/ascii.c b/elfcopy/ascii.c
index 4ba05c427d9e..caa2ada1dde3 100644
--- a/elfcopy/ascii.c
+++ b/elfcopy/ascii.c
@@ -36,7 +36,7 @@
#include "elfcopy.h"
-ELFTC_VCSID("$Id: ascii.c 3487 2016-08-24 18:12:08Z emaste $");
+ELFTC_VCSID("$Id: ascii.c 3757 2019-06-28 01:15:28Z emaste $");
static void append_data(struct section *s, const void *buf, size_t sz);
static char hex_digit(uint8_t n);
@@ -378,9 +378,6 @@ done:
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
elf_errmsg(-1));
- /* Generate section name string table (.shstrtab). */
- set_shstrtab(ecp);
-
/* Update sh_name pointer for each section header entry. */
update_shdr(ecp, 0);
@@ -605,9 +602,6 @@ done:
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
elf_errmsg(-1));
- /* Generate section name string table (.shstrtab). */
- set_shstrtab(ecp);
-
/* Update sh_name pointer for each section header entry. */
update_shdr(ecp, 0);
diff --git a/elfcopy/binary.c b/elfcopy/binary.c
index d6cce9c99576..687cd4eab495 100644
--- a/elfcopy/binary.c
+++ b/elfcopy/binary.c
@@ -36,7 +36,7 @@
#include "elfcopy.h"
-ELFTC_VCSID("$Id: binary.c 3611 2018-04-16 21:35:18Z jkoshy $");
+ELFTC_VCSID("$Id: binary.c 3757 2019-06-28 01:15:28Z emaste $");
/*
* Convert ELF object to `binary'. Sections with SHF_ALLOC flag set
@@ -250,11 +250,8 @@ create_elf_from_binary(struct elfcopy *ecp, int ifd, const char *ifn)
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
elf_errmsg(-1));
- /* Generate section name string table (.shstrtab). */
- ecp->flags |= SYMTAB_EXIST;
- set_shstrtab(ecp);
-
/* Update sh_name pointer for each section header entry. */
+ ecp->flags |= SYMTAB_EXIST;
update_shdr(ecp, 0);
/* Properly set sh_link field of .symtab section. */
diff --git a/elfcopy/elfcopy.h b/elfcopy/elfcopy.h
index a6578113fe55..3a6fdc76136b 100644
--- a/elfcopy/elfcopy.h
+++ b/elfcopy/elfcopy.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: elfcopy.h 3615 2018-05-17 04:12:24Z kaiwang27 $
+ * $Id: elfcopy.h 3757 2019-06-28 01:15:28Z emaste $
*/
#include <sys/queue.h>
@@ -135,9 +135,13 @@ struct section {
int pseudo;
int nocopy;
+ Elftc_String_Table *strtab;
+
TAILQ_ENTRY(section) sec_list; /* next section */
};
+TAILQ_HEAD(sectionlist, section);
+
/* Internal data structure for segments. */
struct segment {
uint64_t vaddr; /* virtual addr (VMA) */
@@ -311,7 +315,6 @@ struct sec_action *lookup_sec_act(struct elfcopy *_ecp,
struct symop *lookup_symop_list(struct elfcopy *_ecp, const char *_name,
unsigned int _op);
void resync_sections(struct elfcopy *_ecp);
-void set_shstrtab(struct elfcopy *_ecp);
void setup_phdr(struct elfcopy *_ecp);
void update_shdr(struct elfcopy *_ecp, int _update_link);
diff --git a/elfcopy/main.c b/elfcopy/main.c
index b58c01ac7bbd..42430ccea0a9 100644
--- a/elfcopy/main.c
+++ b/elfcopy/main.c
@@ -39,7 +39,7 @@
#include "elfcopy.h"
-ELFTC_VCSID("$Id: main.c 3577 2017-09-14 02:19:42Z emaste $");
+ELFTC_VCSID("$Id: main.c 3757 2019-06-28 01:15:28Z emaste $");
enum options
{
@@ -388,9 +388,6 @@ create_elf(struct elfcopy *ecp)
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
elf_errmsg(-1));
- /* Generate section name string table (.shstrtab). */
- set_shstrtab(ecp);
-
/*
* Second processing of output sections: Update section headers.
* At this stage we set name string index, update st_link and st_info
@@ -486,6 +483,9 @@ free_elf(struct elfcopy *ecp)
/* Free symbol table buffers. */
free_symtab(ecp);
+ /* Free section name string table. */
+ elftc_string_table_destroy(ecp->shstrtab->strtab);
+
/* Free internal section list. */
if (!TAILQ_EMPTY(&ecp->v_sec)) {
TAILQ_FOREACH_SAFE(sec, &ecp->v_sec, sec_list, sec_temp) {
@@ -1565,7 +1565,6 @@ main(int argc, char **argv)
ecp = calloc(1, sizeof(*ecp));
if (ecp == NULL)
err(EXIT_FAILURE, "calloc failed");
- memset(ecp, 0, sizeof(*ecp));
ecp->itf = ecp->otf = ETF_ELF;
ecp->iec = ecp->oec = ELFCLASSNONE;
diff --git a/elfcopy/sections.c b/elfcopy/sections.c
index d9d0edda676a..4d45d82a18e7 100644
--- a/elfcopy/sections.c
+++ b/elfcopy/sections.c
@@ -34,7 +34,7 @@
#include "elfcopy.h"
-ELFTC_VCSID("$Id: sections.c 3646 2018-10-27 02:25:39Z emaste $");
+ELFTC_VCSID("$Id: sections.c 3758 2019-06-28 01:16:50Z emaste $");
static void add_gnu_debuglink(struct elfcopy *ecp);
static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc);
@@ -42,19 +42,18 @@ static void check_section_rename(struct elfcopy *ecp, struct section *s);
static void filter_reloc(struct elfcopy *ecp, struct section *s);
static int get_section_flags(struct elfcopy *ecp, const char *name);
static void insert_sections(struct elfcopy *ecp);
-static void insert_to_strtab(struct section *t, const char *s);
static int is_append_section(struct elfcopy *ecp, const char *name);
static int is_compress_section(struct elfcopy *ecp, const char *name);
static int is_debug_section(const char *name);
static int is_dwo_section(const char *name);
static int is_modify_section(struct elfcopy *ecp, const char *name);
static int is_print_section(struct elfcopy *ecp, const char *name);
-static int lookup_string(struct section *t, const char *s);
static void modify_section(struct elfcopy *ecp, struct section *s);
static void pad_section(struct elfcopy *ecp, struct section *s);
static void print_data(const char *d, size_t sz);
static void print_section(struct section *s);
static void *read_section(struct section *s, size_t *size);
+static void set_shstrtab(struct elfcopy *ecp);
static void update_reloc(struct elfcopy *ecp, struct section *s);
static void update_section_group(struct elfcopy *ecp, struct section *s);
@@ -119,21 +118,19 @@ is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info)
errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
elf_errmsg(-1));
- is = NULL;
- while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
- if (sh_info == elf_ndxscn(is)) {
- if (gelf_getshdr(is, &ish) == NULL)
- errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
- elf_errmsg(-1));
- if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==
- NULL)
- errx(EXIT_FAILURE, "elf_strptr failed: %s",
- elf_errmsg(-1));
- if (is_remove_section(ecp, name))
- return (1);
- else
- return (0);
- }
+ is = elf_getscn(ecp->ein, sh_info);
+ if (is != NULL) {
+ if (gelf_getshdr(is, &ish) == NULL)
+ errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
+ elf_errmsg(-1));
+ if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==
+ NULL)
+ errx(EXIT_FAILURE, "elf_strptr failed: %s",
+ elf_errmsg(-1));
+ if (is_remove_section(ecp, name))
+ return (1);
+ else
+ return (0);
}
elferr = elf_errno();
if (elferr != 0)
@@ -314,18 +311,18 @@ insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail)
{
struct section *s;
- if (!tail) {
+ if (tail || TAILQ_EMPTY(&ecp->v_sec) ||
+ TAILQ_LAST(&ecp->v_sec, sectionlist)->off <= sec->off) {
+ TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);
+ } else {
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
if (sec->off < s->off) {
TAILQ_INSERT_BEFORE(s, sec, sec_list);
- goto inc_nos;
+ break;
}
}
}
- TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);
-
-inc_nos:
if (sec->pseudo == 0)
ecp->nos++;
}
@@ -711,13 +708,13 @@ filter_reloc(struct elfcopy *ecp, struct section *s)
#define COPYREL(REL, SZ) do { \
if (nrels == 0) { \
if ((REL##SZ = malloc(cap * \
- sizeof(Elf##SZ##_Rel))) == NULL) \
+ sizeof(*REL##SZ))) == NULL) \
err(EXIT_FAILURE, "malloc failed"); \
} \
if (nrels >= cap) { \
cap *= 2; \
if ((REL##SZ = realloc(REL##SZ, cap * \
- sizeof(Elf##SZ##_Rel))) == NULL) \
+ sizeof(*REL##SZ))) == NULL) \
err(EXIT_FAILURE, "realloc failed"); \
} \
REL##SZ[nrels].r_offset = REL.r_offset; \
@@ -1335,10 +1332,9 @@ insert_sections(struct elfcopy *ecp)
void
add_to_shstrtab(struct elfcopy *ecp, const char *name)
{
- struct section *s;
- s = ecp->shstrtab;
- insert_to_strtab(s, name);
+ if (elftc_string_table_insert(ecp->shstrtab->strtab, name) == 0)
+ errx(EXIT_FAILURE, "elftc_string_table_insert failed");
}
void
@@ -1348,6 +1344,9 @@ update_shdr(struct elfcopy *ecp, int update_link)
GElf_Shdr osh;
int elferr;
+ /* Finalize the section name string table (.shstrtab). */
+ set_shstrtab(ecp);
+
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
if (s->pseudo)
continue;
@@ -1357,7 +1356,8 @@ update_shdr(struct elfcopy *ecp, int update_link)
elf_errmsg(-1));
/* Find section name in string table and set sh_name. */
- osh.sh_name = lookup_string(ecp->shstrtab, s->name);
+ osh.sh_name = elftc_string_table_lookup(ecp->shstrtab->strtab,
+ s->name);
/*
* sh_link needs to be updated, since the index of the
@@ -1395,7 +1395,23 @@ update_shdr(struct elfcopy *ecp, int update_link)
void
init_shstrtab(struct elfcopy *ecp)
{
+ Elf_Scn *shstrtab;
+ GElf_Shdr shdr;
struct section *s;
+ size_t indx, sizehint;
+
+ if (elf_getshstrndx(ecp->ein, &indx) != 0) {
+ shstrtab = elf_getscn(ecp->ein, indx);
+ if (shstrtab == NULL)
+ errx(EXIT_FAILURE, "elf_getscn failed: %s",
+ elf_errmsg(-1));
+ if (gelf_getshdr(shstrtab, &shdr) != &shdr)
+ errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
+ elf_errmsg(-1));
+ sizehint = shdr.sh_size;
+ } else {
+ sizehint = 0;
+ }
if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL)
err(EXIT_FAILURE, "calloc failed");
@@ -1407,19 +1423,22 @@ init_shstrtab(struct elfcopy *ecp)
s->loadable = 0;
s->type = SHT_STRTAB;
s->vma = 0;
+ s->strtab = elftc_string_table_create(sizehint);
- insert_to_strtab(s, "");
- insert_to_strtab(s, ".symtab");
- insert_to_strtab(s, ".strtab");
- insert_to_strtab(s, ".shstrtab");
+ add_to_shstrtab(ecp, "");
+ add_to_shstrtab(ecp, ".symtab");
+ add_to_shstrtab(ecp, ".strtab");
+ add_to_shstrtab(ecp, ".shstrtab");
}
-void
+static void
set_shstrtab(struct elfcopy *ecp)
{
struct section *s;
Elf_Data *data;
GElf_Shdr sh;
+ const char *image;
+ size_t sz;
s = ecp->shstrtab;
@@ -1452,19 +1471,21 @@ set_shstrtab(struct elfcopy *ecp)
* which are reserved for this in the beginning of shstrtab.
*/
if (!(ecp->flags & SYMTAB_EXIST)) {
- s->sz -= sizeof(".symtab\0.strtab");
- memmove(s->buf, (char *)s->buf + sizeof(".symtab\0.strtab"),
- s->sz);
+ elftc_string_table_remove(s->strtab, ".symtab");
+ elftc_string_table_remove(s->strtab, ".strtab");
}
- sh.sh_size = s->sz;
+ image = elftc_string_table_image(s->strtab, &sz);
+ s->sz = sz;
+
+ sh.sh_size = sz;
if (!gelf_update_shdr(s->os, &sh))
errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
elf_errmsg(-1));
data->d_align = 1;
- data->d_buf = s->buf;
- data->d_size = s->sz;
+ data->d_buf = (void *)(uintptr_t)image;
+ data->d_size = sz;
data->d_off = 0;
data->d_type = ELF_T_BYTE;
data->d_version = EV_CURRENT;
@@ -1590,73 +1611,6 @@ add_gnu_debuglink(struct elfcopy *ecp)
ecp->flags |= SEC_ADD;
}
-static void
-insert_to_strtab(struct section *t, const char *s)
-{
- const char *r;
- char *b, *c;
- size_t len, slen;
- int append;
-
- if (t->sz == 0) {
- t->cap = 512;
- if ((t->buf = malloc(t->cap)) == NULL)
- err(EXIT_FAILURE, "malloc failed");
- }
-
- slen = strlen(s);
- append = 0;
- b = t->buf;
- for (c = b; c < b + t->sz;) {
- len = strlen(c);
- if (!append && len >= slen) {
- r = c + (len - slen);
- if (strcmp(r, s) == 0)
- return;
- } else if (len < slen && len != 0) {
- r = s + (slen - len);
- if (strcmp(c, r) == 0) {
- t->sz -= len + 1;
- memmove(c, c + len + 1, t->sz - (c - b));
- append = 1;
- continue;
- }
- }
- c += len + 1;
- }
-
- while (t->sz + slen + 1 >= t->cap) {
- t->cap *= 2;
- if ((t->buf = realloc(t->buf, t->cap)) == NULL)
- err(EXIT_FAILURE, "realloc failed");
- }
- b = t->buf;
- strncpy(&b[t->sz], s, slen);
- b[t->sz + slen] = '\0';
- t->sz += slen + 1;
-}
-
-static int
-lookup_string(struct section *t, const char *s)
-{
- const char *b, *c, *r;
- size_t len, slen;
-
- slen = strlen(s);
- b = t->buf;
- for (c = b; c < b + t->sz;) {
- len = strlen(c);
- if (len >= slen) {
- r = c + (len - slen);
- if (strcmp(r, s) == 0)
- return (r - b);
- }
- c += len + 1;
- }
-
- return (-1);
-}
-
static uint32_t crctable[256] =
{
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
diff --git a/elfdump/elfdump.c b/elfdump/elfdump.c
index dfde9786c9f4..82d0ca459f3a 100644
--- a/elfdump/elfdump.c
+++ b/elfdump/elfdump.c
@@ -50,7 +50,7 @@
#include "_elftc.h"
-ELFTC_VCSID("$Id: elfdump.c 3584 2017-11-05 20:51:43Z jkoshy $");
+ELFTC_VCSID("$Id: elfdump.c 3762 2019-06-28 21:06:24Z emaste $");
#if defined(ELFTC_NEED_ELF_NOTE_DEFINITION)
#include "native-elf-format.h"
@@ -343,17 +343,20 @@ elf_phdr_type_str(unsigned int type)
static char s_type[32];
switch (type) {
- case PT_NULL: return "PT_NULL";
- case PT_LOAD: return "PT_LOAD";
- case PT_DYNAMIC: return "PT_DYNAMIC";
- case PT_INTERP: return "PT_INTERP";
- case PT_NOTE: return "PT_NOTE";
- case PT_SHLIB: return "PT_SHLIB";
- case PT_PHDR: return "PT_PHDR";
- case PT_TLS: return "PT_TLS";
- case PT_GNU_EH_FRAME: return "PT_GNU_EH_FRAME";
- case PT_GNU_STACK: return "PT_GNU_STACK";
- case PT_GNU_RELRO: return "PT_GNU_RELRO";
+ case PT_NULL: return "PT_NULL";
+ case PT_LOAD: return "PT_LOAD";
+ case PT_DYNAMIC: return "PT_DYNAMIC";
+ case PT_INTERP: return "PT_INTERP";
+ case PT_NOTE: return "PT_NOTE";
+ case PT_SHLIB: return "PT_SHLIB";
+ case PT_PHDR: return "PT_PHDR";
+ case PT_TLS: return "PT_TLS";
+ case PT_GNU_EH_FRAME: return "PT_GNU_EH_FRAME";
+ case PT_GNU_STACK: return "PT_GNU_STACK";
+ case PT_GNU_RELRO: return "PT_GNU_RELRO";
+ case PT_OPENBSD_RANDOMIZE: return "PT_OPENBSD_RANDOMIZE";
+ case PT_OPENBSD_WXNEEDED: return "PT_OPENBSD_WXNEEDED";
+ case PT_OPENBSD_BOOTDATA: return "PT_OPENBSD_BOOTDATA";
}
snprintf(s_type, sizeof(s_type), "<unknown: %#x>", type);
return (s_type);
diff --git a/libdwarf/dwarf.h b/libdwarf/dwarf.h
index 632256886981..8f3733566527 100644
--- a/libdwarf/dwarf.h
+++ b/libdwarf/dwarf.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: dwarf.h 3494 2016-09-20 17:16:13Z emaste $
+ * $Id: dwarf.h 3749 2019-06-28 01:10:44Z emaste $
*/
#ifndef _DWARF_H_
@@ -523,6 +523,24 @@
#define DW_LANG_ObjC_plus_plus 0x0011
#define DW_LANG_UPC 0x0012
#define DW_LANG_D 0x0013
+#define DW_LANG_Python 0x0014
+#define DW_LANG_OpenCL 0x0015
+#define DW_LANG_Go 0x0016
+#define DW_LANG_Modula3 0x0017
+#define DW_LANG_Haskell 0x0018
+#define DW_LANG_C_plus_plus_03 0x0019
+#define DW_LANG_C_plus_plus_11 0x001a
+#define DW_LANG_OCaml 0x001b
+#define DW_LANG_Rust 0x001c
+#define DW_LANG_C11 0x001d
+#define DW_LANG_Swift 0x001e
+#define DW_LANG_Julia 0x001f
+#define DW_LANG_Dylan 0x0020
+#define DW_LANG_C_plus_plus_14 0x0021
+#define DW_LANG_Fortran03 0x0022
+#define DW_LANG_Fortran08 0x0023
+#define DW_LANG_RenderScript 0x0024
+#define DW_LANG_BLISS 0x0025
#define DW_LANG_lo_user 0x8000
#define DW_LANG_Mips_Assembler 0x8001
#define DW_LANG_hi_user 0xffff
diff --git a/libdwarf/dwarf_dump.c b/libdwarf/dwarf_dump.c
index aa7ef1dfc82d..fe61bffc6a17 100644
--- a/libdwarf/dwarf_dump.c
+++ b/libdwarf/dwarf_dump.c
@@ -27,7 +27,7 @@
#include "_libdwarf.h"
-ELFTC_VCSID("$Id: dwarf_dump.c 3494 2016-09-20 17:16:13Z emaste $");
+ELFTC_VCSID("$Id: dwarf_dump.c 3749 2019-06-28 01:10:44Z emaste $");
int
dwarf_get_ACCESS_name(unsigned access, const char **s)
@@ -605,7 +605,7 @@ dwarf_get_DS_name(unsigned ds, const char **s)
case DW_DS_leading_separate:
*s = "DW_DS_leading_separate"; break;
case DW_DS_trailing_separate:
- *s = "DW_DS_trailing_separate";
+ *s = "DW_DS_trailing_separate"; break;
default:
return (DW_DLV_NO_ENTRY);
}
@@ -788,6 +788,42 @@ dwarf_get_LANG_name(unsigned lang, const char **s)
*s = "DW_LANG_UPC"; break;
case DW_LANG_D:
*s = "DW_LANG_D"; break;
+ case DW_LANG_Python:
+ *s = "DW_LANG_Python"; break;
+ case DW_LANG_OpenCL:
+ *s = "DW_LANG_OpenCL"; break;
+ case DW_LANG_Go:
+ *s = "DW_LANG_Go"; break;
+ case DW_LANG_Modula3:
+ *s = "DW_LANG_Modula3"; break;
+ case DW_LANG_Haskell:
+ *s = "DW_LANG_Haskell"; break;
+ case DW_LANG_C_plus_plus_03:
+ *s = "DW_LANG_C_plus_plus_03"; break;
+ case DW_LANG_C_plus_plus_11:
+ *s = "DW_LANG_C_plus_plus_11"; break;
+ case DW_LANG_OCaml:
+ *s = "DW_LANG_OCaml"; break;
+ case DW_LANG_Rust:
+ *s = "DW_LANG_Rust"; break;
+ case DW_LANG_C11:
+ *s = "DW_LANG_C11"; break;
+ case DW_LANG_Swift:
+ *s = "DW_LANG_Swift"; break;
+ case DW_LANG_Julia:
+ *s = "DW_LANG_Julia"; break;
+ case DW_LANG_Dylan:
+ *s = "DW_LANG_Dylan"; break;
+ case DW_LANG_C_plus_plus_14:
+ *s = "DW_LANG_C_plus_plus_14"; break;
+ case DW_LANG_Fortran03:
+ *s = "DW_LANG_Fortran03"; break;
+ case DW_LANG_Fortran08:
+ *s = "DW_LANG_Fortran08"; break;
+ case DW_LANG_RenderScript:
+ *s = "DW_LANG_RenderScript"; break;
+ case DW_LANG_BLISS:
+ *s = "DW_LANG_BLISS"; break;
case DW_LANG_lo_user:
*s = "DW_LANG_lo_user"; break;
case DW_LANG_Mips_Assembler:
diff --git a/libdwarf/libdwarf_attr.c b/libdwarf/libdwarf_attr.c
index dfbbc484c352..a25deedaa5b1 100644
--- a/libdwarf/libdwarf_attr.c
+++ b/libdwarf/libdwarf_attr.c
@@ -27,7 +27,7 @@
#include "_libdwarf.h"
-ELFTC_VCSID("$Id: libdwarf_attr.c 3064 2014-06-06 19:35:55Z kaiwang27 $");
+ELFTC_VCSID("$Id: libdwarf_attr.c 3748 2019-06-28 01:11:13Z emaste $");
int
_dwarf_attr_alloc(Dwarf_Die die, Dwarf_Attribute *atp, Dwarf_Error *error)
@@ -100,7 +100,6 @@ _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp,
uint64_t form, int indirect, Dwarf_Error *error)
{
struct _Dwarf_Attribute atref;
- Dwarf_Section *str;
int ret;
ret = DW_DLE_NONE;
@@ -183,9 +182,7 @@ _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp,
break;
case DW_FORM_strp:
atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
- str = _dwarf_find_section(dbg, ".debug_str");
- assert(str != NULL);
- atref.u[1].s = (char *) str->ds_data + atref.u[0].u64;
+ atref.u[1].s = _dwarf_strtab_get_table(dbg) + atref.u[0].u64;
break;
case DW_FORM_ref_sig8:
atref.u[0].u64 = 8;
diff --git a/libdwarf/libdwarf_reloc.c b/libdwarf/libdwarf_reloc.c
index 2b1ad7214db6..e76675838e41 100644
--- a/libdwarf/libdwarf_reloc.c
+++ b/libdwarf/libdwarf_reloc.c
@@ -26,7 +26,7 @@
#include "_libdwarf.h"
-ELFTC_VCSID("$Id: libdwarf_reloc.c 3578 2017-09-14 02:21:28Z emaste $");
+ELFTC_VCSID("$Id: libdwarf_reloc.c 3741 2019-06-07 06:32:01Z jkoshy $");
Dwarf_Unsigned
_dwarf_get_reloc_type(Dwarf_P_Debug dbg, int is64)
@@ -44,7 +44,7 @@ _dwarf_get_reloc_type(Dwarf_P_Debug dbg, int is64)
case DW_ISA_SPARC:
return (is64 ? R_SPARC_UA64 : R_SPARC_UA32);
case DW_ISA_PPC:
- return (R_PPC_ADDR32);
+ return (is64 ? R_PPC64_ADDR64 : R_PPC_ADDR32);
case DW_ISA_ARM:
return (R_ARM_ABS32);
case DW_ISA_MIPS:
@@ -97,6 +97,12 @@ _dwarf_get_reloc_size(Dwarf_Debug dbg, Dwarf_Unsigned rel_type)
if (rel_type == R_PPC_ADDR32)
return (4);
break;
+ case EM_PPC64:
+ if (rel_type == R_PPC_ADDR32)
+ return (4);
+ else if (rel_type == R_PPC64_ADDR64)
+ return (8);
+ break;
case EM_MIPS:
if (rel_type == R_MIPS_32)
return (4);
diff --git a/libelf/_libelf.h b/libelf/_libelf.h
index 26f17276b170..f826d1c360a5 100644
--- a/libelf/_libelf.h
+++ b/libelf/_libelf.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: _libelf.h 3632 2018-10-10 21:12:43Z jkoshy $
+ * $Id: _libelf.h 3738 2019-05-05 21:49:06Z jkoshy $
*/
#ifndef __LIBELF_H_
@@ -90,7 +90,7 @@ struct _Elf {
Elf_Kind e_kind; /* ELF_K_* */
Elf *e_parent; /* non-NULL for archive members */
unsigned char *e_rawfile; /* uninterpreted bytes */
- size_t e_rawsize; /* size of uninterpreted bytes */
+ off_t e_rawsize; /* size of uninterpreted bytes */
unsigned int e_version; /* file version */
/*
@@ -226,7 +226,7 @@ size_t _libelf_msize(Elf_Type _t, int _elfclass, unsigned int _version);
void *_libelf_newphdr(Elf *_e, int _elfclass, size_t _count);
Elf *_libelf_open_object(int _fd, Elf_Cmd _c, int _reporterror);
struct _Libelf_Data *_libelf_release_data(struct _Libelf_Data *_d);
-Elf *_libelf_release_elf(Elf *_e);
+void _libelf_release_elf(Elf *_e);
Elf_Scn *_libelf_release_scn(Elf_Scn *_s);
int _libelf_setphnum(Elf *_e, void *_eh, int _elfclass, size_t _phnum);
int _libelf_setshnum(Elf *_e, void *_eh, int _elfclass, size_t _shnum);
diff --git a/libelf/_libelf_config.h b/libelf/_libelf_config.h
index d70c04f97098..f28dc8ddf24e 100644
--- a/libelf/_libelf_config.h
+++ b/libelf/_libelf_config.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: _libelf_config.h 3566 2017-08-31 02:28:40Z emaste $
+ * $Id: _libelf_config.h 3764 2019-06-28 21:44:46Z emaste $
*/
#if defined(__APPLE__) || defined(__DragonFly__)
@@ -103,6 +103,12 @@
#define LIBELF_BYTEORDER ELFDATA2LSB
#define LIBELF_CLASS ELFCLASS64
+#elif defined(__riscv64)
+
+#define LIBELF_ARCH EM_RISCV
+#define LIBELF_BYTEORDER ELFDATA2LSB
+#define LIBELF_CLASS ELFCLASS64
+
#elif defined(__sparc__)
#define LIBELF_ARCH EM_SPARCV9
diff --git a/libelf/elf.3 b/libelf/elf.3
index 269725a09ac8..7e1d3cb9a5ed 100644
--- a/libelf/elf.3
+++ b/libelf/elf.3
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2006-2008,2011 Joseph Koshy. All rights reserved.
+.\" Copyright (c) 2006-2008,2011,2019 Joseph Koshy. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: elf.3 3643 2018-10-14 21:09:24Z jkoshy $
+.\" $Id: elf.3 3743 2019-06-12 19:36:30Z jkoshy $
.\"
-.Dd October 10, 2018
+.Dd June 12, 2019
.Dt ELF 3
.Os
.Sh NAME
@@ -266,36 +266,43 @@ The operating version for the data in this buffer.
.El
.Pp
.Vt Elf_Data
-descriptors are usually associated with
+descriptors are usually used in conjunction with
.Vt Elf_Scn
descriptors.
-Existing data descriptors associated with an ELF section may be
-structures are retrieved using the
-.Fn elf_getdata
-and
-.Fn elf_rawdata
-functions.
-The
-.Fn elf_newdata
-function may be used to attach new data descriptors to an ELF section.
.It Vt Elf_Scn
.Vt Elf_Scn
-descriptors represent a section in an ELF object.
+descriptors represent sections in an ELF object.
+These descriptors are opaque and contain no application modifiable
+fields.
.Pp
-They are retrieved using the
+The
+.Vt Elf_Scn
+descriptor for a specific section in an ELF object can be
+retrieved using the
.Fn elf_getscn
function.
-An application may iterate through the existing sections of an ELF
-object using the
+The sections contained in an ELF object can be traversed using the
.Fn elf_nextscn
function.
-New sections may be allocated using the
+New sections are allocated using the
.Fn elf_newscn
function.
.Pp
The
-.Vt Elf_Scn
-descriptor is opaque and contains no application modifiable fields.
+.Vt Elf_Data
+descriptors associated with a given section can be retrieved
+using the
+.Fn elf_getdata
+function.
+New data descriptors can be added to a section
+descriptor using the
+.Fn elf_newdata
+function.
+The untranslated
+.Dq file
+representation of data in a section can be retrieved using the
+.Fn elf_rawdata
+function.
.El
.Ss Supported Elf Types
The following ELF datatypes are supported by the library.
@@ -608,8 +615,11 @@ descriptor itself.
.Xr ar 5 ,
.Xr elf 5
.Sh HISTORY
-The original ELF(3) API was developed for Unix System V.
-The current implementation of the ELF(3) API appeared in
+The original
+.Nm
+API was developed for
+.At V .
+The current implementation of the API appeared in
.Fx 7.0 .
.Sh AUTHORS
The ELF library was written by
diff --git a/libelf/elf_data.c b/libelf/elf_data.c
index bab70d003cee..6c6acb1441b0 100644
--- a/libelf/elf_data.c
+++ b/libelf/elf_data.c
@@ -32,7 +32,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: elf_data.c 3632 2018-10-10 21:12:43Z jkoshy $");
+ELFTC_VCSID("$Id: elf_data.c 3732 2019-04-22 11:08:38Z jkoshy $");
Elf_Data *
elf_getdata(Elf_Scn *s, Elf_Data *ed)
@@ -42,7 +42,7 @@ elf_getdata(Elf_Scn *s, Elf_Data *ed)
int elfclass, elftype;
size_t count, fsz, msz;
struct _Libelf_Data *d;
- uint64_t sh_align, sh_offset, sh_size;
+ uint64_t sh_align, sh_offset, sh_size, raw_size;
_libelf_translator_function *xlate;
d = (struct _Libelf_Data *) ed;
@@ -59,7 +59,8 @@ elf_getdata(Elf_Scn *s, Elf_Data *ed)
return (&d->d_data);
if (d != NULL)
- return (&STAILQ_NEXT(d, d_next)->d_data);
+ return (STAILQ_NEXT(d, d_next) ?
+ &STAILQ_NEXT(d, d_next)->d_data : NULL);
if (e->e_rawfile == NULL) {
/*
@@ -91,9 +92,10 @@ elf_getdata(Elf_Scn *s, Elf_Data *ed)
return (NULL);
}
+ raw_size = (uint64_t) e->e_rawsize;
if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST ||
elftype > ELF_T_LAST || (sh_type != SHT_NOBITS &&
- (sh_offset > e->e_rawsize || sh_size > e->e_rawsize - sh_offset))) {
+ (sh_offset > raw_size || sh_size > raw_size - sh_offset))) {
LIBELF_SET_ERROR(SECTION, 0);
return (NULL);
}
@@ -116,7 +118,8 @@ elf_getdata(Elf_Scn *s, Elf_Data *ed)
count = (size_t) (sh_size / fsz);
- msz = _libelf_msize(elftype, elfclass, e->e_version);
+ if ((msz = _libelf_msize(elftype, elfclass, e->e_version)) == 0)
+ return (NULL);
if (count > 0 && msz > SIZE_MAX / count) {
LIBELF_SET_ERROR(RANGE, 0);
@@ -215,7 +218,7 @@ elf_rawdata(Elf_Scn *s, Elf_Data *ed)
int elf_class;
uint32_t sh_type;
struct _Libelf_Data *d;
- uint64_t sh_align, sh_offset, sh_size;
+ uint64_t sh_align, sh_offset, sh_size, raw_size;
if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) {
LIBELF_SET_ERROR(ARGUMENT, 0);
@@ -253,8 +256,9 @@ elf_rawdata(Elf_Scn *s, Elf_Data *ed)
return (NULL);
}
+ raw_size = (uint64_t) e->e_rawsize;
if (sh_type != SHT_NOBITS &&
- (sh_offset > e->e_rawsize || sh_size > e->e_rawsize - sh_offset)) {
+ (sh_offset > raw_size || sh_size > raw_size - sh_offset)) {
LIBELF_SET_ERROR(SECTION, 0);
return (NULL);
}
diff --git a/libelf/elf_end.c b/libelf/elf_end.c
index 3f32ebbee8ec..ed0c3ef845a9 100644
--- a/libelf/elf_end.c
+++ b/libelf/elf_end.c
@@ -34,7 +34,7 @@
#include <sys/mman.h>
#endif
-ELFTC_VCSID("$Id: elf_end.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: elf_end.c 3738 2019-05-05 21:49:06Z jkoshy $");
int
elf_end(Elf *e)
@@ -81,14 +81,14 @@ elf_end(Elf *e)
free(e->e_rawfile);
#if ELFTC_HAVE_MMAP
else if (e->e_flags & LIBELF_F_RAWFILE_MMAP)
- (void) munmap(e->e_rawfile, e->e_rawsize);
+ (void) munmap(e->e_rawfile, (size_t) e->e_rawsize);
#endif
}
sv = e;
if ((e = e->e_parent) != NULL)
e->e_u.e_ar.e_nchildren--;
- sv = _libelf_release_elf(sv);
+ _libelf_release_elf(sv);
}
return (0);
diff --git a/libelf/elf_flagdata.3 b/libelf/elf_flagdata.3
index c210e4a56971..997da1e570be 100644
--- a/libelf/elf_flagdata.3
+++ b/libelf/elf_flagdata.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: elf_flagdata.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: elf_flagdata.3 3743 2019-06-12 19:36:30Z jkoshy $
.\"
-.Dd December 3, 2011
+.Dd June 12, 2019
.Dt ELF_FLAGDATA 3
.Os
.Sh NAME
@@ -34,7 +34,7 @@
.Nm elf_flagphdr ,
.Nm elf_flagscn ,
.Nm elf_flagshdr
-.Nd manipulate flags associated with ELF(3) data structures
+.Nd manipulate flags associated with ELF data structures
.Sh LIBRARY
.Lb libelf
.Sh SYNOPSIS
@@ -65,7 +65,9 @@ and
.Ar scn
denote the data structures whose flags need to be changed.
These values should have been returned by prior calls to
-functions in the ELF(3) API set:
+functions in the
+.Xr elf 3
+API set:
.Bl -bullet -compact
.It
Argument
@@ -175,7 +177,9 @@ function and the
.Dv ELF_F_ARCHIVE
and
.Dv ELF_F_ARCHIVE_SYSV
-flags are an extension to the ELF(3) API.
+flags are an extension to the
+.Xr elf 3
+API.
.Sh ERRORS
These functions may fail with the following errors:
.Bl -tag -width "[ELF_E_RESOURCE]"
diff --git a/libelf/elf_getdata.3 b/libelf/elf_getdata.3
index b287a25a00bc..66a6ef4fa9dd 100644
--- a/libelf/elf_getdata.3
+++ b/libelf/elf_getdata.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: elf_getdata.3 3643 2018-10-14 21:09:24Z jkoshy $
+.\" $Id: elf_getdata.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd January 26, 2011
+.Dd April 22, 2019
.Dt ELF_GETDATA 3
.Os
.Sh NAME
@@ -214,7 +214,12 @@ is incorrect.
.It Bq Er ELF_E_UNIMPL
The section type associated with section
.Ar scn
-is currently unsupported by the library.
+is not supported.
+.It Bq Er ELF_E_VERSION
+Section
+.Ar scn
+was associated with an ELF object with an unsupported
+version.
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/elf_getident.c b/libelf/elf_getident.c
index a69139c932cf..1196a76329f6 100644
--- a/libelf/elf_getident.c
+++ b/libelf/elf_getident.c
@@ -30,7 +30,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: elf_getident.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: elf_getident.c 3712 2019-03-16 22:23:34Z jkoshy $");
char *
elf_getident(Elf *e, size_t *sz)
@@ -54,7 +54,7 @@ elf_getident(Elf *e, size_t *sz)
else if (e->e_kind == ELF_K_ELF)
*sz = EI_NIDENT;
else
- *sz = e->e_rawsize;
+ *sz = (size_t) e->e_rawsize;
}
return ((char *) e->e_rawfile);
diff --git a/libelf/elf_next.3 b/libelf/elf_next.3
index 0c2d92d67e2d..1ef02a9851b9 100644
--- a/libelf/elf_next.3
+++ b/libelf/elf_next.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: elf_next.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: elf_next.3 3698 2019-02-28 06:34:42Z jkoshy $
.\"
-.Dd June 17, 2006
+.Dd February 27, 2019
.Dt ELF_NEXT 3
.Os
.Sh NAME
@@ -88,6 +88,9 @@ Argument
was not associated with a containing
.Xr ar 1
archive.
+.It Bq Er ELF_E_ARGUMENT
+An error was encountered while parsing the archive containing argument
+.Ar elf .
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/elf_next.c b/libelf/elf_next.c
index 4c33714f291a..dd5a93e4ed1d 100644
--- a/libelf/elf_next.c
+++ b/libelf/elf_next.c
@@ -30,7 +30,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: elf_next.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: elf_next.c 3710 2019-03-12 09:42:35Z jkoshy $");
Elf_Cmd
elf_next(Elf *e)
@@ -60,5 +60,19 @@ elf_next(Elf *e)
parent->e_u.e_ar.e_next = (next >= (off_t) parent->e_rawsize) ?
(off_t) 0 : next;
+ /*
+ * Return an error if the 'e_next' field falls outside the current
+ * file.
+ *
+ * This check is performed after updating the parent descriptor's
+ * 'e_next' field so that the next call to elf_begin(3) will terminate
+ * traversal of a too-small archive even if client code forgets to
+ * check the return value from elf_next(3).
+ */
+ if (next > (off_t) parent->e_rawsize) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (ELF_C_NULL);
+ }
+
return (ELF_C_READ);
}
diff --git a/libelf/elf_open.3 b/libelf/elf_open.3
index acfbe8bc1cfd..054036a24935 100644
--- a/libelf/elf_open.3
+++ b/libelf/elf_open.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: elf_open.3 3643 2018-10-14 21:09:24Z jkoshy $
+.\" $Id: elf_open.3 3743 2019-06-12 19:36:30Z jkoshy $
.\"
-.Dd May 31, 2012
+.Dd June 12, 2019
.Dt ELF_OPEN 3
.Os
.Sh NAME
@@ -43,7 +43,9 @@ The functions
.Fn elf_open
and
.Fn elf_openmemory
-are extensions to the ELF(3) API, for the internal use of the
+are extensions to the
+.Xr elf 3
+API, for the internal use of the
Elftoolchain project.
Portable applications should not use these functions.
.Pp
@@ -71,7 +73,9 @@ specifies the size of the memory area in bytes.
The function returns a pointer to a ELF descriptor if successful, or
NULL if an error occurred.
.Sh COMPATIBILITY
-These functions are non-standard extensions to the ELF(3) API set.
+These functions are non-standard extensions to the
+.Xr elf 3
+API set.
.Pp
The behavior of these functions differs from their counterparts
.Xr elf_begin 3
diff --git a/libelf/elf_rand.c b/libelf/elf_rand.c
index eb2c9eaa2c1a..ac3bd0bc60e0 100644
--- a/libelf/elf_rand.c
+++ b/libelf/elf_rand.c
@@ -29,16 +29,25 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: elf_rand.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: elf_rand.c 3716 2019-03-18 22:01:01Z jkoshy $");
off_t
elf_rand(Elf *ar, off_t offset)
{
struct ar_hdr *arh;
+ off_t offset_of_member;
if (ar == NULL || ar->e_kind != ELF_K_AR ||
(offset & 1) || offset < SARMAG ||
- (size_t) offset + sizeof(struct ar_hdr) >= ar->e_rawsize) {
+ offset >= ar->e_rawsize) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return 0;
+ }
+
+ offset_of_member = offset + (off_t) sizeof(struct ar_hdr);
+
+ if (offset_of_member <= 0 || /* Numeric overflow. */
+ offset_of_member >= ar->e_rawsize) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return 0;
}
diff --git a/libelf/elf_rawfile.c b/libelf/elf_rawfile.c
index f63982fb0b4b..97abf06a2267 100644
--- a/libelf/elf_rawfile.c
+++ b/libelf/elf_rawfile.c
@@ -28,15 +28,13 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: elf_rawfile.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: elf_rawfile.c 3712 2019-03-16 22:23:34Z jkoshy $");
char *
elf_rawfile(Elf *e, size_t *sz)
{
- size_t size;
unsigned char *ptr;
- size = e ? e->e_rawsize : 0;
ptr = NULL;
if (e == NULL)
@@ -45,7 +43,7 @@ elf_rawfile(Elf *e, size_t *sz)
LIBELF_SET_ERROR(SEQUENCE, 0);
if (sz)
- *sz = size;
+ *sz = e ? (size_t) e->e_rawsize : 0;
return ((char *) ptr);
}
diff --git a/libelf/elf_scn.c b/libelf/elf_scn.c
index b72fef66c46b..f702474f35b2 100644
--- a/libelf/elf_scn.c
+++ b/libelf/elf_scn.c
@@ -36,7 +36,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: elf_scn.c 3632 2018-10-10 21:12:43Z jkoshy $");
+ELFTC_VCSID("$Id: elf_scn.c 3712 2019-03-16 22:23:34Z jkoshy $");
/*
* Load an ELF section table and create a list of Elf_Scn structures.
@@ -58,10 +58,11 @@ _libelf_load_section_headers(Elf *e, void *ehdr)
assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0);
#define CHECK_EHDR(E,EH) do { \
- if (shoff > e->e_rawsize || \
+ uintmax_t rawsize = (uintmax_t) e->e_rawsize; \
+ if (shoff > (uintmax_t) e->e_rawsize || \
fsz != (EH)->e_shentsize || \
shnum > SIZE_MAX / fsz || \
- fsz * shnum > e->e_rawsize - shoff) { \
+ fsz * shnum > rawsize - shoff) { \
LIBELF_SET_ERROR(HEADER, 0); \
return (0); \
} \
diff --git a/libelf/elf_update.3 b/libelf/elf_update.3
index b6419cf9bf53..b87ab1640d1f 100644
--- a/libelf/elf_update.3
+++ b/libelf/elf_update.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: elf_update.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: elf_update.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd August 14, 2011
+.Dd April 22, 2019
.Dt ELF_UPDATE 3
.Os
.Sh NAME
@@ -345,6 +345,10 @@ operation was requested after a prior call to
disassociated the ELF descriptor
.Ar elf
from its underlying file.
+.It Bq Er ELF_E_UNIMPL
+Argument
+.Ar elf
+contained a section with an unsupported ELF type.
.It Bq Er ELF_E_VERSION
Argument
.Ar elf
diff --git a/libelf/elf_update.c b/libelf/elf_update.c
index 25fa98d0bb12..d99a7bf937c6 100644
--- a/libelf/elf_update.c
+++ b/libelf/elf_update.c
@@ -41,7 +41,7 @@
#include <sys/mman.h>
#endif
-ELFTC_VCSID("$Id: elf_update.c 3632 2018-10-10 21:12:43Z jkoshy $");
+ELFTC_VCSID("$Id: elf_update.c 3763 2019-06-28 21:43:27Z emaste $");
/*
* Layout strategy:
@@ -142,7 +142,7 @@ _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc)
assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS);
elftype = _libelf_xlate_shtype(sh_type);
- if (elftype > ELF_T_LAST) {
+ if (elftype < ELF_T_FIRST || elftype > ELF_T_LAST) {
LIBELF_SET_ERROR(SECTION, 0);
return (0);
}
@@ -222,10 +222,16 @@ _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc)
}
/*
+ * The data buffer's ELF type, ELF class and ELF version
+ * should be supported.
+ */
+ if ((msz = _libelf_msize(d->d_type, ec, e->e_version)) == 0)
+ return (0);
+
+ /*
* 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);
@@ -800,7 +806,8 @@ _libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
d = &ld->d_data;
- msz = _libelf_msize(d->d_type, ec, e->e_version);
+ if ((msz = _libelf_msize(d->d_type, ec, e->e_version)) == 0)
+ return ((off_t) -1);
if ((uint64_t) rc < sh_off + d->d_off)
(void) memset(nf + rc,
@@ -812,6 +819,7 @@ _libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
assert(d->d_buf != NULL);
assert(d->d_version == e->e_version);
assert(d->d_size % msz == 0);
+ assert(msz != 0);
nobjects = (size_t) (d->d_size / msz);
@@ -851,7 +859,8 @@ _libelf_write_ehdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
assert(ehdr != NULL);
fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
- msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version)) == 0)
+ return ((off_t) -1);
em = _libelf_elfmachine(e);
@@ -885,15 +894,17 @@ _libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
Elf32_Ehdr *eh32;
Elf64_Ehdr *eh64;
Elf_Data dst, src;
- size_t fsz, phnum;
+ size_t fsz, msz, phnum;
uint64_t phoff;
assert(ex->ex_type == ELF_EXTENT_PHDR);
ec = e->e_class;
+
ehdr = _libelf_ehdr(e, ec, 0);
- phnum = e->e_u.e_elf.e_nphdr;
+ assert(ehdr != NULL);
+ phnum = e->e_u.e_elf.e_nphdr;
assert(phnum > 0);
if (ec == ELFCLASS32) {
@@ -913,14 +924,15 @@ _libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
(void) memset(&dst, 0, sizeof(dst));
(void) memset(&src, 0, sizeof(src));
+ if ((msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version)) == 0)
+ return ((off_t) -1);
fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);
assert(fsz > 0);
src.d_buf = _libelf_getphdr(e, ec);
src.d_version = dst.d_version = e->e_version;
src.d_type = ELF_T_PHDR;
- src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec,
- e->e_version);
+ src.d_size = phnum * msz;
dst.d_size = fsz;
dst.d_buf = nf + ex->ex_start;
@@ -945,13 +957,16 @@ _libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
uint64_t shoff;
Elf32_Ehdr *eh32;
Elf64_Ehdr *eh64;
- size_t fsz, nscn;
+ size_t fsz, msz, nscn;
Elf_Data dst, src;
assert(ex->ex_type == ELF_EXTENT_SHDR);
ec = e->e_class;
+
ehdr = _libelf_ehdr(e, ec, 0);
+ assert(ehdr != NULL);
+
nscn = e->e_u.e_elf.e_nscn;
if (ec == ELFCLASS32) {
@@ -971,8 +986,11 @@ _libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
(void) memset(&dst, 0, sizeof(dst));
(void) memset(&src, 0, sizeof(src));
+ if ((msz = _libelf_msize(ELF_T_SHDR, ec, e->e_version)) == 0)
+ return ((off_t) -1);
+
src.d_type = ELF_T_SHDR;
- src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version);
+ src.d_size = msz;
src.d_version = dst.d_version = e->e_version;
fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
@@ -1084,7 +1102,7 @@ _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents)
if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
assert(e->e_rawfile != NULL);
assert(e->e_cmd == ELF_C_RDWR);
- if (munmap(e->e_rawfile, e->e_rawsize) < 0) {
+ if (munmap(e->e_rawfile, (size_t) e->e_rawsize) < 0) {
LIBELF_SET_ERROR(IO, errno);
goto error;
}
@@ -1109,12 +1127,14 @@ _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents)
assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) ||
(e->e_flags & LIBELF_F_RAWFILE_MMAP));
if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) {
+ assert((e->e_flags & LIBELF_F_RAWFILE_MMAP) == 0);
free(e->e_rawfile);
e->e_rawfile = newfile;
newfile = NULL;
}
#if ELFTC_HAVE_MMAP
else if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
+ assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) == 0);
if ((e->e_rawfile = mmap(NULL, (size_t) newsize,
PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) ==
MAP_FAILED) {
@@ -1125,7 +1145,7 @@ _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents)
#endif /* ELFTC_HAVE_MMAP */
/* Record the new size of the file. */
- e->e_rawsize = (size_t) newsize;
+ e->e_rawsize = newsize;
} else {
/* File opened in ELF_C_WRITE mode. */
assert(e->e_rawfile == NULL);
diff --git a/libelf/gelf.3 b/libelf/gelf.3
index 704ae154700f..d703c1b3f65e 100644
--- a/libelf/gelf.3
+++ b/libelf/gelf.3
@@ -21,13 +21,13 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf.3 3643 2018-10-14 21:09:24Z jkoshy $
+.\" $Id: gelf.3 3743 2019-06-12 19:36:30Z jkoshy $
.\"
-.Dd September 1, 2006
+.Dd June 12, 2019
.Dt GELF 3
.Os
.Sh NAME
-.Nm GElf
+.Nm gelf
.Nd class-independent API for ELF manipulation
.Sh LIBRARY
.Lb libelf
@@ -192,7 +192,10 @@ Copy back an ELF symbol table entry.
.Xr elf 3 ,
.Xr elf 5
.Sh HISTORY
-The GELF(3) API first appeared in System V Release 4.
+The
+.Nm
+API first appeared in
+.At V.4 .
This implementation of the API first appeared in
.Fx 7.0 .
.Sh AUTHORS
diff --git a/libelf/gelf_cap.c b/libelf/gelf_cap.c
index f509c69c2ba5..6ebdd97a0c52 100644
--- a/libelf/gelf_cap.c
+++ b/libelf/gelf_cap.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: gelf_cap.c 3177 2015-03-30 18:19:41Z emaste $");
+ELFTC_VCSID("$Id: gelf_cap.c 3732 2019-04-22 11:08:38Z jkoshy $");
GElf_Cap *
gelf_getcap(Elf_Data *ed, int ndx, GElf_Cap *dst)
@@ -67,9 +67,8 @@ gelf_getcap(Elf_Data *ed, int ndx, GElf_Cap *dst)
return (NULL);
}
- msz = _libelf_msize(ELF_T_CAP, ec, e->e_version);
-
- assert(msz > 0);
+ if ((msz = _libelf_msize(ELF_T_CAP, ec, e->e_version)) == 0)
+ return (NULL);
if (msz * (size_t) ndx >= d->d_data.d_size) {
LIBELF_SET_ERROR(ARGUMENT, 0);
@@ -127,8 +126,8 @@ gelf_update_cap(Elf_Data *ed, int ndx, GElf_Cap *gc)
return (0);
}
- msz = _libelf_msize(ELF_T_CAP, ec, e->e_version);
- assert(msz > 0);
+ if ((msz = _libelf_msize(ELF_T_CAP, ec, e->e_version)) == 0)
+ return (0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
LIBELF_SET_ERROR(ARGUMENT, 0);
diff --git a/libelf/gelf_dyn.c b/libelf/gelf_dyn.c
index 74233094bf6c..1c8b133ceada 100644
--- a/libelf/gelf_dyn.c
+++ b/libelf/gelf_dyn.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: gelf_dyn.c 3177 2015-03-30 18:19:41Z emaste $");
+ELFTC_VCSID("$Id: gelf_dyn.c 3732 2019-04-22 11:08:38Z jkoshy $");
GElf_Dyn *
gelf_getdyn(Elf_Data *ed, int ndx, GElf_Dyn *dst)
@@ -67,9 +67,9 @@ gelf_getdyn(Elf_Data *ed, int ndx, GElf_Dyn *dst)
return (NULL);
}
- msz = _libelf_msize(ELF_T_DYN, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_DYN, ec, e->e_version)) == 0)
+ return (NULL);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
@@ -127,9 +127,9 @@ gelf_update_dyn(Elf_Data *ed, int ndx, GElf_Dyn *ds)
return (0);
}
- msz = _libelf_msize(ELF_T_DYN, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_DYN, ec, e->e_version)) == 0)
+ return (0);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
diff --git a/libelf/gelf_getcap.3 b/libelf/gelf_getcap.3
index 276933a8365a..d1c1c2c76c1d 100644
--- a/libelf/gelf_getcap.3
+++ b/libelf/gelf_getcap.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_getcap.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_getcap.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd August 29, 2006
+.Dd April 22, 2019
.Dt GELF_GETCAP 3
.Os
.Sh NAME
@@ -113,6 +113,12 @@ was not associated with a section of type
.Dv SHT_SUNW_cap .
.It Bq Er ELF_E_RANGE
A value was not representable in the target type.
+.It Bq Er ELF_E_VERSION
+The
+.Vt Elf_Data
+descriptor denoted by argument
+.Ar data
+is associated with an ELF object with an unsupported version.
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/gelf_getdyn.3 b/libelf/gelf_getdyn.3
index a4e51ecd0ee2..1db1a5a5e918 100644
--- a/libelf/gelf_getdyn.3
+++ b/libelf/gelf_getdyn.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_getdyn.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_getdyn.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd August 29, 2006
+.Dd April 22, 2019
.Dt GELF_GETDYN 3
.Os
.Sh NAME
@@ -115,6 +115,13 @@ was not associated with a section of type
.Dv SHT_DYNAMIC .
.It Bq Er ELF_E_RANGE
A value was not representable in the target type.
+.It Bq Er ELF_E_VERSION
+The
+.Vt Elf_Data
+descriptor denoted by argument
+.Ar data
+is associated with an ELF object with an unsupported version.
+.El
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/gelf_getmove.3 b/libelf/gelf_getmove.3
index 64c52d9682ed..7f10d2c0d1ca 100644
--- a/libelf/gelf_getmove.3
+++ b/libelf/gelf_getmove.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_getmove.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_getmove.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd August 29, 2006
+.Dd April 22, 2019
.Dt GELF_GETMOVE 3
.Os
.Sh NAME
@@ -112,6 +112,12 @@ Data descriptor
was not associated with a section containing move information.
.It Bq Er ELF_E_RANGE
A value was not representable in the target type.
+.It Bq Er ELF_E_VERSION
+The
+.Vt Elf_Data
+descriptor denoted by argument
+.Ar data
+is associated with an ELF object with an unsupported version.
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/gelf_getrel.3 b/libelf/gelf_getrel.3
index c21be0da8b46..056bf1a67fcc 100644
--- a/libelf/gelf_getrel.3
+++ b/libelf/gelf_getrel.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_getrel.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_getrel.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd August 29, 2006
+.Dd April 22, 2019
.Dt GELF_GETREL 3
.Os
.Sh NAME
@@ -113,6 +113,12 @@ was not associated with a section of type
.Dv SHT_REL .
.It Bq Er ELF_E_RANGE
A value was not representable in the target type.
+.It Bq Er ELF_E_VERSION
+The
+.Vt Elf_Data
+descriptor denoted by argument
+.Ar data
+is associated with an ELF object with an unsupported version.
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/gelf_getrela.3 b/libelf/gelf_getrela.3
index 946482e605ef..0eb0ab31ce10 100644
--- a/libelf/gelf_getrela.3
+++ b/libelf/gelf_getrela.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_getrela.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_getrela.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd August 29, 2006
+.Dd April 22, 2019
.Dt GELF_GETRELA 3
.Os
.Sh NAME
@@ -113,6 +113,12 @@ was not associated with a section of type
.Dv SHT_RELA .
.It Bq Er ELF_E_RANGE
A value was not representable in the target type.
+.It Bq Er ELF_E_VERSION
+The
+.Vt Elf_Data
+descriptor denoted by argument
+.Ar data
+is associated with an ELF object with an unsupported version.
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/gelf_getsym.3 b/libelf/gelf_getsym.3
index a139c152d15d..e2bbc9eb2f49 100644
--- a/libelf/gelf_getsym.3
+++ b/libelf/gelf_getsym.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_getsym.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_getsym.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd August 29, 2006
+.Dd April 22, 2019
.Dt GELF_GETSYM 3
.Os
.Sh NAME
@@ -115,6 +115,12 @@ Data descriptor
was not associated with a section containing symbol information.
.It Bq Er ELF_E_RANGE
A value was not representable in the target type.
+.It Bq Er ELF_E_VERSION
+The
+.Vt Elf_Data
+descriptor denoted by argument
+.Ar data
+is associated with an ELF object with an unsupported version.
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/gelf_getsyminfo.3 b/libelf/gelf_getsyminfo.3
index 0f602c289795..71a69b87cff1 100644
--- a/libelf/gelf_getsyminfo.3
+++ b/libelf/gelf_getsyminfo.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_getsyminfo.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_getsyminfo.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd August 29, 2006
+.Dd April 22, 2019
.Dt GELF_GETSYMINFO 3
.Os
.Sh NAME
@@ -105,6 +105,12 @@ descriptor.
Data descriptor
.Ar data
was not associated with a section containing symbol information.
+.It Bq Er ELF_E_VERSION
+The
+.Vt Elf_Data
+descriptor denoted by argument
+.Ar data
+is associated with an ELF object with an unsupported version.
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/gelf_getsymshndx.3 b/libelf/gelf_getsymshndx.3
index 595472a429e3..66b3efd3d89e 100644
--- a/libelf/gelf_getsymshndx.3
+++ b/libelf/gelf_getsymshndx.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_getsymshndx.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_getsymshndx.3 3734 2019-04-22 14:10:49Z jkoshy $
.\"
-.Dd November 5, 2006
+.Dd April 22, 2019
.Dt GELF_GETSYMSHNDX 3
.Os
.Sh NAME
@@ -152,6 +152,14 @@ Data descriptor
and
.Ar xndxdata
were associated with different ELF objects.
+.It Bq Er ELF_E_VERSION
+The
+.Vt Elf_Data
+descriptors denoted by arguments
+.Ar symdata
+and
+.Ar xndxdata
+are associated with an ELF object with an unsupported version.
.El
.Sh SEE ALSO
.Xr elf 3 ,
diff --git a/libelf/gelf_move.c b/libelf/gelf_move.c
index 2ec8f251f8fa..e5187bf05cf9 100644
--- a/libelf/gelf_move.c
+++ b/libelf/gelf_move.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: gelf_move.c 3177 2015-03-30 18:19:41Z emaste $");
+ELFTC_VCSID("$Id: gelf_move.c 3732 2019-04-22 11:08:38Z jkoshy $");
GElf_Move *
gelf_getmove(Elf_Data *ed, int ndx, GElf_Move *dst)
@@ -67,9 +67,9 @@ gelf_getmove(Elf_Data *ed, int ndx, GElf_Move *dst)
return (NULL);
}
- msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version)) == 0)
+ return (NULL);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
@@ -130,9 +130,9 @@ gelf_update_move(Elf_Data *ed, int ndx, GElf_Move *gm)
return (0);
}
- msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version)) == 0)
+ return (0);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
diff --git a/libelf/gelf_newehdr.3 b/libelf/gelf_newehdr.3
index 38698c32e8b0..5a15ea7d76c6 100644
--- a/libelf/gelf_newehdr.3
+++ b/libelf/gelf_newehdr.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_newehdr.3 3643 2018-10-14 21:09:24Z jkoshy $
+.\" $Id: gelf_newehdr.3 3743 2019-06-12 19:36:30Z jkoshy $
.\"
-.Dd October 22, 2007
+.Dd June 12, 2019
.Dt GELF_NEWEHDR 3
.Os
.Sh NAME
@@ -134,7 +134,9 @@ The
function uses a type of
.Ft "void *"
for its returned value.
-This differs from some other implementations of the ELF(3) API, which use an
+This differs from some other implementations of the
+.Xr elf 3
+API, which use an
.Ft "unsigned long"
return type.
.Sh ERRORS
diff --git a/libelf/gelf_newphdr.3 b/libelf/gelf_newphdr.3
index a881aab4dd6e..01d6cbc38118 100644
--- a/libelf/gelf_newphdr.3
+++ b/libelf/gelf_newphdr.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: gelf_newphdr.3 3639 2018-10-14 14:07:02Z jkoshy $
+.\" $Id: gelf_newphdr.3 3743 2019-06-12 19:36:30Z jkoshy $
.\"
-.Dd October 22, 2007
+.Dd June 12, 2019
.Dt GELF_NEWPHDR 3
.Os
.Sh NAME
@@ -103,7 +103,9 @@ The
function uses a type of
.Ft "void *"
for its returned value.
-This differs from some other implementations of the ELF(3) API, which use an
+This differs from some other implementations of the
+.Xr elf 3
+API, which use an
.Ft "unsigned long"
return type.
.Sh ERRORS
diff --git a/libelf/gelf_rel.c b/libelf/gelf_rel.c
index 02a613383dfb..54a1002c8679 100644
--- a/libelf/gelf_rel.c
+++ b/libelf/gelf_rel.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: gelf_rel.c 3177 2015-03-30 18:19:41Z emaste $");
+ELFTC_VCSID("$Id: gelf_rel.c 3739 2019-05-06 05:18:15Z jkoshy $");
GElf_Rel *
gelf_getrel(Elf_Data *ed, int ndx, GElf_Rel *dst)
@@ -67,9 +67,9 @@ gelf_getrel(Elf_Data *ed, int ndx, GElf_Rel *dst)
return (NULL);
}
- msz = _libelf_msize(ELF_T_REL, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_REL, ec, e->e_version)) == 0)
+ return (NULL);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
@@ -129,9 +129,9 @@ gelf_update_rel(Elf_Data *ed, int ndx, GElf_Rel *dr)
return (0);
}
- msz = _libelf_msize(ELF_T_REL, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_REL, ec, e->e_version)) == 0)
+ return (0);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
@@ -144,7 +144,7 @@ gelf_update_rel(Elf_Data *ed, int ndx, GElf_Rel *dr)
LIBELF_COPY_U32(rel32, dr, r_offset);
- if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) ||
+ if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0U) ||
ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) {
LIBELF_SET_ERROR(RANGE, 0);
return (0);
diff --git a/libelf/gelf_rela.c b/libelf/gelf_rela.c
index d485ab909299..0fa20a515292 100644
--- a/libelf/gelf_rela.c
+++ b/libelf/gelf_rela.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: gelf_rela.c 3177 2015-03-30 18:19:41Z emaste $");
+ELFTC_VCSID("$Id: gelf_rela.c 3739 2019-05-06 05:18:15Z jkoshy $");
GElf_Rela *
gelf_getrela(Elf_Data *ed, int ndx, GElf_Rela *dst)
@@ -67,9 +67,9 @@ gelf_getrela(Elf_Data *ed, int ndx, GElf_Rela *dst)
return (NULL);
}
- msz = _libelf_msize(ELF_T_RELA, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_RELA, ec, e->e_version)) == 0)
+ return (NULL);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
@@ -130,9 +130,9 @@ gelf_update_rela(Elf_Data *ed, int ndx, GElf_Rela *dr)
return (0);
}
- msz = _libelf_msize(ELF_T_RELA, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_RELA, ec, e->e_version)) == 0)
+ return (0);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
@@ -145,7 +145,7 @@ gelf_update_rela(Elf_Data *ed, int ndx, GElf_Rela *dr)
LIBELF_COPY_U32(rela32, dr, r_offset);
- if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) ||
+ if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0U) ||
ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) {
LIBELF_SET_ERROR(RANGE, 0);
return (0);
diff --git a/libelf/gelf_sym.c b/libelf/gelf_sym.c
index ecd85fceefb4..c5f4484d56e6 100644
--- a/libelf/gelf_sym.c
+++ b/libelf/gelf_sym.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: gelf_sym.c 3177 2015-03-30 18:19:41Z emaste $");
+ELFTC_VCSID("$Id: gelf_sym.c 3732 2019-04-22 11:08:38Z jkoshy $");
GElf_Sym *
gelf_getsym(Elf_Data *ed, int ndx, GElf_Sym *dst)
@@ -67,9 +67,9 @@ gelf_getsym(Elf_Data *ed, int ndx, GElf_Sym *dst)
return (NULL);
}
- msz = _libelf_msize(ELF_T_SYM, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_SYM, ec, e->e_version)) == 0)
+ return (NULL);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
@@ -129,9 +129,9 @@ gelf_update_sym(Elf_Data *ed, int ndx, GElf_Sym *gs)
return (0);
}
- msz = _libelf_msize(ELF_T_SYM, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_SYM, ec, e->e_version)) == 0)
+ return (0);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
diff --git a/libelf/gelf_syminfo.c b/libelf/gelf_syminfo.c
index f6d7b6c367fa..9f3cd0e6f701 100644
--- a/libelf/gelf_syminfo.c
+++ b/libelf/gelf_syminfo.c
@@ -29,7 +29,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: gelf_syminfo.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: gelf_syminfo.c 3732 2019-04-22 11:08:38Z jkoshy $");
GElf_Syminfo *
gelf_getsyminfo(Elf_Data *ed, int ndx, GElf_Syminfo *dst)
@@ -65,9 +65,9 @@ gelf_getsyminfo(Elf_Data *ed, int ndx, GElf_Syminfo *dst)
return (NULL);
}
- msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version)) == 0)
+ return (NULL);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
@@ -126,9 +126,9 @@ gelf_update_syminfo(Elf_Data *ed, int ndx, GElf_Syminfo *gs)
return (0);
}
- msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version)) == 0)
+ return (0);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= d->d_data.d_size) {
diff --git a/libelf/gelf_symshndx.c b/libelf/gelf_symshndx.c
index b490aa2bb11f..4a48a43d12b8 100644
--- a/libelf/gelf_symshndx.c
+++ b/libelf/gelf_symshndx.c
@@ -29,7 +29,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: gelf_symshndx.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: gelf_symshndx.c 3732 2019-04-22 11:08:38Z jkoshy $");
GElf_Sym *
gelf_getsymshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *dst,
@@ -69,9 +69,9 @@ gelf_getsymshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *dst,
return (NULL);
}
- msz = _libelf_msize(ELF_T_WORD, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_WORD, ec, e->e_version)) == 0)
+ return (NULL);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= id->d_size) {
@@ -121,9 +121,9 @@ gelf_update_symshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *gs,
return (0);
}
- msz = _libelf_msize(ELF_T_WORD, ec, e->e_version);
+ if ((msz = _libelf_msize(ELF_T_WORD, ec, e->e_version)) == 0)
+ return (0);
- assert(msz > 0);
assert(ndx >= 0);
if (msz * (size_t) ndx >= id->d_size) {
diff --git a/libelf/libelf_allocate.c b/libelf/libelf_allocate.c
index 0a74facc9fc4..2146b05141fd 100644
--- a/libelf/libelf_allocate.c
+++ b/libelf/libelf_allocate.c
@@ -36,33 +36,26 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_allocate.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: libelf_allocate.c 3738 2019-05-05 21:49:06Z jkoshy $");
Elf *
_libelf_allocate_elf(void)
{
Elf *e;
- if ((e = malloc(sizeof(*e))) == NULL) {
+ if ((e = calloc((size_t) 1, sizeof(*e))) == NULL) {
LIBELF_SET_ERROR(RESOURCE, errno);
return NULL;
}
e->e_activations = 1;
- e->e_hdr.e_rawhdr = NULL;
e->e_byteorder = ELFDATANONE;
e->e_class = ELFCLASSNONE;
e->e_cmd = ELF_C_NULL;
e->e_fd = -1;
- e->e_flags = 0;
e->e_kind = ELF_K_NONE;
- e->e_parent = NULL;
- e->e_rawfile = NULL;
- e->e_rawsize = 0;
e->e_version = LIBELF_PRIVATE(version);
- (void) memset(&e->e_u, 0, sizeof(e->e_u));
-
return (e);
}
@@ -83,31 +76,25 @@ _libelf_init_elf(Elf *e, Elf_Kind kind)
}
}
-#define FREE(P) do { \
- if (P) \
- free(P); \
- } while (0)
-
-
-Elf *
+void
_libelf_release_elf(Elf *e)
{
Elf_Arhdr *arh;
switch (e->e_kind) {
case ELF_K_AR:
- FREE(e->e_u.e_ar.e_symtab);
+ free(e->e_u.e_ar.e_symtab);
break;
case ELF_K_ELF:
switch (e->e_class) {
case ELFCLASS32:
- FREE(e->e_u.e_elf.e_ehdr.e_ehdr32);
- FREE(e->e_u.e_elf.e_phdr.e_phdr32);
+ free(e->e_u.e_elf.e_ehdr.e_ehdr32);
+ free(e->e_u.e_elf.e_phdr.e_phdr32);
break;
case ELFCLASS64:
- FREE(e->e_u.e_elf.e_ehdr.e_ehdr64);
- FREE(e->e_u.e_elf.e_phdr.e_phdr64);
+ free(e->e_u.e_elf.e_ehdr.e_ehdr64);
+ free(e->e_u.e_elf.e_phdr.e_phdr64);
break;
}
@@ -115,8 +102,8 @@ _libelf_release_elf(Elf *e)
if (e->e_flags & LIBELF_F_AR_HEADER) {
arh = e->e_hdr.e_arhdr;
- FREE(arh->ar_name);
- FREE(arh->ar_rawname);
+ free(arh->ar_name);
+ free(arh->ar_rawname);
free(arh);
}
@@ -127,8 +114,6 @@ _libelf_release_elf(Elf *e)
}
free(e);
-
- return (NULL);
}
struct _Libelf_Data *
diff --git a/libelf/libelf_ar.c b/libelf/libelf_ar.c
index 8fce7419726e..6634d2c73c33 100644
--- a/libelf/libelf_ar.c
+++ b/libelf/libelf_ar.c
@@ -33,7 +33,7 @@
#include "_libelf.h"
#include "_libelf_ar.h"
-ELFTC_VCSID("$Id: libelf_ar.c 3446 2016-05-03 01:31:17Z emaste $");
+ELFTC_VCSID("$Id: libelf_ar.c 3712 2019-03-16 22:23:34Z jkoshy $");
#define LIBELF_NALLOC_SIZE 16
@@ -123,8 +123,16 @@ _libelf_ar_gethdr(Elf *e)
arh = (struct ar_hdr *) (uintptr_t) e->e_hdr.e_rawhdr;
assert((uintptr_t) arh >= (uintptr_t) parent->e_rawfile + SARMAG);
- assert((uintptr_t) arh <= (uintptr_t) parent->e_rawfile +
- parent->e_rawsize - sizeof(struct ar_hdr));
+
+ /*
+ * There needs to be enough space remaining in the file for the
+ * archive header.
+ */
+ if ((uintptr_t) arh > (uintptr_t) parent->e_rawfile +
+ (uintptr_t) parent->e_rawsize - sizeof(struct ar_hdr)) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
if ((eh = malloc(sizeof(Elf_Arhdr))) == NULL) {
LIBELF_SET_ERROR(RESOURCE, 0);
@@ -199,8 +207,8 @@ Elf *
_libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
{
Elf *e;
- off_t next;
size_t nsz, sz;
+ off_t next, end;
struct ar_hdr *arh;
char *member, *namelen;
@@ -217,6 +225,17 @@ _libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
assert((next & 1) == 0);
+ /*
+ * There needs to be enough space in the file to contain an
+ * ar(1) header.
+ */
+ end = next + (off_t) sizeof(struct ar_hdr);
+ if ((uintmax_t) end < (uintmax_t) next || /* Overflow. */
+ end > (off_t) elf->e_rawsize) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
arh = (struct ar_hdr *) (elf->e_rawfile + next);
/*
@@ -229,6 +248,17 @@ _libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
}
/*
+ * Check if the archive member that follows will fit in the
+ * containing archive.
+ */
+ end += (off_t) sz;
+ if (end < next || /* Overflow. */
+ end > (off_t) elf->e_rawsize) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
+ /*
* Adjust the size field for members in BSD archives using
* extended naming.
*/
@@ -286,7 +316,8 @@ Elf_Arsym *
_libelf_ar_process_bsd_symtab(Elf *e, size_t *count)
{
Elf_Arsym *symtab, *sym;
- unsigned int n, nentries;
+ unsigned int n;
+ size_t nentries;
unsigned char *end, *p, *p0, *s, *s0;
const size_t entrysize = 2 * sizeof(long);
long arraysize, fileoffset, stroffset, strtabsize;
@@ -343,7 +374,7 @@ _libelf_ar_process_bsd_symtab(Elf *e, size_t *count)
GET_LONG(p, fileoffset);
if (stroffset < 0 || fileoffset < 0 ||
- (size_t) fileoffset >= e->e_rawsize)
+ (off_t) fileoffset >= e->e_rawsize)
goto symtaberror;
s = s0 + stroffset;
diff --git a/libelf/libelf_convert.m4 b/libelf/libelf_convert.m4
index 04adeb3114a7..bb601ad92841 100644
--- a/libelf/libelf_convert.m4
+++ b/libelf/libelf_convert.m4
@@ -30,7 +30,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_convert.m4 3632 2018-10-10 21:12:43Z jkoshy $");
+ELFTC_VCSID("$Id: libelf_convert.m4 3712 2019-03-16 22:23:34Z jkoshy $");
/* WARNING: GENERATED FROM __file__. */
@@ -820,7 +820,7 @@ _libelf_cvt_GNUHASH64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
if (dsz < srcsz) /* Destination lacks space. */
return (0);
- nchains = srcsz / sizeof(uint32_t);
+ nchains = (uint32_t) (srcsz / sizeof(uint32_t));
chains = (uint32_t *) (uintptr_t) dst;
for (n = 0; n < nchains; n++) {
@@ -901,7 +901,7 @@ _libelf_cvt_GNUHASH64_tof(unsigned char *dst, size_t dsz, unsigned char *src,
if (dsz < srcsz)
return (0);
- nchains = srcsz / sizeof(uint32_t);
+ nchains = (uint32_t) (srcsz / sizeof(uint32_t));
for (n = 0; n < nchains; n++) {
t32 = *s32++;
if (byteswap)
@@ -1078,13 +1078,8 @@ _libelf_translator_function *
_libelf_get_translator(Elf_Type t, int direction, int elfclass, int elfmachine)
{
assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
- assert(elfmachine >= EM_NONE && elfmachine < EM__LAST__);
assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
-
- if (t >= ELF_T_NUM ||
- (elfclass != ELFCLASS32 && elfclass != ELFCLASS64) ||
- (direction != ELF_TOFILE && direction != ELF_TOMEMORY))
- return (NULL);
+ assert(t >= ELF_T_FIRST && t <= ELF_T_LAST);
/* TODO: Handle MIPS64 REL{,A} sections (ticket #559). */
(void) elfmachine;
diff --git a/libelf/libelf_data.c b/libelf/libelf_data.c
index fcffd8bd9d1c..968394d9bf9a 100644
--- a/libelf/libelf_data.c
+++ b/libelf/libelf_data.c
@@ -28,7 +28,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_data.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: libelf_data.c 3737 2019-05-05 14:49:50Z jkoshy $");
int
_libelf_xlate_shtype(uint32_t sht)
@@ -89,8 +89,14 @@ _libelf_xlate_shtype(uint32_t sht)
* OS, processor and user-defined section types) are
* legal, but since we do not know anything more about
* their semantics, we return a type of ELF_T_BYTE.
+ *
+ * The ELF specification uses 32 bit unsigned values for
+ * denoting section types, and defines SHT_HIUSER to be
+ * 0xFFFFFFFFUL (i.e., UINT32_MAX). Consequently, we only
+ * need to check that 'sht' is greater than or equal to
+ * SHT_LOOS.
*/
- if (sht >= SHT_LOOS && sht <= SHT_HIUSER)
+ if (sht >= SHT_LOOS)
return (ELF_T_BYTE);
/*
diff --git a/libelf/libelf_ehdr.c b/libelf/libelf_ehdr.c
index 38e4e74e14d2..e06c03355038 100644
--- a/libelf/libelf_ehdr.c
+++ b/libelf/libelf_ehdr.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_ehdr.c 3632 2018-10-10 21:12:43Z jkoshy $");
+ELFTC_VCSID("$Id: libelf_ehdr.c 3732 2019-04-22 11:08:38Z jkoshy $");
/*
* Retrieve counts for sections, phdrs and the section string table index
@@ -51,7 +51,12 @@ _libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum,
fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1);
assert(fsz > 0);
- if (e->e_rawsize < shoff + fsz) { /* raw file too small */
+ if (shoff + fsz < shoff) { /* Numeric overflow. */
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (0);
+ }
+
+ if ((uint64_t) e->e_rawsize < shoff + fsz) {
LIBELF_SET_ERROR(HEADER, 0);
return (0);
}
@@ -138,14 +143,13 @@ _libelf_ehdr(Elf *e, int ec, int allocate)
fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
assert(fsz > 0);
- if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) {
+ if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < (off_t) fsz) {
LIBELF_SET_ERROR(HEADER, 0);
return (NULL);
}
- msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT);
-
- assert(msz > 0);
+ if ((msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT)) == 0)
+ return (NULL);
if ((ehdr = calloc((size_t) 1, msz)) == NULL) {
LIBELF_SET_ERROR(RESOURCE, 0);
diff --git a/libelf/libelf_extended.c b/libelf/libelf_extended.c
index 96765a8293e1..59376e430861 100644
--- a/libelf/libelf_extended.c
+++ b/libelf/libelf_extended.c
@@ -29,7 +29,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_extended.c 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: libelf_extended.c 3712 2019-03-16 22:23:34Z jkoshy $");
/*
* Retrieve section #0, allocating a new section if needed.
@@ -57,7 +57,7 @@ _libelf_setshnum(Elf *e, void *eh, int ec, size_t shnum)
assert(scn->s_ndx == SHN_UNDEF);
if (ec == ELFCLASS32)
- scn->s_shdr.s_shdr32.sh_size = shnum;
+ scn->s_shdr.s_shdr32.sh_size = (Elf32_Word) shnum;
else
scn->s_shdr.s_shdr64.sh_size = shnum;
@@ -87,9 +87,9 @@ _libelf_setshstrndx(Elf *e, void *eh, int ec, size_t shstrndx)
assert(scn->s_ndx == SHN_UNDEF);
if (ec == ELFCLASS32)
- scn->s_shdr.s_shdr32.sh_link = shstrndx;
+ scn->s_shdr.s_shdr32.sh_link = (Elf32_Word) shstrndx;
else
- scn->s_shdr.s_shdr64.sh_link = shstrndx;
+ scn->s_shdr.s_shdr64.sh_link = (Elf64_Word) shstrndx;
(void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
@@ -116,9 +116,9 @@ _libelf_setphnum(Elf *e, void *eh, int ec, size_t phnum)
assert(scn->s_ndx == SHN_UNDEF);
if (ec == ELFCLASS32)
- scn->s_shdr.s_shdr32.sh_info = phnum;
+ scn->s_shdr.s_shdr32.sh_info = (Elf32_Word) phnum;
else
- scn->s_shdr.s_shdr64.sh_info = phnum;
+ scn->s_shdr.s_shdr64.sh_info = (Elf64_Word) phnum;
(void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
diff --git a/libelf/libelf_memory.c b/libelf/libelf_memory.c
index cb8e8f20438a..12ab12aed70e 100644
--- a/libelf/libelf_memory.c
+++ b/libelf/libelf_memory.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_memory.c 3013 2014-03-23 06:16:59Z jkoshy $");
+ELFTC_VCSID("$Id: libelf_memory.c 3738 2019-05-05 21:49:06Z jkoshy $");
/*
* Create an ELF descriptor for a memory image, optionally reporting
@@ -54,7 +54,7 @@ _libelf_memory(unsigned char *image, size_t sz, int reporterror)
e->e_cmd = ELF_C_READ;
e->e_rawfile = image;
- e->e_rawsize = sz;
+ e->e_rawsize = (off_t) sz;
#undef LIBELF_IS_ELF
#define LIBELF_IS_ELF(P) ((P)[EI_MAG0] == ELFMAG0 && \
@@ -78,7 +78,7 @@ _libelf_memory(unsigned char *image, size_t sz, int reporterror)
if (error != ELF_E_NONE) {
if (reporterror) {
LIBELF_PRIVATE(error) = LIBELF_ERROR(error, 0);
- (void) _libelf_release_elf(e);
+ _libelf_release_elf(e);
return (NULL);
}
} else {
diff --git a/libelf/libelf_msize.m4 b/libelf/libelf_msize.m4
index 179880c43278..2751f5be8b82 100644
--- a/libelf/libelf_msize.m4
+++ b/libelf/libelf_msize.m4
@@ -30,7 +30,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_msize.m4 3174 2015-03-27 17:13:41Z emaste $");
+ELFTC_VCSID("$Id: libelf_msize.m4 3732 2019-04-22 11:08:38Z jkoshy $");
/* WARNING: GENERATED FROM __file__. */
@@ -87,6 +87,14 @@ static struct msize msize[ELF_T_NUM] = {
MSIZES(ELF_TYPE_LIST)
};
+/*
+ * Returns the memory size of the specified ELF type 't' of ELF
+ * class 'ec' and ELF version 'version'.
+ *
+ * If the specified combination of ELF type, class, and version is
+ * unsupported then a value of 0 will be returned and the appropriate
+ * library error code set.
+ */
size_t
_libelf_msize(Elf_Type t, int elfclass, unsigned int version)
{
@@ -102,5 +110,10 @@ _libelf_msize(Elf_Type t, int elfclass, unsigned int version)
sz = (elfclass == ELFCLASS32) ? msize[t].msz32 : msize[t].msz64;
+ if (sz == 0) {
+ LIBELF_SET_ERROR(UNIMPL, 0);
+ return (0);
+ }
+
return (sz);
}
diff --git a/libelf/libelf_phdr.c b/libelf/libelf_phdr.c
index 336ef3877f6f..5675a2e8c54c 100644
--- a/libelf/libelf_phdr.c
+++ b/libelf/libelf_phdr.c
@@ -31,7 +31,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_phdr.c 3632 2018-10-10 21:12:43Z jkoshy $");
+ELFTC_VCSID("$Id: libelf_phdr.c 3732 2019-04-22 11:08:38Z jkoshy $");
void *
_libelf_getphdr(Elf *e, int ec)
@@ -77,14 +77,18 @@ _libelf_getphdr(Elf *e, int ec)
assert(fsz > 0);
- if ((uint64_t) e->e_rawsize < (phoff + fsz)) {
+ if (phoff + fsz < phoff) { /* Numeric overflow. */
LIBELF_SET_ERROR(HEADER, 0);
return (NULL);
}
- msz = _libelf_msize(ELF_T_PHDR, ec, EV_CURRENT);
+ if ((uint64_t) e->e_rawsize < (phoff + fsz)) {
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (NULL);
+ }
- assert(msz > 0);
+ if ((msz = _libelf_msize(ELF_T_PHDR, ec, EV_CURRENT)) == 0)
+ return (NULL);
if ((phdr = calloc(phnum, msz)) == NULL) {
LIBELF_SET_ERROR(RESOURCE, 0);
@@ -125,9 +129,8 @@ _libelf_newphdr(Elf *e, int ec, size_t count)
assert(ec == ELFCLASS32 || ec == ELFCLASS64);
assert(e->e_version == EV_CURRENT);
- msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version);
-
- assert(msz > 0);
+ if ((msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version)) == 0)
+ return (NULL);
newphdr = NULL;
if (count > 0 && (newphdr = calloc(count, msz)) == NULL) {
diff --git a/libelf/libelf_xlate.c b/libelf/libelf_xlate.c
index cfe6a0bdfdbd..7bb0e0f9d683 100644
--- a/libelf/libelf_xlate.c
+++ b/libelf/libelf_xlate.c
@@ -29,7 +29,7 @@
#include "_libelf.h"
-ELFTC_VCSID("$Id: libelf_xlate.c 3632 2018-10-10 21:12:43Z jkoshy $");
+ELFTC_VCSID("$Id: libelf_xlate.c 3732 2019-04-22 11:08:38Z jkoshy $");
/*
* Translate to/from the file representation of ELF objects.
@@ -83,9 +83,8 @@ _libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding,
(src->d_type, (size_t) 1, src->d_version)) == 0)
return (NULL);
- msz = _libelf_msize(src->d_type, elfclass, src->d_version);
-
- assert(msz > 0);
+ if ((msz = _libelf_msize(src->d_type, elfclass, src->d_version)) == 0)
+ return (NULL);
if (src->d_size % (direction == ELF_TOMEMORY ? fsz : msz)) {
LIBELF_SET_ERROR(DATA, 0);
diff --git a/libelf/os.Linux.mk b/libelf/os.Linux.mk
new file mode 100644
index 000000000000..2292b6ec5f02
--- /dev/null
+++ b/libelf/os.Linux.mk
@@ -0,0 +1,31 @@
+# Enable additional warnings.
+CFLAGS+= -Wa,--fatal-warnings
+CFLAGS+= -Wall
+CFLAGS+= -Wcast-align
+CFLAGS+= -Wcast-qual
+CFLAGS+= -Wchar-subscripts
+CFLAGS+= -Wconversion
+CFLAGS+= -Werror
+CFLAGS+= -Wextra
+CFLAGS+= -Wformat=2
+CFLAGS+= -Winline
+CFLAGS+= -Wmissing-prototypes
+CFLAGS+= -Wnested-externs
+CFLAGS+= -Wempty-body
+CFLAGS+= -Wformat-y2k
+CFLAGS+= -Wformat-zero-length
+CFLAGS+= -Wpointer-sign
+CFLAGS+= -Wpointer-to-int-cast
+CFLAGS+= -Wsign-compare
+CFLAGS+= -Wunused-const-variable
+CFLAGS+= -Wunused-parameter
+CFLAGS+= -Wold-style-definition
+CFLAGS+= -Wpointer-arith
+CFLAGS+= -Wredundant-decls
+CFLAGS+= -Wreturn-type
+CFLAGS+= -Wshadow
+CFLAGS+= -Wstrict-prototypes
+CFLAGS+= -Wstrict-overflow
+CFLAGS+= -Wswitch
+CFLAGS+= -Wunused-parameter
+CFLAGS+= -Wwrite-strings
diff --git a/libelftc/elftc_bfd_find_target.3 b/libelftc/elftc_bfd_find_target.3
index 39d72b05341f..169c4723d94c 100644
--- a/libelftc/elftc_bfd_find_target.3
+++ b/libelftc/elftc_bfd_find_target.3
@@ -21,9 +21,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: elftc_bfd_find_target.3 3645 2018-10-15 20:17:14Z jkoshy $
+.\" $Id: elftc_bfd_find_target.3 3752 2019-06-28 01:12:53Z emaste $
.\"
-.Dd November 30, 2011
+.Dd June 27, 2019
.Dt ELFTC_BFD_FIND_TARGET 3
.Os
.Sh NAME
@@ -76,6 +76,9 @@ Known descriptor names and their properties include:
.It Li elf32-powerpc Ta ELF Ta MSB Ta 32
.It Li elf32-powerpc-freebsd Ta ELF Ta MSB Ta 32
.It Li elf32-powerpcle Ta ELF Ta LSB Ta 32
+.It Li elf32-riscv Ta ELF Ta LSB Ta 32
+.It Li elf64-riscv Ta ELF Ta LSB Ta 64
+.It Li elf64-riscv-freebsd Ta ELF Ta LSB Ta 64
.It Li elf32-sh Ta ELF Ta MSB Ta 32
.It Li elf32-shl Ta ELF Ta LSB Ta 32
.It Li elf32-sh-nbsd Ta ELF Ta MSB Ta 32
diff --git a/libelftc/elftc_reloc_type_str.c b/libelftc/elftc_reloc_type_str.c
index fdad9a6448c6..4fa715ae0734 100644
--- a/libelftc/elftc_reloc_type_str.c
+++ b/libelftc/elftc_reloc_type_str.c
@@ -402,6 +402,8 @@ elftc_reloc_type_str(unsigned int mach, unsigned int type)
case 22: return "R_MIPS_GOT_HI16";
case 23: return "R_MIPS_GOT_LO16";
case 24: return "R_MIPS_SUB";
+ case 28: return "R_MIPS_HIGHER";
+ case 29: return "R_MIPS_HIGHEST";
case 30: return "R_MIPS_CALLHI16";
case 31: return "R_MIPS_CALLLO16";
case 37: return "R_MIPS_JALR";
diff --git a/libelftc/elftc_string_table.c b/libelftc/elftc_string_table.c
index bba9ac6a76cd..f9f50fa91f07 100644
--- a/libelftc/elftc_string_table.c
+++ b/libelftc/elftc_string_table.c
@@ -36,7 +36,7 @@
#include "libelftc.h"
#include "_libelftc.h"
-ELFTC_VCSID("$Id: elftc_string_table.c 2869 2013-01-06 13:29:18Z jkoshy $");
+ELFTC_VCSID("$Id: elftc_string_table.c 3750 2019-06-28 01:12:10Z emaste $");
#define ELFTC_STRING_TABLE_DEFAULT_SIZE (4*1024)
#define ELFTC_STRING_TABLE_EXPECTED_STRING_SIZE 16
@@ -44,7 +44,7 @@ ELFTC_VCSID("$Id: elftc_string_table.c 2869 2013-01-06 13:29:18Z jkoshy $");
#define ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT (4*1024)
struct _Elftc_String_Table_Entry {
- int ste_idx;
+ ssize_t ste_idx;
SLIST_ENTRY(_Elftc_String_Table_Entry) ste_next;
};
@@ -64,9 +64,9 @@ struct _Elftc_String_Table_Entry {
} while (0)
struct _Elftc_String_Table {
- unsigned int st_len; /* length and flags */
+ size_t st_len; /* length and flags */
int st_nbuckets;
- int st_string_pool_size;
+ size_t st_string_pool_size;
char *st_string_pool;
SLIST_HEAD(_Elftc_String_Table_Bucket,
_Elftc_String_Table_Entry) st_buckets[];
@@ -86,7 +86,7 @@ elftc_string_table_find_hash_entry(Elftc_String_Table *st, const char *string,
*rhashindex = hashindex;
SLIST_FOREACH(ste, &st->st_buckets[hashindex], ste_next) {
- s = st->st_string_pool + abs(ste->ste_idx);
+ s = st->st_string_pool + labs(ste->ste_idx);
assert(s > st->st_string_pool &&
s < st->st_string_pool + st->st_string_pool_size);
@@ -102,7 +102,7 @@ static int
elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string)
{
char *newpool;
- int len, newsize, stlen;
+ size_t len, newsize, stlen;
len = strlen(string) + 1; /* length, including the trailing NUL */
stlen = ELFTC_STRING_TABLE_LENGTH(st);
@@ -119,17 +119,17 @@ elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string)
st->st_string_pool_size = newsize;
}
- strcpy(st->st_string_pool + stlen, string);
+ memcpy(st->st_string_pool + stlen, string, len);
ELFTC_STRING_TABLE_UPDATE_LENGTH(st, stlen + len);
return (stlen);
}
Elftc_String_Table *
-elftc_string_table_create(int sizehint)
+elftc_string_table_create(size_t sizehint)
{
- int n, nbuckets, tablesize;
struct _Elftc_String_Table *st;
+ int n, nbuckets, tablesize;
if (sizehint < ELFTC_STRING_TABLE_DEFAULT_SIZE)
sizehint = ELFTC_STRING_TABLE_DEFAULT_SIZE;
@@ -167,21 +167,19 @@ elftc_string_table_destroy(Elftc_String_Table *st)
for (n = 0; n < st->st_nbuckets; n++)
SLIST_FOREACH_SAFE(s, &st->st_buckets[n], ste_next, t)
- free(s);
+ free(s);
free(st->st_string_pool);
free(st);
-
- return;
}
Elftc_String_Table *
-elftc_string_table_from_section(Elf_Scn *scn, int sizehint)
+elftc_string_table_from_section(Elf_Scn *scn, size_t sizehint)
{
- int len;
Elf_Data *d;
GElf_Shdr sh;
const char *s, *end;
Elftc_String_Table *st;
+ size_t len;
/* Verify the type of the section passed in. */
if (gelf_getshdr(scn, &sh) == NULL ||
@@ -237,7 +235,8 @@ elftc_string_table_image(Elftc_String_Table *st, size_t *size)
char *r, *s, *end;
struct _Elftc_String_Table_Entry *ste;
struct _Elftc_String_Table_Bucket *head;
- int copied, hashindex, offset, length, newsize;
+ size_t copied, offset, length, newsize;
+ int hashindex;
/*
* For the common case of a string table has not seen
@@ -305,8 +304,9 @@ elftc_string_table_image(Elftc_String_Table *st, size_t *size)
size_t
elftc_string_table_insert(Elftc_String_Table *st, const char *string)
{
- int hashindex, idx;
struct _Elftc_String_Table_Entry *ste;
+ ssize_t idx;
+ int hashindex;
hashindex = 0;
@@ -318,7 +318,7 @@ elftc_string_table_insert(Elftc_String_Table *st, const char *string)
if ((ste = malloc(sizeof(*ste))) == NULL)
return (0);
if ((ste->ste_idx = elftc_string_table_add_to_pool(st,
- string)) == 0) {
+ string)) == 0) {
free(ste);
return (0);
}
@@ -328,7 +328,7 @@ elftc_string_table_insert(Elftc_String_Table *st, const char *string)
idx = ste->ste_idx;
if (idx < 0) /* Undelete. */
- ste->ste_idx = idx = (- idx);
+ ste->ste_idx = idx = -idx;
return (idx);
}
@@ -336,8 +336,9 @@ elftc_string_table_insert(Elftc_String_Table *st, const char *string)
size_t
elftc_string_table_lookup(Elftc_String_Table *st, const char *string)
{
- int hashindex, idx;
struct _Elftc_String_Table_Entry *ste;
+ ssize_t idx;
+ int hashindex;
ste = elftc_string_table_find_hash_entry(st, string, &hashindex);
@@ -352,17 +353,17 @@ elftc_string_table_lookup(Elftc_String_Table *st, const char *string)
int
elftc_string_table_remove(Elftc_String_Table *st, const char *string)
{
- int idx;
struct _Elftc_String_Table_Entry *ste;
+ ssize_t idx;
ste = elftc_string_table_find_hash_entry(st, string, NULL);
if (ste == NULL || (idx = ste->ste_idx) < 0)
return (ELFTC_FAILURE);
- assert(idx > 0 && idx < (int) ELFTC_STRING_TABLE_LENGTH(st));
+ assert(idx > 0 && (size_t)idx < ELFTC_STRING_TABLE_LENGTH(st));
- ste->ste_idx = (- idx);
+ ste->ste_idx = -idx;
ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st);
diff --git a/libelftc/elftc_string_table_create.3 b/libelftc/elftc_string_table_create.3
index 387ad72a3727..47784639dd09 100644
--- a/libelftc/elftc_string_table_create.3
+++ b/libelftc/elftc_string_table_create.3
@@ -22,9 +22,9 @@
.\" out of the use of this software, even if advised of the possibility of
.\" such damage.
.\"
-.\" $Id: elftc_string_table_create.3 3645 2018-10-15 20:17:14Z jkoshy $
+.\" $Id: elftc_string_table_create.3 3750 2019-06-28 01:12:10Z emaste $
.\"
-.Dd January 5, 2013
+.Dd June 27, 2019
.Dt ELFTC_STRING_TABLE_CREATE 3
.Os
.Sh NAME
@@ -40,11 +40,11 @@
.Sh SYNOPSIS
.In libelftc.h
.Ft "Elftc_String_Table *"
-.Fn elftc_string_table_create "int sizehint"
-.Ft int
+.Fn elftc_string_table_create "size_t sizehint"
+.Ft void
.Fn elftc_string_table_destroy "Elftc_String_Table *table"
.Ft "Elftc_String_Table *"
-.Fn elftc_string_table_from_section "Elf_Scn *scn" "int sizehint"
+.Fn elftc_string_table_from_section "Elf_Scn *scn" "size_t sizehint"
.Ft "const char *"
.Fo elftc_string_table_image
.Fa "Elftc_String_Table *table"
@@ -144,7 +144,7 @@ looks up the string referenced by argument
in the string table specified by argument
.Ar table ,
and if found, returns the offset associated with the string.
-The returned offset will be valid till the next call to function
+The returned offset will be valid until the next call to
.Fn elftc_string_table_image .
.Pp
Function
diff --git a/libelftc/libelftc.h b/libelftc/libelftc.h
index a235097e6910..244c029c9fb2 100644
--- a/libelftc/libelftc.h
+++ b/libelftc/libelftc.h
@@ -24,7 +24,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD: users/kaiwang27/elftc/libelftc.h 392 2009-05-31 19:17:46Z kaiwang27 $
- * $Id: libelftc.h 3489 2016-08-31 00:12:15Z emaste $
+ * $Id: libelftc.h 3744 2019-06-28 00:41:47Z emaste $
*/
#ifndef _LIBELFTC_H_
@@ -77,10 +77,10 @@ int elftc_demangle(const char *_mangledname, char *_buffer,
size_t _bufsize, unsigned int _flags);
const char *elftc_reloc_type_str(unsigned int mach, unsigned int type);
int elftc_set_timestamps(const char *_filename, struct stat *_sb);
-Elftc_String_Table *elftc_string_table_create(int _hint);
+Elftc_String_Table *elftc_string_table_create(size_t _sizehint);
void elftc_string_table_destroy(Elftc_String_Table *_table);
Elftc_String_Table *elftc_string_table_from_section(Elf_Scn *_scn,
- int _hint);
+ size_t _sizehint);
const char *elftc_string_table_image(Elftc_String_Table *_table,
size_t *_sz);
size_t elftc_string_table_insert(Elftc_String_Table *_table,
diff --git a/libelftc/libelftc_bfdtarget.c b/libelftc/libelftc_bfdtarget.c
index 48b67a00c75c..5bbf89ba78fa 100644
--- a/libelftc/libelftc_bfdtarget.c
+++ b/libelftc/libelftc_bfdtarget.c
@@ -30,7 +30,7 @@
#include "_libelftc.h"
-ELFTC_VCSID("$Id: libelftc_bfdtarget.c 3516 2017-02-10 02:33:08Z emaste $");
+ELFTC_VCSID("$Id: libelftc_bfdtarget.c 3752 2019-06-28 01:12:53Z emaste $");
struct _Elftc_Bfd_Target _libelftc_targets[] = {
@@ -316,6 +316,31 @@ struct _Elftc_Bfd_Target _libelftc_targets[] = {
},
{
+ .bt_name = "elf32-riscv",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_RISCV,
+ },
+
+ {
+ .bt_name = "elf64-riscv",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_RISCV,
+ },
+
+ {
+ .bt_name = "elf64-riscv-freebsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_RISCV,
+ .bt_osabi = ELFOSABI_FREEBSD,
+ },
+
+ {
.bt_name = "elf64-sh64",
.bt_type = ETF_ELF,
.bt_byteorder = ELFDATA2MSB,
diff --git a/libelftc/make-toolchain-version b/libelftc/make-toolchain-version
index 0cdf370cc32b..cb0f437d069d 100755
--- a/libelftc/make-toolchain-version
+++ b/libelftc/make-toolchain-version
@@ -3,7 +3,7 @@
# This script generates a project-wide version identifier for use by
# the `elftc_version()' API.
#
-# $Id: make-toolchain-version 3414 2016-02-16 22:55:28Z jkoshy $
+# $Id: make-toolchain-version 3731 2019-04-06 14:28:34Z jkoshy $
#
# Defaults.
@@ -33,6 +33,32 @@ usage()
exit 1
}
+# Determine the revision number for the source tree.
+#
+# - If CVS is detected, we use the string `unknown'.
+# - If SVN is detected, we use the `svninfo' tool to determine the
+# in-tree revision number.
+# - Otherwise, we use `git --describe'.
+get_revision_string()
+{
+ v="unknown:unknown"
+ if [ -d CVS ]; then # Look for CVS (NetBSD).
+ v="cvs:unknown"
+ elif [ -d .svn ]; then # An SVN checkout (SourceForge or FreeBSD).
+ svnversion="$(svnversion 2>/dev/null)"
+ if [ -n "${svnversion}" ]; then
+ v="svn:${svnversion}"
+ fi
+ else # Try git (DragonflyBSD).
+ gitversion="$(git describe --all --dirty --long 2> /dev/null)"
+ if [ -n "${gitversion}" ]; then
+ v="git:${gitversion}"
+ fi
+ fi
+
+ echo "${v}"
+}
+
#
# Parse options.
#
@@ -51,37 +77,14 @@ done
[ -n "${top}" ] || usage
-# Try to determine the in-tree revision number.
-#
-# This script attempts to handle the case where our sources have been
-# incorporated into an operating system's base sources.
-#
-# - If SVN is detected, we use the `svninfo' tool to determine the
-# in-tree revision number.
-# - If CVS is detected, we use the string `unknown'.
-# - Otherwise, we use `git --describe'.
-
curdir=`pwd`
cd ${top} || usage "ERROR: Cannot change directory to \"${top}\"."
-if [ -d CVS ]; then # Look for CVS (NetBSD).
- versionstring=" cvs:unknown"
-else # Try git (DragonFlyBSD).
- gitversion="$(git describe --all --dirty --long 2> /dev/null)"
- if [ -n "${gitversion}" ]; then
- versionstring=" git:${gitversion}"
- else # Assume an SVN checkout (SourceForge or FreeBSD).
- svnversion="$(svnversion)"
- if [ -n "${svnversion}" ]; then
- versionstring=" svn:$(svnversion)"
- fi
- fi
-fi
-
-if [ -z "${versionstring}" ]; then
- echo "ERROR: cannot determine a revision number." 1>&2
+# Determine the in-tree revision number.
+versionstring="$(get_revision_string)" || {
+ echo "ERROR: cannot determine a revision number." 1>&2;
exit 1
-fi
+}
cd ${curdir} || usage "Cannot change back to ${curdir}."
@@ -100,7 +103,7 @@ cat > ${tmpfile} <<EOF
const char *
elftc_version(void)
{
- return "${elftcname} ${version} ${buildhost}${versionstring}";
+ return "${elftcname} ${version} ${buildhost} ${versionstring}";
}
EOF
diff --git a/mk/elftoolchain.subdir.mk b/mk/elftoolchain.subdir.mk
index 9b323bae6c3f..a251506c8fe8 100644
--- a/mk/elftoolchain.subdir.mk
+++ b/mk/elftoolchain.subdir.mk
@@ -1,6 +1,6 @@
#
# Rules for recursing into directories
-# $Id: elftoolchain.subdir.mk 3608 2018-04-14 21:23:04Z jkoshy $
+# $Id: elftoolchain.subdir.mk 3720 2019-03-23 08:40:59Z jkoshy $
# Pass down 'test' as a valid target.
@@ -9,7 +9,7 @@
.if ${OS_HOST} == FreeBSD
SUBDIR_TARGETS+= clobber test
.elif ${OS_HOST} == OpenBSD
-clobber test:: _SUBDIRUSE
+clobber: _SUBDIRUSE
.else # NetBSD, pmake on Linux
TARGETS+= cleandepend clobber test
.endif
diff --git a/mk/elftoolchain.test.mk b/mk/elftoolchain.test.mk
index 8fd933809cbe..77541b3d6a26 100644
--- a/mk/elftoolchain.test.mk
+++ b/mk/elftoolchain.test.mk
@@ -8,9 +8,8 @@
.endif
TEST_BASE= $(TOP)/test/libtest
-TEST_LIB= $(TEST_BASE)/lib
-TEST_DRIVER= ${TEST_BASE}/driver
-TEST_DRIVER_MAIN= $(TEST_DRIVER)/test_main.o
+TEST_LIB= $(TEST_BASE)/lib # The test(3) API.
+TEST_DRIVER= ${TEST_BASE}/driver # A command-line driver for tests.
CFLAGS+= -I$(TEST_LIB) -I${TEST_DRIVER}
@@ -29,7 +28,7 @@ _M4_SRCS= ${TEST_SRCS:M*.m4}
SRCS= ${_C_SRCS} ${_M4_SRCS} # See <bsd.prog.mk>
CLEANFILES+= ${_M4_SRCS:S/.m4$/.c/g} ${TEST_DATA}
-${PROG}: ${TEST_DATA} ${TEST_LIB} ${TEST_DRIVER_MAIN}
+${PROG}: ${TEST_DATA}
.if defined(MAKE_TEST_SCAFFOLDING) && ${MAKE_TEST_SCAFFOLDING} == "yes"
_TC_SRC= ${.OBJDIR}/tc.c # Test scaffolding.
@@ -45,6 +44,6 @@ ${_TC_SRC}: ${_TEST_OBJS}
.endif
.endif
-LDADD+= ${TEST_DRIVER_MAIN} -L${TEST_LIB} -ltest
+LDADD+= -L${TEST_LIB} -ltest -L${TEST_DRIVER} -ldriver
.include "${TOP}/mk/elftoolchain.prog.mk"
diff --git a/nm/nm.c b/nm/nm.c
index 493f3a80b408..c5c80455144c 100644
--- a/nm/nm.c
+++ b/nm/nm.c
@@ -48,7 +48,7 @@
#include "_elftc.h"
-ELFTC_VCSID("$Id: nm.c 3504 2016-12-17 15:33:16Z kaiwang27 $");
+ELFTC_VCSID("$Id: nm.c 3722 2019-03-23 17:01:58Z jkoshy $");
/* symbol information list */
STAILQ_HEAD(sym_head, sym_entry);
@@ -1143,7 +1143,6 @@ read_elf(Elf *elf, const char *filename, Elf_Kind kind)
Elf_Arhdr *arhdr;
Elf_Scn *scn;
GElf_Shdr shdr;
- GElf_Half i;
Dwarf_Line *lbuf;
Dwarf_Unsigned lineno;
Dwarf_Signed lcount, filecount;
@@ -1158,7 +1157,7 @@ read_elf(Elf *elf, const char *filename, Elf_Kind kind)
struct var_info_entry *var;
const char *shname, *objname;
char *type_table, **sec_table, *sfile, **src_files;
- size_t shstrndx, shnum, dynndx, strndx;
+ size_t i, shstrndx, shnum, dynndx, strndx;
int ret, rtn, e_err;
#define OBJNAME (objname == NULL ? filename : objname)
diff --git a/readelf/readelf.1 b/readelf/readelf.1
index 9df20621c278..1f0b7bc918b0 100644
--- a/readelf/readelf.1
+++ b/readelf/readelf.1
@@ -22,9 +22,9 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $Id: readelf.1 3642 2018-10-14 14:24:28Z jkoshy $
+.\" $Id: readelf.1 3753 2019-06-28 01:13:13Z emaste $
.\"
-.Dd September 13, 2012
+.Dd June 27, 2019
.Dt READELF 1
.Os
.Sh NAME
@@ -113,6 +113,8 @@ Print symbol tables.
.It Fl t | Fl -section-details
Print additional information about sections, such as the flags
fields in section headers.
+Implies
+.Fl S .
.It Fl v | Fl -version
Prints a version identifier for
.Nm
diff --git a/readelf/readelf.c b/readelf/readelf.c
index b2534792e2e0..ee0f67117361 100644
--- a/readelf/readelf.c
+++ b/readelf/readelf.c
@@ -47,7 +47,7 @@
#include "_elftc.h"
-ELFTC_VCSID("$Id: readelf.c 3649 2018-11-24 03:26:23Z emaste $");
+ELFTC_VCSID("$Id: readelf.c 3769 2019-06-29 15:15:02Z emaste $");
/*
* readelf(1) options.
@@ -206,6 +206,11 @@ struct eflags_desc {
const char *desc;
};
+struct flag_desc {
+ uint64_t flag;
+ const char *desc;
+};
+
struct mips_option {
uint64_t flag;
const char *desc;
@@ -284,6 +289,7 @@ static void dump_dwarf_ranges_foreach(struct readelf *re, Dwarf_Die die,
static void dump_dwarf_str(struct readelf *re);
static void dump_eflags(struct readelf *re, uint64_t e_flags);
static void dump_elf(struct readelf *re);
+static void dump_flags(struct flag_desc *fd, uint64_t flags);
static void dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab);
static void dump_dynamic(struct readelf *re);
static void dump_liblist(struct readelf *re);
@@ -298,6 +304,8 @@ static void dump_mips_specific_info(struct readelf *re);
static void dump_notes(struct readelf *re);
static void dump_notes_content(struct readelf *re, const char *buf, size_t sz,
off_t off);
+static void dump_notes_data(const char *name, uint32_t type, const char *buf,
+ size_t sz);
static void dump_svr4_hash(struct section *s);
static void dump_svr4_hash64(struct readelf *re, struct section *s);
static void dump_gnu_hash(struct readelf *re, struct section *s);
@@ -1184,6 +1192,7 @@ note_type_gnu(unsigned int nt)
case 2: return "NT_GNU_HWCAP (Hardware capabilities)";
case 3: return "NT_GNU_BUILD_ID (Build id set by ld(1))";
case 4: return "NT_GNU_GOLD_VERSION (GNU gold version)";
+ case 5: return "NT_GNU_PROPERTY_TYPE_0";
default: return (note_type_unknown(nt));
}
}
@@ -2261,8 +2270,15 @@ dump_eflags(struct readelf *re, uint64_t e_flags)
}
edesc = mips_eflags_desc;
break;
- case EM_PPC:
case EM_PPC64:
+ switch (e_flags) {
+ case 0: printf(", Unspecified or Power ELF V1 ABI"); break;
+ case 1: printf(", Power ELF V1 ABI"); break;
+ case 2: printf(", OpenPOWER ELF V2 ABI"); break;
+ default: break;
+ }
+ /* FALLTHROUGH */
+ case EM_PPC:
edesc = powerpc_eflags_desc;
break;
case EM_SPARC:
@@ -2714,6 +2730,59 @@ dump_arch_dyn_val(struct readelf *re, GElf_Dyn *dyn)
}
static void
+dump_flags(struct flag_desc *desc, uint64_t val)
+{
+ struct flag_desc *fd;
+
+ for (fd = desc; fd->flag != 0; fd++) {
+ if (val & fd->flag) {
+ val &= ~fd->flag;
+ printf(" %s", fd->desc);
+ }
+ }
+ if (val != 0)
+ printf(" unknown (0x%jx)", (uintmax_t)val);
+ printf("\n");
+}
+
+static struct flag_desc dt_flags[] = {
+ { DF_ORIGIN, "ORIGIN" },
+ { DF_SYMBOLIC, "SYMBOLIC" },
+ { DF_TEXTREL, "TEXTREL" },
+ { DF_BIND_NOW, "BIND_NOW" },
+ { DF_STATIC_TLS, "STATIC_TLS" },
+ { 0, NULL }
+};
+
+static struct flag_desc dt_flags_1[] = {
+ { DF_1_BIND_NOW, "NOW" },
+ { DF_1_GLOBAL, "GLOBAL" },
+ { 0x4, "GROUP" },
+ { DF_1_NODELETE, "NODELETE" },
+ { DF_1_LOADFLTR, "LOADFLTR" },
+ { 0x20, "INITFIRST" },
+ { DF_1_NOOPEN, "NOOPEN" },
+ { DF_1_ORIGIN, "ORIGIN" },
+ { 0x100, "DIRECT" },
+ { DF_1_INTERPOSE, "INTERPOSE" },
+ { DF_1_NODEFLIB, "NODEFLIB" },
+ { 0x1000, "NODUMP" },
+ { 0x2000, "CONFALT" },
+ { 0x4000, "ENDFILTEE" },
+ { 0x8000, "DISPRELDNE" },
+ { 0x10000, "DISPRELPND" },
+ { 0x20000, "NODIRECT" },
+ { 0x40000, "IGNMULDEF" },
+ { 0x80000, "NOKSYMS" },
+ { 0x100000, "NOHDR" },
+ { 0x200000, "EDITED" },
+ { 0x400000, "NORELOC" },
+ { 0x800000, "SYMINTPOSE" },
+ { 0x1000000, "GLOBAUDIT" },
+ { 0, NULL }
+};
+
+static void
dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)
{
const char *name;
@@ -2760,6 +2829,7 @@ dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)
case DT_SYMENT:
case DT_RELSZ:
case DT_RELENT:
+ case DT_PREINIT_ARRAYSZ:
case DT_INIT_ARRAYSZ:
case DT_FINI_ARRAYSZ:
case DT_GNU_CONFLICTSZ:
@@ -2796,6 +2866,12 @@ dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)
case DT_GNU_PRELINKED:
printf(" %s\n", timestamp(dyn->d_un.d_val));
break;
+ case DT_FLAGS:
+ dump_flags(dt_flags, dyn->d_un.d_val);
+ break;
+ case DT_FLAGS_1:
+ dump_flags(dt_flags_1, dyn->d_un.d_val);
+ break;
default:
printf("\n");
}
@@ -3414,6 +3490,52 @@ dump_notes(struct readelf *re)
}
}
+static struct flag_desc note_feature_ctl_flags[] = {
+ { 0x1, "ASLR_DISABLE" },
+ { 0, NULL }
+};
+
+static void
+dump_notes_data(const char *name, uint32_t type, const char *buf, size_t sz)
+{
+ size_t i;
+ const uint32_t *ubuf;
+
+ /* Note data is at least 4-byte aligned. */
+ if (((uintptr_t)buf & 3) != 0) {
+ warnx("bad note data alignment");
+ goto unknown;
+ }
+ ubuf = (const uint32_t *)(const void *)buf;
+
+ if (strcmp(name, "FreeBSD") == 0) {
+ switch (type) {
+ case NT_FREEBSD_ABI_TAG:
+ if (sz != 4)
+ goto unknown;
+ printf(" ABI tag: %u\n", ubuf[0]);
+ return;
+ /* NT_FREEBSD_NOINIT_TAG carries no data, treat as unknown. */
+ case NT_FREEBSD_ARCH_TAG:
+ if (sz != 4)
+ goto unknown;
+ printf(" Arch tag: %x\n", ubuf[0]);
+ return;
+ case NT_FREEBSD_FEATURE_CTL:
+ if (sz != 4)
+ goto unknown;
+ printf(" Features:");
+ dump_flags(note_feature_ctl_flags, ubuf[0]);
+ return;
+ }
+ }
+unknown:
+ printf(" description data:");
+ for (i = 0; i < sz; i++)
+ printf(" %02x", (unsigned char)buf[i]);
+ printf("\n");
+}
+
static void
dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off)
{
@@ -3430,7 +3552,9 @@ dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off)
return;
}
note = (Elf_Note *)(uintptr_t) buf;
- name = (char *)(uintptr_t)(note + 1);
+ buf += sizeof(Elf_Note);
+ name = buf;
+ buf += roundup2(note->n_namesz, 4);
/*
* The name field is required to be nul-terminated, and
* n_namesz includes the terminating nul in observed
@@ -3448,8 +3572,8 @@ dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off)
printf(" %-13s %#010jx", name, (uintmax_t) note->n_descsz);
printf(" %s\n", note_type(name, re->ehdr.e_type,
note->n_type));
- buf += sizeof(Elf_Note) + roundup2(note->n_namesz, 4) +
- roundup2(note->n_descsz, 4);
+ dump_notes_data(name, note->n_type, buf, note->n_descsz);
+ buf += roundup2(note->n_descsz, 4);
}
}
@@ -6906,13 +7030,13 @@ dump_object(struct readelf *re)
if ((re->elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
warnx("elf_begin() failed: %s", elf_errmsg(-1));
- return;
+ goto done;
}
switch (elf_kind(re->elf)) {
case ELF_K_NONE:
warnx("Not an ELF file.");
- return;
+ goto done;
case ELF_K_ELF:
dump_elf(re);
break;
@@ -6921,10 +7045,11 @@ dump_object(struct readelf *re)
break;
default:
warnx("Internal: libelf returned unknown elf kind.");
- return;
}
+done:
elf_end(re->elf);
+ close(fd);
}
static void
@@ -7345,7 +7470,7 @@ main(int argc, char **argv)
re->options |= RE_S;
break;
case 't':
- re->options |= RE_T;
+ re->options |= RE_SS | RE_T;
break;
case 'u':
re->options |= RE_U;
diff --git a/test/ar/tc/add-nonexistent/out/archive.a b/test/ar/tc/add-nonexistent/out/archive.a
new file mode 100644
index 000000000000..8b277f0dd5dc
--- /dev/null
+++ b/test/ar/tc/add-nonexistent/out/archive.a
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/libelf/tset/Makefile b/test/libelf/tset/Makefile
index 63e958691306..5a5e96f6ebd1 100644
--- a/test/libelf/tset/Makefile
+++ b/test/libelf/tset/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $
+# $Id: Makefile 3715 2019-03-18 09:15:40Z jkoshy $
#
TOP= ../../..
@@ -36,6 +36,7 @@ SUBDIR+= elf_ndxscn
SUBDIR+= elf_next
SUBDIR+= elf_newscn
SUBDIR+= elf_nextscn
+SUBDIR+= elf_rand
SUBDIR+= elf_rawfile
SUBDIR+= elf_strptr
SUBDIR+= elf_update
diff --git a/test/libelf/tset/bin/elfc b/test/libelf/tset/bin/elfc
index 98995e820e26..4c77e4220b18 100755
--- a/test/libelf/tset/bin/elfc
+++ b/test/libelf/tset/bin/elfc
@@ -74,7 +74,7 @@
# sections, a section index may be manually specified using a
# 'sh_index' pseudo field.
#
-# $Id: elfc 3614 2018-04-21 19:48:04Z jkoshy $
+# $Id: elfc 3689 2019-02-23 22:50:51Z jkoshy $
version = "%prog 1.0"
usage = "usage: %prog [options] [input-file]"
@@ -442,6 +442,14 @@ def check_dict(d, l, node=None):
raise ElfError(node, "{%s} Unknown key(s) %s" % \
(node.tag, unknown))
+def bounded_value(v, encoding):
+ """Return the value of 'v' bounded to the maximum size for a type."""
+ if encoding == "H":
+ return (v & 0xFFFF)
+ elif encoding == "I":
+ return (v & 0xFFFFFFFF)
+ return v
+
#
# Helper classes.
#
@@ -559,8 +567,10 @@ class ElfType:
else:
n = 3
for t in self.fields:
- if t[n] != "":
- a.append(getattr(self, t[0]))
+ field_encoding = t[n]
+ if field_encoding != "":
+ v = getattr(self, t[0])
+ a.append(bounded_value(v, field_encoding))
return tuple(a)
def getfields(self, elfclass):
diff --git a/test/libelf/tset/common/Makefile b/test/libelf/tset/common/Makefile
index 5dd5bf9c1a5b..8f8400a39753 100644
--- a/test/libelf/tset/common/Makefile
+++ b/test/libelf/tset/common/Makefile
@@ -1,10 +1,11 @@
-# $Id: Makefile 1719 2011-08-12 08:24:14Z jkoshy $
+# $Id: Makefile 3690 2019-02-23 22:51:13Z jkoshy $
TOP= ../../../..
YAML_FILES= check_elf \
getclass \
ehdr \
+ ehdr-malformed-1 \
fsize \
newehdr newscn newscn2 \
phdr \
diff --git a/test/libelf/tset/common/ehdr-malformed-1.yaml b/test/libelf/tset/common/ehdr-malformed-1.yaml
new file mode 100644
index 000000000000..d7c000f47aed
--- /dev/null
+++ b/test/libelf/tset/common/ehdr-malformed-1.yaml
@@ -0,0 +1,23 @@
+%YAML 1.1
+# $Id$
+---
+ehdr: !Ehdr
+ e_ident: !Ident # e_ident[] members
+ ei_class: ELFCLASSNONE
+ ei_data: ELFDATANONE
+ ei_osabi: ELFOSABI_SYSV
+ ei_abiversion: 0
+ # other members
+ e_type: 0xFF03
+ e_machine: 0x42
+ e_version: 0xFFFFFFFF
+ e_entry: 0xFFFFFFFFFFFFFFFF
+ e_phoff: 0xFFFFFFFFFFFFFFFF
+ e_shoff: 0xFFFFFFFFFFFFFFFF
+ e_flags: [ 64, 8, 2, 1]
+ e_ehsize: 62
+ e_phentsize: 228
+ e_phnum: 0
+ e_shentsize: 8192
+ e_shnum: 0
+ e_shstrndx: 0
diff --git a/test/libelf/tset/common/ehdr_template.m4 b/test/libelf/tset/common/ehdr_template.m4
index 872e0ff3b7c8..31cacd4de541 100644
--- a/test/libelf/tset/common/ehdr_template.m4
+++ b/test/libelf/tset/common/ehdr_template.m4
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ehdr_template.m4 3174 2015-03-27 17:13:41Z emaste $
+ * $Id: ehdr_template.m4 3703 2019-03-02 20:41:03Z jkoshy $
*/
include(`elfts.m4')
@@ -367,3 +367,51 @@ tcElfWrongSize$1(void)
FN(`LSB')
FN(`MSB')
+
+/*
+ * Verify that malformed ELF objects are rejected.
+ */
+
+undefine(`FN')
+define(`FN',`
+void
+tcMalformed1$1(void)
+{
+ int error, fd, result;
+ Elf *e;
+ char *fn;
+ TS_EHDR *eh;
+
+ TP_CHECK_INITIALIZATION();
+
+ TP_ANNOUNCE("TS_ICNAME with a malformed ELF header "
+ "fails with ELF_E_HEADER.");
+
+ e = NULL;
+ fd = -1;
+ fn = "ehdr-malformed-1.TOLOWER($1)`'TS_EHDRSZ";
+ result = TET_UNRESOLVED;
+
+ _TS_OPEN_FILE(e, fn, ELF_C_READ, fd, goto done;);
+
+ error = 0;
+ if ((eh = TS_ICFUNC`'(e)) != NULL) {
+ TP_FAIL("\"%s\" TS_ICNAME`'() succeeded.", fn);
+ goto done;
+ } else if ((error = elf_errno()) != ELF_E_HEADER) {
+ TP_FAIL("\"%s\" incorrect error (%d).", fn, error);
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (e)
+ (void) elf_end(e);
+ if (fd != -1)
+ (void) close(fd);
+ tet_result(result);
+}')
+
+FN(`LSB')
+FN(`MSB')
diff --git a/test/libelf/tset/elf32_getehdr/Makefile b/test/libelf/tset/elf32_getehdr/Makefile
index 8285b1f8ed6e..1b01505e750c 100644
--- a/test/libelf/tset/elf32_getehdr/Makefile
+++ b/test/libelf/tset/elf32_getehdr/Makefile
@@ -1,8 +1,8 @@
-# $Id: Makefile 1368 2011-01-22 09:09:15Z jkoshy $
+# $Id: Makefile 3691 2019-02-23 23:34:04Z jkoshy $
TOP= ../../../..
TS_SRCS= ehdr.m4
-TS_YAML= ehdr
+TS_YAML= ehdr ehdr-malformed-1
.include "${TOP}/mk/elftoolchain.tet.mk"
diff --git a/test/libelf/tset/elf32_newehdr/Makefile b/test/libelf/tset/elf32_newehdr/Makefile
index 78c4f1238af3..7c109199cf4f 100644
--- a/test/libelf/tset/elf32_newehdr/Makefile
+++ b/test/libelf/tset/elf32_newehdr/Makefile
@@ -1,9 +1,10 @@
-# $Id: Makefile 1358 2011-01-08 05:40:41Z jkoshy $
+# $Id: Makefile 3702 2019-03-02 20:40:55Z jkoshy $
TOP= ../../../..
TS_SRCS= ehdr.m4
TS_DATA= ehdr.msb32 ehdr.lsb32 ehdr.msb64 ehdr.lsb64 \
+ ehdr-malformed-1.lsb32 ehdr-malformed-1.msb32 \
newehdr.lsb32 newehdr.msb32
.include "${TOP}/mk/elftoolchain.tet.mk"
diff --git a/test/libelf/tset/elf64_getehdr/Makefile b/test/libelf/tset/elf64_getehdr/Makefile
index e8bb49ad4d25..1b01505e750c 100644
--- a/test/libelf/tset/elf64_getehdr/Makefile
+++ b/test/libelf/tset/elf64_getehdr/Makefile
@@ -1,8 +1,8 @@
-# $Id: Makefile 1358 2011-01-08 05:40:41Z jkoshy $
+# $Id: Makefile 3691 2019-02-23 23:34:04Z jkoshy $
TOP= ../../../..
TS_SRCS= ehdr.m4
-TS_YAML= ehdr
+TS_YAML= ehdr ehdr-malformed-1
.include "${TOP}/mk/elftoolchain.tet.mk"
diff --git a/test/libelf/tset/elf64_newehdr/Makefile b/test/libelf/tset/elf64_newehdr/Makefile
index 88ccf4d1791b..1e56f4113374 100644
--- a/test/libelf/tset/elf64_newehdr/Makefile
+++ b/test/libelf/tset/elf64_newehdr/Makefile
@@ -1,9 +1,10 @@
-# $Id: Makefile 1358 2011-01-08 05:40:41Z jkoshy $
+# $Id: Makefile 3702 2019-03-02 20:40:55Z jkoshy $
TOP= ../../../..
TS_SRCS= ehdr.m4
TS_DATA= ehdr.msb64 ehdr.lsb64 ehdr.msb32 ehdr.lsb32 \
+ ehdr-malformed-1.lsb64 ehdr-malformed-1.msb64 \
newehdr.lsb64 newehdr.msb64
.include "${TOP}/mk/elftoolchain.tet.mk"
diff --git a/test/libelf/tset/elf_begin/Makefile b/test/libelf/tset/elf_begin/Makefile
index d5c675cd0449..bdc1575f80c6 100644
--- a/test/libelf/tset/elf_begin/Makefile
+++ b/test/libelf/tset/elf_begin/Makefile
@@ -1,8 +1,9 @@
-# $Id: Makefile 2933 2013-03-30 01:33:02Z jkoshy $
+# $Id: Makefile 3704 2019-03-02 20:41:12Z jkoshy $
TOP= ../../../..
TS_SRCS= begin.m4
+TS_FILES= entry-too-large.ar
TS_DATA= check_elf.msb32 check_elf.lsb32 check_elf.msb64 \
check_elf.lsb64 a.ar a-bsd.ar a.o zero
CLEANFILES+= a.c
diff --git a/test/libelf/tset/elf_begin/begin.m4 b/test/libelf/tset/elf_begin/begin.m4
index 9a282eb3f746..16ac34e66826 100644
--- a/test/libelf/tset/elf_begin/begin.m4
+++ b/test/libelf/tset/elf_begin/begin.m4
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: begin.m4 2933 2013-03-30 01:33:02Z jkoshy $
+ * $Id: begin.m4 3706 2019-03-02 20:57:45Z jkoshy $
*/
#include <sys/stat.h>
@@ -634,3 +634,44 @@ tcArMemoryFdIgnored_$1(void)
ARFN(`BSD')
ARFN(`SVR4')
+
+/*
+ * Verify behavior with a corrupted header containing a too-large size.
+ */
+void
+tcArEntryTooLarge(void)
+{
+ Elf *ar_e, *e;
+ int error, fd, result;
+
+ result = TET_UNRESOLVED;
+ ar_e = NULL;
+ e = NULL;
+
+ TP_ANNOUNCE("elf_begin() returns ELF_E_ARCHIVE for too-large archive "
+ "entries.");
+
+ TP_SET_VERSION();
+
+ _TS_OPEN_FILE(ar_e, "entry-too-large.ar", ELF_C_READ, fd, goto done;);
+
+ if ((e = elf_begin(fd, ELF_C_READ, ar_e)) != NULL) {
+ TP_FAIL("elf_begin() succeeded.");
+ goto done;
+ }
+
+ error = elf_errno();
+ if (error != ELF_E_ARCHIVE) {
+ TP_FAIL("unexpected error %d", error);
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (e)
+ (void) elf_end(e);
+ if (ar_e)
+ (void) elf_end(ar_e);
+ tet_result(result);
+}
diff --git a/test/libelf/tset/elf_begin/entry-too-large.ar b/test/libelf/tset/elf_begin/entry-too-large.ar
new file mode 100644
index 000000000000..5cab1486306c
--- /dev/null
+++ b/test/libelf/tset/elf_begin/entry-too-large.ar
@@ -0,0 +1,3 @@
+!<arch>
+a1.c/ 1551379738 1000 1000 100644 9 `
+1234567
diff --git a/test/libelf/tset/elf_getdata/getdata.m4 b/test/libelf/tset/elf_getdata/getdata.m4
index 40afc8a4ec30..332f81bcebe3 100644
--- a/test/libelf/tset/elf_getdata/getdata.m4
+++ b/test/libelf/tset/elf_getdata/getdata.m4
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: getdata.m4 2090 2011-10-27 08:07:39Z jkoshy $
+ * $Id: getdata.m4 3695 2019-02-25 18:55:07Z jkoshy $
*/
#include <libelf.h>
@@ -68,6 +68,36 @@ findscn(Elf *e, const char *name)
return (NULL);
}
+/*
+ * Check the contents of an Elf_Data descriptor.
+ *
+ * The return value from this helper is as follows:
+ *
+ * 0 - the descriptor matched the specified content.
+ * -1 - the descriptor size had a mismatch.
+ * >0 - the content of the descriptor did not match. The returned value
+ * is the index of the first byte that differs.
+ */
+static int
+match_content(Elf_Data *ed, size_t nbytes, const char *content)
+{
+ int n;
+ const char *buf;
+
+ if (ed->d_size != nbytes)
+ return (-1);
+
+ buf = (const char *) ed->d_buf;
+ for (n = 0; n < nbytes; n++) {
+ if (*buf != *content)
+ return (n);
+ buf++;
+ content++;
+ }
+
+ return (0);
+}
+
define(`ZEROSECTION',".zerosection")
undefine(`FN')
define(`FN',`
@@ -106,6 +136,11 @@ tcZeroSection$1$2(void)
goto done;
}
+ if ((ed = elf_getdata(scn, ed)) != NULL) {
+ TP_FAIL("Extra data descriptor in section.");
+ goto done;
+ }
+
result = TET_PASS;
done:
@@ -139,16 +174,17 @@ define(`_FN',`
void
tcNonZeroSection$1$2(void)
{
- Elf *e;
int error, fd, result;
- const size_t strsectionsize = sizeof stringsection;
- size_t n, shstrndx;
+ int match_error;
+ size_t shstrndx;
const char *buf;
Elf_Scn *scn;
Elf_Data *ed;
+ Elf *e;
- e = NULL;
fd = -1;
+ e = NULL;
+ scn = NULL;
result = TET_UNRESOLVED;
TP_ANNOUNCE("a data descriptor for a non-zero sized section "
@@ -170,19 +206,22 @@ tcNonZeroSection$1$2(void)
goto done;
}
- if (ed->d_size != strsectionsize) {
+ match_error = match_content(ed, sizeof(stringsection),
+ stringsection);
+ if (match_error == -1) {
TP_FAIL("Illegal values returned: d_size %d != expected %d",
- (int) ed->d_size, strsectionsize);
+ (int) ed->d_size, sizeof(stringsection));
goto done;
- }
-
- if (memcmp(stringsection, ed->d_buf, strsectionsize) != 0) {
+ } else if (match_error > 0) {
buf = (const char *) ed->d_buf;
- for (n = 0; n < strsectionsize; n++)
- if (buf[n] != stringsection[n])
- break;
TP_FAIL("String mismatch: buf[%d] \"%c\" != \"%c\"",
- n, buf[n], stringsection[n]);
+ match_error, buf[match_error],
+ stringsection[match_error]);
+ goto done;
+ }
+
+ if ((ed = elf_getdata(scn, ed)) != NULL) {
+ TP_FAIL("Extra data descriptor in section.");
goto done;
}
@@ -201,3 +240,112 @@ _FN(lsb,32)
_FN(lsb,64)
_FN(msb,32)
_FN(msb,64)
+
+static const char new_content[] = {
+changequote({,})
+ 'n', 'e', 'w', ' ', 'c', 'o', 'n', 't', 'e', 'n', 't', '\0'
+changequote
+};
+
+/*
+ * Verify that a section with multiple Elf_Data segments is handled correctly.
+ */
+undefine(`_FN')
+define(`_FN',`
+void
+tcDataTraversal$1$2(void)
+{
+ Elf *e;
+ Elf_Scn *scn;
+ Elf_Data *ed;
+ size_t shstrndx;
+ int error, fd, match_error, result;
+
+ e = NULL;
+ fd = -1;
+ result = TET_UNRESOLVED;
+
+ TP_ANNOUNCE("multiple Elf_Data segments can be traversed.");
+ _TS_OPEN_FILE(e, "zerosection.$1$2", ELF_C_READ, fd, goto done;);
+
+ if (elf_getshdrstrndx(e, &shstrndx) != 0 ||
+ (scn = elf_getscn(e, shstrndx)) == NULL) {
+ TP_UNRESOLVED("Cannot find the string table");
+ goto done;
+ }
+
+ /*
+ * Add new data to the string section.
+ */
+ if ((ed = elf_newdata(scn)) == NULL) {
+ TP_UNRESOLVED("Cannot allocate new data.");
+ goto done;
+ }
+
+ ed->d_buf = (char *) new_content;
+ ed->d_size = sizeof(new_content);
+
+ /*
+ * Rescan the descriptor list for the section.
+ */
+ ed = NULL;
+ if ((ed = elf_getdata(scn, ed)) == NULL) {
+ error = elf_errno();
+ TP_FAIL("elf_getdata failed %d \"%s\"", error,
+ elf_errmsg(error));
+ goto done;
+ }
+
+ match_error = match_content(ed, sizeof(stringsection),
+ stringsection);
+ if (match_error == -1) {
+ TP_FAIL("Unexpected size of first descriptor: "
+ "d_size %d != expected %d", (int) ed->d_size,
+ sizeof(stringsection));
+ goto done;
+ } else if (match_error > 0) {
+ TP_FAIL("String content mismatch for data descriptor 1.");
+ goto done;
+ }
+
+ if ((ed = elf_getdata(scn, ed)) == NULL) {
+ error = elf_errno();
+ TP_FAIL("Missing second data section: %d \"%s\"", error,
+ elf_errmsg(error));
+ goto done;
+ }
+
+ match_error = match_content(ed, sizeof(new_content),
+ new_content);
+ if (match_error == -1) {
+ TP_FAIL("Unexpected size of second descriptor: "
+ "d_size %d != expected %d", (int) ed->d_size,
+ sizeof(new_content));
+ goto done;
+ } else if (match_error > 0) {
+ TP_FAIL("String content mismatch for data descriptor 2.");
+ goto done;
+ }
+
+ /*
+ * There should be no other Elf_Data descriptors.
+ */
+ if ((ed = elf_getdata(scn, ed)) != NULL) {
+ TP_FAIL("Too many Elf_Data descriptors for section.");
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (e)
+ elf_end(e);
+ if (fd != -1)
+ (void) close(fd);
+ tet_result(result);
+}')
+
+_FN(lsb,32)
+_FN(lsb,64)
+_FN(msb,32)
+_FN(msb,64)
diff --git a/test/libelf/tset/elf_rand/Makefile b/test/libelf/tset/elf_rand/Makefile
new file mode 100644
index 000000000000..1b17ff29796c
--- /dev/null
+++ b/test/libelf/tset/elf_rand/Makefile
@@ -0,0 +1,18 @@
+# $Id$
+
+TOP= ../../../..
+
+TS_SRCS= rand.m4
+TS_DATA= a.ar s1 s2
+TS_FILES= empty-file.ar missing-file.ar
+
+s1: .SILENT
+ echo 'This is s1.' > ${.TARGET}
+s2: .SILENT
+ echo 's2.' > ${.TARGET}
+
+a.ar: s1 s2 .SILENT
+ rm -f ${.TARGET}
+ ${AR} crv ${.TARGET} s1 s2 > /dev/null
+
+.include "${TOP}/mk/elftoolchain.tet.mk"
diff --git a/test/libelf/tset/elf_rand/empty-file.ar b/test/libelf/tset/elf_rand/empty-file.ar
new file mode 100644
index 000000000000..f7039eda3a06
--- /dev/null
+++ b/test/libelf/tset/elf_rand/empty-file.ar
@@ -0,0 +1,2 @@
+!<arch>
+e1/ 0 0 0 644 0 `
diff --git a/test/libelf/tset/elf_rand/missing-file.ar b/test/libelf/tset/elf_rand/missing-file.ar
new file mode 100644
index 000000000000..d62c803db28b
--- /dev/null
+++ b/test/libelf/tset/elf_rand/missing-file.ar
@@ -0,0 +1,2 @@
+!<arch>
+e1/ 0 0 0 644 42 `
diff --git a/test/libelf/tset/elf_rand/rand.m4 b/test/libelf/tset/elf_rand/rand.m4
new file mode 100644
index 000000000000..bdcf436456b5
--- /dev/null
+++ b/test/libelf/tset/elf_rand/rand.m4
@@ -0,0 +1,415 @@
+/*-
+ * Copyright (c) 2019 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ar.h>
+#include <libelf.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "elfts.h"
+#include "tet_api.h"
+
+IC_REQUIRES_VERSION_INIT();
+
+include(`elfts.m4')
+
+/*
+ * The following definitions should match those in `./Makefile'.
+ */
+define(`TP_ARFILE',`"a.ar"')
+define(`TP_NONARCHIVE', `"s1"')
+
+/*
+ * The use of an offset less than SARMAG should fail.
+ */
+void
+tcSeekBelowSarmag(void)
+{
+ Elf *ar;
+ off_t offset;
+ int error, fd, result;
+
+ fd = -1;
+ ar = NULL;
+ result = TET_UNRESOLVED;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("elf_rand() fails for an offset less than SARMAG");
+
+ TS_OPEN_FILE(ar, TP_ARFILE, ELF_C_READ, fd);
+
+ result = TET_PASS;
+
+ if ((offset = elf_rand(ar, 1)) != 0) {
+ TP_FAIL("elf_rand() succeeded with offset=%lld",
+ (unsigned long long) offset);
+ } else if ((error = elf_errno()) != ELF_E_ARGUMENT) {
+ TP_FAIL("unexpected error=%d \"%s\"", error,
+ elf_errmsg(error));
+ }
+
+ (void) elf_end(ar);
+ (void) close(fd);
+
+ tet_result(result);
+}
+
+/*
+ * The use of an offset greater than the largest valid file offset
+ * should fail.
+ */
+void
+tcSeekMoreThanFileSize(void)
+{
+ Elf *ar;
+ off_t offset;
+ struct stat sb;
+ int error, fd, result;
+
+ result = TET_UNRESOLVED;
+ ar = NULL;
+ fd = -1;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("elf_rand() fails with a too-large offset");
+
+ TS_OPEN_FILE(ar, TP_ARFILE, ELF_C_READ, fd);
+
+ /* Get the file size of the archive. */
+ if (fstat(fd, &sb) < 0) {
+ TP_UNRESOLVED("cannot determine the size of \"%s\"",
+ TP_ARFILE);
+ goto done;
+ }
+
+ result = TET_PASS;
+
+ if ((offset = elf_rand(ar, sb.st_size)) != 0) {
+ TP_FAIL("elf_rand() succeeded with offset=%lld",
+ (unsigned long long) offset);
+ } else if ((error = elf_errno()) != ELF_E_ARGUMENT) {
+ TP_FAIL("unexpected error=%d \"%s\"", error,
+ elf_errmsg(error));
+ }
+
+done:
+ if (ar)
+ (void) elf_end(ar);
+ if (fd != -1)
+ (void) close(fd);
+
+ tet_result(result);
+}
+
+/*
+ * An offset with value SARMAG is accepted.
+ */
+void
+tcOffsetEqualsSARMAG(void)
+{
+ Elf *ar;
+ off_t offset;
+ int fd, result;
+
+ fd = -1;
+ ar = NULL;
+ result = TET_UNRESOLVED;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("elf_rand(SARMAG) succeeds.");
+
+ TS_OPEN_FILE(ar, TP_ARFILE, ELF_C_READ, fd);
+
+ if ((offset = elf_rand(ar, SARMAG)) != SARMAG) {
+ TP_FAIL("unexpected offset: %lld",
+ (long long) offset);
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (ar)
+ (void) elf_end(ar);
+ if (fd != -1)
+ (void) close(fd);
+
+ tet_result(result);
+}
+
+/*
+ * Invoking elf_rand() on a non-archive should fail.
+ */
+void
+tcOnNonArchive(void)
+{
+ Elf *e;
+ off_t offset;
+ int error, fd, result;
+
+ fd = -1;
+ e = NULL;
+ result = TET_UNRESOLVED;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("elf_rand(non-archive) fails.");
+
+ TS_OPEN_FILE(e, TP_NONARCHIVE, ELF_C_READ, fd);
+
+ if ((offset = elf_rand(e, SARMAG)) != 0 ||
+ (error = elf_errno()) != ELF_E_ARGUMENT) {
+ TP_FAIL("unexpected offset=%lld",
+ (long long) offset);
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (e)
+ (void) elf_end(e);
+ if (fd != -1)
+ (void) close(fd);
+
+ tet_result(result);
+}
+
+/*
+ * Use an offset value that could cause an overflow.
+ */
+void
+tcOffsetOverflow(void)
+{
+ Elf *ar;
+ off_t offset;
+ uint64_t max_offset;
+ int error, fd, result;
+
+ fd = -1;
+ ar = NULL;
+ result = TET_UNRESOLVED;
+
+ /* A even offset that is close to overflowing. */
+ max_offset = (1ULL << (sizeof(off_t) * CHAR_BIT - 1)) - 2;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("offset close to overflowing an off_t");
+
+ TS_OPEN_FILE(ar, TP_ARFILE, ELF_C_READ, fd);
+
+ if ((offset = elf_rand(ar, (off_t) max_offset)) != 0) {
+ TP_FAIL("unexpected success, offset=%lld",
+ (long long) offset);
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (ar)
+ (void) elf_end(ar);
+ if (fd != -1)
+ (void) close(fd);
+
+ tet_result(result);
+}
+
+/*
+ * Setting the offset to a value that does not correspond to an ar header
+ * should fail.
+ */
+void
+tcOffsetNotCorrespondingToAnArchiveHeader(void)
+{
+ Elf *ar;
+ off_t offset;
+ int error, fd, result;
+
+ fd = -1;
+ ar = NULL;
+ result = TET_UNRESOLVED;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("elf_rand(non-header-offset) should fail.");
+
+ TS_OPEN_FILE(ar, TP_ARFILE, ELF_C_READ, fd);
+
+ if ((offset = elf_rand(ar, SARMAG+2)) != 0) {
+ TP_FAIL("unexpected success, offset=%lld",
+ (long long) offset);
+ goto done;
+ } else if ((error = elf_errno()) != ELF_E_ARCHIVE) {
+ TP_FAIL("unexpected error=%d \"%s\"", error,
+ elf_errmsg(error));
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (ar)
+ (void) elf_end(ar);
+ if (fd != -1)
+ (void) close(fd);
+
+ tet_result(result);
+}
+
+/*
+ * Odd values of offsets are not legal.
+ */
+void
+tcOddOffset(void)
+{
+ Elf *ar;
+ off_t offset;
+ int error, fd, result;
+
+ fd = -1;
+ ar = NULL;
+ result = TET_UNRESOLVED;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("elf_rand(odd-offset-value) should fail.");
+
+ TS_OPEN_FILE(ar, TP_ARFILE, ELF_C_READ, fd);
+
+ if ((offset = elf_rand(ar, SARMAG+1)) != 0) {
+ TP_FAIL("unexpected success, offset=%lld",
+ (long long) offset);
+ goto done;
+ } else if ((error = elf_errno()) != ELF_E_ARGUMENT) {
+ TP_FAIL("unexpected error=%d \"%s\"", error,
+ elf_errmsg(error));
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (ar)
+ (void) elf_end(ar);
+ if (fd != -1)
+ (void) close(fd);
+
+ tet_result(result);
+}
+
+/*
+ * Negative offset values are not legal.
+ */
+void
+tcNegativeOffset(void)
+{
+ Elf *ar;
+ off_t offset;
+ int error, fd, result;
+
+ fd = -1;
+ ar = NULL;
+ result = TET_UNRESOLVED;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("elf_rand(odd-offset-value) should fail.");
+
+ TS_OPEN_FILE(ar, TP_ARFILE, ELF_C_READ, fd);
+
+ if ((offset = elf_rand(ar, -SARMAG)) != 0) {
+ TP_FAIL("unexpected success, offset=%lld",
+ (long long) offset);
+ goto done;
+ } else if ((error = elf_errno()) != ELF_E_ARGUMENT) {
+ TP_FAIL("unexpected error=%d \"%s\"", error,
+ elf_errmsg(error));
+ goto done;
+ }
+
+ result = TET_PASS;
+
+done:
+ if (ar)
+ (void) elf_end(ar);
+ if (fd != -1)
+ (void) close(fd);
+
+ tet_result(result);
+}
+
+
+/* These offsets correspond to archive TP_ARFILE. */
+static off_t valid_offsets[] = {
+ SARMAG, /* File 's1'. */
+ 80 /* File 's2'. */
+};
+
+static const int number_of_offsets =
+ sizeof(valid_offsets) / sizeof(valid_offsets[0]);
+
+/*
+ * Valid offsets should be usable.
+ */
+void
+tcValidOffsets(void)
+{
+ Elf *ar;
+ off_t offset;
+ int i, error, fd, result;
+
+ fd = -1;
+ ar = NULL;
+ result = TET_UNRESOLVED;
+
+ TP_CHECK_INITIALIZATION();
+ TP_ANNOUNCE("elf_rand(valid-offsets) succeeds.");
+
+ TS_OPEN_FILE(ar, TP_ARFILE, ELF_C_READ, fd);
+
+ for (i = 0; i < number_of_offsets; i++) {
+ if ((offset = elf_rand(ar, valid_offsets[i])) !=
+ valid_offsets[i]) {
+ error = elf_errno();
+ TP_FAIL("failed to seek to offset %lld, error=%d "
+ "\"%s\"", (long long) offset, error,
+ elf_errmsg(error));
+ goto done;
+ }
+ }
+
+ result = TET_PASS;
+
+done:
+ if (ar)
+ (void) elf_end(ar);
+ if (fd != -1)
+ (void) close(fd);
+
+ tet_result(result);
+}
diff --git a/test/libtest/Makefile b/test/libtest/Makefile
index 1dc489b9db8a..3cf6de08f316 100644
--- a/test/libtest/Makefile
+++ b/test/libtest/Makefile
@@ -9,9 +9,8 @@ SUBDIR+= lib
SUBDIR+= driver
SUBDIR+= examples
-.if !make(install)
+.if !make(install) && !make(test)
.include "$(TOP)/mk/elftoolchain.subdir.mk"
.else
-install: .SILENT .PHONY
- echo Nothing to install.
+install test: .SILENT .PHONY
.endif
diff --git a/test/libtest/README.rst b/test/libtest/README.rst
index 3f29c85f8a93..b93dca7a69ee 100644
--- a/test/libtest/README.rst
+++ b/test/libtest/README.rst
@@ -43,7 +43,7 @@ functions contained in a test case named "``helloworld``":
/* File: test.c */
#include "test.h"
- TESTCASE_DESCRIPTION(helloworld) =
+ TEST_CASE_DESCRIPTION(helloworld) =
"A description of the helloworld test case.";
enum test_result
@@ -69,14 +69,14 @@ Test cases can define their own set up and tear down functions:
tc_setup_helloworld(testcase_state *tcs)
{
*tcs = ..allocate a struct helloworld_test.. ;
- return (TESTCASE_OK);
+ return (TEST_CASE_OK);
}
enum testcase_status
tc_teardown_helloworld(testcase_state tcs)
{
.. deallocate test case state..
- return (TESTCASE_OK);
+ return (TEST_CASE_OK);
}
The set up function for a test case will be invoked prior to any of
diff --git a/test/libtest/bin/make-test-scaffolding b/test/libtest/bin/make-test-scaffolding
index c0966d34527b..6ec78e8224e1 100755
--- a/test/libtest/bin/make-test-scaffolding
+++ b/test/libtest/bin/make-test-scaffolding
@@ -79,7 +79,7 @@ cat <<EOF
/* GENERATED FROM: ${@} */
#include <stddef.h>
#include "test.h"
-#include "test_runner.h"
+#include "test_case.h"
EOF
if ! nm ${*} | sort -k 3 | \
@@ -108,9 +108,13 @@ if ! nm ${*} | sort -k 3 | \
function print_test_case_record(tc_name) {
printf("\t{\n")
printf("\t\t.tc_name = \"%s\",\n", tc_name)
- printf("\t\t.tc_description = %s,\n", test_case_descriptions[tc_name])
+ printf("\t\t.tc_description = %s,\n",
+ test_case_descriptions[tc_name])
printf("\t\t.tc_tags = %s,\n", test_case_tags[tc_name])
- printf("\t\t.tc_tests = test_functions_%s\n", tc_name)
+ tf_name = "test_functions_" tc_name
+ printf("\t\t.tc_tests = %s,\n", tf_name)
+ printf("\t\t.tc_count = sizeof (%s) / sizeof (%s[0]),\n",
+ tf_name, tf_name)
printf("\t},\n")
}
function delete_test_functions(tc_name) {
@@ -120,16 +124,19 @@ if ! nm ${*} | sort -k 3 | \
}
}
function print_test_functions_record(tc_name) {
- printf("struct test_descriptor test_functions_%s[] = {\n", tc_name)
+ printf("struct test_function_descriptor test_functions_%s[]",
+ tc_name)
+ printf(" = {\n")
for (tf_name in test_functions) {
if (tc_name != matched_test_case(tf_name))
continue
printf("\t{\n")
- printf("\t\t.t_name = \"%s\",\n", tf_name)
- printf("\t\t.t_description = %s,\n",
+ printf("\t\t.tf_name = \"%s\",\n", tf_name)
+ printf("\t\t.tf_description = %s,\n",
test_function_descriptions[tf_name])
- printf("\t\t.t_func = %s,\n", prefix_tf tf_name)
- printf("\t\t.t_tags = %s\n", test_function_tags[tf_name])
+ printf("\t\t.tf_func = %s,\n", prefix_tf tf_name)
+ printf("\t\t.tf_tags = %s\n",
+ test_function_tags[tf_name])
printf("\t},\n")
}
printf("};\n")
@@ -144,7 +151,7 @@ if ! nm ${*} | sort -k 3 | \
test_case_tags[DEFAULT] = "NULL"
}
($2 == "R" || $2 == "D") && $3 ~ "^" prefix_tc_descr {
- printf("extern testcase_description %s;\n", $3)
+ printf("extern test_case_description %s;\n", $3)
tc_name = suffix($3, prefix_tc_descr)
test_cases[tc_name] = 1
test_case_descriptions[tc_name] = $3
@@ -155,7 +162,7 @@ if ! nm ${*} | sort -k 3 | \
test_case_setup[tc_name] = $3
}
($2 == "R" || $2 == "D") && $3 ~ "^" prefix_tc_tags {
- printf("extern testcase_tags %s;\n", $3)
+ printf("extern test_case_tags %s;\n", $3)
tc_name = suffix($3, prefix_tc_tags)
test_cases[tc_name] = 1
test_case_tags[tc_name] = $3
@@ -206,6 +213,8 @@ if ! nm ${*} | sort -k 3 | \
if (needs_default)
print_test_case_record(DEFAULT)
printf("};\n")
+ printf("const int test_case_count = sizeof(test_cases) / ")
+ printf("sizeof(test_cases[0]);\n")
}'; then
# Cleanup in case of an error.
rm ${output_file}
diff --git a/test/libtest/driver/Makefile b/test/libtest/driver/Makefile
index d149fee159d4..87788d3fb13c 100644
--- a/test/libtest/driver/Makefile
+++ b/test/libtest/driver/Makefile
@@ -6,9 +6,12 @@ TOP= ../../..
CFLAGS+= -I${TOP}/test/libtest/lib
-LIB= test_main
-SRCS= test_main.c
+LIB= driver
+SRCS= driver.c \
+ driver_main.c
WARNS?= 6
+MAN= test_driver.1
+
.include "$(TOP)/mk/elftoolchain.lib.mk"
diff --git a/test/libtest/driver/driver.c b/test/libtest/driver/driver.c
new file mode 100644
index 000000000000..aa85c7cb4ddf
--- /dev/null
+++ b/test/libtest/driver/driver.c
@@ -0,0 +1,216 @@
+/*-
+ * Copyright (c) 2018, Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The implementation of the test driver.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "driver.h"
+
+#if defined(ELFTC_VCSID)
+ELFTC_VCSID("$Id$");
+#endif
+
+#define SYSTEM_TMPDIR_ENV_VAR "TMPDIR"
+
+bool
+test_driver_add_search_path(struct test_run *tr, const char *directory_name)
+{
+ char *canonical_path;
+ struct test_search_path_entry *entry;
+
+ if (!test_driver_is_directory(directory_name))
+ return (false);
+
+ if ((canonical_path = realpath(directory_name, NULL)) == NULL)
+ err(1, "Cannot determine the canonical path for \"%s\"",
+ directory_name);
+
+ /* Look for, and ignore duplicates. */
+ STAILQ_FOREACH(entry, &tr->tr_search_path, tsp_next) {
+ if (strcmp(canonical_path, entry->tsp_directory) == 0)
+ return (true);
+ }
+
+ entry = calloc(1, sizeof(*entry));
+ entry->tsp_directory = canonical_path;
+
+ STAILQ_INSERT_TAIL(&tr->tr_search_path, entry, tsp_next);
+
+ return (true);
+}
+
+/*
+ * Return an initialized test run descriptor.
+ *
+ * The caller should use test_driver_free_run() to release the returned
+ * descriptor.
+ */
+struct test_run *
+test_driver_allocate_run(void)
+{
+ struct test_run *tr;
+
+ tr = calloc(sizeof(struct test_run), 1);
+ tr->tr_action = TEST_RUN_EXECUTE;
+ tr->tr_style = TR_STYLE_LIBTEST;
+ STAILQ_INIT(&tr->tr_test_cases);
+ STAILQ_INIT(&tr->tr_search_path);
+
+ return (tr);
+}
+
+/*
+ * Destroy an allocated test run descriptor.
+ *
+ * The passed in pointer should not be used after this function returns.
+ */
+void
+test_driver_free_run(struct test_run *tr)
+{
+ struct test_search_path_entry *path_entry;
+ struct test_case_selector *test_case_entry;
+ struct test_function_selector *function_entry;
+
+ free(tr->tr_runtime_base_directory);
+ free(tr->tr_name);
+ if (tr->tr_artefact_archive)
+ free(tr->tr_artefact_archive);
+
+ /* Free the search path list. */
+ while (!STAILQ_EMPTY(&tr->tr_search_path)) {
+ path_entry = STAILQ_FIRST(&tr->tr_search_path);
+ STAILQ_REMOVE_HEAD(&tr->tr_search_path, tsp_next);
+ free(path_entry);
+ }
+
+ /* Free the test selector list. */
+ while (!STAILQ_EMPTY(&tr->tr_test_cases)) {
+ test_case_entry = STAILQ_FIRST(&tr->tr_test_cases);
+ STAILQ_REMOVE_HEAD(&tr->tr_test_cases, tcs_next);
+
+ /* Free the linked test functions. */
+ while (!STAILQ_EMPTY(&test_case_entry->tcs_functions)) {
+ function_entry =
+ STAILQ_FIRST(&test_case_entry->tcs_functions);
+ STAILQ_REMOVE_HEAD(&test_case_entry->tcs_functions,
+ tfs_next);
+
+ free(function_entry);
+ }
+
+ free(test_case_entry);
+ }
+
+ free(tr);
+}
+
+/*
+ * Populate unset fields of a struct test_run with defaults.
+ */
+bool
+test_driver_finish_run_initialization(struct test_run *tr, const char *argv0)
+{
+ struct timeval tv;
+ const char *basedir;
+ const char *search_path;
+ const char *last_component;
+ char *argv0_copy, *path_copy, *path_element;
+ char test_name[NAME_MAX];
+
+ if (tr->tr_name == NULL) {
+ /* Per POSIX, basename(3) can modify its argument. */
+ argv0_copy = strdup(argv0);
+ last_component = basename(argv0_copy);
+
+ if (gettimeofday(&tv, NULL))
+ return (false);
+
+ (void) snprintf(test_name, sizeof(test_name), "%s+%ld%ld",
+ last_component, (long) tv.tv_sec, (long) tv.tv_usec);
+
+ tr->tr_name = strdup(test_name);
+
+ free(argv0_copy);
+ }
+
+ /*
+ * Select a base directory, if one was not specified.
+ */
+ if (tr->tr_runtime_base_directory == NULL) {
+ basedir = getenv(TEST_TMPDIR_ENV_VAR);
+ if (basedir == NULL)
+ basedir = getenv(SYSTEM_TMPDIR_ENV_VAR);
+ if (basedir == NULL)
+ basedir = "/tmp";
+ tr->tr_runtime_base_directory = realpath(basedir, NULL);
+ if (tr->tr_runtime_base_directory == NULL)
+ err(1, "realpath(%s) failed", basedir);
+ }
+
+ /*
+ * Add the search paths specified by the environment variable
+ * 'TEST_PATH' to the end of the search list.
+ */
+ if ((search_path = getenv(TEST_SEARCH_PATH_ENV_VAR)) != NULL &&
+ *search_path != '\0') {
+ path_copy = strdup(search_path);
+ path_element = strtok(path_copy, ":");
+ do {
+ if (!test_driver_add_search_path(tr, path_element))
+ warnx("in environment variable \"%s\": path "
+ "\"%s\" does not name a directory.",
+ TEST_SEARCH_PATH_ENV_VAR, path_element);
+ } while ((path_element = strtok(NULL, ":")) != NULL);
+ }
+
+ return (true);
+}
+
+/*
+ * Helper: return true if the passed in path names a directory, or false
+ * otherwise.
+ */
+bool
+test_driver_is_directory(const char *path)
+{
+ struct stat sb;
+ if (stat(path, &sb) != 0)
+ return false;
+ return S_ISDIR(sb.st_mode);
+}
diff --git a/test/libtest/driver/driver.h b/test/libtest/driver/driver.h
new file mode 100644
index 000000000000..5ae5cfd81246
--- /dev/null
+++ b/test/libtest/driver/driver.h
@@ -0,0 +1,206 @@
+/*-
+ * Copyright (c) 2018,2019 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LIBTEST_DRIVER_H_
+#define _LIBTEST_DRIVER_H_
+
+#include <sys/queue.h>
+
+#include <limits.h>
+#include <stdbool.h>
+
+#include "_elftc.h"
+
+#include "test.h"
+
+#define TEST_SEARCH_PATH_ENV_VAR "TEST_PATH"
+#define TEST_TMPDIR_ENV_VAR "TEST_TMPDIR"
+
+/*
+ * Run time data strucrures.
+ */
+
+/* The completion status for a test run */
+enum test_run_status {
+ /*
+ * All test cases were successfully invoked, and all their contained
+ * test purposes passed.
+ */
+ TR_STATUS_PASS = 0,
+
+ /*
+ * All test cases were successfully invoked but at least one test
+ * function reported a failure.
+ */
+ TR_STATUS_FAIL = 1,
+
+ /*
+ * At least one test case reported an error during its set up or tear
+ * down phase.
+ */
+ TR_STATUS_ERROR = 2
+};
+
+/*
+ * The 'style' of the run determines the manner in which the test
+ * executable reports test status.
+ */
+enum test_run_style {
+ /* Libtest semantics. */
+ TR_STYLE_LIBTEST,
+
+ /*
+ * Be compatible with the Test Anything Protocol
+ * (http://testanything.org/).
+ */
+ TR_STYLE_TAP,
+
+ /* Be compatible with NetBSD ATF(9). */
+ TR_STYLE_ATF
+};
+
+/*
+ * Structures used for selecting tests.
+ */
+struct test_function_selector {
+ const struct test_function_descriptor *tfs_descriptor;
+
+ STAILQ_ENTRY(test_function_selector) tfs_next;
+ int tfs_is_selected;
+};
+
+STAILQ_HEAD(test_function_selector_list, test_function_selector);
+
+struct test_case_selector {
+ const struct test_case_descriptor *tcs_descriptor;
+ STAILQ_ENTRY(test_case_selector) tcs_next;
+ struct test_function_selector_list tcs_functions;
+ int tcs_selected_count;
+};
+
+/*
+ * The action being requested of the test driver.
+ */
+enum test_run_action {
+ TEST_RUN_EXECUTE, /* Execute the selected tests. */
+ TEST_RUN_LIST, /* Only list tests. */
+};
+
+STAILQ_HEAD(test_case_selector_list, test_case_selector);
+
+/*
+ * Runtime directories to look up data files.
+ */
+struct test_search_path_entry {
+ char *tsp_directory;
+ STAILQ_ENTRY(test_search_path_entry) tsp_next;
+};
+
+STAILQ_HEAD(test_search_path_list, test_search_path_entry);
+
+/*
+ * Used to track flags that were explicity set on the command line.
+ */
+enum test_run_flags {
+ TRF_BASE_DIRECTORY = 1U << 0,
+ TRF_EXECUTION_TIME = 1U << 1,
+ TRF_ARTEFACT_ARCHIVE = 1U << 2,
+ TRF_NAME = 1U << 3,
+ TRF_SEARCH_PATH = 1U << 4,
+ TRF_EXECUTION_STYLE = 1U << 5,
+};
+
+/*
+ * Parameters for the run.
+ */
+struct test_run {
+ /*
+ * Flags tracking the options which were explicitly set.
+ *
+ * This field is a bitmask formed of 'enum test_run_flags' values.
+ */
+ unsigned int tr_commandline_flags;
+
+ /* What the test run should do. */
+ enum test_run_action tr_action;
+
+ /* The desired behavior of the test harness. */
+ enum test_run_style tr_style;
+
+ /* The desired verbosity level. */
+ int tr_verbosity;
+
+ /* An optional name assigned by the user for this test run. */
+ char *tr_name;
+
+ /*
+ * The absolute path to the directory under which the test is
+ * to be run.
+ *
+ * Each test case will be invoked in some subdirectory of this
+ * directory.
+ */
+ char *tr_runtime_base_directory;
+
+ /*
+ * The test timeout in seconds.
+ *
+ * A value of zero indicates that the test driver should wait
+ * indefinitely for tests.
+ */
+ long tr_max_seconds_per_test;
+
+ /*
+ * If not NULL, An absolute pathname to an archive that will hold
+ * the artefacts created by a test run.
+ */
+ char *tr_artefact_archive;
+
+ /*
+ * Directories to use when resolving non-absolute data file
+ * names.
+ */
+ struct test_search_path_list tr_search_path;
+
+ /* All tests selected for this run. */
+ struct test_case_selector_list tr_test_cases;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct test_run *test_driver_allocate_run(void);
+bool test_driver_add_search_path(struct test_run *,
+ const char *search_path);
+void test_driver_free_run(struct test_run *);
+bool test_driver_is_directory(const char *);
+bool test_driver_finish_run_initialization(struct test_run *,
+ const char *argv0);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBTEST_DRIVER_H_ */
diff --git a/test/libtest/driver/driver_main.c b/test/libtest/driver/driver_main.c
new file mode 100644
index 000000000000..c43ccf52ca15
--- /dev/null
+++ b/test/libtest/driver/driver_main.c
@@ -0,0 +1,726 @@
+/*-
+ * Copyright (c) 2018, Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file defines a "main()" that invokes (or lists) the tests that were
+ * linked into the current executable.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sysexits.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "_elftc.h"
+
+#include "test.h"
+#include "test_case.h"
+
+#include "driver.h"
+
+#if defined(ELFTC_VCSID)
+ELFTC_VCSID("$Id$");
+#endif
+
+enum selection_scope {
+ SCOPE_TEST_CASE = 0, /* c:STRING */
+ SCOPE_TEST_FUNCTION, /* f:STRING */
+ SCOPE_TAG, /* t:STRING */
+};
+
+/* Selection list entry. */
+struct selection_option {
+ STAILQ_ENTRY(selection_option) so_next;
+
+ /* The text to use for matching. */
+ const char *so_pattern;
+
+ /*
+ * Whether matched test and test cases should be selected
+ * (if false) or deselected (if true).
+ */
+ bool so_select_tests;
+
+ /* The kind of information to match. */
+ enum selection_scope so_selection_scope;
+};
+
+/* All selection options specified. */
+STAILQ_HEAD(selection_option_list, selection_option);
+
+static struct selection_option *
+parse_selection_option(const char *option)
+{
+ int scope_char;
+ bool select_tests;
+ enum selection_scope scope;
+ struct selection_option *so;
+
+ scope_char = '\0';
+ select_tests = true;
+ scope = SCOPE_TEST_CASE;
+
+ /* Deselection patterns start with a '-'. */
+ if (*option == '-') {
+ select_tests = false;
+ option++;
+ }
+
+ /*
+ * If a scope was not specified, the selection scope defaults
+ * to SCOPE_TEST_CASE.
+ */
+ if (strchr(option, ':') == NULL)
+ scope_char = 'c';
+ else {
+ scope_char = *option++;
+ if (*option != ':')
+ return (NULL);
+ option++; /* Skip over the ':'. */
+ }
+
+ if (*option == '\0')
+ return (NULL);
+
+ switch (scope_char) {
+ case 'c':
+ scope = SCOPE_TEST_CASE;
+ break;
+ case 'f':
+ scope = SCOPE_TEST_FUNCTION;
+ break;
+ case 't':
+ scope = SCOPE_TAG;
+ break;
+ default:
+ return (NULL);
+ }
+
+ so = calloc(1, sizeof(*so));
+ so->so_pattern = option;
+ so->so_selection_scope = scope;
+ so->so_select_tests = select_tests;
+
+ return (so);
+}
+
+/* Test execution styles. */
+struct style_entry {
+ enum test_run_style se_style;
+ const char *se_name;
+};
+
+static const struct style_entry known_styles[] = {
+ { TR_STYLE_LIBTEST, "libtest" },
+ { TR_STYLE_TAP, "tap" },
+ { TR_STYLE_ATF, "atf" }
+};
+
+/*
+ * Parse a test run style.
+ *
+ * This function returns true if the run style was recognized, or
+ * false otherwise.
+ */
+static bool
+parse_run_style(const char *option, enum test_run_style *run_style)
+{
+ size_t n;
+
+ for (n = 0; n < sizeof(known_styles) / sizeof(known_styles[0]); n++) {
+ if (strcasecmp(option, known_styles[n].se_name) == 0) {
+ *run_style = known_styles[n].se_style;
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+/*
+ * Return the canonical spelling of a test execution style.
+ */
+static const char *
+to_execution_style_name(enum test_run_style run_style)
+{
+ size_t n;
+
+ for (n = 0; n < sizeof(known_styles) / sizeof(known_styles[0]); n++) {
+ if (known_styles[n].se_style == run_style)
+ return (known_styles[n].se_name);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Parse a string value containing a positive integral number.
+ */
+static bool
+parse_execution_time(const char *option, long *execution_time) {
+ char *end;
+ long value;
+
+ if (option == NULL || *option == '\0')
+ return (false);
+
+ value = strtol(option, &end, 10);
+
+ /* Check for parse errors. */
+ if (*end != '\0')
+ return (false);
+
+ /* Reject negative numbers. */
+ if (value < 0)
+ return (false);
+
+ /* Check for overflows during parsing. */
+ if (value == LONG_MAX && errno == ERANGE)
+ return (false);
+
+ *execution_time = value;
+
+ return (true);
+}
+
+/*
+ * Match the names of test cases.
+ *
+ * In the event of a match, then the selection state specifed in
+ * 'option' is applied to all the test functions in the test case.
+ */
+static void
+match_test_cases(struct selection_option *option,
+ struct test_case_selector *tcs)
+{
+ const struct test_case_descriptor *tcd;
+ struct test_function_selector *tfs;
+
+ tcd = tcs->tcs_descriptor;
+
+ if (fnmatch(option->so_pattern, tcd->tc_name, 0))
+ return;
+
+ STAILQ_FOREACH(tfs, &tcs->tcs_functions, tfs_next)
+ tfs->tfs_is_selected = option->so_select_tests;
+}
+
+/*
+ * Match the names of test functions.
+ */
+static void
+match_test_functions(struct selection_option *option,
+ struct test_case_selector *tcs)
+{
+ struct test_function_selector *tfs;
+ const struct test_function_descriptor *tfd;
+
+ STAILQ_FOREACH(tfs, &tcs->tcs_functions, tfs_next) {
+ tfd = tfs->tfs_descriptor;
+
+ if (fnmatch(option->so_pattern, tfd->tf_name, 0))
+ continue;
+
+ tfs->tfs_is_selected = option->so_select_tests;
+ }
+}
+
+/*
+ * Helper: returns true if the specified text matches any of the
+ * entries in the array 'tags'.
+ */
+static bool
+match_tags_helper(const char *pattern, const char *tags[])
+{
+ const char **tag;
+
+ if (!tags)
+ return (false);
+
+ for (tag = tags; *tag && **tag != '\0'; tag++) {
+ if (!fnmatch(pattern, *tag, 0))
+ return (true);
+ }
+
+ return (false);
+}
+
+/*
+ * Match tags.
+ *
+ * Matches against test case tags apply to all the test
+ * functions in the test case.
+ *
+ * Matches against test function tags apply to the matched
+ * test function only.
+ */
+static void
+match_tags(struct selection_option *option,
+ struct test_case_selector *tcs)
+{
+ const struct test_case_descriptor *tcd;
+ const struct test_function_descriptor *tfd;
+ struct test_function_selector *tfs;
+
+ tcd = tcs->tcs_descriptor;
+
+ /*
+ * If the tag in the option matches a tag associated with
+ * a test case, then we set all of the test case's functions
+ * to the specified selection state.
+ */
+ if (match_tags_helper(option->so_pattern, tcd->tc_tags)) {
+ STAILQ_FOREACH(tfs, &tcs->tcs_functions, tfs_next)
+ tfs->tfs_is_selected = option->so_select_tests;
+ return;
+ }
+
+ /*
+ * Otherwise, check the tag against the tags for each function
+ * in the test case and set the selection state of each matched
+ * function.
+ */
+ STAILQ_FOREACH(tfs, &tcs->tcs_functions, tfs_next) {
+ tfd = tfs->tfs_descriptor;
+ if (match_tags_helper(option->so_pattern, tfd->tf_tags))
+ tfs->tfs_is_selected = option->so_select_tests;
+ }
+}
+
+/*
+ * Add the selected tests to the test run.
+ *
+ * The memory used by the options list is returned to the system when this
+ * function completes.
+ */
+static void
+select_tests(struct test_run *tr,
+ struct selection_option_list *selections)
+{
+ int i, j;
+ struct selection_option *selection;
+ const struct test_case_descriptor *tcd;
+ struct test_case_selector *tcs;
+ struct test_function_selector *tfs;
+ bool default_selection_state;
+ int selected_count;
+
+ default_selection_state = STAILQ_EMPTY(selections);
+
+ /*
+ * Set up runtime descriptors.
+ */
+ for (i = 0; i < test_case_count; i++) {
+ if ((tcs = calloc(1, sizeof(*tcs))) == NULL)
+ err(EX_OSERR, "cannot allocate a test-case selector");
+ STAILQ_INSERT_TAIL(&tr->tr_test_cases, tcs, tcs_next);
+ STAILQ_INIT(&tcs->tcs_functions);
+
+ tcd = &test_cases[i];
+
+ tcs->tcs_descriptor = tcd;
+
+ for (j = 0; j < tcd->tc_count; j++) {
+ if ((tfs = calloc(1, sizeof(*tfs))) == NULL)
+ err(EX_OSERR, "cannot allocate a test "
+ "function selector");
+ STAILQ_INSERT_TAIL(&tcs->tcs_functions, tfs, tfs_next);
+
+ tfs->tfs_descriptor = tcd->tc_tests + j;
+ tfs->tfs_is_selected = default_selection_state;
+ }
+ }
+
+ /*
+ * Set or reset the selection state based on the options.
+ */
+ STAILQ_FOREACH(selection, selections, so_next) {
+ STAILQ_FOREACH(tcs, &tr->tr_test_cases, tcs_next) {
+ switch (selection->so_selection_scope) {
+ case SCOPE_TEST_CASE:
+ match_test_cases(selection, tcs);
+ break;
+ case SCOPE_TEST_FUNCTION:
+ match_test_functions(selection, tcs);
+ break;
+ case SCOPE_TAG:
+ match_tags(selection, tcs);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Determine the count of tests selected, for each test case.
+ */
+ STAILQ_FOREACH(tcs, &tr->tr_test_cases, tcs_next) {
+ selected_count = 0;
+ STAILQ_FOREACH(tfs, &tcs->tcs_functions, tfs_next)
+ selected_count += tfs->tfs_is_selected;
+ tcs->tcs_selected_count = selected_count;
+ }
+
+ /* Free up the selection list. */
+ while (!STAILQ_EMPTY(selections)) {
+ selection = STAILQ_FIRST(selections);
+ STAILQ_REMOVE_HEAD(selections, so_next);
+ free(selection);
+ }
+}
+
+/*
+ * Translate a file name to absolute form.
+ *
+ * The caller needs to free the returned pointer.
+ */
+static char *
+to_absolute_path(const char *filename)
+{
+ size_t space_needed;
+ char *absolute_path;
+ char current_directory[PATH_MAX];
+
+ if (filename == NULL || *filename == '\0')
+ return (NULL);
+ if (*filename == '/')
+ return strdup(filename);
+
+ if (getcwd(current_directory, sizeof(current_directory)) == NULL)
+ err(1, "getcwd failed");
+
+ /* Reserve space for the slash separator and the trailing NUL. */
+ space_needed = strlen(current_directory) + strlen(filename) + 2;
+ if ((absolute_path = malloc(space_needed)) == NULL)
+ err(1, "malloc failed");
+ if (snprintf(absolute_path, space_needed, "%s/%s", current_directory,
+ filename) != (int) (space_needed - 1))
+ err(1, "snprintf failed");
+ return (absolute_path);
+}
+
+
+/*
+ * Display run parameters.
+ */
+
+#define FIELD_NAME_WIDTH 24
+#define INFOLINE(NAME, FLAG, FORMAT, ...) do { \
+ printf("I %c %-*s " FORMAT, \
+ (FLAG) ? '!' : '.', \
+ FIELD_NAME_WIDTH, NAME, __VA_ARGS__); \
+ } while (0)
+
+static void
+show_run_header(const struct test_run *tr)
+{
+ time_t start_time;
+ struct test_search_path_entry *path_entry;
+
+ if (tr->tr_verbosity == 0)
+ return;
+
+ INFOLINE("test-run-name", tr->tr_commandline_flags & TRF_NAME,
+ "%s\n", tr->tr_name);
+
+ INFOLINE("test-execution-style",
+ tr->tr_commandline_flags & TRF_EXECUTION_STYLE,
+ "%s\n", to_execution_style_name(tr->tr_style));
+
+ if (!STAILQ_EMPTY(&tr->tr_search_path)) {
+ INFOLINE("test-search-path",
+ tr->tr_commandline_flags & TRF_SEARCH_PATH,
+ "%c", '[');
+ STAILQ_FOREACH(path_entry, &tr->tr_search_path, tsp_next) {
+ printf(" %s", path_entry->tsp_directory);
+ }
+ printf(" ]\n");
+ }
+
+ INFOLINE("test-run-base-directory",
+ tr->tr_commandline_flags & TRF_BASE_DIRECTORY,
+ "%s\n", tr->tr_runtime_base_directory);
+
+ if (tr->tr_artefact_archive) {
+ INFOLINE("test-artefact-archive",
+ tr->tr_commandline_flags & TRF_ARTEFACT_ARCHIVE,
+ "%s\n", tr->tr_artefact_archive);
+ }
+
+ printf("I %c %-*s ",
+ tr->tr_commandline_flags & TRF_EXECUTION_TIME ? '=' : '.',
+ FIELD_NAME_WIDTH, "test-execution-time");
+ if (tr->tr_max_seconds_per_test == 0)
+ printf("unlimited\n");
+ else
+ printf("%lu\n", tr->tr_max_seconds_per_test);
+
+ printf("I %% %-*s %d\n", FIELD_NAME_WIDTH, "test-case-count",
+ test_case_count);
+
+ if (tr->tr_action == TEST_RUN_EXECUTE) {
+ start_time = time(NULL);
+ printf("I %% %-*s %s", FIELD_NAME_WIDTH,
+ "test-run-start-time", ctime(&start_time));
+ }
+}
+
+static void
+show_run_trailer(const struct test_run *tr)
+{
+ time_t end_time;
+
+ if (tr->tr_verbosity == 0)
+ return;
+
+ if (tr->tr_action == TEST_RUN_EXECUTE) {
+ end_time = time(NULL);
+ printf("I %% %-*s %s", FIELD_NAME_WIDTH, "test-run-end-time",
+ asctime(localtime(&end_time)));
+ }
+}
+
+#undef INFOLINE
+#undef FIELD_HEADER_WIDTH
+
+/*
+ * Helper: returns a character indicating the selection status for
+ * a test case. This character is as follows:
+ *
+ * - "*" all test functions in the test case were selected.
+ * - "+" some test functions in the test case were selected.
+ * - "-" no test functions from the test case were selected.
+ */
+static int
+get_test_case_status(const struct test_case_selector *tcs)
+{
+ if (tcs->tcs_selected_count == 0)
+ return '-';
+ if (tcs->tcs_selected_count == tcs->tcs_descriptor->tc_count)
+ return '*';
+ return '?';
+}
+
+/*
+ * Helper: print out a comma-separated list of tags.
+ */
+static void
+show_tags(int indent, const char *tags[])
+{
+ const char **tag;
+
+ printf("%*c: ", indent, ' ');
+ for (tag = tags; *tag && **tag != '\0';) {
+ printf("%s", *tag++);
+ if (*tag && **tag != '\0')
+ printf(",");
+ }
+ printf("\n");
+}
+
+/*
+ * Display a test case descriptor.
+ */
+static void
+show_test_case(struct test_run *tr, const struct test_case_selector *tcs)
+{
+ const struct test_case_descriptor *tcd;
+ int prefix_char;
+
+ prefix_char = get_test_case_status(tcs);
+ tcd = tcs->tcs_descriptor;
+
+ printf("C %c %s\n", prefix_char, tcd->tc_name);
+
+ if (tr->tr_verbosity > 0 && tcd->tc_tags != NULL)
+ show_tags(2, tcd->tc_tags);
+
+ if (tr->tr_verbosity > 1 && tcd->tc_description)
+ printf(" & %s\n", tcd->tc_description);
+}
+
+static void
+show_test_function(struct test_run *tr,
+ const struct test_function_selector *tfs)
+{
+ const struct test_function_descriptor *tfd;
+ int selection_char;
+
+ selection_char = tfs->tfs_is_selected ? '*' : '-';
+ tfd = tfs->tfs_descriptor;
+
+ printf(" F %c %s\n", selection_char, tfd->tf_name);
+
+ if (tr->tr_verbosity > 0 && tfd->tf_tags != NULL)
+ show_tags(4, tfd->tf_tags);
+
+ if (tr->tr_verbosity > 1 && tfd->tf_description)
+ printf(" & %s\n", tfd->tf_description);
+}
+
+static int
+show_listing(struct test_run *tr)
+{
+ const struct test_case_selector *tcs;
+ const struct test_function_selector *tfs;
+
+ STAILQ_FOREACH(tcs, &tr->tr_test_cases, tcs_next) {
+ show_test_case(tr, tcs);
+ STAILQ_FOREACH(tfs, &tcs->tcs_functions, tfs_next)
+ show_test_function(tr, tfs);
+ }
+
+ return (EXIT_SUCCESS);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct test_run *tr;
+ int exit_code, option;
+ enum test_run_style run_style;
+ struct selection_option *selector;
+ struct selection_option_list selections =
+ STAILQ_HEAD_INITIALIZER(selections);
+
+ tr = test_driver_allocate_run();
+
+ /* Parse arguments. */
+ while ((option = getopt(argc, argv, ":R:T:c:ln:p:s:t:v")) != -1) {
+ switch (option) {
+ case 'R': /* Test runtime directory. */
+ if (!test_driver_is_directory(optarg))
+ errx(EX_USAGE, "option -%c: argument \"%s\" "
+ "does not name a directory.", option,
+ optarg);
+ tr->tr_runtime_base_directory = realpath(optarg, NULL);
+ if (tr->tr_runtime_base_directory == NULL)
+ err(1, "realpath failed for \"%s\"", optarg);
+ tr->tr_commandline_flags |= TRF_BASE_DIRECTORY;
+ break;
+ case 'T': /* Max execution time for a test function. */
+ if (!parse_execution_time(
+ optarg, &tr->tr_max_seconds_per_test))
+ errx(EX_USAGE, "option -%c: argument \"%s\" "
+ "is not a valid execution time value.",
+ option, optarg);
+ tr->tr_commandline_flags |= TRF_EXECUTION_TIME;
+ break;
+ case 'c': /* The archive holding artefacts. */
+ tr->tr_artefact_archive = to_absolute_path(optarg);
+ tr->tr_commandline_flags |= TRF_ARTEFACT_ARCHIVE;
+ break;
+ case 'l': /* List matching tests. */
+ tr->tr_action = TEST_RUN_LIST;
+ break;
+ case 'n': /* Test run name. */
+ if (tr->tr_name)
+ free(tr->tr_name);
+ tr->tr_name = strdup(optarg);
+ tr->tr_commandline_flags |= TRF_NAME;
+ break;
+ case 'p': /* Add a search path entry. */
+ if (!test_driver_add_search_path(tr, optarg))
+ errx(EX_USAGE, "option -%c: argument \"%s\" "
+ "does not name a directory.", option,
+ optarg);
+ tr->tr_commandline_flags |= TRF_SEARCH_PATH;
+ break;
+ case 's': /* Test execution style. */
+ if (!parse_run_style(optarg, &run_style))
+ errx(EX_USAGE, "option -%c: argument \"%s\" "
+ "is not a supported test execution style.",
+ option, optarg);
+ tr->tr_style = run_style;
+ tr->tr_commandline_flags |= TRF_EXECUTION_STYLE;
+ break;
+ case 't': /* Test selection option. */
+ if ((selector = parse_selection_option(optarg)) == NULL)
+ errx(EX_USAGE, "option -%c: argument \"%s\" "
+ "is not a valid selection pattern.",
+ option, optarg);
+ STAILQ_INSERT_TAIL(&selections, selector, so_next);
+ break;
+ case 'v':
+ tr->tr_verbosity++;
+ break;
+ case ':':
+ errx(EX_USAGE,
+ "ERROR: option -%c requires an argument.", optopt);
+ break;
+ case '?':
+ errx(EX_USAGE,
+ "ERROR: unrecognized option -%c", optopt);
+ break;
+ default:
+ errx(EX_USAGE, "ERROR: unspecified error.");
+ break;
+ }
+ }
+
+ /*
+ * Set unset fields of the test run descriptor to their
+ * defaults.
+ */
+ if (!test_driver_finish_run_initialization(tr, argv[0]))
+ err(EX_OSERR, "cannot initialize test driver");
+
+ /* Choose tests and test cases to act upon. */
+ select_tests(tr, &selections);
+
+ assert(STAILQ_EMPTY(&selections));
+
+ show_run_header(tr);
+
+ /* Perform the requested action. */
+ switch (tr->tr_action) {
+ case TEST_RUN_LIST:
+ exit_code = show_listing(tr);
+ break;
+
+ case TEST_RUN_EXECUTE:
+ default:
+ /* Not yet implemented. */
+ exit_code = EX_UNAVAILABLE;
+ }
+
+ show_run_trailer(tr);
+
+ test_driver_free_run(tr);
+
+ exit(exit_code);
+}
diff --git a/test/libtest/driver/test_driver.1 b/test/libtest/driver/test_driver.1
new file mode 100644
index 000000000000..a987002e8c67
--- /dev/null
+++ b/test/libtest/driver/test_driver.1
@@ -0,0 +1,308 @@
+.\" Copyright (c) 2019 Joseph Koshy.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id$
+.\"
+.Dd April 02, 2019
+.Dt TEST-DRIVER 1
+.Os
+.Sh NAME
+.Nm test-driver
+.Nd scaffolding for executing
+.Xr test 3
+based tests from the command-line
+.Sh SYNOPSIS
+.Nm test-executable
+.Op Fl c Ar artefact-archive-name
+.Op Fl l
+.Op Fl n Ar run-name
+.Op Fl p Ar search-path-directory
+.Op Fl R Ar runtime-base-directory
+.Op Fl s Ar execution-style
+.Op Fl t Ar test-selector
+.Op Fl T Ar seconds
+.Op Fl v
+.Sh DESCRIPTION
+The
+.Nm
+library provides a
+.Fn main
+function that will execute the
+.Xr test 3
+based tests in an executable according to the options specified
+on the command-line.
+The
+.Nm
+library usually used in conjunction with code generated by the
+.Xr make-test-scaffolding 1
+utility.
+.Pp
+Test executables built using
+.Nm
+recognize the following command-line options:
+.Bl -tag -width indent
+.It Fl c Ar archive-name
+If this option is specified, then the
+.Nm
+provided scaffolding will copy test outputs and other artefacts from
+the test run to the archive named by argument
+.Ar archive-name .
+The format of the archive is specified by the path name suffix of the
+artefact name.
+The supported output formats are those supported by
+.Xr libarchive 3 .
+.It Fl l
+If this option is specified, then the
+.Nm
+utility will list the selected tests and exit.
+.It Fl n Ar run-name
+Use the specified test run name in status messages and to name
+any files and directories created during the test run.
+If this option is not specified, then the base name of the test
+executable is used.
+.It Fl p Ar search-path-directory
+Add the argument
+.Ar search-path-directory
+to the list of directories searched for by
+.Xr test 3
+utility functions.
+.It Fl R Ar runtime-base-directory
+Set the runtime base directory to the directory specified by the
+argument
+.Ar runtime-base-directory .
+Tests execute with their current directory set to a subdirectory
+within this directory.
+The path specified by argument
+.Ar runtime-base-directory
+must exist, and must name a directory.
+.Pp
+If this option is not specified, then the
+.Ev TEST_TMPDIR
+environment variable will be examined.
+If set to a non-empty value, then its value will be used.
+Otherwise, the value of the
+.Ev TMPDIR
+environment variable will be used, if non-empty.
+If neither of the environment variables
+.Ev TEST_TMPDIR
+and
+.Ev TMPDIR
+contain a non-empty value, then the path
+.Dq Pa /tmp
+will be used.
+.It Fl s Ar execution-style
+Set the desired execution style to that specified by argument
+.Ar execution-style .
+Legal values for
+.Ar execution-style
+are:
+.Bl -tag -width indent -compact
+.It Li atf
+Be compatible with
+.Nx
+.Xr atf 9 .
+.It Li tap
+Be compatible with TAP
+.Pq Test Anything Protocol .
+.It Li test
+Be compatible with libtest (this test framework).
+.El
+The default is to use libtest semantics.
+.It Fl t Ar test-selector
+Select (or deselect) tests to execute according to the argument
+.Ar test-selector .
+.Pp
+Test selectors are specified using the following syntax:
+.Bl -tag -compact -width indent
+.It Xo
+.Op Li - Ns
+.Li c : Ns Ar pattern
+.Xc
+Select test cases whose names match
+.Ar pattern .
+Selecting a test case will cause all of its contained
+test functions to be selected.
+.It Xo
+.Op Li - Ns
+.Li f : Ns Ar pattern
+.Xc
+Select test functions whose names match
+.Ar pattern .
+.It Xo
+.Op Li - Ns
+.Li t : Ns Ar pattern
+.Xc
+Select the test cases and test functions associated with
+tags matching
+.Ar pattern .
+.It Xo
+.Op Li - Ns
+.Ar pattern
+.Xc
+If the
+.Li c ,
+.Li f
+or
+.Li t
+qualifiers were not specified, then the pattern is matched
+against the names of test cases.
+.El
+The
+.Ar pattern
+fields of test selectors use shell wildcard syntax, as implemented by
+.Xr fnmatch 3 .
+.Pp
+If no test selectors are specified then all the tests present in
+the test executable will be run.
+Otherwise, the test selectors specified are processed in the
+order specified on the command line.
+.Pp
+A test selector that does not start with a
+.Dq Li -
+will add the entries that it matches to the currently selected list
+of tests.
+A test selector that starts with a
+.Dq Li -
+will remove the entries that it matches from the currently selected list
+of tests.
+.Pp
+If at least one test selector was specified, and if the result of
+applying the specified test selectors was an empty list
+of tests, then the
+.Nm
+library will exit with an error message.
+.It Fl T Ar seconds
+Set the timeout for individual tests to
+.Ar seconds .
+If a test function fails to return with the specified number of seconds
+then it is treated as having failed.
+The default is to wait indefinitely for the test function to complete.
+.It Fl v
+Increase verbosity level by 1.
+The default verbosity level is 0.
+.El
+.Ss Link-time Pre-requisites
+The
+.Nm
+library expects the following symbols to be present in the
+test executable it is linked with:
+.Pp
+.Bl -tag -width indent -compact
+.It Xo
+.Vt struct test_case_descriptor
+.Va test_cases Ns []
+.Xc
+An array of test cases descriptors.
+Test case descriptors described by
+.Xr test_case 5 .
+.It Xo
+.Vt int
+.Va test_case_count
+.Xc
+The number of entries in the
+.Va test_cases
+array.
+.El
+.Ss Test Execution
+At start up, the
+.Fn main
+function provided by
+.Nm
+will select tests (and test cases) to execute, based on the test
+selection options specified.
+.Pp
+For each selected test case, test execution proceeds as follows:
+.Bl -enum -compact
+.It
+The runtime directory for the test case is created.
+.It
+The test process forks, with test execution continuing in the
+child.
+.It
+.Pq Child
+The current directory of the process is changed to the runtime
+directory.
+.It
+.Pq Child
+The test case set up function is then executed.
+If this function returns an error then test case execution is
+aborted.
+.It
+.Pq Child
+Each selected test function in the test case is then executed and
+its status is output to stdout (or stderr) according to the test
+execution style selected.
+.It
+.Pq Child
+The test case tear down function is then executed.
+.It
+If test artefacts need to be preserved, then these are
+copied to the specified archive.
+.It
+The test's runtime directory is then deleted.
+.El
+.Pp
+After all test cases have been attempted, the
+.Fn main
+function exits with the exit code appropriate for the
+test execution style selected.
+.Sh EXAMPLES
+To run all tests in the binary named
+.Pa tc_example ,
+copying test artefacts to a
+.Xr cpio 1
+archive named
+.Pa /tmp/tc_example.cpio ,
+use:
+.Bd -literal -offset indent
+tc_example -c /tmp/tc_example.cpio
+.Ed
+.Pp
+To execute tests in the test case
+.Dq tc1
+alone, use:
+.Bd -literal -offset indent
+tc_example -t 'c:tc1'
+.Ed
+.Pp
+To execute tests in the test case
+.Dq tc1
+but not the test functions associated with tag
+.Li tag1 ,
+use:
+.Bd -literal -offset indent
+tc_example -t 'c:tc1' -t '-t:tag1'
+.Ed
+.Sh DIAGNOSTICS
+Test programs built with the
+.Nm
+library will exit with an exit code of 0 if all of the selected tests
+passed when run, and with a non-zero exit code if an error
+occurred during test execution.
+.Sh SEE ALSO
+.Xr make-test-scaffolding 1 ,
+.Xr fnmatch 3 ,
+.Xr libarchive 3 ,
+.Xr test 3 ,
+.Xr test_case 5
diff --git a/test/libtest/examples/minimal_example.c b/test/libtest/examples/minimal_example.c
index 4ad08b4bce06..3bc76fe66ea9 100644
--- a/test/libtest/examples/minimal_example.c
+++ b/test/libtest/examples/minimal_example.c
@@ -41,10 +41,16 @@
#include "test.h"
/*
+ * Function prototypes.
+ */
+enum test_result tf_helloworld(test_case_state);
+
+/*
* Function names prefixed with 'tf_' name test functions.
*/
enum test_result
-tf_helloworld(testcase_state state)
+tf_helloworld(test_case_state state)
{
+ (void) state;
return (TEST_PASS);
}
diff --git a/test/libtest/examples/simple_example.c b/test/libtest/examples/simple_example.c
index 6a4f6697eb51..6d72f65dd451 100644
--- a/test/libtest/examples/simple_example.c
+++ b/test/libtest/examples/simple_example.c
@@ -31,6 +31,14 @@
#include "test.h"
/*
+ * Function prototypes.
+ */
+enum test_case_status tc_setup_helloworld(test_case_state *);
+enum test_case_status tc_teardown_helloworld(test_case_state);
+enum test_result tf_helloworld_sayhello(test_case_state);
+enum test_result tf_helloworld_saygoodbye(test_case_state);
+
+/*
* This source defines a single test case named 'helloworld' containing a
* single test function named 'sayhello' contained in that test case. At
* test execution time the test case would be selectable using the tags
@@ -64,35 +72,37 @@
/*
* A symbol name prefixed with 'tc_description_' contains a
- * test case description. The TESTCASE_DESCRIPTION macro offers
+ * test case description. The TEST_CASE_DESCRIPTION macro offers
* a convenient way to define such symbols. In the case of the
* symbol below, the test case named is 'helloworld'.
*/
-TESTCASE_DESCRIPTION(helloworld) = "A description for a test case.";
+TEST_CASE_DESCRIPTION(helloworld) = "A description for a test case.";
/*
* Function names prefixed with 'tc_setup_' are assumed to be test
* case set up functions.
*/
-enum testcase_status
-tc_setup_helloworld(testcase_state *state)
+enum test_case_status
+tc_setup_helloworld(test_case_state *state)
{
- return (TESTCASE_OK);
+ (void) state;
+ return (TEST_CASE_OK);
}
/*
* Function names prefixed with 'tc_teardown_' are assumed to be test
* case tear down functions.
*/
-enum testcase_status
-tc_teardown_helloworld(testcase_state state)
+enum test_case_status
+tc_teardown_helloworld(test_case_state state)
{
- return (TESTCASE_OK);
+ (void) state;
+ return (TEST_CASE_OK);
}
/*
* Names prefixed with 'tc_tags_' denote the tags associated with test
- * cases. The TESTCASE_TAGS macro offers a convenient way to define such
+ * cases. The TESTC_ASE_TAGS macro offers a convenient way to define such
* symbols.
*
* In the example below, all test functions belonging to the test case
@@ -100,7 +110,7 @@ tc_teardown_helloworld(testcase_state state)
*
* Tags lists are terminated by a NULL entry.
*/
-TESTCASE_TAGS(helloworld) = {
+TEST_CASE_TAGS(helloworld) = {
"tag1",
"tag2",
NULL
@@ -110,8 +120,16 @@ TESTCASE_TAGS(helloworld) = {
* Function names prefixed with 'tf_' name test functions.
*/
enum test_result
-tf_helloworld_sayhello(testcase_state state)
+tf_helloworld_sayhello(test_case_state state)
+{
+ (void) state;
+ return (TEST_PASS);
+}
+
+enum test_result
+tf_helloworld_saygoodbye(test_case_state state)
{
+ (void) state;
return (TEST_PASS);
}
@@ -126,6 +144,9 @@ tf_helloworld_sayhello(testcase_state state)
TEST_DESCRIPTION(helloworld_sayhello) =
"A description for the test function 'tf_helloworld_sayhello'.";
+TEST_DESCRIPTION(helloworld_saygoodbye) =
+ "A description for the test function 'tf_helloworld_saygoodbye'.";
+
/*
* Names prefixed by 'tf_tags_' contain the tags associated with
* test functions.
@@ -143,3 +164,8 @@ test_tags tf_tags_helloworld_sayhello = {
"tag4",
NULL
};
+
+test_tags tf_tags_helloworld_saygoodbye = {
+ "tag5",
+ NULL
+};
diff --git a/test/libtest/lib/Makefile b/test/libtest/lib/Makefile
index 7359ddd76a6c..e36d8fa072ba 100644
--- a/test/libtest/lib/Makefile
+++ b/test/libtest/lib/Makefile
@@ -4,10 +4,9 @@ TOP= ../../..
LIB= test
-SRCS= test.c \
- test_runner.c
+SRCS= test.c
-INCS= test.h
+INCS= test.h test_case.h
WARNS?= 6
diff --git a/test/libtest/lib/test.3 b/test/libtest/lib/test.3
index c7045b4039c4..e170c181595a 100644
--- a/test/libtest/lib/test.3
+++ b/test/libtest/lib/test.3
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2018, Joseph Koshy.
+.\" Copyright (c) 2018,2019 Joseph Koshy.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -24,7 +24,7 @@
.\"
.\" $Id$
.\"
-.Dd December 25, 2018
+.Dd January 21, 2019
.Dt TEST 3
.Os
.Sh NAME
@@ -34,20 +34,20 @@
.Lb libtest
.Sh SYNOPSIS
.In test.h
-.Ft enum testcase_status
-.Fn testcase_setup "testcase_state *state"
-.Ft enum testcase_status
-.Fn testcase_teardown "testcase_state state"
+.Ft enum test_case_status
+.Fn test_case_setup "test_case_state *state"
+.Ft enum test_case_status
+.Fn test_case_teardown "test_case_state state"
.Ft enum test_result
-.Fn test_function "testcase_state state"
+.Fn test_function "test_case_state state"
.Vt "const char"
.Va test_description [] ;
.Vt "const char *"
.Va test_tags [] ;
.Vt "const char"
-.Va testcase_description [] ;
+.Va test_case_description [] ;
.Vt "const char *"
-.Va testcase_tags [] ;
+.Va test_case_tags [] ;
.Sh DESCRIPTION
The
.Lb libtest
@@ -76,7 +76,7 @@ If specified, this set up function would be invoked prior to any test
function contained in the test case.
The set up function can allocate and initialize test-specific state, to be
passed to test functions.
-If no set up function is specified for the test case, a default no-op
+If no set up function is specified for the test case, a default (no-op)
function will be supplied.
.It
An optional test case tear down function.
diff --git a/test/libtest/lib/test.h b/test/libtest/lib/test.h
index 86f91463993b..6928f867a6f4 100644
--- a/test/libtest/lib/test.h
+++ b/test/libtest/lib/test.h
@@ -44,60 +44,59 @@ enum test_result {
/*
* The return values from test case set up and tear down functions.
*
- * - TESTCASE_OK : The set up or tear down function was successful.
- * - TESTCASE_ERROR : Set up or tear down actions could not be completed.
+ * - TEST_CASE_OK : The set up or tear down function was successful.
+ * - TEST_CASE_ERROR : Set up or tear down actions could not be completed.
*
- * If a test case set up function returns TESTCASE_ERROR then:
+ * If a test case set up function returns TEST_CASE_ERROR then:
* - The test functions in the test case will not be run.
* - The test case's tear down function will not be invoked.
* - The test run as a whole will be treated as being in error.
*
- * If a test case tear down function returns a TESTCASE_ERROR, then
+ * If a test case tear down function returns a TEST_CASE_ERROR, then
* the test run as a whole be treated as being in error.
*/
-enum testcase_status {
- TESTCASE_OK = 0,
- TESTCASE_ERROR = 1
+enum test_case_status {
+ TEST_CASE_OK = 0,
+ TEST_CASE_ERROR = 1
};
/*
- * A testcase_state denotes resources that are shared by the test
- * functions that are part of a test case. A testcase_state is allocated
- * by the set up function for a test case. Conversely the test case's
- * tear down function is responsible for deallocating the resources
- * allocated by the set up function.
+ * A 'test_case_state' is a handle to resources shared by the test functions
+ * that make up a test case. A test_case_state is allocated by the test case
+ * set up function and is deallocated by the test case tear down function.
*
- * The test(3) framework treats a testcase_state as an opaque value.
+ * The test(3) framework treats a 'test_case_state' as an opaque value.
*/
-typedef void *testcase_state;
+typedef void *test_case_state;
/*
* Test case and test function descriptions, and convenience macros
* to define these.
*/
-typedef const char testcase_description[];
+typedef const char test_case_description[];
-#if !defined(TEST_DESCRIPTION)
-#define TEST_DESCRIPTION(NAME) test_description tf_description_##NAME
+#if !defined(TEST_CASE_DESCRIPTION)
+#define TEST_CASE_DESCRIPTION(NAME) test_case_description tc_description_##NAME
#endif
typedef const char test_description[];
-#if !defined(TESTCASE_DESCRIPTION)
-#define TESTCASE_DESCRIPTION(NAME) testcase_description tc_description_##NAME
+#if !defined(TEST_DESCRIPTION)
+#define TEST_DESCRIPTION(NAME) test_description tf_description_##NAME
#endif
/*
* Test case and test function tags, and convenience macros to define
* these.
*/
-typedef const char *testcase_tags[];
+typedef const char *test_case_tags[];
-#if !defined(TESTCASE_TAGS)
-#define TESTCASE_TAGS(NAME) testcase_tags tc_tags_##NAME
+#if !defined(TEST_CASE_TAGS)
+#define TEST_CASE_TAGS(NAME) test_case_tags tc_tags_##NAME
#endif
typedef const char *test_tags[];
+
#if !defined(TEST_TAGS)
#define TEST_TAGS(NAME) test_tags tf_tags_##NAME
#endif
@@ -108,7 +107,7 @@ typedef const char *test_tags[];
* If defined for a test case, this function will be called prior to
* the execution of an of the test functions within the test cae. Test
* case execution will be aborted if the function returns any value other
- * than TESTCASE_OK.
+ * than TEST_CASE_OK.
*
* The function can set '*state' to a memory area holding test state to be
* passed to test functions.
@@ -116,8 +115,8 @@ typedef const char *test_tags[];
* If the test case does not define a set up function, then a default
* no-op set up function will be used.
*/
-typedef enum testcase_status (test_case_setup_function)
- (testcase_state *state);
+typedef enum test_case_status test_case_setup_function(
+ test_case_state *state);
/*
* A test function.
@@ -127,7 +126,7 @@ typedef enum testcase_status (test_case_setup_function)
* its test succeeded or TEST_FAIL otherwise. In the event the test could
* not be executed, it can return TEST_UNRESOLVED.
*/
-typedef enum test_result (test_function)(testcase_state state);
+typedef enum test_result test_function(test_case_state state);
/*
* A test case tear down function.
@@ -138,7 +137,8 @@ typedef enum test_result (test_function)(testcase_state state);
* responsible for deallocating the resources that the set up function
* had allocated.
*/
-typedef enum testcase_status (test_case_teardown_function)(testcase_state state);
+typedef enum test_case_status test_case_teardown_function(
+ test_case_state state);
#ifdef __cplusplus
extern "C" {
diff --git a/test/libtest/driver/test_main.c b/test/libtest/lib/test_case.h
index 90e46d9a5fe2..c40b15fb69a1 100644
--- a/test/libtest/driver/test_main.c
+++ b/test/libtest/lib/test_case.h
@@ -24,26 +24,35 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef _LIBTEST_TEST_CASE_H_
+#define _LIBTEST_TEST_CASE_H_
+
+#include "test.h"
+
/*
- * This file defines a "main" that parses command-line arguments and invokes
- * the selected test cases.
+ * These structures describe the test cases that are linked into a
+ * test executable.
*/
-#include <sys/param.h>
-#include <assert.h>
-#include <stdlib.h>
+/* A single test function, with its associated tags and description. */
+struct test_function_descriptor {
+ const char *tf_name; /* Test name. */
+ const char *tf_description; /* Test description. */
+ const char **tf_tags; /* The tags for the test. */
+ test_function *tf_func; /* The function to invoke. */
+};
-#include "_elftc.h"
-#include "test.h"
-#include "test_runner.h"
+/* A test case, with its associated tests. */
+struct test_case_descriptor {
+ const char *tc_name; /* Test case name. */
+ const char *tc_description; /* Test case description. */
+ const char **tc_tags; /* Any associated tags. */
+ const struct test_function_descriptor *tc_tests; /* Contained tests. */
+ const int tc_count; /* The number of tests. */
+};
-ELFTC_VCSID("$Id$");
+/* All test cases linked into the test binary. */
+extern struct test_case_descriptor test_cases[];
+extern const int test_case_count;
-int
-main(int argc, char **argv)
-{
- (void) test_cases;
- (void) argc;
- (void) argv;
- exit(0);
-}
+#endif /* _LIBTEST_TEST_CASE_H_ */
diff --git a/test/libtest/lib/test_runner.c b/test/libtest/lib/test_runner.c
deleted file mode 100644
index 1366ff4a538e..000000000000
--- a/test/libtest/lib/test_runner.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-
- * Copyright (c) 2018, Joseph Koshy
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * An implementation of a test driver for test(3) tests.
- */
-
-/* To be implemented. */
diff --git a/test/libtest/lib/test_runner.h b/test/libtest/lib/test_runner.h
deleted file mode 100644
index cbf00f29b44d..000000000000
--- a/test/libtest/lib/test_runner.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*-
- * Copyright (c) 2018, Joseph Koshy
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _LIBTEST_TEST_RUNNER_H_
-#define _LIBTEST_TEST_RUNNER_H_
-
-#include "test.h"
-
-/*
- * These data structures and functions are used by test driver that
- * execute tests.
- */
-
-/*
- * The completion status for a test run:
- *
- * - TESTRUN_PASS : All test cases were successfully invoked and all test
- * purposes in the test cases passed.
- * - TESTRUN_FAIL : All test cases were successfully invoked but at least
- * one test purpose reported a test failure.
- * - TESTRUN_ERROR : At least one test case reported an error during its
- * set up or tear down phase.
- */
-enum testrun_status {
- TESTRUN_PASS = 0,
- TESTRUN_FAIL = 1,
- TESTRUN_ERROR = 2
-};
-
-/*
- * A single test function, with its associated tags and description.
- */
-struct test_descriptor {
- const char *t_name; /* Test name. */
- const char *t_description; /* Test description. */
- const char **t_tags; /* Tags associated with the test. */
- test_function *t_func; /* The function to invoke. */
-};
-
-/*
- * A test case.
- */
-struct test_case_descriptor {
- const char *tc_name; /* Test case name. */
- const char *tc_description; /* Test case description. */
- const char **tc_tags; /* Any associated tags. */
- struct test_descriptor *tc_tests; /* The tests in this test case. */
-};
-
-/*
- * All test cases.
- */
-extern struct test_case_descriptor test_cases[];
-
-enum testrun_style {
- /* Libtest semantics. */
- TESTRUN_STYLE_LIBTEST,
-
- /*
- * Be compatible with the Test Anything Protocol
- * (http://testanything.org/).
- */
- TESTRUN_STYLE_TAP,
-
- /* Be compatible with NetBSD ATF(9). */
- TESTRUN_STYLE_ATF
-};
-
-/*
- * Parameters for the run.
- */
-struct test_run {
- /*
- * An optional name assigned by the user for this test run.
- *
- * This name is reported in test logs and is not interpreted
- * by the test harness.
- */
- char *testrun_name;
-
- /* The source directory for the run. */
- char *testrun_source_directory;
-
- /* The directory in which the test is executing. */
- char *testrun_test_directory;
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBTEST_TEST_RUNNER_H_ */
diff --git a/test/nm/ts/Makefile.tset b/test/nm/ts/Makefile.tset
index ac5fd0ad4540..4b9ca8adb073 100644
--- a/test/nm/ts/Makefile.tset
+++ b/test/nm/ts/Makefile.tset
@@ -1,4 +1,4 @@
-# $Id: Makefile.tset 2085 2011-10-27 05:06:47Z jkoshy $
+# $Id: Makefile.tset 3719 2019-03-23 08:30:55Z jkoshy $
NM_EXEC?= ${.CURDIR}/../../../../nm/nm
CSTD?= iso9899:1999
@@ -16,7 +16,7 @@ CLEANFILES+= test_nm.c
.endif
.endfor
-.if !exists(${TS_DATA:R})
+.if !empty(${TS_DATA:R}) && !exists(${TS_DATA:R})
${TS_DATA}:
uudecode ${TS_DATA}.uu
.endif
diff --git a/test/tet/patches/configure.patch b/test/tet/patches/configure.patch
index 9fb02049c545..c2307504cacf 100644
--- a/test/tet/patches/configure.patch
+++ b/test/tet/patches/configure.patch
@@ -1,13 +1,13 @@
-: $Id: configure.patch 2204 2011-11-24 05:23:42Z jkoshy $
+: $Id: configure.patch 3721 2019-03-23 09:04:45Z jkoshy $
---- tet3.8/configure-- 2005-12-09 16:29:17 +0530
-+++ tet3.8/configure 2011-11-24 01:42:02 +0530
-@@ -317,7 +317,7 @@
+--- tet3.8/configure-- Sat Mar 23 10:36:51 2019
++++ tet3.8/configure Sat Mar 23 10:38:03 2019
+@@ -317,7 +317,7 @@ CRAY*)
*-sgi-irix*)
fname=irix.mk
;;
-*-freebsd)
-+*-freebsd | *-netbsd | *-dragonfly) # Use FreeBSD's configuration.
++*-freebsd | *-netbsd | *-dragonfly | *-openbsd) #Use FreeBSD's configuration.
fname=freebsd.mk
;;
*-bsdi)