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,10 +67,12 @@
#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,75 +108,10 @@
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);
@@ -1972,11 +1909,13 @@
ctx->ecc_doffset += src->sh_size;
}
/*
* Walk sections for a given ELF object, counting (or copying) those of
- * interest (CTF, symtab, strtab).
+ * 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,11 +1929,12 @@
boolean_t ctf_link = B_FALSE;
caddr_t shbase;
size_t shsize, shstrsize;
char *shstrbase;
- if ((content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) == 0) {
+ 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,10 +1968,56 @@
}
} 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,30 +2033,37 @@
continue;
}
symtab = symchk;
strtab = strchk;
- if (symtab != NULL && ctf != NULL) {
+ 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);
- v[idx].sh_name = shstrtab_ndx(shstrtab, STR_CTF);
+ 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,16 +2090,26 @@
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);
+ 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 {
- symtab_name = shstrtab_ndx(shstrtab, STR_SYMTAB);
- strtab_name = shstrtab_ndx(shstrtab, STR_STRTAB);
+ 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,11 +2165,12 @@
ASSERT(AS_WRITE_HELD(as));
if (v != NULL) {
ASSERT(nv != 0);
- shstrtab_init(&shstrtab);
+ if (!shstrtab_init(&shstrtab))
+ return (ENOMEM);
remain = nv;
} else {
ASSERT(nv == 0);
/*
@@ -2210,10 +2214,14 @@
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,21 +2234,27 @@
*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);
- return (EIO);
+ error = EIO;
+ goto done;
}
- v[idx].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB);
+ 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,10 +2267,13 @@
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,13 +2317,12 @@
/*
* Count the number of section headers we're going to need.
*/
nshdrs = 0;
- if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) {
+ 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,14 +2331,15 @@
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.
+ * 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));