1 /*- 2 * Copyright (c) 2008 Hyogeol Lee 3 * Copyright (c) 2000, 2001 David O'Brien 4 * Copyright (c) 1996 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <err.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <gelf.h> 37 #include <getopt.h> 38 #include <libelf.h> 39 #include <libelftc.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include "_elftc.h" 46 47 ELFTC_VCSID("$Id: brandelf.c 3440 2016-04-07 14:51:47Z emaste $"); 48 49 /* Backwards compatability for older FreeBSD releases. */ 50 #ifndef ELFOSABI_CLOUDABI 51 #define ELFOSABI_CLOUDABI 17 52 #endif 53 54 static int elftype(const char *); 55 static const char *iselftype(int); 56 static void printelftypes(void); 57 static void printversion(void); 58 static void usage(void); 59 60 struct ELFtypes { 61 const char *str; 62 int value; 63 }; 64 /* XXX - any more types? */ 65 static struct ELFtypes elftypes[] = { 66 { "86Open", ELFOSABI_86OPEN }, 67 { "AIX", ELFOSABI_AIX }, 68 { "ARM", ELFOSABI_ARM }, 69 { "AROS", ELFOSABI_AROS }, 70 { "CloudABI", ELFOSABI_CLOUDABI }, 71 { "FreeBSD", ELFOSABI_FREEBSD }, 72 { "GNU", ELFOSABI_GNU }, 73 { "HP/UX", ELFOSABI_HPUX}, 74 { "Hurd", ELFOSABI_HURD }, 75 { "IRIX", ELFOSABI_IRIX }, 76 { "Linux", ELFOSABI_GNU }, 77 { "Modesto", ELFOSABI_MODESTO }, 78 { "NSK", ELFOSABI_NSK }, 79 { "NetBSD", ELFOSABI_NETBSD}, 80 { "None", ELFOSABI_NONE}, 81 { "OpenBSD", ELFOSABI_OPENBSD }, 82 { "OpenVMS", ELFOSABI_OPENVMS }, 83 { "Standalone", ELFOSABI_STANDALONE }, 84 { "SVR4", ELFOSABI_NONE }, 85 { "Solaris", ELFOSABI_SOLARIS }, 86 { "Tru64", ELFOSABI_TRU64 } 87 }; 88 89 static struct option brandelf_longopts[] = { 90 { "help", no_argument, NULL, 'h' }, 91 { "version", no_argument, NULL, 'V' }, 92 { NULL, 0, NULL, 0 } 93 }; 94 95 int 96 main(int argc, char **argv) 97 { 98 GElf_Ehdr ehdr; 99 Elf *elf; 100 Elf_Kind kind; 101 int type = ELFOSABI_NONE; 102 int retval = 0; 103 int ch, change = 0, force = 0, listed = 0; 104 105 if (elf_version(EV_CURRENT) == EV_NONE) 106 errx(EXIT_FAILURE, "elf_version error"); 107 108 while ((ch = getopt_long(argc, argv, "Vf:hlt:v", brandelf_longopts, 109 NULL)) != -1) 110 switch (ch) { 111 case 'f': 112 if (change) 113 errx(EXIT_FAILURE, "ERROR: the -f option is " 114 "incompatible with the -t option."); 115 force = 1; 116 type = atoi(optarg); 117 if (errno == ERANGE || type < 0 || type > 255) { 118 warnx("ERROR: invalid argument to option " 119 "-f: %s", optarg); 120 usage(); 121 } 122 break; 123 case 'h': 124 usage(); 125 break; 126 case 'l': 127 printelftypes(); 128 listed = 1; 129 break; 130 case 'v': 131 /* This flag is ignored. */ 132 break; 133 case 't': 134 if (force) 135 errx(EXIT_FAILURE, "the -t option is " 136 "incompatible with the -f option."); 137 if ((type = elftype(optarg)) == -1) { 138 warnx("ERROR: invalid ELF type '%s'", optarg); 139 usage(); 140 } 141 142 change = 1; 143 break; 144 case 'V': 145 printversion(); 146 break; 147 default: 148 usage(); 149 } 150 argc -= optind; 151 argv += optind; 152 if (!argc) { 153 if (listed) 154 exit(0); 155 else { 156 warnx("no file(s) specified"); 157 usage(); 158 } 159 } 160 161 while (argc) { 162 int fd; 163 164 elf = NULL; 165 166 if ((fd = open(argv[0], (change || force) ? O_RDWR : 167 O_RDONLY, 0)) < 0) { 168 warn("error opening file %s", argv[0]); 169 retval = 1; 170 goto fail; 171 } 172 173 if ((elf = elf_begin(fd, (change || force) ? ELF_C_RDWR : 174 ELF_C_READ, NULL)) == NULL) { 175 warnx("elf_begin failed: %s", elf_errmsg(-1)); 176 retval = 1; 177 goto fail; 178 } 179 180 if ((kind = elf_kind(elf)) != ELF_K_ELF) { 181 if (kind == ELF_K_AR) 182 warnx("file '%s' is an archive.", argv[0]); 183 else 184 warnx("file '%s' is not an ELF file.", 185 argv[0]); 186 retval = 1; 187 goto fail; 188 } 189 190 if (gelf_getehdr(elf, &ehdr) == NULL) { 191 warnx("gelf_getehdr: %s", elf_errmsg(-1)); 192 retval = 1; 193 goto fail; 194 } 195 196 if (!change && !force) { 197 fprintf(stdout, 198 "File '%s' is of brand '%s' (%u).\n", 199 argv[0], iselftype(ehdr.e_ident[EI_OSABI]), 200 ehdr.e_ident[EI_OSABI]); 201 if (!iselftype(type)) { 202 warnx("ELF ABI Brand '%u' is unknown", 203 type); 204 printelftypes(); 205 } 206 } else { 207 208 /* 209 * Keep the existing layout of the ELF object. 210 */ 211 if (elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT) == 0) { 212 warnx("elf_flagelf failed: %s", 213 elf_errmsg(-1)); 214 retval = 1; 215 goto fail; 216 } 217 218 /* 219 * Update the ABI type. 220 */ 221 ehdr.e_ident[EI_OSABI] = (unsigned char) type; 222 if (gelf_update_ehdr(elf, &ehdr) == 0) { 223 warnx("gelf_update_ehdr error: %s", 224 elf_errmsg(-1)); 225 retval = 1; 226 goto fail; 227 } 228 229 /* 230 * Write back changes. 231 */ 232 if (elf_update(elf, ELF_C_WRITE) == -1) { 233 warnx("elf_update error: %s", elf_errmsg(-1)); 234 retval = 1; 235 goto fail; 236 } 237 } 238 fail: 239 240 if (elf) 241 elf_end(elf); 242 243 if (fd >= 0 && close(fd) == -1) { 244 warnx("%s: close error", argv[0]); 245 retval = 1; 246 } 247 248 argc--; 249 argv++; 250 } 251 252 return (retval); 253 } 254 255 #define USAGE_MESSAGE "\ 256 Usage: %s [options] file...\n\ 257 Set or display the ABI field for an ELF object.\n\n\ 258 Supported options are:\n\ 259 -f NUM Set the ELF ABI to the number 'NUM'.\n\ 260 -h | --help Print a usage message and exit.\n\ 261 -l List known ELF ABI names.\n\ 262 -t ABI Set the ELF ABI to the value named by \"ABI\".\n\ 263 -V | --version Print a version identifier and exit.\n" 264 265 static void 266 usage(void) 267 { 268 (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); 269 exit(1); 270 } 271 272 static void 273 printversion(void) 274 { 275 (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); 276 exit(0); 277 } 278 279 static const char * 280 iselftype(int etype) 281 { 282 size_t elfwalk; 283 284 for (elfwalk = 0; 285 elfwalk < sizeof(elftypes)/sizeof(elftypes[0]); 286 elfwalk++) 287 if (etype == elftypes[elfwalk].value) 288 return (elftypes[elfwalk].str); 289 return (0); 290 } 291 292 static int 293 elftype(const char *elfstrtype) 294 { 295 size_t elfwalk; 296 297 for (elfwalk = 0; 298 elfwalk < sizeof(elftypes)/sizeof(elftypes[0]); 299 elfwalk++) 300 if (strcasecmp(elfstrtype, elftypes[elfwalk].str) == 0) 301 return (elftypes[elfwalk].value); 302 return (-1); 303 } 304 305 static void 306 printelftypes(void) 307 { 308 size_t elfwalk; 309 310 (void) printf("Known ELF types are: "); 311 for (elfwalk = 0; 312 elfwalk < sizeof(elftypes)/sizeof(elftypes[0]); 313 elfwalk++) 314 (void) printf("%s(%u) ", elftypes[elfwalk].str, 315 elftypes[elfwalk].value); 316 (void) printf("\n"); 317 } 318