brandelf.c revision 260684
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/cdefs.h>
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <err.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <gelf.h>
39#include <getopt.h>
40#include <libelf.h>
41#include <libelftc.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <unistd.h>
46
47#include "_elftc.h"
48
49ELFTC_VCSID("$Id: brandelf.c 2324 2011-12-12 06:36:27Z jkoshy $");
50
51static int elftype(const char *);
52static const char *iselftype(int);
53static void printelftypes(void);
54static void printversion(void);
55static void usage(void);
56
57struct ELFtypes {
58	const char *str;
59	int value;
60};
61/* XXX - any more types? */
62static struct ELFtypes elftypes[] = {
63	{ "86Open",	ELFOSABI_86OPEN },
64	{ "AIX",	ELFOSABI_AIX },
65	{ "ARM",	ELFOSABI_ARM },
66	{ "AROS",	ELFOSABI_AROS },
67	{ "FreeBSD",	ELFOSABI_FREEBSD },
68	{ "GNU",	ELFOSABI_GNU },
69	{ "HP/UX",	ELFOSABI_HPUX},
70	{ "Hurd",	ELFOSABI_HURD },
71	{ "IRIX",	ELFOSABI_IRIX },
72	{ "Linux",	ELFOSABI_GNU },
73	{ "Modesto",	ELFOSABI_MODESTO },
74	{ "NSK",	ELFOSABI_NSK },
75	{ "NetBSD",	ELFOSABI_NETBSD},
76	{ "None",	ELFOSABI_NONE},
77	{ "OpenBSD",	ELFOSABI_OPENBSD },
78	{ "OpenVMS",	ELFOSABI_OPENVMS },
79	{ "Standalone",	ELFOSABI_STANDALONE },
80	{ "SVR4",	ELFOSABI_NONE },
81	{ "Solaris",	ELFOSABI_SOLARIS },
82	{ "Tru64",	ELFOSABI_TRU64 }
83};
84
85static struct option brandelf_longopts[] = {
86	{ "help",	no_argument,	NULL,   'h' },
87	{ "version",	no_argument,	NULL, 	'V' },
88	{ NULL,		0,		NULL,	0   }
89};
90
91int
92main(int argc, char **argv)
93{
94	GElf_Ehdr ehdr;
95	Elf *elf;
96	Elf_Kind kind;
97	int type = ELFOSABI_NONE;
98	int retval = 0;
99	int ch, change = 0, verbose = 0, force = 0, listed = 0;
100
101	if (elf_version(EV_CURRENT) == EV_NONE)
102		errx(EXIT_FAILURE, "elf_version error");
103
104	while ((ch = getopt_long(argc, argv, "Vf:hlt:v", brandelf_longopts,
105		NULL)) != -1)
106		switch (ch) {
107		case 'f':
108			if (change)
109				errx(EXIT_FAILURE, "ERROR: the -f option is "
110				    "incompatible with the -t option.");
111			force = 1;
112			type = atoi(optarg);
113			if (errno == ERANGE || type < 0 || type > 255) {
114				warnx("ERROR: invalid argument to option "
115				    "-f: %s", optarg);
116				usage();
117			}
118			break;
119		case 'h':
120			usage();
121			break;
122		case 'l':
123			printelftypes();
124			listed = 1;
125			break;
126		case 'v':
127			verbose = 1;
128			break;
129		case 't':
130			if (force)
131				errx(EXIT_FAILURE, "the -t option is "
132				    "incompatible with the -f option.");
133			if ((type = elftype(optarg)) == -1) {
134				warnx("ERROR: invalid ELF type '%s'", optarg);
135				usage();
136			}
137
138			change = 1;
139			break;
140		case 'V':
141			printversion();
142			break;
143		default:
144			usage();
145	}
146	argc -= optind;
147	argv += optind;
148	if (!argc) {
149		if (listed)
150			exit(0);
151		else {
152			warnx("no file(s) specified");
153			usage();
154		}
155	}
156
157	while (argc) {
158		int fd;
159
160		elf = NULL;
161
162		if ((fd = open(argv[0], (change || force) ? O_RDWR :
163		    O_RDONLY, 0)) < 0) {
164			warn("error opening file %s", argv[0]);
165			retval = 1;
166			goto fail;
167		}
168
169		if ((elf = elf_begin(fd, (change || force) ? ELF_C_RDWR :
170		    ELF_C_READ, NULL)) == NULL) {
171			warnx("elf_begin failed: %s", elf_errmsg(-1));
172			retval = 1;
173			goto fail;
174		}
175
176		if ((kind = elf_kind(elf)) != ELF_K_ELF) {
177			if (kind == ELF_K_AR)
178				warnx("file '%s' is an archive.", argv[0]);
179			else
180				warnx("file '%s' is not an ELF file.",
181				    argv[0]);
182			retval = 1;
183			goto fail;
184		}
185
186		if (gelf_getehdr(elf, &ehdr) == NULL) {
187			warnx("gelf_getehdr: %s", elf_errmsg(-1));
188			retval = 1;
189			goto fail;
190		}
191
192		if (!change && !force) {
193			fprintf(stdout,
194			    "File '%s' is of brand '%s' (%u).\n",
195			    argv[0], iselftype(ehdr.e_ident[EI_OSABI]),
196			    ehdr.e_ident[EI_OSABI]);
197			if (!iselftype(type)) {
198				warnx("ELF ABI Brand '%u' is unknown",
199				      type);
200				printelftypes();
201			}
202		} else {
203
204			/*
205			 * Keep the existing layout of the ELF object.
206			 */
207			if (elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT) == 0) {
208				warnx("elf_flagelf failed: %s",
209				    elf_errmsg(-1));
210				retval = 1;
211				goto fail;
212			}
213
214			/*
215			 * Update the ABI type.
216			 */
217			ehdr.e_ident[EI_OSABI] = type;
218			if (gelf_update_ehdr(elf, &ehdr) == 0) {
219				warnx("gelf_update_ehdr error: %s",
220				    elf_errmsg(-1));
221				retval = 1;
222				goto fail;
223			}
224
225			/*
226			 * Write back changes.
227			 */
228			if (elf_update(elf, ELF_C_WRITE) == -1) {
229				warnx("elf_update error: %s", elf_errmsg(-1));
230				retval = 1;
231				goto fail;
232			}
233		}
234fail:
235
236		if (elf)
237			elf_end(elf);
238
239		if (fd >= 0 && close(fd) == -1) {
240			warnx("%s: close error", argv[0]);
241			retval = 1;
242		}
243
244		argc--;
245		argv++;
246	}
247
248	return (retval);
249}
250
251#define	USAGE_MESSAGE	"\
252Usage: %s [options] file...\n\
253  Set or display the ABI field for an ELF object.\n\n\
254  Supported options are:\n\
255  -f NUM                    Set the ELF ABI to the number 'NUM'.\n\
256  -h | --help               Print a usage message and exit.\n\
257  -l                        List known ELF ABI names.\n\
258  -t ABI                    Set the ELF ABI to the value named by \"ABI\".\n\
259  -v                        Be verbose.\n\
260  -V | --version            Print a version identifier and exit.\n"
261
262static void
263usage(void)
264{
265	(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
266	exit(1);
267}
268
269static void
270printversion(void)
271{
272	(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
273	exit(0);
274}
275
276static const char *
277iselftype(int etype)
278{
279	size_t elfwalk;
280
281	for (elfwalk = 0;
282	     elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
283	     elfwalk++)
284		if (etype == elftypes[elfwalk].value)
285			return (elftypes[elfwalk].str);
286	return (0);
287}
288
289static int
290elftype(const char *elfstrtype)
291{
292	size_t elfwalk;
293
294	for (elfwalk = 0;
295	     elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
296	     elfwalk++)
297		if (strcasecmp(elfstrtype, elftypes[elfwalk].str) == 0)
298			return (elftypes[elfwalk].value);
299	return (-1);
300}
301
302static void
303printelftypes(void)
304{
305	size_t elfwalk;
306
307	(void) printf("Known ELF types are: ");
308	for (elfwalk = 0;
309	     elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
310	     elfwalk++)
311		(void) printf("%s(%u) ", elftypes[elfwalk].str,
312		    elftypes[elfwalk].value);
313	(void) printf("\n");
314}
315