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