diff options
Diffstat (limited to 'contrib/elftoolchain/elfcopy')
-rw-r--r-- | contrib/elftoolchain/elfcopy/Makefile | 41 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/archive.c | 523 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/ascii.c | 1078 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/binary.c | 285 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/elfcopy.1 | 333 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/elfcopy.h | 317 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/main.c | 1530 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/mcs.1 | 125 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/sections.c | 1573 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/segments.c | 495 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/strip.1 | 132 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/symbols.c | 1097 |
12 files changed, 0 insertions, 7529 deletions
diff --git a/contrib/elftoolchain/elfcopy/Makefile b/contrib/elftoolchain/elfcopy/Makefile deleted file mode 100644 index cb1a31b400ee..000000000000 --- a/contrib/elftoolchain/elfcopy/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# $Id: Makefile 2290 2011-12-04 07:20:46Z jkoshy $ - -TOP= .. - -PROG= elfcopy - -SRCS= archive.c ascii.c binary.c main.c sections.c segments.c symbols.c - -WARNS?= 5 - -DPADD= ${LIBELF} ${LIBELFTC} -LDADD= -lelf -lelftc - -.if !defined(LIBELF_AR) -LDADD+= -larchive -.endif - -MAN= elfcopy.1 mcs.1 strip.1 - -NO_SHARED?= yes - -LINKS= ${BINDIR}/elfcopy ${BINDIR}/strip \ - ${BINDIR}/elfcopy ${BINDIR}/mcs - -EXTRA_TARGETS= strip mcs - -CLEANFILES+= ${EXTRA_TARGETS} - -# Create in-place symbolic links to "elfcopy" at build time. - -all: ${EXTRA_TARGETS} - -${EXTRA_TARGETS}: ${PROG} - ln -s ${PROG} ${.TARGET} - -.include "${TOP}/mk/elftoolchain.prog.mk" - -.if ${OS_HOST} == "OpenBSD" -CFLAGS+= -I/usr/local/include -LDFLAGS+= -L/usr/local/lib -.endif diff --git a/contrib/elftoolchain/elfcopy/archive.c b/contrib/elftoolchain/elfcopy/archive.c deleted file mode 100644 index 682a1df66dcc..000000000000 --- a/contrib/elftoolchain/elfcopy/archive.c +++ /dev/null @@ -1,523 +0,0 @@ -/*- - * Copyright (c) 2007-2009 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/stat.h> -#include <err.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#ifndef LIBELF_AR -#include <archive.h> -#include <archive_entry.h> -#endif /* ! LIBELF_AR */ - -#include "elfcopy.h" - -ELFTC_VCSID("$Id: archive.c 3174 2015-03-27 17:13:41Z emaste $"); - -#define _ARMAG_LEN 8 /* length of ar magic string */ -#define _ARHDR_LEN 60 /* length of ar header */ -#define _INIT_AS_CAP 128 /* initial archive string table size */ -#define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */ -#define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ -#define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ - -#ifndef LIBELF_AR -static void ac_read_objs(struct elfcopy *ecp, int ifd); -static void ac_write_cleanup(struct elfcopy *ecp); -static void ac_write_data(struct archive *a, const void *buf, size_t s); -static void ac_write_objs(struct elfcopy *ecp, int ofd); -#endif /* ! LIBELF_AR */ -static void add_to_ar_str_table(struct elfcopy *elfcopy, const char *name); -static void add_to_ar_sym_table(struct elfcopy *ecp, const char *name); -static void extract_arsym(struct elfcopy *ecp); -static void process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj); -static void sync_ar(struct elfcopy *ecp); - - -static void -process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj) -{ - struct stat sb; - char *tempfile; - int fd; - - /* Output to a temporary file. */ - create_tempfile(&tempfile, &fd); - if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_begin() failed: %s", - elf_errmsg(-1)); - elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); - create_elf(ecp); - elf_end(ecp->ein); - elf_end(ecp->eout); - free(obj->buf); - obj->buf = NULL; - - /* Extract archive symbols. */ - if (lseek(fd, 0, SEEK_SET) < 0) - err(EXIT_FAILURE, "lseek failed for '%s'", tempfile); - if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_begin() failed: %s", - elf_errmsg(-1)); - extract_arsym(ecp); - elf_end(ecp->eout); - - if (fstat(fd, &sb) == -1) - err(EXIT_FAILURE, "fstat %s failed", tempfile); - if (lseek(fd, 0, SEEK_SET) < 0) - err(EXIT_FAILURE, "lseek %s failed", tempfile); - obj->size = sb.st_size; - if ((obj->maddr = malloc(obj->size)) == NULL) - err(EXIT_FAILURE, "memory allocation failed for '%s'", - tempfile); - if ((size_t) read(fd, obj->maddr, obj->size) != obj->size) - err(EXIT_FAILURE, "read failed for '%s'", tempfile); - if (unlink(tempfile)) - err(EXIT_FAILURE, "unlink %s failed", tempfile); - free(tempfile); - close(fd); - if (strlen(obj->name) > _MAXNAMELEN_SVR4) - add_to_ar_str_table(ecp, obj->name); - ecp->rela_off += _ARHDR_LEN + obj->size + obj->size % 2; - STAILQ_INSERT_TAIL(&ecp->v_arobj, obj, objs); -} - -/* - * Append to the archive string table buffer. - */ -static void -add_to_ar_str_table(struct elfcopy *ecp, const char *name) -{ - - if (ecp->as == NULL) { - ecp->as_cap = _INIT_AS_CAP; - ecp->as_sz = 0; - if ((ecp->as = malloc(ecp->as_cap)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - } - - /* - * The space required for holding one member name in as table includes: - * strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding). - */ - while (ecp->as_sz + strlen(name) + 3 > ecp->as_cap) { - ecp->as_cap *= 2; - ecp->as = realloc(ecp->as, ecp->as_cap); - if (ecp->as == NULL) - err(EXIT_FAILURE, "realloc failed"); - } - strncpy(&ecp->as[ecp->as_sz], name, strlen(name)); - ecp->as_sz += strlen(name); - ecp->as[ecp->as_sz++] = '/'; - ecp->as[ecp->as_sz++] = '\n'; -} - -/* - * Append to the archive symbol table buffer. - */ -static void -add_to_ar_sym_table(struct elfcopy *ecp, const char *name) -{ - - if (ecp->s_so == NULL) { - if ((ecp->s_so = malloc(_INIT_SYMOFF_CAP)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - ecp->s_so_cap = _INIT_SYMOFF_CAP; - ecp->s_cnt = 0; - } - - if (ecp->s_sn == NULL) { - if ((ecp->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - ecp->s_sn_cap = _INIT_SYMNAME_CAP; - ecp->s_sn_sz = 0; - } - - if (ecp->s_cnt * sizeof(uint32_t) >= ecp->s_so_cap) { - ecp->s_so_cap *= 2; - ecp->s_so = realloc(ecp->s_so, ecp->s_so_cap); - if (ecp->s_so == NULL) - err(EXIT_FAILURE, "realloc failed"); - } - ecp->s_so[ecp->s_cnt] = ecp->rela_off; - ecp->s_cnt++; - - /* - * The space required for holding one symbol name in sn table includes: - * strlen(name) + (1 for '\n') + (possibly 1 for padding). - */ - while (ecp->s_sn_sz + strlen(name) + 2 > ecp->s_sn_cap) { - ecp->s_sn_cap *= 2; - ecp->s_sn = realloc(ecp->s_sn, ecp->s_sn_cap); - if (ecp->s_sn == NULL) - err(EXIT_FAILURE, "realloc failed"); - } - strncpy(&ecp->s_sn[ecp->s_sn_sz], name, strlen(name)); - ecp->s_sn_sz += strlen(name); - ecp->s_sn[ecp->s_sn_sz++] = '\0'; -} - -static void -sync_ar(struct elfcopy *ecp) -{ - size_t s_sz; /* size of archive symbol table. */ - size_t pm_sz; /* size of pseudo members */ - int i; - - /* - * Pad the symbol name string table. It is treated specially because - * symbol name table should be padded by a '\0', not the common '\n' - * for other members. The size of sn table includes the pad bit. - */ - if (ecp->s_cnt != 0 && ecp->s_sn_sz % 2 != 0) - ecp->s_sn[ecp->s_sn_sz++] = '\0'; - - /* - * Archive string table is padded by a "\n" as the normal members. - * The difference is that the size of archive string table counts - * in the pad bit, while normal members' size fileds do not. - */ - if (ecp->as != NULL && ecp->as_sz % 2 != 0) - ecp->as[ecp->as_sz++] = '\n'; - - /* - * If there is a symbol table, calculate the size of pseudo members, - * convert previously stored relative offsets to absolute ones, and - * then make them Big Endian. - * - * absolute_offset = htobe32(relative_offset + size_of_pseudo_members) - */ - - if (ecp->s_cnt != 0) { - s_sz = (ecp->s_cnt + 1) * sizeof(uint32_t) + ecp->s_sn_sz; - pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); - if (ecp->as != NULL) - pm_sz += _ARHDR_LEN + ecp->as_sz; - for (i = 0; (size_t)i < ecp->s_cnt; i++) - *(ecp->s_so + i) = htobe32(*(ecp->s_so + i) + - pm_sz); - } -} - -/* - * Extract global symbols from archive members. - */ -static void -extract_arsym(struct elfcopy *ecp) -{ - Elf_Scn *scn; - GElf_Shdr shdr; - GElf_Sym sym; - Elf_Data *data; - char *name; - size_t n, shstrndx; - int elferr, tabndx, len, i; - - if (elf_kind(ecp->eout) != ELF_K_ELF) { - warnx("internal: cannot extract symbols from non-elf object"); - return; - } - if (elf_getshstrndx(ecp->eout, &shstrndx) == 0) { - warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); - return; - } - - tabndx = -1; - scn = NULL; - while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { - if (gelf_getshdr(scn, &shdr) != &shdr) { - warnx("elf_getshdr failed: %s", elf_errmsg(-1)); - continue; - } - if ((name = elf_strptr(ecp->eout, shstrndx, shdr.sh_name)) == - NULL) { - warnx("elf_strptr failed: %s", elf_errmsg(-1)); - continue; - } - if (strcmp(name, ".strtab") == 0) { - tabndx = elf_ndxscn(scn); - break; - } - } - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); - - /* Ignore members without symbol table. */ - if (tabndx == -1) - return; - - scn = NULL; - while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { - if (gelf_getshdr(scn, &shdr) != &shdr) { - warnx("elf_getshdr failed: %s", elf_errmsg(-1)); - continue; - } - if (shdr.sh_type != SHT_SYMTAB) - continue; - - data = NULL; - n = 0; - while (n < shdr.sh_size && - (data = elf_getdata(scn, data)) != NULL) { - len = data->d_size / shdr.sh_entsize; - for (i = 0; i < len; i++) { - if (gelf_getsym(data, i, &sym) != &sym) { - warnx("gelf_getsym failed: %s", - elf_errmsg(-1)); - continue; - } - - /* keep only global or weak symbols */ - if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && - GELF_ST_BIND(sym.st_info) != STB_WEAK) - continue; - - /* keep only defined symbols */ - if (sym.st_shndx == SHN_UNDEF) - continue; - - if ((name = elf_strptr(ecp->eout, tabndx, - sym.st_name)) == NULL) { - warnx("elf_strptr failed: %s", - elf_errmsg(-1)); - continue; - } - - add_to_ar_sym_table(ecp, name); - } - } - } - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); -} - -#ifndef LIBELF_AR - -/* - * Convenient wrapper for general libarchive error handling. - */ -#define AC(CALL) do { \ - if ((CALL)) \ - errx(EXIT_FAILURE, "%s", archive_error_string(a)); \ -} while (0) - -/* Earlier versions of libarchive had some functions that returned 'void'. */ -#if ARCHIVE_VERSION_NUMBER >= 2000000 -#define ACV(CALL) AC(CALL) -#else -#define ACV(CALL) do { \ - (CALL); \ - } while (0) -#endif - -int -ac_detect_ar(int ifd) -{ - struct archive *a; - struct archive_entry *entry; - int r; - - r = -1; - if ((a = archive_read_new()) == NULL) - return (0); - archive_read_support_format_ar(a); - if (archive_read_open_fd(a, ifd, 10240) == ARCHIVE_OK) - r = archive_read_next_header(a, &entry); - archive_read_close(a); - archive_read_free(a); - - return (r == ARCHIVE_OK); -} - -void -ac_create_ar(struct elfcopy *ecp, int ifd, int ofd) -{ - - ac_read_objs(ecp, ifd); - sync_ar(ecp); - ac_write_objs(ecp, ofd); - ac_write_cleanup(ecp); -} - -static void -ac_read_objs(struct elfcopy *ecp, int ifd) -{ - struct archive *a; - struct archive_entry *entry; - struct ar_obj *obj; - const char *name; - char *buff; - size_t size; - int r; - - ecp->rela_off = 0; - if (lseek(ifd, 0, SEEK_SET) == -1) - err(EXIT_FAILURE, "lseek failed"); - if ((a = archive_read_new()) == NULL) - errx(EXIT_FAILURE, "%s", archive_error_string(a)); - archive_read_support_format_ar(a); - AC(archive_read_open_fd(a, ifd, 10240)); - for(;;) { - r = archive_read_next_header(a, &entry); - if (r == ARCHIVE_FATAL) - errx(EXIT_FAILURE, "%s", archive_error_string(a)); - if (r == ARCHIVE_EOF) - break; - if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) - warnx("%s", archive_error_string(a)); - if (r == ARCHIVE_RETRY) - continue; - - name = archive_entry_pathname(entry); - - /* skip pseudo members. */ - if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0) - continue; - - size = archive_entry_size(entry); - - if (size > 0) { - if ((buff = malloc(size)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - if (archive_read_data(a, buff, size) != (ssize_t)size) { - warnx("%s", archive_error_string(a)); - free(buff); - continue; - } - if ((obj = malloc(sizeof(*obj))) == NULL) - err(EXIT_FAILURE, "malloc failed"); - if ((obj->name = strdup(name)) == NULL) - err(EXIT_FAILURE, "strdup failed"); - obj->buf = buff; - obj->uid = archive_entry_uid(entry); - obj->gid = archive_entry_gid(entry); - obj->md = archive_entry_mode(entry); - obj->mtime = archive_entry_mtime(entry); - if ((ecp->ein = elf_memory(buff, size)) == NULL) - errx(EXIT_FAILURE, "elf_memory() failed: %s", - elf_errmsg(-1)); - if (elf_kind(ecp->ein) != ELF_K_ELF) - errx(EXIT_FAILURE, - "file format not recognized"); - process_ar_obj(ecp, obj); - } - } - AC(archive_read_close(a)); - ACV(archive_read_free(a)); -} - -static void -ac_write_objs(struct elfcopy *ecp, int ofd) -{ - struct archive *a; - struct archive_entry *entry; - struct ar_obj *obj; - int nr; - - if ((a = archive_write_new()) == NULL) - errx(EXIT_FAILURE, "%s", archive_error_string(a)); - archive_write_set_format_ar_svr4(a); - AC(archive_write_open_fd(a, ofd)); - - /* Write the archive symbol table, even if it's empty. */ - entry = archive_entry_new(); - archive_entry_copy_pathname(entry, "/"); - archive_entry_set_mtime(entry, time(NULL), 0); - archive_entry_set_size(entry, (ecp->s_cnt + 1) * sizeof(uint32_t) + - ecp->s_sn_sz); - AC(archive_write_header(a, entry)); - nr = htobe32(ecp->s_cnt); - ac_write_data(a, &nr, sizeof(uint32_t)); - ac_write_data(a, ecp->s_so, sizeof(uint32_t) * ecp->s_cnt); - ac_write_data(a, ecp->s_sn, ecp->s_sn_sz); - archive_entry_free(entry); - - /* Write the archive string table, if exist. */ - if (ecp->as != NULL) { - entry = archive_entry_new(); - archive_entry_copy_pathname(entry, "//"); - archive_entry_set_size(entry, ecp->as_sz); - AC(archive_write_header(a, entry)); - ac_write_data(a, ecp->as, ecp->as_sz); - archive_entry_free(entry); - } - - /* Write normal members. */ - STAILQ_FOREACH(obj, &ecp->v_arobj, objs) { - entry = archive_entry_new(); - archive_entry_copy_pathname(entry, obj->name); - archive_entry_set_uid(entry, obj->uid); - archive_entry_set_gid(entry, obj->gid); - archive_entry_set_mode(entry, obj->md); - archive_entry_set_size(entry, obj->size); - archive_entry_set_mtime(entry, obj->mtime, 0); - archive_entry_set_filetype(entry, AE_IFREG); - AC(archive_write_header(a, entry)); - ac_write_data(a, obj->maddr, obj->size); - archive_entry_free(entry); - } - - AC(archive_write_close(a)); - ACV(archive_write_free(a)); -} - -static void -ac_write_cleanup(struct elfcopy *ecp) -{ - struct ar_obj *obj, *obj_temp; - - STAILQ_FOREACH_SAFE(obj, &ecp->v_arobj, objs, obj_temp) { - STAILQ_REMOVE(&ecp->v_arobj, obj, ar_obj, objs); - if (obj->maddr != NULL) - free(obj->maddr); - free(obj->name); - free(obj); - } - - free(ecp->as); - free(ecp->s_so); - free(ecp->s_sn); - ecp->as = NULL; - ecp->s_so = NULL; - ecp->s_sn = NULL; -} - -/* - * Wrapper for archive_write_data(). - */ -static void -ac_write_data(struct archive *a, const void *buf, size_t s) -{ - if (archive_write_data(a, buf, s) != (ssize_t)s) - errx(EXIT_FAILURE, "%s", archive_error_string(a)); -} - -#endif /* ! LIBELF_AR */ diff --git a/contrib/elftoolchain/elfcopy/ascii.c b/contrib/elftoolchain/elfcopy/ascii.c deleted file mode 100644 index cad4eb8a91eb..000000000000 --- a/contrib/elftoolchain/elfcopy/ascii.c +++ /dev/null @@ -1,1078 +0,0 @@ -/*- - * Copyright (c) 2010,2011 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 <ctype.h> -#include <err.h> -#include <gelf.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "elfcopy.h" - -ELFTC_VCSID("$Id: ascii.c 3177 2015-03-30 18:19:41Z emaste $"); - -static void append_data(struct section *s, const void *buf, size_t sz); -static char hex_digit(uint8_t n); -static int hex_value(int x); -static void finalize_data_section(struct section *s); -static int ishexdigit(int x); -static int ihex_read(const char *line, char *type, uint64_t *addr, - uint64_t *num, uint8_t *data, size_t *sz); -static void ihex_write(int ofd, int type, uint64_t addr, uint64_t num, - const void *buf, size_t sz); -static void ihex_write_00(int ofd, uint64_t addr, const void *buf, size_t sz); -static void ihex_write_01(int ofd); -static void ihex_write_04(int ofd, uint16_t addr); -static void ihex_write_05(int ofd, uint64_t e_entry); -static struct section *new_data_section(struct elfcopy *ecp, int sec_index, - uint64_t off, uint64_t addr); -static int read_num(const char *line, int *len, uint64_t *num, size_t sz, - int *checksum); -static int srec_read(const char *line, char *type, uint64_t *addr, - uint8_t *data, size_t *sz); -static void srec_write(int ofd, char type, uint64_t addr, const void *buf, - size_t sz); -static void srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn, - GElf_Shdr *sh); -static void srec_write_S0(int ofd, const char *ofn); -static void srec_write_Sd(int ofd, char dr, uint64_t addr, const void *buf, - size_t sz, size_t rlen); -static void srec_write_Se(int ofd, uint64_t e_entry, int forceS3); -static void write_num(char *line, int *len, uint64_t num, size_t sz, - int *checksum); - -#define _LINE_BUFSZ 1024 -#define _DATA_BUFSZ 256 - -/* - * Convert ELF object to S-Record. - */ -void -create_srec(struct elfcopy *ecp, int ifd, int ofd, const char *ofn) -{ - Elf *e; - Elf_Scn *scn; - Elf_Data *d; - GElf_Ehdr eh; - GElf_Shdr sh; - uint64_t max_addr; - size_t rlen; - int elferr, addr_sz; - char dr; - - if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_begin() failed: %s", - elf_errmsg(-1)); - - /* Output a symbol table for `symbolsrec' target. */ - if (!strncmp(ecp->otgt, "symbolsrec", strlen("symbolsrec"))) { - scn = NULL; - while ((scn = elf_nextscn(e, scn)) != NULL) { - if (gelf_getshdr(scn, &sh) == NULL) { - warnx("gelf_getshdr failed: %s", - elf_errmsg(-1)); - (void) elf_errno(); - continue; - } - if (sh.sh_type != SHT_SYMTAB) - continue; - srec_write_symtab(ofd, ofn, e, scn, &sh); - break; - } - } - - if (ecp->flags & SREC_FORCE_S3) - dr = '3'; - else { - /* - * Find maximum address size in the first iteration. - */ - max_addr = 0; - scn = NULL; - while ((scn = elf_nextscn(e, scn)) != NULL) { - if (gelf_getshdr(scn, &sh) == NULL) { - warnx("gelf_getshdr failed: %s", - elf_errmsg(-1)); - (void) elf_errno(); - continue; - } - if ((sh.sh_flags & SHF_ALLOC) == 0 || - sh.sh_type == SHT_NOBITS || - sh.sh_size == 0) - continue; - if ((uint64_t) sh.sh_addr > max_addr) - max_addr = sh.sh_addr; - } - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); - - if (max_addr <= 0xFFFF) - dr = '1'; - else if (max_addr <= 0xFFFFFF) - dr = '2'; - else - dr = '3'; - } - - if (ecp->flags & SREC_FORCE_LEN) { - addr_sz = dr - '0' + 1; - if (ecp->srec_len < 1) - rlen = 1; - else if (ecp->srec_len + addr_sz + 1 > 255) - rlen = 255 - (addr_sz + 1); - else - rlen = ecp->srec_len; - } else - rlen = 16; - - /* Generate S0 record which contains the output filename. */ - srec_write_S0(ofd, ofn); - - /* Generate S{1,2,3} data records for section data. */ - scn = NULL; - while ((scn = elf_nextscn(e, scn)) != NULL) { - if (gelf_getshdr(scn, &sh) == NULL) { - warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); - (void) elf_errno(); - continue; - } - if ((sh.sh_flags & SHF_ALLOC) == 0 || - sh.sh_type == SHT_NOBITS || - sh.sh_size == 0) - continue; - if (sh.sh_addr > 0xFFFFFFFF) { - warnx("address space too big for S-Record file"); - continue; - } - (void) elf_errno(); - if ((d = elf_getdata(scn, NULL)) == NULL) { - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_getdata failed: %s", elf_errmsg(-1)); - continue; - } - if (d->d_buf == NULL || d->d_size == 0) - continue; - srec_write_Sd(ofd, dr, sh.sh_addr, d->d_buf, d->d_size, rlen); - } - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); - - /* Generate S{7,8,9} end of block recrod. */ - if (gelf_getehdr(e, &eh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - srec_write_Se(ofd, eh.e_entry, ecp->flags & SREC_FORCE_S3); -} - -void -create_elf_from_srec(struct elfcopy *ecp, int ifd) -{ - char line[_LINE_BUFSZ], name[_LINE_BUFSZ]; - uint8_t data[_DATA_BUFSZ]; - GElf_Ehdr oeh; - struct section *s, *shtab; - FILE *ifp; - uint64_t addr, entry, off, sec_addr; - uintmax_t st_value; - size_t sz; - int _ifd, first, sec_index, in_symtab, symtab_created; - char *rlt; - char type; - - if ((_ifd = dup(ifd)) < 0) - err(EXIT_FAILURE, "dup failed"); - if ((ifp = fdopen(_ifd, "r")) == NULL) - err(EXIT_FAILURE, "fdopen failed"); - - /* Create EHDR for output .o file. */ - if (gelf_newehdr(ecp->eout, ecp->oec) == NULL) - errx(EXIT_FAILURE, "gelf_newehdr failed: %s", - elf_errmsg(-1)); - if (gelf_getehdr(ecp->eout, &oeh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - /* Initialise e_ident fields. */ - oeh.e_ident[EI_CLASS] = ecp->oec; - oeh.e_ident[EI_DATA] = ecp->oed; - /* - * TODO: Set OSABI according to the OS platform where elfcopy(1) - * was build. (probably) - */ - oeh.e_ident[EI_OSABI] = ELFOSABI_NONE; - oeh.e_machine = ecp->oem; - oeh.e_type = ET_REL; - oeh.e_entry = 0; - - ecp->flags |= RELOCATABLE; - - /* Create .shstrtab section */ - init_shstrtab(ecp); - ecp->shstrtab->off = 0; - - /* Data sections are inserted after EHDR. */ - off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT); - if (off == 0) - errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); - - /* Create data sections. */ - s = NULL; - first = 1; - sec_index = 1; - sec_addr = entry = 0; - while (fgets(line, _LINE_BUFSZ, ifp) != NULL) { - if (line[0] == '\r' || line[0] == '\n') - continue; - if (line[0] == '$' && line[1] == '$') { - ecp->flags |= SYMTAB_EXIST; - while ((rlt = fgets(line, _LINE_BUFSZ, ifp)) != NULL) { - if (line[0] == '$' && line[1] == '$') - break; - } - if (rlt == NULL) - break; - continue; - } - if (line[0] != 'S' || line[1] < '0' || line[1] > '9') { - warnx("Invalid srec record"); - continue; - } - if (srec_read(line, &type, &addr, data, &sz) < 0) { - warnx("Invalid srec record or mismatched checksum"); - continue; - } - switch (type) { - case '1': - case '2': - case '3': - if (sz == 0) - break; - if (first || sec_addr != addr) { - if (s != NULL) - finalize_data_section(s); - s = new_data_section(ecp, sec_index, off, - addr); - if (s == NULL) { - warnx("new_data_section failed"); - break; - } - sec_index++; - sec_addr = addr; - first = 0; - } - append_data(s, data, sz); - off += sz; - sec_addr += sz; - break; - case '7': - case '8': - case '9': - entry = addr; - break; - default: - break; - } - } - if (s != NULL) - finalize_data_section(s); - if (ferror(ifp)) - warn("fgets failed"); - - /* Insert .shstrtab after data sections. */ - if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL) - errx(EXIT_FAILURE, "elf_newscn failed: %s", - elf_errmsg(-1)); - insert_to_sec_list(ecp, ecp->shstrtab, 1); - - /* Insert section header table here. */ - shtab = insert_shtab(ecp, 1); - - /* - * Rescan and create symbol table if we found '$$' section in - * the first scan. - */ - symtab_created = 0; - in_symtab = 0; - if (ecp->flags & SYMTAB_EXIST) { - if (fseek(ifp, 0, SEEK_SET) < 0) { - warn("fseek failed"); - ecp->flags &= ~SYMTAB_EXIST; - goto done; - } - while (fgets(line, _LINE_BUFSZ, ifp) != NULL) { - if (in_symtab) { - if (line[0] == '$' && line[1] == '$') { - in_symtab = 0; - continue; - } - if (sscanf(line, "%s $%jx", name, - &st_value) != 2) { - warnx("Invalid symbolsrec record"); - continue; - } - if (!symtab_created) { - create_external_symtab(ecp); - symtab_created = 1; - } - add_to_symtab(ecp, name, st_value, 0, SHN_ABS, - ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1); - } - if (line[0] == '$' && line[1] == '$') { - in_symtab = 1; - continue; - } - } - } - if (ferror(ifp)) - warn("fgets failed"); - if (symtab_created) { - finalize_external_symtab(ecp); - create_symtab_data(ecp); - /* Count in .symtab and .strtab section headers. */ - shtab->sz += gelf_fsize(ecp->eout, ELF_T_SHDR, 2, EV_CURRENT); - } else - ecp->flags &= ~SYMTAB_EXIST; - -done: - fclose(ifp); - - /* Set entry point. */ - oeh.e_entry = entry; - - /* - * Write the underlying ehdr. Note that it should be called - * before elf_setshstrndx() since it will overwrite e->e_shstrndx. - */ - if (gelf_update_ehdr(ecp->eout, &oeh) == 0) - errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", - elf_errmsg(-1)); - - /* Generate section name string table (.shstrtab). */ - set_shstrtab(ecp); - - /* Update sh_name pointer for each section header entry. */ - update_shdr(ecp, 0); - - /* Renew oeh to get the updated e_shstrndx. */ - if (gelf_getehdr(ecp->eout, &oeh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - /* Resync section offsets. */ - resync_sections(ecp); - - /* Store SHDR offset in EHDR. */ - oeh.e_shoff = shtab->off; - - /* Update ehdr since we modified e_shoff. */ - if (gelf_update_ehdr(ecp->eout, &oeh) == 0) - errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", - elf_errmsg(-1)); - - /* Write out the output elf object. */ - if (elf_update(ecp->eout, ELF_C_WRITE) < 0) - errx(EXIT_FAILURE, "elf_update() failed: %s", - elf_errmsg(-1)); - - /* Release allocated resource. */ - free_elf(ecp); -} - -void -create_ihex(int ifd, int ofd) -{ - Elf *e; - Elf_Scn *scn; - Elf_Data *d; - GElf_Ehdr eh; - GElf_Shdr sh; - int elferr; - uint16_t addr_hi, old_addr_hi; - - if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_begin() failed: %s", - elf_errmsg(-1)); - - old_addr_hi = 0; - scn = NULL; - while ((scn = elf_nextscn(e, scn)) != NULL) { - if (gelf_getshdr(scn, &sh) == NULL) { - warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); - (void) elf_errno(); - continue; - } - if ((sh.sh_flags & SHF_ALLOC) == 0 || - sh.sh_type == SHT_NOBITS || - sh.sh_size == 0) - continue; - if (sh.sh_addr > 0xFFFFFFFF) { - warnx("address space too big for Intel Hex file"); - continue; - } - (void) elf_errno(); - if ((d = elf_getdata(scn, NULL)) == NULL) { - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_getdata failed: %s", elf_errmsg(-1)); - continue; - } - if (d->d_buf == NULL || d->d_size == 0) - continue; - addr_hi = (sh.sh_addr >> 16) & 0xFFFF; - if (addr_hi > 0 && addr_hi != old_addr_hi) { - /* Write 04 record if addr_hi is new. */ - old_addr_hi = addr_hi; - ihex_write_04(ofd, addr_hi); - } - ihex_write_00(ofd, sh.sh_addr, d->d_buf, d->d_size); - } - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); - - if (gelf_getehdr(e, &eh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - ihex_write_05(ofd, eh.e_entry); - ihex_write_01(ofd); -} - -void -create_elf_from_ihex(struct elfcopy *ecp, int ifd) -{ - char line[_LINE_BUFSZ]; - uint8_t data[_DATA_BUFSZ]; - GElf_Ehdr oeh; - struct section *s, *shtab; - FILE *ifp; - uint64_t addr, addr_base, entry, num, off, rec_addr, sec_addr; - size_t sz; - int _ifd, first, sec_index; - char type; - - if ((_ifd = dup(ifd)) < 0) - err(EXIT_FAILURE, "dup failed"); - if ((ifp = fdopen(_ifd, "r")) == NULL) - err(EXIT_FAILURE, "fdopen failed"); - - /* Create EHDR for output .o file. */ - if (gelf_newehdr(ecp->eout, ecp->oec) == NULL) - errx(EXIT_FAILURE, "gelf_newehdr failed: %s", - elf_errmsg(-1)); - if (gelf_getehdr(ecp->eout, &oeh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - /* Initialise e_ident fields. */ - oeh.e_ident[EI_CLASS] = ecp->oec; - oeh.e_ident[EI_DATA] = ecp->oed; - /* - * TODO: Set OSABI according to the OS platform where elfcopy(1) - * was build. (probably) - */ - oeh.e_ident[EI_OSABI] = ELFOSABI_NONE; - oeh.e_machine = ecp->oem; - oeh.e_type = ET_REL; - oeh.e_entry = 0; - - ecp->flags |= RELOCATABLE; - - /* Create .shstrtab section */ - init_shstrtab(ecp); - ecp->shstrtab->off = 0; - - /* Data sections are inserted after EHDR. */ - off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT); - if (off == 0) - errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); - - /* Create data sections. */ - s = NULL; - first = 1; - sec_index = 1; - addr_base = rec_addr = sec_addr = entry = 0; - while (fgets(line, _LINE_BUFSZ, ifp) != NULL) { - if (line[0] == '\r' || line[0] == '\n') - continue; - if (line[0] != ':') { - warnx("Invalid ihex record"); - continue; - } - if (ihex_read(line, &type, &addr, &num, data, &sz) < 0) { - warnx("Invalid ihex record or mismatched checksum"); - continue; - } - switch (type) { - case '0': - /* Data record. */ - if (sz == 0) - break; - rec_addr = addr_base + addr; - if (first || sec_addr != rec_addr) { - if (s != NULL) - finalize_data_section(s); - s = new_data_section(ecp, sec_index, off, - rec_addr); - if (s == NULL) { - warnx("new_data_section failed"); - break; - } - sec_index++; - sec_addr = rec_addr; - first = 0; - } - append_data(s, data, sz); - off += sz; - sec_addr += sz; - break; - case '1': - /* End of file record. */ - goto done; - case '2': - /* Extended segment address record. */ - addr_base = addr << 4; - break; - case '3': - /* Start segment address record (CS:IP). Ignored. */ - break; - case '4': - /* Extended linear address record. */ - addr_base = num << 16; - break; - case '5': - /* Start linear address record. */ - entry = num; - break; - default: - break; - } - } -done: - if (s != NULL) - finalize_data_section(s); - if (ferror(ifp)) - warn("fgets failed"); - fclose(ifp); - - /* Insert .shstrtab after data sections. */ - if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL) - errx(EXIT_FAILURE, "elf_newscn failed: %s", - elf_errmsg(-1)); - insert_to_sec_list(ecp, ecp->shstrtab, 1); - - /* Insert section header table here. */ - shtab = insert_shtab(ecp, 1); - - /* Set entry point. */ - oeh.e_entry = entry; - - /* - * Write the underlying ehdr. Note that it should be called - * before elf_setshstrndx() since it will overwrite e->e_shstrndx. - */ - if (gelf_update_ehdr(ecp->eout, &oeh) == 0) - errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", - elf_errmsg(-1)); - - /* Generate section name string table (.shstrtab). */ - set_shstrtab(ecp); - - /* Update sh_name pointer for each section header entry. */ - update_shdr(ecp, 0); - - /* Renew oeh to get the updated e_shstrndx. */ - if (gelf_getehdr(ecp->eout, &oeh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - /* Resync section offsets. */ - resync_sections(ecp); - - /* Store SHDR offset in EHDR. */ - oeh.e_shoff = shtab->off; - - /* Update ehdr since we modified e_shoff. */ - if (gelf_update_ehdr(ecp->eout, &oeh) == 0) - errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", - elf_errmsg(-1)); - - /* Write out the output elf object. */ - if (elf_update(ecp->eout, ELF_C_WRITE) < 0) - errx(EXIT_FAILURE, "elf_update() failed: %s", - elf_errmsg(-1)); - - /* Release allocated resource. */ - free_elf(ecp); -} - -#define _SEC_NAMESZ 64 -#define _SEC_INIT_CAP 1024 - -static struct section * -new_data_section(struct elfcopy *ecp, int sec_index, uint64_t off, - uint64_t addr) -{ - char *name; - - if ((name = malloc(_SEC_NAMESZ)) == NULL) - errx(EXIT_FAILURE, "malloc failed"); - snprintf(name, _SEC_NAMESZ, ".sec%d", sec_index); - - return (create_external_section(ecp, name, name, NULL, 0, off, - SHT_PROGBITS, ELF_T_BYTE, SHF_ALLOC | SHF_WRITE, 1, addr, 0)); -} - -static void -finalize_data_section(struct section *s) -{ - Elf_Data *od; - - if ((od = elf_newdata(s->os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s", - elf_errmsg(-1)); - od->d_align = s->align; - od->d_off = 0; - od->d_buf = s->buf; - od->d_size = s->sz; - od->d_version = EV_CURRENT; -} - -static void -append_data(struct section *s, const void *buf, size_t sz) -{ - uint8_t *p; - - if (s->buf == NULL) { - s->sz = 0; - s->cap = _SEC_INIT_CAP; - if ((s->buf = malloc(s->cap)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - } - - while (sz + s->sz > s->cap) { - s->cap *= 2; - if ((s->buf = realloc(s->buf, s->cap)) == NULL) - err(EXIT_FAILURE, "realloc failed"); - } - - p = s->buf; - memcpy(&p[s->sz], buf, sz); - s->sz += sz; -} - -static int -srec_read(const char *line, char *type, uint64_t *addr, uint8_t *data, - size_t *sz) -{ - uint64_t count, _checksum, num; - size_t addr_sz; - int checksum, i, len; - - checksum = 0; - len = 2; - if (read_num(line, &len, &count, 1, &checksum) < 0) - return (-1); - *type = line[1]; - switch (*type) { - case '0': - case '1': - case '5': - case '9': - addr_sz = 2; - break; - case '2': - case '8': - addr_sz = 3; - break; - case '3': - case '7': - addr_sz = 4; - break; - default: - return (-1); - } - - if (read_num(line, &len, addr, addr_sz, &checksum) < 0) - return (-1); - - count -= addr_sz + 1; - if (*type >= '0' && *type <= '3') { - for (i = 0; (uint64_t) i < count; i++) { - if (read_num(line, &len, &num, 1, &checksum) < 0) - return -1; - data[i] = (uint8_t) num; - } - *sz = count; - } else - *sz = 0; - - if (read_num(line, &len, &_checksum, 1, NULL) < 0) - return (-1); - - if ((int) _checksum != (~checksum & 0xFF)) - return (-1); - - return (0); -} - -static void -srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn, GElf_Shdr *sh) -{ - char line[_LINE_BUFSZ]; - GElf_Sym sym; - Elf_Data *d; - const char *name; - size_t sc; - int elferr, i; - -#define _WRITE_LINE do { \ - if (write(ofd, line, strlen(line)) != (ssize_t) strlen(line)) \ - errx(EXIT_FAILURE, "write failed"); \ - } while (0) - - - (void) elf_errno(); - if ((d = elf_getdata(scn, NULL)) == NULL) { - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_getdata failed: %s", - elf_errmsg(-1)); - return; - } - if (d->d_buf == NULL || d->d_size == 0) - return; - - snprintf(line, sizeof(line), "$$ %s\r\n", ofn); - _WRITE_LINE; - sc = d->d_size / sh->sh_entsize; - for (i = 1; (size_t) i < sc; i++) { - if (gelf_getsym(d, i, &sym) != &sym) { - warnx("gelf_getsym failed: %s", elf_errmsg(-1)); - continue; - } - if (GELF_ST_TYPE(sym.st_info) == STT_SECTION || - GELF_ST_TYPE(sym.st_info) == STT_FILE) - continue; - if ((name = elf_strptr(e, sh->sh_link, sym.st_name)) == NULL) { - warnx("elf_strptr failed: %s", elf_errmsg(-1)); - continue; - } - snprintf(line, sizeof(line), " %s $%jx\r\n", name, - (uintmax_t) sym.st_value); - _WRITE_LINE; - } - snprintf(line, sizeof(line), "$$ \r\n"); - _WRITE_LINE; - -#undef _WRITE_LINE -} - -static void -srec_write_S0(int ofd, const char *ofn) -{ - - srec_write(ofd, '0', 0, ofn, strlen(ofn)); -} - -static void -srec_write_Sd(int ofd, char dr, uint64_t addr, const void *buf, size_t sz, - size_t rlen) -{ - const uint8_t *p, *pe; - - p = buf; - pe = p + sz; - while (pe - p >= (int) rlen) { - srec_write(ofd, dr, addr, p, rlen); - addr += rlen; - p += rlen; - } - if (pe - p > 0) - srec_write(ofd, dr, addr, p, pe - p); -} - -static void -srec_write_Se(int ofd, uint64_t e_entry, int forceS3) -{ - char er; - - if (e_entry > 0xFFFFFFFF) { - warnx("address space too big for S-Record file"); - return; - } - - if (forceS3) - er = '7'; - else { - if (e_entry <= 0xFFFF) - er = '9'; - else if (e_entry <= 0xFFFFFF) - er = '8'; - else - er = '7'; - } - - srec_write(ofd, er, e_entry, NULL, 0); -} - -static void -srec_write(int ofd, char type, uint64_t addr, const void *buf, size_t sz) -{ - char line[_LINE_BUFSZ]; - const uint8_t *p, *pe; - int len, addr_sz, checksum; - - if (type == '0' || type == '1' || type == '5' || type == '9') - addr_sz = 2; - else if (type == '2' || type == '8') - addr_sz = 3; - else - addr_sz = 4; - - checksum = 0; - line[0] = 'S'; - line[1] = type; - len = 2; - write_num(line, &len, addr_sz + sz + 1, 1, &checksum); - write_num(line, &len, addr, addr_sz, &checksum); - for (p = buf, pe = p + sz; p < pe; p++) - write_num(line, &len, *p, 1, &checksum); - write_num(line, &len, ~checksum & 0xFF, 1, NULL); - line[len++] = '\r'; - line[len++] = '\n'; - if (write(ofd, line, len) != (ssize_t) len) - err(EXIT_FAILURE, "write failed"); -} - -static void -ihex_write_00(int ofd, uint64_t addr, const void *buf, size_t sz) -{ - uint16_t addr_hi, old_addr_hi; - const uint8_t *p, *pe; - - old_addr_hi = (addr >> 16) & 0xFFFF; - p = buf; - pe = p + sz; - while (pe - p >= 16) { - ihex_write(ofd, 0, addr, 0, p, 16); - addr += 16; - p += 16; - addr_hi = (addr >> 16) & 0xFFFF; - if (addr_hi != old_addr_hi) { - old_addr_hi = addr_hi; - ihex_write_04(ofd, addr_hi); - } - } - if (pe - p > 0) - ihex_write(ofd, 0, addr, 0, p, pe - p); -} - -static int -ihex_read(const char *line, char *type, uint64_t *addr, uint64_t *num, - uint8_t *data, size_t *sz) -{ - uint64_t count, _checksum; - int checksum, i, len; - - *sz = 0; - checksum = 0; - len = 1; - if (read_num(line, &len, &count, 1, &checksum) < 0) - return (-1); - if (read_num(line, &len, addr, 2, &checksum) < 0) - return (-1); - if (line[len++] != '0') - return (-1); - *type = line[len++]; - checksum += *type - '0'; - switch (*type) { - case '0': - for (i = 0; (uint64_t) i < count; i++) { - if (read_num(line, &len, num, 1, &checksum) < 0) - return (-1); - data[i] = (uint8_t) *num; - } - *sz = count; - break; - case '1': - if (count != 0) - return (-1); - break; - case '2': - case '4': - if (count != 2) - return (-1); - if (read_num(line, &len, num, 2, &checksum) < 0) - return (-1); - break; - case '3': - case '5': - if (count != 4) - return (-1); - if (read_num(line, &len, num, 4, &checksum) < 0) - return (-1); - break; - default: - return (-1); - } - - if (read_num(line, &len, &_checksum, 1, &checksum) < 0) - return (-1); - - if ((checksum & 0xFF) != 0) { - return (-1); - } - - return (0); -} - -static void -ihex_write_01(int ofd) -{ - - ihex_write(ofd, 1, 0, 0, NULL, 0); -} - -static void -ihex_write_04(int ofd, uint16_t addr) -{ - - ihex_write(ofd, 4, 0, addr, NULL, 2); -} - -static void -ihex_write_05(int ofd, uint64_t e_entry) -{ - - if (e_entry > 0xFFFFFFFF) { - warnx("address space too big for Intel Hex file"); - return; - } - - ihex_write(ofd, 5, 0, e_entry, NULL, 4); -} - -static void -ihex_write(int ofd, int type, uint64_t addr, uint64_t num, const void *buf, - size_t sz) -{ - char line[_LINE_BUFSZ]; - const uint8_t *p, *pe; - int len, checksum; - - if (sz > 16) - errx(EXIT_FAILURE, "Internal: ihex_write() sz too big"); - checksum = 0; - line[0] = ':'; - len = 1; - write_num(line, &len, sz, 1, &checksum); - write_num(line, &len, addr, 2, &checksum); - write_num(line, &len, type, 1, &checksum); - if (sz > 0) { - if (buf != NULL) { - for (p = buf, pe = p + sz; p < pe; p++) - write_num(line, &len, *p, 1, &checksum); - } else - write_num(line, &len, num, sz, &checksum); - } - write_num(line, &len, (~checksum + 1) & 0xFF, 1, NULL); - line[len++] = '\r'; - line[len++] = '\n'; - if (write(ofd, line, len) != (ssize_t) len) - err(EXIT_FAILURE, "write failed"); -} - -static int -read_num(const char *line, int *len, uint64_t *num, size_t sz, int *checksum) -{ - uint8_t b; - - *num = 0; - for (; sz > 0; sz--) { - if (!ishexdigit(line[*len]) || !ishexdigit(line[*len + 1])) - return (-1); - b = (hex_value(line[*len]) << 4) | hex_value(line[*len + 1]); - *num = (*num << 8) | b; - *len += 2; - if (checksum != NULL) - *checksum = (*checksum + b) & 0xFF; - } - - return (0); -} - -static void -write_num(char *line, int *len, uint64_t num, size_t sz, int *checksum) -{ - uint8_t b; - - for (; sz > 0; sz--) { - b = (num >> ((sz - 1) * 8)) & 0xFF; - line[*len] = hex_digit((b >> 4) & 0xF); - line[*len + 1] = hex_digit(b & 0xF); - *len += 2; - if (checksum != NULL) - *checksum = (*checksum + b) & 0xFF; - } -} - -static char -hex_digit(uint8_t n) -{ - - return ((n < 10) ? '0' + n : 'A' + (n - 10)); -} - -static int -hex_value(int x) -{ - - if (isdigit(x)) - return (x - '0'); - else if (x >= 'a' && x <= 'f') - return (x - 'a' + 10); - else - return (x - 'A' + 10); -} - -static int -ishexdigit(int x) -{ - - if (isdigit(x)) - return (1); - if ((x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F')) - return (1); - - return (0); -} diff --git a/contrib/elftoolchain/elfcopy/binary.c b/contrib/elftoolchain/elfcopy/binary.c deleted file mode 100644 index 23e46e77f392..000000000000 --- a/contrib/elftoolchain/elfcopy/binary.c +++ /dev/null @@ -1,285 +0,0 @@ -/*- - * Copyright (c) 2010,2011 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/stat.h> -#include <err.h> -#include <gelf.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "elfcopy.h" - -ELFTC_VCSID("$Id: binary.c 3174 2015-03-27 17:13:41Z emaste $"); - -/* - * Convert ELF object to `binary'. Sections with SHF_ALLOC flag set - * are copied to the result binary. The relative offsets for each section - * are retained, so the result binary file might contain "holes". - */ -void -create_binary(int ifd, int ofd) -{ - Elf *e; - Elf_Scn *scn; - Elf_Data *d; - GElf_Shdr sh; - off_t base, off; - int elferr; - - if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_begin() failed: %s", - elf_errmsg(-1)); - - base = 0; - if (lseek(ofd, base, SEEK_SET) < 0) - err(EXIT_FAILURE, "lseek failed"); - - /* - * Find base offset in the first iteration. - */ - base = -1; - scn = NULL; - while ((scn = elf_nextscn(e, scn)) != NULL) { - if (gelf_getshdr(scn, &sh) == NULL) { - warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); - (void) elf_errno(); - continue; - } - if ((sh.sh_flags & SHF_ALLOC) == 0 || - sh.sh_type == SHT_NOBITS || - sh.sh_size == 0) - continue; - if (base == -1 || (off_t) sh.sh_offset < base) - base = sh.sh_offset; - } - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); - - if (base == -1) - return; - - /* - * Write out sections in the second iteration. - */ - scn = NULL; - while ((scn = elf_nextscn(e, scn)) != NULL) { - if (gelf_getshdr(scn, &sh) == NULL) { - warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); - (void) elf_errno(); - continue; - } - if ((sh.sh_flags & SHF_ALLOC) == 0 || - sh.sh_type == SHT_NOBITS || - sh.sh_size == 0) - continue; - (void) elf_errno(); - if ((d = elf_getdata(scn, NULL)) == NULL) { - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_getdata failed: %s", elf_errmsg(-1)); - continue; - } - if (d->d_buf == NULL || d->d_size == 0) - continue; - - /* lseek to section offset relative to `base'. */ - off = sh.sh_offset - base; - if (lseek(ofd, off, SEEK_SET) < 0) - err(EXIT_FAILURE, "lseek failed"); - - /* Write out section contents. */ - if (write(ofd, d->d_buf, d->d_size) != (ssize_t) d->d_size) - err(EXIT_FAILURE, "write failed"); - } - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); -} - -#define _SYMBOL_NAMSZ 1024 - -/* - * Convert `binary' to ELF object. The input `binary' is converted to - * a relocatable (.o) file, a few symbols will also be created to make - * it easier to access the binary data in other compilation units. - */ -void -create_elf_from_binary(struct elfcopy *ecp, int ifd, const char *ifn) -{ - char name[_SYMBOL_NAMSZ]; - struct section *sec, *sec_temp, *shtab; - struct stat sb; - GElf_Ehdr oeh; - GElf_Shdr sh; - void *content; - uint64_t off, data_start, data_end, data_size; - - /* Reset internal section list. */ - if (!TAILQ_EMPTY(&ecp->v_sec)) - TAILQ_FOREACH_SAFE(sec, &ecp->v_sec, sec_list, sec_temp) { - TAILQ_REMOVE(&ecp->v_sec, sec, sec_list); - free(sec); - } - - if (fstat(ifd, &sb) == -1) - err(EXIT_FAILURE, "fstat failed"); - - /* Read the input binary file to a internal buffer. */ - if ((content = malloc(sb.st_size)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - if (read(ifd, content, sb.st_size) != sb.st_size) - err(EXIT_FAILURE, "read failed"); - - /* - * TODO: copy the input binary to output binary verbatim if -O is not - * specified. - */ - - /* Create EHDR for output .o file. */ - if (gelf_newehdr(ecp->eout, ecp->oec) == NULL) - errx(EXIT_FAILURE, "gelf_newehdr failed: %s", - elf_errmsg(-1)); - if (gelf_getehdr(ecp->eout, &oeh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - /* Initialise e_ident fields. */ - oeh.e_ident[EI_CLASS] = ecp->oec; - oeh.e_ident[EI_DATA] = ecp->oed; - /* - * TODO: Set OSABI according to the OS platform where elfcopy(1) - * was build. (probably) - */ - oeh.e_ident[EI_OSABI] = ELFOSABI_NONE; - oeh.e_machine = ecp->oem; - oeh.e_type = ET_REL; - oeh.e_entry = 0; - - ecp->flags |= RELOCATABLE; - - /* Create .shstrtab section */ - init_shstrtab(ecp); - ecp->shstrtab->off = 0; - - /* - * Create `.data' section which contains the binary data. The - * section is inserted immediately after EHDR. - */ - off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT); - if (off == 0) - errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); - (void) create_external_section(ecp, ".data", NULL, content, sb.st_size, - off, SHT_PROGBITS, ELF_T_BYTE, SHF_ALLOC | SHF_WRITE, 1, 0, 1); - - /* Insert .shstrtab after .data section. */ - if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL) - errx(EXIT_FAILURE, "elf_newscn failed: %s", - elf_errmsg(-1)); - insert_to_sec_list(ecp, ecp->shstrtab, 1); - - /* Insert section header table here. */ - shtab = insert_shtab(ecp, 1); - - /* Count in .symtab and .strtab section headers. */ - shtab->sz += gelf_fsize(ecp->eout, ELF_T_SHDR, 2, EV_CURRENT); - -#define _GEN_SYMNAME(S) do { \ - snprintf(name, sizeof(name), "%s%s%s", "_binary_", ifn, S); \ -} while (0) - - /* - * Create symbol table. - */ - create_external_symtab(ecp); - data_start = 0; - data_end = data_start + sb.st_size; - data_size = sb.st_size; - _GEN_SYMNAME("_start"); - add_to_symtab(ecp, name, data_start, 0, 1, - ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1); - _GEN_SYMNAME("_end"); - add_to_symtab(ecp, name, data_end, 0, 1, - ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1); - _GEN_SYMNAME("_size"); - add_to_symtab(ecp, name, data_size, 0, SHN_ABS, - ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1); - finalize_external_symtab(ecp); - create_symtab_data(ecp); -#undef _GEN_SYMNAME - - /* - * Write the underlying ehdr. Note that it should be called - * before elf_setshstrndx() since it will overwrite e->e_shstrndx. - */ - if (gelf_update_ehdr(ecp->eout, &oeh) == 0) - errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", - elf_errmsg(-1)); - - /* Generate section name string table (.shstrtab). */ - ecp->flags |= SYMTAB_EXIST; - set_shstrtab(ecp); - - /* Update sh_name pointer for each section header entry. */ - update_shdr(ecp, 0); - - /* Properly set sh_link field of .symtab section. */ - if (gelf_getshdr(ecp->symtab->os, &sh) == NULL) - errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s", - elf_errmsg(-1)); - sh.sh_link = elf_ndxscn(ecp->strtab->os); - if (!gelf_update_shdr(ecp->symtab->os, &sh)) - errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", - elf_errmsg(-1)); - - /* Renew oeh to get the updated e_shstrndx. */ - if (gelf_getehdr(ecp->eout, &oeh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - /* Resync section offsets. */ - resync_sections(ecp); - - /* Store SHDR offset in EHDR. */ - oeh.e_shoff = shtab->off; - - /* Update ehdr since we modified e_shoff. */ - if (gelf_update_ehdr(ecp->eout, &oeh) == 0) - errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", - elf_errmsg(-1)); - - /* Write out the output elf object. */ - if (elf_update(ecp->eout, ELF_C_WRITE) < 0) - errx(EXIT_FAILURE, "elf_update() failed: %s", - elf_errmsg(-1)); - - /* Release allocated resource. */ - free(content); - free_elf(ecp); -} diff --git a/contrib/elftoolchain/elfcopy/elfcopy.1 b/contrib/elftoolchain/elfcopy/elfcopy.1 deleted file mode 100644 index 4889570ebc8e..000000000000 --- a/contrib/elftoolchain/elfcopy/elfcopy.1 +++ /dev/null @@ -1,333 +0,0 @@ -.\" Copyright (c) 2008-2009,2011 Joseph Koshy. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" This software is provided by Joseph Koshy ``as is'' and -.\" any express or implied warranties, including, but not limited to, the -.\" implied warranties of merchantability and fitness for a particular purpose -.\" are disclaimed. in no event shall Joseph Koshy be liable -.\" for any direct, indirect, incidental, special, exemplary, or consequential -.\" damages (including, but not limited to, procurement of substitute goods -.\" or services; loss of use, data, or profits; or business interruption) -.\" however caused and on any theory of liability, whether in contract, strict -.\" liability, or tort (including negligence or otherwise) arising in any way -.\" out of the use of this software, even if advised of the possibility of -.\" such damage. -.\" -.\" $Id: elfcopy.1 3195 2015-05-12 17:22:19Z emaste $ -.\" -.Dd March 27, 2015 -.Os -.Dt ELFCOPY 1 -.Sh NAME -.Nm elfcopy -.Nd copy and translate object files -.Sh SYNOPSIS -.Nm -.Op Fl I Ar objformat | Fl s Ar objformat | Fl -input-target= Ns Ar objformat -.Op Fl K Ar symbolname | Fl -keep-symbol= Ns Ar symbolname -.Op Fl L Ar symbolname | Fl -localize-symbol= Ns Ar symbolname -.Op Fl N Ar symbolname | Fl -strip-symbol= Ns Ar symbolname -.Op Fl O Ar objformat | Fl -output-target= Ns Ar objformat -.Op Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname -.Op Fl S | Fl -strip-all -.Op Fl V | Fl -version -.Op Fl W Ar symbolname | Fl -weaken-symbol= Ns Ar symbolname -.Op Fl X | Fl -discard-locals -.Op Fl d | Fl g | Fl -strip-debug -.Op Fl h | Fl -help -.Op Fl j Ar sectionname | Fl -only-section= Ns Ar sectionname -.Op Fl p | Fl -preserve-dates -.Op Fl w | Fl -wildcard -.Op Fl x | Fl -discard-all -.Op Fl -add-section Ar sectionname Ns = Ns Ar filename -.Oo -.Fl -adjust-section-vma Ar section Ns {+|-|=} Ns Ar val | -.Fl -change-section-address Ar section Ns {+|-|=} Ns Ar val -.Oc -.Oo -.Fl -adjust-start Ns = Ns Ar increment | -.Fl -change-start Ns = Ns Ar increment -.Oc -.Oo -.Fl -adjust-vma Ns = Ns Ar increment | -.Fl -change-addresses Ns = Ns Ar increment -.Oc -.Op Fl -adjust-warnings | Fl -change-warnings -.Op Fl -change-section-lma Ar section Ns {+|-|=} Ns Ar val -.Op Fl -change-section-vma Ar section Ns {+|-|=} Ns Ar val -.Op Fl -extract-dwo -.Op Fl -gap-fill Ns = Ns Ar val -.Op Fl -localize-hidden -.Op Fl -no-adjust-warnings | Fl -no-change-warnings -.Op Fl -only-keep-debug -.Op Fl -pad-to Ns = Ns Ar address -.Op Fl -prefix-alloc-sections Ns = Ns Ar string -.Op Fl -prefix-sections Ns = Ns Ar string -.Op Fl -prefix-symbols Ns = Ns Ar string -.Op Fl -rename-section Ar oldname Ns = Ns Ar newname Ns Op Ar ,flags -.Op Fl -set-section-flags Ar sectionname Ns = Ns Ar flags -.Op Fl -set-start Ns = Ns Ar address -.Op Fl -srec-forceS3 -.Op Fl -srec-len Ns = Ns Ar val -.Op Fl -strip-dwo -.Op Fl -strip-unneeded -.Ar infile -.Op Ar outfile -.Sh DESCRIPTION -The -.Nm -utility copies the content of the ELF object named by argument -.Ar infile -to that named by argument -.Ar outfile , -transforming it according to the command line options specified. -If argument -.Ar outfile -is not specified, -.Nm -will create a temporary file and will subsequently rename it as -.Ar infile . -.Pp -The -.Nm -utility supports the following options: -.Bl -tag -width indent -.It Fl I Ar objformat | Fl s Ar objformat | Fl -input-target= Ns Ar objformat -Specify that the input file named by the argument -.Ar infile -is in the object format specified by the argument -.Ar objformat . -.It Fl K Ar symbolname | Fl -keep-symbol= Ns Ar symbolname -Copy the symbol named by argument -.Ar symbolname -to the output. -.It Fl L Ar symbolname | Fl -localize-symbol= Ns Ar symbolname -Make the symbol named by argument -.Ar symbolname -local to the output file. -.It Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbolname -Do not copy the symbol named by argument -.Ar symbolname -to the output. -.It Fl O Ar objformat | Fl -output-target= Ns Ar objformat -Write the output file using the object format specified in argument -.Ar objformat . -.It Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname -Remove any section with name -.Ar sectionname -from the output file. -.It Fl S | Fl -strip-all -Do not copy symbol and relocation information to the target file. -.It Fl V | Fl -version -Print a version identifier and exit. -.It Fl W Ar symbolname | Fl -weaken-symbol= Ns Ar symbolname -Mark the symbol named by argument -.Ar symbolname -as weak in the output. -.It Fl X | Fl -discard-locals -Do not copy compiler generated local symbols to the output. -.It Fl d | Fl g | Fl -strip-debug -Do not copy debugging information to the target file. -.It Fl h | Fl -help -Display a help message and exit. -.It Fl j Ar sectionname | Fl -only-section= Ns Ar sectionname -Copy only the section named by argument -.Ar sectionname -to the output. -.It Fl p | Fl -preserve-dates -Set the access and modification times of the output file to the -same as those of the input. -.It Fl w | Fl -wildcard -Use shell-style patterns to name symbols. -The following meta-characters are recognized in patterns: -.Bl -tag -width "...." -compact -.It Li ! -If this is the first character of the pattern, invert the sense of the -pattern match. -.It Li * -Matches any string of characters in a symbol name. -.It Li ? -Matches zero or one character in a symbol name. -.It Li [ -Mark the start of a character class. -.It Li \e -Remove the special meaning of the next character in the pattern. -.It Li ] -Mark the end of a character class. -.El -.It Fl x | Fl -discard-all -Do not copy non-global symbols to the output. -.It Fl -add-section Ar sectionname Ns = Ns Ar filename -Add a new section to the output file with name -.Ar sectionname . -The contents of the section are taken from the file named by -argument -.Ar filename . -The size of the section will be the number of bytes in file -.Ar filename . -.It Xo -.Fl -adjust-section-vma Ar section Ns {+|-|=} Ns Ar val | -.Fl -change-section-address Ar section Ns {+|-|=} Ns Ar val -.Xc -Depending on the operator specified, increase, decrease or set both -the virtual memory address and the load memory address of the section -named by the argument -.Ar section . -The argument -.Ar val -specifies the desired increment, decrement or new value for the -address. -.It Xo -.Fl -adjust-start Ns = Ns Ar increment | -.Fl -change-start Ns = Ns Ar increment -.Xc -Increase the entry point address of the output ELF object by the value -specified in the argument -.Ar increment . -.It Xo -.Fl -adjust-vma Ns = Ns Ar increment | -.Fl -change-addresses Ns = Ns Ar increment -.Xc -Increase the virtual memory address and the load memory address of all -sections by the value specified by the argument -.Ar increment . -.It Fl -adjust-warnings | Fl -change-warnings -Issue a warning if the section specified by the options -.Fl -change-section-address , -.Fl -change-section-lma -or -.Fl -change-section-vma -does not exist in the input object. -This is the default. -.It Fl -change-section-lma Ar section Ns {+|-|=} Ns Ar val -Change or set the load memory address of the section named by the -argument -.Ar section . -Depending on the operator specified, the value in argument -.Ar val -will be used as an increment, a decrement or as the new value -of the load memory address. -.It Fl -change-section-vma Ar section Ns {+|-|=} Ns Ar val -Change or set the virtual memory address of the section named by the -argument -.Ar section . -Depending on the operator specified, the value in argument -.Ar val -will be used as an increment, a decrement or as the new value -of the virtual memory address. -.It Fl -extract-dwo -Copy only .dwo debug sections to the output file. -.It Fl -gap-fill Ns = Ns Ar val -Fill the gaps between sections with the byte value specified by -the argument -.Ar val . -.It Fl -localize-hidden -Make all hidden symbols local to the output file. -This includes symbols with internal visiblity. -.It Fl -no-adjust-warnings | Fl -no-change-warnings -Do not issue a warning if the section specified by the options -.Fl -change-section-address , -.Fl -change-section-lma -or -.Fl -change-section-vma -is missing in the input object. -.It Fl -only-keep-debug -Copy only debugging information to the output file. -.It Fl -pad-to Ns = Ns Ar address -Pad the load memory address of the output object to the value -specified by the argument -.Ar address -by increasing the size of the section with the highest load memory -address. -.It Fl -prefix-alloc-sections Ns = Ns Ar string -Prefix the section names of all the allocated sections with -.Ar string . -.It Fl -prefix-sections Ns = Ns Ar string -Prefix the section names of all the sections with -.Ar string . -.It Fl -prefix-symbols Ns = Ns Ar string -Prefix the symbol names of all the symbols with -.Ar string . -.It Fl -rename-section Ar oldname Ns = Ns Ar newname Ns Op Ar ,flags -Rename the section named by argument -.Ar oldname -to -.Ar newname , -optionally changing the sections flags to that specified by argument -.Ar flags . -Allowed values for the argument -.Ar flags -are as for option -.Fl -set-section-flags -below. -.It Fl -set-section-flags Ar sectionname Ns = Ns Ar flags -Set the flags for the section named by argument -.Ar sectionname -to those specified by argument -.Ar flags . -Argument -.Ar flags -is a comma separated list of the following flag names: -.Bl -tag -width "readonly" -compact -.It alloc -The section occupies space in the output file. -.It code -The section contains machine instructions. -.It contents -This flag is accepted but is ignored. -.It data -The section contains writeable data. -.It debug -The section holds debugging information. -.It load -The section is loadable. -.It noload -The section should not be loaded into memory. -.It readonly -The section is not writable. -.It rom -The section contains ROM'able contents. -.It share -This flag is accepted but is ignored. -.El -.It Fl -set-start Ns = Ns Ar address -Set the start address of the output ELF object to the value specified -by the argument -.Ar address . -.It Fl -srec-forceS3 -Only generate S-records of type -.Dq S3 . -This option is only meaningful when the output target is set to -.Dq srec . -.It Fl -srec-len Ns = Ns Ar val -Set the maximum length of an S-record line to -.Ar val . -This option is only meaningful when the output target is set to -.Dq srec . -.It Fl -strip-dwo -Do not copy .dwo debug sections to the output file. -.It Fl -strip-unneeded -Do not copy symbols that are not needed for relocation processing. -.El -.Sh DIAGNOSTICS -.Ex -std -.Sh SEE ALSO -.Xr ar 1 , -.Xr ld 1 , -.Xr mcs 1 , -.Xr strip 1 , -.Xr elf 3 , -.Xr ar 5 , -.Xr elf 5 -.Sh HISTORY -.Nm -has been implemented by -.An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . diff --git a/contrib/elftoolchain/elfcopy/elfcopy.h b/contrib/elftoolchain/elfcopy/elfcopy.h deleted file mode 100644 index b750246d850d..000000000000 --- a/contrib/elftoolchain/elfcopy/elfcopy.h +++ /dev/null @@ -1,317 +0,0 @@ -/*- - * Copyright (c) 2007-2013 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: elfcopy.h 3173 2015-03-27 16:46:13Z emaste $ - */ - -#include <sys/queue.h> -#include <gelf.h> -#include <libelftc.h> - -#include "_elftc.h" - -/* - * User specified symbol operation (strip, keep, localize, globalize, - * weaken, rename, etc). - */ -struct symop { - const char *name; - const char *newname; - -#define SYMOP_KEEP 0x0001U -#define SYMOP_STRIP 0x0002U -#define SYMOP_GLOBALIZE 0x0004U -#define SYMOP_LOCALIZE 0x0008U -#define SYMOP_KEEPG 0x0010U -#define SYMOP_WEAKEN 0x0020U -#define SYMOP_REDEF 0x0040U - - unsigned int op; - - STAILQ_ENTRY(symop) symop_list; -}; - -/* File containing symbol list. */ -struct symfile { - dev_t dev; - ino_t ino; - size_t size; - char *data; - unsigned int op; - - STAILQ_ENTRY(symfile) symfile_list; -}; - -/* Sections to copy/remove/rename/... */ -struct sec_action { - const char *name; - const char *addopt; - const char *newname; - const char *string; - uint64_t lma; - uint64_t vma; - int64_t lma_adjust; - int64_t vma_adjust; - -#define SF_ALLOC 0x0001U -#define SF_LOAD 0x0002U -#define SF_NOLOAD 0x0004U -#define SF_READONLY 0x0008U -#define SF_DEBUG 0x0010U -#define SF_CODE 0x0020U -#define SF_DATA 0x0040U -#define SF_ROM 0x0080U -#define SF_SHARED 0X0100U -#define SF_CONTENTS 0x0200U - - int flags; - int add; - int append; - int compress; - int copy; - int print; - int remove; - int rename; - int setflags; - int setlma; - int setvma; - - STAILQ_ENTRY(sec_action) sac_list; -}; - -/* Sections to add from file. */ -struct sec_add { - char *name; - char *content; - size_t size; - - STAILQ_ENTRY(sec_add) sadd_list; -}; - -struct segment; - -/* Internal data structure for sections. */ -struct section { - struct segment *seg; /* containing segment */ - struct segment *seg_tls; /* tls segment */ - const char *name; /* section name */ - char *newname; /* new section name */ - Elf_Scn *is; /* input scn */ - Elf_Scn *os; /* output scn */ - void *buf; /* section content */ - uint8_t *pad; /* section padding */ - uint64_t off; /* section offset */ - uint64_t sz; /* section size */ - uint64_t cap; /* section capacity */ - uint64_t align; /* section alignment */ - uint64_t type; /* section type */ - uint64_t vma; /* section virtual addr */ - uint64_t lma; /* section load addr */ - uint64_t pad_sz;/* section padding size */ - int loadable; /* whether loadable */ - int pseudo; - int nocopy; - - TAILQ_ENTRY(section) sec_list; /* next section */ -}; - -/* Internal data structure for segments. */ -struct segment { - uint64_t addr; /* load addr */ - uint64_t off; /* file offset */ - uint64_t fsz; /* file size */ - uint64_t msz; /* memory size */ - uint64_t type; /* segment type */ - int remove; /* whether remove */ - int nsec; /* number of sections contained */ - struct section **v_sec; /* list of sections contained */ - - STAILQ_ENTRY(segment) seg_list; /* next segment */ -}; - -/* - * In-memory representation of ar(1) archive member(object). - */ -struct ar_obj { - char *name; /* member name */ - char *buf; /* member content */ - void *maddr; /* mmap start address */ - uid_t uid; /* user id */ - gid_t gid; /* group id */ - mode_t md; /* octal file permissions */ - size_t size; /* member size */ - time_t mtime; /* modification time */ - - STAILQ_ENTRY(ar_obj) objs; -}; - -/* - * Structure encapsulates the "global" data for "elfcopy" program. - */ -struct elfcopy { - const char *progname; /* program name */ - int iec; /* elfclass of input object */ - Elftc_Bfd_Target_Flavor itf; /* flavour of input object */ - Elftc_Bfd_Target_Flavor otf; /* flavour of output object */ - const char *otgt; /* output target name */ - int oec; /* elfclass of output object */ - unsigned char oed; /* endianess of output object */ - int oem; /* EM_XXX of output object */ - int abi; /* OSABI of output object */ - Elf *ein; /* ELF descriptor of input object */ - Elf *eout; /* ELF descriptor of output object */ - int iphnum; /* num. of input object phdr entries */ - int ophnum; /* num. of output object phdr entries */ - int nos; /* num. of output object sections */ - - enum { - STRIP_NONE = 0, - STRIP_ALL, - STRIP_DEBUG, - STRIP_DWO, - STRIP_NONDEBUG, - STRIP_NONDWO, - STRIP_UNNEEDED - } strip; - -#define EXECUTABLE 0x00000001U -#define DYNAMIC 0x00000002U -#define RELOCATABLE 0x00000004U -#define SYMTAB_EXIST 0x00000010U -#define SYMTAB_INTACT 0x00000020U -#define KEEP_GLOBAL 0x00000040U -#define DISCARD_LOCAL 0x00000080U -#define WEAKEN_ALL 0x00000100U -#define PRESERVE_DATE 0x00001000U -#define SREC_FORCE_S3 0x00002000U -#define SREC_FORCE_LEN 0x00004000U -#define SET_START 0x00008000U -#define GAP_FILL 0x00010000U -#define WILDCARD 0x00020000U -#define NO_CHANGE_WARN 0x00040000U -#define SEC_ADD 0x00080000U -#define SEC_APPEND 0x00100000U -#define SEC_COMPRESS 0x00200000U -#define SEC_PRINT 0x00400000U -#define SEC_REMOVE 0x00800000U -#define SEC_COPY 0x01000000U -#define DISCARD_LLABEL 0x02000000U -#define LOCALIZE_HIDDEN 0x04000000U - - int flags; /* elfcopy run control flags. */ - int64_t change_addr; /* Section address adjustment. */ - int64_t change_start; /* Entry point adjustment. */ - uint64_t set_start; /* Entry point value. */ - unsigned long srec_len; /* S-Record length. */ - uint64_t pad_to; /* load address padding. */ - uint8_t fill; /* gap fill value. */ - char *prefix_sec; /* section prefix. */ - char *prefix_alloc; /* alloc section prefix. */ - char *prefix_sym; /* symbol prefix. */ - char *debuglink; /* GNU debuglink file. */ - struct section *symtab; /* .symtab section. */ - struct section *strtab; /* .strtab section. */ - struct section *shstrtab; /* .shstrtab section. */ - uint64_t *secndx; /* section index map. */ - uint64_t *symndx; /* symbol index map. */ - unsigned char *v_rel; /* symbols needed by relocation. */ - unsigned char *v_secsym; /* sections with section symbol. */ - STAILQ_HEAD(, segment) v_seg; /* list of segments. */ - STAILQ_HEAD(, sec_action) v_sac;/* list of section operations. */ - STAILQ_HEAD(, sec_add) v_sadd; /* list of sections to add. */ - STAILQ_HEAD(, symop) v_symop; /* list of symbols operations. */ - STAILQ_HEAD(, symfile) v_symfile; /* list of symlist files. */ - TAILQ_HEAD(, section) v_sec; /* list of sections. */ - - /* - * Fields for the ar(1) archive. - */ - char *as; /* buffer for archive string table. */ - size_t as_sz; /* current size of as table. */ - size_t as_cap; /* capacity of as table buffer. */ - uint32_t s_cnt; /* current number of symbols. */ - uint32_t *s_so; /* symbol offset table. */ - size_t s_so_cap; /* capacity of so table buffer. */ - char *s_sn; /* symbol name table */ - size_t s_sn_cap; /* capacity of sn table buffer. */ - size_t s_sn_sz; /* current size of sn table. */ - off_t rela_off; /* offset relative to pseudo members. */ - STAILQ_HEAD(, ar_obj) v_arobj; /* archive object(member) list. */ -}; - -void add_section(struct elfcopy *_ecp, const char *_optarg); -void add_to_shstrtab(struct elfcopy *_ecp, const char *_name); -void add_to_symop_list(struct elfcopy *_ecp, const char *_name, - const char *_newname, unsigned int _op); -void add_to_symtab(struct elfcopy *_ecp, const char *_name, - uint64_t _st_value, uint64_t _st_size, uint16_t _st_shndx, - unsigned char _st_info, unsigned char _st_other, int _ndx_known); -int add_to_inseg_list(struct elfcopy *_ecp, struct section *_sec); -void adjust_addr(struct elfcopy *_ecp); -void copy_content(struct elfcopy *_ecp); -void copy_data(struct section *_s); -void copy_phdr(struct elfcopy *_ecp); -void copy_shdr(struct elfcopy *_ecp, struct section *_s, const char *_name, - int _copy, int _sec_flags); -void create_binary(int _ifd, int _ofd); -void create_elf(struct elfcopy *_ecp); -void create_elf_from_binary(struct elfcopy *_ecp, int _ifd, const char *ifn); -void create_elf_from_ihex(struct elfcopy *_ecp, int _ifd); -void create_elf_from_srec(struct elfcopy *_ecp, int _ifd); -struct section *create_external_section(struct elfcopy *_ecp, const char *_name, - char *_newname, void *_buf, uint64_t _size, uint64_t _off, uint64_t _stype, - Elf_Type _dtype, uint64_t flags, uint64_t _align, uint64_t _vma, - int _loadable); -void create_external_symtab(struct elfcopy *_ecp); -void create_ihex(int _ifd, int _ofd); -void create_scn(struct elfcopy *_ecp); -void create_srec(struct elfcopy *_ecp, int _ifd, int _ofd, const char *_ofn); -void create_symtab(struct elfcopy *_ecp); -void create_symtab_data(struct elfcopy *_ecp); -void create_tempfile(char **_fn, int *_fd); -void finalize_external_symtab(struct elfcopy *_ecp); -void free_elf(struct elfcopy *_ecp); -void free_sec_act(struct elfcopy *_ecp); -void free_sec_add(struct elfcopy *_ecp); -void free_symtab(struct elfcopy *_ecp); -void init_shstrtab(struct elfcopy *_ecp); -void insert_to_sec_list(struct elfcopy *_ecp, struct section *_sec, - int _tail); -struct section *insert_shtab(struct elfcopy *_ecp, int tail); -int is_remove_reloc_sec(struct elfcopy *_ecp, uint32_t _sh_info); -int is_remove_section(struct elfcopy *_ecp, const char *_name); -struct sec_action *lookup_sec_act(struct elfcopy *_ecp, - const char *_name, int _add); -struct symop *lookup_symop_list(struct elfcopy *_ecp, const char *_name, - unsigned int _op); -void resync_sections(struct elfcopy *_ecp); -void set_shstrtab(struct elfcopy *_ecp); -void setup_phdr(struct elfcopy *_ecp); -void update_shdr(struct elfcopy *_ecp, int _update_link); - -#ifndef LIBELF_AR -int ac_detect_ar(int _ifd); -void ac_create_ar(struct elfcopy *_ecp, int _ifd, int _ofd); -#endif /* ! LIBELF_AR */ diff --git a/contrib/elftoolchain/elfcopy/main.c b/contrib/elftoolchain/elfcopy/main.c deleted file mode 100644 index a48aea589748..000000000000 --- a/contrib/elftoolchain/elfcopy/main.c +++ /dev/null @@ -1,1530 +0,0 @@ -/*- - * Copyright (c) 2007-2013 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/stat.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <getopt.h> -#include <libelftc.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "elfcopy.h" - -ELFTC_VCSID("$Id: main.c 3174 2015-03-27 17:13:41Z emaste $"); - -enum options -{ - ECP_ADD_GNU_DEBUGLINK, - ECP_ADD_SECTION, - ECP_CHANGE_ADDR, - ECP_CHANGE_SEC_ADDR, - ECP_CHANGE_SEC_LMA, - ECP_CHANGE_SEC_VMA, - ECP_CHANGE_START, - ECP_CHANGE_WARN, - ECP_GAP_FILL, - ECP_GLOBALIZE_SYMBOL, - ECP_GLOBALIZE_SYMBOLS, - ECP_KEEP_SYMBOLS, - ECP_KEEP_GLOBAL_SYMBOLS, - ECP_LOCALIZE_HIDDEN, - ECP_LOCALIZE_SYMBOLS, - ECP_NO_CHANGE_WARN, - ECP_ONLY_DEBUG, - ECP_ONLY_DWO, - ECP_PAD_TO, - ECP_PREFIX_ALLOC, - ECP_PREFIX_SEC, - ECP_PREFIX_SYM, - ECP_REDEF_SYMBOL, - ECP_REDEF_SYMBOLS, - ECP_RENAME_SECTION, - ECP_SET_OSABI, - ECP_SET_SEC_FLAGS, - ECP_SET_START, - ECP_SREC_FORCE_S3, - ECP_SREC_LEN, - ECP_STRIP_DWO, - ECP_STRIP_SYMBOLS, - ECP_STRIP_UNNEEDED, - ECP_WEAKEN_ALL, - ECP_WEAKEN_SYMBOLS -}; - -static struct option mcs_longopts[] = -{ - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 } -}; - -static struct option strip_longopts[] = -{ - {"discard-all", no_argument, NULL, 'x'}, - {"discard-locals", no_argument, NULL, 'X'}, - {"help", no_argument, NULL, 'h'}, - {"input-target", required_argument, NULL, 'I'}, - {"keep-symbol", required_argument, NULL, 'K'}, - {"only-keep-debug", no_argument, NULL, ECP_ONLY_DEBUG}, - {"output-file", required_argument, NULL, 'o'}, - {"output-target", required_argument, NULL, 'O'}, - {"preserve-dates", no_argument, NULL, 'p'}, - {"remove-section", required_argument, NULL, 'R'}, - {"strip-all", no_argument, NULL, 's'}, - {"strip-debug", no_argument, NULL, 'S'}, - {"strip-symbol", required_argument, NULL, 'N'}, - {"strip-unneeded", no_argument, NULL, ECP_STRIP_UNNEEDED}, - {"version", no_argument, NULL, 'V'}, - {"wildcard", no_argument, NULL, 'w'}, - {NULL, 0, NULL, 0} -}; - -static struct option elfcopy_longopts[] = -{ - {"add-gnu-debuglink", required_argument, NULL, ECP_ADD_GNU_DEBUGLINK}, - {"add-section", required_argument, NULL, ECP_ADD_SECTION}, - {"adjust-section-vma", required_argument, NULL, ECP_CHANGE_SEC_ADDR}, - {"adjust-vma", required_argument, NULL, ECP_CHANGE_ADDR}, - {"adjust-start", required_argument, NULL, ECP_CHANGE_START}, - {"adjust-warnings", no_argument, NULL, ECP_CHANGE_WARN}, - {"binary-architecture", required_argument, NULL, 'B'}, - {"change-addresses", required_argument, NULL, ECP_CHANGE_ADDR}, - {"change-section-address", required_argument, NULL, - ECP_CHANGE_SEC_ADDR}, - {"change-section-lma", required_argument, NULL, ECP_CHANGE_SEC_LMA}, - {"change-section-vma", required_argument, NULL, ECP_CHANGE_SEC_VMA}, - {"change-start", required_argument, NULL, ECP_CHANGE_START}, - {"change-warnings", no_argument, NULL, ECP_CHANGE_WARN}, - {"discard-all", no_argument, NULL, 'x'}, - {"discard-locals", no_argument, NULL, 'X'}, - {"extract-dwo", no_argument, NULL, ECP_ONLY_DWO}, - {"gap-fill", required_argument, NULL, ECP_GAP_FILL}, - {"globalize-symbol", required_argument, NULL, ECP_GLOBALIZE_SYMBOL}, - {"globalize-symbols", required_argument, NULL, ECP_GLOBALIZE_SYMBOLS}, - {"help", no_argument, NULL, 'h'}, - {"input-target", required_argument, NULL, 'I'}, - {"keep-symbol", required_argument, NULL, 'K'}, - {"keep-symbols", required_argument, NULL, ECP_KEEP_SYMBOLS}, - {"keep-global-symbol", required_argument, NULL, 'G'}, - {"keep-global-symbols", required_argument, NULL, - ECP_KEEP_GLOBAL_SYMBOLS}, - {"localize-hidden", no_argument, NULL, ECP_LOCALIZE_HIDDEN}, - {"localize-symbol", required_argument, NULL, 'L'}, - {"localize-symbols", required_argument, NULL, ECP_LOCALIZE_SYMBOLS}, - {"no-adjust-warnings", no_argument, NULL, ECP_NO_CHANGE_WARN}, - {"no-change-warnings", no_argument, NULL, ECP_NO_CHANGE_WARN}, - {"only-keep-debug", no_argument, NULL, ECP_ONLY_DEBUG}, - {"only-section", required_argument, NULL, 'j'}, - {"osabi", required_argument, NULL, ECP_SET_OSABI}, - {"output-target", required_argument, NULL, 'O'}, - {"pad-to", required_argument, NULL, ECP_PAD_TO}, - {"preserve-dates", no_argument, NULL, 'p'}, - {"prefix-alloc-sections", required_argument, NULL, ECP_PREFIX_ALLOC}, - {"prefix-sections", required_argument, NULL, ECP_PREFIX_SEC}, - {"prefix-symbols", required_argument, NULL, ECP_PREFIX_SYM}, - {"redefine-sym", required_argument, NULL, ECP_REDEF_SYMBOL}, - {"redefine-syms", required_argument, NULL, ECP_REDEF_SYMBOLS}, - {"remove-section", required_argument, NULL, 'R'}, - {"rename-section", required_argument, NULL, ECP_RENAME_SECTION}, - {"set-section-flags", required_argument, NULL, ECP_SET_SEC_FLAGS}, - {"set-start", required_argument, NULL, ECP_SET_START}, - {"srec-forceS3", no_argument, NULL, ECP_SREC_FORCE_S3}, - {"srec-len", required_argument, NULL, ECP_SREC_LEN}, - {"strip-all", no_argument, NULL, 'S'}, - {"strip-debug", no_argument, 0, 'g'}, - {"strip-dwo", no_argument, NULL, ECP_STRIP_DWO}, - {"strip-symbol", required_argument, NULL, 'N'}, - {"strip-symbols", required_argument, NULL, ECP_STRIP_SYMBOLS}, - {"strip-unneeded", no_argument, NULL, ECP_STRIP_UNNEEDED}, - {"version", no_argument, NULL, 'V'}, - {"weaken", no_argument, NULL, ECP_WEAKEN_ALL}, - {"weaken-symbol", required_argument, NULL, 'W'}, - {"weaken-symbols", required_argument, NULL, ECP_WEAKEN_SYMBOLS}, - {"wildcard", no_argument, NULL, 'w'}, - {NULL, 0, NULL, 0} -}; - -static struct { - const char *name; - int value; -} sec_flags[] = { - {"alloc", SF_ALLOC}, - {"load", SF_LOAD}, - {"noload", SF_NOLOAD}, - {"readonly", SF_READONLY}, - {"debug", SF_DEBUG}, - {"code", SF_CODE}, - {"data", SF_DATA}, - {"rom", SF_ROM}, - {"share", SF_SHARED}, - {"contents", SF_CONTENTS}, - {NULL, 0} -}; - -static struct { - const char *name; - int abi; -} osabis[] = { - {"sysv", ELFOSABI_SYSV}, - {"hpus", ELFOSABI_HPUX}, - {"netbsd", ELFOSABI_NETBSD}, - {"linux", ELFOSABI_LINUX}, - {"hurd", ELFOSABI_HURD}, - {"86open", ELFOSABI_86OPEN}, - {"solaris", ELFOSABI_SOLARIS}, - {"aix", ELFOSABI_AIX}, - {"irix", ELFOSABI_IRIX}, - {"freebsd", ELFOSABI_FREEBSD}, - {"tru64", ELFOSABI_TRU64}, - {"modesto", ELFOSABI_MODESTO}, - {"openbsd", ELFOSABI_OPENBSD}, - {"openvms", ELFOSABI_OPENVMS}, - {"nsk", ELFOSABI_NSK}, - {"arm", ELFOSABI_ARM}, - {"standalone", ELFOSABI_STANDALONE}, - {NULL, 0} -}; - -static int copy_from_tempfile(const char *src, const char *dst, - int infd, int *outfd, int in_place); -static void create_file(struct elfcopy *ecp, const char *src, - const char *dst); -static void elfcopy_main(struct elfcopy *ecp, int argc, char **argv); -static void elfcopy_usage(void); -static void mcs_main(struct elfcopy *ecp, int argc, char **argv); -static void mcs_usage(void); -static void parse_sec_address_op(struct elfcopy *ecp, int optnum, - const char *optname, char *s); -static void parse_sec_flags(struct sec_action *sac, char *s); -static void parse_symlist_file(struct elfcopy *ecp, const char *fn, - unsigned int op); -static void print_version(void); -static void set_input_target(struct elfcopy *ecp, const char *target_name); -static void set_osabi(struct elfcopy *ecp, const char *abi); -static void set_output_target(struct elfcopy *ecp, const char *target_name); -static void strip_main(struct elfcopy *ecp, int argc, char **argv); -static void strip_usage(void); - -/* - * An ELF object usually has a sturcture described by the - * diagram below. - * _____________ - * | | - * | NULL | <- always a SHT_NULL section - * |_____________| - * | | - * | .interp | - * |_____________| - * | | - * | ... | - * |_____________| - * | | - * | .text | - * |_____________| - * | | - * | ... | - * |_____________| - * | | - * | .comment | <- above(include) this: normal sections - * |_____________| - * | | - * | add sections| <- unloadable sections added by --add-section - * |_____________| - * | | - * | .shstrtab | <- section name string table - * |_____________| - * | | - * | shdrs | <- section header table - * |_____________| - * | | - * | .symtab | <- symbol table, if any - * |_____________| - * | | - * | .strtab | <- symbol name string table, if any - * |_____________| - * | | - * | .rel.text | <- relocation info for .o files. - * |_____________| - */ -void -create_elf(struct elfcopy *ecp) -{ - struct section *shtab; - GElf_Ehdr ieh; - GElf_Ehdr oeh; - size_t ishnum; - - ecp->flags |= SYMTAB_INTACT; - - /* Create EHDR. */ - if (gelf_getehdr(ecp->ein, &ieh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - if ((ecp->iec = gelf_getclass(ecp->ein)) == ELFCLASSNONE) - errx(EXIT_FAILURE, "getclass() failed: %s", - elf_errmsg(-1)); - - if (ecp->oec == ELFCLASSNONE) - ecp->oec = ecp->iec; - if (ecp->oed == ELFDATANONE) - ecp->oed = ieh.e_ident[EI_DATA]; - - if (gelf_newehdr(ecp->eout, ecp->oec) == NULL) - errx(EXIT_FAILURE, "gelf_newehdr failed: %s", - elf_errmsg(-1)); - if (gelf_getehdr(ecp->eout, &oeh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - memcpy(oeh.e_ident, ieh.e_ident, sizeof(ieh.e_ident)); - oeh.e_ident[EI_CLASS] = ecp->oec; - oeh.e_ident[EI_DATA] = ecp->oed; - if (ecp->abi != -1) - oeh.e_ident[EI_OSABI] = ecp->abi; - oeh.e_flags = ieh.e_flags; - oeh.e_machine = ieh.e_machine; - oeh.e_type = ieh.e_type; - oeh.e_entry = ieh.e_entry; - oeh.e_version = ieh.e_version; - - if (ieh.e_type == ET_EXEC) - ecp->flags |= EXECUTABLE; - else if (ieh.e_type == ET_DYN) - ecp->flags |= DYNAMIC; - else if (ieh.e_type == ET_REL) - ecp->flags |= RELOCATABLE; - else - errx(EXIT_FAILURE, "unsupported e_type"); - - if (!elf_getshnum(ecp->ein, &ishnum)) - errx(EXIT_FAILURE, "elf_getshnum failed: %s", - elf_errmsg(-1)); - if (ishnum > 0 && (ecp->secndx = calloc(ishnum, - sizeof(*ecp->secndx))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - - /* Read input object program header. */ - setup_phdr(ecp); - - /* - * Scan of input sections: we iterate through sections from input - * object, skip sections need to be stripped, allot Elf_Scn and - * create internal section structure for sections we want. - * (i.e., determine output sections) - */ - create_scn(ecp); - - /* Apply section address changes, if any. */ - adjust_addr(ecp); - - /* - * Determine if the symbol table needs to be changed based on - * command line options. - */ - if (ecp->strip == STRIP_DEBUG || - ecp->strip == STRIP_UNNEEDED || - ecp->flags & WEAKEN_ALL || - ecp->flags & LOCALIZE_HIDDEN || - ecp->flags & DISCARD_LOCAL || - ecp->flags & DISCARD_LLABEL || - ecp->prefix_sym != NULL || - !STAILQ_EMPTY(&ecp->v_symop)) - ecp->flags &= ~SYMTAB_INTACT; - - /* - * Create symbol table. Symbols are filtered or stripped according to - * command line args specified by user, and later updated for the new - * layout of sections in the output object. - */ - if ((ecp->flags & SYMTAB_EXIST) != 0) - create_symtab(ecp); - - /* - * First processing of output sections: at this stage we copy the - * content of each section from input to output object. Section - * content will be modified and printed (mcs) if need. Also content of - * relocation section probably will be filtered and updated according - * to symbol table changes. - */ - copy_content(ecp); - - /* - * Write the underlying ehdr. Note that it should be called - * before elf_setshstrndx() since it will overwrite e->e_shstrndx. - */ - if (gelf_update_ehdr(ecp->eout, &oeh) == 0) - errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", - elf_errmsg(-1)); - - /* Generate section name string table (.shstrtab). */ - set_shstrtab(ecp); - - /* - * Second processing of output sections: Update section headers. - * At this stage we set name string index, update st_link and st_info - * for output sections. - */ - update_shdr(ecp, 1); - - /* Renew oeh to get the updated e_shstrndx. */ - if (gelf_getehdr(ecp->eout, &oeh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - /* - * Insert SHDR table into the internal section list as a "pseudo" - * section, so later it will get sorted and resynced just as "normal" - * sections. - */ - shtab = insert_shtab(ecp, 0); - - /* - * Resync section offsets in the output object. This is needed - * because probably sections are modified or new sections are added, - * as a result overlap/gap might appears. - */ - resync_sections(ecp); - - /* Store SHDR offset in EHDR. */ - oeh.e_shoff = shtab->off; - - /* Put program header table immediately after the Elf header. */ - if (ecp->ophnum > 0) { - oeh.e_phoff = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT); - if (oeh.e_phoff == 0) - errx(EXIT_FAILURE, "gelf_fsize() failed: %s", - elf_errmsg(-1)); - } - - /* - * Update ELF object entry point if requested. - */ - if (ecp->change_addr != 0) - oeh.e_entry += ecp->change_addr; - if (ecp->flags & SET_START) - oeh.e_entry = ecp->set_start; - if (ecp->change_start != 0) - oeh.e_entry += ecp->change_start; - - /* - * Update ehdr again before we call elf_update(), since we - * modified e_shoff and e_phoff. - */ - if (gelf_update_ehdr(ecp->eout, &oeh) == 0) - errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", - elf_errmsg(-1)); - - if (ecp->ophnum > 0) - copy_phdr(ecp); - - /* Write out the output elf object. */ - if (elf_update(ecp->eout, ELF_C_WRITE) < 0) - errx(EXIT_FAILURE, "elf_update() failed: %s", - elf_errmsg(-1)); - - /* Release allocated resource. */ - free_elf(ecp); -} - -void -free_elf(struct elfcopy *ecp) -{ - struct segment *seg, *seg_temp; - struct section *sec, *sec_temp; - - /* Free internal segment list. */ - if (!STAILQ_EMPTY(&ecp->v_seg)) { - STAILQ_FOREACH_SAFE(seg, &ecp->v_seg, seg_list, seg_temp) { - STAILQ_REMOVE(&ecp->v_seg, seg, segment, seg_list); - free(seg); - } - } - - /* Free symbol table buffers. */ - free_symtab(ecp); - - /* Free internal section list. */ - if (!TAILQ_EMPTY(&ecp->v_sec)) { - TAILQ_FOREACH_SAFE(sec, &ecp->v_sec, sec_list, sec_temp) { - TAILQ_REMOVE(&ecp->v_sec, sec, sec_list); - if (sec->buf != NULL) - free(sec->buf); - if (sec->newname != NULL) - free(sec->newname); - if (sec->pad != NULL) - free(sec->pad); - free(sec); - } - } -} - -/* Create a temporary file. */ -void -create_tempfile(char **fn, int *fd) -{ - const char *tmpdir; - char *cp, *tmpf; - size_t tlen, plen; - -#define _TEMPFILE "ecp.XXXXXXXX" -#define _TEMPFILEPATH "/tmp/ecp.XXXXXXXX" - - if (fn == NULL || fd == NULL) - return; - /* Repect TMPDIR environment variable. */ - tmpdir = getenv("TMPDIR"); - if (tmpdir != NULL && *tmpdir != '\0') { - tlen = strlen(tmpdir); - plen = strlen(_TEMPFILE); - tmpf = malloc(tlen + plen + 2); - if (tmpf == NULL) - err(EXIT_FAILURE, "malloc failed"); - strncpy(tmpf, tmpdir, tlen); - cp = &tmpf[tlen - 1]; - if (*cp++ != '/') - *cp++ = '/'; - strncpy(cp, _TEMPFILE, plen); - cp[plen] = '\0'; - } else { - tmpf = strdup(_TEMPFILEPATH); - if (tmpf == NULL) - err(EXIT_FAILURE, "strdup failed"); - } - if ((*fd = mkstemp(tmpf)) == -1) - err(EXIT_FAILURE, "mkstemp %s failed", tmpf); - if (fchmod(*fd, 0644) == -1) - err(EXIT_FAILURE, "fchmod %s failed", tmpf); - *fn = tmpf; - -#undef _TEMPFILE -#undef _TEMPFILEPATH -} - -/* - * Copy temporary file with path src and file descriptor infd to path dst. - * If in_place is set act as if editing the file in place, avoiding rename() - * to preserve hard and symbolic links. Output file remains open, with file - * descriptor returned in outfd. - */ -static int -copy_from_tempfile(const char *src, const char *dst, int infd, int *outfd, - int in_place) -{ - int tmpfd; - - /* - * First, check if we can use rename(). - */ - if (in_place == 0) { - if (rename(src, dst) >= 0) { - *outfd = infd; - return (0); - } else if (errno != EXDEV) - return (-1); - - /* - * If the rename() failed due to 'src' and 'dst' residing in - * two different file systems, invoke a helper function in - * libelftc to do the copy. - */ - - if (unlink(dst) < 0) - return (-1); - } - - if ((tmpfd = open(dst, O_CREAT | O_TRUNC | O_WRONLY, 0755)) < 0) - return (-1); - - if (elftc_copyfile(infd, tmpfd) < 0) - return (-1); - - /* - * Remove the temporary file from the file system - * namespace, and close its file descriptor. - */ - if (unlink(src) < 0) - return (-1); - - (void) close(infd); - - /* - * Return the file descriptor for the destination. - */ - *outfd = tmpfd; - - return (0); -} - -static void -create_file(struct elfcopy *ecp, const char *src, const char *dst) -{ - struct stat sb; - char *tempfile, *elftemp; - int efd, ifd, ofd, ofd0, tfd; - int in_place; - - tempfile = NULL; - - if (src == NULL) - errx(EXIT_FAILURE, "internal: src == NULL"); - if ((ifd = open(src, O_RDONLY)) == -1) - err(EXIT_FAILURE, "open %s failed", src); - - if (fstat(ifd, &sb) == -1) - err(EXIT_FAILURE, "fstat %s failed", src); - - if (dst == NULL) - create_tempfile(&tempfile, &ofd); - else - if ((ofd = open(dst, O_RDWR|O_CREAT, 0755)) == -1) - err(EXIT_FAILURE, "open %s failed", dst); - -#ifndef LIBELF_AR - /* Detect and process ar(1) archive using libarchive. */ - if (ac_detect_ar(ifd)) { - ac_create_ar(ecp, ifd, ofd); - goto copy_done; - } -#endif - - if (lseek(ifd, 0, SEEK_SET) < 0) - err(EXIT_FAILURE, "lseek failed"); - - /* - * If input object is not ELF file, convert it to an intermediate - * ELF object before processing. - */ - if (ecp->itf != ETF_ELF) { - create_tempfile(&elftemp, &efd); - if ((ecp->eout = elf_begin(efd, ELF_C_WRITE, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_begin() failed: %s", - elf_errmsg(-1)); - elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); - if (ecp->itf == ETF_BINARY) - create_elf_from_binary(ecp, ifd, src); - else if (ecp->itf == ETF_IHEX) - create_elf_from_ihex(ecp, ifd); - else if (ecp->itf == ETF_SREC) - create_elf_from_srec(ecp, ifd); - else - errx(EXIT_FAILURE, "Internal: invalid target flavour"); - elf_end(ecp->eout); - - /* Open intermediate ELF object as new input object. */ - close(ifd); - if ((ifd = open(elftemp, O_RDONLY)) == -1) - err(EXIT_FAILURE, "open %s failed", src); - close(efd); - free(elftemp); - } - - if ((ecp->ein = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_begin() failed: %s", - elf_errmsg(-1)); - - switch (elf_kind(ecp->ein)) { - case ELF_K_NONE: - errx(EXIT_FAILURE, "file format not recognized"); - case ELF_K_ELF: - if ((ecp->eout = elf_begin(ofd, ELF_C_WRITE, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_begin() failed: %s", - elf_errmsg(-1)); - - /* elfcopy(1) manage ELF layout by itself. */ - elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); - - /* - * Create output ELF object. - */ - create_elf(ecp); - elf_end(ecp->eout); - - /* - * Convert the output ELF object to binary/srec/ihex if need. - */ - if (ecp->otf != ETF_ELF) { - /* - * Create (another) tempfile for binary/srec/ihex - * output object. - */ - if (tempfile != NULL) { - if (unlink(tempfile) < 0) - err(EXIT_FAILURE, "unlink %s failed", - tempfile); - free(tempfile); - } - create_tempfile(&tempfile, &ofd0); - - - /* - * Rewind the file descriptor being processed. - */ - if (lseek(ofd, 0, SEEK_SET) < 0) - err(EXIT_FAILURE, - "lseek failed for the output object"); - - /* - * Call flavour-specific conversion routine. - */ - switch (ecp->otf) { - case ETF_BINARY: - create_binary(ofd, ofd0); - break; - case ETF_IHEX: - create_ihex(ofd, ofd0); - break; - case ETF_SREC: - create_srec(ecp, ofd, ofd0, - dst != NULL ? dst : src); - break; - default: - errx(EXIT_FAILURE, "Internal: unsupported" - " output flavour %d", ecp->oec); - } - - close(ofd); - ofd = ofd0; - } - - break; - - case ELF_K_AR: - /* XXX: Not yet supported. */ - break; - default: - errx(EXIT_FAILURE, "file format not supported"); - } - - elf_end(ecp->ein); - -#ifndef LIBELF_AR -copy_done: -#endif - - if (tempfile != NULL) { - in_place = 0; - if (dst == NULL) { - dst = src; - if (lstat(dst, &sb) != -1 && - (sb.st_nlink > 1 || S_ISLNK(sb.st_mode))) - in_place = 1; - } - - if (copy_from_tempfile(tempfile, dst, ofd, &tfd, in_place) < 0) - err(EXIT_FAILURE, "creation of %s failed", dst); - - free(tempfile); - tempfile = NULL; - - ofd = tfd; - } - - if (strcmp(dst, "/dev/null") && fchmod(ofd, sb.st_mode) == -1) - err(EXIT_FAILURE, "fchmod %s failed", dst); - - if ((ecp->flags & PRESERVE_DATE) && - elftc_set_timestamps(dst, &sb) < 0) - err(EXIT_FAILURE, "setting timestamps failed"); - - close(ifd); - close(ofd); -} - -static void -elfcopy_main(struct elfcopy *ecp, int argc, char **argv) -{ - struct sec_action *sac; - const char *infile, *outfile; - char *fn, *s; - int opt; - - while ((opt = getopt_long(argc, argv, "dB:gG:I:j:K:L:N:O:pR:s:SwW:xXV", - elfcopy_longopts, NULL)) != -1) { - switch(opt) { - case 'B': - /* ignored */ - break; - case 'R': - sac = lookup_sec_act(ecp, optarg, 1); - if (sac->copy != 0) - errx(EXIT_FAILURE, - "both copy and remove specified"); - sac->remove = 1; - ecp->flags |= SEC_REMOVE; - break; - case 'S': - ecp->strip = STRIP_ALL; - break; - case 'g': - ecp->strip = STRIP_DEBUG; - break; - case 'G': - ecp->flags |= KEEP_GLOBAL; - add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEPG); - break; - case 'I': - case 's': - set_input_target(ecp, optarg); - break; - case 'j': - sac = lookup_sec_act(ecp, optarg, 1); - if (sac->remove != 0) - errx(EXIT_FAILURE, - "both copy and remove specified"); - sac->copy = 1; - ecp->flags |= SEC_COPY; - break; - case 'K': - add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEP); - break; - case 'L': - add_to_symop_list(ecp, optarg, NULL, SYMOP_LOCALIZE); - break; - case 'N': - add_to_symop_list(ecp, optarg, NULL, SYMOP_STRIP); - break; - case 'O': - set_output_target(ecp, optarg); - break; - case 'p': - ecp->flags |= PRESERVE_DATE; - break; - case 'V': - print_version(); - break; - case 'w': - ecp->flags |= WILDCARD; - break; - case 'W': - add_to_symop_list(ecp, optarg, NULL, SYMOP_WEAKEN); - break; - case 'x': - ecp->flags |= DISCARD_LOCAL; - break; - case 'X': - ecp->flags |= DISCARD_LLABEL; - break; - case ECP_ADD_GNU_DEBUGLINK: - ecp->debuglink = optarg; - break; - case ECP_ADD_SECTION: - add_section(ecp, optarg); - break; - case ECP_CHANGE_ADDR: - ecp->change_addr = (int64_t) strtoll(optarg, NULL, 0); - break; - case ECP_CHANGE_SEC_ADDR: - parse_sec_address_op(ecp, opt, "--change-section-addr", - optarg); - break; - case ECP_CHANGE_SEC_LMA: - parse_sec_address_op(ecp, opt, "--change-section-lma", - optarg); - break; - case ECP_CHANGE_SEC_VMA: - parse_sec_address_op(ecp, opt, "--change-section-vma", - optarg); - break; - case ECP_CHANGE_START: - ecp->change_start = (int64_t) strtoll(optarg, NULL, 0); - break; - case ECP_CHANGE_WARN: - /* default */ - break; - case ECP_GAP_FILL: - ecp->fill = (uint8_t) strtoul(optarg, NULL, 0); - ecp->flags |= GAP_FILL; - break; - case ECP_GLOBALIZE_SYMBOL: - add_to_symop_list(ecp, optarg, NULL, SYMOP_GLOBALIZE); - break; - case ECP_GLOBALIZE_SYMBOLS: - parse_symlist_file(ecp, optarg, SYMOP_GLOBALIZE); - break; - case ECP_KEEP_SYMBOLS: - parse_symlist_file(ecp, optarg, SYMOP_KEEP); - break; - case ECP_KEEP_GLOBAL_SYMBOLS: - parse_symlist_file(ecp, optarg, SYMOP_KEEPG); - break; - case ECP_LOCALIZE_HIDDEN: - ecp->flags |= LOCALIZE_HIDDEN; - break; - case ECP_LOCALIZE_SYMBOLS: - parse_symlist_file(ecp, optarg, SYMOP_LOCALIZE); - break; - case ECP_NO_CHANGE_WARN: - ecp->flags |= NO_CHANGE_WARN; - break; - case ECP_ONLY_DEBUG: - ecp->strip = STRIP_NONDEBUG; - break; - case ECP_ONLY_DWO: - ecp->strip = STRIP_NONDWO; - break; - case ECP_PAD_TO: - ecp->pad_to = (uint64_t) strtoull(optarg, NULL, 0); - break; - case ECP_PREFIX_ALLOC: - ecp->prefix_alloc = optarg; - break; - case ECP_PREFIX_SEC: - ecp->prefix_sec = optarg; - break; - case ECP_PREFIX_SYM: - ecp->prefix_sym = optarg; - break; - case ECP_REDEF_SYMBOL: - if ((s = strchr(optarg, '=')) == NULL) - errx(EXIT_FAILURE, - "illegal format for --redefine-sym"); - *s++ = '\0'; - add_to_symop_list(ecp, optarg, s, SYMOP_REDEF); - break; - case ECP_REDEF_SYMBOLS: - parse_symlist_file(ecp, optarg, SYMOP_REDEF); - break; - case ECP_RENAME_SECTION: - if ((fn = strchr(optarg, '=')) == NULL) - errx(EXIT_FAILURE, - "illegal format for --rename-section"); - *fn++ = '\0'; - - /* Check for optional flags. */ - if ((s = strchr(fn, ',')) != NULL) - *s++ = '\0'; - - sac = lookup_sec_act(ecp, optarg, 1); - sac->rename = 1; - sac->newname = fn; - if (s != NULL) - parse_sec_flags(sac, s); - break; - case ECP_SET_OSABI: - set_osabi(ecp, optarg); - break; - case ECP_SET_SEC_FLAGS: - if ((s = strchr(optarg, '=')) == NULL) - errx(EXIT_FAILURE, - "illegal format for --set-section-flags"); - *s++ = '\0'; - sac = lookup_sec_act(ecp, optarg, 1); - parse_sec_flags(sac, s); - break; - case ECP_SET_START: - ecp->flags |= SET_START; - ecp->set_start = (uint64_t) strtoull(optarg, NULL, 0); - break; - case ECP_SREC_FORCE_S3: - ecp->flags |= SREC_FORCE_S3; - break; - case ECP_SREC_LEN: - ecp->flags |= SREC_FORCE_LEN; - ecp->srec_len = strtoul(optarg, NULL, 0); - break; - case ECP_STRIP_DWO: - ecp->strip = STRIP_DWO; - break; - case ECP_STRIP_SYMBOLS: - parse_symlist_file(ecp, optarg, SYMOP_STRIP); - break; - case ECP_STRIP_UNNEEDED: - ecp->strip = STRIP_UNNEEDED; - break; - case ECP_WEAKEN_ALL: - ecp->flags |= WEAKEN_ALL; - break; - case ECP_WEAKEN_SYMBOLS: - parse_symlist_file(ecp, optarg, SYMOP_WEAKEN); - break; - default: - elfcopy_usage(); - } - } - - if (optind == argc || optind + 2 < argc) - elfcopy_usage(); - - infile = argv[optind]; - outfile = NULL; - if (optind + 1 < argc) - outfile = argv[optind + 1]; - - create_file(ecp, infile, outfile); -} - -static void -mcs_main(struct elfcopy *ecp, int argc, char **argv) -{ - struct sec_action *sac; - const char *string; - int append, delete, compress, name, print; - int opt, i; - - append = delete = compress = name = print = 0; - string = NULL; - while ((opt = getopt_long(argc, argv, "a:cdhn:pV", mcs_longopts, - NULL)) != -1) { - switch(opt) { - case 'a': - append = 1; - string = optarg; /* XXX multiple -a not supported */ - break; - case 'c': - compress = 1; - break; - case 'd': - delete = 1; - break; - case 'n': - name = 1; - (void)lookup_sec_act(ecp, optarg, 1); - break; - case 'p': - print = 1; - break; - case 'V': - print_version(); - break; - case 'h': - default: - mcs_usage(); - } - } - - if (optind == argc) - mcs_usage(); - - /* Must specify one operation at least. */ - if (!append && !compress && !delete && !print) - mcs_usage(); - - /* - * If we are going to delete, ignore other operations. This is - * different from the Solaris implementation, which can print - * and delete a section at the same time, for example. Also, this - * implementation do not respect the order between operations that - * user specified, i.e., "mcs -pc a.out" equals to "mcs -cp a.out". - */ - if (delete) { - append = compress = print = 0; - ecp->flags |= SEC_REMOVE; - } - if (append) - ecp->flags |= SEC_APPEND; - if (compress) - ecp->flags |= SEC_COMPRESS; - if (print) - ecp->flags |= SEC_PRINT; - - /* .comment is the default section to operate on. */ - if (!name) - (void)lookup_sec_act(ecp, ".comment", 1); - - STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { - sac->append = append; - sac->compress = compress; - sac->print = print; - sac->remove = delete; - sac->string = string; - } - - for (i = optind; i < argc; i++) { - /* If only -p is specified, output to /dev/null */ - if (print && !append && !compress && !delete) - create_file(ecp, argv[i], "/dev/null"); - else - create_file(ecp, argv[i], NULL); - } -} - -static void -strip_main(struct elfcopy *ecp, int argc, char **argv) -{ - struct sec_action *sac; - const char *outfile; - int opt; - int i; - - outfile = NULL; - while ((opt = getopt_long(argc, argv, "hI:K:N:o:O:pR:sSdgVxXw", - strip_longopts, NULL)) != -1) { - switch(opt) { - case 'R': - sac = lookup_sec_act(ecp, optarg, 1); - sac->remove = 1; - ecp->flags |= SEC_REMOVE; - break; - case 's': - ecp->strip = STRIP_ALL; - break; - case 'S': - case 'g': - case 'd': - ecp->strip = STRIP_DEBUG; - break; - case 'I': - /* ignored */ - break; - case 'K': - add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEP); - break; - case 'N': - add_to_symop_list(ecp, optarg, NULL, SYMOP_STRIP); - break; - case 'o': - outfile = optarg; - break; - case 'O': - set_output_target(ecp, optarg); - break; - case 'p': - ecp->flags |= PRESERVE_DATE; - break; - case 'V': - print_version(); - break; - case 'w': - ecp->flags |= WILDCARD; - break; - case 'x': - ecp->flags |= DISCARD_LOCAL; - break; - case 'X': - ecp->flags |= DISCARD_LLABEL; - break; - case ECP_ONLY_DEBUG: - ecp->strip = STRIP_NONDEBUG; - break; - case ECP_STRIP_UNNEEDED: - ecp->strip = STRIP_UNNEEDED; - break; - case 'h': - default: - strip_usage(); - } - } - - if (ecp->strip == 0 && - ((ecp->flags & DISCARD_LOCAL) == 0) && - ((ecp->flags & DISCARD_LLABEL) == 0) && - lookup_symop_list(ecp, NULL, SYMOP_STRIP) == NULL) - ecp->strip = STRIP_ALL; - if (optind == argc) - strip_usage(); - - for (i = optind; i < argc; i++) - create_file(ecp, argv[i], outfile); -} - -static void -parse_sec_flags(struct sec_action *sac, char *s) -{ - const char *flag; - int found, i; - - for (flag = strtok(s, ","); flag; flag = strtok(NULL, ",")) { - found = 0; - for (i = 0; sec_flags[i].name != NULL; i++) - if (strcasecmp(sec_flags[i].name, flag) == 0) { - sac->flags |= sec_flags[i].value; - found = 1; - break; - } - if (!found) - errx(EXIT_FAILURE, "unrecognized section flag %s", - flag); - } -} - -static void -parse_sec_address_op(struct elfcopy *ecp, int optnum, const char *optname, - char *s) -{ - struct sec_action *sac; - const char *name; - char *v; - char op; - - name = v = s; - do { - v++; - } while (*v != '\0' && *v != '=' && *v != '+' && *v != '-'); - if (*v == '\0' || *(v + 1) == '\0') - errx(EXIT_FAILURE, "invalid format for %s", optname); - op = *v; - *v++ = '\0'; - sac = lookup_sec_act(ecp, name, 1); - switch (op) { - case '=': - if (optnum == ECP_CHANGE_SEC_LMA || - optnum == ECP_CHANGE_SEC_ADDR) { - sac->setlma = 1; - sac->lma = (uint64_t) strtoull(v, NULL, 0); - } - if (optnum == ECP_CHANGE_SEC_VMA || - optnum == ECP_CHANGE_SEC_ADDR) { - sac->setvma = 1; - sac->vma = (uint64_t) strtoull(v, NULL, 0); - } - break; - case '+': - if (optnum == ECP_CHANGE_SEC_LMA || - optnum == ECP_CHANGE_SEC_ADDR) - sac->lma_adjust = (int64_t) strtoll(v, NULL, 0); - if (optnum == ECP_CHANGE_SEC_VMA || - optnum == ECP_CHANGE_SEC_ADDR) - sac->vma_adjust = (int64_t) strtoll(v, NULL, 0); - break; - case '-': - if (optnum == ECP_CHANGE_SEC_LMA || - optnum == ECP_CHANGE_SEC_ADDR) - sac->lma_adjust = (int64_t) -strtoll(v, NULL, 0); - if (optnum == ECP_CHANGE_SEC_VMA || - optnum == ECP_CHANGE_SEC_ADDR) - sac->vma_adjust = (int64_t) -strtoll(v, NULL, 0); - break; - default: - break; - } -} - -static void -parse_symlist_file(struct elfcopy *ecp, const char *fn, unsigned int op) -{ - struct symfile *sf; - struct stat sb; - FILE *fp; - char *data, *p, *line, *end, *e, *n; - - if (stat(fn, &sb) == -1) - err(EXIT_FAILURE, "stat %s failed", fn); - - /* Check if we already read and processed this file. */ - STAILQ_FOREACH(sf, &ecp->v_symfile, symfile_list) { - if (sf->dev == sb.st_dev && sf->ino == sb.st_ino) - goto process_symfile; - } - - if ((fp = fopen(fn, "r")) == NULL) - err(EXIT_FAILURE, "can not open %s", fn); - if ((data = malloc(sb.st_size + 1)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - if (fread(data, 1, sb.st_size, fp) == 0 || ferror(fp)) - err(EXIT_FAILURE, "fread failed"); - fclose(fp); - data[sb.st_size] = '\0'; - - if ((sf = calloc(1, sizeof(*sf))) == NULL) - err(EXIT_FAILURE, "malloc failed"); - sf->dev = sb.st_dev; - sf->ino = sb.st_ino; - sf->size = sb.st_size + 1; - sf->data = data; - -process_symfile: - - /* - * Basically what we do here is to convert EOL to '\0', and remove - * leading and trailing whitespaces for each line. - */ - - end = sf->data + sf->size; - line = NULL; - for(p = sf->data; p < end; p++) { - if ((*p == '\t' || *p == ' ') && line == NULL) - continue; - if (*p == '\r' || *p == '\n' || *p == '\0') { - *p = '\0'; - if (line == NULL) - continue; - - /* Skip comment. */ - if (*line == '#') { - line = NULL; - continue; - } - - e = p - 1; - while(e != line && (*e == '\t' || *e == ' ')) - *e-- = '\0'; - if (op != SYMOP_REDEF) - add_to_symop_list(ecp, line, NULL, op); - else { - if (strlen(line) < 3) - errx(EXIT_FAILURE, - "illegal format for" - " --redefine-sym"); - for(n = line + 1; n < e; n++) { - if (*n == ' ' || *n == '\t') { - while(*n == ' ' || *n == '\t') - *n++ = '\0'; - break; - } - } - if (n >= e) - errx(EXIT_FAILURE, - "illegal format for" - " --redefine-sym"); - add_to_symop_list(ecp, line, n, op); - } - line = NULL; - continue; - } - - if (line == NULL) - line = p; - } -} - -static void -set_input_target(struct elfcopy *ecp, const char *target_name) -{ - Elftc_Bfd_Target *tgt; - - if ((tgt = elftc_bfd_find_target(target_name)) == NULL) - errx(EXIT_FAILURE, "%s: invalid target name", target_name); - ecp->itf = elftc_bfd_target_flavor(tgt); -} - -static void -set_output_target(struct elfcopy *ecp, const char *target_name) -{ - Elftc_Bfd_Target *tgt; - - if ((tgt = elftc_bfd_find_target(target_name)) == NULL) - errx(EXIT_FAILURE, "%s: invalid target name", target_name); - ecp->otf = elftc_bfd_target_flavor(tgt); - if (ecp->otf == ETF_ELF) { - ecp->oec = elftc_bfd_target_class(tgt); - ecp->oed = elftc_bfd_target_byteorder(tgt); - ecp->oem = elftc_bfd_target_machine(tgt); - } - ecp->otgt = target_name; -} - -static void -set_osabi(struct elfcopy *ecp, const char *abi) -{ - int i, found; - - found = 0; - for (i = 0; osabis[i].name != NULL; i++) - if (strcasecmp(osabis[i].name, abi) == 0) { - ecp->abi = osabis[i].abi; - found = 1; - break; - } - if (!found) - errx(EXIT_FAILURE, "unrecognized OSABI %s", abi); -} - -#define ELFCOPY_USAGE_MESSAGE "\ -Usage: %s [options] infile [outfile]\n\ - Transform an ELF object.\n\n\ - Options:\n\ - -d | -g | --strip-debug Remove debugging information from the output.\n\ - -j SECTION | --only-section=SECTION\n\ - Copy only the named section to the output.\n\ - -p | --preserve-dates Preserve access and modification times.\n\ - -w | --wildcard Use shell-style patterns to name symbols.\n\ - -x | --discard-all Do not copy non-globals to the output.\n\ - -I FORMAT | --input-target=FORMAT\n\ - (Accepted but ignored).\n\ - -K SYM | --keep-symbol=SYM Copy symbol SYM to the output.\n\ - -L SYM | --localize-symbol=SYM\n\ - Make symbol SYM local to the output file.\n\ - -N SYM | --strip-symbol=SYM Do not copy symbol SYM to the output.\n\ - -R NAME | --remove-section=NAME\n\ - Remove the named section.\n\ - -S | --strip-all Remove all symbol and relocation information\n\ - from the output.\n\ - -V | --version Print a version identifier and exit.\n\ - -W SYM | --weaken-symbol=SYM Mark symbol SYM as weak in the output.\n\ - -X | --discard-locals Do not copy compiler generated symbols to\n\ - the output.\n\ - --add-section NAME=FILE Add the contents of FILE to the ELF object as\n\ - a new section named NAME.\n\ - --adjust-section-vma SECTION{=,+,-}VAL | \\\n\ - --change-section-address SECTION{=,+,-}VAL\n\ - Set or adjust the VMA and the LMA of the\n\ - named section by VAL.\n\ - --adjust-start=INCR | --change-start=INCR\n\ - Add INCR to the start address for the ELF\n\ - object.\n\ - --adjust-vma=INCR | --change-addresses=INCR\n\ - Increase the VMA and LMA of all sections by\n\ - INCR.\n\ - --adjust-warning | --change-warnings\n\ - Issue warnings for non-existent sections.\n\ - --change-section-lma SECTION{=,+,-}VAL\n\ - Set or adjust the LMA address of the named\n\ - section by VAL.\n\ - --change-section-vma SECTION{=,+,-}VAL\n\ - Set or adjust the VMA address of the named\n\ - section by VAL.\n\ - --gap-fill=VAL Fill the gaps between sections with bytes\n\ - of value VAL.\n\ - --localize-hidden Make all hidden symbols local to the output\n\ - file.\n\ - --no-adjust-warning| --no-change-warnings\n\ - Do not issue warnings for non-existent\n\ - sections.\n\ - --only-keep-debug Copy only debugging information.\n\ - --output-target=FORMAT Use the specified format for the output.\n\ - --pad-to=ADDRESS Pad the output object upto the given address.\n\ - --prefix-alloc-sections=STRING\n\ - Prefix the section names of all the allocated\n\ - sections with STRING.\n\ - --prefix-sections=STRING Prefix the section names of all the sections\n\ - with STRING.\n\ - --prefix-symbols=STRING Prefix the symbol names of all the symbols\n\ - with STRING.\n\ - --rename-section OLDNAME=NEWNAME[,FLAGS]\n\ - Rename and optionally change section flags.\n\ - --set-section-flags SECTION=FLAGS\n\ - Set section flags for the named section.\n\ - Supported flags are: 'alloc', 'code',\n\ - 'contents', 'data', 'debug', 'load',\n\ - 'noload', 'readonly', 'rom', and 'shared'.\n\ - --set-start=ADDRESS Set the start address of the ELF object.\n\ - --srec-forceS3 Only generate S3 S-Records.\n\ - --srec-len=LEN Set the maximum length of a S-Record line.\n\ - --strip-unneeded Do not copy relocation information.\n" - -static void -elfcopy_usage(void) -{ - (void) fprintf(stderr, ELFCOPY_USAGE_MESSAGE, ELFTC_GETPROGNAME()); - exit(EXIT_FAILURE); -} - -#define MCS_USAGE_MESSAGE "\ -Usage: %s [options] file...\n\ - Manipulate the comment section in an ELF object.\n\n\ - Options:\n\ - -a STRING Append 'STRING' to the comment section.\n\ - -c Remove duplicate entries from the comment section.\n\ - -d Delete the comment section.\n\ - -h | --help Print a help message and exit.\n\ - -n NAME Operate on the ELF section with name 'NAME'.\n\ - -p Print the contents of the comment section.\n\ - -V | --version Print a version identifier and exit.\n" - -static void -mcs_usage(void) -{ - (void) fprintf(stderr, MCS_USAGE_MESSAGE, ELFTC_GETPROGNAME()); - exit(EXIT_FAILURE); -} - -#define STRIP_USAGE_MESSAGE "\ -Usage: %s [options] file...\n\ - Discard information from ELF objects.\n\n\ - Options:\n\ - -d | -g | -S | --strip-debug Remove debugging symbols.\n\ - -h | --help Print a help message.\n\ - --only-keep-debug Keep debugging information only.\n\ - -p | --preserve-dates Preserve access and modification times.\n\ - -s | --strip-all Remove all symbols.\n\ - --strip-unneeded Remove symbols not needed for relocation\n\ - processing.\n\ - -w | --wildcard Use shell-style patterns to name symbols.\n\ - -x | --discard-all Discard all non-global symbols.\n\ - -I TGT| --input-target=TGT (Accepted, but ignored).\n\ - -K SYM | --keep-symbol=SYM Keep symbol 'SYM' in the output.\n\ - -N SYM | --strip-symbol=SYM Remove symbol 'SYM' from the output.\n\ - -O TGT | --output-target=TGT Set the output file format to 'TGT'.\n\ - -R SEC | --remove-section=SEC Remove the section named 'SEC'.\n\ - -V | --version Print a version identifier and exit.\n\ - -X | --discard-locals Remove compiler-generated local symbols.\n" - -static void -strip_usage(void) -{ - (void) fprintf(stderr, STRIP_USAGE_MESSAGE, ELFTC_GETPROGNAME()); - exit(EXIT_FAILURE); -} - -static void -print_version(void) -{ - (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); - exit(EXIT_SUCCESS); -} - -int -main(int argc, char **argv) -{ - struct elfcopy *ecp; - - if (elf_version(EV_CURRENT) == EV_NONE) - errx(EXIT_FAILURE, "ELF library initialization failed: %s", - elf_errmsg(-1)); - - ecp = calloc(1, sizeof(*ecp)); - if (ecp == NULL) - err(EXIT_FAILURE, "calloc failed"); - memset(ecp, 0, sizeof(*ecp)); - - ecp->itf = ecp->otf = ETF_ELF; - ecp->iec = ecp->oec = ELFCLASSNONE; - ecp->oed = ELFDATANONE; - ecp->abi = -1; - /* There is always an empty section. */ - ecp->nos = 1; - ecp->fill = 0; - - STAILQ_INIT(&ecp->v_seg); - STAILQ_INIT(&ecp->v_sac); - STAILQ_INIT(&ecp->v_sadd); - STAILQ_INIT(&ecp->v_symop); - STAILQ_INIT(&ecp->v_symfile); - STAILQ_INIT(&ecp->v_arobj); - TAILQ_INIT(&ecp->v_sec); - - if ((ecp->progname = ELFTC_GETPROGNAME()) == NULL) - ecp->progname = "elfcopy"; - - if (strcmp(ecp->progname, "strip") == 0) - strip_main(ecp, argc, argv); - else if (strcmp(ecp->progname, "mcs") == 0) - mcs_main(ecp, argc, argv); - else - elfcopy_main(ecp, argc, argv); - - free_sec_add(ecp); - free_sec_act(ecp); - free(ecp); - - exit(EXIT_SUCCESS); -} diff --git a/contrib/elftoolchain/elfcopy/mcs.1 b/contrib/elftoolchain/elfcopy/mcs.1 deleted file mode 100644 index edbafb7b88a7..000000000000 --- a/contrib/elftoolchain/elfcopy/mcs.1 +++ /dev/null @@ -1,125 +0,0 @@ -.\" Copyright (c) 2011 Joseph Koshy. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY JOSEPH KOSHY ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL JOSEPH KOSHY BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id: mcs.1 2247 2011-11-29 08:41:34Z jkoshy $ -.\" -.Dd November 29, 2011 -.Os -.Dt MCS 1 -.Sh NAME -.Nm mcs -.Nd manipulate the comment section of an ELF object -.Sh SYNOPSIS -.Nm -.Op Fl a Ar string -.Op Fl c -.Op Fl n Ar name -.Op Fl p -.Ar -.Nm -.Fl d -.Op Fl n Ar name -.Ar -.Nm -.Fl h | Fl -help -.Nm -.Fl V | Fl -version -.Sh DESCRIPTION -The -.Nm -utility is used to manipulate comment sections in an ELF object. -If a command-line argument -.Ar file -names an -.Xr ar 1 -archive, then -.Nm -will operate on the ELF objects contained in the archive. -.Pp -By default -.Nm -operates on the ELF section named -.Dq .comment . -This may be changed using the -.Fl n -option. -.Pp -The -.Nm -utility supports the following options: -.Bl -tag -width ".Fl a Ar string" -.It Fl a Ar string -Append the text in -.Ar string -to the comment section. -This option may be specified multiple times. -.It Fl c -Compress the comment section by removing duplicate entries. -.It Fl d -Delete the comment section from the ELF object. -.It Fl h | Fl -help -Display a usage message and exit. -.It Fl n Ar name -Operate on the section named -.Ar name . -.It Fl p -Print the contents of the comment section. -This step is taken after actions specified by the -.Fl a -and -.Fl c -options (if any) are completed. -.It Fl V | Fl -version -Print a version identifier and exit. -.El -.Sh COMPATIBILITY -The behavior of the -.Nm -utility differs from its SVR4 counterpart in the following ways: -.Bl -bullet -compact -.It -If the -.Fl d -option is specified, it causes any -.Fl a , -.Fl c -and -.Fl p -options present to be ignored. -.It -The order of options -.Fl a , -.Fl c , -.Fl d , -and -.Fl p -on the command line is not significant. -.El -.Sh DIAGNOSTICS -.Ex -std -.Sh SEE ALSO -.Xr ar 1 , -.Xr elfcopy 1 , -.Xr ld 1 , -.Xr nm 1 , -.Xr strip 1 diff --git a/contrib/elftoolchain/elfcopy/sections.c b/contrib/elftoolchain/elfcopy/sections.c deleted file mode 100644 index 7c43a3577f2f..000000000000 --- a/contrib/elftoolchain/elfcopy/sections.c +++ /dev/null @@ -1,1573 +0,0 @@ -/*- - * Copyright (c) 2007-2011,2014 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/stat.h> -#include <err.h> -#include <libgen.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "elfcopy.h" - -ELFTC_VCSID("$Id: sections.c 3185 2015-04-11 08:56:34Z kaiwang27 $"); - -static void add_gnu_debuglink(struct elfcopy *ecp); -static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc); -static void check_section_rename(struct elfcopy *ecp, struct section *s); -static void filter_reloc(struct elfcopy *ecp, struct section *s); -static int get_section_flags(struct elfcopy *ecp, const char *name); -static void insert_sections(struct elfcopy *ecp); -static void insert_to_strtab(struct section *t, const char *s); -static int is_append_section(struct elfcopy *ecp, const char *name); -static int is_compress_section(struct elfcopy *ecp, const char *name); -static int is_debug_section(const char *name); -static int is_dwo_section(const char *name); -static int is_modify_section(struct elfcopy *ecp, const char *name); -static int is_print_section(struct elfcopy *ecp, const char *name); -static int lookup_string(struct section *t, const char *s); -static void modify_section(struct elfcopy *ecp, struct section *s); -static void pad_section(struct elfcopy *ecp, struct section *s); -static void print_data(const char *d, size_t sz); -static void print_section(struct section *s); -static void *read_section(struct section *s, size_t *size); -static void update_reloc(struct elfcopy *ecp, struct section *s); - -int -is_remove_section(struct elfcopy *ecp, const char *name) -{ - - /* Always keep section name table */ - if (strcmp(name, ".shstrtab") == 0) - return 0; - if (strcmp(name, ".symtab") == 0 || - strcmp(name, ".strtab") == 0) { - if (ecp->strip == STRIP_ALL && lookup_symop_list( - ecp, NULL, SYMOP_KEEP) == NULL) - return (1); - else - return (0); - } - - if (ecp->strip == STRIP_DWO && is_dwo_section(name)) - return (1); - if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name)) - return (1); - - if (is_debug_section(name)) { - if (ecp->strip == STRIP_ALL || - ecp->strip == STRIP_DEBUG || - ecp->strip == STRIP_UNNEEDED || - (ecp->flags & DISCARD_LOCAL)) - return (1); - if (ecp->strip == STRIP_NONDEBUG) - return (0); - } - - if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) { - struct sec_action *sac; - - sac = lookup_sec_act(ecp, name, 0); - if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove) - return (1); - if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy)) - return (1); - } - - return (0); -} - -/* - * Relocation section needs to be removed if the section it applies to - * will be removed. - */ -int -is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info) -{ - const char *name; - GElf_Shdr ish; - Elf_Scn *is; - size_t indx; - int elferr; - - if (elf_getshstrndx(ecp->ein, &indx) == 0) - errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", - elf_errmsg(-1)); - - is = NULL; - while ((is = elf_nextscn(ecp->ein, is)) != NULL) { - if (sh_info == elf_ndxscn(is)) { - if (gelf_getshdr(is, &ish) == NULL) - errx(EXIT_FAILURE, "gelf_getshdr failed: %s", - elf_errmsg(-1)); - if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == - NULL) - errx(EXIT_FAILURE, "elf_strptr failed: %s", - elf_errmsg(-1)); - if (is_remove_section(ecp, name)) - return (1); - else - return (0); - } - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_nextscn failed: %s", - elf_errmsg(elferr)); - - /* Remove reloc section if we can't find the target section. */ - return (1); -} - -static int -is_append_section(struct elfcopy *ecp, const char *name) -{ - struct sec_action *sac; - - sac = lookup_sec_act(ecp, name, 0); - if (sac != NULL && sac->append != 0 && sac->string != NULL) - return (1); - - return (0); -} - -static int -is_compress_section(struct elfcopy *ecp, const char *name) -{ - struct sec_action *sac; - - sac = lookup_sec_act(ecp, name, 0); - if (sac != NULL && sac->compress != 0) - return (1); - - return (0); -} - -static void -check_section_rename(struct elfcopy *ecp, struct section *s) -{ - struct sec_action *sac; - char *prefix; - size_t namelen; - - if (s->pseudo) - return; - - sac = lookup_sec_act(ecp, s->name, 0); - if (sac != NULL && sac->rename) - s->name = sac->newname; - - if (!strcmp(s->name, ".symtab") || - !strcmp(s->name, ".strtab") || - !strcmp(s->name, ".shstrtab")) - return; - - prefix = NULL; - if (s->loadable && ecp->prefix_alloc != NULL) - prefix = ecp->prefix_alloc; - else if (ecp->prefix_sec != NULL) - prefix = ecp->prefix_sec; - - if (prefix != NULL) { - namelen = strlen(s->name) + strlen(prefix) + 1; - if ((s->newname = malloc(namelen)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - snprintf(s->newname, namelen, "%s%s", prefix, s->name); - s->name = s->newname; - } -} - -static int -get_section_flags(struct elfcopy *ecp, const char *name) -{ - struct sec_action *sac; - - sac = lookup_sec_act(ecp, name, 0); - if (sac != NULL && sac->flags) - return sac->flags; - - return (0); -} - -/* - * Determine whether the section are debugging section. - * According to libbfd, debugging sections are recognized - * only by name. - */ -static int -is_debug_section(const char *name) -{ - const char *dbg_sec[] = { - ".debug", - ".gnu.linkonce.wi.", - ".line", - ".stab", - NULL - }; - const char **p; - - for(p = dbg_sec; *p; p++) { - if (strncmp(name, *p, strlen(*p)) == 0) - return (1); - } - - return (0); -} - -static int -is_dwo_section(const char *name) -{ - size_t len; - - if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0) - return (1); - return (0); -} - -static int -is_print_section(struct elfcopy *ecp, const char *name) -{ - struct sec_action *sac; - - sac = lookup_sec_act(ecp, name, 0); - if (sac != NULL && sac->print != 0) - return (1); - - return (0); -} - -static int -is_modify_section(struct elfcopy *ecp, const char *name) -{ - - if (is_append_section(ecp, name) || - is_compress_section(ecp, name)) - return (1); - - return (0); -} - -struct sec_action* -lookup_sec_act(struct elfcopy *ecp, const char *name, int add) -{ - struct sec_action *sac; - - if (name == NULL) - return NULL; - - STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { - if (strcmp(name, sac->name) == 0) - return sac; - } - - if (add == 0) - return NULL; - - if ((sac = malloc(sizeof(*sac))) == NULL) - errx(EXIT_FAILURE, "not enough memory"); - memset(sac, 0, sizeof(*sac)); - sac->name = name; - STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list); - - return (sac); -} - -void -free_sec_act(struct elfcopy *ecp) -{ - struct sec_action *sac, *sac_temp; - - STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) { - STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list); - free(sac); - } -} - -void -insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail) -{ - struct section *s; - - if (!tail) { - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (sec->off < s->off) { - TAILQ_INSERT_BEFORE(s, sec, sec_list); - goto inc_nos; - } - } - } - - TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list); - -inc_nos: - if (sec->pseudo == 0) - ecp->nos++; -} - -/* - * First step of section creation: create scn and internal section - * structure, discard sections to be removed. - */ -void -create_scn(struct elfcopy *ecp) -{ - struct section *s; - const char *name; - Elf_Scn *is; - GElf_Shdr ish; - size_t indx; - uint64_t oldndx, newndx; - int elferr, sec_flags; - - /* - * Insert a pseudo section that contains the ELF header - * and program header. Used as reference for section offset - * or load address adjustment. - */ - if ((s = calloc(1, sizeof(*s))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - s->off = 0; - s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) + - gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT); - s->align = 1; - s->pseudo = 1; - s->loadable = add_to_inseg_list(ecp, s); - insert_to_sec_list(ecp, s, 0); - - /* Create internal .shstrtab section. */ - init_shstrtab(ecp); - - if (elf_getshstrndx(ecp->ein, &indx) == 0) - errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", - elf_errmsg(-1)); - - is = NULL; - while ((is = elf_nextscn(ecp->ein, is)) != NULL) { - if (gelf_getshdr(is, &ish) == NULL) - errx(EXIT_FAILURE, "219 gelf_getshdr failed: %s", - elf_errmsg(-1)); - if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL) - errx(EXIT_FAILURE, "elf_strptr failed: %s", - elf_errmsg(-1)); - - /* Skip sections to be removed. */ - if (is_remove_section(ecp, name)) - continue; - - /* - * Relocation section need to be remove if the section - * it applies will be removed. - */ - if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA) - if (ish.sh_info != 0 && - is_remove_reloc_sec(ecp, ish.sh_info)) - continue; - - /* - * Section groups should be removed if symbol table will - * be removed. (section group's signature stored in symbol - * table) - */ - if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL) - continue; - - /* Get section flags set by user. */ - sec_flags = get_section_flags(ecp, name); - - /* Create internal section object. */ - if (strcmp(name, ".shstrtab") != 0) { - if ((s = calloc(1, sizeof(*s))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - s->name = name; - s->is = is; - s->off = ish.sh_offset; - s->sz = ish.sh_size; - s->align = ish.sh_addralign; - s->type = ish.sh_type; - s->vma = ish.sh_addr; - - /* - * Search program headers to determine whether section - * is loadable, but if user explicitly set section flags - * while neither "load" nor "alloc" is set, we make the - * section unloadable. - */ - if (sec_flags && - (sec_flags & (SF_LOAD | SF_ALLOC)) == 0) - s->loadable = 0; - else - s->loadable = add_to_inseg_list(ecp, s); - } else { - /* Assuming .shstrtab is "unloadable". */ - s = ecp->shstrtab; - s->off = ish.sh_offset; - } - - oldndx = newndx = SHN_UNDEF; - if (strcmp(name, ".symtab") != 0 && - strcmp(name, ".strtab") != 0) { - if (!strcmp(name, ".shstrtab")) { - /* - * Add sections specified by --add-section and - * gnu debuglink. we want these sections have - * smaller index than .shstrtab section. - */ - if (ecp->debuglink != NULL) - add_gnu_debuglink(ecp); - if (ecp->flags & SEC_ADD) - insert_sections(ecp); - } - if ((s->os = elf_newscn(ecp->eout)) == NULL) - errx(EXIT_FAILURE, "elf_newscn failed: %s", - elf_errmsg(-1)); - if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF) - errx(EXIT_FAILURE, "elf_ndxscn failed: %s", - elf_errmsg(-1)); - } - if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF) - errx(EXIT_FAILURE, "elf_ndxscn failed: %s", - elf_errmsg(-1)); - if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF) - ecp->secndx[oldndx] = newndx; - - /* - * If strip action is STRIP_NONDEBUG(only keep debug), - * change sections flags of loadable sections to SHF_NOBITS, - * and the content of those sections will be ignored. - */ - if (ecp->strip == STRIP_NONDEBUG && (ish.sh_flags & SHF_ALLOC)) - s->type = SHT_NOBITS; - - check_section_rename(ecp, s); - - /* create section header based on input object. */ - if (strcmp(name, ".symtab") != 0 && - strcmp(name, ".strtab") != 0 && - strcmp(name, ".shstrtab") != 0) - copy_shdr(ecp, s, NULL, 0, sec_flags); - - if (strcmp(name, ".symtab") == 0) { - ecp->flags |= SYMTAB_EXIST; - ecp->symtab = s; - } - if (strcmp(name, ".strtab") == 0) - ecp->strtab = s; - - insert_to_sec_list(ecp, s, 0); - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_nextscn failed: %s", - elf_errmsg(elferr)); -} - -struct section * -insert_shtab(struct elfcopy *ecp, int tail) -{ - struct section *s, *shtab; - GElf_Ehdr ieh; - int nsecs; - - /* - * Treat section header table as a "pseudo" section, insert it - * into section list, so later it will get sorted and resynced - * just as normal sections. - */ - if ((shtab = calloc(1, sizeof(*shtab))) == NULL) - errx(EXIT_FAILURE, "calloc failed"); - if (!tail) { - /* - * "shoff" of input object is used as a hint for section - * resync later. - */ - if (gelf_getehdr(ecp->ein, &ieh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - shtab->off = ieh.e_shoff; - } else - shtab->off = 0; - /* Calculate number of sections in the output object. */ - nsecs = 0; - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (!s->pseudo) - nsecs++; - } - /* Remember there is always a null section, so we +1 here. */ - shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT); - if (shtab->sz == 0) - errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); - shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8); - shtab->loadable = 0; - shtab->pseudo = 1; - insert_to_sec_list(ecp, shtab, tail); - - return (shtab); -} - -void -copy_content(struct elfcopy *ecp) -{ - struct section *s; - - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - /* Skip pseudo section. */ - if (s->pseudo) - continue; - - /* Skip special sections. */ - if (strcmp(s->name, ".symtab") == 0 || - strcmp(s->name, ".strtab") == 0 || - strcmp(s->name, ".shstrtab") == 0) - continue; - - /* - * If strip action is STRIP_ALL, relocation info need - * to be stripped. Skip filtering otherwisw. - */ - if (ecp->strip == STRIP_ALL && - (s->type == SHT_REL || s->type == SHT_RELA)) - filter_reloc(ecp, s); - - if (is_modify_section(ecp, s->name)) - modify_section(ecp, s); - - copy_data(s); - - /* - * If symbol table is modified, relocation info might - * need update, as symbol index may have changed. - */ - if ((ecp->flags & SYMTAB_INTACT) == 0 && - (ecp->flags & SYMTAB_EXIST) && - (s->type == SHT_REL || s->type == SHT_RELA)) - update_reloc(ecp, s); - - if (is_print_section(ecp, s->name)) - print_section(s); - } -} - -/* - * Filter relocation entries, only keep those entries whose - * symbol is in the keep list. - */ -static void -filter_reloc(struct elfcopy *ecp, struct section *s) -{ - const char *name; - GElf_Shdr ish; - GElf_Rel rel; - GElf_Rela rela; - Elf32_Rel *rel32; - Elf64_Rel *rel64; - Elf32_Rela *rela32; - Elf64_Rela *rela64; - Elf_Data *id; - uint64_t cap, n, nrels; - int elferr, i; - - if (gelf_getshdr(s->is, &ish) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - - /* We don't want to touch relocation info for dynamic symbols. */ - if ((ecp->flags & SYMTAB_EXIST) == 0) { - if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0) { - /* - * This reloc section applies to the symbol table - * that was stripped, so discard whole section. - */ - s->nocopy = 1; - s->sz = 0; - } - return; - } else { - /* Symbol table exist, check if index equals. */ - if (ish.sh_link != elf_ndxscn(ecp->symtab->is)) - return; - } - -#define COPYREL(REL, SZ) do { \ - if (nrels == 0) { \ - if ((REL##SZ = malloc(cap * \ - sizeof(Elf##SZ##_Rel))) == NULL) \ - err(EXIT_FAILURE, "malloc failed"); \ - } \ - if (nrels >= cap) { \ - cap *= 2; \ - if ((REL##SZ = realloc(REL##SZ, cap * \ - sizeof(Elf##SZ##_Rel))) == NULL) \ - err(EXIT_FAILURE, "realloc failed"); \ - } \ - REL##SZ[nrels].r_offset = REL.r_offset; \ - REL##SZ[nrels].r_info = REL.r_info; \ - if (s->type == SHT_RELA) \ - rela##SZ[nrels].r_addend = rela.r_addend; \ - nrels++; \ -} while (0) - - nrels = 0; - cap = 4; /* keep list is usually small. */ - rel32 = NULL; - rel64 = NULL; - rela32 = NULL; - rela64 = NULL; - if ((id = elf_getdata(s->is, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_getdata() failed: %s", - elf_errmsg(-1)); - n = ish.sh_size / ish.sh_entsize; - for(i = 0; (uint64_t)i < n; i++) { - if (s->type == SHT_REL) { - if (gelf_getrel(id, i, &rel) != &rel) - errx(EXIT_FAILURE, "gelf_getrel failed: %s", - elf_errmsg(-1)); - } else { - if (gelf_getrela(id, i, &rela) != &rela) - errx(EXIT_FAILURE, "gelf_getrel failed: %s", - elf_errmsg(-1)); - } - name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is), - GELF_R_SYM(rel.r_info)); - if (name == NULL) - errx(EXIT_FAILURE, "elf_strptr failed: %s", - elf_errmsg(-1)); - if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) { - if (ecp->oec == ELFCLASS32) { - if (s->type == SHT_REL) - COPYREL(rel, 32); - else - COPYREL(rela, 32); - } else { - if (s->type == SHT_REL) - COPYREL(rel, 64); - else - COPYREL(rela, 64); - } - } - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_getdata() failed: %s", - elf_errmsg(elferr)); - - if (ecp->oec == ELFCLASS32) { - if (s->type == SHT_REL) - s->buf = rel32; - else - s->buf = rela32; - } else { - if (s->type == SHT_REL) - s->buf = rel64; - else - s->buf = rela64; - } - s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL : - ELF_T_RELA), nrels, EV_CURRENT); - s->nocopy = 1; -} - -static void -update_reloc(struct elfcopy *ecp, struct section *s) -{ - GElf_Shdr osh; - GElf_Rel rel; - GElf_Rela rela; - Elf_Data *od; - uint64_t n; - int i; - -#define UPDATEREL(REL) do { \ - if (gelf_get##REL(od, i, &REL) != &REL) \ - errx(EXIT_FAILURE, "gelf_get##REL failed: %s", \ - elf_errmsg(-1)); \ - REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)], \ - GELF_R_TYPE(REL.r_info)); \ - if (!gelf_update_##REL(od, i, &REL)) \ - errx(EXIT_FAILURE, "gelf_update_##REL failed: %s", \ - elf_errmsg(-1)); \ -} while(0) - - if (s->sz == 0) - return; - if (gelf_getshdr(s->os, &osh) == NULL) - errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", - elf_errmsg(-1)); - /* Only process .symtab reloc info. */ - if (osh.sh_link != elf_ndxscn(ecp->symtab->is)) - return; - if ((od = elf_getdata(s->os, NULL)) == NULL) - errx(EXIT_FAILURE, "elf_getdata() failed: %s", - elf_errmsg(-1)); - n = osh.sh_size / osh.sh_entsize; - for(i = 0; (uint64_t)i < n; i++) { - if (s->type == SHT_REL) - UPDATEREL(rel); - else - UPDATEREL(rela); - } -} - -static void -pad_section(struct elfcopy *ecp, struct section *s) -{ - GElf_Shdr osh; - Elf_Data *od; - - if (s == NULL || s->pad_sz == 0) - return; - - if ((s->pad = malloc(s->pad_sz)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - memset(s->pad, ecp->fill, s->pad_sz); - - /* Create a new Elf_Data to contain the padding bytes. */ - if ((od = elf_newdata(s->os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s", - elf_errmsg(-1)); - od->d_align = 1; - od->d_off = s->sz; - od->d_buf = s->pad; - od->d_type = ELF_T_BYTE; - od->d_size = s->pad_sz; - od->d_version = EV_CURRENT; - - /* Update section header. */ - if (gelf_getshdr(s->os, &osh) == NULL) - errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", - elf_errmsg(-1)); - osh.sh_size = s->sz + s->pad_sz; - if (!gelf_update_shdr(s->os, &osh)) - errx(EXIT_FAILURE, "elf_update_shdr failed: %s", - elf_errmsg(-1)); -} - -void -resync_sections(struct elfcopy *ecp) -{ - struct section *s, *ps; - GElf_Shdr osh; - uint64_t off; - int first; - - ps = NULL; - first = 1; - off = 0; - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (first) { - off = s->off; - first = 0; - } - - /* - * Ignore TLS sections with load address 0 and without - * content. We don't need to adjust their file offset or - * VMA, only the size matters. - */ - if (s->seg_tls != NULL && s->type == SHT_NOBITS && - s->off == 0) - continue; - - /* Align section offset. */ - if (s->align == 0) - s->align = 1; - if (off <= s->off) { - if (!s->loadable) - s->off = roundup(off, s->align); - } else { - if (s->loadable) - warnx("moving loadable section %s, " - "is this intentional?", s->name); - s->off = roundup(off, s->align); - } - - /* Calculate next section offset. */ - off = s->off; - if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL)) - off += s->sz; - - if (s->pseudo) { - ps = NULL; - continue; - } - - /* Count padding bytes added through --pad-to. */ - if (s->pad_sz > 0) - off += s->pad_sz; - - /* Update section header accordingly. */ - if (gelf_getshdr(s->os, &osh) == NULL) - errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", - elf_errmsg(-1)); - osh.sh_addr = s->vma; - osh.sh_offset = s->off; - osh.sh_size = s->sz; - if (!gelf_update_shdr(s->os, &osh)) - errx(EXIT_FAILURE, "elf_update_shdr failed: %s", - elf_errmsg(-1)); - - /* Add padding for previous section, if need. */ - if (ps != NULL) { - if (ps->pad_sz > 0) { - /* Apply padding added by --pad-to. */ - pad_section(ecp, ps); - } else if ((ecp->flags & GAP_FILL) && - (ps->off + ps->sz < s->off)) { - /* - * Fill the gap between sections by padding - * the section with lower address. - */ - ps->pad_sz = s->off - (ps->off + ps->sz); - pad_section(ecp, ps); - } - } - - ps = s; - } - - /* Pad the last section, if need. */ - if (ps != NULL && ps->pad_sz > 0) - pad_section(ecp, ps); -} - -static void -modify_section(struct elfcopy *ecp, struct section *s) -{ - struct sec_action *sac; - size_t srcsz, dstsz, p, len; - char *b, *c, *d, *src, *end; - int dupe; - - src = read_section(s, &srcsz); - if (src == NULL || srcsz == 0) { - /* For empty section, we proceed if we need to append. */ - if (!is_append_section(ecp, s->name)) - return; - } - - /* Allocate buffer needed for new section data. */ - dstsz = srcsz; - if (is_append_section(ecp, s->name)) { - sac = lookup_sec_act(ecp, s->name, 0); - dstsz += strlen(sac->string) + 1; - } - if ((b = malloc(dstsz)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - s->buf = b; - - /* Compress section. */ - p = 0; - if (is_compress_section(ecp, s->name)) { - end = src + srcsz; - for(c = src; c < end;) { - len = 0; - while(c + len < end && c[len] != '\0') - len++; - if (c + len == end) { - /* XXX should we warn here? */ - strncpy(&b[p], c, len); - p += len; - break; - } - dupe = 0; - for (d = b; d < b + p; ) { - if (strcmp(d, c) == 0) { - dupe = 1; - break; - } - d += strlen(d) + 1; - } - if (!dupe) { - strncpy(&b[p], c, len); - b[p + len] = '\0'; - p += len + 1; - } - c += len + 1; - } - } else { - memcpy(b, src, srcsz); - p += srcsz; - } - - /* Append section. */ - if (is_append_section(ecp, s->name)) { - sac = lookup_sec_act(ecp, s->name, 0); - len = strlen(sac->string); - strncpy(&b[p], sac->string, len); - b[p + len] = '\0'; - p += len + 1; - } - - s->sz = p; - s->nocopy = 1; -} - -static void -print_data(const char *d, size_t sz) -{ - const char *c; - - for (c = d; c < d + sz; c++) { - if (*c == '\0') - putchar('\n'); - else - putchar(*c); - } -} - -static void -print_section(struct section *s) -{ - Elf_Data *id; - int elferr; - - if (s->buf != NULL && s->sz > 0) { - print_data(s->buf, s->sz); - } else { - id = NULL; - while ((id = elf_getdata(s->is, id)) != NULL) - print_data(id->d_buf, id->d_size); - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_getdata() failed: %s", - elf_errmsg(elferr)); - } - putchar('\n'); -} - -static void * -read_section(struct section *s, size_t *size) -{ - Elf_Data *id; - char *b; - size_t sz; - int elferr; - - sz = 0; - b = NULL; - id = NULL; - while ((id = elf_getdata(s->is, id)) != NULL) { - if (b == NULL) - b = malloc(id->d_size); - else - b = malloc(sz + id->d_size); - if (b == NULL) - err(EXIT_FAILURE, "malloc or realloc failed"); - - memcpy(&b[sz], id->d_buf, id->d_size); - sz += id->d_size; - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_getdata() failed: %s", - elf_errmsg(elferr)); - - *size = sz; - - return (b); -} - -void -copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy, - int sec_flags) -{ - GElf_Shdr ish, osh; - - if (gelf_getshdr(s->is, &ish) == NULL) - errx(EXIT_FAILURE, "526 gelf_getshdr() failed: %s", - elf_errmsg(-1)); - if (gelf_getshdr(s->os, &osh) == NULL) - errx(EXIT_FAILURE, "529 gelf_getshdr() failed: %s", - elf_errmsg(-1)); - - if (copy) - (void) memcpy(&osh, &ish, sizeof(ish)); - else { - osh.sh_type = s->type; - osh.sh_addr = s->vma; - osh.sh_offset = s->off; - osh.sh_size = s->sz; - osh.sh_link = ish.sh_link; - osh.sh_info = ish.sh_info; - osh.sh_addralign = s->align; - osh.sh_entsize = ish.sh_entsize; - - if (sec_flags) { - osh.sh_flags = 0; - if (sec_flags & SF_ALLOC) { - osh.sh_flags |= SHF_ALLOC; - if (!s->loadable) - warnx("set SHF_ALLOC flag for " - "unloadable section %s", - s->name); - } - if ((sec_flags & SF_READONLY) == 0) - osh.sh_flags |= SHF_WRITE; - if (sec_flags & SF_CODE) - osh.sh_flags |= SHF_EXECINSTR; - } else - osh.sh_flags = ish.sh_flags; - } - - if (name == NULL) - add_to_shstrtab(ecp, s->name); - else - add_to_shstrtab(ecp, name); - - if (!gelf_update_shdr(s->os, &osh)) - errx(EXIT_FAILURE, "elf_update_shdr failed: %s", - elf_errmsg(-1)); -} - -void -copy_data(struct section *s) -{ - Elf_Data *id, *od; - int elferr; - - if (s->nocopy && s->buf == NULL) - return; - - if ((id = elf_getdata(s->is, NULL)) == NULL) { - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_getdata() failed: %s", - elf_errmsg(elferr)); - return; - } - - if ((od = elf_newdata(s->os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s", - elf_errmsg(-1)); - - if (s->nocopy) { - /* Use s->buf as content if s->nocopy is set. */ - od->d_align = id->d_align; - od->d_off = 0; - od->d_buf = s->buf; - od->d_type = id->d_type; - od->d_size = s->sz; - od->d_version = id->d_version; - } else { - od->d_align = id->d_align; - od->d_off = id->d_off; - od->d_buf = id->d_buf; - od->d_type = id->d_type; - od->d_size = id->d_size; - od->d_version = id->d_version; - } - - /* - * Alignment Fixup. libelf does not allow the alignment for - * Elf_Data descriptor to be set to 0. In this case we workaround - * it by setting the alignment to 1. - * - * According to the ELF ABI, alignment 0 and 1 has the same - * meaning: the section has no alignment constraints. - */ - if (od->d_align == 0) - od->d_align = 1; -} - -struct section * -create_external_section(struct elfcopy *ecp, const char *name, char *newname, - void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype, - uint64_t flags, uint64_t align, uint64_t vma, int loadable) -{ - struct section *s; - Elf_Scn *os; - Elf_Data *od; - GElf_Shdr osh; - - if ((os = elf_newscn(ecp->eout)) == NULL) - errx(EXIT_FAILURE, "elf_newscn() failed: %s", - elf_errmsg(-1)); - if ((s = calloc(1, sizeof(*s))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - s->name = name; - s->newname = newname; /* needs to be free()'ed */ - s->off = off; - s->sz = size; - s->vma = vma; - s->align = align; - s->loadable = loadable; - s->is = NULL; - s->os = os; - s->type = stype; - s->nocopy = 1; - insert_to_sec_list(ecp, s, 1); - - if (gelf_getshdr(os, &osh) == NULL) - errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", - elf_errmsg(-1)); - osh.sh_flags = flags; - osh.sh_type = s->type; - osh.sh_addr = s->vma; - osh.sh_addralign = s->align; - if (!gelf_update_shdr(os, &osh)) - errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", - elf_errmsg(-1)); - add_to_shstrtab(ecp, name); - - if (buf != NULL && size != 0) { - if ((od = elf_newdata(os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s", - elf_errmsg(-1)); - od->d_align = align; - od->d_off = 0; - od->d_buf = buf; - od->d_size = size; - od->d_type = dtype; - od->d_version = EV_CURRENT; - } - - /* - * Clear SYMTAB_INTACT, as we probably need to update/add new - * STT_SECTION symbols into the symbol table. - */ - ecp->flags &= ~SYMTAB_INTACT; - - return (s); -} - -/* - * Insert sections specified by --add-section to the end of section list. - */ -static void -insert_sections(struct elfcopy *ecp) -{ - struct sec_add *sa; - struct section *s; - size_t off; - - /* Put these sections in the end of current list. */ - off = 0; - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (s->type != SHT_NOBITS && s->type != SHT_NULL) - off = s->off + s->sz; - else - off = s->off; - } - - STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) { - - /* TODO: Add section header vma/lma, flag changes here */ - - (void) create_external_section(ecp, sa->name, NULL, sa->content, - sa->size, off, SHT_PROGBITS, ELF_T_BYTE, 0, 1, 0, 0); - } -} - -void -add_to_shstrtab(struct elfcopy *ecp, const char *name) -{ - struct section *s; - - s = ecp->shstrtab; - insert_to_strtab(s, name); -} - -void -update_shdr(struct elfcopy *ecp, int update_link) -{ - struct section *s; - GElf_Shdr osh; - int elferr; - - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (s->pseudo) - continue; - - if (gelf_getshdr(s->os, &osh) == NULL) - errx(EXIT_FAILURE, "668 gelf_getshdr failed: %s", - elf_errmsg(-1)); - - /* Find section name in string table and set sh_name. */ - osh.sh_name = lookup_string(ecp->shstrtab, s->name); - - /* - * sh_link needs to be updated, since the index of the - * linked section might have changed. - */ - if (update_link && osh.sh_link != 0) - osh.sh_link = ecp->secndx[osh.sh_link]; - - /* - * sh_info of relocation section links to the section to which - * its relocation info applies. So it may need update as well. - */ - if ((s->type == SHT_REL || s->type == SHT_RELA) && - osh.sh_info != 0) - osh.sh_info = ecp->secndx[osh.sh_info]; - - /* - * sh_info of SHT_GROUP section needs to point to the correct - * string in the symbol table. - */ - if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) && - (ecp->flags & SYMTAB_INTACT) == 0) - osh.sh_info = ecp->symndx[osh.sh_info]; - - if (!gelf_update_shdr(s->os, &osh)) - errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", - elf_errmsg(-1)); - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_nextscn failed: %s", - elf_errmsg(elferr)); -} - -void -init_shstrtab(struct elfcopy *ecp) -{ - struct section *s; - - if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - s = ecp->shstrtab; - s->name = ".shstrtab"; - s->is = NULL; - s->sz = 0; - s->align = 1; - s->loadable = 0; - s->type = SHT_STRTAB; - s->vma = 0; - - insert_to_strtab(s, ""); - insert_to_strtab(s, ".symtab"); - insert_to_strtab(s, ".strtab"); - insert_to_strtab(s, ".shstrtab"); -} - -void -set_shstrtab(struct elfcopy *ecp) -{ - struct section *s; - Elf_Data *data; - GElf_Shdr sh; - - s = ecp->shstrtab; - - if (gelf_getshdr(s->os, &sh) == NULL) - errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s", - elf_errmsg(-1)); - sh.sh_addr = 0; - sh.sh_addralign = 1; - sh.sh_offset = s->off; - sh.sh_type = SHT_STRTAB; - sh.sh_flags = 0; - sh.sh_entsize = 0; - sh.sh_info = 0; - sh.sh_link = 0; - - if ((data = elf_newdata(s->os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s", - elf_errmsg(-1)); - - /* - * If we don't have a symbol table, skip those a few bytes - * which are reserved for this in the beginning of shstrtab. - */ - if (!(ecp->flags & SYMTAB_EXIST)) { - s->sz -= sizeof(".symtab\0.strtab"); - memmove(s->buf, (char *)s->buf + sizeof(".symtab\0.strtab"), - s->sz); - } - - sh.sh_size = s->sz; - if (!gelf_update_shdr(s->os, &sh)) - errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", - elf_errmsg(-1)); - - data->d_align = 1; - data->d_buf = s->buf; - data->d_size = s->sz; - data->d_off = 0; - data->d_type = ELF_T_BYTE; - data->d_version = EV_CURRENT; - - if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os))) - errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s", - elf_errmsg(-1)); -} - -void -add_section(struct elfcopy *ecp, const char *arg) -{ - struct sec_add *sa; - struct stat sb; - const char *s, *fn; - FILE *fp; - int len; - - if ((s = strchr(arg, '=')) == NULL) - errx(EXIT_FAILURE, - "illegal format for --add-section option"); - if ((sa = malloc(sizeof(*sa))) == NULL) - err(EXIT_FAILURE, "malloc failed"); - - len = s - arg; - if ((sa->name = malloc(len + 1)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - strncpy(sa->name, arg, len); - sa->name[len] = '\0'; - - fn = s + 1; - if (stat(fn, &sb) == -1) - err(EXIT_FAILURE, "stat failed"); - sa->size = sb.st_size; - if ((sa->content = malloc(sa->size)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - if ((fp = fopen(fn, "r")) == NULL) - err(EXIT_FAILURE, "can not open %s", fn); - if (fread(sa->content, 1, sa->size, fp) == 0 || - ferror(fp)) - err(EXIT_FAILURE, "fread failed"); - fclose(fp); - - STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); - ecp->flags |= SEC_ADD; -} - -void -free_sec_add(struct elfcopy *ecp) -{ - struct sec_add *sa, *sa_temp; - - STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) { - STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list); - free(sa->name); - free(sa->content); - free(sa); - } -} - -static void -add_gnu_debuglink(struct elfcopy *ecp) -{ - struct sec_add *sa; - struct stat sb; - FILE *fp; - char *fnbase, *buf; - int crc_off; - int crc; - - if (ecp->debuglink == NULL) - return; - - /* Read debug file content. */ - if ((sa = malloc(sizeof(*sa))) == NULL) - err(EXIT_FAILURE, "malloc failed"); - if ((sa->name = strdup(".gnu_debuglink")) == NULL) - err(EXIT_FAILURE, "strdup failed"); - if (stat(ecp->debuglink, &sb) == -1) - err(EXIT_FAILURE, "stat failed"); - if ((buf = malloc(sb.st_size)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - if ((fp = fopen(ecp->debuglink, "r")) == NULL) - err(EXIT_FAILURE, "can not open %s", ecp->debuglink); - if (fread(buf, 1, sb.st_size, fp) == 0 || - ferror(fp)) - err(EXIT_FAILURE, "fread failed"); - fclose(fp); - - /* Calculate crc checksum. */ - crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF); - free(buf); - - /* Calculate section size and the offset to store crc checksum. */ - if ((fnbase = basename(ecp->debuglink)) == NULL) - err(EXIT_FAILURE, "basename failed"); - crc_off = roundup(strlen(fnbase) + 1, 4); - sa->size = crc_off + 4; - - /* Section content. */ - if ((sa->content = calloc(1, sa->size)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - strncpy(sa->content, fnbase, strlen(fnbase)); - if (ecp->oed == ELFDATA2LSB) { - sa->content[crc_off] = crc & 0xFF; - sa->content[crc_off + 1] = (crc >> 8) & 0xFF; - sa->content[crc_off + 2] = (crc >> 16) & 0xFF; - sa->content[crc_off + 3] = crc >> 24; - } else { - sa->content[crc_off] = crc >> 24; - sa->content[crc_off + 1] = (crc >> 16) & 0xFF; - sa->content[crc_off + 2] = (crc >> 8) & 0xFF; - sa->content[crc_off + 3] = crc & 0xFF; - } - - STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); - ecp->flags |= SEC_ADD; -} - -static void -insert_to_strtab(struct section *t, const char *s) -{ - const char *r; - char *b, *c; - size_t len, slen; - int append; - - if (t->sz == 0) { - t->cap = 512; - if ((t->buf = malloc(t->cap)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - } - - slen = strlen(s); - append = 0; - b = t->buf; - for (c = b; c < b + t->sz;) { - len = strlen(c); - if (!append && len >= slen) { - r = c + (len - slen); - if (strcmp(r, s) == 0) - return; - } else if (len < slen && len != 0) { - r = s + (slen - len); - if (strcmp(c, r) == 0) { - t->sz -= len + 1; - memmove(c, c + len + 1, t->sz - (c - b)); - append = 1; - continue; - } - } - c += len + 1; - } - - while (t->sz + slen + 1 >= t->cap) { - t->cap *= 2; - if ((t->buf = realloc(t->buf, t->cap)) == NULL) - err(EXIT_FAILURE, "realloc failed"); - } - b = t->buf; - strncpy(&b[t->sz], s, slen); - b[t->sz + slen] = '\0'; - t->sz += slen + 1; -} - -static int -lookup_string(struct section *t, const char *s) -{ - const char *b, *c, *r; - size_t len, slen; - - slen = strlen(s); - b = t->buf; - for (c = b; c < b + t->sz;) { - len = strlen(c); - if (len >= slen) { - r = c + (len - slen); - if (strcmp(r, s) == 0) - return (r - b); - } - c += len + 1; - } - - return (-1); -} - -static uint32_t crctable[256] = -{ - 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, - 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, - 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, - 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, - 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, - 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, - 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, - 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, - 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, - 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, - 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, - 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, - 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, - 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, - 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, - 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, - 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, - 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, - 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, - 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, - 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, - 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, - 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, - 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, - 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, - 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, - 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, - 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, - 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, - 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, - 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, - 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, - 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, - 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, - 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, - 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, - 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, - 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, - 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, - 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, - 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, - 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, - 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, - 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, - 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, - 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, - 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, - 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, - 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, - 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, - 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, - 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, - 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, - 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, - 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, - 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, - 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, - 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, - 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, - 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, - 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, - 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, - 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, - 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL -}; - -static uint32_t -calc_crc32(const char *p, size_t len, uint32_t crc) -{ - uint32_t i; - - for (i = 0; i < len; i++) { - crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8); - } - - return (crc ^ 0xFFFFFFFF); -} diff --git a/contrib/elftoolchain/elfcopy/segments.c b/contrib/elftoolchain/elfcopy/segments.c deleted file mode 100644 index 1e271a6f4347..000000000000 --- a/contrib/elftoolchain/elfcopy/segments.c +++ /dev/null @@ -1,495 +0,0 @@ -/*- - * Copyright (c) 2007-2010,2012 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 <err.h> -#include <gelf.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "elfcopy.h" - -ELFTC_VCSID("$Id: segments.c 3196 2015-05-12 17:33:48Z emaste $"); - -static void insert_to_inseg_list(struct segment *seg, struct section *sec); - -/* - * elfcopy's segment handling is relatively simpler and less powerful than - * libbfd. Program headers are modified or copied from input to output objects, - * but never re-generated. As a result, if the input object has incorrect - * program headers, the output object's program headers will remain incorrect - * or become even worse. - */ - -/* - * Check whether a section is "loadable". If so, add it to the - * corresponding segment list(s) and return 1. - */ -int -add_to_inseg_list(struct elfcopy *ecp, struct section *s) -{ - struct segment *seg; - int loadable; - - if (ecp->ophnum == 0) - return (0); - - /* - * Segment is a different view of an ELF object. One segment can - * contain one or more sections, and one section can be included - * in one or more segments, or not included in any segment at all. - * We call those sections which can be found in one or more segments - * "loadable" sections, and call the rest "unloadable" sections. - * We keep track of "loadable" sections in their containing - * segment(s)' v_sec queue. These information are later used to - * recalculate the extents of segments, when sections are removed, - * for example. - */ - loadable = 0; - STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { - if (s->off < seg->off || (s->vma < seg->addr && !s->pseudo)) - continue; - if (s->off + s->sz > seg->off + seg->fsz && - s->type != SHT_NOBITS) - continue; - if (s->off + s->sz > seg->off + seg->msz) - continue; - if (s->vma + s->sz > seg->addr + seg->msz) - continue; - - insert_to_inseg_list(seg, s); - if (seg->type == PT_LOAD) - s->seg = seg; - else if (seg->type == PT_TLS) - s->seg_tls = seg; - s->lma = seg->addr + (s->off - seg->off); - loadable = 1; - } - - return (loadable); -} - -void -adjust_addr(struct elfcopy *ecp) -{ - struct section *s, *s0; - struct segment *seg; - struct sec_action *sac; - uint64_t dl, lma, start, end; - int found, i; - - /* - * Apply VMA and global LMA changes in the first iteration. - */ - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - - /* Only adjust loadable section's address. */ - if (!s->loadable || s->seg == NULL) - continue; - - /* Apply global LMA adjustment. */ - if (ecp->change_addr != 0) - s->lma += ecp->change_addr; - - if (!s->pseudo) { - /* Apply global VMA adjustment. */ - if (ecp->change_addr != 0) - s->vma += ecp->change_addr; - - /* Apply section VMA adjustment. */ - sac = lookup_sec_act(ecp, s->name, 0); - if (sac == NULL) - continue; - if (sac->setvma) - s->vma = sac->vma; - if (sac->vma_adjust != 0) - s->vma += sac->vma_adjust; - } - } - - /* - * Apply sections LMA change in the second iteration. - */ - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - - /* Only adjust loadable section's LMA. */ - if (!s->loadable || s->seg == NULL) - continue; - - /* - * Check if there is a LMA change request for this - * section. - */ - sac = lookup_sec_act(ecp, s->name, 0); - if (sac == NULL) - continue; - if (!sac->setlma && sac->lma_adjust == 0) - continue; - lma = s->lma; - if (sac->setlma) - lma = sac->lma; - if (sac->lma_adjust != 0) - lma += sac->lma_adjust; - if (lma == s->lma) - continue; - - /* - * Check if the LMA change is viable. - * - * 1. Check if the new LMA is properly aligned accroding to - * section alignment. - * - * 2. Compute the new extent of segment that contains this - * section, make sure it doesn't overlap with other - * segments. - */ -#ifdef DEBUG - printf("LMA for section %s: %#jx\n", s->name, lma); -#endif - - if (lma % s->align != 0) - errx(EXIT_FAILURE, "The load address %#jx for " - "section %s is not aligned to %ju", - (uintmax_t) lma, s->name, s->align); - - if (lma < s->lma) { - /* Move section to lower address. */ - if (lma < s->lma - s->seg->addr) - errx(EXIT_FAILURE, "Not enough space to move " - "section %s load address to %#jx", s->name, - (uintmax_t) lma); - start = lma - (s->lma - s->seg->addr); - if (s == s->seg->v_sec[s->seg->nsec - 1]) - end = start + s->seg->msz; - else - end = s->seg->addr + s->seg->msz; - - } else { - /* Move section to upper address. */ - if (s == s->seg->v_sec[0]) - start = lma; - else - start = s->seg->addr; - end = lma + (s->seg->addr + s->seg->msz - s->lma); - if (end < start) - errx(EXIT_FAILURE, "Not enough space to move " - "section %s load address to %#jx", s->name, - (uintmax_t) lma); - } - -#ifdef DEBUG - printf("new extent for segment containing %s: (%#jx,%#jx)\n", - s->name, start, end); -#endif - - STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { - if (seg == s->seg || seg->type != PT_LOAD) - continue; - if (start > seg->addr + seg->msz) - continue; - if (end < seg->addr) - continue; - errx(EXIT_FAILURE, "The extent of segment containing " - "section %s overlaps with segment(%#jx,%#jx)", - s->name, seg->addr, seg->addr + seg->msz); - } - - /* - * Update section LMA and file offset. - */ - - if (lma < s->lma) { - /* - * To move a section to lower load address, we decrease - * the load addresses of the section and all the - * sections that are before it, and we increase the - * file offsets of all the sections that are after it. - */ - dl = s->lma - lma; - for (i = 0; i < s->seg->nsec; i++) { - s0 = s->seg->v_sec[i]; - s0->lma -= dl; -#ifdef DEBUG - printf("section %s LMA set to %#jx\n", - s0->name, (uintmax_t) s0->lma); -#endif - if (s0 == s) - break; - } - for (i = i + 1; i < s->seg->nsec; i++) { - s0 = s->seg->v_sec[i]; - s0->off += dl; -#ifdef DEBUG - printf("section %s offset set to %#jx\n", - s0->name, (uintmax_t) s0->off); -#endif - } - } else { - /* - * To move a section to upper load address, we increase - * the load addresses of the section and all the - * sections that are after it, and we increase the - * their file offsets too unless the section in question - * is the first in its containing segment. - */ - dl = lma - s->lma; - for (i = 0; i < s->seg->nsec; i++) - if (s->seg->v_sec[i] == s) - break; - if (i >= s->seg->nsec) - errx(EXIT_FAILURE, "Internal: section `%s' not" - " found in its containing segement", - s->name); - for (; i < s->seg->nsec; i++) { - s0 = s->seg->v_sec[i]; - s0->lma += dl; -#ifdef DEBUG - printf("section %s LMA set to %#jx\n", - s0->name, (uintmax_t) s0->lma); -#endif - if (s != s->seg->v_sec[0]) { - s0->off += dl; -#ifdef DEBUG - printf("section %s offset set to %#jx\n", - s0->name, (uintmax_t) s0->off); -#endif - } - } - } - } - - /* - * Apply load address padding. - */ - - if (ecp->pad_to != 0) { - - /* - * Find the section with highest load address. - */ - - s = NULL; - STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { - if (seg->type != PT_LOAD) - continue; - for (i = seg->nsec - 1; i >= 0; i--) - if (seg->v_sec[i]->type != SHT_NOBITS) - break; - if (i < 0) - continue; - if (s == NULL) - s = seg->v_sec[i]; - else { - s0 = seg->v_sec[i]; - if (s0->lma > s->lma) - s = s0; - } - } - - if (s == NULL) - goto issue_warn; - - /* No need to pad if the pad_to address is lower. */ - if (ecp->pad_to <= s->lma + s->sz) - goto issue_warn; - - s->pad_sz = ecp->pad_to - (s->lma + s->sz); -#ifdef DEBUG - printf("pad section %s load to address %#jx by %#jx\n", s->name, - (uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz); -#endif - } - -issue_warn: - - /* - * Issue a warning if there are VMA/LMA adjust requests for - * some nonexistent sections. - */ - if ((ecp->flags & NO_CHANGE_WARN) == 0) { - STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { - if (!sac->setvma && !sac->setlma && - !sac->vma_adjust && !sac->lma_adjust) - continue; - found = 0; - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (s->pseudo || s->name == NULL) - continue; - if (!strcmp(s->name, sac->name)) { - found = 1; - break; - } - } - if (!found) - warnx("cannot find section `%s'", sac->name); - } - } -} - -static void -insert_to_inseg_list(struct segment *seg, struct section *sec) -{ - struct section *s; - int i; - - seg->nsec++; - seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec)); - if (seg->v_sec == NULL) - err(EXIT_FAILURE, "realloc failed"); - - /* - * Sort the section in order of offset. - */ - - for (i = seg->nsec - 1; i > 0; i--) { - s = seg->v_sec[i - 1]; - if (sec->off >= s->off) { - seg->v_sec[i] = sec; - break; - } else - seg->v_sec[i] = s; - } - if (i == 0) - seg->v_sec[0] = sec; -} - -void -setup_phdr(struct elfcopy *ecp) -{ - struct segment *seg; - GElf_Phdr iphdr; - size_t iphnum; - int i; - - if (elf_getphnum(ecp->ein, &iphnum) == 0) - errx(EXIT_FAILURE, "elf_getphnum failed: %s", - elf_errmsg(-1)); - - ecp->ophnum = ecp->iphnum = iphnum; - if (iphnum == 0) - return; - - /* If --only-keep-debug is specified, discard all program headers. */ - if (ecp->strip == STRIP_NONDEBUG) { - ecp->ophnum = 0; - return; - } - - for (i = 0; (size_t)i < iphnum; i++) { - if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr) - errx(EXIT_FAILURE, "gelf_getphdr failed: %s", - elf_errmsg(-1)); - if ((seg = calloc(1, sizeof(*seg))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - seg->addr = iphdr.p_vaddr; - seg->off = iphdr.p_offset; - seg->fsz = iphdr.p_filesz; - seg->msz = iphdr.p_memsz; - seg->type = iphdr.p_type; - STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list); - } -} - -void -copy_phdr(struct elfcopy *ecp) -{ - struct segment *seg; - struct section *s; - GElf_Phdr iphdr, ophdr; - int i; - - STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { - if (seg->type == PT_PHDR) { - if (!TAILQ_EMPTY(&ecp->v_sec)) { - s = TAILQ_FIRST(&ecp->v_sec); - if (s->pseudo) - seg->addr = s->lma + - gelf_fsize(ecp->eout, ELF_T_EHDR, - 1, EV_CURRENT); - } - seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR, - ecp->ophnum, EV_CURRENT); - continue; - } - - seg->fsz = seg->msz = 0; - for (i = 0; i < seg->nsec; i++) { - s = seg->v_sec[i]; - seg->msz = s->vma + s->sz - seg->addr; - if (s->type != SHT_NOBITS) - seg->fsz = s->off + s->sz - seg->off; - } - } - - /* - * Allocate space for program headers, note that libelf keep - * track of the number in internal variable, and a call to - * elf_update is needed to update e_phnum of ehdr. - */ - if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL) - errx(EXIT_FAILURE, "gelf_newphdr() failed: %s", - elf_errmsg(-1)); - - /* - * This elf_update() call is to update the e_phnum field in - * ehdr. It's necessary because later we will call gelf_getphdr(), - * which does sanity check by comparing ndx argument with e_phnum. - */ - if (elf_update(ecp->eout, ELF_C_NULL) < 0) - errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1)); - - /* - * iphnum == ophnum, since we don't remove program headers even if - * they no longer contain sections. - */ - i = 0; - STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { - if (i >= ecp->iphnum) - break; - if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr) - errx(EXIT_FAILURE, "gelf_getphdr failed: %s", - elf_errmsg(-1)); - if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr) - errx(EXIT_FAILURE, "gelf_getphdr failed: %s", - elf_errmsg(-1)); - - ophdr.p_type = iphdr.p_type; - ophdr.p_vaddr = seg->addr; - ophdr.p_paddr = seg->addr; - ophdr.p_flags = iphdr.p_flags; - ophdr.p_align = iphdr.p_align; - ophdr.p_offset = seg->off; - ophdr.p_filesz = seg->fsz; - ophdr.p_memsz = seg->msz; - if (!gelf_update_phdr(ecp->eout, i, &ophdr)) - err(EXIT_FAILURE, "gelf_update_phdr failed :%s", - elf_errmsg(-1)); - - i++; - } -} diff --git a/contrib/elftoolchain/elfcopy/strip.1 b/contrib/elftoolchain/elfcopy/strip.1 deleted file mode 100644 index e07affbb9440..000000000000 --- a/contrib/elftoolchain/elfcopy/strip.1 +++ /dev/null @@ -1,132 +0,0 @@ -.\" Copyright (c) 2011 Joseph Koshy. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY JOSEPH KOSHY ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL JOSEPH KOSHY BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id: strip.1 2069 2011-10-26 15:53:48Z jkoshy $ -.\" -.Dd September 17, 2011 -.Os -.Dt STRIP 1 -.Sh NAME -.Nm strip -.Nd discard information from ELF objects -.Sh SYNOPSIS -.Nm -.Op Fl d | Fl g | Fl S | Fl -strip-debug -.Op Fl h | Fl -help -.Op Fl -only-keep-debug -.Op Fl o Ar outputfile | Fl -output-file= Ns Ar outputfile -.Op Fl p | Fl -preserve-dates -.Op Fl s | Fl -strip-all -.Op Fl -strip-unneeded -.Op Fl w | Fl -wildcard -.Op Fl x | Fl -discard-all -.Op Fl I Ar format | Fl -input-target= Ns Ar format -.Op Fl K Ar symbol | Fl -keep-symbol= Ns Ar symbol -.Op Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbol -.Op Fl O Ar format | Fl -output-target= Ns Ar format -.Op Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname -.Op Fl V | Fl -version -.Op Fl X | Fl -discard-locals -.Ar -.Sh DESCRIPTION -The -.Nm -utility is used to discard information from ELF objects. -.Pp -The -.Nm -utility supports the following options: -.Bl -tag -width indent -.It Fl d | Fl g | Fl S | Fl -strip-debug -Remove debugging symbols only. -.It Fl h | Fl -help -Print a help message and exit. -.It Fl -only-keep-debug -Remove all content except that which would be used for debugging. -.It Fl o Ar outputfile | Fl -output-file= Ns Ar outputfile -Write the stripped object to file -.Ar outputfile . -The default behaviour is to modify objects in place. -.It Fl p | Fl -preserve-dates -Preserve the object's access and modification times. -.It Fl s | Fl -strip-all -Remove all symbols. -.It Fl -strip-unneeded -Remove all symbols not needed for further relocation processing. -.It Fl w | Fl -wildcard -Use shell-style patterns to name symbols. -The following meta-characters are recognized in patterns: -.Bl -tag -width "...." -compact -.It Li ! -If this is the first character of the pattern, invert the sense of the -pattern match. -.It Li * -Matches any string of characters in a symbol name. -.It Li ? -Matches zero or one character in a symbol name. -.It Li [ -Mark the start of a character class. -.It Li \e -Remove the special meaning of the next character in the pattern. -.It Li ] -Mark the end of a character class. -.El -.It Fl x | Fl -discard-all -Discard all non-global symbols. -.It Fl I Ar format | Fl -input-target= Ns Ar format -These options are accepted, but are ignored. -.It Fl K Ar symbol | Fl -keep-symbol= Ns Ar symbol -Keep the symbol -.Ar symbol -even if it would otherwise be stripped. -This option may be specified multiple times. -.It Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbol -Remove the symbol -.Ar symbol -even if it would otherwise have been kept. -This option may be specified multiple times. -.It Fl O Ar format | Fl -output-target= Ns Ar format -Set the output file format to -.Ar format . -For the full list of supported formats, please see the documentation -for function -.Xr elftc_bfd_find_target 3 . -.It Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname -Remove the section named by the argument -.Ar sectionname . -This option may be specified multiple times. -.It Fl V | Fl -version -Print a version identifier and exit. -.It Fl X | Fl -discard-locals -Remove compiler-generated local symbols. -.El -.Sh DIAGNOSTICS -.Ex -std -.Sh SEE ALSO -.Xr ar 1 , -.Xr elfcopy 1 , -.Xr ld 1 , -.Xr mcs 1 , -.Xr elf 3 , -.Xr elftc_bfd_find_target 3 , -.Xr fnmatch 3 diff --git a/contrib/elftoolchain/elfcopy/symbols.c b/contrib/elftoolchain/elfcopy/symbols.c deleted file mode 100644 index 4a7d38a10812..000000000000 --- a/contrib/elftoolchain/elfcopy/symbols.c +++ /dev/null @@ -1,1097 +0,0 @@ -/*- - * Copyright (c) 2007-2013 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 <err.h> -#include <fnmatch.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "elfcopy.h" - -ELFTC_VCSID("$Id: symbols.c 3191 2015-05-04 17:07:01Z jkoshy $"); - -/* Symbol table buffer structure. */ -struct symbuf { - Elf32_Sym *l32; /* 32bit local symbol */ - Elf32_Sym *g32; /* 32bit global symbol */ - Elf64_Sym *l64; /* 64bit local symbol */ - Elf64_Sym *g64; /* 64bit global symbol */ - size_t ngs, nls; /* number of each kind */ - size_t gcap, lcap; /* buffer capacities. */ -}; - -struct sthash { - LIST_ENTRY(sthash) sh_next; - size_t sh_off; -}; -typedef LIST_HEAD(,sthash) hash_head; -#define STHASHSIZE 65536 - -struct strimpl { - char *buf; /* string table */ - size_t sz; /* entries */ - size_t cap; /* buffer capacity */ - hash_head hash[STHASHSIZE]; -}; - - -/* String table buffer structure. */ -struct strbuf { - struct strimpl l; /* local symbols */ - struct strimpl g; /* global symbols */ -}; - -static int is_debug_symbol(unsigned char st_info); -static int is_global_symbol(unsigned char st_info); -static int is_local_symbol(unsigned char st_info); -static int is_local_label(const char *name); -static int is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s); -static int is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, - GElf_Sym *s, const char *name); -static int is_weak_symbol(unsigned char st_info); -static int lookup_exact_string(hash_head *hash, const char *buf, - const char *s); -static int generate_symbols(struct elfcopy *ecp); -static void mark_symbols(struct elfcopy *ecp, size_t sc); -static int match_wildcard(const char *name, const char *pattern); -uint32_t str_hash(const char *s); - -/* Convenient bit vector operation macros. */ -#define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7)) -#define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7))) -#define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7))) - -static int -is_debug_symbol(unsigned char st_info) -{ - - if (GELF_ST_TYPE(st_info) == STT_SECTION || - GELF_ST_TYPE(st_info) == STT_FILE) - return (1); - - return (0); -} - -static int -is_global_symbol(unsigned char st_info) -{ - - if (GELF_ST_BIND(st_info) == STB_GLOBAL) - return (1); - - return (0); -} - -static int -is_weak_symbol(unsigned char st_info) -{ - - if (GELF_ST_BIND(st_info) == STB_WEAK) - return (1); - - return (0); -} - -static int -is_local_symbol(unsigned char st_info) -{ - - if (GELF_ST_BIND(st_info) == STB_LOCAL) - return (1); - - return (0); -} - -static int -is_hidden_symbol(unsigned char st_other) -{ - - if (GELF_ST_VISIBILITY(st_other) == STV_HIDDEN || - GELF_ST_VISIBILITY(st_other) == STV_INTERNAL) - return (1); - - return (0); -} - -static int -is_local_label(const char *name) -{ - - /* Compiler generated local symbols that start with .L */ - if (name[0] == '.' && name[1] == 'L') - return (1); - - return (0); -} - -/* - * Symbols related to relocation are needed. - */ -static int -is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s) -{ - - /* If symbol involves relocation, it is needed. */ - if (BIT_ISSET(ecp->v_rel, i)) - return (1); - - /* - * For relocatable files (.o files), global and weak symbols - * are needed. - */ - if (ecp->flags & RELOCATABLE) { - if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info)) - return (1); - } - - return (0); -} - -static int -is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, - const char *name) -{ - GElf_Sym sym0 = { - 0, /* st_name */ - 0, /* st_value */ - 0, /* st_size */ - 0, /* st_info */ - 0, /* st_other */ - SHN_UNDEF, /* st_shndx */ - }; - - if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) - return (0); - - if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) - return (1); - - /* - * Keep the first symbol if it is the special reserved symbol. - * XXX Should we generate one if it's missing? - */ - if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym))) - return (0); - - /* Remove the symbol if the section it refers to was removed. */ - if (s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE && - ecp->secndx[s->st_shndx] == 0) - return (1); - - if (ecp->strip == STRIP_ALL) - return (1); - - if (ecp->v_rel == NULL) - mark_symbols(ecp, sc); - - if (is_needed_symbol(ecp, i, s)) - return (0); - - if (ecp->strip == STRIP_UNNEEDED) - return (1); - - if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) && - !is_debug_symbol(s->st_info)) - return (1); - - if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) && - !is_debug_symbol(s->st_info) && is_local_label(name)) - return (1); - - if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info)) - return (1); - - return (0); -} - -/* - * Mark symbols refered by relocation entries. - */ -static void -mark_symbols(struct elfcopy *ecp, size_t sc) -{ - const char *name; - Elf_Data *d; - Elf_Scn *s; - GElf_Rel r; - GElf_Rela ra; - GElf_Shdr sh; - size_t n, indx; - int elferr, i, len; - - ecp->v_rel = calloc((sc + 7) / 8, 1); - if (ecp->v_rel == NULL) - err(EXIT_FAILURE, "calloc failed"); - - if (elf_getshstrndx(ecp->ein, &indx) == 0) - errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", - elf_errmsg(-1)); - - s = NULL; - while ((s = elf_nextscn(ecp->ein, s)) != NULL) { - if (gelf_getshdr(s, &sh) != &sh) - errx(EXIT_FAILURE, "elf_getshdr failed: %s", - elf_errmsg(-1)); - - if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA) - continue; - - /* - * Skip if this reloc section won't appear in the - * output object. - */ - if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL) - errx(EXIT_FAILURE, "elf_strptr failed: %s", - elf_errmsg(-1)); - if (is_remove_section(ecp, name) || - is_remove_reloc_sec(ecp, sh.sh_info)) - continue; - - /* Skip if it's not for .symtab */ - if (sh.sh_link != elf_ndxscn(ecp->symtab->is)) - continue; - - d = NULL; - n = 0; - while (n < sh.sh_size && (d = elf_getdata(s, d)) != NULL) { - len = d->d_size / sh.sh_entsize; - for (i = 0; i < len; i++) { - if (sh.sh_type == SHT_REL) { - if (gelf_getrel(d, i, &r) != &r) - errx(EXIT_FAILURE, - "elf_getrel failed: %s", - elf_errmsg(-1)); - n = GELF_R_SYM(r.r_info); - } else { - if (gelf_getrela(d, i, &ra) != &ra) - errx(EXIT_FAILURE, - "elf_getrela failed: %s", - elf_errmsg(-1)); - n = GELF_R_SYM(ra.r_info); - } - if (n > 0 && n < sc) - BIT_SET(ecp->v_rel, n); - else if (n != 0) - warnx("invalid symbox index"); - } - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_getdata failed: %s", - elf_errmsg(elferr)); - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_nextscn failed: %s", - elf_errmsg(elferr)); -} - -static int -generate_symbols(struct elfcopy *ecp) -{ - struct section *s; - struct symop *sp; - struct symbuf *sy_buf; - struct strbuf *st_buf; - const char *name; - char *newname; - unsigned char *gsym; - GElf_Shdr ish; - GElf_Sym sym; - Elf_Data* id; - Elf_Scn *is; - size_t ishstrndx, namelen, ndx, sc, symndx; - int ec, elferr, i; - - if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0) - errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", - elf_errmsg(-1)); - if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE) - errx(EXIT_FAILURE, "gelf_getclass failed: %s", - elf_errmsg(-1)); - - /* Create buffers for .symtab and .strtab. */ - if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - sy_buf->gcap = sy_buf->lcap = 64; - st_buf->g.cap = 256; - st_buf->l.cap = 64; - st_buf->l.sz = 1; /* '\0' at start. */ - st_buf->g.sz = 0; - - ecp->symtab->sz = 0; - ecp->strtab->sz = 0; - ecp->symtab->buf = sy_buf; - ecp->strtab->buf = st_buf; - - /* - * Create bit vector v_secsym, which is used to mark sections - * that already have corresponding STT_SECTION symbols. - */ - ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1); - if (ecp->v_secsym == NULL) - err(EXIT_FAILURE, "calloc failed"); - - /* Locate .strtab of input object. */ - symndx = 0; - name = NULL; - is = NULL; - while ((is = elf_nextscn(ecp->ein, is)) != NULL) { - if (gelf_getshdr(is, &ish) != &ish) - errx(EXIT_FAILURE, "elf_getshdr failed: %s", - elf_errmsg(-1)); - if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) == - NULL) - errx(EXIT_FAILURE, "elf_strptr failed: %s", - elf_errmsg(-1)); - if (strcmp(name, ".strtab") == 0) { - symndx = elf_ndxscn(is); - break; - } - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_nextscn failed: %s", - elf_errmsg(elferr)); - - /* Symbol table should exist if this function is called. */ - if (symndx == 0) { - warnx("can't find .strtab section"); - return (0); - } - - /* Locate .symtab of input object. */ - is = NULL; - while ((is = elf_nextscn(ecp->ein, is)) != NULL) { - if (gelf_getshdr(is, &ish) != &ish) - errx(EXIT_FAILURE, "elf_getshdr failed: %s", - elf_errmsg(-1)); - if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) == - NULL) - errx(EXIT_FAILURE, "elf_strptr failed: %s", - elf_errmsg(-1)); - if (strcmp(name, ".symtab") == 0) - break; - } - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_nextscn failed: %s", - elf_errmsg(elferr)); - if (is == NULL) - errx(EXIT_FAILURE, "can't find .strtab section"); - - /* - * Create bit vector gsym to mark global symbols, and symndx - * to keep track of symbol index changes from input object to - * output object, it is used by update_reloc() later to update - * relocation information. - */ - gsym = NULL; - sc = ish.sh_size / ish.sh_entsize; - if (sc > 0) { - ecp->symndx = calloc(sc, sizeof(*ecp->symndx)); - if (ecp->symndx == NULL) - err(EXIT_FAILURE, "calloc failed"); - gsym = calloc((sc + 7) / 8, sizeof(*gsym)); - if (gsym == NULL) - err(EXIT_FAILURE, "calloc failed"); - if ((id = elf_getdata(is, NULL)) == NULL) { - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_getdata failed: %s", - elf_errmsg(elferr)); - return (0); - } - } else - return (0); - - /* Copy/Filter each symbol. */ - for (i = 0; (size_t)i < sc; i++) { - if (gelf_getsym(id, i, &sym) != &sym) - errx(EXIT_FAILURE, "gelf_getsym failed: %s", - elf_errmsg(-1)); - if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL) - errx(EXIT_FAILURE, "elf_strptr failed: %s", - elf_errmsg(-1)); - - /* Symbol filtering. */ - if (is_remove_symbol(ecp, sc, i, &sym, name) != 0) - continue; - - /* Check if we need to change the binding of this symbol. */ - if (is_global_symbol(sym.st_info) || - is_weak_symbol(sym.st_info)) { - /* - * XXX Binutils objcopy does not weaken certain - * symbols. - */ - if (ecp->flags & WEAKEN_ALL || - lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL) - sym.st_info = GELF_ST_INFO(STB_WEAK, - GELF_ST_TYPE(sym.st_info)); - /* Do not localize undefined symbols. */ - if (sym.st_shndx != SHN_UNDEF && - lookup_symop_list(ecp, name, SYMOP_LOCALIZE) != - NULL) - sym.st_info = GELF_ST_INFO(STB_LOCAL, - GELF_ST_TYPE(sym.st_info)); - if (ecp->flags & KEEP_GLOBAL && - sym.st_shndx != SHN_UNDEF && - lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL) - sym.st_info = GELF_ST_INFO(STB_LOCAL, - GELF_ST_TYPE(sym.st_info)); - if (ecp->flags & LOCALIZE_HIDDEN && - sym.st_shndx != SHN_UNDEF && - is_hidden_symbol(sym.st_other)) - sym.st_info = GELF_ST_INFO(STB_LOCAL, - GELF_ST_TYPE(sym.st_info)); - } else { - /* STB_LOCAL binding. */ - if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) != - NULL) - sym.st_info = GELF_ST_INFO(STB_GLOBAL, - GELF_ST_TYPE(sym.st_info)); - /* XXX We should globalize weak symbol? */ - } - - /* Check if we need to rename this symbol. */ - if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL) - name = sp->newname; - - /* Check if we need to prefix the symbols. */ - newname = NULL; - if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') { - namelen = strlen(name) + strlen(ecp->prefix_sym) + 1; - if ((newname = malloc(namelen)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - snprintf(newname, namelen, "%s%s", ecp->prefix_sym, - name); - name = newname; - } - - /* Copy symbol, mark global/weak symbol and add to index map. */ - if (is_global_symbol(sym.st_info) || - is_weak_symbol(sym.st_info)) { - BIT_SET(gsym, i); - ecp->symndx[i] = sy_buf->ngs; - } else - ecp->symndx[i] = sy_buf->nls; - add_to_symtab(ecp, name, sym.st_value, sym.st_size, - sym.st_shndx, sym.st_info, sym.st_other, 0); - - if (newname != NULL) - free(newname); - - /* - * If the symbol is a STT_SECTION symbol, mark the section - * it points to. - */ - if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) - BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]); - } - - /* - * Give up if there is no real symbols inside the table. - * XXX The logic here needs to be improved. We need to - * check if that only local symbol is the reserved symbol. - */ - if (sy_buf->nls <= 1 && sy_buf->ngs == 0) - return (0); - - /* - * Create STT_SECTION symbols for sections that do not already - * got one. However, we do not create STT_SECTION symbol for - * .symtab, .strtab, .shstrtab and reloc sec of relocatables. - */ - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (s->pseudo) - continue; - if (strcmp(s->name, ".symtab") == 0 || - strcmp(s->name, ".strtab") == 0 || - strcmp(s->name, ".shstrtab") == 0) - continue; - if ((ecp->flags & RELOCATABLE) != 0 && - ((s->type == SHT_REL) || (s->type == SHT_RELA))) - continue; - - if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) - errx(EXIT_FAILURE, "elf_ndxscn failed: %s", - elf_errmsg(-1)); - - if (!BIT_ISSET(ecp->v_secsym, ndx)) { - sym.st_name = 0; - sym.st_value = s->vma; - sym.st_size = 0; - sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); - /* - * Don't let add_to_symtab() touch sym.st_shndx. - * In this case, we know the index already. - */ - add_to_symtab(ecp, NULL, sym.st_value, sym.st_size, - ndx, sym.st_info, sym.st_other, 1); - } - } - - /* - * Update st_name and index map for global/weak symbols. Note that - * global/weak symbols are put after local symbols. - */ - if (gsym != NULL) { - for(i = 0; (size_t) i < sc; i++) { - if (!BIT_ISSET(gsym, i)) - continue; - - /* Update st_name. */ - if (ec == ELFCLASS32) - sy_buf->g32[ecp->symndx[i]].st_name += - st_buf->l.sz; - else - sy_buf->g64[ecp->symndx[i]].st_name += - st_buf->l.sz; - - /* Update index map. */ - ecp->symndx[i] += sy_buf->nls; - } - free(gsym); - } - - return (1); -} - -void -create_symtab(struct elfcopy *ecp) -{ - struct section *s, *sy, *st; - size_t maxndx, ndx; - - sy = ecp->symtab; - st = ecp->strtab; - - /* - * Set section index map for .symtab and .strtab. We need to set - * these map because otherwise symbols which refer to .symtab and - * .strtab will be removed by symbol filtering unconditionally. - * And we have to figure out scn index this way (instead of calling - * elf_ndxscn) because we can not create Elf_Scn before we're certain - * that .symtab and .strtab will exist in the output object. - */ - maxndx = 0; - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (s->os == NULL) - continue; - if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) - errx(EXIT_FAILURE, "elf_ndxscn failed: %s", - elf_errmsg(-1)); - if (ndx > maxndx) - maxndx = ndx; - } - ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1; - ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2; - - /* - * Generate symbols for output object if SYMTAB_INTACT is not set. - * If there is no symbol in the input object or all the symbols are - * stripped, then free all the resouces allotted for symbol table, - * and clear SYMTAB_EXIST flag. - */ - if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) { - TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list); - TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list); - free(ecp->symtab); - free(ecp->strtab); - ecp->symtab = NULL; - ecp->strtab = NULL; - ecp->flags &= ~SYMTAB_EXIST; - return; - } - - /* Create output Elf_Scn for .symtab and .strtab. */ - if ((sy->os = elf_newscn(ecp->eout)) == NULL || - (st->os = elf_newscn(ecp->eout)) == NULL) - errx(EXIT_FAILURE, "elf_newscn failed: %s", - elf_errmsg(-1)); - /* Update secndx anyway. */ - ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os); - ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os); - - /* - * Copy .symtab and .strtab section headers from input to output - * object to start with, these will be overridden later if need. - */ - copy_shdr(ecp, sy, ".symtab", 1, 0); - copy_shdr(ecp, st, ".strtab", 1, 0); - - /* Copy verbatim if symbol table is intact. */ - if (ecp->flags & SYMTAB_INTACT) { - copy_data(sy); - copy_data(st); - return; - } - - create_symtab_data(ecp); -} - -void -free_symtab(struct elfcopy *ecp) -{ - struct symbuf *sy_buf; - struct strbuf *st_buf; - struct sthash *sh, *shtmp; - int i; - - if (ecp->symtab != NULL && ecp->symtab->buf != NULL) { - sy_buf = ecp->symtab->buf; - if (sy_buf->l32 != NULL) - free(sy_buf->l32); - if (sy_buf->g32 != NULL) - free(sy_buf->g32); - if (sy_buf->l64 != NULL) - free(sy_buf->l64); - if (sy_buf->g64 != NULL) - free(sy_buf->g64); - } - - if (ecp->strtab != NULL && ecp->strtab->buf != NULL) { - st_buf = ecp->strtab->buf; - if (st_buf->l.buf != NULL) - free(st_buf->l.buf); - if (st_buf->g.buf != NULL) - free(st_buf->g.buf); - for (i = 0; i < STHASHSIZE; i++) { - LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next, - shtmp) { - LIST_REMOVE(sh, sh_next); - free(sh); - } - LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next, - shtmp) { - LIST_REMOVE(sh, sh_next); - free(sh); - } - } - } -} - -void -create_external_symtab(struct elfcopy *ecp) -{ - struct section *s; - struct symbuf *sy_buf; - struct strbuf *st_buf; - GElf_Shdr sh; - size_t ndx; - - if (ecp->oec == ELFCLASS32) - ecp->symtab = create_external_section(ecp, ".symtab", NULL, - NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0); - else - ecp->symtab = create_external_section(ecp, ".symtab", NULL, - NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0); - - ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0, - SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0); - - /* Let sh_link field of .symtab section point to .strtab section. */ - if (gelf_getshdr(ecp->symtab->os, &sh) == NULL) - errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", - elf_errmsg(-1)); - sh.sh_link = elf_ndxscn(ecp->strtab->os); - if (!gelf_update_shdr(ecp->symtab->os, &sh)) - errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", - elf_errmsg(-1)); - - /* Create buffers for .symtab and .strtab. */ - if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL) - err(EXIT_FAILURE, "calloc failed"); - sy_buf->gcap = sy_buf->lcap = 64; - st_buf->g.cap = 256; - st_buf->l.cap = 64; - st_buf->l.sz = 1; /* '\0' at start. */ - st_buf->g.sz = 0; - - ecp->symtab->sz = 0; - ecp->strtab->sz = 0; - ecp->symtab->buf = sy_buf; - ecp->strtab->buf = st_buf; - - /* Always create the special symbol at the symtab beginning. */ - add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF, - ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1); - - /* Create STT_SECTION symbols. */ - TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - if (s->pseudo) - continue; - if (strcmp(s->name, ".symtab") == 0 || - strcmp(s->name, ".strtab") == 0 || - strcmp(s->name, ".shstrtab") == 0) - continue; - (void) elf_errno(); - if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) { - warnx("elf_ndxscn failed: %s", - elf_errmsg(-1)); - continue; - } - add_to_symtab(ecp, NULL, 0, 0, ndx, - GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1); - } -} - -void -add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value, - uint64_t st_size, uint16_t st_shndx, unsigned char st_info, - unsigned char st_other, int ndx_known) -{ - struct symbuf *sy_buf; - struct strbuf *st_buf; - struct sthash *sh; - uint32_t hash; - int pos; - - /* - * Convenient macro for copying global/local 32/64 bit symbols - * from input object to the buffer created for output object. - * It handles buffer growing, st_name calculating and st_shndx - * updating for symbols with non-special section index. - */ -#define _ADDSYM(B, SZ) do { \ - if (sy_buf->B##SZ == NULL) { \ - sy_buf->B##SZ = malloc(sy_buf->B##cap * \ - sizeof(Elf##SZ##_Sym)); \ - if (sy_buf->B##SZ == NULL) \ - err(EXIT_FAILURE, "malloc failed"); \ - } else if (sy_buf->n##B##s >= sy_buf->B##cap) { \ - sy_buf->B##cap *= 2; \ - sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap * \ - sizeof(Elf##SZ##_Sym)); \ - if (sy_buf->B##SZ == NULL) \ - err(EXIT_FAILURE, "realloc failed"); \ - } \ - sy_buf->B##SZ[sy_buf->n##B##s].st_info = st_info; \ - sy_buf->B##SZ[sy_buf->n##B##s].st_other = st_other; \ - sy_buf->B##SZ[sy_buf->n##B##s].st_value = st_value; \ - sy_buf->B##SZ[sy_buf->n##B##s].st_size = st_size; \ - if (ndx_known) \ - sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \ - else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE) \ - sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \ - else \ - sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = \ - ecp->secndx[st_shndx]; \ - if (st_buf->B.buf == NULL) { \ - st_buf->B.buf = calloc(st_buf->B.cap, \ - sizeof(*st_buf->B.buf)); \ - if (st_buf->B.buf == NULL) \ - err(EXIT_FAILURE, "malloc failed"); \ - } \ - if (name != NULL && *name != '\0') { \ - pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\ - name); \ - if (pos != -1) \ - sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos; \ - else { \ - sy_buf->B##SZ[sy_buf->n##B##s].st_name = \ - st_buf->B.sz; \ - while (st_buf->B.sz + strlen(name) >= \ - st_buf->B.cap - 1) { \ - st_buf->B.cap *= 2; \ - st_buf->B.buf = realloc(st_buf->B.buf, \ - st_buf->B.cap); \ - if (st_buf->B.buf == NULL) \ - err(EXIT_FAILURE, \ - "realloc failed"); \ - } \ - if ((sh = malloc(sizeof(*sh))) == NULL) \ - err(EXIT_FAILURE, "malloc failed"); \ - sh->sh_off = st_buf->B.sz; \ - hash = str_hash(name); \ - LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh, \ - sh_next); \ - strncpy(&st_buf->B.buf[st_buf->B.sz], name, \ - strlen(name)); \ - st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \ - st_buf->B.sz += strlen(name) + 1; \ - } \ - } else \ - sy_buf->B##SZ[sy_buf->n##B##s].st_name = 0; \ - sy_buf->n##B##s++; \ -} while (0) - - sy_buf = ecp->symtab->buf; - st_buf = ecp->strtab->buf; - - if (ecp->oec == ELFCLASS32) { - if (is_local_symbol(st_info)) - _ADDSYM(l, 32); - else - _ADDSYM(g, 32); - } else { - if (is_local_symbol(st_info)) - _ADDSYM(l, 64); - else - _ADDSYM(g, 64); - } - - /* Update section size. */ - ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) * - (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)); - ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz; - -#undef _ADDSYM -} - -void -finalize_external_symtab(struct elfcopy *ecp) -{ - struct symbuf *sy_buf; - struct strbuf *st_buf; - int i; - - /* - * Update st_name for global/weak symbols. (global/weak symbols - * are put after local symbols) - */ - sy_buf = ecp->symtab->buf; - st_buf = ecp->strtab->buf; - for (i = 0; (size_t) i < sy_buf->ngs; i++) { - if (ecp->oec == ELFCLASS32) - sy_buf->g32[i].st_name += st_buf->l.sz; - else - sy_buf->g64[i].st_name += st_buf->l.sz; - } -} - -void -create_symtab_data(struct elfcopy *ecp) -{ - struct section *sy, *st; - struct symbuf *sy_buf; - struct strbuf *st_buf; - Elf_Data *gsydata, *lsydata, *gstdata, *lstdata; - GElf_Shdr shy, sht; - - sy = ecp->symtab; - st = ecp->strtab; - - if (gelf_getshdr(sy->os, ­) == NULL) - errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", - elf_errmsg(-1)); - if (gelf_getshdr(st->os, &sht) == NULL) - errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", - elf_errmsg(-1)); - - /* - * Create two Elf_Data for .symtab section of output object, one - * for local symbols and another for global symbols. Note that - * local symbols appear first in the .symtab. - */ - sy_buf = sy->buf; - if (sy_buf->nls > 0) { - if ((lsydata = elf_newdata(sy->os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s.", - elf_errmsg(-1)); - if (ecp->oec == ELFCLASS32) { - lsydata->d_align = 4; - lsydata->d_off = 0; - lsydata->d_buf = sy_buf->l32; - lsydata->d_size = sy_buf->nls * - sizeof(Elf32_Sym); - lsydata->d_type = ELF_T_SYM; - lsydata->d_version = EV_CURRENT; - } else { - lsydata->d_align = 8; - lsydata->d_off = 0; - lsydata->d_buf = sy_buf->l64; - lsydata->d_size = sy_buf->nls * - sizeof(Elf64_Sym); - lsydata->d_type = ELF_T_SYM; - lsydata->d_version = EV_CURRENT; - } - } - if (sy_buf->ngs > 0) { - if ((gsydata = elf_newdata(sy->os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s.", - elf_errmsg(-1)); - if (ecp->oec == ELFCLASS32) { - gsydata->d_align = 4; - gsydata->d_off = sy_buf->nls * - sizeof(Elf32_Sym); - gsydata->d_buf = sy_buf->g32; - gsydata->d_size = sy_buf->ngs * - sizeof(Elf32_Sym); - gsydata->d_type = ELF_T_SYM; - gsydata->d_version = EV_CURRENT; - } else { - gsydata->d_align = 8; - gsydata->d_off = sy_buf->nls * - sizeof(Elf64_Sym); - gsydata->d_buf = sy_buf->g64; - gsydata->d_size = sy_buf->ngs * - sizeof(Elf64_Sym); - gsydata->d_type = ELF_T_SYM; - gsydata->d_version = EV_CURRENT; - } - } - - /* - * Create two Elf_Data for .strtab, one for local symbol name - * and another for globals. Same as .symtab, local symbol names - * appear first. - */ - st_buf = st->buf; - if ((lstdata = elf_newdata(st->os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s.", - elf_errmsg(-1)); - lstdata->d_align = 1; - lstdata->d_off = 0; - lstdata->d_buf = st_buf->l.buf; - lstdata->d_size = st_buf->l.sz; - lstdata->d_type = ELF_T_BYTE; - lstdata->d_version = EV_CURRENT; - - if (st_buf->g.sz > 0) { - if ((gstdata = elf_newdata(st->os)) == NULL) - errx(EXIT_FAILURE, "elf_newdata() failed: %s.", - elf_errmsg(-1)); - gstdata->d_align = 1; - gstdata->d_off = lstdata->d_size; - gstdata->d_buf = st_buf->g.buf; - gstdata->d_size = st_buf->g.sz; - gstdata->d_type = ELF_T_BYTE; - gstdata->d_version = EV_CURRENT; - } - - shy.sh_addr = 0; - shy.sh_addralign = (ecp->oec == ELFCLASS32 ? 4 : 8); - shy.sh_size = sy->sz; - shy.sh_type = SHT_SYMTAB; - shy.sh_flags = 0; - shy.sh_entsize = gelf_fsize(ecp->eout, ELF_T_SYM, 1, - EV_CURRENT); - /* - * According to SYSV abi, here sh_info is one greater than - * the symbol table index of the last local symbol(binding - * STB_LOCAL). - */ - shy.sh_info = sy_buf->nls; - - sht.sh_addr = 0; - sht.sh_addralign = 1; - sht.sh_size = st->sz; - sht.sh_type = SHT_STRTAB; - sht.sh_flags = 0; - sht.sh_entsize = 0; - sht.sh_info = 0; - sht.sh_link = 0; - - if (!gelf_update_shdr(sy->os, ­)) - errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", - elf_errmsg(-1)); - if (!gelf_update_shdr(st->os, &sht)) - errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", - elf_errmsg(-1)); -} - -void -add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname, - unsigned int op) -{ - struct symop *s; - - if ((s = lookup_symop_list(ecp, name, ~0U)) == NULL) { - if ((s = calloc(1, sizeof(*s))) == NULL) - errx(EXIT_FAILURE, "not enough memory"); - s->name = name; - if (op == SYMOP_REDEF) - s->newname = newname; - } - - s->op |= op; - STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list); -} - -static int -match_wildcard(const char *name, const char *pattern) -{ - int reverse, match; - - reverse = 0; - if (*pattern == '!') { - reverse = 1; - pattern++; - } - - match = 0; - if (!fnmatch(pattern, name, 0)) - match = 1; - - return (reverse ? !match : match); -} - -struct symop * -lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op) -{ - struct symop *s; - - STAILQ_FOREACH(s, &ecp->v_symop, symop_list) { - if (name == NULL || !strcmp(name, s->name) || - ((ecp->flags & WILDCARD) && match_wildcard(name, s->name))) - if ((s->op & op) != 0) - return (s); - } - - return (NULL); -} - -static int -lookup_exact_string(hash_head *buckets, const char *buf, const char *s) -{ - struct sthash *sh; - uint32_t hash; - - hash = str_hash(s); - LIST_FOREACH(sh, &buckets[hash], sh_next) - if (strcmp(buf + sh->sh_off, s) == 0) - return sh->sh_off; - return (-1); -} - -uint32_t -str_hash(const char *s) -{ - uint32_t hash; - - for (hash = 2166136261UL; *s; s++) - hash = (hash ^ *s) * 16777619; - - return (hash & (STHASHSIZE - 1)); -} |