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) 2015, Joyent, Inc.
  14  */
  15 
  16 /*
  17  * Create CTF from extant debugging information
  18  */
  19 
  20 #include <stdio.h>
  21 #include <unistd.h>
  22 #include <stdlib.h>
  23 #include <stdarg.h>
  24 #include <sys/types.h>
  25 #include <sys/stat.h>
  26 #include <fcntl.h>
  27 #include <errno.h>
  28 #include <libelf.h>
  29 #include <libctf.h>
  30 #include <string.h>
  31 #include <libgen.h>
  32 #include <limits.h>
  33 #include <strings.h>


  52         va_start(ap, fmt);
  53         (void) vfprintf(stderr, fmt, ap);
  54         va_end(ap);
  55 
  56         exit(CTFCONVERT_FATAL);
  57 }
  58 
  59 
  60 static void
  61 ctfconvert_usage(const char *fmt, ...)
  62 {
  63         if (fmt != NULL) {
  64                 va_list ap;
  65 
  66                 (void) fprintf(stderr, "%s: ", ctfconvert_progname);
  67                 va_start(ap, fmt);
  68                 (void) vfprintf(stderr, fmt, ap);
  69                 va_end(ap);
  70         }
  71 
  72         (void) fprintf(stderr, "Usage: %s [-is] [-j nthrs] [-l label | "
  73             "-L labelenv] [-o outfile] input\n"
  74             "\n"
  75             "\t-i  ignore files not built partially from C sources\n"
  76             "\t-j  use nthrs threads to perform the merge\n"
  77             "\t-k  keep around original input file on failure\n"

  78             "\t-o  copy input to outfile and add CTF\n"
  79             "\t-l  set output container's label to specified value\n"
  80             "\t-L  set output container's label to value from environment\n",
  81             ctfconvert_progname);
  82 }
  83 
  84 /*
  85  * This is a bit unfortunate. Traditionally we do type uniquification across all
  86  * modules in the kernel, including ip and unix against genunix. However, when
  87  * _MACHDEP is defined, then the cpu_t ends up having an additional member
  88  * (cpu_m), thus changing the ability for us to uniquify against it. This in
  89  * turn causes a lot of type sprawl, as there's a lot of things that end up
  90  * referring to the cpu_t and it chains out from there.
  91  *
  92  * So, if we find that a cpu_t has been defined and it has a couple of useful
  93  * sentinel members and it does *not* have the cpu_m member, then we will try
  94  * and lookup or create a forward declaration to the machcpu, append it to the
  95  * end, and update the file.
  96  *
  97  * This currently is only invoked if an undocumented option -X is passed. This


 242         ctfconvert_fatal("failed to execute alternate program %s: %s",
 243             altexec, strerror(errno));
 244 }
 245 
 246 int
 247 main(int argc, char *argv[])
 248 {
 249         int c, ifd, err;
 250         boolean_t keep = B_FALSE;
 251         uint_t flags = 0;
 252         uint_t nthreads = CTFCONVERT_DEFAULT_NTHREADS;
 253         const char *outfile = NULL;
 254         const char *label = NULL;
 255         const char *infile = NULL;
 256         char *tmpfile;
 257         ctf_file_t *ofp;
 258         long argj;
 259         char *eptr;
 260         char buf[4096];
 261         boolean_t optx = B_FALSE;

 262 
 263         ctfconvert_progname = basename(argv[0]);
 264 
 265         ctfconvert_altexec(argv);
 266 
 267         while ((c = getopt(argc, argv, ":j:kl:L:o:iX")) != -1) {
 268                 switch (c) {
 269                 case 'k':
 270                         keep = B_TRUE;
 271                         break;
 272                 case 'l':
 273                         label = optarg;
 274                         break;
 275                 case 'L':
 276                         label = getenv(optarg);
 277                         break;
 278                 case 'j':
 279                         errno = 0;
 280                         argj = strtol(optarg, &eptr, 10);
 281                         if (errno != 0 || argj == LONG_MAX ||
 282                             argj > 1024 || *eptr != '\0') {
 283                                 ctfconvert_fatal("invalid argument for -j: "
 284                                     "%s\n", optarg);
 285                         }
 286                         nthreads = (uint_t)argj;
 287                         break;












 288                 case 'o':
 289                         outfile = optarg;
 290                         break;
 291                 case 'i':
 292                         flags |= CTF_CONVERT_F_IGNNONC;
 293                         break;
 294                 case 'X':
 295                         optx = B_TRUE;
 296                         break;
 297                 case ':':
 298                         ctfconvert_usage("Option -%c requires an operand\n",
 299                             optopt);
 300                         return (CTFCONVERT_USAGE);
 301                 case '?':
 302                         ctfconvert_usage("Unknown option: -%c\n", optopt);
 303                         return (CTFCONVERT_USAGE);
 304                 }
 305         }
 306 
 307         argv += optind;
 308         argc -= optind;
 309 
 310         if (argc < 1) {
 311                 ctfconvert_usage("Missing required input file\n");
 312                 return (CTFCONVERT_USAGE);
 313         }
 314         infile = argv[0];
 315 
 316         if (elf_version(EV_CURRENT) == EV_NONE)
 317                 ctfconvert_fatal("failed to initialize libelf: library is "
 318                     "out of date\n");
 319 
 320         ifd = open(infile, O_RDONLY);
 321         if (ifd < 0) {
 322                 ctfconvert_fatal("failed to open input file %s: %s\n", infile,
 323                     strerror(errno));
 324         }
 325 
 326         /*
 327          * By default we remove the input file on failure unless we've been
 328          * given an output file or -k has been specified.
 329          */
 330         if (outfile != NULL && strcmp(infile, outfile) != 0)
 331                 keep = B_TRUE;
 332 
 333         ofp = ctf_fdconvert(ifd, label, nthreads, flags, &err, buf,
 334             sizeof (buf));
 335         if (ofp == NULL) {
 336                 /*
 337                  * -i says that we shouldn't concern ourselves with source files
 338                  * that weren't built from C source code in part. Because this
 339                  * has been traditionally used across all of illumos, we still
 340                  * honor it.



 341                  */
 342                 if ((flags & CTF_CONVERT_F_IGNNONC) != 0 &&
 343                     err == ECTF_CONVNOCSRC) {
 344                         exit(CTFCONVERT_OK);
 345                 }






 346                 if (keep == B_FALSE)
 347                         (void) unlink(infile);




 348                 ctfconvert_fatal("CTF conversion failed: %s\n",
 349                     err == ECTF_CONVBKERR ? buf : ctf_errmsg(err));
 350         }

 351 
 352         if (optx == B_TRUE)
 353                 ctfconvert_fixup_genunix(ofp);
 354 
 355         tmpfile = NULL;
 356         if (outfile == NULL || strcmp(infile, outfile) == 0) {
 357                 if (asprintf(&tmpfile, "%s.ctf", infile) == -1) {
 358                         if (keep == B_FALSE)
 359                                 (void) unlink(infile);
 360                         ctfconvert_fatal("failed to allocate memory for "
 361                             "temporary file: %s\n", strerror(errno));
 362                 }
 363                 outfile = tmpfile;
 364         }
 365         err = ctf_elfwrite(ofp, infile, outfile, CTF_ELFWRITE_F_COMPRESS);
 366         if (err == CTF_ERR) {
 367                 (void) unlink(outfile);
 368                 if (keep == B_FALSE)
 369                         (void) unlink(infile);
 370                 ctfconvert_fatal("failed to write CTF section to output file: "
   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  * Create CTF from extant debugging information
  18  */
  19 
  20 #include <stdio.h>
  21 #include <unistd.h>
  22 #include <stdlib.h>
  23 #include <stdarg.h>
  24 #include <sys/types.h>
  25 #include <sys/stat.h>
  26 #include <fcntl.h>
  27 #include <errno.h>
  28 #include <libelf.h>
  29 #include <libctf.h>
  30 #include <string.h>
  31 #include <libgen.h>
  32 #include <limits.h>
  33 #include <strings.h>


  52         va_start(ap, fmt);
  53         (void) vfprintf(stderr, fmt, ap);
  54         va_end(ap);
  55 
  56         exit(CTFCONVERT_FATAL);
  57 }
  58 
  59 
  60 static void
  61 ctfconvert_usage(const char *fmt, ...)
  62 {
  63         if (fmt != NULL) {
  64                 va_list ap;
  65 
  66                 (void) fprintf(stderr, "%s: ", ctfconvert_progname);
  67                 va_start(ap, fmt);
  68                 (void) vfprintf(stderr, fmt, ap);
  69                 va_end(ap);
  70         }
  71 
  72         (void) fprintf(stderr, "Usage: %s [-ims] [-j nthrs] [-l label | "
  73             "-L labelenv] [-o outfile] input\n"
  74             "\n"
  75             "\t-i  ignore files not built partially from C sources\n"
  76             "\t-j  use nthrs threads to perform the merge\n"
  77             "\t-k  keep around original input file on failure\n"
  78             "\t-m  allow input to have missing debug info\n"
  79             "\t-o  copy input to outfile and add CTF\n"
  80             "\t-l  set output container's label to specified value\n"
  81             "\t-L  set output container's label to value from environment\n",
  82             ctfconvert_progname);
  83 }
  84 
  85 /*
  86  * This is a bit unfortunate. Traditionally we do type uniquification across all
  87  * modules in the kernel, including ip and unix against genunix. However, when
  88  * _MACHDEP is defined, then the cpu_t ends up having an additional member
  89  * (cpu_m), thus changing the ability for us to uniquify against it. This in
  90  * turn causes a lot of type sprawl, as there's a lot of things that end up
  91  * referring to the cpu_t and it chains out from there.
  92  *
  93  * So, if we find that a cpu_t has been defined and it has a couple of useful
  94  * sentinel members and it does *not* have the cpu_m member, then we will try
  95  * and lookup or create a forward declaration to the machcpu, append it to the
  96  * end, and update the file.
  97  *
  98  * This currently is only invoked if an undocumented option -X is passed. This


 243         ctfconvert_fatal("failed to execute alternate program %s: %s",
 244             altexec, strerror(errno));
 245 }
 246 
 247 int
 248 main(int argc, char *argv[])
 249 {
 250         int c, ifd, err;
 251         boolean_t keep = B_FALSE;
 252         uint_t flags = 0;
 253         uint_t nthreads = CTFCONVERT_DEFAULT_NTHREADS;
 254         const char *outfile = NULL;
 255         const char *label = NULL;
 256         const char *infile = NULL;
 257         char *tmpfile;
 258         ctf_file_t *ofp;
 259         long argj;
 260         char *eptr;
 261         char buf[4096];
 262         boolean_t optx = B_FALSE;
 263         boolean_t ignore_non_c = B_FALSE;
 264 
 265         ctfconvert_progname = basename(argv[0]);
 266 
 267         ctfconvert_altexec(argv);
 268 
 269         while ((c = getopt(argc, argv, ":ij:kl:L:mo:X")) != -1) {
 270                 switch (c) {
 271                 case 'i':
 272                         ignore_non_c = B_TRUE;
 273                         break;






 274                 case 'j':
 275                         errno = 0;
 276                         argj = strtol(optarg, &eptr, 10);
 277                         if (errno != 0 || argj == LONG_MAX ||
 278                             argj > 1024 || *eptr != '\0') {
 279                                 ctfconvert_fatal("invalid argument for -j: "
 280                                     "%s\n", optarg);
 281                         }
 282                         nthreads = (uint_t)argj;
 283                         break;
 284                 case 'k':
 285                         keep = B_TRUE;
 286                         break;
 287                 case 'l':
 288                         label = optarg;
 289                         break;
 290                 case 'L':
 291                         label = getenv(optarg);
 292                         break;
 293                 case 'm':
 294                         flags |= CTF_ALLOW_MISSING_DEBUG;
 295                         break;
 296                 case 'o':
 297                         outfile = optarg;
 298                         break;



 299                 case 'X':
 300                         optx = B_TRUE;
 301                         break;
 302                 case ':':
 303                         ctfconvert_usage("Option -%c requires an operand\n",
 304                             optopt);
 305                         return (CTFCONVERT_USAGE);
 306                 case '?':
 307                         ctfconvert_usage("Unknown option: -%c\n", optopt);
 308                         return (CTFCONVERT_USAGE);
 309                 }
 310         }
 311 
 312         argv += optind;
 313         argc -= optind;
 314 
 315         if (argc != 1) {
 316                 ctfconvert_usage("Exactly one input file is required\n");
 317                 return (CTFCONVERT_USAGE);
 318         }
 319         infile = argv[0];
 320 
 321         if (elf_version(EV_CURRENT) == EV_NONE)
 322                 ctfconvert_fatal("failed to initialize libelf: library is "
 323                     "out of date\n");
 324 
 325         ifd = open(infile, O_RDONLY);
 326         if (ifd < 0) {
 327                 ctfconvert_fatal("failed to open input file %s: %s\n", infile,
 328                     strerror(errno));
 329         }
 330 
 331         /*
 332          * By default we remove the input file on failure unless we've been
 333          * given an output file or -k has been specified.
 334          */
 335         if (outfile != NULL && strcmp(infile, outfile) != 0)
 336                 keep = B_TRUE;
 337 
 338         ofp = ctf_fdconvert(ifd, label, nthreads, flags, &err, buf,
 339             sizeof (buf));
 340         if (ofp == NULL) {
 341                 /*
 342                  * Normally, ctfconvert requires that its input file has at
 343                  * least one C-source compilation unit, and that every C-source
 344                  * compilation unit has DWARF. This is to avoid accidentally
 345                  * leaving out useful CTF.
 346                  *
 347                  * However, for the benefit of intransigent build environments,
 348                  * the -i and -m options can be used to relax this.
 349                  */
 350                 if (err == ECTF_CONVNOCSRC && ignore_non_c) {

 351                         exit(CTFCONVERT_OK);
 352                 }
 353 
 354                 if (err == ECTF_CONVNODEBUG &&
 355                     (flags & CTF_ALLOW_MISSING_DEBUG) != 0) {
 356                         exit(CTFCONVERT_OK);
 357                 }
 358 
 359                 if (keep == B_FALSE)
 360                         (void) unlink(infile);
 361 
 362                 if (err == ECTF_CONVBKERR || err == ECTF_CONVNODEBUG) {
 363                         ctfconvert_fatal("%s", buf);
 364                 } else {
 365                         ctfconvert_fatal("CTF conversion failed: %s\n",
 366                             ctf_errmsg(err));
 367                 }
 368         }
 369 
 370         if (optx == B_TRUE)
 371                 ctfconvert_fixup_genunix(ofp);
 372 
 373         tmpfile = NULL;
 374         if (outfile == NULL || strcmp(infile, outfile) == 0) {
 375                 if (asprintf(&tmpfile, "%s.ctf", infile) == -1) {
 376                         if (keep == B_FALSE)
 377                                 (void) unlink(infile);
 378                         ctfconvert_fatal("failed to allocate memory for "
 379                             "temporary file: %s\n", strerror(errno));
 380                 }
 381                 outfile = tmpfile;
 382         }
 383         err = ctf_elfwrite(ofp, infile, outfile, CTF_ELFWRITE_F_COMPRESS);
 384         if (err == CTF_ERR) {
 385                 (void) unlink(outfile);
 386                 if (keep == B_FALSE)
 387                         (void) unlink(infile);
 388                 ctfconvert_fatal("failed to write CTF section to output file: "