1260684Skaiw/*-
2260684Skaiw * Copyright (c) 2008 Hyogeol Lee
3260684Skaiw * Copyright (c) 2000, 2001 David O'Brien
4289071Semaste * Copyright (c) 1996 S��ren Schmidt
5260684Skaiw * All rights reserved.
6260684Skaiw *
7260684Skaiw * Redistribution and use in source and binary forms, with or without
8260684Skaiw * modification, are permitted provided that the following conditions
9260684Skaiw * are met:
10260684Skaiw * 1. Redistributions of source code must retain the above copyright
11260684Skaiw *    notice, this list of conditions and the following disclaimer
12260684Skaiw *    in this position and unchanged.
13260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright
14260684Skaiw *    notice, this list of conditions and the following disclaimer in the
15260684Skaiw *    documentation and/or other materials provided with the distribution.
16260684Skaiw * 3. The name of the author may not be used to endorse or promote products
17260684Skaiw *    derived from this software without specific prior written permission
18260684Skaiw *
19260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20260684Skaiw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21260684Skaiw * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22260684Skaiw * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23260684Skaiw * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24260684Skaiw * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25260684Skaiw * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26260684Skaiw * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27260684Skaiw * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28260684Skaiw * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29260684Skaiw */
30260684Skaiw
31260684Skaiw#include <sys/types.h>
32260684Skaiw#include <sys/stat.h>
33260684Skaiw#include <err.h>
34260684Skaiw#include <errno.h>
35260684Skaiw#include <fcntl.h>
36260684Skaiw#include <gelf.h>
37260684Skaiw#include <getopt.h>
38260684Skaiw#include <libelf.h>
39260684Skaiw#include <libelftc.h>
40260684Skaiw#include <stdio.h>
41260684Skaiw#include <stdlib.h>
42260684Skaiw#include <string.h>
43260684Skaiw#include <unistd.h>
44260684Skaiw
45260684Skaiw#include "_elftc.h"
46260684Skaiw
47300311SemasteELFTC_VCSID("$Id: brandelf.c 3440 2016-04-07 14:51:47Z emaste $");
48260684Skaiw
49260684Skaiwstatic int elftype(const char *);
50260684Skaiwstatic const char *iselftype(int);
51260684Skaiwstatic void printelftypes(void);
52260684Skaiwstatic void printversion(void);
53260684Skaiwstatic void usage(void);
54260684Skaiw
55260684Skaiwstruct ELFtypes {
56260684Skaiw	const char *str;
57260684Skaiw	int value;
58260684Skaiw};
59260684Skaiw/* XXX - any more types? */
60260684Skaiwstatic struct ELFtypes elftypes[] = {
61260684Skaiw	{ "86Open",	ELFOSABI_86OPEN },
62260684Skaiw	{ "AIX",	ELFOSABI_AIX },
63260684Skaiw	{ "ARM",	ELFOSABI_ARM },
64260684Skaiw	{ "AROS",	ELFOSABI_AROS },
65300311Semaste	{ "CloudABI",	ELFOSABI_CLOUDABI },
66260684Skaiw	{ "FreeBSD",	ELFOSABI_FREEBSD },
67260684Skaiw	{ "GNU",	ELFOSABI_GNU },
68260684Skaiw	{ "HP/UX",	ELFOSABI_HPUX},
69260684Skaiw	{ "Hurd",	ELFOSABI_HURD },
70260684Skaiw	{ "IRIX",	ELFOSABI_IRIX },
71260684Skaiw	{ "Linux",	ELFOSABI_GNU },
72260684Skaiw	{ "Modesto",	ELFOSABI_MODESTO },
73260684Skaiw	{ "NSK",	ELFOSABI_NSK },
74260684Skaiw	{ "NetBSD",	ELFOSABI_NETBSD},
75260684Skaiw	{ "None",	ELFOSABI_NONE},
76260684Skaiw	{ "OpenBSD",	ELFOSABI_OPENBSD },
77260684Skaiw	{ "OpenVMS",	ELFOSABI_OPENVMS },
78260684Skaiw	{ "Standalone",	ELFOSABI_STANDALONE },
79260684Skaiw	{ "SVR4",	ELFOSABI_NONE },
80260684Skaiw	{ "Solaris",	ELFOSABI_SOLARIS },
81260684Skaiw	{ "Tru64",	ELFOSABI_TRU64 }
82260684Skaiw};
83260684Skaiw
84260684Skaiwstatic struct option brandelf_longopts[] = {
85260684Skaiw	{ "help",	no_argument,	NULL,   'h' },
86260684Skaiw	{ "version",	no_argument,	NULL, 	'V' },
87260684Skaiw	{ NULL,		0,		NULL,	0   }
88260684Skaiw};
89260684Skaiw
90260684Skaiwint
91260684Skaiwmain(int argc, char **argv)
92260684Skaiw{
93260684Skaiw	GElf_Ehdr ehdr;
94260684Skaiw	Elf *elf;
95260684Skaiw	Elf_Kind kind;
96260684Skaiw	int type = ELFOSABI_NONE;
97260684Skaiw	int retval = 0;
98276077Semaste	int ch, change = 0, force = 0, listed = 0;
99260684Skaiw
100260684Skaiw	if (elf_version(EV_CURRENT) == EV_NONE)
101260684Skaiw		errx(EXIT_FAILURE, "elf_version error");
102260684Skaiw
103260684Skaiw	while ((ch = getopt_long(argc, argv, "Vf:hlt:v", brandelf_longopts,
104260684Skaiw		NULL)) != -1)
105260684Skaiw		switch (ch) {
106260684Skaiw		case 'f':
107260684Skaiw			if (change)
108260684Skaiw				errx(EXIT_FAILURE, "ERROR: the -f option is "
109260684Skaiw				    "incompatible with the -t option.");
110260684Skaiw			force = 1;
111260684Skaiw			type = atoi(optarg);
112260684Skaiw			if (errno == ERANGE || type < 0 || type > 255) {
113260684Skaiw				warnx("ERROR: invalid argument to option "
114260684Skaiw				    "-f: %s", optarg);
115260684Skaiw				usage();
116260684Skaiw			}
117260684Skaiw			break;
118260684Skaiw		case 'h':
119260684Skaiw			usage();
120260684Skaiw			break;
121260684Skaiw		case 'l':
122260684Skaiw			printelftypes();
123260684Skaiw			listed = 1;
124260684Skaiw			break;
125260684Skaiw		case 'v':
126276077Semaste			/* This flag is ignored. */
127260684Skaiw			break;
128260684Skaiw		case 't':
129260684Skaiw			if (force)
130260684Skaiw				errx(EXIT_FAILURE, "the -t option is "
131260684Skaiw				    "incompatible with the -f option.");
132260684Skaiw			if ((type = elftype(optarg)) == -1) {
133260684Skaiw				warnx("ERROR: invalid ELF type '%s'", optarg);
134260684Skaiw				usage();
135260684Skaiw			}
136260684Skaiw
137260684Skaiw			change = 1;
138260684Skaiw			break;
139260684Skaiw		case 'V':
140260684Skaiw			printversion();
141260684Skaiw			break;
142260684Skaiw		default:
143260684Skaiw			usage();
144260684Skaiw	}
145260684Skaiw	argc -= optind;
146260684Skaiw	argv += optind;
147260684Skaiw	if (!argc) {
148260684Skaiw		if (listed)
149260684Skaiw			exit(0);
150260684Skaiw		else {
151260684Skaiw			warnx("no file(s) specified");
152260684Skaiw			usage();
153260684Skaiw		}
154260684Skaiw	}
155260684Skaiw
156260684Skaiw	while (argc) {
157260684Skaiw		int fd;
158260684Skaiw
159260684Skaiw		elf = NULL;
160260684Skaiw
161260684Skaiw		if ((fd = open(argv[0], (change || force) ? O_RDWR :
162260684Skaiw		    O_RDONLY, 0)) < 0) {
163260684Skaiw			warn("error opening file %s", argv[0]);
164260684Skaiw			retval = 1;
165260684Skaiw			goto fail;
166260684Skaiw		}
167260684Skaiw
168260684Skaiw		if ((elf = elf_begin(fd, (change || force) ? ELF_C_RDWR :
169260684Skaiw		    ELF_C_READ, NULL)) == NULL) {
170260684Skaiw			warnx("elf_begin failed: %s", elf_errmsg(-1));
171260684Skaiw			retval = 1;
172260684Skaiw			goto fail;
173260684Skaiw		}
174260684Skaiw
175260684Skaiw		if ((kind = elf_kind(elf)) != ELF_K_ELF) {
176260684Skaiw			if (kind == ELF_K_AR)
177260684Skaiw				warnx("file '%s' is an archive.", argv[0]);
178260684Skaiw			else
179260684Skaiw				warnx("file '%s' is not an ELF file.",
180260684Skaiw				    argv[0]);
181260684Skaiw			retval = 1;
182260684Skaiw			goto fail;
183260684Skaiw		}
184260684Skaiw
185260684Skaiw		if (gelf_getehdr(elf, &ehdr) == NULL) {
186260684Skaiw			warnx("gelf_getehdr: %s", elf_errmsg(-1));
187260684Skaiw			retval = 1;
188260684Skaiw			goto fail;
189260684Skaiw		}
190260684Skaiw
191260684Skaiw		if (!change && !force) {
192260684Skaiw			fprintf(stdout,
193260684Skaiw			    "File '%s' is of brand '%s' (%u).\n",
194260684Skaiw			    argv[0], iselftype(ehdr.e_ident[EI_OSABI]),
195260684Skaiw			    ehdr.e_ident[EI_OSABI]);
196260684Skaiw			if (!iselftype(type)) {
197260684Skaiw				warnx("ELF ABI Brand '%u' is unknown",
198260684Skaiw				      type);
199260684Skaiw				printelftypes();
200260684Skaiw			}
201260684Skaiw		} else {
202260684Skaiw
203260684Skaiw			/*
204260684Skaiw			 * Keep the existing layout of the ELF object.
205260684Skaiw			 */
206260684Skaiw			if (elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT) == 0) {
207260684Skaiw				warnx("elf_flagelf failed: %s",
208260684Skaiw				    elf_errmsg(-1));
209260684Skaiw				retval = 1;
210260684Skaiw				goto fail;
211260684Skaiw			}
212260684Skaiw
213260684Skaiw			/*
214260684Skaiw			 * Update the ABI type.
215260684Skaiw			 */
216295577Semaste			ehdr.e_ident[EI_OSABI] = (unsigned char) type;
217260684Skaiw			if (gelf_update_ehdr(elf, &ehdr) == 0) {
218260684Skaiw				warnx("gelf_update_ehdr error: %s",
219260684Skaiw				    elf_errmsg(-1));
220260684Skaiw				retval = 1;
221260684Skaiw				goto fail;
222260684Skaiw			}
223260684Skaiw
224260684Skaiw			/*
225260684Skaiw			 * Write back changes.
226260684Skaiw			 */
227260684Skaiw			if (elf_update(elf, ELF_C_WRITE) == -1) {
228260684Skaiw				warnx("elf_update error: %s", elf_errmsg(-1));
229260684Skaiw				retval = 1;
230260684Skaiw				goto fail;
231260684Skaiw			}
232260684Skaiw		}
233260684Skaiwfail:
234260684Skaiw
235260684Skaiw		if (elf)
236260684Skaiw			elf_end(elf);
237260684Skaiw
238260684Skaiw		if (fd >= 0 && close(fd) == -1) {
239260684Skaiw			warnx("%s: close error", argv[0]);
240260684Skaiw			retval = 1;
241260684Skaiw		}
242260684Skaiw
243260684Skaiw		argc--;
244260684Skaiw		argv++;
245260684Skaiw	}
246260684Skaiw
247260684Skaiw	return (retval);
248260684Skaiw}
249260684Skaiw
250260684Skaiw#define	USAGE_MESSAGE	"\
251260684SkaiwUsage: %s [options] file...\n\
252260684Skaiw  Set or display the ABI field for an ELF object.\n\n\
253260684Skaiw  Supported options are:\n\
254260684Skaiw  -f NUM                    Set the ELF ABI to the number 'NUM'.\n\
255260684Skaiw  -h | --help               Print a usage message and exit.\n\
256260684Skaiw  -l                        List known ELF ABI names.\n\
257260684Skaiw  -t ABI                    Set the ELF ABI to the value named by \"ABI\".\n\
258260684Skaiw  -V | --version            Print a version identifier and exit.\n"
259260684Skaiw
260260684Skaiwstatic void
261260684Skaiwusage(void)
262260684Skaiw{
263260684Skaiw	(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
264260684Skaiw	exit(1);
265260684Skaiw}
266260684Skaiw
267260684Skaiwstatic void
268260684Skaiwprintversion(void)
269260684Skaiw{
270260684Skaiw	(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
271260684Skaiw	exit(0);
272260684Skaiw}
273260684Skaiw
274260684Skaiwstatic const char *
275260684Skaiwiselftype(int etype)
276260684Skaiw{
277260684Skaiw	size_t elfwalk;
278260684Skaiw
279260684Skaiw	for (elfwalk = 0;
280260684Skaiw	     elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
281260684Skaiw	     elfwalk++)
282260684Skaiw		if (etype == elftypes[elfwalk].value)
283260684Skaiw			return (elftypes[elfwalk].str);
284260684Skaiw	return (0);
285260684Skaiw}
286260684Skaiw
287260684Skaiwstatic int
288260684Skaiwelftype(const char *elfstrtype)
289260684Skaiw{
290260684Skaiw	size_t elfwalk;
291260684Skaiw
292260684Skaiw	for (elfwalk = 0;
293260684Skaiw	     elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
294260684Skaiw	     elfwalk++)
295260684Skaiw		if (strcasecmp(elfstrtype, elftypes[elfwalk].str) == 0)
296260684Skaiw			return (elftypes[elfwalk].value);
297260684Skaiw	return (-1);
298260684Skaiw}
299260684Skaiw
300260684Skaiwstatic void
301260684Skaiwprintelftypes(void)
302260684Skaiw{
303260684Skaiw	size_t elfwalk;
304260684Skaiw
305260684Skaiw	(void) printf("Known ELF types are: ");
306260684Skaiw	for (elfwalk = 0;
307260684Skaiw	     elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
308260684Skaiw	     elfwalk++)
309260684Skaiw		(void) printf("%s(%u) ", elftypes[elfwalk].str,
310260684Skaiw		    elftypes[elfwalk].value);
311260684Skaiw	(void) printf("\n");
312260684Skaiw}
313