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>

@@ -8,11 +8,11 @@
  * source.  A copy of the CDDL is also available via the Internet at
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
  */
 
 /*
  * merge CTF containers
  */

@@ -36,11 +36,10 @@
 #include <limits.h>
 
 static char *g_progname;
 static char *g_unique;
 static char *g_outfile;
-static boolean_t g_req;
 static uint_t g_nctf;
 
 #define CTFMERGE_OK     0
 #define CTFMERGE_FATAL  1
 #define CTFMERGE_USAGE  2

@@ -62,77 +61,43 @@
                 (void) unlink(g_outfile);
 
         exit(CTFMERGE_FATAL);
 }
 
-static boolean_t
-ctfmerge_expect_ctf(const char *name, Elf *elf)
+/*
+ * We failed to find CTF for this file, check if it's OK. If we're not derived
+ * from C, or we have the -m option, we let missing CTF pass.
+ */
+static void
+ctfmerge_check_for_c(const char *name, Elf *elf, uint_t flags)
 {
-        Elf_Scn *scn, *strscn;
-        Elf_Data *data, *strdata;
-        GElf_Shdr shdr;
-        ulong_t i;
+        char errmsg[1024];
 
-        if (g_req == B_FALSE)
-                return (B_FALSE);
+        if (flags & CTF_ALLOW_MISSING_DEBUG)
+                return;
 
-        scn = NULL;
-        while ((scn = elf_nextscn(elf, scn)) != NULL) {
-                if (gelf_getshdr(scn, &shdr) == NULL) {
-                        ctfmerge_fatal("failed to get section header for file "
-                            "%s: %s\n", name, elf_errmsg(elf_errno()));
-                }
-
-                if (shdr.sh_type == SHT_SYMTAB)
+        switch (ctf_has_c_source(elf, errmsg, sizeof (errmsg))) {
+        case CHR_ERROR:
+                ctfmerge_fatal("failed to open %s: %s\n", name, errmsg);
                         break;
-        }
 
-        if (scn == NULL)
-                return (B_FALSE);
+        case CHR_NO_C_SOURCE:
+                return;
 
-        if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL)
-                ctfmerge_fatal("failed to get section header for file %s: %s\n",
-                    name, elf_errmsg(elf_errno()));
-
-        if ((data = elf_getdata(scn, NULL)) == NULL)
-                ctfmerge_fatal("failed to read symbol table for %s: %s\n",
-                    name, elf_errmsg(elf_errno()));
-
-        if ((strdata = elf_getdata(strscn, NULL)) == NULL)
-                ctfmerge_fatal("failed to read string table for %s: %s\n",
-                    name, elf_errmsg(elf_errno()));
-
-        for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
-                GElf_Sym sym;
-                const char *file;
-                size_t len;
-
-                if (gelf_getsym(data, i, &sym) == NULL)
-                        ctfmerge_fatal("failed to read symbol table entry %lu "
-                            "for %s: %s\n", i, name, elf_errmsg(elf_errno()));
-
-                if (GELF_ST_TYPE(sym.st_info) != STT_FILE)
-                        continue;
-
-                file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);
-                len = strlen(file);
-                if (len < 2 || name[len - 2] != '.')
-                        continue;
-
-                if (name[len - 1] == 'c')
-                        return (B_TRUE);
+        default:
+                ctfmerge_fatal("failed to open %s: %s\n", name,
+                    ctf_errmsg(ECTF_NOCTFDATA));
+                break;
         }
-
-        return (B_FALSE);
 }
 
 /*
  * Go through and construct enough information for this Elf Object to try and do
  * a ctf_bufopen().
  */
