Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 186317
b: refs/heads/master
c: 8d9032b
h: refs/heads/master
i:
  186315: f2de324
v: v3
  • Loading branch information
Daisuke HATAYAMA authored and Linus Torvalds committed Mar 6, 2010
1 parent 703440c commit 051bd88
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 93eb211e6c9ff6054fcf9c5b9e344d8d9ad29175
refs/heads/master: 8d9032bbe4671dc481261ccd4e161cd96e54b118
16 changes: 16 additions & 0 deletions trunk/arch/ia64/kernel/elfcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,19 @@ int elf_core_write_extra_data(struct file *file, size_t *size,
}
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;
}
16 changes: 16 additions & 0 deletions trunk/arch/um/sys-i386/elfcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,19 @@ int elf_core_write_extra_data(struct file *file, size_t *size,
}
return 1;
}

size_t elf_core_extra_data_size(void)
{
if ( vsyscall_ehdr ) {
const struct elfhdr *const ehdrp =
(struct elfhdr *)vsyscall_ehdr;
const struct elf_phdr *const phdrp =
(const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff);
int i;

for (i = 0; i < ehdrp->e_phnum; ++i)
if (phdrp[i].p_type == PT_LOAD)
return (size_t) phdrp[i].p_filesz;
}
return 0;
}
66 changes: 63 additions & 3 deletions trunk/fs/binfmt_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1838,6 +1838,34 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
return gate_vma;
}

static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
elf_addr_t e_shoff, int segs)
{
elf->e_shoff = e_shoff;
elf->e_shentsize = sizeof(*shdr4extnum);
elf->e_shnum = 1;
elf->e_shstrndx = SHN_UNDEF;

memset(shdr4extnum, 0, sizeof(*shdr4extnum));

shdr4extnum->sh_type = SHT_NULL;
shdr4extnum->sh_size = elf->e_shnum;
shdr4extnum->sh_link = elf->e_shstrndx;
shdr4extnum->sh_info = segs;
}

static size_t elf_core_vma_data_size(struct vm_area_struct *gate_vma,
unsigned long mm_flags)
{
struct vm_area_struct *vma;
size_t size = 0;

for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma))
size += vma_dump_size(vma, mm_flags);
return size;
}

/*
* Actual dumper
*
Expand All @@ -1857,6 +1885,9 @@ static int elf_core_dump(struct coredump_params *cprm)
unsigned long mm_flags;
struct elf_note_info info;
struct elf_phdr *phdr4note = NULL;
struct elf_shdr *shdr4extnum = NULL;
Elf_Half e_phnum;
elf_addr_t e_shoff;

/*
* We no longer stop all VM operations.
Expand Down Expand Up @@ -1885,12 +1916,19 @@ static int elf_core_dump(struct coredump_params *cprm)
if (gate_vma != NULL)
segs++;

/* for notes section */
segs++;

/* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
* this, kernel supports extended numbering. Have a look at
* include/linux/elf.h for further information. */
e_phnum = segs > PN_XNUM ? PN_XNUM : segs;

/*
* Collect all the non-memory information about the process for the
* notes. This also sets up the file header.
*/
if (!fill_note_info(elf, segs + 1, /* including notes section */
&info, cprm->signr, cprm->regs))
if (!fill_note_info(elf, e_phnum, &info, cprm->signr, cprm->regs))
goto cleanup;

has_dumped = 1;
Expand All @@ -1900,7 +1938,7 @@ static int elf_core_dump(struct coredump_params *cprm)
set_fs(KERNEL_DS);

offset += sizeof(*elf); /* Elf header */
offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */
offset += segs * sizeof(struct elf_phdr); /* Program headers */
foffset = offset;

/* Write notes phdr entry */
Expand All @@ -1926,6 +1964,19 @@ static int elf_core_dump(struct coredump_params *cprm)
*/
mm_flags = current->mm->flags;

offset += elf_core_vma_data_size(gate_vma, mm_flags);
offset += elf_core_extra_data_size();
e_shoff = offset;

if (e_phnum == PN_XNUM) {
shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
if (!shdr4extnum)
goto end_coredump;
fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
}

offset = dataoff;

size += sizeof(*elf);
if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
goto end_coredump;
Expand Down Expand Up @@ -2003,11 +2054,20 @@ static int elf_core_dump(struct coredump_params *cprm)
if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
goto end_coredump;

if (e_phnum == PN_XNUM) {
size += sizeof(*shdr4extnum);
if (size > cprm->limit
|| !dump_write(cprm->file, shdr4extnum,
sizeof(*shdr4extnum)))
goto end_coredump;
}

end_coredump:
set_fs(fs);

cleanup:
free_note_info(&info);
kfree(shdr4extnum);
kfree(phdr4note);
kfree(elf);
out:
Expand Down
63 changes: 61 additions & 2 deletions trunk/fs/binfmt_elf_fdpic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1505,6 +1505,22 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
return sz;
}

static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
elf_addr_t e_shoff, int segs)
{
elf->e_shoff = e_shoff;
elf->e_shentsize = sizeof(*shdr4extnum);
elf->e_shnum = 1;
elf->e_shstrndx = SHN_UNDEF;

memset(shdr4extnum, 0, sizeof(*shdr4extnum));

shdr4extnum->sh_type = SHT_NULL;
shdr4extnum->sh_size = elf->e_shnum;
shdr4extnum->sh_link = elf->e_shstrndx;
shdr4extnum->sh_info = segs;
}

