1bc1f688bSRobert Mustacchi /*
2bc1f688bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3bc1f688bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4bc1f688bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5bc1f688bSRobert Mustacchi  * 1.0 of the CDDL.
6bc1f688bSRobert Mustacchi  *
7bc1f688bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8bc1f688bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9bc1f688bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10bc1f688bSRobert Mustacchi  */
11bc1f688bSRobert Mustacchi 
12bc1f688bSRobert Mustacchi /*
13ce115d25SJohn Levon  * Copyright 2019 Joyent, Inc.
14*dd442252SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
15bc1f688bSRobert Mustacchi  */
16bc1f688bSRobert Mustacchi 
17bc1f688bSRobert Mustacchi /*
18bc1f688bSRobert Mustacchi  * Create CTF from extant debugging information
19bc1f688bSRobert Mustacchi  */
20bc1f688bSRobert Mustacchi 
21bc1f688bSRobert Mustacchi #include <stdio.h>
22bc1f688bSRobert Mustacchi #include <unistd.h>
23bc1f688bSRobert Mustacchi #include <stdlib.h>
24bc1f688bSRobert Mustacchi #include <stdarg.h>
25bc1f688bSRobert Mustacchi #include <sys/types.h>
26bc1f688bSRobert Mustacchi #include <sys/stat.h>
27bc1f688bSRobert Mustacchi #include <fcntl.h>
28bc1f688bSRobert Mustacchi #include <errno.h>
29bc1f688bSRobert Mustacchi #include <libelf.h>
30bc1f688bSRobert Mustacchi #include <libctf.h>
31bc1f688bSRobert Mustacchi #include <string.h>
32bc1f688bSRobert Mustacchi #include <libgen.h>
33bc1f688bSRobert Mustacchi #include <limits.h>
34bc1f688bSRobert Mustacchi #include <strings.h>
35bc1f688bSRobert Mustacchi #include <sys/debug.h>
36bc1f688bSRobert Mustacchi 
37bc1f688bSRobert Mustacchi #define	CTFCONVERT_OK		0
38bc1f688bSRobert Mustacchi #define	CTFCONVERT_FATAL	1
39bc1f688bSRobert Mustacchi #define	CTFCONVERT_USAGE	2
40bc1f688bSRobert Mustacchi 
41bc1f688bSRobert Mustacchi static char *ctfconvert_progname;
42bc1f688bSRobert Mustacchi 
43bc1f688bSRobert Mustacchi static void
44bc1f688bSRobert Mustacchi ctfconvert_fatal(const char *fmt, ...)
45bc1f688bSRobert Mustacchi {
46bc1f688bSRobert Mustacchi 	va_list ap;
47bc1f688bSRobert Mustacchi 
48bc1f688bSRobert Mustacchi 	(void) fprintf(stderr, "%s: ", ctfconvert_progname);
49bc1f688bSRobert Mustacchi 	va_start(ap, fmt);
50bc1f688bSRobert Mustacchi 	(void) vfprintf(stderr, fmt, ap);
51bc1f688bSRobert Mustacchi 	va_end(ap);
52bc1f688bSRobert Mustacchi 
53bc1f688bSRobert Mustacchi 	exit(CTFCONVERT_FATAL);
54bc1f688bSRobert Mustacchi }
55bc1f688bSRobert Mustacchi 
56*dd442252SAndy Fiddaman static void
57*dd442252SAndy Fiddaman ctfconvert_warning(void *arg, const char *fmt, ...)
58*dd442252SAndy Fiddaman {
59*dd442252SAndy Fiddaman 	va_list ap;
60*dd442252SAndy Fiddaman 	char *buf;
61*dd442252SAndy Fiddaman 
62*dd442252SAndy Fiddaman 	va_start(ap, fmt);
63*dd442252SAndy Fiddaman 	if (vasprintf(&buf, fmt, ap) != -1) {
64*dd442252SAndy Fiddaman 		(void) fprintf(stderr, "%s: WARNING: %s", ctfconvert_progname,
65*dd442252SAndy Fiddaman 		    buf);
66*dd442252SAndy Fiddaman 		free(buf);
67*dd442252SAndy Fiddaman 	}
68*dd442252SAndy Fiddaman 	va_end(ap);
69*dd442252SAndy Fiddaman }
70bc1f688bSRobert Mustacchi 
71bc1f688bSRobert Mustacchi static void
72bc1f688bSRobert Mustacchi ctfconvert_usage(const char *fmt, ...)
73bc1f688bSRobert Mustacchi {
74bc1f688bSRobert Mustacchi 	if (fmt != NULL) {
75bc1f688bSRobert Mustacchi 		va_list ap;
76bc1f688bSRobert Mustacchi 
77bc1f688bSRobert Mustacchi 		(void) fprintf(stderr, "%s: ", ctfconvert_progname);
78bc1f688bSRobert Mustacchi 		va_start(ap, fmt);
79bc1f688bSRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
80bc1f688bSRobert Mustacchi 		va_end(ap);
81bc1f688bSRobert Mustacchi 	}
82bc1f688bSRobert Mustacchi 
83*dd442252SAndy Fiddaman 	(void) fprintf(stderr, "Usage: %s [-ikms] [-j nthrs] [-l label | "
84effb27eeSAndy Fiddaman 	    "-L labelenv] [-b batchsize]\n"
85effb27eeSAndy Fiddaman 	    "                  [-o outfile] input\n"
86bc1f688bSRobert Mustacchi 	    "\n"
87effb27eeSAndy Fiddaman 	    "\t-b  batch process this many dies at a time (default %d)\n"
88bc1f688bSRobert Mustacchi 	    "\t-i  ignore files not built partially from C sources\n"
89effb27eeSAndy Fiddaman 	    "\t-j  use nthrs threads to perform the merge (default %d)\n"
90bc1f688bSRobert Mustacchi 	    "\t-k  keep around original input file on failure\n"
91bc1f688bSRobert Mustacchi 	    "\t-l  set output container's label to specified value\n"
92effb27eeSAndy Fiddaman 	    "\t-L  set output container's label to value from environment\n"
93effb27eeSAndy Fiddaman 	    "\t-m  allow input to have missing debug info\n"
94*dd442252SAndy Fiddaman 	    "\t-o  copy input to outfile and add CTF\n"
95*dd442252SAndy Fiddaman 	    "\t-s  allow truncation of data that cannot be fully converted\n",
96effb27eeSAndy Fiddaman 	    ctfconvert_progname,
97*dd442252SAndy Fiddaman 	    CTF_CONVERT_DEFAULT_BATCHSIZE,
98*dd442252SAndy Fiddaman 	    CTF_CONVERT_DEFAULT_NTHREADS);
99bc1f688bSRobert Mustacchi }
100bc1f688bSRobert Mustacchi 
101bc1f688bSRobert Mustacchi /*
102bc1f688bSRobert Mustacchi  * This is a bit unfortunate. Traditionally we do type uniquification across all
103bc1f688bSRobert Mustacchi  * modules in the kernel, including ip and unix against genunix. However, when
104bc1f688bSRobert Mustacchi  * _MACHDEP is defined, then the cpu_t ends up having an additional member
105bc1f688bSRobert Mustacchi  * (cpu_m), thus changing the ability for us to uniquify against it. This in
106bc1f688bSRobert Mustacchi  * turn causes a lot of type sprawl, as there's a lot of things that end up
107bc1f688bSRobert Mustacchi  * referring to the cpu_t and it chains out from there.
108bc1f688bSRobert Mustacchi  *
109bc1f688bSRobert Mustacchi  * So, if we find that a cpu_t has been defined and it has a couple of useful
110bc1f688bSRobert Mustacchi  * sentinel members and it does *not* have the cpu_m member, then we will try
111bc1f688bSRobert Mustacchi  * and lookup or create a forward declaration to the machcpu, append it to the
112bc1f688bSRobert Mustacchi  * end, and update the file.
113bc1f688bSRobert Mustacchi  *
114bc1f688bSRobert Mustacchi  * This currently is only invoked if an undocumented option -X is passed. This
115bc1f688bSRobert Mustacchi  * value is private to illumos and it can be changed at any time inside of it,
116bc1f688bSRobert Mustacchi  * so if -X wants to be used for something, it should be. The ability to rely on
117bc1f688bSRobert Mustacchi  * -X for others is strictly not an interface in any way, shape, or form.
118bc1f688bSRobert Mustacchi  *
119bc1f688bSRobert Mustacchi  * The following struct contains most of the information that we care about and
120bc1f688bSRobert Mustacchi  * that we want to validate exists before we decide what to do.
121bc1f688bSRobert Mustacchi  */
122bc1f688bSRobert Mustacchi 
123bc1f688bSRobert Mustacchi typedef struct ctfconvert_fixup {
124bc1f688bSRobert Mustacchi 	boolean_t	cf_cyclic;	/* Do we have a cpu_cyclic member */
125bc1f688bSRobert Mustacchi 	boolean_t	cf_mcpu;	/* We have a cpu_m member */
126bc1f688bSRobert Mustacchi 	boolean_t	cf_lastpad;	/* Is the pad member the last entry */
127bc1f688bSRobert Mustacchi 	ulong_t		cf_padoff;	/* offset of the pad */
128bc1f688bSRobert Mustacchi } ctfconvert_fixup_t;
129bc1f688bSRobert Mustacchi 
130bc1f688bSRobert Mustacchi /* ARGSUSED */
131bc1f688bSRobert Mustacchi static int
132bc1f688bSRobert Mustacchi ctfconvert_fixup_genunix_cb(const char *name, ctf_id_t tid, ulong_t off,
133bc1f688bSRobert Mustacchi     void *arg)
134bc1f688bSRobert Mustacchi {
135bc1f688bSRobert Mustacchi 	ctfconvert_fixup_t *cfp = arg;
136bc1f688bSRobert Mustacchi 
137bc1f688bSRobert Mustacchi 	cfp->cf_lastpad = B_FALSE;
138bc1f688bSRobert Mustacchi 	if (strcmp(name, "cpu_cyclic") == 0) {
139bc1f688bSRobert Mustacchi 		cfp->cf_cyclic = B_TRUE;
140bc1f688bSRobert Mustacchi 		return (0);
141bc1f688bSRobert Mustacchi 	}
142bc1f688bSRobert Mustacchi 
143bc1f688bSRobert Mustacchi 	if (strcmp(name, "cpu_m") == 0) {
144bc1f688bSRobert Mustacchi 		cfp->cf_mcpu = B_TRUE;
145bc1f688bSRobert Mustacchi 		return (0);
146bc1f688bSRobert Mustacchi 	}
147bc1f688bSRobert Mustacchi 
148bc1f688bSRobert Mustacchi 	if (strcmp(name, "cpu_m_pad") == 0) {
149bc1f688bSRobert Mustacchi 		cfp->cf_lastpad = B_TRUE;
150bc1f688bSRobert Mustacchi 		cfp->cf_padoff = off;
151bc1f688bSRobert Mustacchi 		return (0);
152bc1f688bSRobert Mustacchi 	}
153bc1f688bSRobert Mustacchi 
154bc1f688bSRobert Mustacchi 	return (0);
155bc1f688bSRobert Mustacchi }
156bc1f688bSRobert Mustacchi 
157bc1f688bSRobert Mustacchi static void
158bc1f688bSRobert Mustacchi ctfconvert_fixup_genunix(ctf_file_t *fp)
159bc1f688bSRobert Mustacchi {
160bc1f688bSRobert Mustacchi 	ctf_id_t cpuid, mcpu;
161bc1f688bSRobert Mustacchi 	ssize_t sz;
162bc1f688bSRobert Mustacchi 	ctfconvert_fixup_t cf;
163bc1f688bSRobert Mustacchi 	int model, ptrsz;
164bc1f688bSRobert Mustacchi 
165bc1f688bSRobert Mustacchi 	cpuid = ctf_lookup_by_name(fp, "struct cpu");
166bc1f688bSRobert Mustacchi 	if (cpuid == CTF_ERR)
167bc1f688bSRobert Mustacchi 		return;
168bc1f688bSRobert Mustacchi 
169bc1f688bSRobert Mustacchi 	if (ctf_type_kind(fp, cpuid) != CTF_K_STRUCT)
170bc1f688bSRobert Mustacchi 		return;
171bc1f688bSRobert Mustacchi 
172bc1f688bSRobert Mustacchi 	if ((sz = ctf_type_size(fp, cpuid)) == CTF_ERR)
173bc1f688bSRobert Mustacchi 		return;
174bc1f688bSRobert Mustacchi 
175bc1f688bSRobert Mustacchi 	model = ctf_getmodel(fp);
176bc1f688bSRobert Mustacchi 	VERIFY(model == CTF_MODEL_ILP32 || model == CTF_MODEL_LP64);
177bc1f688bSRobert Mustacchi 	ptrsz = model == CTF_MODEL_ILP32 ? 4 : 8;
178bc1f688bSRobert Mustacchi 
179bc1f688bSRobert Mustacchi 	bzero(&cf, sizeof (ctfconvert_fixup_t));
180bc1f688bSRobert Mustacchi 	if (ctf_member_iter(fp, cpuid, ctfconvert_fixup_genunix_cb, &cf) ==
181bc1f688bSRobert Mustacchi 	    CTF_ERR)
182bc1f688bSRobert Mustacchi 		return;
183bc1f688bSRobert Mustacchi 
184bc1f688bSRobert Mustacchi 	/*
185bc1f688bSRobert Mustacchi 	 * Finally, we want to verify that the cpu_m is actually the last member
186bc1f688bSRobert Mustacchi 	 * that we have here.
187bc1f688bSRobert Mustacchi 	 */
188bc1f688bSRobert Mustacchi 	if (cf.cf_cyclic == B_FALSE || cf.cf_mcpu == B_TRUE ||
189bc1f688bSRobert Mustacchi 	    cf.cf_lastpad == B_FALSE) {
190bc1f688bSRobert Mustacchi 		return;
191bc1f688bSRobert Mustacchi 	}
192bc1f688bSRobert Mustacchi 
193bc1f688bSRobert Mustacchi 	if (cf.cf_padoff + ptrsz * NBBY != sz * NBBY) {
194bc1f688bSRobert Mustacchi 		return;
195bc1f688bSRobert Mustacchi 	}
196bc1f688bSRobert Mustacchi 
197bc1f688bSRobert Mustacchi 	/*
198bc1f688bSRobert Mustacchi 	 * Okay, we're going to do this, try to find a struct machcpu. We either
199bc1f688bSRobert Mustacchi 	 * want a forward or a struct. If we find something else, error. If we
200bc1f688bSRobert Mustacchi 	 * find nothing, add a forward and then add the member.
201bc1f688bSRobert Mustacchi 	 */
202bc1f688bSRobert Mustacchi 	mcpu = ctf_lookup_by_name(fp, "struct machcpu");
203bc1f688bSRobert Mustacchi 	if (mcpu == CTF_ERR) {
204bc1f688bSRobert Mustacchi 		mcpu = ctf_add_forward(fp, CTF_ADD_NONROOT, "machcpu",
205bc1f688bSRobert Mustacchi 		    CTF_K_STRUCT);
206bc1f688bSRobert Mustacchi 		if (mcpu == CTF_ERR) {
207bc1f688bSRobert Mustacchi 			ctfconvert_fatal("failed to add 'struct machcpu' "
208*dd442252SAndy Fiddaman 			    "forward: %s\n", ctf_errmsg(ctf_errno(fp)));
209bc1f688bSRobert Mustacchi 		}
210bc1f688bSRobert Mustacchi 	} else {
211bc1f688bSRobert Mustacchi 		int kind;
212bc1f688bSRobert Mustacchi 		if ((kind = ctf_type_kind(fp, mcpu)) == CTF_ERR) {
213bc1f688bSRobert Mustacchi 			ctfconvert_fatal("failed to get the type kind for "
214*dd442252SAndy Fiddaman 			    "the struct machcpu: %s\n",
215bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(fp)));
216bc1f688bSRobert Mustacchi 		}
217bc1f688bSRobert Mustacchi 
218bc1f688bSRobert Mustacchi 		if (kind != CTF_K_STRUCT && kind != CTF_K_FORWARD)
219bc1f688bSRobert Mustacchi 			ctfconvert_fatal("encountered a struct machcpu of the "
220bc1f688bSRobert Mustacchi 			    "wrong type, found type kind %d\n", kind);
221bc1f688bSRobert Mustacchi 	}
222bc1f688bSRobert Mustacchi 
223bc1f688bSRobert Mustacchi 	if (ctf_update(fp) == CTF_ERR) {
224bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to update output file: %s\n",
225bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(fp)));
226bc1f688bSRobert Mustacchi 	}
227bc1f688bSRobert Mustacchi 
228bc1f688bSRobert Mustacchi 	if (ctf_add_member(fp, cpuid, "cpu_m", mcpu, sz * NBBY) == CTF_ERR) {
229bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to add the m_cpu member: %s\n",
230bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(fp)));
231bc1f688bSRobert Mustacchi 	}
232bc1f688bSRobert Mustacchi 
233bc1f688bSRobert Mustacchi 	if (ctf_update(fp) == CTF_ERR) {
234bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to update output file: %s\n",
235bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(fp)));
236bc1f688bSRobert Mustacchi 	}
237bc1f688bSRobert Mustacchi 
238bc1f688bSRobert Mustacchi 	VERIFY(ctf_type_size(fp, cpuid) == sz);
239bc1f688bSRobert Mustacchi }
240bc1f688bSRobert Mustacchi 
241bc1f688bSRobert Mustacchi int
242bc1f688bSRobert Mustacchi main(int argc, char *argv[])
243bc1f688bSRobert Mustacchi {
244bc1f688bSRobert Mustacchi 	int c, ifd, err;
245bc1f688bSRobert Mustacchi 	boolean_t keep = B_FALSE;
246*dd442252SAndy Fiddaman 	ctf_convert_flag_t flags = 0;
247*dd442252SAndy Fiddaman 	uint_t bsize = CTF_CONVERT_DEFAULT_BATCHSIZE;
248*dd442252SAndy Fiddaman 	uint_t nthreads = CTF_CONVERT_DEFAULT_NTHREADS;
249bc1f688bSRobert Mustacchi 	const char *outfile = NULL;
250bc1f688bSRobert Mustacchi 	const char *label = NULL;
251bc1f688bSRobert Mustacchi 	const char *infile = NULL;
252bc1f688bSRobert Mustacchi 	char *tmpfile;
253bc1f688bSRobert Mustacchi 	ctf_file_t *ofp;
254*dd442252SAndy Fiddaman 	char buf[4096] = "";
255bc1f688bSRobert Mustacchi 	boolean_t optx = B_FALSE;
2563eca6103SJohn Levon 	boolean_t ignore_non_c = B_FALSE;
257*dd442252SAndy Fiddaman 	ctf_convert_t *cch;
258bc1f688bSRobert Mustacchi 
259bc1f688bSRobert Mustacchi 	ctfconvert_progname = basename(argv[0]);
260bc1f688bSRobert Mustacchi 
261*dd442252SAndy Fiddaman 	while ((c = getopt(argc, argv, ":b:ij:kl:L:mo:sX")) != -1) {
262bc1f688bSRobert Mustacchi 		switch (c) {
263effb27eeSAndy Fiddaman 		case 'b': {
264effb27eeSAndy Fiddaman 			long argno;
265effb27eeSAndy Fiddaman 			const char *errstr;
266effb27eeSAndy Fiddaman 
267effb27eeSAndy Fiddaman 			argno = strtonum(optarg, 1, UINT_MAX, &errstr);
268effb27eeSAndy Fiddaman 			if (errstr != NULL) {
269effb27eeSAndy Fiddaman 				ctfconvert_fatal("invalid argument for -b: "
270effb27eeSAndy Fiddaman 				    "%s - %s\n", optarg, errstr);
271effb27eeSAndy Fiddaman 			}
272effb27eeSAndy Fiddaman 			bsize = (uint_t)argno;
273effb27eeSAndy Fiddaman 			break;
274effb27eeSAndy Fiddaman 		}
2753eca6103SJohn Levon 		case 'i':
2763eca6103SJohn Levon 			ignore_non_c = B_TRUE;
277bc1f688bSRobert Mustacchi 			break;
278effb27eeSAndy Fiddaman 		case 'j': {
279effb27eeSAndy Fiddaman 			long argno;
280effb27eeSAndy Fiddaman 			const char *errstr;
281effb27eeSAndy Fiddaman 
282effb27eeSAndy Fiddaman 			argno = strtonum(optarg, 1, 1024, &errstr);
283effb27eeSAndy Fiddaman 			if (errstr != NULL) {
284bc1f688bSRobert Mustacchi 				ctfconvert_fatal("invalid argument for -j: "
285effb27eeSAndy Fiddaman 				    "%s - %s\n", optarg, errstr);
286bc1f688bSRobert Mustacchi 			}
287effb27eeSAndy Fiddaman 			nthreads = (uint_t)argno;
288bc1f688bSRobert Mustacchi 			break;
289effb27eeSAndy Fiddaman 		}
2903eca6103SJohn Levon 		case 'k':
2913eca6103SJohn Levon 			keep = B_TRUE;
2923eca6103SJohn Levon 			break;
2933eca6103SJohn Levon 		case 'l':
2943eca6103SJohn Levon 			label = optarg;
2953eca6103SJohn Levon 			break;
2963eca6103SJohn Levon 		case 'L':
2973eca6103SJohn Levon 			label = getenv(optarg);
2983eca6103SJohn Levon 			break;
2993eca6103SJohn Levon 		case 'm':
3003eca6103SJohn Levon 			flags |= CTF_ALLOW_MISSING_DEBUG;
3013eca6103SJohn Levon 			break;
302bc1f688bSRobert Mustacchi 		case 'o':
303bc1f688bSRobert Mustacchi 			outfile = optarg;
304bc1f688bSRobert Mustacchi 			break;
305*dd442252SAndy Fiddaman 		case 's':
306*dd442252SAndy Fiddaman 			flags |= CTF_ALLOW_TRUNCATION;
307*dd442252SAndy Fiddaman 			break;
308bc1f688bSRobert Mustacchi 		case 'X':
309bc1f688bSRobert Mustacchi 			optx = B_TRUE;
310bc1f688bSRobert Mustacchi 			break;
311bc1f688bSRobert Mustacchi 		case ':':
312bc1f688bSRobert Mustacchi 			ctfconvert_usage("Option -%c requires an operand\n",
313bc1f688bSRobert Mustacchi 			    optopt);
314bc1f688bSRobert Mustacchi 			return (CTFCONVERT_USAGE);
315bc1f688bSRobert Mustacchi 		case '?':
316bc1f688bSRobert Mustacchi 			ctfconvert_usage("Unknown option: -%c\n", optopt);
317bc1f688bSRobert Mustacchi 			return (CTFCONVERT_USAGE);
318bc1f688bSRobert Mustacchi 		}
319bc1f688bSRobert Mustacchi 	}
320bc1f688bSRobert Mustacchi 
321bc1f688bSRobert Mustacchi 	argv += optind;
322bc1f688bSRobert Mustacchi 	argc -= optind;
323bc1f688bSRobert Mustacchi 
3243eca6103SJohn Levon 	if (argc != 1) {
3253eca6103SJohn Levon 		ctfconvert_usage("Exactly one input file is required\n");
326bc1f688bSRobert Mustacchi 		return (CTFCONVERT_USAGE);
327bc1f688bSRobert Mustacchi 	}
328bc1f688bSRobert Mustacchi 	infile = argv[0];
329bc1f688bSRobert Mustacchi 
330bc1f688bSRobert Mustacchi 	if (elf_version(EV_CURRENT) == EV_NONE)
331bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to initialize libelf: library is "
332bc1f688bSRobert Mustacchi 		    "out of date\n");
333bc1f688bSRobert Mustacchi 
334bc1f688bSRobert Mustacchi 	ifd = open(infile, O_RDONLY);
335bc1f688bSRobert Mustacchi 	if (ifd < 0) {
336bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to open input file %s: %s\n", infile,
337bc1f688bSRobert Mustacchi 		    strerror(errno));
338bc1f688bSRobert Mustacchi 	}
339bc1f688bSRobert Mustacchi 
340bc1f688bSRobert Mustacchi 	/*
341bc1f688bSRobert Mustacchi 	 * By default we remove the input file on failure unless we've been
342bc1f688bSRobert Mustacchi 	 * given an output file or -k has been specified.
343bc1f688bSRobert Mustacchi 	 */
344bc1f688bSRobert Mustacchi 	if (outfile != NULL && strcmp(infile, outfile) != 0)
345bc1f688bSRobert Mustacchi 		keep = B_TRUE;
346bc1f688bSRobert Mustacchi 
347*dd442252SAndy Fiddaman 	cch = ctf_convert_init(&err);
348*dd442252SAndy Fiddaman 	if (cch == NULL) {
349*dd442252SAndy Fiddaman 		ctfconvert_fatal(
350*dd442252SAndy Fiddaman 		    "failed to create libctf conversion handle: %s\n",
351*dd442252SAndy Fiddaman 		    strerror(err));
352*dd442252SAndy Fiddaman 	}
353*dd442252SAndy Fiddaman 	if ((err = ctf_convert_set_nthreads(cch, nthreads)) != 0)
354*dd442252SAndy Fiddaman 		ctfconvert_fatal("Could not set number of threads: %s\n",
355*dd442252SAndy Fiddaman 		    strerror(err));
356*dd442252SAndy Fiddaman 	if ((err = ctf_convert_set_batchsize(cch, bsize)) != 0)
357*dd442252SAndy Fiddaman 		ctfconvert_fatal("Could not set batch size: %s\n",
358*dd442252SAndy Fiddaman 		    strerror(err));
359*dd442252SAndy Fiddaman 	if ((err = ctf_convert_set_flags(cch, flags)) != 0)
360*dd442252SAndy Fiddaman 		ctfconvert_fatal("Could not set conversion flags: %s\n",
361*dd442252SAndy Fiddaman 		    strerror(err));
362*dd442252SAndy Fiddaman 	if (label != NULL && (err = ctf_convert_set_label(cch, label)) != 0)
363*dd442252SAndy Fiddaman 		ctfconvert_fatal("Could not set label: %s\n",
364*dd442252SAndy Fiddaman 		    strerror(err));
365*dd442252SAndy Fiddaman 	if ((err = ctf_convert_set_warncb(cch, ctfconvert_warning, NULL)) != 0)
366*dd442252SAndy Fiddaman 		ctfconvert_fatal("Could not set warning callback: %s\n",
367*dd442252SAndy Fiddaman 		    strerror(err));
368*dd442252SAndy Fiddaman 
369*dd442252SAndy Fiddaman 	ofp = ctf_fdconvert(cch, ifd, &err, buf, sizeof (buf));
370*dd442252SAndy Fiddaman 
371*dd442252SAndy Fiddaman 	ctf_convert_fini(cch);
372*dd442252SAndy Fiddaman 
373bc1f688bSRobert Mustacchi 	if (ofp == NULL) {
374bc1f688bSRobert Mustacchi 		/*
3753eca6103SJohn Levon 		 * Normally, ctfconvert requires that its input file has at
3763eca6103SJohn Levon 		 * least one C-source compilation unit, and that every C-source
3773eca6103SJohn Levon 		 * compilation unit has DWARF. This is to avoid accidentally
3783eca6103SJohn Levon 		 * leaving out useful CTF.
3793eca6103SJohn Levon 		 *
3803eca6103SJohn Levon 		 * However, for the benefit of intransigent build environments,
3813eca6103SJohn Levon 		 * the -i and -m options can be used to relax this.
382bc1f688bSRobert Mustacchi 		 */
3833eca6103SJohn Levon 		if (err == ECTF_CONVNOCSRC && ignore_non_c) {
384bc1f688bSRobert Mustacchi 			exit(CTFCONVERT_OK);
385bc1f688bSRobert Mustacchi 		}
3863eca6103SJohn Levon 
3873eca6103SJohn Levon 		if (err == ECTF_CONVNODEBUG &&
3883eca6103SJohn Levon 		    (flags & CTF_ALLOW_MISSING_DEBUG) != 0) {
3893eca6103SJohn Levon 			exit(CTFCONVERT_OK);
3903eca6103SJohn Levon 		}
3913eca6103SJohn Levon 
392bc1f688bSRobert Mustacchi 		if (keep == B_FALSE)
393bc1f688bSRobert Mustacchi 			(void) unlink(infile);
3943eca6103SJohn Levon 
395*dd442252SAndy Fiddaman 		switch (err) {
396*dd442252SAndy Fiddaman 		case ECTF_CONVBKERR:
397*dd442252SAndy Fiddaman 			ctfconvert_fatal("CTF conversion failed: %s", buf);
398*dd442252SAndy Fiddaman 			break;
399*dd442252SAndy Fiddaman 		case ECTF_CONVNODEBUG:
400*dd442252SAndy Fiddaman 			ctfconvert_fatal("CTF conversion failed due to "
401*dd442252SAndy Fiddaman 			    "missing debug data; use -m to override\n");
402*dd442252SAndy Fiddaman 			break;
403*dd442252SAndy Fiddaman 		default:
404*dd442252SAndy Fiddaman 			if (*buf != '\0') {
405*dd442252SAndy Fiddaman 				(void) fprintf(stderr, "%s: %s",
406*dd442252SAndy Fiddaman 				    ctfconvert_progname, buf);
407*dd442252SAndy Fiddaman 			}
4083eca6103SJohn Levon 			ctfconvert_fatal("CTF conversion failed: %s\n",
4093eca6103SJohn Levon 			    ctf_errmsg(err));
4103eca6103SJohn Levon 		}
411bc1f688bSRobert Mustacchi 	}
412bc1f688bSRobert Mustacchi 
413bc1f688bSRobert Mustacchi 	if (optx == B_TRUE)
414bc1f688bSRobert Mustacchi 		ctfconvert_fixup_genunix(ofp);
415bc1f688bSRobert Mustacchi 
416bc1f688bSRobert Mustacchi 	tmpfile = NULL;
417bc1f688bSRobert Mustacchi 	if (outfile == NULL || strcmp(infile, outfile) == 0) {
418bc1f688bSRobert Mustacchi 		if (asprintf(&tmpfile, "%s.ctf", infile) == -1) {
419bc1f688bSRobert Mustacchi 			if (keep == B_FALSE)
420bc1f688bSRobert Mustacchi 				(void) unlink(infile);
421bc1f688bSRobert Mustacchi 			ctfconvert_fatal("failed to allocate memory for "
422bc1f688bSRobert Mustacchi 			    "temporary file: %s\n", strerror(errno));
423bc1f688bSRobert Mustacchi 		}
424bc1f688bSRobert Mustacchi 		outfile = tmpfile;
425bc1f688bSRobert Mustacchi 	}
426bc1f688bSRobert Mustacchi 	err = ctf_elfwrite(ofp, infile, outfile, CTF_ELFWRITE_F_COMPRESS);
427bc1f688bSRobert Mustacchi 	if (err == CTF_ERR) {
428bc1f688bSRobert Mustacchi 		(void) unlink(outfile);
429bc1f688bSRobert Mustacchi 		if (keep == B_FALSE)
430bc1f688bSRobert Mustacchi 			(void) unlink(infile);
431bc1f688bSRobert Mustacchi 		ctfconvert_fatal("failed to write CTF section to output file: "
432*dd442252SAndy Fiddaman 		    "%s\n", ctf_errmsg(ctf_errno(ofp)));
433bc1f688bSRobert Mustacchi 	}
434bc1f688bSRobert Mustacchi 	ctf_close(ofp);
435bc1f688bSRobert Mustacchi 
436bc1f688bSRobert Mustacchi 	if (tmpfile != NULL) {
437bc1f688bSRobert Mustacchi 		if (rename(tmpfile, infile) != 0) {
438bc1f688bSRobert Mustacchi 			int e = errno;
439bc1f688bSRobert Mustacchi 			(void) unlink(outfile);
440bc1f688bSRobert Mustacchi 			if (keep == B_FALSE)
441bc1f688bSRobert Mustacchi 				(void) unlink(infile);
442bc1f688bSRobert Mustacchi 			ctfconvert_fatal("failed to rename temporary file: "
443bc1f688bSRobert Mustacchi 			    "%s\n", strerror(e));
444bc1f688bSRobert Mustacchi 		}
445bc1f688bSRobert Mustacchi 	}
446bc1f688bSRobert Mustacchi 	free(tmpfile);
447bc1f688bSRobert Mustacchi 
448bc1f688bSRobert Mustacchi 	return (CTFCONVERT_OK);
449bc1f688bSRobert Mustacchi }
450