xref: /titanic_51/usr/src/cmd/ctfmerge/ctfmerge.c (revision 7fd791373689a6af05e27efec3b1ab556e02aa23)
1*7fd79137SRobert Mustacchi /*
2*7fd79137SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*7fd79137SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*7fd79137SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*7fd79137SRobert Mustacchi  * 1.0 of the CDDL.
6*7fd79137SRobert Mustacchi  *
7*7fd79137SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*7fd79137SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*7fd79137SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*7fd79137SRobert Mustacchi  */
11*7fd79137SRobert Mustacchi 
12*7fd79137SRobert Mustacchi /*
13*7fd79137SRobert Mustacchi  * Copyright (c) 2017, Joyent, Inc.
14*7fd79137SRobert Mustacchi  */
15*7fd79137SRobert Mustacchi 
16*7fd79137SRobert Mustacchi /*
17*7fd79137SRobert Mustacchi  * merge CTF containers
18*7fd79137SRobert Mustacchi  */
19*7fd79137SRobert Mustacchi 
20*7fd79137SRobert Mustacchi #include <stdio.h>
21*7fd79137SRobert Mustacchi #include <libctf.h>
22*7fd79137SRobert Mustacchi #include <sys/stat.h>
23*7fd79137SRobert Mustacchi #include <sys/types.h>
24*7fd79137SRobert Mustacchi #include <fcntl.h>
25*7fd79137SRobert Mustacchi #include <errno.h>
26*7fd79137SRobert Mustacchi #include <strings.h>
27*7fd79137SRobert Mustacchi #include <assert.h>
28*7fd79137SRobert Mustacchi #include <unistd.h>
29*7fd79137SRobert Mustacchi #include <sys/fcntl.h>
30*7fd79137SRobert Mustacchi #include <stdlib.h>
31*7fd79137SRobert Mustacchi #include <libelf.h>
32*7fd79137SRobert Mustacchi #include <gelf.h>
33*7fd79137SRobert Mustacchi #include <sys/mman.h>
34*7fd79137SRobert Mustacchi #include <libgen.h>
35*7fd79137SRobert Mustacchi #include <stdarg.h>
36*7fd79137SRobert Mustacchi #include <limits.h>
37*7fd79137SRobert Mustacchi 
38*7fd79137SRobert Mustacchi static char *g_progname;
39*7fd79137SRobert Mustacchi static char *g_unique;
40*7fd79137SRobert Mustacchi static char *g_outfile;
41*7fd79137SRobert Mustacchi static boolean_t g_req;
42*7fd79137SRobert Mustacchi static uint_t g_nctf;
43*7fd79137SRobert Mustacchi 
44*7fd79137SRobert Mustacchi #define	CTFMERGE_OK	0
45*7fd79137SRobert Mustacchi #define	CTFMERGE_FATAL	1
46*7fd79137SRobert Mustacchi #define	CTFMERGE_USAGE	2
47*7fd79137SRobert Mustacchi 
48*7fd79137SRobert Mustacchi #define	CTFMERGE_DEFAULT_NTHREADS	8
49*7fd79137SRobert Mustacchi #define	CTFMERGE_ALTEXEC	"CTFMERGE_ALTEXEC"
50*7fd79137SRobert Mustacchi 
51*7fd79137SRobert Mustacchi static void
52*7fd79137SRobert Mustacchi ctfmerge_fatal(const char *fmt, ...)
53*7fd79137SRobert Mustacchi {
54*7fd79137SRobert Mustacchi 	va_list ap;
55*7fd79137SRobert Mustacchi 
56*7fd79137SRobert Mustacchi 	(void) fprintf(stderr, "%s: ", g_progname);
57*7fd79137SRobert Mustacchi 	va_start(ap, fmt);
58*7fd79137SRobert Mustacchi 	(void) vfprintf(stderr, fmt, ap);
59*7fd79137SRobert Mustacchi 	va_end(ap);
60*7fd79137SRobert Mustacchi 
61*7fd79137SRobert Mustacchi 	if (g_outfile != NULL)
62*7fd79137SRobert Mustacchi 		(void) unlink(g_outfile);
63*7fd79137SRobert Mustacchi 
64*7fd79137SRobert Mustacchi 	exit(CTFMERGE_FATAL);
65*7fd79137SRobert Mustacchi }
66*7fd79137SRobert Mustacchi 
67*7fd79137SRobert Mustacchi static boolean_t
68*7fd79137SRobert Mustacchi ctfmerge_expect_ctf(const char *name, Elf *elf)
69*7fd79137SRobert Mustacchi {
70*7fd79137SRobert Mustacchi 	Elf_Scn *scn, *strscn;
71*7fd79137SRobert Mustacchi 	Elf_Data *data, *strdata;
72*7fd79137SRobert Mustacchi 	GElf_Shdr shdr;
73*7fd79137SRobert Mustacchi 	ulong_t i;
74*7fd79137SRobert Mustacchi 
75*7fd79137SRobert Mustacchi 	if (g_req == B_FALSE)
76*7fd79137SRobert Mustacchi 		return (B_FALSE);
77*7fd79137SRobert Mustacchi 
78*7fd79137SRobert Mustacchi 	scn = NULL;
79*7fd79137SRobert Mustacchi 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
80*7fd79137SRobert Mustacchi 		if (gelf_getshdr(scn, &shdr) == NULL) {
81*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to get section header for file "
82*7fd79137SRobert Mustacchi 			    "%s: %s\n", name, elf_errmsg(elf_errno()));
83*7fd79137SRobert Mustacchi 		}
84*7fd79137SRobert Mustacchi 
85*7fd79137SRobert Mustacchi 		if (shdr.sh_type == SHT_SYMTAB)
86*7fd79137SRobert Mustacchi 			break;
87*7fd79137SRobert Mustacchi 	}
88*7fd79137SRobert Mustacchi 
89*7fd79137SRobert Mustacchi 	if (scn == NULL)
90*7fd79137SRobert Mustacchi 		return (B_FALSE);
91*7fd79137SRobert Mustacchi 
92*7fd79137SRobert Mustacchi 	if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL)
93*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to get section header for file %s: %s\n",
94*7fd79137SRobert Mustacchi 		    name, elf_errmsg(elf_errno()));
95*7fd79137SRobert Mustacchi 
96*7fd79137SRobert Mustacchi 	if ((data = elf_getdata(scn, NULL)) == NULL)
97*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to read symbol table for %s: %s\n",
98*7fd79137SRobert Mustacchi 		    name, elf_errmsg(elf_errno()));
99*7fd79137SRobert Mustacchi 
100*7fd79137SRobert Mustacchi 	if ((strdata = elf_getdata(strscn, NULL)) == NULL)
101*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to read string table for %s: %s\n",
102*7fd79137SRobert Mustacchi 		    name, elf_errmsg(elf_errno()));
103*7fd79137SRobert Mustacchi 
104*7fd79137SRobert Mustacchi 	for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
105*7fd79137SRobert Mustacchi 		GElf_Sym sym;
106*7fd79137SRobert Mustacchi 		const char *file;
107*7fd79137SRobert Mustacchi 		size_t len;
108*7fd79137SRobert Mustacchi 
109*7fd79137SRobert Mustacchi 		if (gelf_getsym(data, i, &sym) == NULL)
110*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to read symbol table entry %lu "
111*7fd79137SRobert Mustacchi 			    "for %s: %s\n", i, name, elf_errmsg(elf_errno()));
112*7fd79137SRobert Mustacchi 
113*7fd79137SRobert Mustacchi 		if (GELF_ST_TYPE(sym.st_info) != STT_FILE)
114*7fd79137SRobert Mustacchi 			continue;
115*7fd79137SRobert Mustacchi 
116*7fd79137SRobert Mustacchi 		file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);
117*7fd79137SRobert Mustacchi 		len = strlen(file);
118*7fd79137SRobert Mustacchi 		if (len < 2 || name[len - 2] != '.')
119*7fd79137SRobert Mustacchi 			continue;
120*7fd79137SRobert Mustacchi 
121*7fd79137SRobert Mustacchi 		if (name[len - 1] == 'c')
122*7fd79137SRobert Mustacchi 			return (B_TRUE);
123*7fd79137SRobert Mustacchi 	}
124*7fd79137SRobert Mustacchi 
125*7fd79137SRobert Mustacchi 	return (B_FALSE);
126*7fd79137SRobert Mustacchi }
127*7fd79137SRobert Mustacchi 
128*7fd79137SRobert Mustacchi /*
129*7fd79137SRobert Mustacchi  * Go through and construct enough information for this Elf Object to try and do
130*7fd79137SRobert Mustacchi  * a ctf_bufopen().
131*7fd79137SRobert Mustacchi  */
132*7fd79137SRobert Mustacchi static void
133*7fd79137SRobert Mustacchi ctfmerge_elfopen(const char *name, Elf *elf, ctf_merge_t *cmh)
134*7fd79137SRobert Mustacchi {
135*7fd79137SRobert Mustacchi 	GElf_Ehdr ehdr;
136*7fd79137SRobert Mustacchi 	GElf_Shdr shdr;
137*7fd79137SRobert Mustacchi 	Elf_Scn *scn;
138*7fd79137SRobert Mustacchi 	Elf_Data *ctf_data, *str_data, *sym_data;
139*7fd79137SRobert Mustacchi 	ctf_sect_t ctfsect, symsect, strsect;
140*7fd79137SRobert Mustacchi 	ctf_file_t *fp;
141*7fd79137SRobert Mustacchi 	int err;
142*7fd79137SRobert Mustacchi 
143*7fd79137SRobert Mustacchi 	if (gelf_getehdr(elf, &ehdr) == NULL)
144*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to get ELF header for %s: %s\n",
145*7fd79137SRobert Mustacchi 		    name, elf_errmsg(elf_errno()));
146*7fd79137SRobert Mustacchi 
147*7fd79137SRobert Mustacchi 	bzero(&ctfsect, sizeof (ctf_sect_t));
148*7fd79137SRobert Mustacchi 	bzero(&symsect, sizeof (ctf_sect_t));
149*7fd79137SRobert Mustacchi 	bzero(&strsect, sizeof (ctf_sect_t));
150*7fd79137SRobert Mustacchi 
151*7fd79137SRobert Mustacchi 	scn = NULL;
152*7fd79137SRobert Mustacchi 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
153*7fd79137SRobert Mustacchi 		const char *sname;
154*7fd79137SRobert Mustacchi 
155*7fd79137SRobert Mustacchi 		if (gelf_getshdr(scn, &shdr) == NULL)
156*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to get section header for "
157*7fd79137SRobert Mustacchi 			    "file %s: %s\n", name, elf_errmsg(elf_errno()));
158*7fd79137SRobert Mustacchi 
159*7fd79137SRobert Mustacchi 		sname = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
160*7fd79137SRobert Mustacchi 		if (shdr.sh_type == SHT_PROGBITS &&
161*7fd79137SRobert Mustacchi 		    strcmp(sname, ".SUNW_ctf") == 0) {
162*7fd79137SRobert Mustacchi 			ctfsect.cts_name = sname;
163*7fd79137SRobert Mustacchi 			ctfsect.cts_type = shdr.sh_type;
164*7fd79137SRobert Mustacchi 			ctfsect.cts_flags = shdr.sh_flags;
165*7fd79137SRobert Mustacchi 			ctfsect.cts_size = shdr.sh_size;
166*7fd79137SRobert Mustacchi 			ctfsect.cts_entsize = shdr.sh_entsize;
167*7fd79137SRobert Mustacchi 			ctfsect.cts_offset = (off64_t)shdr.sh_offset;
168*7fd79137SRobert Mustacchi 
169*7fd79137SRobert Mustacchi 			ctf_data = elf_getdata(scn, NULL);
170*7fd79137SRobert Mustacchi 			if (ctf_data == NULL)
171*7fd79137SRobert Mustacchi 				ctfmerge_fatal("failed to get ELF CTF "
172*7fd79137SRobert Mustacchi 				    "data section for %s: %s\n", name,
173*7fd79137SRobert Mustacchi 				    elf_errmsg(elf_errno()));
174*7fd79137SRobert Mustacchi 			ctfsect.cts_data = ctf_data->d_buf;
175*7fd79137SRobert Mustacchi 		} else if (shdr.sh_type == SHT_SYMTAB) {
176*7fd79137SRobert Mustacchi 			Elf_Scn *strscn;
177*7fd79137SRobert Mustacchi 			GElf_Shdr strhdr;
178*7fd79137SRobert Mustacchi 
179*7fd79137SRobert Mustacchi 			symsect.cts_name = sname;
180*7fd79137SRobert Mustacchi 			symsect.cts_type = shdr.sh_type;
181*7fd79137SRobert Mustacchi 			symsect.cts_flags = shdr.sh_flags;
182*7fd79137SRobert Mustacchi 			symsect.cts_size = shdr.sh_size;
183*7fd79137SRobert Mustacchi 			symsect.cts_entsize = shdr.sh_entsize;
184*7fd79137SRobert Mustacchi 			symsect.cts_offset = (off64_t)shdr.sh_offset;
185*7fd79137SRobert Mustacchi 
186*7fd79137SRobert Mustacchi 			if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL ||
187*7fd79137SRobert Mustacchi 			    gelf_getshdr(strscn, &strhdr) == NULL)
188*7fd79137SRobert Mustacchi 				ctfmerge_fatal("failed to get "
189*7fd79137SRobert Mustacchi 				    "string table for file %s: %s\n", name,
190*7fd79137SRobert Mustacchi 				    elf_errmsg(elf_errno()));
191*7fd79137SRobert Mustacchi 
192*7fd79137SRobert Mustacchi 			strsect.cts_name = elf_strptr(elf, ehdr.e_shstrndx,
193*7fd79137SRobert Mustacchi 			    strhdr.sh_name);
194*7fd79137SRobert Mustacchi 			strsect.cts_type = strhdr.sh_type;
195*7fd79137SRobert Mustacchi 			strsect.cts_flags = strhdr.sh_flags;
196*7fd79137SRobert Mustacchi 			strsect.cts_size = strhdr.sh_size;
197*7fd79137SRobert Mustacchi 			strsect.cts_entsize = strhdr.sh_entsize;
198*7fd79137SRobert Mustacchi 			strsect.cts_offset = (off64_t)strhdr.sh_offset;
199*7fd79137SRobert Mustacchi 
200*7fd79137SRobert Mustacchi 			sym_data = elf_getdata(scn, NULL);
201*7fd79137SRobert Mustacchi 			if (sym_data == NULL)
202*7fd79137SRobert Mustacchi 				ctfmerge_fatal("failed to get ELF CTF "
203*7fd79137SRobert Mustacchi 				    "data section for %s: %s\n", name,
204*7fd79137SRobert Mustacchi 				    elf_errmsg(elf_errno()));
205*7fd79137SRobert Mustacchi 			symsect.cts_data = sym_data->d_buf;
206*7fd79137SRobert Mustacchi 
207*7fd79137SRobert Mustacchi 			str_data = elf_getdata(strscn, NULL);
208*7fd79137SRobert Mustacchi 			if (str_data == NULL)
209*7fd79137SRobert Mustacchi 				ctfmerge_fatal("failed to get ELF CTF "
210*7fd79137SRobert Mustacchi 				    "data section for %s: %s\n", name,
211*7fd79137SRobert Mustacchi 				    elf_errmsg(elf_errno()));
212*7fd79137SRobert Mustacchi 			strsect.cts_data = str_data->d_buf;
213*7fd79137SRobert Mustacchi 		}
214*7fd79137SRobert Mustacchi 	}
215*7fd79137SRobert Mustacchi 
216*7fd79137SRobert Mustacchi 	if (ctfsect.cts_type == SHT_NULL) {
217*7fd79137SRobert Mustacchi 		if (ctfmerge_expect_ctf(name, elf) == B_FALSE)
218*7fd79137SRobert Mustacchi 			return;
219*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to open %s: %s\n", name,
220*7fd79137SRobert Mustacchi 		    ctf_errmsg(ECTF_NOCTFDATA));
221*7fd79137SRobert Mustacchi 	}
222*7fd79137SRobert Mustacchi 
223*7fd79137SRobert Mustacchi 	if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL) {
224*7fd79137SRobert Mustacchi 		fp = ctf_bufopen(&ctfsect, &symsect, &strsect, &err);
225*7fd79137SRobert Mustacchi 	} else {
226*7fd79137SRobert Mustacchi 		fp = ctf_bufopen(&ctfsect, NULL, NULL, &err);
227*7fd79137SRobert Mustacchi 	}
228*7fd79137SRobert Mustacchi 
229*7fd79137SRobert Mustacchi 	if (fp == NULL) {
230*7fd79137SRobert Mustacchi 		if (ctfmerge_expect_ctf(name, elf) == B_TRUE) {
231*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to open file %s: %s\n",
232*7fd79137SRobert Mustacchi 			    name, ctf_errmsg(err));
233*7fd79137SRobert Mustacchi 		}
234*7fd79137SRobert Mustacchi 	} else {
235*7fd79137SRobert Mustacchi 		if ((err = ctf_merge_add(cmh, fp)) != 0) {
236*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to add input %s: %s\n",
237*7fd79137SRobert Mustacchi 			    name, ctf_errmsg(err));
238*7fd79137SRobert Mustacchi 		}
239*7fd79137SRobert Mustacchi 		g_nctf++;
240*7fd79137SRobert Mustacchi 	}
241*7fd79137SRobert Mustacchi }
242*7fd79137SRobert Mustacchi 
243*7fd79137SRobert Mustacchi static void
244*7fd79137SRobert Mustacchi ctfmerge_read_archive(const char *name, int fd, Elf *elf,
245*7fd79137SRobert Mustacchi     ctf_merge_t *cmh)
246*7fd79137SRobert Mustacchi {
247*7fd79137SRobert Mustacchi 	Elf *aelf;
248*7fd79137SRobert Mustacchi 	Elf_Cmd cmd = ELF_C_READ;
249*7fd79137SRobert Mustacchi 	int cursec = 1;
250*7fd79137SRobert Mustacchi 	char *nname;
251*7fd79137SRobert Mustacchi 
252*7fd79137SRobert Mustacchi 	while ((aelf = elf_begin(fd, cmd, elf)) != NULL) {
253*7fd79137SRobert Mustacchi 		Elf_Arhdr *arhdr;
254*7fd79137SRobert Mustacchi 		boolean_t leakelf = B_FALSE;
255*7fd79137SRobert Mustacchi 
256*7fd79137SRobert Mustacchi 		if ((arhdr = elf_getarhdr(aelf)) == NULL)
257*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to get archive header %d for "
258*7fd79137SRobert Mustacchi 			    "%s: %s\n", cursec, name, elf_errmsg(elf_errno()));
259*7fd79137SRobert Mustacchi 
260*7fd79137SRobert Mustacchi 		if (*(arhdr->ar_name) == '/')
261*7fd79137SRobert Mustacchi 			goto next;
262*7fd79137SRobert Mustacchi 
263*7fd79137SRobert Mustacchi 		if (asprintf(&nname, "%s.%s.%d", name, arhdr->ar_name,
264*7fd79137SRobert Mustacchi 		    cursec) < 0)
265*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to allocate memory for archive "
266*7fd79137SRobert Mustacchi 			    "%d of file %s\n", cursec, name);
267*7fd79137SRobert Mustacchi 
268*7fd79137SRobert Mustacchi 		switch (elf_kind(aelf)) {
269*7fd79137SRobert Mustacchi 		case ELF_K_AR:
270*7fd79137SRobert Mustacchi 			ctfmerge_read_archive(nname, fd, aelf, cmh);
271*7fd79137SRobert Mustacchi 			free(nname);
272*7fd79137SRobert Mustacchi 			break;
273*7fd79137SRobert Mustacchi 		case ELF_K_ELF:
274*7fd79137SRobert Mustacchi 			ctfmerge_elfopen(nname, aelf, cmh);
275*7fd79137SRobert Mustacchi 			free(nname);
276*7fd79137SRobert Mustacchi 			leakelf = B_TRUE;
277*7fd79137SRobert Mustacchi 			break;
278*7fd79137SRobert Mustacchi 		default:
279*7fd79137SRobert Mustacchi 			ctfmerge_fatal("unknown elf kind (%d) in archive %d "
280*7fd79137SRobert Mustacchi 			    "for %s\n", elf_kind(aelf), cursec, name);
281*7fd79137SRobert Mustacchi 		}
282*7fd79137SRobert Mustacchi 
283*7fd79137SRobert Mustacchi next:
284*7fd79137SRobert Mustacchi 		cmd = elf_next(aelf);
285*7fd79137SRobert Mustacchi 		if (leakelf == B_FALSE)
286*7fd79137SRobert Mustacchi 			(void) elf_end(aelf);
287*7fd79137SRobert Mustacchi 		cursec++;
288*7fd79137SRobert Mustacchi 	}
289*7fd79137SRobert Mustacchi }
290*7fd79137SRobert Mustacchi 
291*7fd79137SRobert Mustacchi static void
292*7fd79137SRobert Mustacchi ctfmerge_usage(const char *fmt, ...)
293*7fd79137SRobert Mustacchi {
294*7fd79137SRobert Mustacchi 	if (fmt != NULL) {
295*7fd79137SRobert Mustacchi 		va_list ap;
296*7fd79137SRobert Mustacchi 
297*7fd79137SRobert Mustacchi 		(void) fprintf(stderr, "%s: ", g_progname);
298*7fd79137SRobert Mustacchi 		va_start(ap, fmt);
299*7fd79137SRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
300*7fd79137SRobert Mustacchi 		va_end(ap);
301*7fd79137SRobert Mustacchi 	}
302*7fd79137SRobert Mustacchi 
303*7fd79137SRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s [-t] [-d uniqfile] [-l label] "
304*7fd79137SRobert Mustacchi 	    "[-L labelenv] [-j nthrs] -o outfile file ...\n"
305*7fd79137SRobert Mustacchi 	    "\n"
306*7fd79137SRobert Mustacchi 	    "\t-d  uniquify merged output against uniqfile\n"
307*7fd79137SRobert Mustacchi 	    "\t-j  use nthrs threads to perform the merge\n"
308*7fd79137SRobert Mustacchi 	    "\t-l  set output container's label to specified value\n"
309*7fd79137SRobert Mustacchi 	    "\t-L  set output container's label to value from environment\n"
310*7fd79137SRobert Mustacchi 	    "\t-o  file to add CTF data to\n"
311*7fd79137SRobert Mustacchi 	    "\t-t  require CTF data from all inputs built from C sources\n",
312*7fd79137SRobert Mustacchi 	    g_progname);
313*7fd79137SRobert Mustacchi }
314*7fd79137SRobert Mustacchi 
315*7fd79137SRobert Mustacchi static void
316*7fd79137SRobert Mustacchi ctfmerge_altexec(char **argv)
317*7fd79137SRobert Mustacchi {
318*7fd79137SRobert Mustacchi 	const char *alt;
319*7fd79137SRobert Mustacchi 	char *altexec;
320*7fd79137SRobert Mustacchi 
321*7fd79137SRobert Mustacchi 	alt = getenv(CTFMERGE_ALTEXEC);
322*7fd79137SRobert Mustacchi 	if (alt == NULL || *alt == '\0')
323*7fd79137SRobert Mustacchi 		return;
324*7fd79137SRobert Mustacchi 
325*7fd79137SRobert Mustacchi 	altexec = strdup(alt);
326*7fd79137SRobert Mustacchi 	if (altexec == NULL)
327*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to allocate memory for altexec\n");
328*7fd79137SRobert Mustacchi 	if (unsetenv(CTFMERGE_ALTEXEC) != 0)
329*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to unset %s from environment: %s\n",
330*7fd79137SRobert Mustacchi 		    CTFMERGE_ALTEXEC, strerror(errno));
331*7fd79137SRobert Mustacchi 
332*7fd79137SRobert Mustacchi 	(void) execv(altexec, argv);
333*7fd79137SRobert Mustacchi 	ctfmerge_fatal("failed to execute alternate program %s: %s",
334*7fd79137SRobert Mustacchi 	    altexec, strerror(errno));
335*7fd79137SRobert Mustacchi }
336*7fd79137SRobert Mustacchi 
337*7fd79137SRobert Mustacchi int
338*7fd79137SRobert Mustacchi main(int argc, char *argv[])
339*7fd79137SRobert Mustacchi {
340*7fd79137SRobert Mustacchi 	int err, i, c, ofd;
341*7fd79137SRobert Mustacchi 	uint_t nthreads = CTFMERGE_DEFAULT_NTHREADS;
342*7fd79137SRobert Mustacchi 	char *tmpfile = NULL, *label = NULL;
343*7fd79137SRobert Mustacchi 	int wflags = CTF_ELFWRITE_F_COMPRESS;
344*7fd79137SRobert Mustacchi 	ctf_file_t *ofp;
345*7fd79137SRobert Mustacchi 	ctf_merge_t *cmh;
346*7fd79137SRobert Mustacchi 	long argj;
347*7fd79137SRobert Mustacchi 	char *eptr;
348*7fd79137SRobert Mustacchi 
349*7fd79137SRobert Mustacchi 	g_progname = basename(argv[0]);
350*7fd79137SRobert Mustacchi 
351*7fd79137SRobert Mustacchi 	ctfmerge_altexec(argv);
352*7fd79137SRobert Mustacchi 
353*7fd79137SRobert Mustacchi 	/*
354*7fd79137SRobert Mustacchi 	 * We support a subset of the old CTF merge flags, mostly for
355*7fd79137SRobert Mustacchi 	 * compatability.
356*7fd79137SRobert Mustacchi 	 */
357*7fd79137SRobert Mustacchi 	while ((c = getopt(argc, argv, ":d:fgj:l:L:o:t")) != -1) {
358*7fd79137SRobert Mustacchi 		switch (c) {
359*7fd79137SRobert Mustacchi 		case 'd':
360*7fd79137SRobert Mustacchi 			g_unique = optarg;
361*7fd79137SRobert Mustacchi 			break;
362*7fd79137SRobert Mustacchi 		case 'f':
363*7fd79137SRobert Mustacchi 			/* Silently ignored for compatibility */
364*7fd79137SRobert Mustacchi 			break;
365*7fd79137SRobert Mustacchi 		case 'g':
366*7fd79137SRobert Mustacchi 			/* Silently ignored for compatibility */
367*7fd79137SRobert Mustacchi 			break;
368*7fd79137SRobert Mustacchi 		case 'j':
369*7fd79137SRobert Mustacchi 			errno = 0;
370*7fd79137SRobert Mustacchi 			argj = strtol(optarg, &eptr, 10);
371*7fd79137SRobert Mustacchi 			if (errno != 0 || argj == LONG_MAX ||
372*7fd79137SRobert Mustacchi 			    argj > 1024 || *eptr != '\0') {
373*7fd79137SRobert Mustacchi 				ctfmerge_fatal("invalid argument for -j: %s\n",
374*7fd79137SRobert Mustacchi 				    optarg);
375*7fd79137SRobert Mustacchi 			}
376*7fd79137SRobert Mustacchi 			nthreads = (uint_t)argj;
377*7fd79137SRobert Mustacchi 			break;
378*7fd79137SRobert Mustacchi 		case 'l':
379*7fd79137SRobert Mustacchi 			label = optarg;
380*7fd79137SRobert Mustacchi 			break;
381*7fd79137SRobert Mustacchi 		case 'L':
382*7fd79137SRobert Mustacchi 			label = getenv(optarg);
383*7fd79137SRobert Mustacchi 			break;
384*7fd79137SRobert Mustacchi 		case 'o':
385*7fd79137SRobert Mustacchi 			g_outfile = optarg;
386*7fd79137SRobert Mustacchi 			break;
387*7fd79137SRobert Mustacchi 		case 't':
388*7fd79137SRobert Mustacchi 			g_req = B_TRUE;
389*7fd79137SRobert Mustacchi 			break;
390*7fd79137SRobert Mustacchi 		case ':':
391*7fd79137SRobert Mustacchi 			ctfmerge_usage("Option -%c requires an operand\n",
392*7fd79137SRobert Mustacchi 			    optopt);
393*7fd79137SRobert Mustacchi 			return (CTFMERGE_USAGE);
394*7fd79137SRobert Mustacchi 		case '?':
395*7fd79137SRobert Mustacchi 			ctfmerge_usage("Unknown option: -%c\n", optopt);
396*7fd79137SRobert Mustacchi 			return (CTFMERGE_USAGE);
397*7fd79137SRobert Mustacchi 		}
398*7fd79137SRobert Mustacchi 	}
399*7fd79137SRobert Mustacchi 
400*7fd79137SRobert Mustacchi 	if (g_outfile == NULL) {
401*7fd79137SRobert Mustacchi 		ctfmerge_usage("missing required -o output file\n");
402*7fd79137SRobert Mustacchi 		return (CTFMERGE_USAGE);
403*7fd79137SRobert Mustacchi 	}
404*7fd79137SRobert Mustacchi 
405*7fd79137SRobert Mustacchi 	(void) elf_version(EV_CURRENT);
406*7fd79137SRobert Mustacchi 
407*7fd79137SRobert Mustacchi 	/*
408*7fd79137SRobert Mustacchi 	 * Obviously this isn't atomic, but at least gives us a good starting
409*7fd79137SRobert Mustacchi 	 * point.
410*7fd79137SRobert Mustacchi 	 */
411*7fd79137SRobert Mustacchi 	if ((ofd = open(g_outfile, O_RDWR)) < 0)
412*7fd79137SRobert Mustacchi 		ctfmerge_fatal("cannot open output file %s: %s\n", g_outfile,
413*7fd79137SRobert Mustacchi 		    strerror(errno));
414*7fd79137SRobert Mustacchi 
415*7fd79137SRobert Mustacchi 	argc -= optind;
416*7fd79137SRobert Mustacchi 	argv += optind;
417*7fd79137SRobert Mustacchi 
418*7fd79137SRobert Mustacchi 	if (argc < 1) {
419*7fd79137SRobert Mustacchi 		ctfmerge_usage("no input files specified");
420*7fd79137SRobert Mustacchi 		return (CTFMERGE_USAGE);
421*7fd79137SRobert Mustacchi 	}
422*7fd79137SRobert Mustacchi 
423*7fd79137SRobert Mustacchi 	cmh = ctf_merge_init(ofd, &err);
424*7fd79137SRobert Mustacchi 	if (cmh == NULL)
425*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to create merge handle: %s\n",
426*7fd79137SRobert Mustacchi 		    ctf_errmsg(err));
427*7fd79137SRobert Mustacchi 
428*7fd79137SRobert Mustacchi 	if ((err = ctf_merge_set_nthreads(cmh, nthreads)) != 0)
429*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to set parallelism to %u: %s\n",
430*7fd79137SRobert Mustacchi 		    nthreads, ctf_errmsg(err));
431*7fd79137SRobert Mustacchi 
432*7fd79137SRobert Mustacchi 	for (i = 0; i < argc; i++) {
433*7fd79137SRobert Mustacchi 		ctf_file_t *ifp;
434*7fd79137SRobert Mustacchi 		int fd;
435*7fd79137SRobert Mustacchi 
436*7fd79137SRobert Mustacchi 		if ((fd = open(argv[i], O_RDONLY)) < 0)
437*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to open file %s: %s\n",
438*7fd79137SRobert Mustacchi 			    argv[i], strerror(errno));
439*7fd79137SRobert Mustacchi 		ifp = ctf_fdopen(fd, &err);
440*7fd79137SRobert Mustacchi 		if (ifp == NULL) {
441*7fd79137SRobert Mustacchi 			Elf *e;
442*7fd79137SRobert Mustacchi 
443*7fd79137SRobert Mustacchi 			if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
444*7fd79137SRobert Mustacchi 				(void) close(fd);
445*7fd79137SRobert Mustacchi 				ctfmerge_fatal("failed to open %s: %s\n",
446*7fd79137SRobert Mustacchi 				    argv[i], ctf_errmsg(err));
447*7fd79137SRobert Mustacchi 			}
448*7fd79137SRobert Mustacchi 
449*7fd79137SRobert Mustacchi 			/*
450*7fd79137SRobert Mustacchi 			 * It's an ELF file, check if we have an archive or if
451*7fd79137SRobert Mustacchi 			 * we're expecting CTF here.
452*7fd79137SRobert Mustacchi 			 */
453*7fd79137SRobert Mustacchi 			switch (elf_kind(e)) {
454*7fd79137SRobert Mustacchi 			case ELF_K_AR:
455*7fd79137SRobert Mustacchi 				break;
456*7fd79137SRobert Mustacchi 			case ELF_K_ELF:
457*7fd79137SRobert Mustacchi 				if (ctfmerge_expect_ctf(argv[i], e) == B_TRUE) {
458*7fd79137SRobert Mustacchi 					(void) elf_end(e);
459*7fd79137SRobert Mustacchi 					(void) close(fd);
460*7fd79137SRobert Mustacchi 					ctfmerge_fatal("failed to "
461*7fd79137SRobert Mustacchi 					    "open %s: file was built from C "
462*7fd79137SRobert Mustacchi 					    "sources, but missing CTF\n",
463*7fd79137SRobert Mustacchi 					    argv[i]);
464*7fd79137SRobert Mustacchi 				}
465*7fd79137SRobert Mustacchi 				(void) elf_end(e);
466*7fd79137SRobert Mustacchi 				(void) close(fd);
467*7fd79137SRobert Mustacchi 				continue;
468*7fd79137SRobert Mustacchi 			default:
469*7fd79137SRobert Mustacchi 				(void) elf_end(e);
470*7fd79137SRobert Mustacchi 				(void) close(fd);
471*7fd79137SRobert Mustacchi 				ctfmerge_fatal("failed to open %s: "
472*7fd79137SRobert Mustacchi 				    "unsupported ELF file type", argv[i]);
473*7fd79137SRobert Mustacchi 			}
474*7fd79137SRobert Mustacchi 
475*7fd79137SRobert Mustacchi 			ctfmerge_read_archive(argv[i], fd, e, cmh);
476*7fd79137SRobert Mustacchi 			(void) elf_end(e);
477*7fd79137SRobert Mustacchi 			(void) close(fd);
478*7fd79137SRobert Mustacchi 			continue;
479*7fd79137SRobert Mustacchi 		}
480*7fd79137SRobert Mustacchi 		(void) close(fd);
481*7fd79137SRobert Mustacchi 		if ((err = ctf_merge_add(cmh, ifp)) != 0)
482*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to add input %s: %s\n",
483*7fd79137SRobert Mustacchi 			    argv[i], ctf_errmsg(err));
484*7fd79137SRobert Mustacchi 		g_nctf++;
485*7fd79137SRobert Mustacchi 	}
486*7fd79137SRobert Mustacchi 
487*7fd79137SRobert Mustacchi 	if (g_nctf == 0) {
488*7fd79137SRobert Mustacchi 		ctf_merge_fini(cmh);
489*7fd79137SRobert Mustacchi 		return (0);
490*7fd79137SRobert Mustacchi 	}
491*7fd79137SRobert Mustacchi 
492*7fd79137SRobert Mustacchi 	if (g_unique != NULL) {
493*7fd79137SRobert Mustacchi 		ctf_file_t *ufp;
494*7fd79137SRobert Mustacchi 		char *base;
495*7fd79137SRobert Mustacchi 
496*7fd79137SRobert Mustacchi 		ufp = ctf_open(g_unique, &err);
497*7fd79137SRobert Mustacchi 		if (ufp == NULL) {
498*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to open uniquify file %s: %s\n",
499*7fd79137SRobert Mustacchi 			    g_unique, ctf_errmsg(err));
500*7fd79137SRobert Mustacchi 		}
501*7fd79137SRobert Mustacchi 
502*7fd79137SRobert Mustacchi 		base = basename(g_unique);
503*7fd79137SRobert Mustacchi 		(void) ctf_merge_uniquify(cmh, ufp, base);
504*7fd79137SRobert Mustacchi 	}
505*7fd79137SRobert Mustacchi 
506*7fd79137SRobert Mustacchi 	if (label != NULL) {
507*7fd79137SRobert Mustacchi 		if ((err = ctf_merge_label(cmh, label)) != 0)
508*7fd79137SRobert Mustacchi 			ctfmerge_fatal("failed to add label %s: %s\n", label,
509*7fd79137SRobert Mustacchi 			    ctf_errmsg(err));
510*7fd79137SRobert Mustacchi 	}
511*7fd79137SRobert Mustacchi 
512*7fd79137SRobert Mustacchi 	err = ctf_merge_merge(cmh, &ofp);
513*7fd79137SRobert Mustacchi 	if (err != 0)
514*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to merge types: %s\n", ctf_errmsg(err));
515*7fd79137SRobert Mustacchi 	ctf_merge_fini(cmh);
516*7fd79137SRobert Mustacchi 
517*7fd79137SRobert Mustacchi 	if (asprintf(&tmpfile, "%s.ctf", g_outfile) == -1)
518*7fd79137SRobert Mustacchi 		ctfmerge_fatal("ran out of memory for temporary file name\n");
519*7fd79137SRobert Mustacchi 	err = ctf_elfwrite(ofp, g_outfile, tmpfile, wflags);
520*7fd79137SRobert Mustacchi 	if (err == CTF_ERR) {
521*7fd79137SRobert Mustacchi 		(void) unlink(tmpfile);
522*7fd79137SRobert Mustacchi 		free(tmpfile);
523*7fd79137SRobert Mustacchi 		ctfmerge_fatal("encountered a libctf error: %s!\n",
524*7fd79137SRobert Mustacchi 		    ctf_errmsg(ctf_errno(ofp)));
525*7fd79137SRobert Mustacchi 	}
526*7fd79137SRobert Mustacchi 
527*7fd79137SRobert Mustacchi 	if (rename(tmpfile, g_outfile) != 0) {
528*7fd79137SRobert Mustacchi 		(void) unlink(tmpfile);
529*7fd79137SRobert Mustacchi 		free(tmpfile);
530*7fd79137SRobert Mustacchi 		ctfmerge_fatal("failed to rename temporary file: %s\n",
531*7fd79137SRobert Mustacchi 		    strerror(errno));
532*7fd79137SRobert Mustacchi 	}
533*7fd79137SRobert Mustacchi 	free(tmpfile);
534*7fd79137SRobert Mustacchi 
535*7fd79137SRobert Mustacchi 	return (CTFMERGE_OK);
536*7fd79137SRobert Mustacchi }
537