X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Felfedit.c;h=ea261de4244183fb6291679d996c745798bdc29a;hb=6ae978f133a67d34d01b6bb2053f1ba20ad13eeb;hp=1805ec1b5e91c4a78c4e79ca2cc7d6079ac2bd2a;hpb=3284fe0c5e852fb8a3a06630c161b9633b9f6682;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/elfedit.c b/binutils/elfedit.c index 1805ec1b5e..ea261de424 100644 --- a/binutils/elfedit.c +++ b/binutils/elfedit.c @@ -1,6 +1,5 @@ /* elfedit.c -- Update the ELF header of an ELF format file - Copyright 2010 - Free Software Foundation, Inc. + Copyright (C) 2010-2019 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -22,7 +21,6 @@ #include "config.h" #include "sysdep.h" #include -#include #if __GNUC__ >= 2 /* Define BFD64 here, even if our default architecture is 32 bit ELF @@ -57,24 +55,254 @@ static int input_elf_type = -1; static int output_elf_type = -1; static int input_elf_osabi = -1; static int output_elf_osabi = -1; -static int input_elf_class = -1; +enum elfclass + { + ELF_CLASS_UNKNOWN = -1, + ELF_CLASS_NONE = ELFCLASSNONE, + ELF_CLASS_32 = ELFCLASS32, + ELF_CLASS_64 = ELFCLASS64, + ELF_CLASS_BOTH + }; +static enum elfclass input_elf_class = ELF_CLASS_UNKNOWN; +static enum elfclass output_elf_class = ELF_CLASS_BOTH; + +#ifdef HAVE_MMAP +#include + +static unsigned int enable_x86_features; +static unsigned int disable_x86_features; static int -update_elf_header (const char *file_name, FILE *file) +update_gnu_property (const char *file_name, FILE *file) { - int class, machine, type, status, osabi; + char *map; + Elf_Internal_Phdr *phdrs; + struct stat st_buf; + unsigned int i; + int ret; - if (elf_header.e_ident[EI_MAG0] != ELFMAG0 - || elf_header.e_ident[EI_MAG1] != ELFMAG1 - || elf_header.e_ident[EI_MAG2] != ELFMAG2 - || elf_header.e_ident[EI_MAG3] != ELFMAG3) + if (!enable_x86_features && !disable_x86_features) + return 0; + + if (elf_header.e_machine != EM_386 + && elf_header.e_machine != EM_X86_64) { - error - (_("%s: Not an ELF file - wrong magic bytes at the start\n"), - file_name); + error (_("%s: Not an i386 nor x86-64 ELF file\n"), file_name); return 0; } + if (fstat (fileno (file), &st_buf) < 0) + { + error (_("%s: stat () failed\n"), file_name); + return 1; + } + + map = mmap (NULL, st_buf.st_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fileno (file), 0); + if (map == MAP_FAILED) + { + error (_("%s: mmap () failed\n"), file_name); + return 0; + } + + phdrs = xmalloc (elf_header.e_phnum * sizeof (*phdrs)); + + if (elf_header.e_ident[EI_CLASS] == ELFCLASS32) + { + Elf32_External_Phdr *phdrs32 + = (Elf32_External_Phdr *) (map + elf_header.e_phoff); + for (i = 0; i < elf_header.e_phnum; i++) + { + phdrs[i].p_type = BYTE_GET (phdrs32[i].p_type); + phdrs[i].p_offset = BYTE_GET (phdrs32[i].p_offset); + phdrs[i].p_vaddr = BYTE_GET (phdrs32[i].p_vaddr); + phdrs[i].p_paddr = BYTE_GET (phdrs32[i].p_paddr); + phdrs[i].p_filesz = BYTE_GET (phdrs32[i].p_filesz); + phdrs[i].p_memsz = BYTE_GET (phdrs32[i].p_memsz); + phdrs[i].p_flags = BYTE_GET (phdrs32[i].p_flags); + phdrs[i].p_align = BYTE_GET (phdrs32[i].p_align); + } + } + else + { + Elf64_External_Phdr *phdrs64 + = (Elf64_External_Phdr *) (map + elf_header.e_phoff); + for (i = 0; i < elf_header.e_phnum; i++) + { + phdrs[i].p_type = BYTE_GET (phdrs64[i].p_type); + phdrs[i].p_offset = BYTE_GET (phdrs64[i].p_offset); + phdrs[i].p_vaddr = BYTE_GET (phdrs64[i].p_vaddr); + phdrs[i].p_paddr = BYTE_GET (phdrs64[i].p_paddr); + phdrs[i].p_filesz = BYTE_GET (phdrs64[i].p_filesz); + phdrs[i].p_memsz = BYTE_GET (phdrs64[i].p_memsz); + phdrs[i].p_flags = BYTE_GET (phdrs64[i].p_flags); + phdrs[i].p_align = BYTE_GET (phdrs64[i].p_align); + } + } + + ret = 0; + for (i = 0; i < elf_header.e_phnum; i++) + if (phdrs[i].p_type == PT_NOTE) + { + size_t offset = phdrs[i].p_offset; + size_t size = phdrs[i].p_filesz; + size_t align = phdrs[i].p_align; + char *buf = map + offset; + char *p = buf; + + while (p < buf + size) + { + Elf_External_Note *xnp = (Elf_External_Note *) p; + Elf_Internal_Note in; + + if (offsetof (Elf_External_Note, name) > buf - p + size) + { + ret = 1; + goto out; + } + + in.type = BYTE_GET (xnp->type); + in.namesz = BYTE_GET (xnp->namesz); + in.namedata = xnp->name; + if (in.namesz > buf - in.namedata + size) + { + ret = 1; + goto out; + } + + in.descsz = BYTE_GET (xnp->descsz); + in.descdata = p + ELF_NOTE_DESC_OFFSET (in.namesz, align); + in.descpos = offset + (in.descdata - buf); + if (in.descsz != 0 + && (in.descdata >= buf + size + || in.descsz > buf - in.descdata + size)) + { + ret = 1; + goto out; + } + + if (in.namesz == sizeof "GNU" + && strcmp (in.namedata, "GNU") == 0 + && in.type == NT_GNU_PROPERTY_TYPE_0) + { + unsigned char *ptr; + unsigned char *ptr_end; + + if (in.descsz < 8 || (in.descsz % align) != 0) + { + ret = 1; + goto out; + } + + ptr = (unsigned char *) in.descdata; + ptr_end = ptr + in.descsz; + + do + { + unsigned int type = byte_get (ptr, 4); + unsigned int datasz = byte_get (ptr + 4, 4); + unsigned int bitmask, old_bitmask; + + ptr += 8; + if ((ptr + datasz) > ptr_end) + { + ret = 1; + goto out; + } + + if (type == GNU_PROPERTY_X86_FEATURE_1_AND) + { + if (datasz != 4) + { + ret = 1; + goto out; + } + + old_bitmask = byte_get (ptr, 4); + bitmask = old_bitmask; + if (enable_x86_features) + bitmask |= enable_x86_features; + if (disable_x86_features) + bitmask &= ~disable_x86_features; + if (old_bitmask != bitmask) + BYTE_PUT (ptr, bitmask); + goto out; + } + + ptr += ELF_ALIGN_UP (datasz, align); + } + while ((ptr_end - ptr) >= 8); + } + + p += ELF_NOTE_NEXT_OFFSET (in.namesz, in.descsz, align); + } + } + +out: + if (ret != 0) + error (_("%s: Invalid PT_NOTE segment\n"), file_name); + + free (phdrs); + munmap (map, st_buf.st_size); + + return ret; +} + +/* Set enable_x86_features and disable_x86_features for a feature + string, FEATURE. */ + +static int +elf_x86_feature (const char *feature, int enable) +{ + unsigned int x86_feature; + if (strcasecmp (feature, "ibt") == 0) + x86_feature = GNU_PROPERTY_X86_FEATURE_1_IBT; + else if (strcasecmp (feature, "shstk") == 0) + x86_feature = GNU_PROPERTY_X86_FEATURE_1_SHSTK; + else + return -1; + + if (enable) + { + enable_x86_features |= x86_feature; + disable_x86_features &= ~x86_feature; + } + else + { + disable_x86_features |= x86_feature; + enable_x86_features &= ~x86_feature; + } + + return 0; +} +#endif + +/* Return ELF class for a machine type, MACH. */ + +static enum elfclass +elf_class (int mach) +{ + switch (mach) + { + case EM_386: + case EM_IAMCU: + return ELF_CLASS_32; + case EM_L1OM: + case EM_K1OM: + return ELF_CLASS_64; + case EM_X86_64: + case EM_NONE: + return ELF_CLASS_BOTH; + default: + return ELF_CLASS_BOTH; + } +} + +static int +update_elf_header (const char *file_name, FILE *file) +{ + int class, machine, type, status, osabi; + if (elf_header.e_ident[EI_VERSION] != EV_CURRENT) { error @@ -89,17 +317,29 @@ update_elf_header (const char *file_name, FILE *file) return 1; class = elf_header.e_ident[EI_CLASS]; + machine = elf_header.e_machine; /* Skip if class doesn't match. */ - if (input_elf_class != -1 && class != input_elf_class) + if (input_elf_class == ELF_CLASS_UNKNOWN) + input_elf_class = elf_class (machine); + + if (input_elf_class != ELF_CLASS_BOTH + && (int) input_elf_class != class) { error - (_("%s: Unmatched EI_CLASS: %d is not %d\n"), + (_("%s: Unmatched input EI_CLASS: %d is not %d\n"), file_name, class, input_elf_class); return 0; } - machine = elf_header.e_machine; + if (output_elf_class != ELF_CLASS_BOTH + && (int) output_elf_class != class) + { + error + (_("%s: Unmatched output EI_CLASS: %d is not %d\n"), + file_name, class, output_elf_class); + return 0; + } /* Skip if e_machine doesn't match. */ if (input_elf_machine != -1 && machine != input_elf_machine) @@ -173,6 +413,12 @@ get_file_header (FILE * file) if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1) return 0; + if (elf_header.e_ident[EI_MAG0] != ELFMAG0 + || elf_header.e_ident[EI_MAG1] != ELFMAG1 + || elf_header.e_ident[EI_MAG2] != ELFMAG2 + || elf_header.e_ident[EI_MAG3] != ELFMAG3) + return 0; + /* Determine how to read the rest of the header. */ switch (elf_header.e_ident[EI_DATA]) { @@ -193,8 +439,6 @@ get_file_header (FILE * file) switch (elf_header.e_ident[EI_CLASS]) { default: - error (_("Unsupported EI_CLASS: %d\n"), - elf_header.e_ident[EI_CLASS]); return 0; case ELFCLASS32: @@ -501,6 +745,12 @@ process_file (const char *file_name) rewind (file); archive_file_size = archive_file_offset = 0; ret = process_object (file_name, file); +#ifdef HAVE_MMAP + if (!ret + && (elf_header.e_type == ET_EXEC + || elf_header.e_type == ET_DYN)) + ret = update_gnu_property (file_name, file); +#endif } fclose (file); @@ -518,8 +768,8 @@ osabis[] = { ELFOSABI_NONE, "none" }, { ELFOSABI_HPUX, "HPUX" }, { ELFOSABI_NETBSD, "NetBSD" }, - { ELFOSABI_LINUX, "Linux" }, - { ELFOSABI_HURD, "Hurd" }, + { ELFOSABI_GNU, "GNU" }, + { ELFOSABI_GNU, "Linux" }, { ELFOSABI_SOLARIS, "Solaris" }, { ELFOSABI_AIX, "AIX" }, { ELFOSABI_IRIX, "Irix" }, @@ -554,8 +804,14 @@ elf_osabi (const char *osabi) static int elf_machine (const char *mach) { + if (strcasecmp (mach, "i386") == 0) + return EM_386; + if (strcasecmp (mach, "iamcu") == 0) + return EM_IAMCU; if (strcasecmp (mach, "l1om") == 0) return EM_L1OM; + if (strcasecmp (mach, "k1om") == 0) + return EM_K1OM; if (strcasecmp (mach, "x86_64") == 0) return EM_X86_64; if (strcasecmp (mach, "x86-64") == 0) @@ -568,24 +824,6 @@ elf_machine (const char *mach) return -1; } -/* Return ELF class for a machine type, MACH. */ - -static int -elf_class (int mach) -{ - switch (mach) - { - case EM_L1OM: - case EM_X86_64: - return ELFCLASS64; - case EM_NONE: - return ELFCLASSNONE; - default: - error (_("Unknown machine type: %d\n"), mach); - return -1; - } -} - /* Return ET_XXX for a type string, TYPE. */ static int @@ -612,7 +850,11 @@ enum command_line_switch OPTION_INPUT_TYPE, OPTION_OUTPUT_TYPE, OPTION_INPUT_OSABI, - OPTION_OUTPUT_OSABI + OPTION_OUTPUT_OSABI, +#ifdef HAVE_MMAP + OPTION_ENABLE_X86_FEATURE, + OPTION_DISABLE_X86_FEATURE, +#endif }; static struct option options[] = @@ -623,12 +865,18 @@ static struct option options[] = {"output-type", required_argument, 0, OPTION_OUTPUT_TYPE}, {"input-osabi", required_argument, 0, OPTION_INPUT_OSABI}, {"output-osabi", required_argument, 0, OPTION_OUTPUT_OSABI}, +#ifdef HAVE_MMAP + {"enable-x86-feature", + required_argument, 0, OPTION_ENABLE_X86_FEATURE}, + {"disable-x86-feature", + required_argument, 0, OPTION_DISABLE_X86_FEATURE}, +#endif {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {0, no_argument, 0, 0} }; -static void +ATTRIBUTE_NORETURN static void usage (FILE *stream, int exit_status) { fprintf (stream, _("Usage: %s elffile(s)\n"), @@ -641,7 +889,15 @@ usage (FILE *stream, int exit_status) --input-type Set input file type to \n\ --output-type Set output file type to \n\ --input-osabi Set input OSABI to \n\ - --output-osabi Set output OSABI to \n\ + --output-osabi Set output OSABI to \n")); +#ifdef HAVE_MMAP + fprintf (stream, _("\ + --enable-x86-feature \n\ + Enable x86 feature \n\ + --disable-x86-feature \n\ + Disable x86 feature \n")); +#endif + fprintf (stream, _("\ -h --help Display this information\n\ -v --version Display the version number of %s\n\ "), @@ -677,7 +933,7 @@ main (int argc, char ** argv) if (input_elf_machine < 0) return 1; input_elf_class = elf_class (input_elf_machine); - if (input_elf_class < 0) + if (input_elf_class == ELF_CLASS_UNKNOWN) return 1; break; @@ -685,6 +941,9 @@ main (int argc, char ** argv) output_elf_machine = elf_machine (optarg); if (output_elf_machine < 0) return 1; + output_elf_class = elf_class (output_elf_machine); + if (output_elf_class == ELF_CLASS_UNKNOWN) + return 1; break; case OPTION_INPUT_TYPE: @@ -711,6 +970,18 @@ main (int argc, char ** argv) return 1; break; +#ifdef HAVE_MMAP + case OPTION_ENABLE_X86_FEATURE: + if (elf_x86_feature (optarg, 1) < 0) + return 1; + break; + + case OPTION_DISABLE_X86_FEATURE: + if (elf_x86_feature (optarg, 0) < 0) + return 1; + break; +#endif + case 'h': usage (stdout, 0); @@ -725,6 +996,10 @@ main (int argc, char ** argv) if (optind == argc || (output_elf_machine == -1 +#ifdef HAVE_MMAP + && ! enable_x86_features + && ! disable_x86_features +#endif && output_elf_type == -1 && output_elf_osabi == -1)) usage (stderr, 1);