summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elf_info.c40
-rw-r--r--elf_info.h1
-rw-r--r--makedumpfile.c73
3 files changed, 91 insertions, 23 deletions
diff --git a/elf_info.c b/elf_info.c
index 204bfbf..e9c2671 100644
--- a/elf_info.c
+++ b/elf_info.c
@@ -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");
diff --git a/elf_info.h b/elf_info.h
index cd4ffa6..934b608 100644
--- a/elf_info.h
+++ b/elf_info.h
@@ -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.
*/