summaryrefslogtreecommitdiff
path: root/sys/kern/exec_elf.c
diff options
context:
space:
mode:
authorPhilip Guenther <guenther@cvs.openbsd.org>2017-03-05 00:45:32 +0000
committerPhilip Guenther <guenther@cvs.openbsd.org>2017-03-05 00:45:32 +0000
commitf46e226ea387f6570231c4ef8bbcc71c6c54231c (patch)
tree4752d60634c18250afd0d16d34e54545214562e9 /sys/kern/exec_elf.c
parent2ea29e653090373a99e7349318c19686aef78101 (diff)
Generating a coredump requires walking the map twice; change
uvm_coredump_walkmap() to do both with a callback in between so it can hold locks/change state across the two. ok stefan@
Diffstat (limited to 'sys/kern/exec_elf.c')
-rw-r--r--sys/kern/exec_elf.c243
1 files changed, 118 insertions, 125 deletions
diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c
index 209672e185d..643a2165885 100644
--- a/sys/kern/exec_elf.c
+++ b/sys/kern/exec_elf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_elf.c,v 1.138 2017/02/11 06:07:03 guenther Exp $ */
+/* $OpenBSD: exec_elf.c,v 1.139 2017/03/05 00:45:30 guenther Exp $ */
/*
* Copyright (c) 1996 Per Fogelstrom
@@ -933,21 +933,20 @@ coredump_elf(struct proc *p, void *cookie)
}
#else /* !SMALL_KERNEL */
-
-struct countsegs_state {
- int npsections;
-};
-
-int coredump_countsegs_elf(struct proc *, void *,
- struct uvm_coredump_state *);
-
struct writesegs_state {
- Elf_Phdr *psections;
+ off_t notestart;
+ off_t secstart;
off_t secoff;
+ struct proc *p;
+ void *iocookie;
+ Elf_Phdr *psections;
+ size_t psectionslen;
+ size_t notesize;
+ int npsections;
};
-int coredump_writeseghdrs_elf(struct proc *, void *,
- struct uvm_coredump_state *);
+uvm_coredump_setup_cb coredump_setup_elf;
+uvm_coredump_walk_cb coredump_walk_elf;
int coredump_notes_elf(struct proc *, void *, size_t *);
int coredump_note_elf(struct proc *, void *, size_t *);
@@ -960,184 +959,178 @@ int coredump_writenote_elf(struct proc *, void *, Elf_Note *,
int
coredump_elf(struct proc *p, void *cookie)
{
- Elf_Ehdr ehdr;
- Elf_Phdr *psections = NULL;
- struct countsegs_state cs;
+#ifdef DIAGNOSTIC
+ off_t offset;
+#endif
struct writesegs_state ws;
- off_t notestart, secstart, offset;
- size_t notesize, psectionslen;
+ size_t notesize;
int error, i;
+ ws.p = p;
+ ws.iocookie = cookie;
+ ws.psections = NULL;
+
/*
- * We have to make a total of 3 passes across the map:
- *
- * 1. Count the number of map entries (the number of
- * PT_LOAD sections).
- *
- * 2. Write the P-section headers.
- *
- * 3. Write the P-sections.
+ * Walk the map to get all the segment offsets and lengths,
+ * write out the ELF header.
*/
-
- /* Pass 1: count the entries. */
- cs.npsections = 0;
- error = uvm_coredump_walkmap(p, NULL, coredump_countsegs_elf, &cs);
- if (error)
- goto out;
-
- /* Count the PT_NOTE section. */
- cs.npsections++;
-
- /* Get the size of the notes. */
- error = coredump_notes_elf(p, NULL, &notesize);
- if (error)
- goto out;
-
- memset(&ehdr, 0, sizeof(ehdr));
- memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
- ehdr.e_ident[EI_CLASS] = ELF_TARG_CLASS;
- ehdr.e_ident[EI_DATA] = ELF_TARG_DATA;
- ehdr.e_ident[EI_VERSION] = EV_CURRENT;
- /* XXX Should be the OSABI/ABI version of the executable. */
- ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV;
- ehdr.e_ident[EI_ABIVERSION] = 0;
- ehdr.e_type = ET_CORE;
- /* XXX This should be the e_machine of the executable. */
- ehdr.e_machine = ELF_TARG_MACH;
- ehdr.e_version = EV_CURRENT;
- ehdr.e_entry = 0;
- ehdr.e_phoff = sizeof(ehdr);
- ehdr.e_shoff = 0;
- ehdr.e_flags = 0;
- ehdr.e_ehsize = sizeof(ehdr);
- ehdr.e_phentsize = sizeof(Elf_Phdr);
- ehdr.e_phnum = cs.npsections;
- ehdr.e_shentsize = 0;
- ehdr.e_shnum = 0;
- ehdr.e_shstrndx = 0;
-
- /* Write out the ELF header. */
- error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr));
- if (error)
- goto out;
-
- psections = mallocarray(cs.npsections, sizeof(Elf_Phdr),
- M_TEMP, M_WAITOK|M_ZERO);
- psectionslen = cs.npsections * sizeof(Elf_Phdr);
-
- offset = sizeof(ehdr);
- notestart = offset + psectionslen;
- secstart = notestart + notesize;
-
- /* Pass 2: now write the P-section headers. */
- ws.secoff = secstart;
- ws.psections = psections;
- error = uvm_coredump_walkmap(p, cookie, coredump_writeseghdrs_elf, &ws);
+ error = uvm_coredump_walkmap(p, coredump_setup_elf,
+ coredump_walk_elf, &ws);
if (error)
goto out;
- /* Write out the PT_NOTE header. */
- ws.psections->p_type = PT_NOTE;
- ws.psections->p_offset = notestart;
- ws.psections->p_vaddr = 0;
- ws.psections->p_paddr = 0;
- ws.psections->p_filesz = notesize;
- ws.psections->p_memsz = 0;
- ws.psections->p_flags = PF_R;
- ws.psections->p_align = ELFROUNDSIZE;
-
- error = coredump_write(cookie, UIO_SYSSPACE, psections, psectionslen);
+ error = coredump_write(cookie, UIO_SYSSPACE, ws.psections,
+ ws.psectionslen);
if (error)
goto out;
-#ifdef DIAGNOSTIC
- offset += psectionslen;
- if (offset != notestart)
- panic("coredump: offset %lld != notestart %lld",
- (long long) offset, (long long) notestart);
-#endif
-
/* Write out the notes. */
error = coredump_notes_elf(p, cookie, &notesize);
if (error)
goto out;
#ifdef DIAGNOSTIC
- offset += notesize;
- if (offset != secstart)
+ if (notesize != ws.notesize)
+ panic("coredump: notesize changed: %zu != %zu",
+ ws.notesize, notesize);
+ offset = ws.notestart + notesize;
+ if (offset != ws.secstart)
panic("coredump: offset %lld != secstart %lld",
- (long long) offset, (long long) secstart);
+ (long long) offset, (long long) ws.secstart);
#endif
/* Pass 3: finally, write the sections themselves. */
- for (i = 0; i < cs.npsections - 1; i++) {
- if (psections[i].p_filesz == 0)
+ for (i = 0; i < ws.npsections - 1; i++) {
+ Elf_Phdr *pent = &ws.psections[i];
+ if (pent->p_filesz == 0)
continue;
#ifdef DIAGNOSTIC
- if (offset != psections[i].p_offset)
+ if (offset != pent->p_offset)
panic("coredump: offset %lld != p_offset[%d] %lld",
(long long) offset, i,
- (long long) psections[i].p_filesz);
+ (long long) pent->p_filesz);
#endif
error = coredump_write(cookie, UIO_USERSPACE,
- (void *)(vaddr_t)psections[i].p_vaddr,
- psections[i].p_filesz);
+ (void *)(vaddr_t)pent->p_vaddr, pent->p_filesz);
if (error)
goto out;
- coredump_unmap(cookie, (vaddr_t)psections[i].p_vaddr,
- (vaddr_t)psections[i].p_vaddr + psections[i].p_filesz);
+ coredump_unmap(cookie, (vaddr_t)pent->p_vaddr,
+ (vaddr_t)pent->p_vaddr + pent->p_filesz);
#ifdef DIAGNOSTIC
- offset += psections[i].p_filesz;
+ offset += ws.psections[i].p_filesz;
#endif
}
out:
- free(psections, M_TEMP, psectionslen);
+ free(ws.psections, M_TEMP, ws.psectionslen);
return (error);
}
+
+
int
-coredump_countsegs_elf(struct proc *p, void *iocookie,
- struct uvm_coredump_state *us)
+coredump_setup_elf(int segment_count, void *cookie)
{
- struct countsegs_state *cs = us->cookie;
+ Elf_Ehdr ehdr;
+ struct writesegs_state *ws = cookie;
+ Elf_Phdr *note;
+ int error;
+
+ /* Get the count of segments, plus one for the PT_NOTE */
+ ws->npsections = segment_count + 1;
+
+ /* Get the size of the notes. */
+ error = coredump_notes_elf(ws->p, NULL, &ws->notesize);
+ if (error)
+ return error;
+
+ /* Setup the ELF header */
+ memset(&ehdr, 0, sizeof(ehdr));
+ memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
+ ehdr.e_ident[EI_CLASS] = ELF_TARG_CLASS;
+ ehdr.e_ident[EI_DATA] = ELF_TARG_DATA;
+ ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ /* XXX Should be the OSABI/ABI version of the executable. */
+ ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV;
+ ehdr.e_ident[EI_ABIVERSION] = 0;
+ ehdr.e_type = ET_CORE;
+ /* XXX This should be the e_machine of the executable. */
+ ehdr.e_machine = ELF_TARG_MACH;
+ ehdr.e_version = EV_CURRENT;
+ ehdr.e_entry = 0;
+ ehdr.e_phoff = sizeof(ehdr);
+ ehdr.e_shoff = 0;
+ ehdr.e_flags = 0;
+ ehdr.e_ehsize = sizeof(ehdr);
+ ehdr.e_phentsize = sizeof(Elf_Phdr);
+ ehdr.e_phnum = ws->npsections;
+ ehdr.e_shentsize = 0;
+ ehdr.e_shnum = 0;
+ ehdr.e_shstrndx = 0;
+
+ /* Write out the ELF header. */
+ error = coredump_write(ws->iocookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr));
+ if (error)
+ return error;
+
+ /*
+ * Allocate the segment header array and setup to collect
+ * the section sizes and offsets
+ */
+ ws->psections = mallocarray(ws->npsections, sizeof(Elf_Phdr),
+ M_TEMP, M_WAITOK|M_ZERO);
+ ws->psectionslen = ws->npsections * sizeof(Elf_Phdr);
+
+ ws->notestart = sizeof(ehdr) + ws->psectionslen;
+ ws->secstart = ws->notestart + ws->notesize;
+ ws->secoff = ws->secstart;
+
+ /* Fill in the PT_NOTE segment header in the last slot */
+ note = &ws->psections[ws->npsections - 1];
+ note->p_type = PT_NOTE;
+ note->p_offset = ws->notestart;
+ note->p_vaddr = 0;
+ note->p_paddr = 0;
+ note->p_filesz = ws->notesize;
+ note->p_memsz = 0;
+ note->p_flags = PF_R;
+ note->p_align = ELFROUNDSIZE;
- cs->npsections++;
return (0);
}
int
-coredump_writeseghdrs_elf(struct proc *p, void *iocookie,
- struct uvm_coredump_state *us)
+coredump_walk_elf(vaddr_t start, vaddr_t realend, vaddr_t end, vm_prot_t prot,
+ int nsegment, void *cookie)
{
- struct writesegs_state *ws = us->cookie;
+ struct writesegs_state *ws = cookie;
Elf_Phdr phdr;
vsize_t size, realsize;
- size = us->end - us->start;
- realsize = us->realend - us->start;
+ size = end - start;
+ realsize = realend - start;
phdr.p_type = PT_LOAD;
phdr.p_offset = ws->secoff;
- phdr.p_vaddr = us->start;
+ phdr.p_vaddr = start;
phdr.p_paddr = 0;
phdr.p_filesz = realsize;
phdr.p_memsz = size;
phdr.p_flags = 0;
- if (us->prot & PROT_READ)
+ if (prot & PROT_READ)
phdr.p_flags |= PF_R;
- if (us->prot & PROT_WRITE)
+ if (prot & PROT_WRITE)
phdr.p_flags |= PF_W;
- if (us->prot & PROT_EXEC)
+ if (prot & PROT_EXEC)
phdr.p_flags |= PF_X;
phdr.p_align = PAGE_SIZE;
ws->secoff += phdr.p_filesz;
- *ws->psections++ = phdr;
+ ws->psections[nsegment] = phdr;
return (0);
}