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