Print this page
13925 core files should include DWARF (fix mismerge)
13925 core files should include DWARF
Reviewed by: Rich Lowe <richlowe@richlowe.net>
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Adam Leventhal <adam.leventhal@gmail.com>
Approved by: Dan McDonald <danmcd@joyent.com>
        
*** 67,76 ****
--- 67,78 ----
  #include "elf_impl.h"
  #include <sys/sdt.h>
  #include <sys/siginfo.h>
  #include <sys/random.h>
  
+ #include <core_shstrtab.h>
+ 
  #if defined(__x86)
  #include <sys/comm_page_util.h>
  #include <sys/fp.h>
  #endif /* defined(__x86) */
  
*** 106,180 ****
  uint_t elf_nphdr_max = 1000;
  uint_t elf_nshdr_max = 10000;
  size_t elf_shstrtab_max = 100 * 1024;
  #endif
  
- 
- 
- typedef enum {
-         STR_CTF,
-         STR_SYMTAB,
-         STR_DYNSYM,
-         STR_STRTAB,
-         STR_DYNSTR,
-         STR_SHSTRTAB,
-         STR_NUM
- } shstrtype_t;
- 
- static const char *shstrtab_data[] = {
-         ".SUNW_ctf",
-         ".symtab",
-         ".dynsym",
-         ".strtab",
-         ".dynstr",
-         ".shstrtab"
- };
- 
- typedef struct shstrtab {
-         uint_t  sst_ndx[STR_NUM];
-         uint_t  sst_cur;
- } shstrtab_t;
- 
- static void
- shstrtab_init(shstrtab_t *s)
- {
-         bzero(&s->sst_ndx, sizeof (s->sst_ndx));
-         s->sst_cur = 1;
- }
- 
- static uint_t
- shstrtab_ndx(shstrtab_t *s, shstrtype_t type)
- {
-         uint_t ret;
- 
-         if ((ret = s->sst_ndx[type]) != 0)
-                 return (ret);
- 
-         ret = s->sst_ndx[type] = s->sst_cur;
-         s->sst_cur += strlen(shstrtab_data[type]) + 1;
- 
-         return (ret);
- }
- 
- static size_t
- shstrtab_size(const shstrtab_t *s)
- {
-         return (s->sst_cur);
- }
- 
- static void
- shstrtab_dump(const shstrtab_t *s, char *buf)
- {
-         uint_t i, ndx;
- 
-         *buf = '\0';
-         for (i = 0; i < STR_NUM; i++) {
-                 if ((ndx = s->sst_ndx[i]) != 0)
-                         (void) strcpy(buf + ndx, shstrtab_data[i]);
-         }
- }
- 
  static int
  dtrace_safe_phdr(Phdr *phdrp, struct uarg *args, uintptr_t base)
  {
          ASSERT(phdrp->p_type == PT_SUNWDTRACE);
  
--- 108,117 ----
*** 1972,1982 ****
          ctx->ecc_doffset += src->sh_size;
  }
  
  /*
   * Walk sections for a given ELF object, counting (or copying) those of
!  * interest (CTF, symtab, strtab).
   */
  static uint_t
  elf_process_obj_scns(elf_core_ctx_t *ctx, vnode_t *mvp, caddr_t saddr,
      Shdr *v, uint_t idx, uint_t remain, shstrtab_t *shstrtab)
  {
--- 1909,1921 ----
          ctx->ecc_doffset += src->sh_size;
  }
  
  /*
   * Walk sections for a given ELF object, counting (or copying) those of
!  * interest (CTF, symtab, strtab, DWARF debug).
!  *
!  * Returns UINT_MAX upon low-memory.
   */
  static uint_t
  elf_process_obj_scns(elf_core_ctx_t *ctx, vnode_t *mvp, caddr_t saddr,
      Shdr *v, uint_t idx, uint_t remain, shstrtab_t *shstrtab)
  {
*** 1990,2000 ****
          boolean_t ctf_link = B_FALSE;
          caddr_t shbase;
          size_t shsize, shstrsize;
          char *shstrbase;
  
!         if ((content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) == 0) {
                  return (0);
          }
  
          if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx, &nphdrs) != 0 ||
              getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx, &shbase, &shsize,
