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.
14dd442252SAndy 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
ctfconvert_fatal(const char * fmt,...)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
56dd442252SAndy Fiddaman static void
ctfconvert_warning(void * arg,const char * fmt,...)57dd442252SAndy Fiddaman ctfconvert_warning(void *arg, const char *fmt, ...)
58dd442252SAndy Fiddaman {
59dd442252SAndy Fiddaman va_list ap;
60dd442252SAndy Fiddaman char *buf;
61dd442252SAndy Fiddaman
62dd442252SAndy Fiddaman va_start(ap, fmt);
63dd442252SAndy Fiddaman if (vasprintf(&buf, fmt, ap) != -1) {
64dd442252SAndy Fiddaman (void) fprintf(stderr, "%s: WARNING: %s", ctfconvert_progname,
65dd442252SAndy Fiddaman buf);
66dd442252SAndy Fiddaman free(buf);
67dd442252SAndy Fiddaman }
68dd442252SAndy Fiddaman va_end(ap);
69dd442252SAndy Fiddaman }
70bc1f688bSRobert Mustacchi
71bc1f688bSRobert Mustacchi static void
ctfconvert_usage(const char * fmt,...)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
8373197b54SAndy Fiddaman (void) fprintf(stderr, "Usage: %s [-fikms] [-j nthrs] [-l label | "
84effb27eeSAndy Fiddaman "-L labelenv] [-b batchsize]\n"
8588a08813SAndy Fiddaman " [-o outfile] [-M ignorefile] input\n"
86bc1f688bSRobert Mustacchi "\n"
87effb27eeSAndy Fiddaman "\t-b batch process this many dies at a time (default %d)\n"
8873197b54SAndy Fiddaman "\t-f always attempt to convert files\n"
89bc1f688bSRobert Mustacchi "\t-i ignore files not built partially from C sources\n"
90effb27eeSAndy Fiddaman "\t-j use nthrs threads to perform the merge (default %d)\n"
91bc1f688bSRobert Mustacchi "\t-k keep around original input file on failure\n"
92bc1f688bSRobert Mustacchi "\t-l set output container's label to specified value\n"
93effb27eeSAndy Fiddaman "\t-L set output container's label to value from environment\n"
94effb27eeSAndy Fiddaman "\t-m allow input to have missing debug info\n"
9588a08813SAndy Fiddaman "\t-M allow files listed in ignorefile to have missing debug\n"
96dd442252SAndy Fiddaman "\t-o copy input to outfile and add CTF\n"
97dd442252SAndy Fiddaman "\t-s allow truncation of data that cannot be fully converted\n",
98effb27eeSAndy Fiddaman ctfconvert_progname,
99dd442252SAndy Fiddaman CTF_CONVERT_DEFAULT_BATCHSIZE,
100dd442252SAndy Fiddaman CTF_CONVERT_DEFAULT_NTHREADS);
101bc1f688bSRobert Mustacchi }
102bc1f688bSRobert Mustacchi
103bc1f688bSRobert Mustacchi /*
104bc1f688bSRobert Mustacchi * This is a bit unfortunate. Traditionally we do type uniquification across all
105bc1f688bSRobert Mustacchi * modules in the kernel, including ip and unix against genunix. However, when
106bc1f688bSRobert Mustacchi * _MACHDEP is defined, then the cpu_t ends up having an additional member
107bc1f688bSRobert Mustacchi * (cpu_m), thus changing the ability for us to uniquify against it. This in
108bc1f688bSRobert Mustacchi * turn causes a lot of type sprawl, as there's a lot of things that end up
109bc1f688bSRobert Mustacchi * referring to the cpu_t and it chains out from there.
110bc1f688bSRobert Mustacchi *
111bc1f688bSRobert Mustacchi * So, if we find that a cpu_t has been defined and it has a couple of useful
112bc1f688bSRobert Mustacchi * sentinel members and it does *not* have the cpu_m member, then we will try
113bc1f688bSRobert Mustacchi * and lookup or create a forward declaration to the machcpu, append it to the
114bc1f688bSRobert Mustacchi * end, and update the file.
115bc1f688bSRobert Mustacchi *
116bc1f688bSRobert Mustacchi * This currently is only invoked if an undocumented option -X is passed. This
117bc1f688bSRobert Mustacchi * value is private to illumos and it can be changed at any time inside of it,
118bc1f688bSRobert Mustacchi * so if -X wants to be used for something, it should be. The ability to rely on
119bc1f688bSRobert Mustacchi * -X for others is strictly not an interface in any way, shape, or form.
120bc1f688bSRobert Mustacchi *
121bc1f688bSRobert Mustacchi * The following struct contains most of the information that we care about and
122bc1f688bSRobert Mustacchi * that we want to validate exists before we decide what to do.
123bc1f688bSRobert Mustacchi */
124bc1f688bSRobert Mustacchi
125bc1f688bSRobert Mustacchi typedef struct ctfconvert_fixup {
126bc1f688bSRobert Mustacchi boolean_t cf_cyclic; /* Do we have a cpu_cyclic member */
127bc1f688bSRobert Mustacchi boolean_t cf_mcpu; /* We have a cpu_m member */
128bc1f688bSRobert Mustacchi boolean_t cf_lastpad; /* Is the pad member the last entry */
129bc1f688bSRobert Mustacchi ulong_t cf_padoff; /* offset of the pad */
130bc1f688bSRobert Mustacchi } ctfconvert_fixup_t;
131bc1f688bSRobert Mustacchi
132bc1f688bSRobert Mustacchi /* ARGSUSED */
133bc1f688bSRobert Mustacchi static int
ctfconvert_fixup_genunix_cb(const char * name,ctf_id_t tid,ulong_t off,void * arg)134bc1f688bSRobert Mustacchi ctfconvert_fixup_genunix_cb(const char *name, ctf_id_t tid, ulong_t off,
135bc1f688bSRobert Mustacchi void *arg)
136bc1f688bSRobert Mustacchi {
137bc1f688bSRobert Mustacchi ctfconvert_fixup_t *cfp = arg;
138bc1f688bSRobert Mustacchi
139bc1f688bSRobert Mustacchi cfp->cf_lastpad = B_FALSE;
140bc1f688bSRobert Mustacchi if (strcmp(name, "cpu_cyclic") == 0) {
141bc1f688bSRobert Mustacchi cfp->cf_cyclic = B_TRUE;
142bc1f688bSRobert Mustacchi return (0);
143bc1f688bSRobert Mustacchi }
144bc1f688bSRobert Mustacchi
145bc1f688bSRobert Mustacchi if (strcmp(name, "cpu_m") == 0) {
146bc1f688bSRobert Mustacchi cfp->cf_mcpu = B_TRUE;
147bc1f688bSRobert Mustacchi return (0);
148bc1f688bSRobert Mustacchi }
149bc1f688bSRobert Mustacchi
150bc1f688bSRobert Mustacchi if (strcmp(name, "cpu_m_pad") == 0) {
151bc1f688bSRobert Mustacchi cfp->cf_lastpad = B_TRUE;
152bc1f688bSRobert Mustacchi cfp->cf_padoff = off;
153bc1f688bSRobert Mustacchi return (0);
154bc1f688bSRobert Mustacchi }
155bc1f688bSRobert Mustacchi
156bc1f688bSRobert Mustacchi return (0);
157bc1f688bSRobert Mustacchi }
158bc1f688bSRobert Mustacchi
159bc1f688bSRobert Mustacchi static void
ctfconvert_fixup_genunix(ctf_file_t * fp)160bc1f688bSRobert Mustacchi ctfconvert_fixup_genunix(ctf_file_t *fp)
161bc1f688bSRobert Mustacchi {
162bc1f688bSRobert Mustacchi ctf_id_t cpuid, mcpu;
163bc1f688bSRobert Mustacchi ssize_t sz;
164bc1f688bSRobert Mustacchi ctfconvert_fixup_t cf;
165bc1f688bSRobert Mustacchi int model, ptrsz;
166bc1f688bSRobert Mustacchi
167bc1f688bSRobert Mustacchi cpuid = ctf_lookup_by_name(fp, "struct cpu");
168bc1f688bSRobert Mustacchi if (cpuid == CTF_ERR)
169bc1f688bSRobert Mustacchi return;
170bc1f688bSRobert Mustacchi
171bc1f688bSRobert Mustacchi if (ctf_type_kind(fp, cpuid) != CTF_K_STRUCT)
172bc1f688bSRobert Mustacchi return;
173bc1f688bSRobert Mustacchi
174bc1f688bSRobert Mustacchi if ((sz = ctf_type_size(fp, cpuid)) == CTF_ERR)
175bc1f688bSRobert Mustacchi return;
176bc1f688bSRobert Mustacchi
177bc1f688bSRobert Mustacchi model = ctf_getmodel(fp);
178bc1f688bSRobert Mustacchi VERIFY(model == CTF_MODEL_ILP32 || model == CTF_MODEL_LP64);
179bc1f688bSRobert Mustacchi ptrsz = model == CTF_MODEL_ILP32 ? 4 : 8;
180bc1f688bSRobert Mustacchi
181bc1f688bSRobert Mustacchi bzero(&cf, sizeof (ctfconvert_fixup_t));
182bc1f688bSRobert Mustacchi if (ctf_member_iter(fp, cpuid, ctfconvert_fixup_genunix_cb, &cf) ==
183bc1f688bSRobert Mustacchi CTF_ERR)
184bc1f688bSRobert Mustacchi return;
185bc1f688bSRobert Mustacchi
186bc1f688bSRobert Mustacchi /*
187bc1f688bSRobert Mustacchi * Finally, we want to verify that the cpu_m is actually the last member
188bc1f688bSRobert Mustacchi * that we have here.
189bc1f688bSRobert Mustacchi */
190bc1f688bSRobert Mustacchi if (cf.cf_cyclic == B_FALSE || cf.cf_mcpu == B_TRUE ||
191bc1f688bSRobert Mustacchi cf.cf_lastpad == B_FALSE) {
192bc1f688bSRobert Mustacchi return;
193bc1f688bSRobert Mustacchi }
194bc1f688bSRobert Mustacchi
195bc1f688bSRobert Mustacchi if (cf.cf_padoff + ptrsz * NBBY != sz * NBBY) {
196bc1f688bSRobert Mustacchi return;
197bc1f688bSRobert Mustacchi }
198bc1f688bSRobert Mustacchi
199bc1f688bSRobert Mustacchi /*
200bc1f688bSRobert Mustacchi * Okay, we're going to do this, try to find a struct machcpu. We either
201bc1f688bSRobert Mustacchi * want a forward or a struct. If we find something else, error. If we
202bc1f688bSRobert Mustacchi * find nothing, add a forward and then add the member.
203bc1f688bSRobert Mustacchi */
204bc1f688bSRobert Mustacchi mcpu = ctf_lookup_by_name(fp, "struct machcpu");
205bc1f688bSRobert Mustacchi if (mcpu == CTF_ERR) {
206bc1f688bSRobert Mustacchi mcpu = ctf_add_forward(fp, CTF_ADD_NONROOT, "machcpu",
207bc1f688bSRobert Mustacchi CTF_K_STRUCT);
208bc1f688bSRobert Mustacchi if (mcpu == CTF_ERR) {
209bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to add 'struct machcpu' "
210dd442252SAndy Fiddaman "forward: %s\n", ctf_errmsg(ctf_errno(fp)));
211bc1f688bSRobert Mustacchi }
212bc1f688bSRobert Mustacchi } else {
213bc1f688bSRobert Mustacchi int kind;
214bc1f688bSRobert Mustacchi if ((kind = ctf_type_kind(fp, mcpu)) == CTF_ERR) {
215bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to get the type kind for "
216dd442252SAndy Fiddaman "the struct machcpu: %s\n",
217bc1f688bSRobert Mustacchi ctf_errmsg(ctf_errno(fp)));
218bc1f688bSRobert Mustacchi }
219bc1f688bSRobert Mustacchi
220bc1f688bSRobert Mustacchi if (kind != CTF_K_STRUCT && kind != CTF_K_FORWARD)
221bc1f688bSRobert Mustacchi ctfconvert_fatal("encountered a struct machcpu of the "
222bc1f688bSRobert Mustacchi "wrong type, found type kind %d\n", kind);
223bc1f688bSRobert Mustacchi }
224bc1f688bSRobert Mustacchi
225bc1f688bSRobert Mustacchi if (ctf_update(fp) == CTF_ERR) {
226bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to update output file: %s\n",
227bc1f688bSRobert Mustacchi ctf_errmsg(ctf_errno(fp)));
228bc1f688bSRobert Mustacchi }
229bc1f688bSRobert Mustacchi
230bc1f688bSRobert Mustacchi if (ctf_add_member(fp, cpuid, "cpu_m", mcpu, sz * NBBY) == CTF_ERR) {
231bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to add the m_cpu member: %s\n",
232bc1f688bSRobert Mustacchi ctf_errmsg(ctf_errno(fp)));
233bc1f688bSRobert Mustacchi }
234bc1f688bSRobert Mustacchi
235bc1f688bSRobert Mustacchi if (ctf_update(fp) == CTF_ERR) {
236bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to update output file: %s\n",
237bc1f688bSRobert Mustacchi ctf_errmsg(ctf_errno(fp)));
238bc1f688bSRobert Mustacchi }
239bc1f688bSRobert Mustacchi
240bc1f688bSRobert Mustacchi VERIFY(ctf_type_size(fp, cpuid) == sz);
241bc1f688bSRobert Mustacchi }
242bc1f688bSRobert Mustacchi
243bc1f688bSRobert Mustacchi int
main(int argc,char * argv[])244bc1f688bSRobert Mustacchi main(int argc, char *argv[])
245bc1f688bSRobert Mustacchi {
246bc1f688bSRobert Mustacchi int c, ifd, err;
247bc1f688bSRobert Mustacchi boolean_t keep = B_FALSE;
248dd442252SAndy Fiddaman ctf_convert_flag_t flags = 0;
249dd442252SAndy Fiddaman uint_t bsize = CTF_CONVERT_DEFAULT_BATCHSIZE;
250dd442252SAndy Fiddaman uint_t nthreads = CTF_CONVERT_DEFAULT_NTHREADS;
251bc1f688bSRobert Mustacchi const char *outfile = NULL;
252bc1f688bSRobert Mustacchi const char *label = NULL;
253bc1f688bSRobert Mustacchi const char *infile = NULL;
25488a08813SAndy Fiddaman const char *ignorefile = NULL;
255bc1f688bSRobert Mustacchi char *tmpfile;
256bc1f688bSRobert Mustacchi ctf_file_t *ofp;
257dd442252SAndy Fiddaman char buf[4096] = "";
258bc1f688bSRobert Mustacchi boolean_t optx = B_FALSE;
2593eca6103SJohn Levon boolean_t ignore_non_c = B_FALSE;
260dd442252SAndy Fiddaman ctf_convert_t *cch;
261bc1f688bSRobert Mustacchi
262bc1f688bSRobert Mustacchi ctfconvert_progname = basename(argv[0]);
263bc1f688bSRobert Mustacchi
26488a08813SAndy Fiddaman while ((c = getopt(argc, argv, ":b:fij:kl:L:mM:o:sX")) != -1) {
265bc1f688bSRobert Mustacchi switch (c) {
266effb27eeSAndy Fiddaman case 'b': {
267effb27eeSAndy Fiddaman long argno;
268effb27eeSAndy Fiddaman const char *errstr;
269effb27eeSAndy Fiddaman
270effb27eeSAndy Fiddaman argno = strtonum(optarg, 1, UINT_MAX, &errstr);
271effb27eeSAndy Fiddaman if (errstr != NULL) {
272effb27eeSAndy Fiddaman ctfconvert_fatal("invalid argument for -b: "
273effb27eeSAndy Fiddaman "%s - %s\n", optarg, errstr);
274effb27eeSAndy Fiddaman }
275effb27eeSAndy Fiddaman bsize = (uint_t)argno;
276effb27eeSAndy Fiddaman break;
277effb27eeSAndy Fiddaman }
27873197b54SAndy Fiddaman case 'f':
27973197b54SAndy Fiddaman flags |= CTF_FORCE_CONVERSION;
28073197b54SAndy Fiddaman break;
2813eca6103SJohn Levon case 'i':
2823eca6103SJohn Levon ignore_non_c = B_TRUE;
283bc1f688bSRobert Mustacchi break;
284effb27eeSAndy Fiddaman case 'j': {
285effb27eeSAndy Fiddaman long argno;
286effb27eeSAndy Fiddaman const char *errstr;
287effb27eeSAndy Fiddaman
288effb27eeSAndy Fiddaman argno = strtonum(optarg, 1, 1024, &errstr);
289effb27eeSAndy Fiddaman if (errstr != NULL) {
290bc1f688bSRobert Mustacchi ctfconvert_fatal("invalid argument for -j: "
291effb27eeSAndy Fiddaman "%s - %s\n", optarg, errstr);
292bc1f688bSRobert Mustacchi }
293effb27eeSAndy Fiddaman nthreads = (uint_t)argno;
294bc1f688bSRobert Mustacchi break;
295effb27eeSAndy Fiddaman }
2963eca6103SJohn Levon case 'k':
2973eca6103SJohn Levon keep = B_TRUE;
2983eca6103SJohn Levon break;
2993eca6103SJohn Levon case 'l':
3003eca6103SJohn Levon label = optarg;
3013eca6103SJohn Levon break;
3023eca6103SJohn Levon case 'L':
3033eca6103SJohn Levon label = getenv(optarg);
3043eca6103SJohn Levon break;
3053eca6103SJohn Levon case 'm':
3063eca6103SJohn Levon flags |= CTF_ALLOW_MISSING_DEBUG;
3073eca6103SJohn Levon break;
30888a08813SAndy Fiddaman case 'M':
30988a08813SAndy Fiddaman ignorefile = optarg;
31088a08813SAndy Fiddaman break;
311bc1f688bSRobert Mustacchi case 'o':
312bc1f688bSRobert Mustacchi outfile = optarg;
313bc1f688bSRobert Mustacchi break;
314dd442252SAndy Fiddaman case 's':
315dd442252SAndy Fiddaman flags |= CTF_ALLOW_TRUNCATION;
316dd442252SAndy Fiddaman break;
317bc1f688bSRobert Mustacchi case 'X':
318bc1f688bSRobert Mustacchi optx = B_TRUE;
319bc1f688bSRobert Mustacchi break;
320bc1f688bSRobert Mustacchi case ':':
321bc1f688bSRobert Mustacchi ctfconvert_usage("Option -%c requires an operand\n",
322bc1f688bSRobert Mustacchi optopt);
323bc1f688bSRobert Mustacchi return (CTFCONVERT_USAGE);
324bc1f688bSRobert Mustacchi case '?':
325bc1f688bSRobert Mustacchi ctfconvert_usage("Unknown option: -%c\n", optopt);
326bc1f688bSRobert Mustacchi return (CTFCONVERT_USAGE);
327bc1f688bSRobert Mustacchi }
328bc1f688bSRobert Mustacchi }
329bc1f688bSRobert Mustacchi
330bc1f688bSRobert Mustacchi argv += optind;
331bc1f688bSRobert Mustacchi argc -= optind;
332bc1f688bSRobert Mustacchi
3333eca6103SJohn Levon if (argc != 1) {
3343eca6103SJohn Levon ctfconvert_usage("Exactly one input file is required\n");
335bc1f688bSRobert Mustacchi return (CTFCONVERT_USAGE);
336bc1f688bSRobert Mustacchi }
337bc1f688bSRobert Mustacchi infile = argv[0];
338bc1f688bSRobert Mustacchi
339bc1f688bSRobert Mustacchi if (elf_version(EV_CURRENT) == EV_NONE)
340bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to initialize libelf: library is "
341bc1f688bSRobert Mustacchi "out of date\n");
342bc1f688bSRobert Mustacchi
343bc1f688bSRobert Mustacchi ifd = open(infile, O_RDONLY);
344bc1f688bSRobert Mustacchi if (ifd < 0) {
345bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to open input file %s: %s\n", infile,
346bc1f688bSRobert Mustacchi strerror(errno));
347bc1f688bSRobert Mustacchi }
348bc1f688bSRobert Mustacchi
349bc1f688bSRobert Mustacchi /*
350bc1f688bSRobert Mustacchi * By default we remove the input file on failure unless we've been
351bc1f688bSRobert Mustacchi * given an output file or -k has been specified.
352bc1f688bSRobert Mustacchi */
353bc1f688bSRobert Mustacchi if (outfile != NULL && strcmp(infile, outfile) != 0)
354bc1f688bSRobert Mustacchi keep = B_TRUE;
355bc1f688bSRobert Mustacchi
356dd442252SAndy Fiddaman cch = ctf_convert_init(&err);
357dd442252SAndy Fiddaman if (cch == NULL) {
358dd442252SAndy Fiddaman ctfconvert_fatal(
359dd442252SAndy Fiddaman "failed to create libctf conversion handle: %s\n",
360dd442252SAndy Fiddaman strerror(err));
361dd442252SAndy Fiddaman }
362dd442252SAndy Fiddaman if ((err = ctf_convert_set_nthreads(cch, nthreads)) != 0)
363dd442252SAndy Fiddaman ctfconvert_fatal("Could not set number of threads: %s\n",
364dd442252SAndy Fiddaman strerror(err));
365dd442252SAndy Fiddaman if ((err = ctf_convert_set_batchsize(cch, bsize)) != 0)
366dd442252SAndy Fiddaman ctfconvert_fatal("Could not set batch size: %s\n",
367dd442252SAndy Fiddaman strerror(err));
368dd442252SAndy Fiddaman if ((err = ctf_convert_set_flags(cch, flags)) != 0)
369dd442252SAndy Fiddaman ctfconvert_fatal("Could not set conversion flags: %s\n",
370dd442252SAndy Fiddaman strerror(err));
371dd442252SAndy Fiddaman if (label != NULL && (err = ctf_convert_set_label(cch, label)) != 0)
372dd442252SAndy Fiddaman ctfconvert_fatal("Could not set label: %s\n",
373dd442252SAndy Fiddaman strerror(err));
374dd442252SAndy Fiddaman if ((err = ctf_convert_set_warncb(cch, ctfconvert_warning, NULL)) != 0)
375dd442252SAndy Fiddaman ctfconvert_fatal("Could not set warning callback: %s\n",
376dd442252SAndy Fiddaman strerror(err));
377dd442252SAndy Fiddaman
37888a08813SAndy Fiddaman if (ignorefile != NULL) {
37988a08813SAndy Fiddaman char *buf = NULL;
38088a08813SAndy Fiddaman ssize_t cnt;
38188a08813SAndy Fiddaman size_t len = 0;
38288a08813SAndy Fiddaman FILE *fp;
38388a08813SAndy Fiddaman
38488a08813SAndy Fiddaman if ((fp = fopen(ignorefile, "r")) == NULL) {
38588a08813SAndy Fiddaman ctfconvert_fatal("Could not open ignorefile '%s': %s\n",
38688a08813SAndy Fiddaman ignorefile, strerror(errno));
38788a08813SAndy Fiddaman }
38888a08813SAndy Fiddaman
38988a08813SAndy Fiddaman while ((cnt = getline(&buf, &len, fp)) != -1) {
39088a08813SAndy Fiddaman char *p = buf;
39188a08813SAndy Fiddaman
39288a08813SAndy Fiddaman if (cnt == 0 || *p == '#')
39388a08813SAndy Fiddaman continue;
39488a08813SAndy Fiddaman
39588a08813SAndy Fiddaman (void) strsep(&p, "\n");
39688a08813SAndy Fiddaman if ((err = ctf_convert_add_ignore(cch, buf)) != 0) {
39788a08813SAndy Fiddaman ctfconvert_fatal(
39888a08813SAndy Fiddaman "Failed to add '%s' to ignore list: %s\n",
39988a08813SAndy Fiddaman buf, strerror(err));
40088a08813SAndy Fiddaman }
40188a08813SAndy Fiddaman }
40288a08813SAndy Fiddaman free(buf);
40388a08813SAndy Fiddaman if (cnt == -1 && ferror(fp) != 0) {
40488a08813SAndy Fiddaman ctfconvert_fatal(
40588a08813SAndy Fiddaman "Error reading from ignorefile '%s': %s\n",
40688a08813SAndy Fiddaman ignorefile, strerror(errno));
40788a08813SAndy Fiddaman }
40888a08813SAndy Fiddaman
40988a08813SAndy Fiddaman (void) fclose(fp);
41088a08813SAndy Fiddaman }
41188a08813SAndy Fiddaman
412dd442252SAndy Fiddaman ofp = ctf_fdconvert(cch, ifd, &err, buf, sizeof (buf));
413dd442252SAndy Fiddaman
414dd442252SAndy Fiddaman ctf_convert_fini(cch);
415dd442252SAndy Fiddaman
416bc1f688bSRobert Mustacchi if (ofp == NULL) {
417bc1f688bSRobert Mustacchi /*
4183eca6103SJohn Levon * Normally, ctfconvert requires that its input file has at
4193eca6103SJohn Levon * least one C-source compilation unit, and that every C-source
4203eca6103SJohn Levon * compilation unit has DWARF. This is to avoid accidentally
4213eca6103SJohn Levon * leaving out useful CTF.
4223eca6103SJohn Levon *
4233eca6103SJohn Levon * However, for the benefit of intransigent build environments,
4243eca6103SJohn Levon * the -i and -m options can be used to relax this.
425bc1f688bSRobert Mustacchi */
4263eca6103SJohn Levon if (err == ECTF_CONVNOCSRC && ignore_non_c) {
427bc1f688bSRobert Mustacchi exit(CTFCONVERT_OK);
428bc1f688bSRobert Mustacchi }
4293eca6103SJohn Levon
4303eca6103SJohn Levon if (err == ECTF_CONVNODEBUG &&
4313eca6103SJohn Levon (flags & CTF_ALLOW_MISSING_DEBUG) != 0) {
4323eca6103SJohn Levon exit(CTFCONVERT_OK);
4333eca6103SJohn Levon }
4343eca6103SJohn Levon
435bc1f688bSRobert Mustacchi if (keep == B_FALSE)
436bc1f688bSRobert Mustacchi (void) unlink(infile);
4373eca6103SJohn Levon
438*16d40492SRobert Mustacchi /*
439*16d40492SRobert Mustacchi * Note, we expect libctf to include a newline it all of its
440*16d40492SRobert Mustacchi * error messages right now (though it perhaps shouldn't).
441*16d40492SRobert Mustacchi */
442dd442252SAndy Fiddaman switch (err) {
443dd442252SAndy Fiddaman case ECTF_CONVBKERR:
444dd442252SAndy Fiddaman ctfconvert_fatal("CTF conversion failed: %s", buf);
445dd442252SAndy Fiddaman break;
446dd442252SAndy Fiddaman case ECTF_CONVNODEBUG:
447dd442252SAndy Fiddaman ctfconvert_fatal("CTF conversion failed due to "
448dd442252SAndy Fiddaman "missing debug data; use -m to override\n");
449dd442252SAndy Fiddaman break;
450dd442252SAndy Fiddaman default:
451dd442252SAndy Fiddaman if (*buf != '\0') {
452dd442252SAndy Fiddaman (void) fprintf(stderr, "%s: %s",
453dd442252SAndy Fiddaman ctfconvert_progname, buf);
454dd442252SAndy Fiddaman }
4553eca6103SJohn Levon ctfconvert_fatal("CTF conversion failed: %s\n",
4563eca6103SJohn Levon ctf_errmsg(err));
4573eca6103SJohn Levon }
458bc1f688bSRobert Mustacchi }
459bc1f688bSRobert Mustacchi
460bc1f688bSRobert Mustacchi if (optx == B_TRUE)
461bc1f688bSRobert Mustacchi ctfconvert_fixup_genunix(ofp);
462bc1f688bSRobert Mustacchi
463bc1f688bSRobert Mustacchi tmpfile = NULL;
464bc1f688bSRobert Mustacchi if (outfile == NULL || strcmp(infile, outfile) == 0) {
465bc1f688bSRobert Mustacchi if (asprintf(&tmpfile, "%s.ctf", infile) == -1) {
466bc1f688bSRobert Mustacchi if (keep == B_FALSE)
467bc1f688bSRobert Mustacchi (void) unlink(infile);
468bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to allocate memory for "
469bc1f688bSRobert Mustacchi "temporary file: %s\n", strerror(errno));
470bc1f688bSRobert Mustacchi }
471bc1f688bSRobert Mustacchi outfile = tmpfile;
472bc1f688bSRobert Mustacchi }
473bc1f688bSRobert Mustacchi err = ctf_elfwrite(ofp, infile, outfile, CTF_ELFWRITE_F_COMPRESS);
474bc1f688bSRobert Mustacchi if (err == CTF_ERR) {
475bc1f688bSRobert Mustacchi (void) unlink(outfile);
476bc1f688bSRobert Mustacchi if (keep == B_FALSE)
477bc1f688bSRobert Mustacchi (void) unlink(infile);
478bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to write CTF section to output file: "
479dd442252SAndy Fiddaman "%s\n", ctf_errmsg(ctf_errno(ofp)));
480bc1f688bSRobert Mustacchi }
481bc1f688bSRobert Mustacchi ctf_close(ofp);
482bc1f688bSRobert Mustacchi
483bc1f688bSRobert Mustacchi if (tmpfile != NULL) {
484bc1f688bSRobert Mustacchi if (rename(tmpfile, infile) != 0) {
485bc1f688bSRobert Mustacchi int e = errno;
486bc1f688bSRobert Mustacchi (void) unlink(outfile);
487bc1f688bSRobert Mustacchi if (keep == B_FALSE)
488bc1f688bSRobert Mustacchi (void) unlink(infile);
489bc1f688bSRobert Mustacchi ctfconvert_fatal("failed to rename temporary file: "
490bc1f688bSRobert Mustacchi "%s\n", strerror(e));
491bc1f688bSRobert Mustacchi }
492bc1f688bSRobert Mustacchi }
493bc1f688bSRobert Mustacchi free(tmpfile);
494bc1f688bSRobert Mustacchi
495bc1f688bSRobert Mustacchi return (CTFCONVERT_OK);
496bc1f688bSRobert Mustacchi }
497