1*bc1f688bSRobert Mustacchi /*
2*bc1f688bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*bc1f688bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*bc1f688bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*bc1f688bSRobert Mustacchi  * 1.0 of the CDDL.
6*bc1f688bSRobert Mustacchi  *
7*bc1f688bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*bc1f688bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*bc1f688bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*bc1f688bSRobert Mustacchi  */
11*bc1f688bSRobert Mustacchi 
12*bc1f688bSRobert Mustacchi /*
13*bc1f688bSRobert Mustacchi  * Copyright (c) 2015, Joyent, Inc.
14*bc1f688bSRobert Mustacchi  */
15*bc1f688bSRobert Mustacchi 
16*bc1f688bSRobert Mustacchi /*
17*bc1f688bSRobert Mustacchi  * Create CTF from extant debugging information
18*bc1f688bSRobert Mustacchi  */
19*bc1f688bSRobert Mustacchi 
20*bc1f688bSRobert Mustacchi #include <stdio.h>
21*bc1f688bSRobert Mustacchi #include <unistd.h>
22*bc1f688bSRobert Mustacchi #include <stdlib.h>
23*bc1f688bSRobert Mustacchi #include <stdarg.h>
24*bc1f688bSRobert Mustacchi #include <sys/types.h>
25*bc1f688bSRobert Mustacchi #include <sys/stat.h>
26*bc1f688bSRobert Mustacchi #include <fcntl.h>
27*bc1f688bSRobert Mustacchi #include <errno.h>
28*bc1f688bSRobert Mustacchi #include <libelf.h>
29*bc1f688bSRobert Mustacchi #include <libctf.h>
30*bc1f688bSRobert Mustacchi #include <string.h>
31*bc1f688bSRobert Mustacchi #include <libgen.h>
32*bc1f688bSRobert Mustacchi #include <limits.h>
33*bc1f688bSRobert Mustacchi #include <strings.h>
34*bc1f688bSRobert Mustacchi #include <sys/debug.h>
35*bc1f688bSRobert Mustacchi 
36*bc1f688bSRobert Mustacchi #define	CTFCONVERT_OK		0
37*bc1f688bSRobert Mustacchi #define	CTFCONVERT_FATAL	1
38*bc1f688bSRobert Mustacchi #define	CTFCONVERT_USAGE	2
39*bc1f688bSRobert Mustacchi 
40*bc1f688bSRobert Mustacchi #define	CTFCONVERT_DEFAULT_NTHREADS	4
41*bc1f688bSRobert Mustacchi 
42*bc1f688bSRobert Mustacchi #define	CTFCONVERT_ALTEXEC	"CTFCONVERT_ALTEXEC"
43*bc1f688bSRobert Mustacchi 
44*bc1f688bSRobert Mustacchi static char *ctfconvert_progname;
45*bc1f688bSRobert Mustacchi 
46*bc1f688bSRobert Mustacchi static void
47*bc1f688bSRobert Mustacchi ctfconvert_fatal(const char *fmt, ...)
48*bc1f688bSRobert Mustacchi {
49*bc1f688bSRobert Mustacchi 	va_list ap;
50*bc1f688bSRobert Mustacchi 
51*bc1f688bSRobert Mustacchi 	(void) fprintf(stderr, "%s: ", ctfconvert_progname);
52*bc1f688bSRobert Mustacchi 	va_start(ap, fmt);
53*bc1f688bSRobert Mustacchi 	(void) vfprintf(stderr, fmt, ap);
54*bc1f688bSRobert Mustacchi 	va_end(ap);
55*bc1f688bSRobert Mustacchi 
56*bc1f688bSRobert Mustacchi 	exit(CTFCONVERT_FATAL);
57*bc1f688bSRobert Mustacchi }
58*bc1f688bSRobert Mustacchi 
59*bc1f688bSRobert Mustacchi 
60*bc1f688bSRobert Mustacchi static void
61*bc1f688bSRobert Mustacchi ctfconvert_usage(const char *fmt, ...)
62*bc1f688bSRobert Mustacchi {
63*bc1f688bSRobert Mustacchi 	if (fmt != NULL) {
64*bc1f688bSRobert Mustacchi 		va_list ap;
65*bc1f688bSRobert Mustacchi 
66*bc1f688bSRobert Mustacchi 		(void) fprintf(stderr, "%s: ", ctfconvert_progname);
67*bc1f688bSRobert Mustacchi 		va_start(ap, fmt);
68*bc1f688bSRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
69*bc1f688bSRobert Mustacchi 		va_end(ap);
70*bc1f688bSRobert Mustacchi 	}
71*bc1f688bSRobert Mustacchi 
72*bc1f688bSRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s [-is] [-j nthrs] [-l label | "
73*bc1f688bSRobert Mustacchi 	    "-L labelenv] [-o outfile] input\n"
74*bc1f688bSRobert Mustacchi 	    "\n"
75*bc1f688bSRobert Mustacchi 	    "\t-i  ignore files not built partially from C sources\n"
76*bc1f688bSRobert Mustacchi 	    "\t-j  use nthrs threads to perform the merge\n"
77*bc1f688bSRobert Mustacchi 	    "\t-k  keep around original input file on failure\n"
78*bc1f688bSRobert Mustacchi 	    "\t-o  copy input to outfile and add CTF\n"
79*bc1f688bSRobert Mustacchi 	    "\t-l  set output container's label to specified value\n"
80*bc1f688bSRobert Mustacchi 	    "\t-L  set output container's label to value from environment\n",
81*bc1f688bSRobert Mustacchi 	    ctfconvert_progname);
82*bc1f688bSRobert Mustacchi }
83*bc1f688bSRobert Mustacchi 
84*bc1f688bSRobert Mustacchi /*
85*bc1f688bSRobert Mustacchi  * This is a bit unfortunate. Traditionally we do type uniquification across all
86*bc1f688bSRobert Mustacchi  * modules in the kernel, including ip and unix against genunix. However, when
87*bc1f688bSRobert Mustacchi  * _MACHDEP is defined, then the cpu_t ends up having an additional member
88*bc1f688bSRobert Mustacchi  * (cpu_m), thus changing the ability for us to uniquify against it. This in
89*bc1f688bSRobert Mustacchi  * turn causes a lot of type sprawl, as there's a lot of things that end up
90*bc1f688bSRobert Mustacchi  * referring to the cpu_t and it chains out from there.
91*bc1f688bSRobert Mustacchi  *
92*bc1f688bSRobert Mustacchi  * So, if we find that a cpu_t has been defined and it has a couple of useful
93*bc1f688bSRobert Mustacchi  * sentinel members and it does *not* have the cpu_m member, then we will try
94*bc1f688bSRobert Mustacchi  * and lookup or create a forward declaration to the machcpu, append it to the
95*bc1f688bSRobert Mustacchi  * end, and update the file.
96*bc1f688bSRobert Mustacchi  *
97*bc1f688bSRobert Mustacchi  * This currently is only invoked if an undocumented option -X is passed. This
98*bc1f688bSRobert Mustacchi  * value is private to illumos and it can be changed at any time inside of it,
99*bc1f688bSRobert Mustacchi  * so if -X wants to be used for something, it should be. The ability to rely on
100*bc1f688bSRobert Mustacchi  * -X for others is strictly not an interface in any way, shape, or form.
101*bc1f688bSRobert Mustacchi  *
102*bc1f688bSRobert Mustacchi  * The following struct contains most of the information that we care about and
103*bc1f688bSRobert Mustacchi  * that we want to validate exists before we decide what to do.
104*bc1f688bSRobert Mustacchi  */
105*bc1f688bSRobert Mustacchi 
106*bc1f688bSRobert Mustacchi typedef struct ctfconvert_fixup {
107*bc1f688bSRobert Mustacchi 	boolean_t	cf_cyclic;	/* Do we have a cpu_cyclic member */
108*bc1f688bSRobert Mustacchi 	boolean_t	cf_mcpu;	/* We have a cpu_m member */
109*bc1f688bSRobert Mustacchi 	boolean_t	cf_lastpad;	/* Is the pad member the last entry */
110*bc1f688bSRobert Mustacchi 	ulong_t		cf_padoff;	/* offset of the pad */
111*bc1f688bSRobert Mustacchi } ctfconvert_fixup_t;
112*bc1f688bSRobert Mustacchi 
113*bc1f688bSRobert Mustacchi /* ARGSUSED */
114*bc1f688bSRobert Mustacchi static int
115*bc1f688bSRobert Mustacchi ctfconvert_fixup_genunix_cb(const char *name, ctf_id_t tid, ulong_t off,
116*bc1f688bSRobert Mustacchi     void *arg)
117*bc1f688bSRobert Mustacchi {
118*bc1f688bSRobert Mustacchi 	ctfconvert_fixup_t *cfp = arg;
119*bc1f688bSRobert Mustacchi 
120*bc1f688bSRobert Mustacchi 	cfp->cf_lastpad = B_FALSE;
121*bc1f688bSRobert Mustacchi 	if (strcmp(name, "cpu_cyclic") == 0) {
122*bc1f688bSRobert Mustacchi 		cfp->cf_cyclic = B_TRUE;
123*bc1f688bSRobert Mustacchi 		return (0);
124*bc1f688bSRobert Mustacchi 	}
125*bc1f688bSRobert Mustacchi 
126*bc1f688bSRobert Mustacchi 	if (strcmp(name, "cpu_m") == 0) {
127*bc1f688bSRobert Mustacchi 		cfp->cf_mcpu = B_TRUE;
128*bc1f688bSRobert Mustacchi 		return (0);
129*bc1f688bSRobert Mustacchi 	}
130*bc1f688bSRobert Mustacchi 
131*bc1f688bSRobert Mustacchi 	if (strcmp(name, "cpu_m_pad") == 0) {
132*bc1f688bSRobert Mustacchi 		cfp->cf_lastpad = B_TRUE;
133*bc1f688bSRobert Mustacchi 		cfp->cf_padoff = off;
134*bc1f688bSRobert Mustacchi 		return (0);
135*bc1f688bSRobert Mustacchi 	}
136*bc1f688bSRobert Mustacchi 
137*bc1f688bSRobert Mustacchi 	return (0);
138*bc1f688bSRobert Mustacchi }
139*bc1f688bSRobert Mustacchi 
140*bc1f688bSRobert Mustacchi static void
141*bc1f688bSRobert Mustacchi ctfconvert_fixup_genunix(ctf_file_t *fp)
142*bc1f688bSRobert Mustacchi {
143*bc1f688bSRobert Mustacchi 	ctf_id_t cpuid, mcpu;
144*bc1f688bSRobert Mustacchi 	ssize_t sz;
145*bc1f688bSRobert Mustacchi 	ctfconvert_fixup_t cf;
146*bc1f688bSRobert Mustacchi 	int model, ptrsz;
147*bc1f688bSRobert Mustacchi 
148*bc1f688bSRobert Mustacchi 	cpuid = ctf_lookup_by_name(fp, "struct cpu");
149*bc1f688bSRobert Mustacchi 	if (cpuid == CTF_ERR)
150*bc1f688bSRobert Mustacchi 		return;
151*bc1f688bSRobert Mustacchi 
152*bc1f688bSRobert Mustacchi 	if (ctf_type_kind(fp, cpuid) != CTF_K_STRUCT)
153*bc1f688bSRobert Mustacchi 		return;
154*bc1f688bSRobert Mustacchi 
155*bc1f688bSRobert Mustacchi 	if ((sz = ctf_type_size(fp, cpuid)) == CTF_ERR)
156*bc1f688bSRobert Mustacchi 		return;
157*bc1f688bSRobert Mustacchi 
158*bc1f688bSRobert Mustacchi 	model = ctf_getmodel(fp);
159*bc1f688bSRobert Mustacchi 	VERIFY(model == CTF_MODEL_ILP32 || model == CTF_MODEL_LP64);
160*bc1f688bSRobert Mustacchi 	ptrsz = model == CTF_MODEL_ILP32 ? 4 : 8;
161*bc1f688bSRobert Mustacchi 
162*bc1f688bSRobert Mustacchi 	bzero(&cf, sizeof (ctfconvert_fixup_t));
163*bc1f688bSRobert Mustacchi 	if (ctf_member_iter(fp, cpuid, ctfconvert_fixup_genunix_cb, &cf) ==
164*bc1f688bSRobert Mustacchi 	    CTF_ERR)
165*bc1f688bSRobert Mustacchi 		return;
166*bc1f688bSRobert Mustacchi 
167*bc1f688bSRobert Mustacchi 	/*
168*bc1f688bSRobert Mustacchi 	 * Finally, we want to verify that the cpu_m is actually the last member
169*bc1f688bSRobert Mustacchi 	 * that we have here.
170*bc1f688bSRobert Mustacchi 	 */
171*bc1f688bSRobert Mustacchi 	if (cf.cf_cyclic == B_FALSE || cf.cf_mcpu == B_TRUE ||
172*bc1f688bSRobert Mustacchi 	    cf.cf_lastpad == B_FALSE) {
173*bc1f688bSRobert Mustacchi 		return;
174*bc1f688bSRobert Mustacchi 	}
175*bc1f688bSRobert Mustacchi 
176*bc1f688bSRobert Mustacchi 	if (cf.cf_padoff + ptrsz * NBBY != sz * NBBY) {
177*bc1f688bSRobert Mustacchi 		return;
178*bc1f688bSRobert Mustacchi 	}
179*bc1f688bSRobert Mustacchi 
180*bc1f688bSRobert Mustacchi 	/*
181*bc1f688bSRobert Mustacchi 	 * Okay, we're going to do this, try to find a struct machcpu. We either
182*bc1f688bSRobert Mustacchi 	 * want a forward or a struct. If we find something else, error. If we
183*bc1f688bSRobert Mustacchi 	 * find nothing, add a forward and then add the member.
184*bc1f688bSRobert Mustacchi 	 */
185*bc1f688bSRobert Mustacchi 	mcpu = ctf_lookup_by_name(fp, "struct machcpu");
186*bc1f688bSRobert Mustacchi 	if (mcpu == CTF_ERR) {
187*bc1f688bSRobert Mustacchi 		mcpu = ctf_add_forward(fp, CTF_ADD_NONROOT, "machcpu",
188*bc1f688bSRobert Mustacchi 		    CTF_K_STRUCT);
189*bc1f688bSRobert Mustacchi 		if (mcpu == CTF_ERR) {
190*bc1f688bSRobert Mustacchi 			ctfconvert_fatal("failed to add 'struct machcpu' "
191*bc1f688bSRobert Mustacchi 			    "forward: %s", ctf_errmsg(ctf_errno(fp)));
192*bc1f688bSRobert Mustacchi 		}
193*bc1f688bSRobert Mustacchi 	} else {
194*bc1f688bSRobert Mustacchi 		int kind;
195*bc1f688bSRobert Mustacchi 		if ((kind = ctf_type_kind(fp, mcpu)) == CTF_ERR) {
196*bc1f688bSRobert Mustacchi 			ctfconvert_fatal("failed to get the type kind for "
197*bc1f688bSRobert Mustacchi 			    "the struct machcpu: %s",
198*bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(fp)));
199*bc1f688bSRobert Mustacchi 		}
200*bc1f688bSRobert Mustacchi 
201*bc1f688bSRobert Mustacchi 		if (kind != CTF_K_STRUCT && kind != CTF_K_FORWARD)
202*bc1f688bSRobert Mustacchi 			ctfconvert_fatal("encountered a struct machcpu of the "
203*bc1f688bSRobert Mustacchi 			    "wrong type, found type kind %d\n", kind);
204*bc1f688bSRobert Mustacchi 	}
205*bc1f688bSRobert Mustacchi 
206*bc1f688bSRobert Mustacchi 	if (ctf_update(fp) == CTF_ERR) {
207*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to update output file: %s\n",
208*bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(fp)));
209*bc1f688bSRobert Mustacchi 	}
210*bc1f688bSRobert Mustacchi 
211*bc1f688bSRobert Mustacchi 	if (ctf_add_member(fp, cpuid, "cpu_m", mcpu, sz * NBBY) == CTF_ERR) {
212*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to add the m_cpu member: %s\n",
213*bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(fp)));
214*bc1f688bSRobert Mustacchi 	}
215*bc1f688bSRobert Mustacchi 
216*bc1f688bSRobert Mustacchi 	if (ctf_update(fp) == CTF_ERR) {
217*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to update output file: %s\n",
218*bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(fp)));
219*bc1f688bSRobert Mustacchi 	}
220*bc1f688bSRobert Mustacchi 
221*bc1f688bSRobert Mustacchi 	VERIFY(ctf_type_size(fp, cpuid) == sz);
222*bc1f688bSRobert Mustacchi }
223*bc1f688bSRobert Mustacchi 
224*bc1f688bSRobert Mustacchi static void
225*bc1f688bSRobert Mustacchi ctfconvert_altexec(char **argv)
226*bc1f688bSRobert Mustacchi {
227*bc1f688bSRobert Mustacchi 	const char *alt;
228*bc1f688bSRobert Mustacchi 	char *altexec;
229*bc1f688bSRobert Mustacchi 
230*bc1f688bSRobert Mustacchi 	alt = getenv(CTFCONVERT_ALTEXEC);
231*bc1f688bSRobert Mustacchi 	if (alt == NULL || *alt == '\0')
232*bc1f688bSRobert Mustacchi 		return;
233*bc1f688bSRobert Mustacchi 
234*bc1f688bSRobert Mustacchi 	altexec = strdup(alt);
235*bc1f688bSRobert Mustacchi 	if (altexec == NULL)
236*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to allocate memory for altexec\n");
237*bc1f688bSRobert Mustacchi 	if (unsetenv(CTFCONVERT_ALTEXEC) != 0)
238*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to unset %s from environment: %s\n",
239*bc1f688bSRobert Mustacchi 		    CTFCONVERT_ALTEXEC, strerror(errno));
240*bc1f688bSRobert Mustacchi 
241*bc1f688bSRobert Mustacchi 	(void) execv(altexec, argv);
242*bc1f688bSRobert Mustacchi 	ctfconvert_fatal("failed to execute alternate program %s: %s",
243*bc1f688bSRobert Mustacchi 	    altexec, strerror(errno));
244*bc1f688bSRobert Mustacchi }
245*bc1f688bSRobert Mustacchi 
246*bc1f688bSRobert Mustacchi int
247*bc1f688bSRobert Mustacchi main(int argc, char *argv[])
248*bc1f688bSRobert Mustacchi {
249*bc1f688bSRobert Mustacchi 	int c, ifd, err;
250*bc1f688bSRobert Mustacchi 	boolean_t keep = B_FALSE;
251*bc1f688bSRobert Mustacchi 	uint_t flags = 0;
252*bc1f688bSRobert Mustacchi 	uint_t nthreads = CTFCONVERT_DEFAULT_NTHREADS;
253*bc1f688bSRobert Mustacchi 	const char *outfile = NULL;
254*bc1f688bSRobert Mustacchi 	const char *label = NULL;
255*bc1f688bSRobert Mustacchi 	const char *infile = NULL;
256*bc1f688bSRobert Mustacchi 	char *tmpfile;
257*bc1f688bSRobert Mustacchi 	ctf_file_t *ofp;
258*bc1f688bSRobert Mustacchi 	long argj;
259*bc1f688bSRobert Mustacchi 	char *eptr;
260*bc1f688bSRobert Mustacchi 	char buf[4096];
261*bc1f688bSRobert Mustacchi 	boolean_t optx = B_FALSE;
262*bc1f688bSRobert Mustacchi 
263*bc1f688bSRobert Mustacchi 	ctfconvert_progname = basename(argv[0]);
264*bc1f688bSRobert Mustacchi 
265*bc1f688bSRobert Mustacchi 	ctfconvert_altexec(argv);
266*bc1f688bSRobert Mustacchi 
267*bc1f688bSRobert Mustacchi 	while ((c = getopt(argc, argv, ":j:kl:L:o:iX")) != -1) {
268*bc1f688bSRobert Mustacchi 		switch (c) {
269*bc1f688bSRobert Mustacchi 		case 'k':
270*bc1f688bSRobert Mustacchi 			keep = B_TRUE;
271*bc1f688bSRobert Mustacchi 			break;
272*bc1f688bSRobert Mustacchi 		case 'l':
273*bc1f688bSRobert Mustacchi 			label = optarg;
274*bc1f688bSRobert Mustacchi 			break;
275*bc1f688bSRobert Mustacchi 		case 'L':
276*bc1f688bSRobert Mustacchi 			label = getenv(optarg);
277*bc1f688bSRobert Mustacchi 			break;
278*bc1f688bSRobert Mustacchi 		case 'j':
279*bc1f688bSRobert Mustacchi 			errno = 0;
280*bc1f688bSRobert Mustacchi 			argj = strtol(optarg, &eptr, 10);
281*bc1f688bSRobert Mustacchi 			if (errno != 0 || argj == LONG_MAX ||
282*bc1f688bSRobert Mustacchi 			    argj > 1024 || *eptr != '\0') {
283*bc1f688bSRobert Mustacchi 				ctfconvert_fatal("invalid argument for -j: "
284*bc1f688bSRobert Mustacchi 				    "%s\n", optarg);
285*bc1f688bSRobert Mustacchi 			}
286*bc1f688bSRobert Mustacchi 			nthreads = (uint_t)argj;
287*bc1f688bSRobert Mustacchi 			break;
288*bc1f688bSRobert Mustacchi 		case 'o':
289*bc1f688bSRobert Mustacchi 			outfile = optarg;
290*bc1f688bSRobert Mustacchi 			break;
291*bc1f688bSRobert Mustacchi 		case 'i':
292*bc1f688bSRobert Mustacchi 			flags |= CTF_CONVERT_F_IGNNONC;
293*bc1f688bSRobert Mustacchi 			break;
294*bc1f688bSRobert Mustacchi 		case 'X':
295*bc1f688bSRobert Mustacchi 			optx = B_TRUE;
296*bc1f688bSRobert Mustacchi 			break;
297*bc1f688bSRobert Mustacchi 		case ':':
298*bc1f688bSRobert Mustacchi 			ctfconvert_usage("Option -%c requires an operand\n",
299*bc1f688bSRobert Mustacchi 			    optopt);
300*bc1f688bSRobert Mustacchi 			return (CTFCONVERT_USAGE);
301*bc1f688bSRobert Mustacchi 		case '?':
302*bc1f688bSRobert Mustacchi 			ctfconvert_usage("Unknown option: -%c\n", optopt);
303*bc1f688bSRobert Mustacchi 			return (CTFCONVERT_USAGE);
304*bc1f688bSRobert Mustacchi 		}
305*bc1f688bSRobert Mustacchi 	}
306*bc1f688bSRobert Mustacchi 
307*bc1f688bSRobert Mustacchi 	argv += optind;
308*bc1f688bSRobert Mustacchi 	argc -= optind;
309*bc1f688bSRobert Mustacchi 
310*bc1f688bSRobert Mustacchi 	if (argc < 1) {
311*bc1f688bSRobert Mustacchi 		ctfconvert_usage("Missing required input file\n");
312*bc1f688bSRobert Mustacchi 		return (CTFCONVERT_USAGE);
313*bc1f688bSRobert Mustacchi 	}
314*bc1f688bSRobert Mustacchi 	infile = argv[0];
315*bc1f688bSRobert Mustacchi 
316*bc1f688bSRobert Mustacchi 	if (elf_version(EV_CURRENT) == EV_NONE)
317*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to initialize libelf: library is "
318*bc1f688bSRobert Mustacchi 		    "out of date\n");
319*bc1f688bSRobert Mustacchi 
320*bc1f688bSRobert Mustacchi 	ifd = open(infile, O_RDONLY);
321*bc1f688bSRobert Mustacchi 	if (ifd < 0) {
322*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to open input file %s: %s\n", infile,
323*bc1f688bSRobert Mustacchi 		    strerror(errno));
324*bc1f688bSRobert Mustacchi 	}
325*bc1f688bSRobert Mustacchi 
326*bc1f688bSRobert Mustacchi 	/*
327*bc1f688bSRobert Mustacchi 	 * By default we remove the input file on failure unless we've been
328*bc1f688bSRobert Mustacchi 	 * given an output file or -k has been specified.
329*bc1f688bSRobert Mustacchi 	 */
330*bc1f688bSRobert Mustacchi 	if (outfile != NULL && strcmp(infile, outfile) != 0)
331*bc1f688bSRobert Mustacchi 		keep = B_TRUE;
332*bc1f688bSRobert Mustacchi 
333*bc1f688bSRobert Mustacchi 	ofp = ctf_fdconvert(ifd, label, nthreads, flags, &err, buf,
334*bc1f688bSRobert Mustacchi 	    sizeof (buf));
335*bc1f688bSRobert Mustacchi 	if (ofp == NULL) {
336*bc1f688bSRobert Mustacchi 		/*
337*bc1f688bSRobert Mustacchi 		 * -i says that we shouldn't concern ourselves with source files
338*bc1f688bSRobert Mustacchi 		 * that weren't built from C source code in part. Because this
339*bc1f688bSRobert Mustacchi 		 * has been traditionally used across all of illumos, we still
340*bc1f688bSRobert Mustacchi 		 * honor it.
341*bc1f688bSRobert Mustacchi 		 */
342*bc1f688bSRobert Mustacchi 		if ((flags & CTF_CONVERT_F_IGNNONC) != 0 &&
343*bc1f688bSRobert Mustacchi 		    err == ECTF_CONVNOCSRC) {
344*bc1f688bSRobert Mustacchi 			exit(CTFCONVERT_OK);
345*bc1f688bSRobert Mustacchi 		}
346*bc1f688bSRobert Mustacchi 		if (keep == B_FALSE)
347*bc1f688bSRobert Mustacchi 			(void) unlink(infile);
348*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("CTF conversion failed: %s\n",
349*bc1f688bSRobert Mustacchi 		    err == ECTF_CONVBKERR ? buf : ctf_errmsg(err));
350*bc1f688bSRobert Mustacchi 	}
351*bc1f688bSRobert Mustacchi 
352*bc1f688bSRobert Mustacchi 	if (optx == B_TRUE)
353*bc1f688bSRobert Mustacchi 		ctfconvert_fixup_genunix(ofp);
354*bc1f688bSRobert Mustacchi 
355*bc1f688bSRobert Mustacchi 	tmpfile = NULL;
356*bc1f688bSRobert Mustacchi 	if (outfile == NULL || strcmp(infile, outfile) == 0) {
357*bc1f688bSRobert Mustacchi 		if (asprintf(&tmpfile, "%s.ctf", infile) == -1) {
358*bc1f688bSRobert Mustacchi 			if (keep == B_FALSE)
359*bc1f688bSRobert Mustacchi 				(void) unlink(infile);
360*bc1f688bSRobert Mustacchi 			ctfconvert_fatal("failed to allocate memory for "
361*bc1f688bSRobert Mustacchi 			    "temporary file: %s\n", strerror(errno));
362*bc1f688bSRobert Mustacchi 		}
363*bc1f688bSRobert Mustacchi 		outfile = tmpfile;
364*bc1f688bSRobert Mustacchi 	}
365*bc1f688bSRobert Mustacchi 	err = ctf_elfwrite(ofp, infile, outfile, CTF_ELFWRITE_F_COMPRESS);
366*bc1f688bSRobert Mustacchi 	if (err == CTF_ERR) {
367*bc1f688bSRobert Mustacchi 		(void) unlink(outfile);
368*bc1f688bSRobert Mustacchi 		if (keep == B_FALSE)
369*bc1f688bSRobert Mustacchi 			(void) unlink(infile);
370*bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to write CTF section to output file: "
371*bc1f688bSRobert Mustacchi 		    "%s", ctf_errmsg(ctf_errno(ofp)));
372*bc1f688bSRobert Mustacchi 	}
373*bc1f688bSRobert Mustacchi 	ctf_close(ofp);
374*bc1f688bSRobert Mustacchi 
375*bc1f688bSRobert Mustacchi 	if (tmpfile != NULL) {
376*bc1f688bSRobert Mustacchi 		if (rename(tmpfile, infile) != 0) {
377*bc1f688bSRobert Mustacchi 			int e = errno;
378*bc1f688bSRobert Mustacchi 			(void) unlink(outfile);
379*bc1f688bSRobert Mustacchi 			if (keep == B_FALSE)
380*bc1f688bSRobert Mustacchi 				(void) unlink(infile);
381*bc1f688bSRobert Mustacchi 			ctfconvert_fatal("failed to rename temporary file: "
382*bc1f688bSRobert Mustacchi 			    "%s\n", strerror(e));
383*bc1f688bSRobert Mustacchi 		}
384*bc1f688bSRobert Mustacchi 	}
385*bc1f688bSRobert Mustacchi 	free(tmpfile);
386*bc1f688bSRobert Mustacchi 
387*bc1f688bSRobert Mustacchi 	return (CTFCONVERT_OK);
388*bc1f688bSRobert Mustacchi }
389