[PATCH resend v2 2/3] makedumpfile: make the incomplete dumpfile generated by ENOSPC error analyzable

Atsushi Kumagai kumagai-atsushi at mxc.nes.nec.co.jp
Tue Oct 7 22:39:42 PDT 2014


>Since the incomplete dumpfile generated by ENOSPC error can't be anylyzed
>by crash utility, but sometimes this file may contain important information
>and the panic problem won't be reproduced, then we came up with an idea to
>modify the exist data of the incomplete dumpfile to make it analyzable by
>crash utility. And each of those dumpfiles has a flag to indicate that it
>has been modified. As there are two formats of these dumpfiles, different
>methods and flags are needed to deal with each of them,
>
>elf:
>Modify the value of the PT_LOAD program header to reflect the actual size
>of the incomplete dumpfile. This method can't be used to modify the dumpfile
>written in flattened mode. This format use the "e_flags" of "elf header"
>to indicate that it has been modified.

Is it necessary to change the PT_LOAD headers in makedumpfile ?
It sounds too much work for makedumpfile, I think it's better to
avoid such an irreversible and more than enough change in capturing
phase. Are there some reasons why you don't do the same thing on the
fly in crash ?

OTOH, setting the incomplete flag is certainly makedumpfile's task
since crash can't detect ENOSPC.


Thanks
Atsushi Kumagai