-static void
-ctfmerge_elfopen(const char *name, Elf *elf, ctf_merge_t *cmh)
+static int
+ctfmerge_elfopen(const char *name, Elf *elf, ctf_merge_t *cmh, uint_t flags)
 {
         GElf_Ehdr ehdr;
         GElf_Shdr shdr;
         Elf_Scn *scn;
         Elf_Data *ctf_data, *str_data, *sym_data;

@@ -212,53 +177,52 @@
                         strsect.cts_data = str_data->d_buf;
                 }
         }
 
         if (ctfsect.cts_type == SHT_NULL) {
-                if (ctfmerge_expect_ctf(name, elf) == B_FALSE)
-                        return;
-                ctfmerge_fatal("failed to open %s: %s\n", name,
-                    ctf_errmsg(ECTF_NOCTFDATA));
+                ctfmerge_check_for_c(name, elf, flags);
+                return (ENOENT);
         }
 
         if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL) {
                 fp = ctf_bufopen(&ctfsect, &symsect, &strsect, &err);
         } else {
                 fp = ctf_bufopen(&ctfsect, NULL, NULL, &err);
         }
 
         if (fp == NULL) {
-                if (ctfmerge_expect_ctf(name, elf) == B_TRUE) {
                         ctfmerge_fatal("failed to open file %s: %s\n",
                             name, ctf_errmsg(err));
                 }
-        } else {
+
                 if ((err = ctf_merge_add(cmh, fp)) != 0) {
                         ctfmerge_fatal("failed to add input %s: %s\n",
                             name, ctf_errmsg(err));
                 }
+
                 g_nctf++;
-        }
+        return (0);
 }
 
 static void
 ctfmerge_read_archive(const char *name, int fd, Elf *elf,
-    ctf_merge_t *cmh)
+    ctf_merge_t *cmh, uint_t flags)
 {
-        Elf *aelf;
         Elf_Cmd cmd = ELF_C_READ;
         int cursec = 1;
-        char *nname;
+        Elf *aelf;
 
         while ((aelf = elf_begin(fd, cmd, elf)) != NULL) {
+                char *nname = NULL;
                 Elf_Arhdr *arhdr;
-                boolean_t leakelf = B_FALSE;
 
                 if ((arhdr = elf_getarhdr(aelf)) == NULL)
                         ctfmerge_fatal("failed to get archive header %d for "
                             "%s: %s\n", cursec, name, elf_errmsg(elf_errno()));
 
+                cmd = elf_next(aelf);
+
                 if (*(arhdr->ar_name) == '/')
                         goto next;
 
                 if (asprintf(&nname, "%s.%s.%d", name, arhdr->ar_name,
                     cursec) < 0)

@@ -265,32 +229,68 @@
                         ctfmerge_fatal("failed to allocate memory for archive "
                             "%d of file %s\n", cursec, name);
 
                 switch (elf_kind(aelf)) {
                 case ELF_K_AR:
-                        ctfmerge_read_archive(nname, fd, aelf, cmh);
-                        free(nname);
+                        ctfmerge_read_archive(nname, fd, aelf, cmh, flags);
                         break;
                 case ELF_K_ELF:
-                        ctfmerge_elfopen(nname, aelf, cmh);
-                        free(nname);
-                        leakelf = B_TRUE;
+                        /* ctfmerge_elfopen() takes ownership of aelf. */
+                        if (ctfmerge_elfopen(nname, aelf, cmh, flags) == 0)
+                                aelf = NULL;
                         break;
                 default:
                         ctfmerge_fatal("unknown elf kind (%d) in archive %d "
                             "for %s\n", elf_kind(aelf), cursec, name);
+                        break;
                 }
 
 next:
-                cmd = elf_next(aelf);
-                if (leakelf == B_FALSE)
                         (void) elf_end(aelf);
+                free(nname);
                 cursec++;
         }
 }
 
 static void