--- 1929,1940 ----
          boolean_t ctf_link = B_FALSE;
          caddr_t shbase;
          size_t shsize, shstrsize;
          char *shstrbase;
  
!         if ((content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB | CC_CONTENT_DEBUG))
!             == 0) {
                  return (0);
          }
  
          if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx, &nphdrs) != 0 ||
              getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx, &shbase, &shsize,
*** 2028,2037 ****
--- 1968,2023 ----
                          }
                  } else if (symtab == NULL &&
                      (content & CC_CONTENT_SYMTAB) != 0 &&
                      strcmp(name, shstrtab_data[STR_SYMTAB]) == 0) {
                          symchk = shdr;
+                 } else if ((content & CC_CONTENT_DEBUG) != 0 &&
+                     strncmp(name, ".debug_", strlen(".debug_")) == 0) {
+                         /*
+                          * The design of the above check is intentional.  In
+                          * particular, we want to capture any sections that
+                          * begin with '.debug_' for a few reasons:
+                          *
+                          * 1) Various revisions to the DWARF spec end up
+                          * changing the set of section headers that
+                          * exist. This ensures that we don't need to change
+                          * the kernel to get a new version.
+                          *
+                          * 2) Other software uses .debug_ sections for things
+                          * which aren't DWARF. This allows them to be captured
+                          * as well.
+                          *
+                          * Because of this, we emit straight here, unlike the
+                          * other two sections where we wait until we're done
+                          * scanning.
+                          */
+ 
+                         /* We're only counting, don't emit! */
+                         if (v == NULL) {
+                                 count++;
+                                 continue;
+                         }
+ 
+                         elf_ctx_resize_scratch(ctx, shdr->sh_size);
+                         if (!shstrtab_ndx(shstrtab, name, &v[idx].sh_name)) {
+                                 count = UINT_MAX;
+                                 goto done;
+                         }
+                         v[idx].sh_addr = (Addr)(uintptr_t)saddr;
+                         v[idx].sh_type = shdr->sh_type;
+                         v[idx].sh_addralign = shdr->sh_addralign;
+                         *doffp = roundup(*doffp, v[idx].sh_addralign);
+                         v[idx].sh_offset = *doffp;
+                         v[idx].sh_size = shdr->sh_size;
+                         v[idx].sh_link = 0;
+                         v[idx].sh_entsize = shdr->sh_entsize;
+                         v[idx].sh_info = shdr->sh_info;
+ 
+                         elf_copy_scn(ctx, shdr, mvp, &v[idx]);
+                         count++;
+                         idx++;
+                         continue;
                  } else {
                          continue;
                  }
  
                  ASSERT(symchk != NULL);
*** 2047,2076 ****
                          continue;
                  }
                  symtab = symchk;
                  strtab = strchk;
  
!                 if (symtab != NULL && ctf != NULL) {
                          /* No other shdrs are of interest at this point */
                          break;
                  }
          }
  
          if (ctf != NULL)
                  count += 1;
          if (symtab != NULL)
                  count += 2;
          if (v == NULL || count == 0 || count > remain) {
                  count = MIN(count, remain);
                  goto done;
          }
  
          /* output CTF section */
          if (ctf != NULL) {
                  elf_ctx_resize_scratch(ctx, ctf->sh_size);
  
!                 v[idx].sh_name = shstrtab_ndx(shstrtab, STR_CTF);
                  v[idx].sh_addr = (Addr)(uintptr_t)saddr;
                  v[idx].sh_type = SHT_PROGBITS;
                  v[idx].sh_addralign = 4;
                  *doffp = roundup(*doffp, v[idx].sh_addralign);
                  v[idx].sh_offset = *doffp;
--- 2033,2069 ----
                          continue;
                  }
                  symtab = symchk;
                  strtab = strchk;
  
!                 if (symtab != NULL && ctf != NULL &&
!                     (content & CC_CONTENT_DEBUG) == 0) {
                          /* No other shdrs are of interest at this point */
                          break;
                  }
          }
  
          if (ctf != NULL)
                  count += 1;
          if (symtab != NULL)
                  count += 2;
