}
        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;
+}
 
        }
        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;
+}
 
        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
  *
        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.
        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;
        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 */
         */
        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;
        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:
 
        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
  */
 }
 #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
  *
        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.
        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;
        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 */
         */
        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;
        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
 
 
 #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
 #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;
 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
 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
 
                           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 */
 
 {
        return 1;
 }
+
+size_t __weak elf_core_extra_data_size(void)
+{
+       return 0;
+}