+ctfmerge_file_add(ctf_merge_t *cmh, const char *file, uint_t flags)
+{
+        Elf *e;
+        int fd;
+
+        if ((fd = open(file, O_RDONLY)) < 0) {
+                ctfmerge_fatal("failed to open file %s: %s\n",
+                    file, strerror(errno));
+        }
+
+        if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+                (void) close(fd);
+                ctfmerge_fatal("failed to open %s: %s\n",
+                    file, elf_errmsg(elf_errno()));
+        }
+
+        switch (elf_kind(e)) {
+        case ELF_K_AR:
+                ctfmerge_read_archive(file, fd, e, cmh, flags);
+                break;
+
+        case ELF_K_ELF:
+                /* ctfmerge_elfopen() takes ownership of e. */
+                if (ctfmerge_elfopen(file, e, cmh, flags) == 0)
+                        e = NULL;
+                break;
+
+        default:
+                ctfmerge_fatal("unknown elf kind (%d) for %s\n",
+                    elf_kind(e), file);
+        }
+
+        (void) elf_end(e);
+        (void) close(fd);
+}
+
+static void
 ctfmerge_usage(const char *fmt, ...)
 {
         if (fmt != NULL) {
                 va_list ap;
 

@@ -298,19 +298,19 @@
                 va_start(ap, fmt);
                 (void) vfprintf(stderr, fmt, ap);
                 va_end(ap);
         }
 
-        (void) fprintf(stderr, "Usage: %s [-t] [-d uniqfile] [-l label] "
+        (void) fprintf(stderr, "Usage: %s [-m] [-d uniqfile] [-l label] "
             "[-L labelenv] [-j nthrs] -o outfile file ...\n"
             "\n"
             "\t-d  uniquify merged output against uniqfile\n"
             "\t-j  use nthrs threads to perform the merge\n"
             "\t-l  set output container's label to specified value\n"
             "\t-L  set output container's label to value from environment\n"
-            "\t-o  file to add CTF data to\n"
-            "\t-t  require CTF data from all inputs built from C sources\n",
+            "\t-m  allow C-based input files to not have CTF\n"
+            "\t-o  file to add CTF data to\n",
             g_progname);
 }
 
 static void
 ctfmerge_altexec(char **argv)

@@ -339,24 +339,25 @@
 {
         int err, i, c, ofd;
         uint_t nthreads = CTFMERGE_DEFAULT_NTHREADS;
         char *tmpfile = NULL, *label = NULL;
         int wflags = CTF_ELFWRITE_F_COMPRESS;
-        ctf_file_t *ofp;
+        uint_t flags = 0;
         ctf_merge_t *cmh;
+        ctf_file_t *ofp;
         long argj;
         char *eptr;
 
         g_progname = basename(argv[0]);
 
         ctfmerge_altexec(argv);
 
         /*
          * We support a subset of the old CTF merge flags, mostly for
-         * compatability.
+         * compatibility.
          */
-        while ((c = getopt(argc, argv, ":d:fgj:l:L:o:t")) != -1) {
+        while ((c = getopt(argc, argv, ":d:fgj:l:L:mo:t")) != -1) {
                 switch (c) {
                 case 'd':
                         g_unique = optarg;
                         break;
                 case 'f':

@@ -379,15 +380,18 @@
                         label = optarg;
                         break;
                 case 'L':
                         label = getenv(optarg);
                         break;
+                case 'm':
+                        flags |= CTF_ALLOW_MISSING_DEBUG;
+                        break;
                 case 'o':
                         g_outfile = optarg;
                         break;
                 case 't':
-                        g_req = B_TRUE;
+                        /* Silently ignored for compatibility */
                         break;
                 case ':':
                         ctfmerge_usage("Option -%c requires an operand\n",
                             optopt);
                         return (CTFMERGE_USAGE);

@@ -428,64 +432,13 @@
         if ((err = ctf_merge_set_nthreads(cmh, nthreads)) != 0)
                 ctfmerge_fatal("failed to set parallelism to %u: %s\n",
                     nthreads, ctf_errmsg(err));
 
         for (i = 0; i < argc; i++) {
-                ctf_file_t *ifp;
-                int fd;
-
-                if ((fd = open(argv[i], O_RDONLY)) < 0)
-                        ctfmerge_fatal("failed to open file %s: %s\n",
-                            argv[i], strerror(errno));
-                ifp = ctf_fdopen(fd, &err);
-                if (ifp == NULL) {
-                        Elf *e;
-
-                        if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
-                                (void) close(fd);
-                                ctfmerge_fatal("failed to open %s: %s\n",
-                                    argv[i], ctf_errmsg(err));
+                ctfmerge_file_add(cmh, argv[i], flags);
                         }
 
-                        /*
-                         * It's an ELF file, check if we have an archive or if
-                         * we're expecting CTF here.
-                         */
-                        switch (elf_kind(e)) {
-                        case ELF_K_AR:
-                                break;
-                        case ELF_K_ELF:
-                                if (ctfmerge_expect_ctf(argv[i], e) == B_TRUE) {
-                                        (void) elf_end(e);
-                                        (void) close(fd);
-                                        ctfmerge_fatal("failed to "
-                                            "open %s: file was built from C "
-                                            "sources, but missing CTF\n",
-                                            argv[i]);
-                                }
-                                (void) elf_end(e);
-                                (void) close(fd);
-                                continue;
-                        default:
-                                (void) elf_end(e);
-                                (void) close(fd);
-                                ctfmerge_fatal("failed to open %s: "
-                                    "unsupported ELF file type", argv[i]);
-                        }
-
-                        ctfmerge_read_archive(argv[i], fd, e, cmh);
-                        (void) elf_end(e);
-                        (void) close(fd);
-                        continue;
-                }
-                (void) close(fd);
-                if ((err = ctf_merge_add(cmh, ifp)) != 0)
-                        ctfmerge_fatal("failed to add input %s: %s\n",
-                            argv[i], ctf_errmsg(err));
-                g_nctf++;
-        }
-
         if (g_nctf == 0) {
                 ctf_merge_fini(cmh);
                 return (0);
         }