+ 
          if (v == NULL || count == 0 || count > remain) {
                  count = MIN(count, remain);
                  goto done;
          }
  
          /* output CTF section */
          if (ctf != NULL) {
                  elf_ctx_resize_scratch(ctx, ctf->sh_size);
  
!                 if (!shstrtab_ndx(shstrtab, shstrtab_data[STR_CTF],
!                     &v[idx].sh_name)) {
!                         count = UINT_MAX;
!                         goto done;
!                 }
! 
                  v[idx].sh_addr = (Addr)(uintptr_t)saddr;
                  v[idx].sh_type = SHT_PROGBITS;
                  v[idx].sh_addralign = 4;
                  *doffp = roundup(*doffp, v[idx].sh_addralign);
                  v[idx].sh_offset = *doffp;
*** 2097,2112 ****
  
                  elf_ctx_resize_scratch(ctx,
                      MAX(symtab->sh_size, strtab->sh_size));
  
                  if (symtab->sh_type == SHT_DYNSYM) {
!                         symtab_name = shstrtab_ndx(shstrtab, STR_DYNSYM);
!                         strtab_name = shstrtab_ndx(shstrtab, STR_DYNSTR);
                  } else {
!                         symtab_name = shstrtab_ndx(shstrtab, STR_SYMTAB);
!                         strtab_name = shstrtab_ndx(shstrtab, STR_STRTAB);
                  }
  
                  v[idx].sh_name = symtab_name;
                  v[idx].sh_type = symtab->sh_type;
                  v[idx].sh_addr = symtab->sh_addr;
                  if (ehdr.e_type == ET_DYN || v[idx].sh_addr == 0)
--- 2090,2115 ----
  
                  elf_ctx_resize_scratch(ctx,
                      MAX(symtab->sh_size, strtab->sh_size));
  
                  if (symtab->sh_type == SHT_DYNSYM) {
!                         if (!shstrtab_ndx(shstrtab, shstrtab_data[STR_DYNSYM],
!                             &symtab_name) ||
!                             !shstrtab_ndx(shstrtab, shstrtab_data[STR_DYNSTR],
!                             &strtab_name)) {
!                                 count = UINT_MAX;
!                                 goto done;
!                         }
                  } else {
!                         if (!shstrtab_ndx(shstrtab, shstrtab_data[STR_SYMTAB],
!                             &symtab_name) ||
!                             !shstrtab_ndx(shstrtab, shstrtab_data[STR_STRTAB],
!                             &strtab_name)) {
!                                 count = UINT_MAX;
!                                 goto done;
                          }
+                 }
  
                  v[idx].sh_name = symtab_name;
                  v[idx].sh_type = symtab->sh_type;
                  v[idx].sh_addr = symtab->sh_addr;
                  if (ehdr.e_type == ET_DYN || v[idx].sh_addr == 0)
*** 2162,2172 ****
          ASSERT(AS_WRITE_HELD(as));
  
          if (v != NULL) {
                  ASSERT(nv != 0);
  
!                 shstrtab_init(&shstrtab);
                  remain = nv;
          } else {
                  ASSERT(nv == 0);
  
                  /*
--- 2165,2176 ----
          ASSERT(AS_WRITE_HELD(as));
  
          if (v != NULL) {
                  ASSERT(nv != 0);
  
!                 if (!shstrtab_init(&shstrtab))
!                         return (ENOMEM);
                  remain = nv;
          } else {
                  ASSERT(nv == 0);
  
                  /*
*** 2210,2219 ****
--- 2214,2227 ----
                  if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC)
                          continue;
  
                  count = elf_process_obj_scns(ctx, mvp, saddr, v, idx, remain,
                      &shstrtab);
+                 if (count == UINT_MAX) {
+                         error = ENOMEM;
+                         goto done;
+                 }
  
                  ASSERT(count <= remain);
                  ASSERT(v == NULL || (idx + count) < nv);
  
                  remain -= count;
*** 2226,2246 ****
                          *nshdrsp = 0;
                  } else {
                          /* Include room for the shrstrtab at the end */
                          *nshdrsp = idx + 1;
                  }
                  return (0);
          }
  
          if (idx != nv - 1) {
                  cmn_err(CE_WARN, "elfcore: core dump failed for "
                      "process %d; address space is changing",
                      ctx->ecc_p->p_pid);
!                 return (EIO);
          }
  