>The method of dealing with "kdump-compressed" format dumpfiles is implemented
>in the next patch.
>
>Signed-of-by: Wang Xiao <wangx.fnst at cn.fujitsu.com>
>---
> makedumpfile.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 175 insertions(+), 4 deletions(-)
>
>diff --git a/makedumpfile.c b/makedumpfile.c
>index b4d43d8..0c84b35 100644
>--- a/makedumpfile.c
>+++ b/makedumpfile.c
>@@ -24,6 +24,7 @@
> #include <ctype.h>
> #include <sys/time.h>
> #include <limits.h>
>+#include <assert.h>
>
> struct symbol_table	symbol_table;
> struct size_table	size_table;
>@@ -3768,6 +3769,155 @@ read_flat_data_header(struct makedumpfile_data_header *fdh)
> }
>
> int
>+reserve_diskspace(int fd, off_t start_offset, off_t end_offset, char *file_name)
>+{
>+	size_t buf_size;
>+	char *buf = NULL;
>+
>+	int ret = FALSE;
>+
>+	assert(start_offset < end_offset);
>+	buf_size = end_offset - start_offset;
>+
>+	if ((buf = malloc(buf_size)) == NULL) {
>+		ERRMSG("Can't allocate memory for the size of reserved diskspace. %s\n",
>+		       strerror(errno));
>+		return FALSE;
>+	}
>+
>+	memset(buf, 0, buf_size);
>+	if (!write_buffer(fd, start_offset, buf, buf_size, file_name))
>+		goto out;
>+
>+	ret = TRUE;
>+out:
>+	if (buf != NULL) {
>+		free(buf);
>+	}
>+
>+	return ret;
>+}
>+
>+#define DUMP_ELF_INCOMPLETE 0x1
>+int
>+check_and_modify_elf_headers(char *filename) {
>+	int fd, i, phnum, ret = FALSE;
>+	off_t file_end, offset, end_offset;
>+	Elf64_Ehdr ehdr64;
>+	Elf32_Ehdr ehdr32;
>+
>+	if ((fd = open(filename, O_RDWR)) < 0) {
>+		ERRMSG("Can't open the dump file(%s). %s\n",
>+		       filename, strerror(errno));
>+		return FALSE;
>+	}
>+
>+	/*
>+	 * the is_elf64_memory() function still can be used.
>+	 */
>+	if (is_elf64_memory()) { /* ELF64 */
>+		if (!get_elf64_ehdr(fd, filename, &ehdr64)) {
>+			ERRMSG("Can't get ehdr64.\n");
>+			goto out_close_file;
>+		}
>+		phnum = ehdr64.e_phnum;
>+	} else { /* ELF32 */
>+		if (!get_elf32_ehdr(fd, filename, &ehdr32)) {
>+			ERRMSG("Can't get ehdr32.\n");
>+			goto out_close_file;
>+		}
>+		phnum = ehdr32.e_phnum;
>+	}
>+
>+	file_end = lseek(fd, 0, SEEK_END);
>+	if (file_end < 0) {
>+		ERRMSG("Can't detect the size of %s. %s\n",
>+		       filename, strerror(errno));
>+		goto out_close_file;
>+	}
>+
>+	for (i = 0; i < phnum; i++) {
>+		if (is_elf64_memory()) {
>+			Elf64_Phdr phdr64;
>+
>+			if (!get_elf64_phdr(fd, filename, i, &phdr64)) {
>+				ERRMSG("Can't find Phdr %d.\n", i);
>+				goto out_close_file;
>+			}
>+
>+			offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * i;
>+			end_offset = phdr64.p_offset + phdr64.p_filesz;
>+
>+			/*
>+			 * Check the program header and modify its value according
>+			 * to the actual written size.
>+			 */
>+			if (file_end >= end_offset)
>+				continue;
>+			/*
>+			 * This is the last PT_LOAD that still has some data, but
>+			 * not complete.
>+			 */
>+			else if (file_end >= phdr64.p_offset && file_end < end_offset)
>+				phdr64.p_filesz = file_end - phdr64.p_offset;
>+			else if (file_end < phdr64.p_offset) {
>+				phdr64.p_offset = 0;
>+				phdr64.p_filesz = 0;
>+			}
>+
>+			if (!write_buffer(fd, offset, &phdr64,
>+			                  sizeof(Elf64_Phdr), filename))
>+				goto out_close_file;
>+		} else {
>+			Elf32_Phdr phdr32;
>+
>+			if (!get_elf32_phdr(fd, filename, i, &phdr32)) {
>+				ERRMSG("Can't find Phdr %d.\n", i);
>+				goto out_close_file;
>+			}
>+
>+			offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * i;
>+			end_offset = phdr32.p_offset + phdr32.p_filesz;
>+
>+			if (file_end >= end_offset)
>+				continue;
>+			else if (file_end >= phdr32.p_offset && file_end < end_offset)
>+				phdr32.p_filesz = file_end - phdr32.p_offset;
>+			else if (file_end < phdr32.p_offset) {
>+				phdr32.p_offset = 0;
>+				phdr32.p_filesz = 0;
>+			}
>+
>+			if (!write_buffer(fd, offset, &phdr32,
>+			                  sizeof(Elf32_Phdr), filename))
>+				goto out_close_file;
>+		}
>+	}
>+
>+	/*
>+	 * Set the incomplete flag to the e_flags of elf header.
>+	 */
>+	if (is_elf64_memory()) {
>+		ehdr64.e_flags |= DUMP_ELF_INCOMPLETE;
>+		if (!write_buffer(fd, 0, &ehdr64, sizeof(Elf64_Ehdr), filename))
>+			goto out_close_file;
>+	} else {
>+		ehdr32.e_flags |= DUMP_ELF_INCOMPLETE;
>+		if (!write_buffer(fd, 0, &ehdr32, sizeof(Elf32_Ehdr), filename))
>+			goto out_close_file;
>+	}
>+
>+	ret = TRUE;
>+out_close_file:
>+	if (close(fd) < 0) {
>+		ERRMSG("Can't close the dump file(%s). %s\n",
>+		       filename, strerror(errno));
>+	}
>+
>+	return ret;
>+}
>+
>+int
> rearrange_dumpdata(void)
> {
> 	int read_size, tmp_read_size;
>@@ -5498,6 +5648,13 @@ write_elf_header(struct cache_data *cd_header)
> 	size_note          = note.p_filesz;
>
> 	/*
>+	 * Reserve a space to store the whole program headers.
>+	 */
>+	if (!reserve_diskspace(cd_header->fd, cd_header->offset,
>+				offset_note_dumpfile, cd_header->file_name))
>+		goto out;
>+
>+	/*
> 	 * Modify the note size in PT_NOTE header to accomodate eraseinfo data.
> 	 * Eraseinfo will be written later.
> 	 */
>@@ -8015,10 +8172,10 @@ writeout_dumpfile(void)
> 			goto out;
> 		if (info->flag_cyclic) {
> 			if (!write_elf_pages_cyclic(&cd_header, &cd_page))
>-				goto out;
>+				goto write_cache_enospc;
> 		} else {
> 			if (!write_elf_pages(&cd_header, &cd_page))
>-				goto out;
>+				goto write_cache_enospc;
> 		}
> 		if (!write_elf_eraseinfo(&cd_header))
> 			goto out;
>@@ -8045,6 +8202,11 @@ writeout_dumpfile(void)
> 	}
>
> 	ret = TRUE;
>+write_cache_enospc:
>+	if ((ret == FALSE) && info->flag_nospace && !info->flag_flatten) {
>+		if (!write_cache_bufsz(&cd_header))
>+			ERRMSG("This dumpfile may lost some important data.\n");
>+	}
> out:
> 	free_cache_data(&cd_header);
> 	free_cache_data(&cd_page);
>@@ -8237,8 +8399,17 @@ retry:
> 		 * to create a dumpfile with it again.
> 		 */
> 		num_retry++;
>-		if ((info->dump_level = get_next_dump_level(num_retry)) < 0)
>- 			return FALSE;
>+		if ((info->dump_level = get_next_dump_level(num_retry)) < 0) {
>+			if (!info->flag_flatten) {
>+				if (info->flag_elf_dumpfile) {
>+					if (check_and_modify_elf_headers(info->name_dumpfile))
>+						MSG("This is an incomplete dumpfile,"
>+						    " but might analyzable.\n");
>+				}
>+			}
>+
>+			return FALSE;
>+		}
> 		MSG("Retry to create a dumpfile by dump_level(%d).\n",
> 		    info->dump_level);
> 		if (!delete_dumpfile())
>--
>1.8.3.1
>
>
>_______________________________________________
>kexec mailing list
>kexec at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/kexec



More information about the kexec mailing list