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