summaryrefslogtreecommitdiffstats
path: root/contrib/elftoolchain/libpe
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2016-02-12 20:54:02 +0000
committeremaste <emaste@FreeBSD.org>2016-02-12 20:54:02 +0000
commita6ae90983efabb9784f1e105ffb29eaec3c0573c (patch)
treecd8537a698afe8dd30dc9c4d04c193e5b3b2e94f /contrib/elftoolchain/libpe
parent0309ab8781484f9cf0561cbbc3cab6df7139d629 (diff)
parent85217dee0e24c5f3ac285420e843063b4b52c1a0 (diff)
downloadFreeBSD-src-a6ae90983efabb9784f1e105ffb29eaec3c0573c.zip
FreeBSD-src-a6ae90983efabb9784f1e105ffb29eaec3c0573c.tar.gz
Update ELF Tool Chain to upstream rev 3400
Some notable improvements include: readelf: - Add AArch64 relocation definitions. - Report value of unknown relocation types. elfcopy: - Consider symbols with STB_GNU_UNIQUE binding as global symbols. - Fixed support for VMA adjustment for loadable sections found in relocatable objects. - Handle nameless global symbols. - Improve wildcard matching for !-prefixed symbols. - Add PE/COFF support. elfdump: - Improve section type reporting. - Add MIPS-specific section types. This update also includes a significant number of bug fixes. PR: 207091 [exp-run] Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'contrib/elftoolchain/libpe')
-rw-r--r--contrib/elftoolchain/libpe/Makefile32
-rw-r--r--contrib/elftoolchain/libpe/_libpe.h213
-rw-r--r--contrib/elftoolchain/libpe/libpe.h121
-rw-r--r--contrib/elftoolchain/libpe/libpe_buffer.c185
-rw-r--r--contrib/elftoolchain/libpe/libpe_coff.c535
-rw-r--r--contrib/elftoolchain/libpe/libpe_dos.c403
-rw-r--r--contrib/elftoolchain/libpe/libpe_init.c145
-rw-r--r--contrib/elftoolchain/libpe/libpe_rich.c128
-rw-r--r--contrib/elftoolchain/libpe/libpe_section.c518
-rw-r--r--contrib/elftoolchain/libpe/libpe_utils.c69
-rw-r--r--contrib/elftoolchain/libpe/os.Linux.mk6
-rw-r--r--contrib/elftoolchain/libpe/os.NetBSD.mk2
-rw-r--r--contrib/elftoolchain/libpe/pe.h292
-rw-r--r--contrib/elftoolchain/libpe/pe_buffer.c100
-rw-r--r--contrib/elftoolchain/libpe/pe_cntl.c62
-rw-r--r--contrib/elftoolchain/libpe/pe_coff.c157
-rw-r--r--contrib/elftoolchain/libpe/pe_dos.c119
-rw-r--r--contrib/elftoolchain/libpe/pe_flag.c187
-rw-r--r--contrib/elftoolchain/libpe/pe_init.c95
-rw-r--r--contrib/elftoolchain/libpe/pe_rich.c107
-rw-r--r--contrib/elftoolchain/libpe/pe_section.c213
-rw-r--r--contrib/elftoolchain/libpe/pe_symtab.c86
-rw-r--r--contrib/elftoolchain/libpe/pe_update.c86
23 files changed, 3861 insertions, 0 deletions
diff --git a/contrib/elftoolchain/libpe/Makefile b/contrib/elftoolchain/libpe/Makefile
new file mode 100644
index 0000000..d02fb50
--- /dev/null
+++ b/contrib/elftoolchain/libpe/Makefile
@@ -0,0 +1,32 @@
+# $Id: Makefile 3349 2016-01-18 21:09:16Z jkoshy $
+
+TOP= ${.CURDIR}/..
+
+LIB= pe
+
+SRCS= libpe_buffer.c \
+ libpe_coff.c \
+ libpe_dos.c \
+ libpe_init.c \
+ libpe_rich.c \
+ libpe_section.c \
+ libpe_utils.c \
+ pe_buffer.c \
+ pe_cntl.c \
+ pe_coff.c \
+ pe_dos.c \
+ pe_flag.c \
+ pe_init.c \
+ pe_rich.c \
+ pe_section.c \
+ pe_symtab.c \
+ pe_update.c
+
+INCS= libpe.h pe.h
+INCSDIR= /usr/include
+
+SHLIB_MAJOR= 1
+
+WARNS?= 6
+
+.include "${TOP}/mk/elftoolchain.lib.mk"
diff --git a/contrib/elftoolchain/libpe/_libpe.h b/contrib/elftoolchain/libpe/_libpe.h
new file mode 100644
index 0000000..1a83a67
--- /dev/null
+++ b/contrib/elftoolchain/libpe/_libpe.h
@@ -0,0 +1,213 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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: _libpe.h 3312 2016-01-10 09:23:51Z kaiwang27 $
+ */
+
+#ifndef __LIBPE_H_
+#define __LIBPE_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "libpe.h"
+
+#include "_elftc.h"
+
+typedef struct _PE_SecBuf {
+ PE_Buffer sb_pb; /* application buffer */
+ PE_Scn *sb_ps; /* PE_Scn pointer */
+ unsigned int sb_flags; /* buffer flags */
+ STAILQ_ENTRY(_PE_SecBuf) sb_next;
+} PE_SecBuf;
+
+struct _PE_Scn {
+ PE *ps_pe; /* PE descriptor */
+ PE_SecHdr ps_sh; /* section header */
+ unsigned int ps_ndx; /* 1-based section index */
+ unsigned int ps_flags; /* section flags */
+ unsigned int ps_falign; /* section file alignment */
+ STAILQ_HEAD(, _PE_SecBuf) ps_b; /* buffer list */
+ STAILQ_ENTRY(_PE_Scn) ps_next;
+};
+
+struct _PE {
+ int pe_fd; /* file descriptor */
+ PE_Cmd pe_cmd; /* open mode */
+ PE_Object pe_obj; /* PE32/PE32+/COFF */
+ size_t pe_fsize; /* file size */
+ unsigned int pe_flags; /* library flags */
+ PE_DosHdr *pe_dh; /* MS-DOS header */
+ char *pe_stub; /* MS-DOS stub */
+ size_t pe_stub_ex; /* MS-DOS stub len (exclude hdr) */
+ char *pe_stub_app; /* MS-DOS stub (app supplied) */
+ size_t pe_stub_app_sz; /* MS-DOS stub len (app supplied) */
+ PE_RichHdr *pe_rh; /* rich header */
+ char *pe_rh_start; /* pointer to rich header */
+ PE_CoffHdr *pe_ch; /* COFF header */
+ PE_OptHdr *pe_oh; /* optional header */
+ PE_DataDir *pe_dd; /* data directories */
+ unsigned int pe_nscn; /* num. of sections */
+ char *pe_symtab; /* COFF symbol table */
+ size_t pe_symbtab_sz; /* size of symbol table */
+ unsigned int pe_nsym; /* num. of symbols */
+ unsigned int pe_rvamax; /* maximum RVA */
+ STAILQ_HEAD(, _PE_Scn) pe_scn; /* section list */
+};
+
+/* Library internal flags */
+#define LIBPE_F_API_MASK 0x000FFFU
+#define LIBPE_F_SPECIAL_FILE 0x001000U
+#define LIBPE_F_BAD_DOS_HEADER 0x002000U
+#define LIBPE_F_BAD_PE_HEADER 0x004000U
+#define LIBPE_F_BAD_COFF_HEADER 0x008000U
+#define LIBPE_F_BAD_OPT_HEADER 0x010000U
+#define LIBPE_F_BAD_SEC_HEADER 0x020000U
+#define LIBPE_F_LOAD_DOS_STUB 0x040000U
+#define LIBPE_F_FD_DONE 0x080000U
+#define LIBPE_F_DIRTY_DOS_HEADER 0x100000U
+#define LIBPE_F_DIRTY_COFF_HEADER 0x200000U
+#define LIBPE_F_DIRTY_OPT_HEADER 0x400000U
+#define LIBPE_F_DIRTY_SEC_HEADER 0x800000U
+
+/* Internal section flags */
+#define LIBPE_F_LOAD_SECTION 0x1000U
+#define LIBPE_F_STRIP_SECTION 0x2000U
+
+/* Internal buffer flags */
+#define LIBPE_F_BUFFER_MALLOCED 0x1000U
+
+/* Library internal defines */
+#define PE_DOS_MAGIC 0x5a4dU
+#define PE_RICH_TEXT "Rich"
+#define PE_RICH_HIDDEN 0x536e6144U /* DanS */
+#define PE_SIGNATURE 0x4550U /* PE\0\0 */
+#define PE_COFF_OPT_SIZE_32 224
+#define PE_COFF_OPT_SIZE_32P 240
+#define PE_SYM_ENTRY_SIZE 18
+
+/* Encode/Decode macros */
+#if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS)
+static __inline uint16_t
+le16dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return ((p[1] << 8) | p[0]);
+}
+
+static __inline uint32_t
+le32dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+}
+
+static __inline uint64_t
+le64dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
+}
+
+static __inline void
+le16enc(void *pp, uint16_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = u & 0xff;
+ p[1] = (u >> 8) & 0xff;
+}
+
+static __inline void
+le32enc(void *pp, uint32_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = u & 0xff;
+ p[1] = (u >> 8) & 0xff;
+ p[2] = (u >> 16) & 0xff;
+ p[3] = (u >> 24) & 0xff;
+}
+
+static __inline void
+le64enc(void *pp, uint64_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ le32enc(p, (uint32_t)(u & 0xffffffffU));
+ le32enc(p + 4, (uint32_t)(u >> 32));
+}
+#endif /* ELFTC_NEED_BYTEORDER_EXTENSIONS */
+
+#define PE_READ16(p,v) do { \
+ (v) = le16dec((p)); \
+ (p) += 2; \
+} while(0)
+
+#define PE_READ32(p,v) do { \
+ (v) = le32dec((p)); \
+ (p) += 4; \
+} while(0)
+
+#define PE_WRITE16(p,v) do { \
+ le16enc((p), (v)); \
+ (p) += 2; \
+} while(0)
+
+#define PE_WRITE32(p,v) do { \
+ le32enc((p), (v)); \
+ (p) += 4; \
+} while(0)
+
+
+/* Internal function declarations */
+off_t libpe_align(PE *, off_t, size_t);
+PE_SecBuf *libpe_alloc_buffer(PE_Scn *, size_t);
+PE_Scn *libpe_alloc_scn(PE *);
+int libpe_load_all_sections(PE *);
+int libpe_load_section(PE *, PE_Scn *);
+int libpe_open_object(PE *);
+int libpe_pad(PE *, size_t);
+int libpe_parse_msdos_header(PE *, char *);
+int libpe_parse_coff_header(PE *, char *);
+int libpe_parse_rich_header(PE *);
+int libpe_parse_section_headers(PE *);
+int libpe_read_msdos_stub(PE *);
+void libpe_release_buffer(PE_SecBuf *);
+void libpe_release_object(PE *);
+void libpe_release_scn(PE_Scn *);
+size_t libpe_resync_buffers(PE_Scn *);
+int libpe_resync_sections(PE *, off_t);
+int libpe_write_buffers(PE_Scn *);
+off_t libpe_write_coff_header(PE *, off_t);
+off_t libpe_write_msdos_stub(PE *, off_t);
+off_t libpe_write_pe_header(PE *, off_t);
+off_t libpe_write_sections(PE *, off_t);
+off_t libpe_write_section_headers(PE *, off_t);
+
+#endif /* !__LIBPE_H_ */
diff --git a/contrib/elftoolchain/libpe/libpe.h b/contrib/elftoolchain/libpe/libpe.h
new file mode 100644
index 0000000..3cec39a
--- /dev/null
+++ b/contrib/elftoolchain/libpe/libpe.h
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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: libpe.h 3312 2016-01-10 09:23:51Z kaiwang27 $
+ */
+
+#ifndef _LIBPE_H_
+#define _LIBPE_H_
+
+#include <sys/types.h>
+
+#include "pe.h"
+
+/* Library private data structures */
+typedef struct _PE PE;
+typedef struct _PE_Scn PE_Scn;
+
+/* Section buffers */
+typedef struct PE_Buffer {
+ unsigned int pb_align;
+ off_t pb_off;
+ size_t pb_size;
+ void *pb_buf;
+} PE_Buffer;
+
+/* Object types */
+typedef enum {
+ PE_O_UNKNOWN = 0,
+ PE_O_PE32,
+ PE_O_PE32P,
+ PE_O_COFF,
+} PE_Object;
+
+/* Commands */
+typedef enum {
+ PE_C_NULL = 0,
+ PE_C_CLR,
+ PE_C_FDDONE,
+ PE_C_FDREAD,
+ PE_C_RDWR,
+ PE_C_READ,
+ PE_C_SET,
+ PE_C_WRITE,
+ PE_C_NUM
+} PE_Cmd;
+
+/* Flags defined by the API. */
+#define PE_F_DIRTY 0x001U
+#define PE_F_STRIP_DOS_STUB 0x002U
+#define PE_F_STRIP_RICH_HEADER 0x004U
+#define PE_F_STRIP_SYMTAB 0x008U
+#define PE_F_STRIP_DEBUG 0x010U
+#define PE_F_STRIP_SECTION 0x020U
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PE_CoffHdr *pe_coff_header(PE *);
+int pe_cntl(PE *, PE_Cmd);
+PE_DataDir *pe_data_dir(PE *);
+void pe_finish(PE *);
+int pe_flag(PE *, PE_Cmd, unsigned int);
+int pe_flag_buffer(PE_Buffer *, PE_Cmd, unsigned int);
+int pe_flag_coff_header(PE *, PE_Cmd, unsigned int);
+int pe_flag_data_dir(PE *, PE_Cmd, unsigned int);
+int pe_flag_dos_header(PE *, PE_Cmd, unsigned int);
+int pe_flag_opt_header(PE *, PE_Cmd, unsigned int);
+int pe_flag_section_header(PE_Scn *, PE_Cmd, unsigned int);
+int pe_flag_scn(PE_Scn *, PE_Cmd, unsigned int);
+PE_Buffer *pe_getbuffer(PE_Scn *, PE_Buffer *);
+PE_Scn *pe_getscn(PE *, size_t);
+PE *pe_init(int, PE_Cmd, PE_Object);
+PE_Scn *pe_insertscn(PE *, size_t);
+PE_DosHdr *pe_msdos_header(PE *);
+char *pe_msdos_stub(PE *, size_t *);
+size_t pe_ndxscn(PE_Scn *);
+PE_Buffer *pe_newbuffer(PE_Scn *);
+PE_Scn *pe_newscn(PE *);
+PE_Scn *pe_nextscn(PE *, PE_Scn *);
+PE_Object pe_object(PE *);
+PE_OptHdr *pe_opt_header(PE *);
+PE_RichHdr *pe_rich_header(PE *);
+int pe_rich_header_validate(PE *);
+PE_SecHdr *pe_section_header(PE_Scn *);
+off_t pe_update(PE *);
+int pe_update_coff_header(PE *, PE_CoffHdr *);
+int pe_update_opt_header(PE *, PE_OptHdr *);
+int pe_update_data_dir(PE *, PE_DataDir *);
+int ps_update_msdos_header(PE *, PE_DosHdr *);
+int ps_update_msdos_stub(PE *, char *, size_t);
+int pe_update_section_header(PE_Scn *, PE_SecHdr *);
+int pe_update_symtab(PE *, char *, size_t, unsigned int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_LIBPE_H_ */
diff --git a/contrib/elftoolchain/libpe/libpe_buffer.c b/contrib/elftoolchain/libpe/libpe_buffer.c
new file mode 100644
index 0000000..cc633dd
--- /dev/null
+++ b/contrib/elftoolchain/libpe/libpe_buffer.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: libpe_buffer.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+PE_SecBuf *
+libpe_alloc_buffer(PE_Scn *ps, size_t sz)
+{
+ PE_SecBuf *sb;
+
+ if ((sb = malloc(sizeof(PE_SecBuf))) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ sb->sb_ps = ps;
+ sb->sb_flags = 0;
+ sb->sb_pb.pb_align = 1;
+ sb->sb_pb.pb_off = 0;
+ sb->sb_pb.pb_size = sz;
+ if (sz > 0) {
+ if ((sb->sb_pb.pb_buf = malloc(sz)) == NULL) {
+ free(sb);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ sb->sb_flags |= LIBPE_F_BUFFER_MALLOCED;
+ } else
+ sb->sb_pb.pb_buf = NULL;
+
+ STAILQ_INSERT_TAIL(&ps->ps_b, sb, sb_next);
+
+ return (sb);
+}
+
+void
+libpe_release_buffer(PE_SecBuf *sb)
+{
+ PE_Scn *ps;
+
+ assert(sb != NULL);
+
+ ps = sb->sb_ps;
+
+ STAILQ_REMOVE(&ps->ps_b, sb, _PE_SecBuf, sb_next);
+
+ if (sb->sb_flags & LIBPE_F_BUFFER_MALLOCED)
+ free(sb->sb_pb.pb_buf);
+
+ free(sb);
+}
+
+static int
+cmp_sb(PE_SecBuf *a, PE_SecBuf *b)
+{
+
+ if (a->sb_pb.pb_off < b->sb_pb.pb_off)
+ return (-1);
+ else if (a->sb_pb.pb_off == b->sb_pb.pb_off)
+ return (0);
+ else
+ return (1);
+}
+
+static void
+sort_buffers(PE_Scn *ps)
+{
+
+ if (STAILQ_EMPTY(&ps->ps_b))
+ return;
+
+ STAILQ_SORT(&ps->ps_b, _PE_SecBuf, sb_next, cmp_sb);
+}
+
+size_t
+libpe_resync_buffers(PE_Scn *ps)
+{
+ PE_SecBuf *sb;
+ PE_Buffer *pb;
+ size_t sz;
+
+ assert(ps->ps_flags & LIBPE_F_LOAD_SECTION);
+
+ sort_buffers(ps);
+
+ sz = 0;
+ STAILQ_FOREACH(sb, &ps->ps_b, sb_next) {
+ if (ps->ps_flags & PE_F_DIRTY)
+ sb->sb_flags |= PE_F_DIRTY;
+
+ pb = (PE_Buffer *) sb;
+ if (pb->pb_align > ps->ps_falign)
+ pb->pb_align = ps->ps_falign;
+ if (pb->pb_buf == NULL || pb->pb_size == 0)
+ continue;
+
+ sz = roundup(sz, pb->pb_align);
+
+ if (pb->pb_off != (off_t) sz) {
+ pb->pb_off = sz;
+ sb->sb_flags |= PE_F_DIRTY;
+ }
+ sz += pb->pb_size;
+ }
+
+ return (sz);
+}
+
+int
+libpe_write_buffers(PE_Scn *ps)
+{
+ PE *pe;
+ PE_SecBuf *sb;
+ PE_Buffer *pb;
+ off_t off;
+
+ assert(ps->ps_flags & LIBPE_F_LOAD_SECTION);
+
+ pe = ps->ps_pe;
+
+ off = 0;
+ STAILQ_FOREACH(sb, &ps->ps_b, sb_next) {
+ pb = &sb->sb_pb;
+ if (pb->pb_buf == NULL || pb->pb_size == 0)
+ continue;
+
+ if ((sb->sb_flags & PE_F_DIRTY) == 0) {
+ assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
+ if (lseek(pe->pe_fd, (off_t) pb->pb_size, SEEK_CUR) <
+ 0) {
+ errno = EIO;
+ return (-1);
+ }
+ goto next_buf;
+ }
+
+ if (pb->pb_off > off) {
+ if (libpe_pad(pe, pb->pb_off - off) < 0)
+ return (-1);
+ off = pb->pb_off;
+ }
+
+ if (write(pe->pe_fd, pb->pb_buf, pb->pb_size) !=
+ (ssize_t) pb->pb_size) {
+ errno = EIO;
+ return (-1);
+ }
+
+ next_buf:
+ off += pb->pb_size;
+ }
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/libpe_coff.c b/contrib/elftoolchain/libpe/libpe_coff.c
new file mode 100644
index 0000000..e161f7c
--- /dev/null
+++ b/contrib/elftoolchain/libpe/libpe_coff.c
@@ -0,0 +1,535 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: libpe_coff.c 3326 2016-01-16 17:46:17Z kaiwang27 $");
+
+int
+libpe_parse_coff_header(PE *pe, char *hdr)
+{
+ char tmp[128];
+ PE_CoffHdr *ch;
+ PE_OptHdr *oh;
+ PE_DataDir *dd;
+ unsigned p, r, s;
+ int i;
+
+ if ((ch = malloc(sizeof(PE_CoffHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ PE_READ16(hdr, ch->ch_machine);
+ PE_READ16(hdr, ch->ch_nsec);
+ PE_READ32(hdr, ch->ch_timestamp);
+ PE_READ32(hdr, ch->ch_symptr);
+ PE_READ32(hdr, ch->ch_nsym);
+ PE_READ16(hdr, ch->ch_optsize);
+ PE_READ16(hdr, ch->ch_char);
+
+ pe->pe_ch = ch;
+
+ /*
+ * The Optional header is omitted for object files.
+ */
+ if (ch->ch_optsize == 0)
+ return (libpe_parse_section_headers(pe));
+
+ if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ pe->pe_oh = oh;
+
+#define READ_OPT(n) \
+ do { \
+ /* \
+ * Since the Optional Header size is variable, we must \
+ * check if the requested read size will overrun the \
+ * remaining header bytes. \
+ */ \
+ if (p + (n) > ch->ch_optsize) { \
+ /* Consume the "extra" bytes */ \
+ r = ch->ch_optsize - p; \
+ if (read(pe->pe_fd, tmp, r) != (ssize_t) r) { \
+ pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;\
+ return (0); \
+ } \
+ return (libpe_parse_section_headers(pe)); \
+ } \
+ if (read(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) { \
+ pe->pe_flags |= LIBPE_F_BAD_OPT_HEADER; \
+ return (0); \
+ } \
+ p += (n); \
+ } while (0)
+#define READ_OPT8(v) do { READ_OPT(1); (v) = *tmp; } while(0)
+#define READ_OPT16(v) do { READ_OPT(2); (v) = le16dec(tmp); } while(0)
+#define READ_OPT32(v) do { READ_OPT(4); (v) = le32dec(tmp); } while(0)
+#define READ_OPT64(v) do { READ_OPT(8); (v) = le64dec(tmp); } while(0)
+
+ /*
+ * Read in the Optional header. Size of some fields are depending
+ * on the PE format specified by the oh_magic field. (PE32 or PE32+)
+ */
+
+ p = 0;
+ READ_OPT16(oh->oh_magic);
+ if (oh->oh_magic == PE_FORMAT_32P)
+ pe->pe_obj = PE_O_PE32P;
+ READ_OPT8(oh->oh_ldvermajor);
+ READ_OPT8(oh->oh_ldverminor);
+ READ_OPT32(oh->oh_textsize);
+ READ_OPT32(oh->oh_datasize);
+ READ_OPT32(oh->oh_bsssize);
+ READ_OPT32(oh->oh_entry);
+ READ_OPT32(oh->oh_textbase);
+ if (oh->oh_magic != PE_FORMAT_32P) {
+ READ_OPT32(oh->oh_database);
+ READ_OPT32(oh->oh_imgbase);
+ } else
+ READ_OPT64(oh->oh_imgbase);
+ READ_OPT32(oh->oh_secalign);
+ READ_OPT32(oh->oh_filealign);
+ READ_OPT16(oh->oh_osvermajor);
+ READ_OPT16(oh->oh_osverminor);
+ READ_OPT16(oh->oh_imgvermajor);
+ READ_OPT16(oh->oh_imgverminor);
+ READ_OPT16(oh->oh_subvermajor);
+ READ_OPT16(oh->oh_subverminor);
+ READ_OPT32(oh->oh_win32ver);
+ READ_OPT32(oh->oh_imgsize);
+ READ_OPT32(oh->oh_hdrsize);
+ READ_OPT32(oh->oh_checksum);
+ READ_OPT16(oh->oh_subsystem);
+ READ_OPT16(oh->oh_dllchar);
+ if (oh->oh_magic != PE_FORMAT_32P) {
+ READ_OPT32(oh->oh_stacksizer);
+ READ_OPT32(oh->oh_stacksizec);
+ READ_OPT32(oh->oh_heapsizer);
+ READ_OPT32(oh->oh_heapsizec);
+ } else {
+ READ_OPT64(oh->oh_stacksizer);
+ READ_OPT64(oh->oh_stacksizec);
+ READ_OPT64(oh->oh_heapsizer);
+ READ_OPT64(oh->oh_heapsizec);
+ }
+ READ_OPT32(oh->oh_ldrflags);
+ READ_OPT32(oh->oh_ndatadir);
+
+ /*
+ * Read in the Data Directories.
+ */
+
+ if (oh->oh_ndatadir > 0) {
+ if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ pe->pe_dd = dd;
+
+ dd->dd_total = oh->oh_ndatadir < PE_DD_MAX ? oh->oh_ndatadir :
+ PE_DD_MAX;
+
+ for (i = 0; (uint32_t) i < dd->dd_total; i++) {
+ READ_OPT32(dd->dd_e[i].de_addr);
+ READ_OPT32(dd->dd_e[i].de_size);
+ }
+ }
+
+ /* Consume the remaining bytes in the Optional header, if any. */
+ if (ch->ch_optsize > p) {
+ r = ch->ch_optsize - p;
+ for (; r > 0; r -= s) {
+ s = r > sizeof(tmp) ? sizeof(tmp) : r;
+ if (read(pe->pe_fd, tmp, s) != (ssize_t) s) {
+ pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
+ return (0);
+ }
+ }
+ }
+
+ return (libpe_parse_section_headers(pe));
+}
+
+off_t
+libpe_write_pe_header(PE *pe, off_t off)
+{
+ char tmp[4];
+
+ if (pe->pe_cmd == PE_C_RDWR &&
+ (pe->pe_flags & LIBPE_F_BAD_PE_HEADER) == 0) {
+ assert(pe->pe_dh != NULL);
+ off = lseek(pe->pe_fd, (off_t) pe->pe_dh->dh_lfanew + 4,
+ SEEK_SET);
+ return (off);
+ }
+
+ /*
+ * PE Header should to be aligned on 8-byte boundary according to
+ * the PE/COFF specification.
+ */
+ if ((off = libpe_align(pe, off, 8)) < 0)
+ return (-1);
+
+ le32enc(tmp, PE_SIGNATURE);
+ if (write(pe->pe_fd, tmp, sizeof(tmp)) != (ssize_t) sizeof(tmp)) {
+ errno = EIO;
+ return (-1);
+ }
+
+ off += 4;
+
+ pe->pe_flags &= ~LIBPE_F_BAD_PE_HEADER;
+
+ /* Trigger rewrite for the following headers. */
+ pe->pe_flags |= LIBPE_F_DIRTY_COFF_HEADER;
+ pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
+
+ return (off);
+}
+
+off_t
+libpe_write_coff_header(PE *pe, off_t off)
+{
+ char tmp[128], *hdr;
+ PE_CoffHdr *ch;
+ PE_DataDir *dd;
+ PE_OptHdr *oh;
+ PE_Scn *ps;
+ PE_SecHdr *sh;
+ unsigned p;
+ uint32_t reloc_rva, reloc_sz;
+ int i, reloc;
+
+ reloc = 0;
+ reloc_rva = reloc_sz = 0;
+
+ if (pe->pe_cmd == PE_C_RDWR) {
+ assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
+
+ if ((pe->pe_flags & LIBPE_F_DIRTY_COFF_HEADER) == 0 &&
+ (pe->pe_flags & LIBPE_F_BAD_COFF_HEADER) == 0) {
+ if (lseek(pe->pe_fd, (off_t) sizeof(PE_CoffHdr),
+ SEEK_CUR) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ off += sizeof(PE_CoffHdr);
+ assert(pe->pe_ch != NULL);
+ ch = pe->pe_ch;
+ goto coff_done;
+ }
+
+ /* lseek(2) to the offset of the COFF header. */
+ if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+
+ if (pe->pe_ch == NULL) {
+ if ((ch = calloc(1, sizeof(PE_CoffHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ pe->pe_ch = ch;
+
+ /*
+ * Default value for ch_machine if not provided by the
+ * application.
+ */
+ if (pe->pe_obj == PE_O_PE32P)
+ ch->ch_machine = IMAGE_FILE_MACHINE_AMD64;
+ else
+ ch->ch_machine = IMAGE_FILE_MACHINE_I386;
+
+ } else
+ ch = pe->pe_ch;
+
+ if (!ch->ch_timestamp)
+ ch->ch_timestamp = time(NULL);
+
+ if (pe->pe_obj == PE_O_PE32) {
+ if (!ch->ch_optsize)
+ ch->ch_optsize = PE_COFF_OPT_SIZE_32;
+ ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
+ IMAGE_FILE_32BIT_MACHINE;
+ } else if (pe->pe_obj == PE_O_PE32P) {
+ if (!ch->ch_optsize)
+ ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
+ ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
+ IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ } else
+ ch->ch_optsize = 0;
+
+ /*
+ * COFF line number is deprecated by the PE/COFF
+ * specification. COFF symbol table is deprecated
+ * for executables.
+ */
+ ch->ch_char |= IMAGE_FILE_LINE_NUMS_STRIPPED;
+ if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P)
+ ch->ch_char |= IMAGE_FILE_LOCAL_SYMS_STRIPPED;
+
+ ch->ch_nsec = pe->pe_nscn;
+
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ sh = &ps->ps_sh;
+
+ if (ps->ps_ndx == 0xFFFFFFFFU) {
+ ch->ch_symptr = sh->sh_rawptr;
+ ch->ch_nsym = pe->pe_nsym;
+ }
+
+ if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P) {
+ if (ps->ps_ndx == (0xFFFF0000 | PE_DD_BASERELOC) ||
+ strncmp(sh->sh_name, ".reloc", strlen(".reloc")) ==
+ 0) {
+ reloc = 1;
+ reloc_rva = sh->sh_addr;
+ reloc_sz = sh->sh_virtsize;
+ }
+ }
+ }
+
+ if (!reloc)
+ ch->ch_char |= IMAGE_FILE_RELOCS_STRIPPED;
+
+ if (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) {
+ if (pe->pe_obj == PE_O_PE32)
+ ch->ch_optsize = PE_COFF_OPT_SIZE_32;
+ else if (pe->pe_obj == PE_O_PE32P)
+ ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
+ else
+ ch->ch_optsize = 0;
+ }
+
+ /*
+ * Write the COFF header.
+ */
+ hdr = tmp;
+ PE_WRITE16(hdr, ch->ch_machine);
+ PE_WRITE16(hdr, ch->ch_nsec);
+ PE_WRITE32(hdr, ch->ch_timestamp);
+ PE_WRITE32(hdr, ch->ch_symptr);
+ PE_WRITE32(hdr, ch->ch_nsym);
+ PE_WRITE16(hdr, ch->ch_optsize);
+ PE_WRITE16(hdr, ch->ch_char);
+ if (write(pe->pe_fd, tmp, sizeof(PE_CoffHdr)) !=
+ (ssize_t) sizeof(PE_CoffHdr)) {
+ errno = EIO;
+ return (-1);
+ }
+
+coff_done:
+ off += sizeof(PE_CoffHdr);
+ pe->pe_flags &= ~LIBPE_F_DIRTY_COFF_HEADER;
+ pe->pe_flags &= ~LIBPE_F_BAD_COFF_HEADER;
+ pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
+
+ if (ch->ch_optsize == 0)
+ return (off);
+
+ /*
+ * Write the Optional header.
+ */
+
+ if (pe->pe_cmd == PE_C_RDWR) {
+ if ((pe->pe_flags & LIBPE_F_DIRTY_OPT_HEADER) == 0 &&
+ (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) == 0) {
+ if (lseek(pe->pe_fd, (off_t) ch->ch_optsize,
+ SEEK_CUR) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ off += ch->ch_optsize;
+ return (off);
+ }
+
+ }
+
+ if (pe->pe_oh == NULL) {
+ if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ pe->pe_oh = oh;
+ } else
+ oh = pe->pe_oh;
+
+ if (pe->pe_obj == PE_O_PE32)
+ oh->oh_magic = PE_FORMAT_32;
+ else
+ oh->oh_magic = PE_FORMAT_32P;
+
+ /*
+ * LinkerVersion should not be less than 2.5, which will cause
+ * Windows to complain the executable is invalid in some case.
+ * By default we set LinkerVersion to 2.22 (binutils 2.22)
+ */
+ if (!oh->oh_ldvermajor && !oh->oh_ldverminor) {
+ oh->oh_ldvermajor = 2;
+ oh->oh_ldverminor = 22;
+ }
+
+ /*
+ * The library always tries to write out all 16 data directories
+ * but the actual data dir written will depend on ch_optsize.
+ */
+ oh->oh_ndatadir = PE_DD_MAX;
+
+ if (!oh->oh_filealign)
+ oh->oh_filealign = 0x200;
+ if (!oh->oh_secalign)
+ oh->oh_secalign = 0x1000;
+ oh->oh_hdrsize = roundup(off + ch->ch_optsize + pe->pe_nscn *
+ sizeof(PE_SecHdr), oh->oh_filealign);
+ oh->oh_imgsize = roundup(pe->pe_rvamax, oh->oh_secalign);
+
+#define WRITE_OPT(n) \
+ do { \
+ /* \
+ * Since the Optional Header size is variable, we must \
+ * check if the requested write size will overrun the \
+ * remaining header bytes. \
+ */ \
+ if (p + (n) > ch->ch_optsize) { \
+ /* Pad the "extra" bytes */ \
+ if (libpe_pad(pe, ch->ch_optsize - p) < 0) { \
+ errno = EIO; \
+ return (-1); \
+ } \
+ goto opt_done; \
+ } \
+ if (write(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) { \
+ errno = EIO; \
+ return (-1); \
+ } \
+ p += (n); \
+ } while (0)
+#define WRITE_OPT8(v) do { *tmp = (v); WRITE_OPT(1); } while(0)
+#define WRITE_OPT16(v) do { le16enc(tmp, (v)); WRITE_OPT(2); } while(0)
+#define WRITE_OPT32(v) do { le32enc(tmp, (v)); WRITE_OPT(4); } while(0)
+#define WRITE_OPT64(v) do { le64enc(tmp, (v)); WRITE_OPT(8); } while(0)
+
+ p = 0;
+ WRITE_OPT16(oh->oh_magic);
+ if (oh->oh_magic == PE_FORMAT_32P)
+ pe->pe_obj = PE_O_PE32P;
+ WRITE_OPT8(oh->oh_ldvermajor);
+ WRITE_OPT8(oh->oh_ldverminor);
+ WRITE_OPT32(oh->oh_textsize);
+ WRITE_OPT32(oh->oh_datasize);
+ WRITE_OPT32(oh->oh_bsssize);
+ WRITE_OPT32(oh->oh_entry);
+ WRITE_OPT32(oh->oh_textbase);
+ if (oh->oh_magic != PE_FORMAT_32P) {
+ WRITE_OPT32(oh->oh_database);
+ WRITE_OPT32(oh->oh_imgbase);
+ } else
+ WRITE_OPT64(oh->oh_imgbase);
+ WRITE_OPT32(oh->oh_secalign);
+ WRITE_OPT32(oh->oh_filealign);
+ WRITE_OPT16(oh->oh_osvermajor);
+ WRITE_OPT16(oh->oh_osverminor);
+ WRITE_OPT16(oh->oh_imgvermajor);
+ WRITE_OPT16(oh->oh_imgverminor);
+ WRITE_OPT16(oh->oh_subvermajor);
+ WRITE_OPT16(oh->oh_subverminor);
+ WRITE_OPT32(oh->oh_win32ver);
+ WRITE_OPT32(oh->oh_imgsize);
+ WRITE_OPT32(oh->oh_hdrsize);
+ WRITE_OPT32(oh->oh_checksum);
+ WRITE_OPT16(oh->oh_subsystem);
+ WRITE_OPT16(oh->oh_dllchar);
+ if (oh->oh_magic != PE_FORMAT_32P) {
+ WRITE_OPT32(oh->oh_stacksizer);
+ WRITE_OPT32(oh->oh_stacksizec);
+ WRITE_OPT32(oh->oh_heapsizer);
+ WRITE_OPT32(oh->oh_heapsizec);
+ } else {
+ WRITE_OPT64(oh->oh_stacksizer);
+ WRITE_OPT64(oh->oh_stacksizec);
+ WRITE_OPT64(oh->oh_heapsizer);
+ WRITE_OPT64(oh->oh_heapsizec);
+ }
+ WRITE_OPT32(oh->oh_ldrflags);
+ WRITE_OPT32(oh->oh_ndatadir);
+
+ /*
+ * Write the Data Directories.
+ */
+
+ if (oh->oh_ndatadir > 0) {
+ if (pe->pe_dd == NULL) {
+ if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ pe->pe_dd = dd;
+ dd->dd_total = PE_DD_MAX;
+ } else
+ dd = pe->pe_dd;
+
+ assert(oh->oh_ndatadir <= PE_DD_MAX);
+
+ if (reloc) {
+ dd->dd_e[PE_DD_BASERELOC].de_addr = reloc_rva;
+ dd->dd_e[PE_DD_BASERELOC].de_size = reloc_sz;
+ }
+
+ for (i = 0; (uint32_t) i < dd->dd_total; i++) {
+ WRITE_OPT32(dd->dd_e[i].de_addr);
+ WRITE_OPT32(dd->dd_e[i].de_size);
+ }
+ }
+
+ /* Pad the remaining bytes in the Optional header, if any. */
+ if (ch->ch_optsize > p) {
+ if (libpe_pad(pe, ch->ch_optsize - p) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+
+opt_done:
+ off += ch->ch_optsize;
+ pe->pe_flags &= ~LIBPE_F_DIRTY_OPT_HEADER;
+ pe->pe_flags &= ~LIBPE_F_BAD_OPT_HEADER;
+ pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
+
+ return (off);
+}
diff --git a/contrib/elftoolchain/libpe/libpe_dos.c b/contrib/elftoolchain/libpe/libpe_dos.c
new file mode 100644
index 0000000..a48ad12
--- /dev/null
+++ b/contrib/elftoolchain/libpe/libpe_dos.c
@@ -0,0 +1,403 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: libpe_dos.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+int
+libpe_parse_msdos_header(PE *pe, char *hdr)
+{
+ PE_DosHdr *dh;
+ char coff[sizeof(PE_CoffHdr)];
+ uint32_t pe_magic;
+ int i;
+
+ if ((pe->pe_stub = malloc(sizeof(PE_DosHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memcpy(pe->pe_stub, hdr, sizeof(PE_DosHdr));
+
+ if ((dh = malloc(sizeof(*dh))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ pe->pe_dh = dh;
+
+ /* Read the conventional MS-DOS EXE header. */
+ memcpy(dh->dh_magic, hdr, 2);
+ hdr += 2;
+ PE_READ16(hdr, dh->dh_lastsize);
+ PE_READ16(hdr, dh->dh_nblock);
+ PE_READ16(hdr, dh->dh_nreloc);
+ PE_READ16(hdr, dh->dh_hdrsize);
+ PE_READ16(hdr, dh->dh_minalloc);
+ PE_READ16(hdr, dh->dh_maxalloc);
+ PE_READ16(hdr, dh->dh_ss);
+ PE_READ16(hdr, dh->dh_sp);
+ PE_READ16(hdr, dh->dh_checksum);
+ PE_READ16(hdr, dh->dh_ip);
+ PE_READ16(hdr, dh->dh_cs);
+ PE_READ16(hdr, dh->dh_relocpos);
+ PE_READ16(hdr, dh->dh_noverlay);
+
+ /* Do not continue if the EXE is not a PE/NE/... (new executable) */
+ if (dh->dh_relocpos != 0x40) {
+ pe->pe_flags |= LIBPE_F_BAD_DOS_HEADER;
+ return (0);
+ }
+
+ for (i = 0; i < 4; i++)
+ PE_READ16(hdr, dh->dh_reserved1[i]);
+ PE_READ16(hdr, dh->dh_oemid);
+ PE_READ16(hdr, dh->dh_oeminfo);
+ for (i = 0; i < 10; i++)
+ PE_READ16(hdr, dh->dh_reserved2[i]);
+ PE_READ32(hdr, dh->dh_lfanew);
+
+ /* Check if the e_lfanew pointer is valid. */
+ if (dh->dh_lfanew > pe->pe_fsize - 4) {
+ pe->pe_flags |= LIBPE_F_BAD_DOS_HEADER;
+ return (0);
+ }
+
+ if (dh->dh_lfanew < sizeof(PE_DosHdr) &&
+ (pe->pe_flags & LIBPE_F_SPECIAL_FILE)) {
+ pe->pe_flags |= LIBPE_F_BAD_DOS_HEADER;
+ return (0);
+ }
+
+ if (dh->dh_lfanew > sizeof(PE_DosHdr)) {
+ pe->pe_stub_ex = dh->dh_lfanew - sizeof(PE_DosHdr);
+ if (pe->pe_flags & LIBPE_F_SPECIAL_FILE) {
+ /* Read in DOS stub now. */
+ if (libpe_read_msdos_stub(pe) < 0) {
+ pe->pe_flags |= LIBPE_F_BAD_DOS_HEADER;
+ return (0);
+ }
+ }
+ }
+
+ if ((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0) {
+ /* Jump to the PE header. */
+ if (lseek(pe->pe_fd, (off_t) dh->dh_lfanew, SEEK_SET) < 0) {
+ pe->pe_flags |= LIBPE_F_BAD_PE_HEADER;
+ return (0);
+ }
+ }
+
+ if (read(pe->pe_fd, &pe_magic, 4) != 4 ||
+ htole32(pe_magic) != PE_SIGNATURE) {
+ pe->pe_flags |= LIBPE_F_BAD_PE_HEADER;
+ return (0);
+ }
+
+ if (read(pe->pe_fd, coff, sizeof(coff)) != (ssize_t) sizeof(coff)) {
+ pe->pe_flags |= LIBPE_F_BAD_COFF_HEADER;
+ return (0);
+ }
+
+ return (libpe_parse_coff_header(pe, coff));
+}
+
+int
+libpe_read_msdos_stub(PE *pe)
+{
+ void *m;
+
+ assert(pe->pe_stub_ex > 0 &&
+ (pe->pe_flags & LIBPE_F_LOAD_DOS_STUB) == 0);
+
+ if ((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0) {
+ if (lseek(pe->pe_fd, (off_t) sizeof(PE_DosHdr), SEEK_SET) <
+ 0) {
+ errno = EIO;
+ goto fail;
+ }
+ }
+
+ if ((m = realloc(pe->pe_stub, sizeof(PE_DosHdr) + pe->pe_stub_ex)) ==
+ NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+ pe->pe_stub = m;
+
+ if (read(pe->pe_fd, pe->pe_stub + sizeof(PE_DosHdr), pe->pe_stub_ex) !=
+ (ssize_t) pe->pe_stub_ex) {
+ errno = EIO;
+ goto fail;
+ }
+
+ pe->pe_flags |= LIBPE_F_LOAD_DOS_STUB;
+
+ /* Search for the Rich header embedded just before the PE header. */
+ (void) libpe_parse_rich_header(pe);
+
+ return (0);
+
+fail:
+ pe->pe_stub_ex = 0;
+
+ return (-1);
+}
+
+/*
+ * The "standard" MS-DOS stub displaying "This program cannot be run in
+ * DOS mode".
+ */
+static const char msdos_stub[] = {
+ '\x0e','\x1f','\xba','\x0e','\x00','\xb4','\x09','\xcd',
+ '\x21','\xb8','\x01','\x4c','\xcd','\x21','\x54','\x68',
+ '\x69','\x73','\x20','\x70','\x72','\x6f','\x67','\x72',
+ '\x61','\x6d','\x20','\x63','\x61','\x6e','\x6e','\x6f',
+ '\x74','\x20','\x62','\x65','\x20','\x72','\x75','\x6e',
+ '\x20','\x69','\x6e','\x20','\x44','\x4f','\x53','\x20',
+ '\x6d','\x6f','\x64','\x65','\x2e','\x0d','\x0d','\x0a',
+ '\x24','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
+};
+
+static void
+init_dos_header(PE_DosHdr *dh)
+{
+
+ dh->dh_magic[0] = 'M';
+ dh->dh_magic[1] = 'Z';
+ dh->dh_lastsize = 144;
+ dh->dh_nblock = 3;
+ dh->dh_hdrsize = 4;
+ dh->dh_maxalloc = 65535;
+ dh->dh_sp = 184;
+ dh->dh_relocpos = 0x40;
+ dh->dh_lfanew = 0x80;
+}
+
+off_t
+libpe_write_msdos_stub(PE *pe, off_t off)
+{
+ PE_DosHdr *dh;
+ char tmp[sizeof(PE_DosHdr)], *hdr;
+ off_t d;
+ int i, strip_rich;
+
+ strip_rich = 0;
+
+ if (pe->pe_cmd == PE_C_RDWR) {
+ assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
+
+ if (pe->pe_dh != NULL &&
+ (pe->pe_flags & PE_F_STRIP_DOS_STUB)) {
+ /*
+ * If we strip MS-DOS stub, everything after it
+ * needs rewritten.
+ */
+ pe->pe_flags |= LIBPE_F_BAD_PE_HEADER;
+ goto done;
+ }
+
+ /*
+ * lseek(2) to the PE signature if MS-DOS stub is not
+ * modified.
+ */
+ if (pe->pe_dh != NULL &&
+ (pe->pe_flags & LIBPE_F_DIRTY_DOS_HEADER) == 0 &&
+ (pe->pe_flags & LIBPE_F_BAD_DOS_HEADER) == 0 &&
+ (pe->pe_flags & PE_F_STRIP_RICH_HEADER) == 0) {
+ if (lseek(pe->pe_fd,
+ (off_t) (sizeof(PE_DosHdr) + pe->pe_stub_ex),
+ SEEK_CUR) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ off = sizeof(PE_DosHdr) + pe->pe_stub_ex;
+ goto done;
+ }
+
+ /* Check if we should strip the Rich header. */
+ if (pe->pe_dh != NULL && pe->pe_stub_app == NULL &&
+ (pe->pe_flags & LIBPE_F_BAD_DOS_HEADER) == 0 &&
+ (pe->pe_flags & PE_F_STRIP_RICH_HEADER)) {
+ if ((pe->pe_flags & LIBPE_F_LOAD_DOS_STUB) == 0) {
+ (void) libpe_read_msdos_stub(pe);
+ if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+ if (pe->pe_rh != NULL) {
+ strip_rich = 1;
+ pe->pe_flags |= LIBPE_F_DIRTY_DOS_HEADER;
+ }
+ }
+
+ /*
+ * If length of MS-DOS stub will change, Mark the PE
+ * signature is broken so that the PE signature and the
+ * headers follow it will be rewritten.
+ *
+ * The sections should be loaded now since the stub might
+ * overwrite the section data.
+ */
+ if ((pe->pe_flags & LIBPE_F_BAD_DOS_HEADER) ||
+ (pe->pe_stub_app != NULL && pe->pe_stub_app_sz !=
+ sizeof(PE_DosHdr) + pe->pe_stub_ex) || strip_rich) {
+ if (libpe_load_all_sections(pe) < 0)
+ return (-1);
+ if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ pe->pe_flags |= LIBPE_F_BAD_PE_HEADER;
+ }
+ }
+
+ if (pe->pe_flags & PE_F_STRIP_DOS_STUB)
+ goto done;
+
+ /* Always use application supplied MS-DOS stub, if exists. */
+ if (pe->pe_stub_app != NULL && pe->pe_stub_app_sz > 0) {
+ if (write(pe->pe_fd, pe->pe_stub_app, pe->pe_stub_app_sz) !=
+ (ssize_t) pe->pe_stub_app_sz) {
+ errno = EIO;
+ return (-1);
+ }
+ off = pe->pe_stub_app_sz;
+ goto done;
+ }
+
+ /*
+ * Write MS-DOS header.
+ */
+
+ if (pe->pe_dh == NULL) {
+ if ((dh = calloc(1, sizeof(PE_DosHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ pe->pe_dh = dh;
+
+ init_dos_header(dh);
+
+ pe->pe_flags |= LIBPE_F_DIRTY_DOS_HEADER;
+ } else
+ dh = pe->pe_dh;
+
+ if (pe->pe_flags & LIBPE_F_BAD_DOS_HEADER)
+ init_dos_header(dh);
+
+ if (strip_rich) {
+ d = pe->pe_rh_start - pe->pe_stub;
+ dh->dh_lfanew = roundup(d, 8);
+ }
+
+ if ((pe->pe_flags & LIBPE_F_DIRTY_DOS_HEADER) ||
+ (pe->pe_flags & LIBPE_F_BAD_DOS_HEADER)) {
+ memcpy(tmp, dh->dh_magic, 2);
+ hdr = tmp + 2;
+ PE_WRITE16(hdr, dh->dh_lastsize);
+ PE_WRITE16(hdr, dh->dh_nblock);
+ PE_WRITE16(hdr, dh->dh_nreloc);
+ PE_WRITE16(hdr, dh->dh_hdrsize);
+ PE_WRITE16(hdr, dh->dh_minalloc);
+ PE_WRITE16(hdr, dh->dh_maxalloc);
+ PE_WRITE16(hdr, dh->dh_ss);
+ PE_WRITE16(hdr, dh->dh_sp);
+ PE_WRITE16(hdr, dh->dh_checksum);
+ PE_WRITE16(hdr, dh->dh_ip);
+ PE_WRITE16(hdr, dh->dh_cs);
+ PE_WRITE16(hdr, dh->dh_relocpos);
+ PE_WRITE16(hdr, dh->dh_noverlay);
+ for (i = 0; i < 4; i++)
+ PE_WRITE16(hdr, dh->dh_reserved1[i]);
+ PE_WRITE16(hdr, dh->dh_oemid);
+ PE_WRITE16(hdr, dh->dh_oeminfo);
+ for (i = 0; i < 10; i++)
+ PE_WRITE16(hdr, dh->dh_reserved2[i]);
+ PE_WRITE32(hdr, dh->dh_lfanew);
+
+ if (write(pe->pe_fd, tmp, sizeof(tmp)) !=
+ (ssize_t) sizeof(tmp)) {
+ errno = EIO;
+ return (-1);
+ }
+ } else {
+ assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
+ if (lseek(pe->pe_fd, (off_t) sizeof(PE_DosHdr), SEEK_CUR) <
+ 0) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+
+ off = sizeof(PE_DosHdr);
+
+ /*
+ * Write the MS-DOS stub.
+ */
+
+ if (strip_rich) {
+ assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
+ assert(pe->pe_stub != NULL && pe->pe_rh_start != NULL);
+ d = pe->pe_rh_start - pe->pe_stub;
+ if (lseek(pe->pe_fd, d, SEEK_SET) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ off = d;
+ goto done;
+ }
+
+ if (pe->pe_cmd == PE_C_RDWR) {
+ if (lseek(pe->pe_fd, (off_t) pe->pe_stub_ex, SEEK_CUR) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ off += pe->pe_stub_ex;
+ goto done;
+ }
+
+ if (write(pe->pe_fd, msdos_stub, sizeof(msdos_stub)) !=
+ (ssize_t) sizeof(msdos_stub)) {
+ errno = EIO;
+ return (-1);
+ }
+ off += sizeof(msdos_stub);
+
+done:
+ pe->pe_flags &= ~LIBPE_F_DIRTY_DOS_HEADER;
+ pe->pe_flags &= ~LIBPE_F_BAD_DOS_HEADER;
+
+ return (off);
+}
diff --git a/contrib/elftoolchain/libpe/libpe_init.c b/contrib/elftoolchain/libpe/libpe_init.c
new file mode 100644
index 0000000..2579774
--- /dev/null
+++ b/contrib/elftoolchain/libpe/libpe_init.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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.
+ */
+
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: libpe_init.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+int
+libpe_open_object(PE *pe)
+{
+ struct stat sb;
+ mode_t mode;
+ char magic[sizeof(PE_DosHdr)];
+
+ if (fstat(pe->pe_fd, &sb) < 0)
+ return (-1);
+
+ mode = sb.st_mode;
+ pe->pe_fsize = (size_t) sb.st_size;
+
+ /* Reject unsupported file types. */
+ if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) &&
+ !S_ISSOCK(mode)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Read/Write mode is not supported for non-regular file. */
+ if (pe->pe_cmd == PE_C_RDWR && !S_ISREG(mode)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* The minimal file should at least contain a COFF header. */
+ if (S_ISREG(mode) && pe->pe_fsize < sizeof(PE_CoffHdr)) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /*
+ * Search for MS-DOS header or COFF header.
+ */
+
+ if (read(pe->pe_fd, magic, 2) != 2) {
+ errno = EIO;
+ return (-1);
+ }
+
+ if (magic[0] == 'M' && magic[1] == 'Z') {
+ pe->pe_obj = PE_O_PE32;
+ if (read(pe->pe_fd, &magic[2], sizeof(PE_DosHdr) - 2) !=
+ (ssize_t) sizeof(PE_DosHdr) - 2) {
+ errno = EIO;
+ return (-1);
+ }
+ return (libpe_parse_msdos_header(pe, magic));
+
+ } else if (magic[0] == 'P' && magic[1] == 'E') {
+ if (read(pe->pe_fd, magic, 2) != 2) {
+ errno = EIO;
+ return (-1);
+ }
+ if (magic[0] == '\0' && magic[1] == '\0') {
+ pe->pe_obj = PE_O_PE32;
+ if (read(pe->pe_fd, magic, sizeof(PE_CoffHdr)) !=
+ (ssize_t) sizeof(PE_CoffHdr)) {
+ errno = EIO;
+ return (-1);
+ }
+ return (libpe_parse_coff_header(pe, magic));
+ }
+ errno = ENOENT;
+ return (-1);
+
+ } else {
+ pe->pe_obj = PE_O_COFF;
+ if (read(pe->pe_fd, &magic[2], sizeof(PE_CoffHdr) - 2) !=
+ (ssize_t) sizeof(PE_CoffHdr) - 2) {
+ errno = EIO;
+ return (-1);
+ }
+ return (libpe_parse_coff_header(pe, magic));
+ }
+}
+
+void
+libpe_release_object(PE *pe)
+{
+ PE_Scn *ps, *_ps;
+
+ if (pe->pe_dh)
+ free(pe->pe_dh);
+
+ if (pe->pe_rh) {
+ free(pe->pe_rh->rh_compid);
+ free(pe->pe_rh->rh_cnt);
+ free(pe->pe_rh);
+ }
+
+ if (pe->pe_ch)
+ free(pe->pe_ch);
+
+ if (pe->pe_oh)
+ free(pe->pe_oh);
+
+ if (pe->pe_dd)
+ free(pe->pe_dd);
+
+ if (pe->pe_stub)
+ free(pe->pe_stub);
+
+ STAILQ_FOREACH_SAFE(ps, &pe->pe_scn, ps_next, _ps)
+ libpe_release_scn(ps);
+
+ free(pe);
+}
diff --git a/contrib/elftoolchain/libpe/libpe_rich.c b/contrib/elftoolchain/libpe/libpe_rich.c
new file mode 100644
index 0000000..4669a22
--- /dev/null
+++ b/contrib/elftoolchain/libpe/libpe_rich.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: libpe_rich.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+static char *
+memfind(char *s, const char *find, size_t slen, size_t flen)
+{
+ int i;
+
+ if (slen == 0 || flen == 0 || flen > slen)
+ return (NULL);
+
+ for (i = 0; (size_t) i <= slen - flen; i++) {
+ if (s[i] != find[0])
+ continue;
+ if (flen == 1)
+ return (&s[i]);
+ if (memcmp(&s[i + 1], &find[1], flen - 1) == 0)
+ return (&s[i]);
+ }
+
+ return (NULL);
+}
+
+int
+libpe_parse_rich_header(PE *pe)
+{
+ PE_RichHdr *rh;
+ char *p, *r, *s;
+ uint32_t x;
+ int found, i;
+
+ assert(pe->pe_stub != NULL && pe->pe_stub_ex > 0);
+
+ /* Search for the "Rich" keyword to locate the Rich header. */
+ s = pe->pe_stub + sizeof(PE_DosHdr);
+ r = memfind(s, PE_RICH_TEXT, pe->pe_stub_ex, 4);
+ if (r == NULL || r + 8 > s + pe->pe_stub_ex) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ if ((rh = calloc(1, sizeof(*rh))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ rh->rh_xor = le32dec(r + 4); /* Retrieve the "XOR mask" */
+
+ /*
+ * Search for the hidden keyword "DanS" by XOR the dwords before
+ * the "Rich" keyword with the XOR mask.
+ */
+ found = 0;
+ for (p = r - 4; p >= s; p -= 4) {
+ x = le32dec(p) ^ rh->rh_xor;
+ if (x == PE_RICH_HIDDEN) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ free(rh);
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /*
+ * Found the "DanS" keyword, which is the start of the Rich header.
+ * The next step is to skip the first 16 bytes (DanS, XOR mask,
+ * XOR mask, XOR mask) and read the (compid,cnt) tuples.
+ */
+ pe->pe_rh_start = p;
+ p += 16;
+ rh->rh_total = (r - p) / 8;
+ if ((rh->rh_compid = malloc(rh->rh_total * sizeof(*rh->rh_compid))) ==
+ NULL) {
+ free(rh);
+ errno = ENOMEM;
+ return (-1);
+ }
+ if ((rh->rh_cnt = malloc(rh->rh_total * sizeof(*rh->rh_cnt))) ==
+ NULL) {
+ free(rh->rh_compid);
+ free(rh);
+ errno = ENOMEM;
+ return (-1);
+ }
+ for (i = 0; (uint32_t) i < rh->rh_total; i++, p += 8) {
+ rh->rh_compid[i] = le32dec(p) ^ rh->rh_xor;
+ rh->rh_cnt[i] = le32dec(p + 4) ^ rh->rh_xor;
+ }
+
+ pe->pe_rh = rh;
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/libpe_section.c b/contrib/elftoolchain/libpe/libpe_section.c
new file mode 100644
index 0000000..7ff63fb
--- /dev/null
+++ b/contrib/elftoolchain/libpe/libpe_section.c
@@ -0,0 +1,518 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: libpe_section.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+PE_Scn *
+libpe_alloc_scn(PE *pe)
+{
+ PE_Scn *ps;
+
+ if ((ps = calloc(1, sizeof(PE_Scn))) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ STAILQ_INIT(&ps->ps_b);
+ ps->ps_pe = pe;
+
+ return (ps);
+}
+
+void
+libpe_release_scn(PE_Scn *ps)
+{
+ PE *pe;
+ PE_SecBuf *sb, *_sb;
+
+ assert(ps != NULL);
+
+ pe = ps->ps_pe;
+
+ STAILQ_REMOVE(&pe->pe_scn, ps, _PE_Scn, ps_next);
+
+ STAILQ_FOREACH_SAFE(sb, &ps->ps_b, sb_next, _sb)
+ libpe_release_buffer(sb);
+
+ free(ps);
+}
+
+static int
+cmp_scn(PE_Scn *a, PE_Scn *b)
+{
+
+ if (a->ps_sh.sh_addr < b->ps_sh.sh_addr)
+ return (-1);
+ else if (a->ps_sh.sh_addr == b->ps_sh.sh_addr)
+ return (0);
+ else
+ return (1);
+}
+
+static void
+sort_sections(PE *pe)
+{
+
+ if (STAILQ_EMPTY(&pe->pe_scn))
+ return;
+
+ /* Sort the list of Scn by RVA in ascending order. */
+ STAILQ_SORT(&pe->pe_scn, _PE_Scn, ps_next, cmp_scn);
+}
+
+int
+libpe_parse_section_headers(PE *pe)
+{
+ char tmp[sizeof(PE_SecHdr)], *hdr;
+ PE_Scn *ps;
+ PE_SecHdr *sh;
+ PE_CoffHdr *ch;
+ PE_DataDir *dd;
+ int found, i;
+
+ assert(pe->pe_ch != NULL);
+
+ for (i = 0; (uint16_t) i < pe->pe_ch->ch_nsec; i++) {
+ if (read(pe->pe_fd, tmp, sizeof(PE_SecHdr)) !=
+ (ssize_t) sizeof(PE_SecHdr)) {
+ pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
+ return (0);
+ }
+
+ if ((ps = libpe_alloc_scn(pe)) == NULL)
+ return (-1);
+ STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
+ ps->ps_ndx = ++pe->pe_nscn; /* Setion index is 1-based */
+ sh = &ps->ps_sh;
+
+ /*
+ * Note that the section name won't be NUL-terminated if
+ * its length happens to be 8.
+ */
+ memcpy(sh->sh_name, tmp, sizeof(sh->sh_name));
+ hdr = tmp + 8;
+ PE_READ32(hdr, sh->sh_virtsize);
+ PE_READ32(hdr, sh->sh_addr);
+ PE_READ32(hdr, sh->sh_rawsize);
+ PE_READ32(hdr, sh->sh_rawptr);
+ PE_READ32(hdr, sh->sh_relocptr);
+ PE_READ32(hdr, sh->sh_lineptr);
+ PE_READ16(hdr, sh->sh_nreloc);
+ PE_READ16(hdr, sh->sh_nline);
+ PE_READ32(hdr, sh->sh_char);
+ }
+
+ /*
+ * For all the data directories that don't belong to any section,
+ * we create pseudo sections for them to make layout easier.
+ */
+ dd = pe->pe_dd;
+ if (dd != NULL && dd->dd_total > 0) {
+ for (i = 0; (uint32_t) i < pe->pe_dd->dd_total; i++) {
+ if (dd->dd_e[i].de_size == 0)
+ continue;
+ found = 0;
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ sh = &ps->ps_sh;
+ if (dd->dd_e[i].de_addr >= sh->sh_addr &&
+ dd->dd_e[i].de_addr + dd->dd_e[i].de_size <=
+ sh->sh_addr + sh->sh_virtsize) {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ if ((ps = libpe_alloc_scn(pe)) == NULL)
+ return (-1);
+ STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
+ ps->ps_ndx = 0xFFFF0000U | i;
+ sh = &ps->ps_sh;
+ sh->sh_rawptr = dd->dd_e[i].de_addr; /* FIXME */
+ sh->sh_rawsize = dd->dd_e[i].de_size;
+ }
+ }
+
+ /*
+ * Also consider the COFF symbol table as a pseudo section.
+ */
+ ch = pe->pe_ch;
+ if (ch->ch_nsym > 0) {
+ if ((ps = libpe_alloc_scn(pe)) == NULL)
+ return (-1);
+ STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
+ ps->ps_ndx = 0xFFFFFFFFU;
+ sh = &ps->ps_sh;
+ sh->sh_rawptr = ch->ch_symptr;
+ sh->sh_rawsize = ch->ch_nsym * PE_SYM_ENTRY_SIZE;
+ pe->pe_nsym = ch->ch_nsym;
+ }
+
+ /* PE file headers initialization is complete if we reach here. */
+ return (0);
+}
+
+int
+libpe_load_section(PE *pe, PE_Scn *ps)
+{
+ PE_SecHdr *sh;
+ PE_SecBuf *sb;
+ size_t sz;
+ char tmp[4];
+
+ assert(pe != NULL && ps != NULL);
+ assert((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0);
+
+ sh = &ps->ps_sh;
+
+ /* Allocate a PE_SecBuf struct without buffer for empty sections. */
+ if (sh->sh_rawsize == 0) {
+ (void) libpe_alloc_buffer(ps, 0);
+ ps->ps_flags |= LIBPE_F_LOAD_SECTION;
+ return (0);
+ }
+
+ if ((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0) {
+ if (lseek(pe->pe_fd, (off_t) sh->sh_rawptr, SEEK_SET) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+
+ if ((sb = libpe_alloc_buffer(ps, sh->sh_rawsize)) == NULL)
+ return (-1);
+
+ if (read(pe->pe_fd, sb->sb_pb.pb_buf, sh->sh_rawsize) !=
+ (ssize_t) sh->sh_rawsize) {
+ errno = EIO;
+ return (-1);
+ }
+
+ if (ps->ps_ndx == 0xFFFFFFFFU) {
+ /*
+ * Index 0xFFFFFFFF indicates this section is a pseudo
+ * section that contains the COFF symbol table. We should
+ * read in the string table right after it.
+ */
+ if (read(pe->pe_fd, tmp, sizeof(tmp)) !=
+ (ssize_t) sizeof(tmp)) {
+ errno = EIO;
+ return (-1);
+ }
+ sz = le32dec(tmp);
+
+ /*
+ * The minimum value for the size field is 4, which indicates
+ * there is no string table.
+ */
+ if (sz > 4) {
+ sz -= 4;
+ if ((sb = libpe_alloc_buffer(ps, sz)) == NULL)
+ return (-1);
+ if (read(pe->pe_fd, sb->sb_pb.pb_buf, sz) !=
+ (ssize_t) sz) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+ }
+
+ ps->ps_flags |= LIBPE_F_LOAD_SECTION;
+
+ return (0);
+}
+
+int
+libpe_load_all_sections(PE *pe)
+{
+ PE_Scn *ps;
+ PE_SecHdr *sh;
+ unsigned r, s;
+ off_t off;
+ char tmp[256];
+
+ /* Calculate the current offset into the file. */
+ off = 0;
+ if (pe->pe_dh != NULL)
+ off += pe->pe_dh->dh_lfanew + 4;
+ if (pe->pe_ch != NULL)
+ off += sizeof(PE_CoffHdr) + pe->pe_ch->ch_optsize;
+
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ if (ps->ps_flags & LIBPE_F_LOAD_SECTION)
+ continue;
+ sh = &ps->ps_sh;
+
+ /*
+ * For special files, we consume the padding in between
+ * and advance to the section offset.
+ */
+ if (pe->pe_flags & LIBPE_F_SPECIAL_FILE) {
+ /* Can't go backwards. */
+ if (off > sh->sh_rawptr) {
+ errno = EIO;
+ return (-1);
+ }
+ if (off < sh->sh_rawptr) {
+ r = sh->sh_rawptr - off;
+ for (; r > 0; r -= s) {
+ s = r > sizeof(tmp) ? sizeof(tmp) : r;
+ if (read(pe->pe_fd, tmp, s) !=
+ (ssize_t) s) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+ }
+ }
+
+ /* Load the section content. */
+ if (libpe_load_section(pe, ps) < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+libpe_resync_sections(PE *pe, off_t off)
+{
+ PE_Scn *ps;
+ PE_SecHdr *sh;
+ size_t falign, nsec;
+
+ /* Firstly, sort all sections by their file offsets. */
+ sort_sections(pe);
+
+ /* Count the number of sections. */
+ nsec = 0;
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
+ continue;
+ if (ps->ps_ndx & 0xFFFF0000U)
+ continue;
+ nsec++;
+ }
+ pe->pe_nscn = nsec;
+
+ /*
+ * Calculate the file offset for the first section. (`off' is
+ * currently pointing to the COFF header.)
+ */
+ off += sizeof(PE_CoffHdr);
+ if (pe->pe_ch != NULL && pe->pe_ch->ch_optsize > 0)
+ off += pe->pe_ch->ch_optsize;
+ else {
+ switch (pe->pe_obj) {
+ case PE_O_PE32:
+ off += PE_COFF_OPT_SIZE_32;
+ break;
+ case PE_O_PE32P:
+ off += PE_COFF_OPT_SIZE_32P;
+ break;
+ case PE_O_COFF:
+ default:
+ break;
+ }
+ }
+ off += nsec * sizeof(PE_SecHdr);
+
+ /*
+ * Determine the file alignment for sections.
+ */
+ if (pe->pe_oh != NULL && pe->pe_oh->oh_filealign > 0)
+ falign = pe->pe_oh->oh_filealign;
+ else {
+ /*
+ * Use the default file alignment defined by the
+ * PE/COFF specification.
+ */
+ if (pe->pe_obj == PE_O_COFF)
+ falign = 4;
+ else
+ falign = 512;
+ }
+
+ /*
+ * Step through each section (and pseduo section) and verify
+ * alignment constraint and overlapping, make adjustment if need.
+ */
+ pe->pe_rvamax = 0;
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
+ continue;
+
+ sh = &ps->ps_sh;
+
+ if (sh->sh_addr + sh->sh_virtsize > pe->pe_rvamax)
+ pe->pe_rvamax = sh->sh_addr + sh->sh_virtsize;
+
+ if (ps->ps_ndx & 0xFFFF0000U)
+ ps->ps_falign = 4;
+ else
+ ps->ps_falign = falign;
+
+ off = roundup(off, ps->ps_falign);
+
+ if (off != sh->sh_rawptr)
+ ps->ps_flags |= PE_F_DIRTY;
+
+ if (ps->ps_flags & PE_F_DIRTY) {
+ if ((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0) {
+ if (libpe_load_section(pe, ps) < 0)
+ return (-1);
+ }
+ sh->sh_rawsize = libpe_resync_buffers(ps);
+ }
+
+ /*
+ * Sections only contains uninitialized data should set
+ * PointerToRawData to zero according to the PE/COFF
+ * specification.
+ */
+ if (sh->sh_rawsize == 0)
+ sh->sh_rawptr = 0;
+ else
+ sh->sh_rawptr = off;
+
+ off += sh->sh_rawsize;
+ }
+
+ return (0);
+}
+
+off_t
+libpe_write_section_headers(PE *pe, off_t off)
+{
+ char tmp[sizeof(PE_SecHdr)], *hdr;
+ PE_Scn *ps;
+ PE_SecHdr *sh;
+
+ if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER || pe->pe_nscn == 0)
+ return (off);
+
+ if ((pe->pe_flags & LIBPE_F_DIRTY_SEC_HEADER) == 0) {
+ off += sizeof(PE_SecHdr) * pe->pe_ch->ch_nsec;
+ return (off);
+ }
+
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
+ continue;
+ if (ps->ps_ndx & 0xFFFF0000U)
+ continue;
+ if ((pe->pe_flags & LIBPE_F_DIRTY_SEC_HEADER) == 0 &&
+ (ps->ps_flags & PE_F_DIRTY) == 0)
+ goto next_header;
+
+ sh = &ps->ps_sh;
+
+ memcpy(tmp, sh->sh_name, sizeof(sh->sh_name));
+ hdr = tmp + 8;
+ PE_WRITE32(hdr, sh->sh_virtsize);
+ PE_WRITE32(hdr, sh->sh_addr);
+ PE_WRITE32(hdr, sh->sh_rawsize);
+ PE_WRITE32(hdr, sh->sh_rawptr);
+ PE_WRITE32(hdr, sh->sh_relocptr);
+ PE_WRITE32(hdr, sh->sh_lineptr);
+ PE_WRITE16(hdr, sh->sh_nreloc);
+ PE_WRITE16(hdr, sh->sh_nline);
+ PE_WRITE32(hdr, sh->sh_char);
+
+ if (write(pe->pe_fd, tmp, sizeof(PE_SecHdr)) !=
+ (ssize_t) sizeof(PE_SecHdr)) {
+ errno = EIO;
+ return (-1);
+ }
+
+ next_header:
+ off += sizeof(PE_SecHdr);
+ }
+
+ return (off);
+}
+
+off_t
+libpe_write_sections(PE *pe, off_t off)
+{
+ PE_Scn *ps;
+ PE_SecHdr *sh;
+
+ if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER)
+ return (off);
+
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ sh = &ps->ps_sh;
+
+ if (ps->ps_flags & LIBPE_F_STRIP_SECTION)
+ continue;
+
+ /* Skip empty sections. */
+ if (sh->sh_rawptr == 0 || sh->sh_rawsize == 0)
+ continue;
+
+ /*
+ * Padding between sections. (padding always written
+ * in case the the section headers or sections are
+ * moved or shrinked.)
+ */
+ assert(off <= sh->sh_rawptr);
+ if (off < sh->sh_rawptr)
+ libpe_pad(pe, sh->sh_rawptr - off);
+
+ if ((ps->ps_flags & PE_F_DIRTY) == 0) {
+ assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
+ if (lseek(pe->pe_fd,
+ (off_t) (sh->sh_rawptr + sh->sh_rawsize),
+ SEEK_SET) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ off = sh->sh_rawptr + sh->sh_rawsize;
+ continue;
+ }
+
+ off = sh->sh_rawptr;
+
+ if (libpe_write_buffers(ps) < 0)
+ return (-1);
+
+ off += sh->sh_rawsize;
+
+ ps->ps_flags &= ~PE_F_DIRTY;
+ }
+
+ return (off);
+}
diff --git a/contrib/elftoolchain/libpe/libpe_utils.c b/contrib/elftoolchain/libpe/libpe_utils.c
new file mode 100644
index 0000000..9bc9a54
--- /dev/null
+++ b/contrib/elftoolchain/libpe/libpe_utils.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: libpe_utils.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+off_t
+libpe_align(PE *pe, off_t off, size_t align)
+{
+ off_t n;
+
+ assert(align > 0 && (align & (align - 1)) == 0);
+
+ n = roundup(off, align);
+ if (n > off) {
+ if (libpe_pad(pe, n - off) < 0)
+ return (-1);
+ }
+
+ return (n);
+}
+
+int
+libpe_pad(PE *pe, size_t pad)
+{
+ char tmp[128];
+ size_t s;
+
+ memset(tmp, 0, sizeof(tmp));
+ for (; pad > 0; pad -= s) {
+ s = pad > sizeof(tmp) ? sizeof(tmp) : pad;
+ if (write(pe->pe_fd, tmp, s) != (ssize_t) s) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/os.Linux.mk b/contrib/elftoolchain/libpe/os.Linux.mk
new file mode 100644
index 0000000..ed5bdf0
--- /dev/null
+++ b/contrib/elftoolchain/libpe/os.Linux.mk
@@ -0,0 +1,6 @@
+# $Id: os.Linux.mk 3312 2016-01-10 09:23:51Z kaiwang27 $
+
+CFLAGS+= -Wall -Wno-unused-parameter -Wstrict-prototypes \
+ -Wmissing-prototypes -Wpointer-arith -Wreturn-type \
+ -Wcast-qual -Wwrite-strings -Wswitch -Wshadow \
+ -Wcast-align -Wunused-parameter
diff --git a/contrib/elftoolchain/libpe/os.NetBSD.mk b/contrib/elftoolchain/libpe/os.NetBSD.mk
new file mode 100644
index 0000000..ae214e3
--- /dev/null
+++ b/contrib/elftoolchain/libpe/os.NetBSD.mk
@@ -0,0 +1,2 @@
+# TODO(#511): Revert after the source tree is -Wconversion clean.
+WARNS=5
diff --git a/contrib/elftoolchain/libpe/pe.h b/contrib/elftoolchain/libpe/pe.h
new file mode 100644
index 0000000..5b6130e
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe.h
@@ -0,0 +1,292 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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: pe.h 3312 2016-01-10 09:23:51Z kaiwang27 $
+ */
+
+#ifndef _PE_H_
+#define _PE_H_
+
+#include <stdint.h>
+
+/*
+ * MS-DOS header.
+ */
+
+typedef struct _PE_DosHdr {
+ char dh_magic[2];
+ uint16_t dh_lastsize;
+ uint16_t dh_nblock;
+ uint16_t dh_nreloc;
+ uint16_t dh_hdrsize;
+ uint16_t dh_minalloc;
+ uint16_t dh_maxalloc;
+ uint16_t dh_ss;
+ uint16_t dh_sp;
+ uint16_t dh_checksum;
+ uint16_t dh_ip;
+ uint16_t dh_cs;
+ uint16_t dh_relocpos;
+ uint16_t dh_noverlay;
+ uint16_t dh_reserved1[4];
+ uint16_t dh_oemid;
+ uint16_t dh_oeminfo;
+ uint16_t dh_reserved2[10];
+ uint32_t dh_lfanew;
+} PE_DosHdr;
+
+/*
+ * Rich header.
+ */
+
+typedef struct _PE_RichHdr {
+ uint32_t rh_xor;
+ uint32_t rh_total;
+ uint32_t *rh_compid;
+ uint32_t *rh_cnt;
+} PE_RichHdr;
+
+/*
+ * COFF header: Machine Types.
+ */
+
+#define IMAGE_FILE_MACHINE_UNKNOWN 0x0 /* not specified */
+#define IMAGE_FILE_MACHINE_AM33 0x1d3 /* Matsushita AM33 */
+#define IMAGE_FILE_MACHINE_AMD64 0x8664 /* x86-64 */
+#define IMAGE_FILE_MACHINE_ARM 0x1c0 /* ARM LE */
+#define IMAGE_FILE_MACHINE_ARMNT 0x1c4 /* ARMv7(or higher) Thumb */
+#define IMAGE_FILE_MACHINE_ARM64 0xaa64 /* ARMv8 64-bit */
+#define IMAGE_FILE_MACHINE_EBC 0xebc /* EFI byte code */
+#define IMAGE_FILE_MACHINE_I386 0x14c /* x86 */
+#define IMAGE_FILE_MACHINE_IA64 0x200 /* IA64 */
+#define IMAGE_FILE_MACHINE_M32R 0x9041 /* Mitsubishi M32R LE */
+#define IMAGE_FILE_MACHINE_MIPS16 0x266 /* MIPS16 */
+#define IMAGE_FILE_MACHINE_MIPSFPU 0x366 /* MIPS with FPU */
+#define IMAGE_FILE_MACHINE_MIPSFPU16 0x466 /* MIPS16 with FPU */
+#define IMAGE_FILE_MACHINE_POWERPC 0x1f0 /* Power PC LE */
+#define IMAGE_FILE_MACHINE_POWERPCFP 0x1f1 /* Power PC floating point */
+#define IMAGE_FILE_MACHINE_R4000 0x166 /* MIPS R4000 LE */
+#define IMAGE_FILE_MACHINE_SH3 0x1a2 /* Hitachi SH3 */
+#define IMAGE_FILE_MACHINE_SH3DSP 0x1a3 /* Hitachi SH3 DSP */
+#define IMAGE_FILE_MACHINE_SH4 0x1a6 /* Hitachi SH4 */
+#define IMAGE_FILE_MACHINE_SH5 0x1a8 /* Hitachi SH5 */
+#define IMAGE_FILE_MACHINE_THUMB 0x1c2 /* ARM or Thumb interworking */
+#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x169 /* MIPS LE WCE v2 */
+
+/*
+ * COFF header: Characteristics
+ */
+
+#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
+#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
+#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
+#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
+#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
+#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
+#define IMAGE_FILE_32BIT_MACHINE 0x0100
+#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
+#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
+#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
+#define IMAGE_FILE_SYSTEM 0x1000
+#define IMAGE_FILE_DLL 0x2000
+#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
+#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
+
+/*
+ * COFF Header.
+ */
+
+typedef struct _PE_CoffHdr {
+ uint16_t ch_machine;
+ uint16_t ch_nsec;
+ uint32_t ch_timestamp;
+ uint32_t ch_symptr;
+ uint32_t ch_nsym;
+ uint16_t ch_optsize;
+ uint16_t ch_char;
+} PE_CoffHdr;
+
+
+/*
+ * Optional Header: Subsystem.
+ */
+
+#define IMAGE_SUBSYSTEM_UNKNOWN 0
+#define IMAGE_SUBSYSTEM_NATIVE 1
+#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
+#define IMAGE_SUBSYSTEM_POSIX_CUI 7
+#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
+#define IMAGE_SUBSYSTEM_EFI_ROM 13
+#define IMAGE_SUBSYSTEM_XBOX 14
+
+/*
+ * Optional Header: DLL Characteristics
+ */
+
+#define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040
+#define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080
+#define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100
+#define IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION 0x0200
+#define IMAGE_DLL_CHARACTERISTICS_NO_SEH 0x0400
+#define IMAGE_DLL_CHARACTERISTICS_NO_BIND 0x0800
+#define IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER 0x2000
+#define IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
+
+/*
+ * Optional Header.
+ */
+
+#define PE_FORMAT_ROM 0x107
+#define PE_FORMAT_32 0x10b
+#define PE_FORMAT_32P 0x20b
+
+typedef struct _PE_OptHdr {
+ uint16_t oh_magic;
+ uint8_t oh_ldvermajor;
+ uint8_t oh_ldverminor;
+ uint32_t oh_textsize;
+ uint32_t oh_datasize;
+ uint32_t oh_bsssize;
+ uint32_t oh_entry;
+ uint32_t oh_textbase;
+ uint32_t oh_database;
+ uint64_t oh_imgbase;
+ uint32_t oh_secalign;
+ uint32_t oh_filealign;
+ uint16_t oh_osvermajor;
+ uint16_t oh_osverminor;
+ uint16_t oh_imgvermajor;
+ uint16_t oh_imgverminor;
+ uint16_t oh_subvermajor;
+ uint16_t oh_subverminor;
+ uint32_t oh_win32ver;
+ uint32_t oh_imgsize;
+ uint32_t oh_hdrsize;
+ uint32_t oh_checksum;
+ uint16_t oh_subsystem;
+ uint16_t oh_dllchar;
+ uint64_t oh_stacksizer;
+ uint64_t oh_stacksizec;
+ uint64_t oh_heapsizer;
+ uint64_t oh_heapsizec;
+ uint32_t oh_ldrflags;
+ uint32_t oh_ndatadir;
+} PE_OptHdr;
+
+/*
+ * Optional Header: Data Directories.
+ */
+
+#define PE_DD_EXPORT 0
+#define PE_DD_IMPORT 1
+#define PE_DD_RESROUCE 2
+#define PE_DD_EXCEPTION 3
+#define PE_DD_CERTIFICATE 4
+#define PE_DD_BASERELOC 5
+#define PE_DD_DEBUG 6
+#define PE_DD_ARCH 7
+#define PE_DD_GLOBALPTR 8
+#define PE_DD_TLS 9
+#define PE_DD_LOADCONFIG 10
+#define PE_DD_BOUNDIMPORT 11
+#define PE_DD_IAT 12
+#define PE_DD_DELAYIMPORT 13
+#define PE_DD_CLRRUNTIME 14
+#define PE_DD_RESERVED 15
+#define PE_DD_MAX 16
+
+typedef struct _PE_DataDirEntry {
+ uint32_t de_addr;
+ uint32_t de_size;
+} PE_DataDirEntry;
+
+typedef struct _PE_DataDir {
+ PE_DataDirEntry dd_e[PE_DD_MAX];
+ uint32_t dd_total;
+} PE_DataDir;
+
+/*
+ * Section Headers: Section flags.
+ */
+
+#define IMAGE_SCN_TYPE_NO_PAD 0x00000008
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
+#define IMAGE_SCN_LNK_OTHER 0x00000100
+#define IMAGE_SCN_LNK_INFO 0x00000200
+#define IMAGE_SCN_LNK_REMOVE 0x00000800
+#define IMAGE_SCN_LNK_COMDAT 0x00001000
+#define IMAGE_SCN_GPREL 0x00008000
+#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
+#define IMAGE_SCN_MEM_16BIT 0x00020000
+#define IMAGE_SCN_MEM_LOCKED 0x00040000
+#define IMAGE_SCN_MEM_PRELOAD 0x00080000
+#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
+#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
+#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
+#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
+#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
+#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
+#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
+#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
+#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
+#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000
+#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000
+#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000
+#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000
+#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000
+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
+#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
+#define IMAGE_SCN_MEM_SHARED 0x10000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+#define IMAGE_SCN_MEM_WRITE 0x80000000
+
+/*
+ * Section Headers.
+ */
+
+typedef struct _PE_SecHdr {
+ char sh_name[8];
+ uint32_t sh_virtsize;
+ uint32_t sh_addr;
+ uint32_t sh_rawsize;
+ uint32_t sh_rawptr;
+ uint32_t sh_relocptr;
+ uint32_t sh_lineptr;
+ uint16_t sh_nreloc;
+ uint16_t sh_nline;
+ uint32_t sh_char;
+} PE_SecHdr;
+
+#endif /* !_PE_H_ */
diff --git a/contrib/elftoolchain/libpe/pe_buffer.c b/contrib/elftoolchain/libpe/pe_buffer.c
new file mode 100644
index 0000000..e4ac19f
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_buffer.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <errno.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_buffer.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+PE_Buffer *
+pe_getbuffer(PE_Scn *ps, PE_Buffer *pb)
+{
+ PE *pe;
+ PE_SecBuf *sb;
+
+ if (ps == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ pe = ps->ps_pe;
+
+ if ((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0) {
+ if (pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (NULL);
+ }
+ if (pe->pe_flags & LIBPE_F_SPECIAL_FILE) {
+ if (libpe_load_all_sections(pe) < 0)
+ return (NULL);
+ } else {
+ if (libpe_load_section(pe, ps) < 0)
+ return (NULL);
+ }
+ }
+
+ sb = (PE_SecBuf *) pb;
+
+ if (sb == NULL)
+ sb = STAILQ_FIRST(&ps->ps_b);
+ else
+ sb = STAILQ_NEXT(sb, sb_next);
+
+ return ((PE_Buffer *) sb);
+}
+
+PE_Buffer *
+pe_newbuffer(PE_Scn *ps)
+{
+ PE *pe;
+ PE_SecBuf *sb;
+
+ if (ps == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ pe = ps->ps_pe;
+
+ if (pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (NULL);
+ }
+
+ if ((ps->ps_flags & LIBPE_F_LOAD_SECTION) == 0) {
+ if (libpe_load_section(pe, ps) < 0)
+ return (NULL);
+ }
+
+ if ((sb = libpe_alloc_buffer(ps, 0)) == NULL)
+ return (NULL);
+
+ sb->sb_flags |= PE_F_DIRTY;
+ ps->ps_flags |= PE_F_DIRTY;
+
+ return ((PE_Buffer *) sb);
+}
diff --git a/contrib/elftoolchain/libpe/pe_cntl.c b/contrib/elftoolchain/libpe/pe_cntl.c
new file mode 100644
index 0000000..1fc8c47
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_cntl.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <errno.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_cntl.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+int
+pe_cntl(PE *pe, PE_Cmd cmd)
+{
+
+ if (pe == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch (cmd) {
+ case PE_C_FDDONE:
+ pe->pe_flags |= LIBPE_F_FD_DONE;
+ break;
+
+ case PE_C_FDREAD:
+ if (pe->pe_cmd == PE_C_WRITE) {
+ errno = EACCES;
+ return (-1);
+ }
+ if (libpe_load_all_sections(pe) < 0)
+ return (-1);
+ break;
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/pe_coff.c b/contrib/elftoolchain/libpe/pe_coff.c
new file mode 100644
index 0000000..d5cd833
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_coff.c
@@ -0,0 +1,157 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_coff.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+PE_CoffHdr *
+pe_coff_header(PE *pe)
+{
+
+ if (pe->pe_ch == NULL) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ return (pe->pe_ch);
+}
+
+PE_OptHdr *
+pe_opt_header(PE *pe)
+{
+
+ if (pe->pe_oh == NULL) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ return (pe->pe_oh);
+}
+
+PE_DataDir *
+pe_data_dir(PE *pe)
+{
+
+ if (pe->pe_dd == NULL) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ return (pe->pe_dd);
+}
+
+int
+pe_update_coff_header(PE *pe, PE_CoffHdr *ch)
+{
+
+ if (pe == NULL || ch == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (-1);
+ }
+
+ if (pe->pe_ch == NULL) {
+ if ((pe->pe_ch = malloc(sizeof(PE_CoffHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ } else {
+ /* Rewrite optional header if `optsize' field changed. */
+ if (pe->pe_ch->ch_optsize != ch->ch_optsize)
+ pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
+ }
+
+ *pe->pe_ch = *ch;
+
+ pe->pe_flags |= LIBPE_F_DIRTY_COFF_HEADER;
+
+ return (0);
+}
+
+int
+pe_update_opt_header(PE *pe, PE_OptHdr *oh)
+{
+
+ if (pe == NULL || oh == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (-1);
+ }
+
+ if (pe->pe_oh == NULL) {
+ if ((pe->pe_oh = malloc(sizeof(PE_OptHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ }
+
+ *pe->pe_oh = *oh;
+
+ pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
+
+ return (0);
+}
+
+int
+pe_update_data_dir(PE *pe, PE_DataDir *dd)
+{
+
+ if (pe == NULL || dd == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (-1);
+ }
+
+ if (pe->pe_dd == NULL) {
+ if ((pe->pe_dd = malloc(sizeof(PE_DataDir))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ }
+
+ *pe->pe_dd = *dd;
+
+ pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/pe_dos.c b/contrib/elftoolchain/libpe/pe_dos.c
new file mode 100644
index 0000000..01ba42f
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_dos.c
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_dos.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+PE_DosHdr *
+pe_msdos_header(PE *pe)
+{
+
+ if (pe == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (pe->pe_dh == NULL) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ return (pe->pe_dh);
+}
+
+char *
+pe_msdos_stub(PE *pe, size_t *len)
+{
+
+ if (pe == NULL || len == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (pe->pe_stub_ex > 0 &&
+ (pe->pe_flags & LIBPE_F_LOAD_DOS_STUB) == 0) {
+ assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
+ (void) libpe_read_msdos_stub(pe);
+ }
+
+ *len = sizeof(PE_DosHdr) + pe->pe_stub_ex;
+
+ return (pe->pe_stub);
+}
+
+int
+ps_update_msdos_header(PE *pe, PE_DosHdr *dh)
+{
+
+ if (pe == NULL || dh == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (-1);
+ }
+
+ if (pe->pe_dh == NULL) {
+ if ((pe->pe_dh = malloc(sizeof(PE_DosHdr))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ }
+
+ *pe->pe_dh = *dh;
+
+ pe->pe_flags |= LIBPE_F_DIRTY_DOS_HEADER;
+
+ return (0);
+}
+
+int
+ps_update_msdos_stub(PE *pe, char *dos_stub, size_t sz)
+{
+
+ if (pe == NULL || dos_stub == NULL || sz == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (-1);
+ }
+
+ pe->pe_stub_app = dos_stub;
+ pe->pe_stub_app_sz = sz;
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/pe_flag.c b/contrib/elftoolchain/libpe/pe_flag.c
new file mode 100644
index 0000000..c392a4d
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_flag.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <errno.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_flag.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+int
+pe_flag(PE *pe, PE_Cmd c, unsigned int flags)
+{
+
+ if (pe == NULL || (c != PE_C_SET && c != PE_C_CLR)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((flags & ~(PE_F_STRIP_DOS_STUB | PE_F_STRIP_RICH_HEADER |
+ PE_F_STRIP_SYMTAB | PE_F_STRIP_DEBUG)) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (c == PE_C_SET)
+ pe->pe_flags |= flags;
+ else
+ pe->pe_flags &= ~flags;
+
+ return (0);
+}
+
+int
+pe_flag_dos_header(PE *pe, PE_Cmd c, unsigned int flags)
+{
+
+ if (pe == NULL || (c != PE_C_SET && c != PE_C_CLR) ||
+ (flags & ~PE_F_DIRTY) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (c == PE_C_SET)
+ pe->pe_flags |= LIBPE_F_DIRTY_DOS_HEADER;
+ else
+ pe->pe_flags &= ~LIBPE_F_DIRTY_DOS_HEADER;
+
+ return (0);
+}
+
+int
+pe_flag_coff_header(PE *pe, PE_Cmd c, unsigned int flags)
+{
+
+ if (pe == NULL || (c != PE_C_SET && c != PE_C_CLR) ||
+ (flags & ~PE_F_DIRTY) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (c == PE_C_SET)
+ pe->pe_flags |= LIBPE_F_DIRTY_COFF_HEADER;
+ else
+ pe->pe_flags &= ~LIBPE_F_DIRTY_COFF_HEADER;
+
+ return (0);
+}
+
+int
+pe_flag_opt_header(PE *pe, PE_Cmd c, unsigned int flags)
+{
+
+ if (pe == NULL || (c != PE_C_SET && c != PE_C_CLR) ||
+ (flags & ~PE_F_DIRTY) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (c == PE_C_SET)
+ pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
+ else
+ pe->pe_flags &= ~LIBPE_F_DIRTY_OPT_HEADER;
+
+ return (0);
+}
+
+int
+pe_flag_data_dir(PE *pe, PE_Cmd c, unsigned int flags)
+{
+
+ if (pe == NULL || (c != PE_C_SET && c != PE_C_CLR) ||
+ (flags & ~PE_F_DIRTY) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (c == PE_C_SET)
+ pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
+ else
+ pe->pe_flags &= ~LIBPE_F_DIRTY_OPT_HEADER;
+
+ return (0);
+}
+
+int
+pe_flag_scn(PE_Scn *ps, PE_Cmd c, unsigned int flags)
+{
+
+ if (ps == NULL || (c != PE_C_SET && c != PE_C_CLR) ||
+ (flags & ~(PE_F_DIRTY | PE_F_STRIP_SECTION)) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (c == PE_C_SET)
+ ps->ps_flags |= flags;
+ else
+ ps->ps_flags &= ~flags;
+
+ return (0);
+}
+
+int
+pe_flag_section_header(PE_Scn *ps, PE_Cmd c, unsigned int flags)
+{
+ PE *pe;
+
+ if (ps == NULL || (c != PE_C_SET && c != PE_C_CLR) ||
+ (flags & ~PE_F_DIRTY) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ pe = ps->ps_pe;
+
+ /* The library doesn't support per section header dirty flag. */
+ if (c == PE_C_SET)
+ pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
+ else
+ pe->pe_flags &= ~LIBPE_F_DIRTY_SEC_HEADER;
+
+ return (0);
+}
+
+int
+pe_flag_buffer(PE_Buffer *pb, PE_Cmd c, unsigned int flags)
+{
+ PE_SecBuf *sb;
+
+ if (pb == NULL || (c != PE_C_SET && c != PE_C_CLR) ||
+ (flags & ~PE_F_DIRTY) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sb = (PE_SecBuf *) pb;
+
+ if (c == PE_C_SET)
+ sb->sb_flags |= flags;
+ else
+ sb->sb_flags &= ~flags;
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/pe_init.c b/contrib/elftoolchain/libpe/pe_init.c
new file mode 100644
index 0000000..4e2f22a
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_init.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2015 Kai Wang
+ * 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.
+ */
+
+#include <sys/queue.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_init.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+PE *
+pe_init(int fd, PE_Cmd c, PE_Object o)
+{
+ PE *pe;
+
+ if ((pe = calloc(1, sizeof(*pe))) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ pe->pe_fd = fd;
+ pe->pe_cmd = c;
+ pe->pe_obj = o;
+ STAILQ_INIT(&pe->pe_scn);
+
+ switch (c) {
+ case PE_C_READ:
+ case PE_C_RDWR:
+ if (libpe_open_object(pe) < 0)
+ goto init_fail;
+ break;
+
+ case PE_C_WRITE:
+ if (o < PE_O_PE32 || o > PE_O_COFF) {
+ errno = EINVAL;
+ goto init_fail;
+ }
+ break;
+
+ default:
+ errno = EINVAL;
+ goto init_fail;
+ }
+
+ return (pe);
+
+init_fail:
+ pe_finish(pe);
+ return (NULL);
+}
+
+void
+pe_finish(PE *pe)
+{
+
+ if (pe == NULL)
+ return;
+
+ libpe_release_object(pe);
+}
+
+PE_Object
+pe_object(PE *pe)
+{
+
+ if (pe == NULL) {
+ errno = EINVAL;
+ return (PE_O_UNKNOWN);
+ }
+
+ return (pe->pe_obj);
+}
diff --git a/contrib/elftoolchain/libpe/pe_rich.c b/contrib/elftoolchain/libpe/pe_rich.c
new file mode 100644
index 0000000..ea1029e
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_rich.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_rich.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+PE_RichHdr *
+pe_rich_header(PE *pe)
+{
+
+ if (pe == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (pe->pe_rh == NULL && pe->pe_stub_ex > 0 &&
+ (pe->pe_flags & LIBPE_F_LOAD_DOS_STUB) == 0) {
+ assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
+ (void) libpe_read_msdos_stub(pe);
+ }
+
+ if (pe->pe_rh == NULL) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ return (pe->pe_rh);
+}
+
+static uint32_t
+rol32(uint32_t n, int c)
+{
+
+ c &= 0x1f;
+
+ return ((n << c) | (n >> (0x20 - c)));
+}
+
+int
+pe_rich_header_validate(PE *pe)
+{
+ PE_RichHdr *rh;
+ uint32_t cksum;
+ char *p;
+ int i, off;
+
+ if (pe_rich_header(pe) == NULL)
+ return (-1);
+
+ assert(pe->pe_rh_start != NULL);
+
+ /*
+ * Initial value of the checksum is the offset to the begin of
+ * the Rich header.
+ */
+ cksum = pe->pe_rh_start - pe->pe_stub;
+
+ /*
+ * Add the bytes before the Rich header to the checksum, rotated
+ * left by the offset.
+ */
+ for (p = pe->pe_stub; p < pe->pe_rh_start; p++) {
+ /* Skip dh_lfanew. */
+ off = p - pe->pe_stub;
+ if (off >= 0x3c && off < 0x40)
+ continue;
+ cksum += rol32((unsigned char) *p, off);
+ }
+
+ /* Add each compid rotated left by its count to the checksum. */
+ rh = pe->pe_rh;
+ for (i = 0; (uint32_t) i < rh->rh_total; i++)
+ cksum += rol32(rh->rh_compid[i], rh->rh_cnt[i]);
+
+ /* Validate the checksum with the XOR mask stored after "Rich". */
+ if (cksum == rh->rh_xor)
+ return (1);
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/pe_section.c b/contrib/elftoolchain/libpe/pe_section.c
new file mode 100644
index 0000000..3e82d84
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_section.c
@@ -0,0 +1,213 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_section.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+PE_Scn *
+pe_getscn(PE *pe, size_t ndx)
+{
+ PE_Scn *ps;
+
+ if (pe == NULL || ndx < 1 || ndx > 0xFFFFU) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ if (ps->ps_ndx == ndx)
+ return (ps);
+ }
+
+ errno = ENOENT;
+
+ return (NULL);
+}
+
+size_t
+pe_ndxscn(PE_Scn *ps)
+{
+
+ if (ps == NULL) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ return (ps->ps_ndx);
+}
+
+PE_Scn *
+pe_nextscn(PE *pe, PE_Scn *ps)
+{
+
+ if (pe == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (ps == NULL)
+ ps = STAILQ_FIRST(&pe->pe_scn);
+ else
+ ps = STAILQ_NEXT(ps, ps_next);
+
+ while (ps != NULL) {
+ if (ps->ps_ndx >= 1 && ps->ps_ndx <= 0xFFFFU)
+ return (ps);
+ ps = STAILQ_NEXT(ps, ps_next);
+ }
+
+ return (NULL);
+}
+
+PE_Scn *
+pe_newscn(PE *pe)
+{
+ PE_Scn *ps, *tps, *_tps;
+
+ if (pe == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (NULL);
+ }
+
+ if ((ps = libpe_alloc_scn(pe)) == NULL)
+ return (NULL);
+
+ if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER) {
+ STAILQ_FOREACH_SAFE(tps, &pe->pe_scn, ps_next, _tps)
+ libpe_release_scn(tps);
+ pe->pe_flags &= ~LIBPE_F_BAD_SEC_HEADER;
+ }
+
+ STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
+
+ ps->ps_flags |= PE_F_DIRTY | LIBPE_F_LOAD_SECTION;
+ pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
+
+ return (ps);
+}
+
+PE_Scn *
+pe_insertscn(PE *pe, size_t ndx)
+{
+ PE_Scn *ps, *a, *b;
+
+ if (pe == NULL || ndx < 1 || ndx > 0xFFFFU) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (NULL);
+ }
+
+ if ((ps = libpe_alloc_scn(pe)) == NULL)
+ return (NULL);
+
+ if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER) {
+ STAILQ_FOREACH_SAFE(a, &pe->pe_scn, ps_next, b)
+ libpe_release_scn(a);
+ pe->pe_flags &= ~LIBPE_F_BAD_SEC_HEADER;
+ }
+
+ b = NULL;
+ STAILQ_FOREACH(a, &pe->pe_scn, ps_next) {
+ if (a->ps_ndx & 0xFFFF0000U)
+ continue;
+ if (a->ps_ndx == ndx)
+ break;
+ b = a;
+ }
+
+ if (a == NULL) {
+ STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
+ if (b == NULL)
+ ps->ps_ndx = 1;
+ else
+ ps->ps_ndx = b->ps_ndx + 1;
+ } else if (b == NULL) {
+ STAILQ_INSERT_HEAD(&pe->pe_scn, ps, ps_next);
+ ps->ps_ndx = 1;
+ } else {
+ STAILQ_INSERT_AFTER(&pe->pe_scn, b, ps, ps_next);
+ ps->ps_ndx = ndx;
+ }
+
+ a = ps;
+ while ((a = STAILQ_NEXT(a, ps_next)) != NULL) {
+ if ((a->ps_ndx & 0xFFFF0000U) == 0)
+ a->ps_ndx++;
+ }
+
+ ps->ps_flags |= PE_F_DIRTY | LIBPE_F_LOAD_SECTION;
+ pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
+
+ return (ps);
+}
+
+PE_SecHdr *
+pe_section_header(PE_Scn *ps)
+{
+
+ if (ps == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ return (&ps->ps_sh);
+}
+
+int
+pe_update_section_header(PE_Scn *ps, PE_SecHdr *sh)
+{
+ PE *pe;
+
+ if (ps == NULL || sh == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ pe = ps->ps_pe;
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (-1);
+ }
+
+ ps->ps_sh = *sh;
+ pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/pe_symtab.c b/contrib/elftoolchain/libpe/pe_symtab.c
new file mode 100644
index 0000000..d0e90d1
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_symtab.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <errno.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_symtab.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+int
+pe_update_symtab(PE *pe, char *symtab, size_t sz, unsigned int nsym)
+{
+ PE_Scn *ps;
+ PE_SecBuf *sb;
+ PE_SecHdr *sh;
+
+ if (pe == NULL || symtab == NULL || sz == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (-1);
+ }
+
+ /* Remove the old symbol table. */
+ STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
+ if (ps->ps_ndx == 0xFFFFFFFFU)
+ libpe_release_scn(ps);
+ }
+
+ /*
+ * Insert the new symbol table.
+ */
+
+ if ((ps = libpe_alloc_scn(pe)) == NULL)
+ return (-1);
+
+ STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
+ ps->ps_ndx = 0xFFFFFFFFU;
+ ps->ps_flags |= PE_F_DIRTY;
+
+ /*
+ * Set the symbol table section offset to the maximum to make sure
+ * that it will be placed in the end of the file during section
+ * layout.
+ */
+ sh = &ps->ps_sh;
+ sh->sh_rawptr = 0xFFFFFFFFU;
+ sh->sh_rawsize = sz;
+
+ /* Allocate the buffer. */
+ if ((sb = libpe_alloc_buffer(ps, 0)) == NULL)
+ return (-1);
+ sb->sb_flags |= PE_F_DIRTY;
+ sb->sb_pb.pb_size = sz;
+ sb->sb_pb.pb_buf = symtab;
+
+ pe->pe_nsym = nsym;
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libpe/pe_update.c b/contrib/elftoolchain/libpe/pe_update.c
new file mode 100644
index 0000000..ec2b2e5
--- /dev/null
+++ b/contrib/elftoolchain/libpe/pe_update.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2016 Kai Wang
+ * 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "_libpe.h"
+
+ELFTC_VCSID("$Id: pe_update.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
+
+off_t
+pe_update(PE *pe)
+{
+ off_t off;
+
+ if (pe == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
+ errno = EACCES;
+ return (-1);
+ }
+
+ if (pe->pe_cmd == PE_C_RDWR || (pe->pe_cmd == PE_C_WRITE &&
+ (pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0)) {
+ if (lseek(pe->pe_fd, 0, SEEK_SET) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+
+ off = 0;
+
+ if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P) {
+ if ((off = libpe_write_msdos_stub(pe, off)) < 0)
+ return (-1);
+
+ if ((off = libpe_write_pe_header(pe, off)) < 0)
+ return (-1);
+ }
+
+ if (libpe_resync_sections(pe, off) < 0)
+ return (-1);
+
+ if ((off = libpe_write_coff_header(pe, off)) < 0)
+ return (-1);
+
+ if ((off = libpe_write_section_headers(pe, off)) < 0)
+ return (-1);
+
+ if ((off = libpe_write_sections(pe, off)) < 0)
+ return (-1);
+
+ if (ftruncate(pe->pe_fd, off) < 0) {
+ errno = EIO;
+ return (-1);
+ }
+
+ return (off);
+}
OpenPOWER on IntegriCloud