Print this page
10816 ctf_dwarf_convert_type() relies on un-initialized id
10817 ctfconvert -i option is mis-handled
10818 Improve ctfconvert error messages
10819 ctfconvert should handle empty dies
10820 ctfconvert -i never converts
10821 bad free in ctf_dwarf_init_die
10815 shouldn't build gcore.c as part of kmdb
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2017, Joyent, Inc.
  14  */
  15 
  16 /*
  17  * merge CTF containers
  18  */
  19 
  20 #include <stdio.h>
  21 #include <libctf.h>
  22 #include <sys/stat.h>
  23 #include <sys/types.h>
  24 #include <fcntl.h>
  25 #include <errno.h>
  26 #include <strings.h>
  27 #include <assert.h>
  28 #include <unistd.h>
  29 #include <sys/fcntl.h>
  30 #include <stdlib.h>
  31 #include <libelf.h>
  32 #include <gelf.h>
  33 #include <sys/mman.h>
  34 #include <libgen.h>
  35 #include <stdarg.h>
  36 #include <limits.h>
  37 
  38 static char *g_progname;
  39 static char *g_unique;
  40 static char *g_outfile;
  41 static boolean_t g_req;
  42 static uint_t g_nctf;
  43 
  44 #define CTFMERGE_OK     0
  45 #define CTFMERGE_FATAL  1
  46 #define CTFMERGE_USAGE  2
  47 
  48 #define CTFMERGE_DEFAULT_NTHREADS       8
  49 #define CTFMERGE_ALTEXEC        "CTFMERGE_ALTEXEC"
  50 
  51 static void
  52 ctfmerge_fatal(const char *fmt, ...)
  53 {
  54         va_list ap;
  55 
  56         (void) fprintf(stderr, "%s: ", g_progname);
  57         va_start(ap, fmt);
  58         (void) vfprintf(stderr, fmt, ap);
  59         va_end(ap);
  60 
  61         if (g_outfile != NULL)
  62                 (void) unlink(g_outfile);
  63 
  64         exit(CTFMERGE_FATAL);
  65 }
  66 
  67 static boolean_t
  68 ctfmerge_expect_ctf(const char *name, Elf *elf)




  69 {
  70         Elf_Scn *scn, *strscn;
  71         Elf_Data *data, *strdata;
  72         GElf_Shdr shdr;
  73         ulong_t i;
  74 
  75         if (g_req == B_FALSE)
  76                 return (B_FALSE);
  77 
  78         scn = NULL;
  79         while ((scn = elf_nextscn(elf, scn)) != NULL) {
  80                 if (gelf_getshdr(scn, &shdr) == NULL) {
  81                         ctfmerge_fatal("failed to get section header for file "
  82                             "%s: %s\n", name, elf_errmsg(elf_errno()));
  83                 }
  84 
  85                 if (shdr.sh_type == SHT_SYMTAB)
  86                         break;
  87         }
  88 
  89         if (scn == NULL)
  90                 return (B_FALSE);
  91 
  92         if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL)
  93                 ctfmerge_fatal("failed to get section header for file %s: %s\n",
  94                     name, elf_errmsg(elf_errno()));
  95 
  96         if ((data = elf_getdata(scn, NULL)) == NULL)
  97                 ctfmerge_fatal("failed to read symbol table for %s: %s\n",
  98                     name, elf_errmsg(elf_errno()));
  99 
 100         if ((strdata = elf_getdata(strscn, NULL)) == NULL)
 101                 ctfmerge_fatal("failed to read string table for %s: %s\n",
 102                     name, elf_errmsg(elf_errno()));
 103 
 104         for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
 105                 GElf_Sym sym;
 106                 const char *file;
 107                 size_t len;
 108 
 109                 if (gelf_getsym(data, i, &sym) == NULL)
 110                         ctfmerge_fatal("failed to read symbol table entry %lu "
 111                             "for %s: %s\n", i, name, elf_errmsg(elf_errno()));
 112 
 113                 if (GELF_ST_TYPE(sym.st_info) != STT_FILE)
 114                         continue;
 115 
 116                 file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);
 117                 len = strlen(file);
 118                 if (len < 2 || name[len - 2] != '.')
 119                         continue;
 120 
 121                 if (name[len - 1] == 'c')
 122                         return (B_TRUE);
 123         }
 124 
 125         return (B_FALSE);
 126 }
 127 
 128 /*
 129  * Go through and construct enough information for this Elf Object to try and do
 130  * a ctf_bufopen().
 131  */
 132 static void
 133 ctfmerge_elfopen(const char *name, Elf *elf, ctf_merge_t *cmh)
 134 {
 135         GElf_Ehdr ehdr;
 136         GElf_Shdr shdr;
 137         Elf_Scn *scn;
 138         Elf_Data *ctf_data, *str_data, *sym_data;
 139         ctf_sect_t ctfsect, symsect, strsect;
 140         ctf_file_t *fp;
 141         int err;
 142 
 143         if (gelf_getehdr(elf, &ehdr) == NULL)
 144                 ctfmerge_fatal("failed to get ELF header for %s: %s\n",
 145                     name, elf_errmsg(elf_errno()));
 146 
 147         bzero(&ctfsect, sizeof (ctf_sect_t));
 148         bzero(&symsect, sizeof (ctf_sect_t));
 149         bzero(&strsect, sizeof (ctf_sect_t));
 150 
 151         scn = NULL;
 152         while ((scn = elf_nextscn(elf, scn)) != NULL) {
 153                 const char *sname;


 197                         strsect.cts_entsize = strhdr.sh_entsize;
 198                         strsect.cts_offset = (off64_t)strhdr.sh_offset;
 199 
 200                         sym_data = elf_getdata(scn, NULL);
 201                         if (sym_data == NULL)
 202                                 ctfmerge_fatal("failed to get ELF CTF "
 203                                     "data section for %s: %s\n", name,
 204                                     elf_errmsg(elf_errno()));
 205                         symsect.cts_data = sym_data->d_buf;
 206 
 207                         str_data = elf_getdata(strscn, NULL);
 208                         if (str_data == NULL)
 209                                 ctfmerge_fatal("failed to get ELF CTF "
 210                                     "data section for %s: %s\n", name,
 211                                     elf_errmsg(elf_errno()));
 212                         strsect.cts_data = str_data->d_buf;
 213                 }
 214         }
 215 
 216         if (ctfsect.cts_type == SHT_NULL) {
 217                 if (ctfmerge_expect_ctf(name, elf) == B_FALSE)
 218                         return;
 219                 ctfmerge_fatal("failed to open %s: %s\n", name,
 220                     ctf_errmsg(ECTF_NOCTFDATA));
 221         }
 222 
 223         if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL) {
 224                 fp = ctf_bufopen(&ctfsect, &symsect, &strsect, &err);
 225         } else {
 226                 fp = ctf_bufopen(&ctfsect, NULL, NULL, &err);
 227         }
 228 
 229         if (fp == NULL) {
 230                 if (ctfmerge_expect_ctf(name, elf) == B_TRUE) {
 231                         ctfmerge_fatal("failed to open file %s: %s\n",
 232                             name, ctf_errmsg(err));
 233                 }
 234         } else {
 235                 if ((err = ctf_merge_add(cmh, fp)) != 0) {
 236                         ctfmerge_fatal("failed to add input %s: %s\n",
 237                             name, ctf_errmsg(err));
 238                 }

 239                 g_nctf++;
 240         }
 241 }
 242 
 243 static void
 244 ctfmerge_read_archive(const char *name, int fd, Elf *elf,
 245     ctf_merge_t *cmh)
 246 {
 247         Elf *aelf;
 248         Elf_Cmd cmd = ELF_C_READ;
 249         int cursec = 1;
 250         char *nname;
 251 
 252         while ((aelf = elf_begin(fd, cmd, elf)) != NULL) {

 253                 Elf_Arhdr *arhdr;
 254                 boolean_t leakelf = B_FALSE;
 255 
 256                 if ((arhdr = elf_getarhdr(aelf)) == NULL)
 257                         ctfmerge_fatal("failed to get archive header %d for "
 258                             "%s: %s\n", cursec, name, elf_errmsg(elf_errno()));
 259 


 260                 if (*(arhdr->ar_name) == '/')
 261                         goto next;
 262 
 263                 if (asprintf(&nname, "%s.%s.%d", name, arhdr->ar_name,
 264                     cursec) < 0)
 265                         ctfmerge_fatal("failed to allocate memory for archive "
 266                             "%d of file %s\n", cursec, name);
 267 
 268                 switch (elf_kind(aelf)) {
 269                 case ELF_K_AR:
 270                         ctfmerge_read_archive(nname, fd, aelf, cmh);
 271                         free(nname);
 272                         break;
 273                 case ELF_K_ELF:
 274                         ctfmerge_elfopen(nname, aelf, cmh);
 275                         free(nname);
 276                         leakelf = B_TRUE;
 277                         break;
 278                 default:
 279                         ctfmerge_fatal("unknown elf kind (%d) in archive %d "
 280                             "for %s\n", elf_kind(aelf), cursec, name);

 281                 }
 282 
 283 next:
 284                 cmd = elf_next(aelf);
 285                 if (leakelf == B_FALSE)
 286                         (void) elf_end(aelf);

 287                 cursec++;
 288         }
 289 }
 290 
 291 static void





































 292 ctfmerge_usage(const char *fmt, ...)
 293 {
 294         if (fmt != NULL) {
 295                 va_list ap;
 296 
 297                 (void) fprintf(stderr, "%s: ", g_progname);
 298                 va_start(ap, fmt);
 299                 (void) vfprintf(stderr, fmt, ap);
 300                 va_end(ap);
 301         }
 302 
 303         (void) fprintf(stderr, "Usage: %s [-t] [-d uniqfile] [-l label] "
 304             "[-L labelenv] [-j nthrs] -o outfile file ...\n"
 305             "\n"
 306             "\t-d  uniquify merged output against uniqfile\n"
 307             "\t-j  use nthrs threads to perform the merge\n"
 308             "\t-l  set output container's label to specified value\n"
 309             "\t-L  set output container's label to value from environment\n"
 310             "\t-o  file to add CTF data to\n"
 311             "\t-t  require CTF data from all inputs built from C sources\n",
 312             g_progname);
 313 }
 314 
 315 static void
 316 ctfmerge_altexec(char **argv)
 317 {
 318         const char *alt;
 319         char *altexec;
 320 
 321         alt = getenv(CTFMERGE_ALTEXEC);
 322         if (alt == NULL || *alt == '\0')
 323                 return;
 324 
 325         altexec = strdup(alt);
 326         if (altexec == NULL)
 327                 ctfmerge_fatal("failed to allocate memory for altexec\n");
 328         if (unsetenv(CTFMERGE_ALTEXEC) != 0)
 329                 ctfmerge_fatal("failed to unset %s from environment: %s\n",
 330                     CTFMERGE_ALTEXEC, strerror(errno));
 331 
 332         (void) execv(altexec, argv);
 333         ctfmerge_fatal("failed to execute alternate program %s: %s",
 334             altexec, strerror(errno));
 335 }
 336 
 337 int
 338 main(int argc, char *argv[])
 339 {
 340         int err, i, c, ofd;
 341         uint_t nthreads = CTFMERGE_DEFAULT_NTHREADS;
 342         char *tmpfile = NULL, *label = NULL;
 343         int wflags = CTF_ELFWRITE_F_COMPRESS;
 344         ctf_file_t *ofp;
 345         ctf_merge_t *cmh;

 346         long argj;
 347         char *eptr;
 348 
 349         g_progname = basename(argv[0]);
 350 
 351         ctfmerge_altexec(argv);
 352 
 353         /*
 354          * We support a subset of the old CTF merge flags, mostly for
 355          * compatability.
 356          */
 357         while ((c = getopt(argc, argv, ":d:fgj:l:L:o:t")) != -1) {
 358                 switch (c) {
 359                 case 'd':
 360                         g_unique = optarg;
 361                         break;
 362                 case 'f':
 363                         /* Silently ignored for compatibility */
 364                         break;
 365                 case 'g':
 366                         /* Silently ignored for compatibility */
 367                         break;
 368                 case 'j':
 369                         errno = 0;
 370                         argj = strtol(optarg, &eptr, 10);
 371                         if (errno != 0 || argj == LONG_MAX ||
 372                             argj > 1024 || *eptr != '\0') {
 373                                 ctfmerge_fatal("invalid argument for -j: %s\n",
 374                                     optarg);
 375                         }
 376                         nthreads = (uint_t)argj;
 377                         break;
 378                 case 'l':
 379                         label = optarg;
 380                         break;
 381                 case 'L':
 382                         label = getenv(optarg);
 383                         break;



 384                 case 'o':
 385                         g_outfile = optarg;
 386                         break;
 387                 case 't':
 388                         g_req = B_TRUE;
 389                         break;
 390                 case ':':
 391                         ctfmerge_usage("Option -%c requires an operand\n",
 392                             optopt);
 393                         return (CTFMERGE_USAGE);
 394                 case '?':
 395                         ctfmerge_usage("Unknown option: -%c\n", optopt);
 396                         return (CTFMERGE_USAGE);
 397                 }
 398         }
 399 
 400         if (g_outfile == NULL) {
 401                 ctfmerge_usage("missing required -o output file\n");
 402                 return (CTFMERGE_USAGE);
 403         }
 404 
 405         (void) elf_version(EV_CURRENT);
 406 
 407         /*
 408          * Obviously this isn't atomic, but at least gives us a good starting


 413                     strerror(errno));
 414 
 415         argc -= optind;
 416         argv += optind;
 417 
 418         if (argc < 1) {
 419                 ctfmerge_usage("no input files specified");
 420                 return (CTFMERGE_USAGE);
 421         }
 422 
 423         cmh = ctf_merge_init(ofd, &err);
 424         if (cmh == NULL)
 425                 ctfmerge_fatal("failed to create merge handle: %s\n",
 426                     ctf_errmsg(err));
 427 
 428         if ((err = ctf_merge_set_nthreads(cmh, nthreads)) != 0)
 429                 ctfmerge_fatal("failed to set parallelism to %u: %s\n",
 430                     nthreads, ctf_errmsg(err));
 431 
 432         for (i = 0; i < argc; i++) {
 433                 ctf_file_t *ifp;
 434                 int fd;
 435 
 436                 if ((fd = open(argv[i], O_RDONLY)) < 0)
 437                         ctfmerge_fatal("failed to open file %s: %s\n",
 438                             argv[i], strerror(errno));
 439                 ifp = ctf_fdopen(fd, &err);
 440                 if (ifp == NULL) {
 441                         Elf *e;
 442 
 443                         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
 444                                 (void) close(fd);
 445                                 ctfmerge_fatal("failed to open %s: %s\n",
 446                                     argv[i], ctf_errmsg(err));
 447                         }
 448 
 449                         /*
 450                          * It's an ELF file, check if we have an archive or if
 451                          * we're expecting CTF here.
 452                          */
 453                         switch (elf_kind(e)) {
 454                         case ELF_K_AR:
 455                                 break;
 456                         case ELF_K_ELF:
 457                                 if (ctfmerge_expect_ctf(argv[i], e) == B_TRUE) {
 458                                         (void) elf_end(e);
 459                                         (void) close(fd);
 460                                         ctfmerge_fatal("failed to "
 461                                             "open %s: file was built from C "
 462                                             "sources, but missing CTF\n",
 463                                             argv[i]);
 464                                 }
 465                                 (void) elf_end(e);
 466                                 (void) close(fd);
 467                                 continue;
 468                         default:
 469                                 (void) elf_end(e);
 470                                 (void) close(fd);
 471                                 ctfmerge_fatal("failed to open %s: "
 472                                     "unsupported ELF file type", argv[i]);
 473                         }
 474 
 475                         ctfmerge_read_archive(argv[i], fd, e, cmh);
 476                         (void) elf_end(e);
 477                         (void) close(fd);
 478                         continue;
 479                 }
 480                 (void) close(fd);
 481                 if ((err = ctf_merge_add(cmh, ifp)) != 0)
 482                         ctfmerge_fatal("failed to add input %s: %s\n",
 483                             argv[i], ctf_errmsg(err));
 484                 g_nctf++;
 485         }
 486 
 487         if (g_nctf == 0) {
 488                 ctf_merge_fini(cmh);
 489                 return (0);
 490         }
 491 
 492         if (g_unique != NULL) {
 493                 ctf_file_t *ufp;
 494                 char *base;
 495 
 496                 ufp = ctf_open(g_unique, &err);
 497                 if (ufp == NULL) {
 498                         ctfmerge_fatal("failed to open uniquify file %s: %s\n",
 499                             g_unique, ctf_errmsg(err));
 500                 }
 501 
 502                 base = basename(g_unique);
 503                 (void) ctf_merge_uniquify(cmh, ufp, base);
 504         }
 505 
 506         if (label != NULL) {


   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2019, Joyent, Inc.
  14  */
  15 
  16 /*
  17  * merge CTF containers
  18  */
  19 
  20 #include <stdio.h>
  21 #include <libctf.h>
  22 #include <sys/stat.h>
  23 #include <sys/types.h>
  24 #include <fcntl.h>
  25 #include <errno.h>
  26 #include <strings.h>
  27 #include <assert.h>
  28 #include <unistd.h>
  29 #include <sys/fcntl.h>
  30 #include <stdlib.h>
  31 #include <libelf.h>
  32 #include <gelf.h>
  33 #include <sys/mman.h>
  34 #include <libgen.h>
  35 #include <stdarg.h>
  36 #include <limits.h>
  37 
  38 static char *g_progname;
  39 static char *g_unique;
  40 static char *g_outfile;

  41 static uint_t g_nctf;
  42 
  43 #define CTFMERGE_OK     0
  44 #define CTFMERGE_FATAL  1
  45 #define CTFMERGE_USAGE  2
  46 
  47 #define CTFMERGE_DEFAULT_NTHREADS       8
  48 #define CTFMERGE_ALTEXEC        "CTFMERGE_ALTEXEC"
  49 
  50 static void
  51 ctfmerge_fatal(const char *fmt, ...)
  52 {
  53         va_list ap;
  54 
  55         (void) fprintf(stderr, "%s: ", g_progname);
  56         va_start(ap, fmt);
  57         (void) vfprintf(stderr, fmt, ap);
  58         va_end(ap);
  59 
  60         if (g_outfile != NULL)
  61                 (void) unlink(g_outfile);
  62 
  63         exit(CTFMERGE_FATAL);
  64 }
  65 
  66 /*
  67  * We failed to find CTF for this file, check if it's OK. If we're not derived
  68  * from C, or we have the -m option, we let missing CTF pass.
  69  */
  70 static void
  71 ctfmerge_check_for_c(const char *name, Elf *elf, uint_t flags)
  72 {
  73         char errmsg[1024];



  74 
  75         if (flags & CTF_ALLOW_MISSING_DEBUG)
  76                 return;
  77 
  78         switch (ctf_has_c_source(elf, errmsg, sizeof (errmsg))) {
  79         case CHR_ERROR:
  80                 ctfmerge_fatal("failed to open %s: %s\n", name, errmsg);





  81                 break;

  82 
  83         case CHR_NO_C_SOURCE:
  84                 return;
  85 
  86         default:
  87                 ctfmerge_fatal("failed to open %s: %s\n", name,
  88                     ctf_errmsg(ECTF_NOCTFDATA));
  89                 break;



























  90         }


  91 }
  92 
  93 /*
  94  * Go through and construct enough information for this Elf Object to try and do
  95  * a ctf_bufopen().
  96  */
  97 static int
  98 ctfmerge_elfopen(const char *name, Elf *elf, ctf_merge_t *cmh, uint_t flags)
  99 {
 100         GElf_Ehdr ehdr;
 101         GElf_Shdr shdr;
 102         Elf_Scn *scn;
 103         Elf_Data *ctf_data, *str_data, *sym_data;
 104         ctf_sect_t ctfsect, symsect, strsect;
 105         ctf_file_t *fp;
 106         int err;
 107 
 108         if (gelf_getehdr(elf, &ehdr) == NULL)
 109                 ctfmerge_fatal("failed to get ELF header for %s: %s\n",
 110                     name, elf_errmsg(elf_errno()));
 111 
 112         bzero(&ctfsect, sizeof (ctf_sect_t));
 113         bzero(&symsect, sizeof (ctf_sect_t));
 114         bzero(&strsect, sizeof (ctf_sect_t));
 115 
 116         scn = NULL;
 117         while ((scn = elf_nextscn(elf, scn)) != NULL) {
 118                 const char *sname;


 162                         strsect.cts_entsize = strhdr.sh_entsize;
 163                         strsect.cts_offset = (off64_t)strhdr.sh_offset;
 164 
 165                         sym_data = elf_getdata(scn, NULL);
 166                         if (sym_data == NULL)
 167                                 ctfmerge_fatal("failed to get ELF CTF "
 168                                     "data section for %s: %s\n", name,
 169                                     elf_errmsg(elf_errno()));
 170                         symsect.cts_data = sym_data->d_buf;
 171 
 172                         str_data = elf_getdata(strscn, NULL);
 173                         if (str_data == NULL)
 174                                 ctfmerge_fatal("failed to get ELF CTF "
 175                                     "data section for %s: %s\n", name,
 176                                     elf_errmsg(elf_errno()));
 177                         strsect.cts_data = str_data->d_buf;
 178                 }
 179         }
 180 
 181         if (ctfsect.cts_type == SHT_NULL) {
 182                 ctfmerge_check_for_c(name, elf, flags);
 183                 return (ENOENT);


 184         }
 185 
 186         if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL) {
 187                 fp = ctf_bufopen(&ctfsect, &symsect, &strsect, &err);
 188         } else {
 189                 fp = ctf_bufopen(&ctfsect, NULL, NULL, &err);
 190         }
 191 
 192         if (fp == NULL) {

 193                 ctfmerge_fatal("failed to open file %s: %s\n",
 194                     name, ctf_errmsg(err));
 195         }
 196 
 197         if ((err = ctf_merge_add(cmh, fp)) != 0) {
 198                 ctfmerge_fatal("failed to add input %s: %s\n",
 199                     name, ctf_errmsg(err));
 200         }
 201 
 202         g_nctf++;
 203         return (0);
 204 }
 205 
 206 static void
 207 ctfmerge_read_archive(const char *name, int fd, Elf *elf,
 208     ctf_merge_t *cmh, uint_t flags)
 209 {

 210         Elf_Cmd cmd = ELF_C_READ;
 211         int cursec = 1;
 212         Elf *aelf;
 213 
 214         while ((aelf = elf_begin(fd, cmd, elf)) != NULL) {
 215                 char *nname = NULL;
 216                 Elf_Arhdr *arhdr;

 217 
 218                 if ((arhdr = elf_getarhdr(aelf)) == NULL)
 219                         ctfmerge_fatal("failed to get archive header %d for "
 220                             "%s: %s\n", cursec, name, elf_errmsg(elf_errno()));
 221 
 222                 cmd = elf_next(aelf);
 223 
 224                 if (*(arhdr->ar_name) == '/')
 225                         goto next;
 226 
 227                 if (asprintf(&nname, "%s.%s.%d", name, arhdr->ar_name,
 228                     cursec) < 0)
 229                         ctfmerge_fatal("failed to allocate memory for archive "
 230                             "%d of file %s\n", cursec, name);
 231 
 232                 switch (elf_kind(aelf)) {
 233                 case ELF_K_AR:
 234                         ctfmerge_read_archive(nname, fd, aelf, cmh, flags);

 235                         break;
 236                 case ELF_K_ELF:
 237                         /* ctfmerge_elfopen() takes ownership of aelf. */
 238                         if (ctfmerge_elfopen(nname, aelf, cmh, flags) == 0)
 239                                 aelf = NULL;
 240                         break;
 241                 default:
 242                         ctfmerge_fatal("unknown elf kind (%d) in archive %d "
 243                             "for %s\n", elf_kind(aelf), cursec, name);
 244                         break;
 245                 }
 246 
 247 next:


 248                 (void) elf_end(aelf);
 249                 free(nname);
 250                 cursec++;
 251         }
 252 }
 253 
 254 static void
 255 ctfmerge_file_add(ctf_merge_t *cmh, const char *file, uint_t flags)
 256 {
 257         Elf *e;
 258         int fd;
 259 
 260         if ((fd = open(file, O_RDONLY)) < 0) {
 261                 ctfmerge_fatal("failed to open file %s: %s\n",
 262                     file, strerror(errno));
 263         }
 264 
 265         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
 266                 (void) close(fd);
 267                 ctfmerge_fatal("failed to open %s: %s\n",
 268                     file, elf_errmsg(elf_errno()));
 269         }
 270 
 271         switch (elf_kind(e)) {
 272         case ELF_K_AR:
 273                 ctfmerge_read_archive(file, fd, e, cmh, flags);
 274                 break;
 275 
 276         case ELF_K_ELF:
 277                 /* ctfmerge_elfopen() takes ownership of e. */
 278                 if (ctfmerge_elfopen(file, e, cmh, flags) == 0)
 279                         e = NULL;
 280                 break;
 281 
 282         default:
 283                 ctfmerge_fatal("unknown elf kind (%d) for %s\n",
 284                     elf_kind(e), file);
 285         }
 286 
 287         (void) elf_end(e);
 288         (void) close(fd);
 289 }
 290 
 291 static void
 292 ctfmerge_usage(const char *fmt, ...)
 293 {
 294         if (fmt != NULL) {
 295                 va_list ap;
 296 
 297                 (void) fprintf(stderr, "%s: ", g_progname);
 298                 va_start(ap, fmt);
 299                 (void) vfprintf(stderr, fmt, ap);
 300                 va_end(ap);
 301         }
 302 
 303         (void) fprintf(stderr, "Usage: %s [-m] [-d uniqfile] [-l label] "
 304             "[-L labelenv] [-j nthrs] -o outfile file ...\n"
 305             "\n"
 306             "\t-d  uniquify merged output against uniqfile\n"
 307             "\t-j  use nthrs threads to perform the merge\n"
 308             "\t-l  set output container's label to specified value\n"
 309             "\t-L  set output container's label to value from environment\n"
 310             "\t-m  allow C-based input files to not have CTF\n"
 311             "\t-o  file to add CTF data to\n",
 312             g_progname);
 313 }
 314 
 315 static void
 316 ctfmerge_altexec(char **argv)
 317 {
 318         const char *alt;
 319         char *altexec;
 320 
 321         alt = getenv(CTFMERGE_ALTEXEC);
 322         if (alt == NULL || *alt == '\0')
 323                 return;
 324 
 325         altexec = strdup(alt);
 326         if (altexec == NULL)
 327                 ctfmerge_fatal("failed to allocate memory for altexec\n");
 328         if (unsetenv(CTFMERGE_ALTEXEC) != 0)
 329                 ctfmerge_fatal("failed to unset %s from environment: %s\n",
 330                     CTFMERGE_ALTEXEC, strerror(errno));
 331 
 332         (void) execv(altexec, argv);
 333         ctfmerge_fatal("failed to execute alternate program %s: %s",
 334             altexec, strerror(errno));
 335 }
 336 
 337 int
 338 main(int argc, char *argv[])
 339 {
 340         int err, i, c, ofd;
 341         uint_t nthreads = CTFMERGE_DEFAULT_NTHREADS;
 342         char *tmpfile = NULL, *label = NULL;
 343         int wflags = CTF_ELFWRITE_F_COMPRESS;
 344         uint_t flags = 0;
 345         ctf_merge_t *cmh;
 346         ctf_file_t *ofp;
 347         long argj;
 348         char *eptr;
 349 
 350         g_progname = basename(argv[0]);
 351 
 352         ctfmerge_altexec(argv);
 353 
 354         /*
 355          * We support a subset of the old CTF merge flags, mostly for
 356          * compatibility.
 357          */
 358         while ((c = getopt(argc, argv, ":d:fgj:l:L:mo:t")) != -1) {
 359                 switch (c) {
 360                 case 'd':
 361                         g_unique = optarg;
 362                         break;
 363                 case 'f':
 364                         /* Silently ignored for compatibility */
 365                         break;
 366                 case 'g':
 367                         /* Silently ignored for compatibility */
 368                         break;
 369                 case 'j':
 370                         errno = 0;
 371                         argj = strtol(optarg, &eptr, 10);
 372                         if (errno != 0 || argj == LONG_MAX ||
 373                             argj > 1024 || *eptr != '\0') {
 374                                 ctfmerge_fatal("invalid argument for -j: %s\n",
 375                                     optarg);
 376                         }
 377                         nthreads = (uint_t)argj;
 378                         break;
 379                 case 'l':
 380                         label = optarg;
 381                         break;
 382                 case 'L':
 383                         label = getenv(optarg);
 384                         break;
 385                 case 'm':
 386                         flags |= CTF_ALLOW_MISSING_DEBUG;
 387                         break;
 388                 case 'o':
 389                         g_outfile = optarg;
 390                         break;
 391                 case 't':
 392                         /* Silently ignored for compatibility */
 393                         break;
 394                 case ':':
 395                         ctfmerge_usage("Option -%c requires an operand\n",
 396                             optopt);
 397                         return (CTFMERGE_USAGE);
 398                 case '?':
 399                         ctfmerge_usage("Unknown option: -%c\n", optopt);
 400                         return (CTFMERGE_USAGE);
 401                 }
 402         }
 403 
 404         if (g_outfile == NULL) {
 405                 ctfmerge_usage("missing required -o output file\n");
 406                 return (CTFMERGE_USAGE);
 407         }
 408 
 409         (void) elf_version(EV_CURRENT);
 410 
 411         /*
 412          * Obviously this isn't atomic, but at least gives us a good starting


 417                     strerror(errno));
 418 
 419         argc -= optind;
 420         argv += optind;
 421 
 422         if (argc < 1) {
 423                 ctfmerge_usage("no input files specified");
 424                 return (CTFMERGE_USAGE);
 425         }
 426 
 427         cmh = ctf_merge_init(ofd, &err);
 428         if (cmh == NULL)
 429                 ctfmerge_fatal("failed to create merge handle: %s\n",
 430                     ctf_errmsg(err));
 431 
 432         if ((err = ctf_merge_set_nthreads(cmh, nthreads)) != 0)
 433                 ctfmerge_fatal("failed to set parallelism to %u: %s\n",
 434                     nthreads, ctf_errmsg(err));
 435 
 436         for (i = 0; i < argc; i++) {
 437                 ctfmerge_file_add(cmh, argv[i], flags);













 438         }
 439 






































 440         if (g_nctf == 0) {
 441                 ctf_merge_fini(cmh);
 442                 return (0);
 443         }
 444 
 445         if (g_unique != NULL) {
 446                 ctf_file_t *ufp;
 447                 char *base;
 448 
 449                 ufp = ctf_open(g_unique, &err);
 450                 if (ufp == NULL) {
 451                         ctfmerge_fatal("failed to open uniquify file %s: %s\n",
 452                             g_unique, ctf_errmsg(err));
 453                 }
 454 
 455                 base = basename(g_unique);
 456                 (void) ctf_merge_uniquify(cmh, ufp, base);
 457         }
 458 
 459         if (label != NULL) {