8d9032bbe4
The current ELF dumper implementation can produce broken corefiles if program headers exceed 65535. This number is determined by the number of vmas which the process have. In particular, some extreme programs may use more than 65535 vmas. (If you google max_map_count, you can find some users facing this problem.) This kind of program never be able to generate correct coredumps. This patch implements ``extended numbering'' that uses sh_info field of the first section header instead of e_phnum field in order to represent upto 4294967295 vmas. This is supported by AMD64-ABI(http://www.x86-64.org/documentation.html) and Solaris(http://docs.sun.com/app/docs/doc/817-1984/). Of course, we are preparing patches for gdb and binutils. Signed-off-by: Daisuke HATAYAMA <d.hatayama@jp.fujitsu.com> Cc: "Luck, Tony" <tony.luck@intel.com> Cc: Jeff Dike <jdike@addtoit.com> Cc: David Howells <dhowells@redhat.com> Cc: Greg Ungerer <gerg@snapgear.com> Cc: Roland McGrath <roland@redhat.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Andi Kleen <andi@firstfloor.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: <linux-arch@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
80 lines
1.8 KiB
C
80 lines
1.8 KiB
C
#include <linux/elf.h>
|
|
#include <linux/coredump.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/mm.h>
|
|
|
|
#include <asm/elf.h>
|
|
|
|
|
|
Elf64_Half elf_core_extra_phdrs(void)
|
|
{
|
|
return GATE_EHDR->e_phnum;
|
|
}
|
|
|
|
int elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size,
|
|
unsigned long limit)
|
|
{
|
|
const struct elf_phdr *const gate_phdrs =
|
|
(const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
|
|
int i;
|
|
Elf64_Off ofs = 0;
|
|
|
|
for (i = 0; i < GATE_EHDR->e_phnum; ++i) {
|
|
struct elf_phdr phdr = gate_phdrs[i];
|
|
|
|
if (phdr.p_type == PT_LOAD) {
|
|
phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz);
|
|
phdr.p_filesz = phdr.p_memsz;
|
|
if (ofs == 0) {
|
|
ofs = phdr.p_offset = offset;
|
|
offset += phdr.p_filesz;
|
|
} else {
|
|
phdr.p_offset = ofs;
|
|
}
|
|
} else {
|
|
phdr.p_offset += ofs;
|
|
}
|
|
phdr.p_paddr = 0; /* match other core phdrs */
|
|
*size += sizeof(phdr);
|
|
if (*size > limit || !dump_write(file, &phdr, sizeof(phdr)))
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int elf_core_write_extra_data(struct file *file, size_t *size,
|
|
unsigned long limit)
|
|
{
|
|
const struct elf_phdr *const gate_phdrs =
|
|
(const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
|
|
int i;
|
|
|
|
for (i = 0; i < GATE_EHDR->e_phnum; ++i) {
|
|
if (gate_phdrs[i].p_type == PT_LOAD) {
|
|
void *addr = (void *)gate_phdrs[i].p_vaddr;
|
|
size_t memsz = PAGE_ALIGN(gate_phdrs[i].p_memsz);
|
|
|
|
*size += memsz;
|
|
if (*size > limit || !dump_write(file, addr, memsz))
|
|
return 0;
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
size_t elf_core_extra_data_size(void)
|
|
{
|
|
const struct elf_phdr *const gate_phdrs =
|
|
(const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
|
|
int i;
|
|
size_t size = 0;
|
|
|
|
for (i = 0; i < GATE_EHDR->e_phnum; ++i) {
|
|
if (gate_phdrs[i].p_type == PT_LOAD) {
|
|
size += PAGE_ALIGN(gate_phdrs[i].p_memsz);
|
|
break;
|
|
}
|
|
}
|
|
return size;
|
|
}
|