!         v[idx].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB);
          v[idx].sh_size = shstrtab_size(&shstrtab);
          v[idx].sh_addralign = 1;
          v[idx].sh_offset = ctx->ecc_doffset;
          v[idx].sh_flags = SHF_STRINGS;
          v[idx].sh_type = SHT_STRTAB;
--- 2234,2260 ----
                          *nshdrsp = 0;
                  } else {
                          /* Include room for the shrstrtab at the end */
                          *nshdrsp = idx + 1;
                  }
+                 /* No need to free up shstrtab so we can just return. */
                  return (0);
          }
  
          if (idx != nv - 1) {
                  cmn_err(CE_WARN, "elfcore: core dump failed for "
                      "process %d; address space is changing",
                      ctx->ecc_p->p_pid);
!                 error = EIO;
!                 goto done;
          }
  
!         if (!shstrtab_ndx(&shstrtab, shstrtab_data[STR_SHSTRTAB],
!             &v[idx].sh_name)) {
!                 error = ENOMEM;
!                 goto done;
!         }
          v[idx].sh_size = shstrtab_size(&shstrtab);
          v[idx].sh_addralign = 1;
          v[idx].sh_offset = ctx->ecc_doffset;
          v[idx].sh_flags = SHF_STRINGS;
          v[idx].sh_type = SHT_STRTAB;
*** 2253,2262 ****
--- 2267,2279 ----
              ctx->ecc_buf, v[idx].sh_size, ctx->ecc_rlimit, ctx->ecc_credp);
          if (error == 0) {
                  ctx->ecc_doffset += v[idx].sh_size;
          }
  
+ done:
+         if (v != NULL)
+                 shstrtab_fini(&shstrtab);
          return (error);
  }
  
  int
  elfcore(vnode_t *vp, proc_t *p, cred_t *credp, rlim64_t rlimit, int sig,
*** 2300,2312 ****
  
          /*
           * Count the number of section headers we're going to need.
           */
          nshdrs = 0;
!         if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) {
                  VERIFY0(elf_process_scns(&ctx, NULL, 0, &nshdrs));
-         }
          AS_LOCK_EXIT(as);
  
          /*
           * The core file contents may require zero section headers, but if
           * we overflow the 16 bits allotted to the program header count in
--- 2317,2328 ----
  
          /*
           * Count the number of section headers we're going to need.
           */
          nshdrs = 0;
!         if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB | CC_CONTENT_DEBUG))
                  VERIFY0(elf_process_scns(&ctx, NULL, 0, &nshdrs));
          AS_LOCK_EXIT(as);
  
          /*
           * The core file contents may require zero section headers, but if
           * we overflow the 16 bits allotted to the program header count in
*** 2315,2328 ****
          if (nshdrs == 0 && nphdrs >= PN_XNUM) {
                  nshdrs = 1;
          }
  
          /*
!          * Allocate a buffer which is sized adequately to hold the ehdr, phdrs
!          * or shdrs needed to produce the core file.  It is used for the three
!          * tasks sequentially, not simultaneously, so it does not need space
!          * for all three data at once, only the largest one.
           */
          VERIFY(nphdrs >= 2);
          phdrsz = nphdrs * sizeof (Phdr);
          shdrsz = nshdrs * sizeof (Shdr);
          bigsize = MAX(sizeof (Ehdr), MAX(phdrsz, shdrsz));
--- 2331,2345 ----
          if (nshdrs == 0 && nphdrs >= PN_XNUM) {
                  nshdrs = 1;
          }
  
          /*
!          * Allocate a buffer which is sized adequately to hold the ehdr,
!          * phdrs, DWARF debug, or shdrs needed to produce the core file.  It
!          * is used for the four tasks sequentially, not simultaneously, so it
!          * does not need space for all four data at once, only the largest
!          * one.
           */
          VERIFY(nphdrs >= 2);
          phdrsz = nphdrs * sizeof (Phdr);
          shdrsz = nshdrs * sizeof (Shdr);
          bigsize = MAX(sizeof (Ehdr), MAX(phdrsz, shdrsz));