Print this page
10703 smatch unreachable code checking needs reworking
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/ctfmerge/ctfmerge.c
+++ new/usr/src/cmd/ctfmerge/ctfmerge.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 * merge CTF containers
18 18 */
19 19
20 20 #include <stdio.h>
21 21 #include <libctf.h>
22 22 #include <sys/stat.h>
23 23 #include <sys/types.h>
24 24 #include <fcntl.h>
25 25 #include <errno.h>
26 26 #include <strings.h>
27 27 #include <assert.h>
28 28 #include <unistd.h>
29 29 #include <sys/fcntl.h>
30 30 #include <stdlib.h>
31 31 #include <libelf.h>
32 32 #include <gelf.h>
33 33 #include <sys/mman.h>
34 34 #include <libgen.h>
35 35 #include <stdarg.h>
36 36 #include <limits.h>
37 37
38 38 static char *g_progname;
39 39 static char *g_unique;
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
40 40 static char *g_outfile;
41 41 static uint_t g_nctf;
42 42
43 43 #define CTFMERGE_OK 0
44 44 #define CTFMERGE_FATAL 1
45 45 #define CTFMERGE_USAGE 2
46 46
47 47 #define CTFMERGE_DEFAULT_NTHREADS 8
48 48 #define CTFMERGE_ALTEXEC "CTFMERGE_ALTEXEC"
49 49
50 -static void
50 +static void __attribute__((__noreturn__))
51 51 ctfmerge_fatal(const char *fmt, ...)
52 52 {
53 53 va_list ap;
54 54
55 55 (void) fprintf(stderr, "%s: ", g_progname);
56 56 va_start(ap, fmt);
57 57 (void) vfprintf(stderr, fmt, ap);
58 58 va_end(ap);
59 59
60 60 if (g_outfile != NULL)
61 61 (void) unlink(g_outfile);
62 62
63 63 exit(CTFMERGE_FATAL);
64 64 }
65 65
66 66 /*
67 67 * We failed to find CTF for this file, check if it's OK. If we're not derived
68 68 * from C, or we have the -m option, we let missing CTF pass.
69 69 */
70 70 static void
71 71 ctfmerge_check_for_c(const char *name, Elf *elf, uint_t flags)
72 72 {
73 73 char errmsg[1024];
74 74
75 75 if (flags & CTF_ALLOW_MISSING_DEBUG)
76 76 return;
77 77
78 78 switch (ctf_has_c_source(elf, errmsg, sizeof (errmsg))) {
79 79 case CHR_ERROR:
80 80 ctfmerge_fatal("failed to open %s: %s\n", name, errmsg);
81 81 break;
82 82
83 83 case CHR_NO_C_SOURCE:
84 84 return;
85 85
86 86 default:
87 87 ctfmerge_fatal("failed to open %s: %s\n", name,
88 88 ctf_errmsg(ECTF_NOCTFDATA));
89 89 break;
90 90 }
91 91 }
92 92
93 93 /*
94 94 * Go through and construct enough information for this Elf Object to try and do
95 95 * a ctf_bufopen().
96 96 */
97 97 static int
98 98 ctfmerge_elfopen(const char *name, Elf *elf, ctf_merge_t *cmh, uint_t flags)
99 99 {
100 100 GElf_Ehdr ehdr;
101 101 GElf_Shdr shdr;
102 102 Elf_Scn *scn;
103 103 Elf_Data *ctf_data, *str_data, *sym_data;
104 104 ctf_sect_t ctfsect, symsect, strsect;
105 105 ctf_file_t *fp;
106 106 int err;
107 107
108 108 if (gelf_getehdr(elf, &ehdr) == NULL)
109 109 ctfmerge_fatal("failed to get ELF header for %s: %s\n",
110 110 name, elf_errmsg(elf_errno()));
111 111
112 112 bzero(&ctfsect, sizeof (ctf_sect_t));
113 113 bzero(&symsect, sizeof (ctf_sect_t));
114 114 bzero(&strsect, sizeof (ctf_sect_t));
115 115
116 116 scn = NULL;
117 117 while ((scn = elf_nextscn(elf, scn)) != NULL) {
118 118 const char *sname;
119 119
120 120 if (gelf_getshdr(scn, &shdr) == NULL)
121 121 ctfmerge_fatal("failed to get section header for "
122 122 "file %s: %s\n", name, elf_errmsg(elf_errno()));
123 123
124 124 sname = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
125 125 if (shdr.sh_type == SHT_PROGBITS &&
126 126 strcmp(sname, ".SUNW_ctf") == 0) {
127 127 ctfsect.cts_name = sname;
128 128 ctfsect.cts_type = shdr.sh_type;
129 129 ctfsect.cts_flags = shdr.sh_flags;
130 130 ctfsect.cts_size = shdr.sh_size;
131 131 ctfsect.cts_entsize = shdr.sh_entsize;
132 132 ctfsect.cts_offset = (off64_t)shdr.sh_offset;
133 133
134 134 ctf_data = elf_getdata(scn, NULL);
135 135 if (ctf_data == NULL)
136 136 ctfmerge_fatal("failed to get ELF CTF "
137 137 "data section for %s: %s\n", name,
138 138 elf_errmsg(elf_errno()));
139 139 ctfsect.cts_data = ctf_data->d_buf;
140 140 } else if (shdr.sh_type == SHT_SYMTAB) {
141 141 Elf_Scn *strscn;
142 142 GElf_Shdr strhdr;
143 143
144 144 symsect.cts_name = sname;
145 145 symsect.cts_type = shdr.sh_type;
146 146 symsect.cts_flags = shdr.sh_flags;
147 147 symsect.cts_size = shdr.sh_size;
148 148 symsect.cts_entsize = shdr.sh_entsize;
149 149 symsect.cts_offset = (off64_t)shdr.sh_offset;
150 150
151 151 if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL ||
152 152 gelf_getshdr(strscn, &strhdr) == NULL)
153 153 ctfmerge_fatal("failed to get "
154 154 "string table for file %s: %s\n", name,
155 155 elf_errmsg(elf_errno()));
156 156
157 157 strsect.cts_name = elf_strptr(elf, ehdr.e_shstrndx,
158 158 strhdr.sh_name);
159 159 strsect.cts_type = strhdr.sh_type;
160 160 strsect.cts_flags = strhdr.sh_flags;
161 161 strsect.cts_size = strhdr.sh_size;
162 162 strsect.cts_entsize = strhdr.sh_entsize;
163 163 strsect.cts_offset = (off64_t)strhdr.sh_offset;
164 164
165 165 sym_data = elf_getdata(scn, NULL);
166 166 if (sym_data == NULL)
167 167 ctfmerge_fatal("failed to get ELF CTF "
168 168 "data section for %s: %s\n", name,
169 169 elf_errmsg(elf_errno()));
170 170 symsect.cts_data = sym_data->d_buf;
171 171
172 172 str_data = elf_getdata(strscn, NULL);
173 173 if (str_data == NULL)
174 174 ctfmerge_fatal("failed to get ELF CTF "
175 175 "data section for %s: %s\n", name,
176 176 elf_errmsg(elf_errno()));
177 177 strsect.cts_data = str_data->d_buf;
178 178 }
179 179 }
180 180
181 181 if (ctfsect.cts_type == SHT_NULL) {
182 182 ctfmerge_check_for_c(name, elf, flags);
183 183 return (ENOENT);
184 184 }
185 185
186 186 if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL) {
187 187 fp = ctf_bufopen(&ctfsect, &symsect, &strsect, &err);
188 188 } else {
189 189 fp = ctf_bufopen(&ctfsect, NULL, NULL, &err);
190 190 }
191 191
192 192 if (fp == NULL) {
193 193 ctfmerge_fatal("failed to open file %s: %s\n",
194 194 name, ctf_errmsg(err));
195 195 }
196 196
197 197 if ((err = ctf_merge_add(cmh, fp)) != 0) {
198 198 ctfmerge_fatal("failed to add input %s: %s\n",
199 199 name, ctf_errmsg(err));
200 200 }
201 201
202 202 g_nctf++;
203 203 return (0);
204 204 }
205 205
206 206 static void
207 207 ctfmerge_read_archive(const char *name, int fd, Elf *elf,
208 208 ctf_merge_t *cmh, uint_t flags)
209 209 {
210 210 Elf_Cmd cmd = ELF_C_READ;
211 211 int cursec = 1;
212 212 Elf *aelf;
213 213
214 214 while ((aelf = elf_begin(fd, cmd, elf)) != NULL) {
215 215 char *nname = NULL;
216 216 Elf_Arhdr *arhdr;
217 217
218 218 if ((arhdr = elf_getarhdr(aelf)) == NULL)
219 219 ctfmerge_fatal("failed to get archive header %d for "
220 220 "%s: %s\n", cursec, name, elf_errmsg(elf_errno()));
221 221
222 222 cmd = elf_next(aelf);
223 223
224 224 if (*(arhdr->ar_name) == '/')
225 225 goto next;
226 226
227 227 if (asprintf(&nname, "%s.%s.%d", name, arhdr->ar_name,
228 228 cursec) < 0)
229 229 ctfmerge_fatal("failed to allocate memory for archive "
230 230 "%d of file %s\n", cursec, name);
231 231
232 232 switch (elf_kind(aelf)) {
233 233 case ELF_K_AR:
234 234 ctfmerge_read_archive(nname, fd, aelf, cmh, flags);
235 235 break;
236 236 case ELF_K_ELF:
237 237 /* ctfmerge_elfopen() takes ownership of aelf. */
238 238 if (ctfmerge_elfopen(nname, aelf, cmh, flags) == 0)
239 239 aelf = NULL;
240 240 break;
241 241 default:
242 242 ctfmerge_fatal("unknown elf kind (%d) in archive %d "
243 243 "for %s\n", elf_kind(aelf), cursec, name);
244 244 break;
245 245 }
246 246
247 247 next:
248 248 (void) elf_end(aelf);
249 249 free(nname);
250 250 cursec++;
251 251 }
252 252 }
253 253
254 254 static void
255 255 ctfmerge_file_add(ctf_merge_t *cmh, const char *file, uint_t flags)
256 256 {
257 257 Elf *e;
258 258 int fd;
259 259
260 260 if ((fd = open(file, O_RDONLY)) < 0) {
261 261 ctfmerge_fatal("failed to open file %s: %s\n",
262 262 file, strerror(errno));
263 263 }
264 264
265 265 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
266 266 (void) close(fd);
267 267 ctfmerge_fatal("failed to open %s: %s\n",
268 268 file, elf_errmsg(elf_errno()));
269 269 }
270 270
271 271 switch (elf_kind(e)) {
272 272 case ELF_K_AR:
273 273 ctfmerge_read_archive(file, fd, e, cmh, flags);
274 274 break;
275 275
276 276 case ELF_K_ELF:
277 277 /* ctfmerge_elfopen() takes ownership of e. */
278 278 if (ctfmerge_elfopen(file, e, cmh, flags) == 0)
279 279 e = NULL;
280 280 break;
281 281
282 282 default:
283 283 ctfmerge_fatal("unknown elf kind (%d) for %s\n",
284 284 elf_kind(e), file);
285 285 }
286 286
287 287 (void) elf_end(e);
288 288 (void) close(fd);
289 289 }
290 290
291 291 static void
292 292 ctfmerge_usage(const char *fmt, ...)
293 293 {
294 294 if (fmt != NULL) {
295 295 va_list ap;
296 296
297 297 (void) fprintf(stderr, "%s: ", g_progname);
298 298 va_start(ap, fmt);
299 299 (void) vfprintf(stderr, fmt, ap);
300 300 va_end(ap);
301 301 }
302 302
303 303 (void) fprintf(stderr, "Usage: %s [-m] [-d uniqfile] [-l label] "
304 304 "[-L labelenv] [-j nthrs] -o outfile file ...\n"
305 305 "\n"
306 306 "\t-d uniquify merged output against uniqfile\n"
307 307 "\t-j use nthrs threads to perform the merge\n"
308 308 "\t-l set output container's label to specified value\n"
309 309 "\t-L set output container's label to value from environment\n"
310 310 "\t-m allow C-based input files to not have CTF\n"
311 311 "\t-o file to add CTF data to\n",
312 312 g_progname);
313 313 }
314 314
315 315 static void
316 316 ctfmerge_altexec(char **argv)
317 317 {
318 318 const char *alt;
319 319 char *altexec;
320 320
321 321 alt = getenv(CTFMERGE_ALTEXEC);
322 322 if (alt == NULL || *alt == '\0')
323 323 return;
324 324
325 325 altexec = strdup(alt);
326 326 if (altexec == NULL)
327 327 ctfmerge_fatal("failed to allocate memory for altexec\n");
328 328 if (unsetenv(CTFMERGE_ALTEXEC) != 0)
329 329 ctfmerge_fatal("failed to unset %s from environment: %s\n",
330 330 CTFMERGE_ALTEXEC, strerror(errno));
331 331
332 332 (void) execv(altexec, argv);
333 333 ctfmerge_fatal("failed to execute alternate program %s: %s",
334 334 altexec, strerror(errno));
335 335 }
336 336
337 337 int
338 338 main(int argc, char *argv[])
339 339 {
340 340 int err, i, c, ofd;
341 341 uint_t nthreads = CTFMERGE_DEFAULT_NTHREADS;
342 342 char *tmpfile = NULL, *label = NULL;
343 343 int wflags = CTF_ELFWRITE_F_COMPRESS;
344 344 uint_t flags = 0;
345 345 ctf_merge_t *cmh;
346 346 ctf_file_t *ofp;
347 347 long argj;
348 348 char *eptr;
349 349
350 350 g_progname = basename(argv[0]);
351 351
352 352 ctfmerge_altexec(argv);
353 353
354 354 /*
355 355 * We support a subset of the old CTF merge flags, mostly for
356 356 * compatibility.
357 357 */
358 358 while ((c = getopt(argc, argv, ":d:fgj:l:L:mo:t")) != -1) {
359 359 switch (c) {
360 360 case 'd':
361 361 g_unique = optarg;
362 362 break;
363 363 case 'f':
364 364 /* Silently ignored for compatibility */
365 365 break;
366 366 case 'g':
367 367 /* Silently ignored for compatibility */
368 368 break;
369 369 case 'j':
370 370 errno = 0;
371 371 argj = strtol(optarg, &eptr, 10);
372 372 if (errno != 0 || argj == LONG_MAX ||
373 373 argj > 1024 || *eptr != '\0') {
374 374 ctfmerge_fatal("invalid argument for -j: %s\n",
375 375 optarg);
376 376 }
377 377 nthreads = (uint_t)argj;
378 378 break;
379 379 case 'l':
380 380 label = optarg;
381 381 break;
382 382 case 'L':
383 383 label = getenv(optarg);
384 384 break;
385 385 case 'm':
386 386 flags |= CTF_ALLOW_MISSING_DEBUG;
387 387 break;
388 388 case 'o':
389 389 g_outfile = optarg;
390 390 break;
391 391 case 't':
392 392 /* Silently ignored for compatibility */
393 393 break;
394 394 case ':':
395 395 ctfmerge_usage("Option -%c requires an operand\n",
396 396 optopt);
397 397 return (CTFMERGE_USAGE);
398 398 case '?':
399 399 ctfmerge_usage("Unknown option: -%c\n", optopt);
400 400 return (CTFMERGE_USAGE);
401 401 }
402 402 }
403 403
404 404 if (g_outfile == NULL) {
405 405 ctfmerge_usage("missing required -o output file\n");
406 406 return (CTFMERGE_USAGE);
407 407 }
408 408
409 409 (void) elf_version(EV_CURRENT);
410 410
411 411 /*
412 412 * Obviously this isn't atomic, but at least gives us a good starting
413 413 * point.
414 414 */
415 415 if ((ofd = open(g_outfile, O_RDWR)) < 0)
416 416 ctfmerge_fatal("cannot open output file %s: %s\n", g_outfile,
417 417 strerror(errno));
418 418
419 419 argc -= optind;
420 420 argv += optind;
421 421
422 422 if (argc < 1) {
423 423 ctfmerge_usage("no input files specified");
424 424 return (CTFMERGE_USAGE);
425 425 }
426 426
427 427 cmh = ctf_merge_init(ofd, &err);
428 428 if (cmh == NULL)
429 429 ctfmerge_fatal("failed to create merge handle: %s\n",
430 430 ctf_errmsg(err));
431 431
432 432 if ((err = ctf_merge_set_nthreads(cmh, nthreads)) != 0)
433 433 ctfmerge_fatal("failed to set parallelism to %u: %s\n",
434 434 nthreads, ctf_errmsg(err));
435 435
436 436 for (i = 0; i < argc; i++) {
437 437 ctfmerge_file_add(cmh, argv[i], flags);
438 438 }
439 439
440 440 if (g_nctf == 0) {
441 441 ctf_merge_fini(cmh);
442 442 return (0);
443 443 }
444 444
445 445 if (g_unique != NULL) {
446 446 ctf_file_t *ufp;
447 447 char *base;
448 448
449 449 ufp = ctf_open(g_unique, &err);
450 450 if (ufp == NULL) {
451 451 ctfmerge_fatal("failed to open uniquify file %s: %s\n",
452 452 g_unique, ctf_errmsg(err));
453 453 }
454 454
455 455 base = basename(g_unique);
456 456 (void) ctf_merge_uniquify(cmh, ufp, base);
457 457 }
458 458
459 459 if (label != NULL) {
460 460 if ((err = ctf_merge_label(cmh, label)) != 0)
461 461 ctfmerge_fatal("failed to add label %s: %s\n", label,
462 462 ctf_errmsg(err));
463 463 }
464 464
465 465 err = ctf_merge_merge(cmh, &ofp);
466 466 if (err != 0)
467 467 ctfmerge_fatal("failed to merge types: %s\n", ctf_errmsg(err));
468 468 ctf_merge_fini(cmh);
469 469
470 470 if (asprintf(&tmpfile, "%s.ctf", g_outfile) == -1)
471 471 ctfmerge_fatal("ran out of memory for temporary file name\n");
472 472 err = ctf_elfwrite(ofp, g_outfile, tmpfile, wflags);
473 473 if (err == CTF_ERR) {
474 474 (void) unlink(tmpfile);
475 475 free(tmpfile);
476 476 ctfmerge_fatal("encountered a libctf error: %s!\n",
477 477 ctf_errmsg(ctf_errno(ofp)));
478 478 }
479 479
480 480 if (rename(tmpfile, g_outfile) != 0) {
481 481 (void) unlink(tmpfile);
482 482 free(tmpfile);
483 483 ctfmerge_fatal("failed to rename temporary file: %s\n",
484 484 strerror(errno));
485 485 }
486 486 free(tmpfile);
487 487
488 488 return (CTFMERGE_OK);
489 489 }
↓ open down ↓ |
429 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX