diff options
-rw-r--r-- | elf_info.c | 40 | ||||
-rw-r--r-- | elf_info.h | 1 | ||||
-rw-r--r-- | makedumpfile.c | 73 |
3 files changed, 91 insertions, 23 deletions
@@ -123,8 +123,11 @@ check_elf_format(int fd, char *filename, int *phnum, unsigned int *num_load) (*num_load) = 0; if ((ehdr64.e_ident[EI_CLASS] == ELFCLASS64) && (ehdr32.e_ident[EI_CLASS] != ELFCLASS32)) { - (*phnum) = ehdr64.e_phnum; - for (i = 0; i < ehdr64.e_phnum; i++) { + if (!get_elf64_phnum(fd, filename, &ehdr64, phnum)) { + ERRMSG("Can't get phnum.\n"); + return FALSE; + } + for (i = 0; i < (*phnum); i++) { if (!get_elf64_phdr(fd, filename, i, &load64)) { ERRMSG("Can't find Phdr %d.\n", i); return FALSE; @@ -1036,6 +1039,34 @@ is_xen_memory(void) } int +get_elf64_phnum(int fd, char *filename, Elf64_Ehdr *ehdr, int *phnum) +{ + Elf64_Shdr shdr; + + /* + * Extended Numbering support + * See include/uapi/linux/elf.h and elf(5) for more information. + */ + if (ehdr->e_phnum == PN_XNUM) { + if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0) { + ERRMSG("Can't seek %s at 0x%lx. %s\n", filename, + ehdr->e_shoff, strerror(errno)); + return FALSE; + } + if (read(fd, &shdr, ehdr->e_shentsize) != ehdr->e_shentsize) { + ERRMSG("Can't read %s at 0x%lx. %s\n", filename, + ehdr->e_shoff, strerror(errno)); + return FALSE; + } + + *phnum = shdr.sh_info; + } else + *phnum = ehdr->e_phnum; + + return TRUE; +} + +int get_phnum_memory(void) { int phnum; @@ -1047,7 +1078,10 @@ get_phnum_memory(void) ERRMSG("Can't get ehdr64.\n"); return FALSE; } - phnum = ehdr64.e_phnum; + if (!get_elf64_phnum(fd_memory, name_memory, &ehdr64, &phnum)) { + ERRMSG("Can't get phnum.\n"); + return FALSE; + } } else { /* ELF32 */ if (!get_elf32_ehdr(fd_memory, name_memory, &ehdr32)) { ERRMSG("Can't get ehdr32.\n"); @@ -54,6 +54,7 @@ int get_kcore_dump_loads(void); int is_elf64_memory(void); int is_xen_memory(void); +int get_elf64_phnum(int fd, char *filename, Elf64_Ehdr *ehdr, int *phnum); int get_phnum_memory(void); int get_phdr_memory(int index, Elf64_Phdr *phdr); off_t get_offset_pt_load_memory(void); diff --git a/makedumpfile.c b/makedumpfile.c index ac19ed8..b9e9dfb 100644 --- a/makedumpfile.c +++ b/makedumpfile.c @@ -6871,10 +6871,17 @@ write_elf_header(struct cache_data *cd_header) ERRMSG("Can't get ehdr64.\n"); goto out; } + + /* For PT_NOTE */ + num_loads_dumpfile++; + /* - * PT_NOTE(1) + PT_LOAD(1+) + * Extended Numbering support + * See include/uapi/linux/elf.h and elf(5) for more information. */ - ehdr64.e_phnum = 1 + num_loads_dumpfile; + ehdr64.e_phnum = (num_loads_dumpfile >= PN_XNUM) ? + PN_XNUM : num_loads_dumpfile; + } else { /* ELF32 */ if (!get_elf32_ehdr(info->fd_memory, info->name_memory, &ehdr32)) { @@ -6888,20 +6895,6 @@ write_elf_header(struct cache_data *cd_header) } /* - * Write an ELF header. - */ - if (is_elf64_memory()) { /* ELF64 */ - if (!write_buffer(info->fd_dumpfile, 0, &ehdr64, sizeof(ehdr64), - info->name_dumpfile)) - goto out; - - } else { /* ELF32 */ - if (!write_buffer(info->fd_dumpfile, 0, &ehdr32, sizeof(ehdr32), - info->name_dumpfile)) - goto out; - } - - /* * Pre-calculate the required size to store eraseinfo in ELF note * section so that we can add enough space in ELF notes section and * adjust the PT_LOAD offset accordingly. @@ -6934,15 +6927,12 @@ write_elf_header(struct cache_data *cd_header) if (is_elf64_memory()) { /* ELF64 */ cd_header->offset = sizeof(ehdr64); offset_note_dumpfile = sizeof(ehdr64) - + sizeof(Elf64_Phdr) * ehdr64.e_phnum; + + sizeof(Elf64_Phdr) * num_loads_dumpfile; } else { cd_header->offset = sizeof(ehdr32); offset_note_dumpfile = sizeof(ehdr32) + sizeof(Elf32_Phdr) * ehdr32.e_phnum; } - offset_note_memory = note.p_offset; - note.p_offset = offset_note_dumpfile; - size_note = note.p_filesz; /* * Reserve a space to store the whole program headers. @@ -6952,6 +6942,35 @@ write_elf_header(struct cache_data *cd_header) goto out; /* + * Write the initial section header just after the program headers + * if necessary. This order is not typical, but looks enough for now. + */ + if (is_elf64_memory() && ehdr64.e_phnum == PN_XNUM) { + Elf64_Shdr shdr64; + + ehdr64.e_shoff = offset_note_dumpfile; + ehdr64.e_shentsize = sizeof(shdr64); + ehdr64.e_shnum = 1; + ehdr64.e_shstrndx = SHN_UNDEF; + + memset(&shdr64, 0, sizeof(shdr64)); + shdr64.sh_type = SHT_NULL; + shdr64.sh_size = ehdr64.e_shnum; + shdr64.sh_link = ehdr64.e_shstrndx; + shdr64.sh_info = num_loads_dumpfile; + + if (!write_buffer(info->fd_dumpfile, offset_note_dumpfile, + &shdr64, sizeof(shdr64), info->name_dumpfile)) + goto out; + + offset_note_dumpfile += sizeof(shdr64); + } + + offset_note_memory = note.p_offset; + note.p_offset = offset_note_dumpfile; + size_note = note.p_filesz; + + /* * Modify the note size in PT_NOTE header to accomodate eraseinfo data. * Eraseinfo will be written later. */ @@ -6968,6 +6987,20 @@ write_elf_header(struct cache_data *cd_header) goto out; /* + * Write the ELF header. + */ + if (is_elf64_memory()) { /* ELF64 */ + if (!write_buffer(info->fd_dumpfile, 0, &ehdr64, sizeof(ehdr64), + info->name_dumpfile)) + goto out; + + } else { /* ELF32 */ + if (!write_buffer(info->fd_dumpfile, 0, &ehdr32, sizeof(ehdr32), + info->name_dumpfile)) + goto out; + } + + /* * Write a PT_NOTE segment. * PT_LOAD header will be written later. */ |