/*
* dump the segments for an MMU process
*/
Expand Down Expand Up @@ -1569,6 +1585,17 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
}
#endif

static size_t elf_core_vma_data_size(unsigned long mm_flags)
{
struct vm_area_struct *vma;
size_t size = 0;

for (vma = current->mm->mmap; vma; vma->vm_next)
if (maydump(vma, mm_flags))
size += vma->vm_end - vma->vm_start;
return size;
}

/*
* Actual dumper
*
Expand Down Expand Up @@ -1601,6 +1628,9 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
elf_addr_t *auxv;
unsigned long mm_flags;
struct elf_phdr *phdr4note = NULL;
struct elf_shdr *shdr4extnum = NULL;
Elf_Half e_phnum;
elf_addr_t e_shoff;

/*
* We no longer stop all VM operations.
Expand Down Expand Up @@ -1667,8 +1697,16 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
segs = current->mm->map_count;
segs += elf_core_extra_phdrs();

/* for notes section */
segs++;

/* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
* this, kernel supports extended numbering. Have a look at
* include/linux/elf.h for further information. */
e_phnum = segs > PN_XNUM ? PN_XNUM : segs;

/* Set up header */
fill_elf_fdpic_header(elf, segs + 1); /* including notes section */
fill_elf_fdpic_header(elf, e_phnum);

has_dumped = 1;
current->flags |= PF_DUMPCORE;
Expand Down Expand Up @@ -1708,7 +1746,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
set_fs(KERNEL_DS);

offset += sizeof(*elf); /* Elf header */
offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
offset += segs * sizeof(struct elf_phdr); /* Program headers */
foffset = offset;

/* Write notes phdr entry */
Expand Down Expand Up @@ -1738,6 +1776,19 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
*/
mm_flags = current->mm->flags;

offset += elf_core_vma_data_size(mm_flags);
offset += elf_core_extra_data_size();
e_shoff = offset;

if (e_phnum == PN_XNUM) {
shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
if (!shdr4extnum)
goto end_coredump;
fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
}

offset = dataoff;

size += sizeof(*elf);
if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
goto end_coredump;
Expand Down Expand Up @@ -1802,6 +1853,14 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
goto end_coredump;

if (e_phnum == PN_XNUM) {
size += sizeof(*shdr4extnum);
if (size > cprm->limit
|| !dump_write(cprm->file, shdr4extnum,
sizeof(*shdr4extnum)))
goto end_coredump;
}

if (cprm->file->f_pos != offset) {
/* Sanity check */
printk(KERN_WARNING
Expand Down
26 changes: 25 additions & 1 deletion trunk/include/linux/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,28 @@ typedef __s64 Elf64_Sxword;

#define PT_GNU_STACK (PT_LOOS + 0x474e551)

/*
* Extended Numbering
*
* If the real number of program header table entries is larger than
* or equal to PN_XNUM(0xffff), it is set to sh_info field of the
* section header at index 0, and PN_XNUM is set to e_phnum
* field. Otherwise, the section header at index 0 is zero
* initialized, if it exists.
*
* Specifications are available in:
*
* - Sun microsystems: Linker and Libraries.
* Part No: 817-1984-17, September 2008.
* URL: http://docs.sun.com/app/docs/doc/817-1984
*
* - System V ABI AMD64 Architecture Processor Supplement
* Draft Version 0.99.,
* May 11, 2009.
* URL: http://www.x86-64.org/
*/
#define PN_XNUM 0xffff

/* These constants define the different elf file types */
#define ET_NONE 0
#define ET_REL 1
Expand Down Expand Up @@ -286,7 +308,7 @@ typedef struct elf64_phdr {
#define SHN_COMMON 0xfff2
#define SHN_HIRESERVE 0xffff

typedef struct {
typedef struct elf32_shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Expand Down Expand Up @@ -394,6 +416,7 @@ typedef struct elf64_note {
extern Elf32_Dyn _DYNAMIC [];
#define elfhdr elf32_hdr
#define elf_phdr elf32_phdr
#define elf_shdr elf32_shdr
#define elf_note elf32_note
#define elf_addr_t Elf32_Off
#define Elf_Half Elf32_Half
Expand All @@ -403,6 +426,7 @@ extern Elf32_Dyn _DYNAMIC [];
extern Elf64_Dyn _DYNAMIC [];
#define elfhdr elf64_hdr
#define elf_phdr elf64_phdr
#define elf_shdr elf64_shdr
#define elf_note elf64_note
#define elf_addr_t Elf64_Off
#define Elf_Half Elf64_Half
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/elfcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,6 @@ elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size,
unsigned long limit);
extern int
elf_core_write_extra_data(struct file *file, size_t *size, unsigned long limit);
extern size_t elf_core_extra_data_size(void);

#endif /* _LINUX_ELFCORE_H */
5 changes: 5 additions & 0 deletions trunk/kernel/elfcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ int __weak elf_core_write_extra_data(struct file *file, size_t *size,
{
return 1;
}

size_t __weak elf_core_extra_data_size(void)
{
return 0;
}

0 comments on commit 051bd88

Please sign in to comment.