commit 7d4f298d3edf2c03b1e107af29962dc4a315050a Author: Mahesh Salgaonkar Date: Fri Aug 19 17:12:59 2011 +0900 [UPDATED PATCH v2 8/8] Add erase information in ELF formatted dumpfile This is an updated patch that fixes a problem where empty ELF note gets populated when info->size_eraseinfo is zero. This updated patch now does not introduce new ELF note if info->size_eraseinfo == 0. Thanks, -Mahesh. makedumpfile: Add erase information in ELF formatted dumpfile From: Mahesh Salgaonkar This patch implements support for inclusion of erase information in ELF formatted dumpfile. This patch introduces a additional ELF Note section that contains erase information. Signed-off-by: Mahesh Salgaonkar --- diff -Nrup kexec-tools-2.0.0.orig/makedumpfile-1.3.5/makedumpfile.c kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.c --- kexec-tools-2.0.0.orig/makedumpfile-1.3.5/makedumpfile.c 2012-01-02 17:20:53.000000000 +0800 +++ kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.c 2012-01-02 17:21:28.000000000 +0800 @@ -3325,6 +3325,9 @@ get_pt_note_info(off_t off_note, unsigne return FALSE; } info->p2m_mfn = p2m_mfn; + } else if (n_type == NT_ERASE_INFO) { + info->offset_eraseinfo = offset_desc; + info->size_eraseinfo = size_desc; } offset += offset_next_note(note); } @@ -4620,6 +4623,15 @@ write_cache_bufsz(struct cache_data *cd) } int +write_cache_zero(struct cache_data *cd, size_t size) +{ + memset(cd->buf + cd->buf_size, 0, size); + cd->buf_size += size; + + return write_cache_bufsz(cd); +} + +int read_buf_from_stdin(void *buf, int buf_size) { int read_size = 0, tmp_read_size = 0; @@ -5750,10 +5762,12 @@ write_elf_header(struct cache_data *cd_h { int i, num_loads_dumpfile, phnum; off_t offset_note_memory, offset_note_dumpfile; - size_t size_note; + size_t size_note, size_eraseinfo = 0; Elf64_Ehdr ehdr64; Elf32_Ehdr ehdr32; Elf64_Phdr note; + char size_str[MAX_SIZE_STR_LEN]; + struct filter_info *fl_info = filter_info; char *buf = NULL; const off_t failed = (off_t)-1; @@ -5806,6 +5820,36 @@ write_elf_header(struct cache_data *cd_h } /* + * 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. + */ + while (fl_info) { + struct erase_info *ei; + + if (!fl_info->erase_info_idx) + continue; + ei = &erase_info[fl_info->erase_info_idx]; + if (fl_info->nullify) + sprintf(size_str, "nullify\n"); + else + sprintf(size_str, "%ld\n", fl_info->size); + + size_eraseinfo += strlen("erase ") + + strlen(ei->symbol_expr) + 1 + + strlen(size_str); + fl_info = fl_info->next; + } + + /* + * Store the size_eraseinfo for later use in write_elf_eraseinfo() + * function. This will overwrite the size fetched during + * get elf_info() function but we are ok with that. + */ + info->size_eraseinfo = size_eraseinfo; + DEBUG_MSG("erase info size: %lu\n", info->size_eraseinfo); + + /* * Write a PT_NOTE header. */ if (!(phnum = get_phnum_memory())) @@ -5835,6 +5879,19 @@ write_elf_header(struct cache_data *cd_h 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. + */ + if (info->size_eraseinfo) { + if (info->flag_elf64_memory) + note.p_filesz += sizeof(Elf64_Nhdr); + else + note.p_filesz += sizeof(Elf32_Nhdr); + note.p_filesz += roundup(ERASEINFO_NOTE_NAME_BYTES, 4) + + roundup(size_eraseinfo, 4); + } + if (!write_elf_phdr(cd_header, ¬e)) goto out; @@ -5861,10 +5918,14 @@ write_elf_header(struct cache_data *cd_h size_note, info->name_dumpfile)) goto out; + /* Set the size_note with new size. */ + size_note = note.p_filesz; + /* * Set an offset of PT_LOAD segment. */ info->offset_load_dumpfile = offset_note_dumpfile + size_note; + info->offset_note_dumpfile = offset_note_dumpfile; ret = TRUE; out: @@ -6677,6 +6738,67 @@ out: } int +write_elf_eraseinfo(struct cache_data *cd_header) +{ + char note[MAX_SIZE_NHDR]; + char buf[ERASEINFO_NOTE_NAME_BYTES + 4]; + unsigned long note_header_size, size_eraseinfo; + + if (!info->size_eraseinfo) + return TRUE; + + DEBUG_MSG("Writing erase info...\n"); + + /* calculate the eraseinfo ELF note offset */ + cd_header->offset = info->offset_note_dumpfile + + roundup(info->size_note, 4); + + /* Write eraseinfo ELF note header. */ + memset(note, 0, sizeof(note)); + if (info->flag_elf64_memory) { + Elf64_Nhdr *nh = (Elf64_Nhdr *)note; + + note_header_size = sizeof(Elf64_Nhdr); + nh->n_namesz = ERASEINFO_NOTE_NAME_BYTES; + nh->n_descsz = info->size_eraseinfo; + nh->n_type = NT_ERASE_INFO; + } else { + Elf32_Nhdr *nh = (Elf32_Nhdr *)note; + + note_header_size = sizeof(Elf32_Nhdr); + nh->n_namesz = ERASEINFO_NOTE_NAME_BYTES; + nh->n_descsz = info->size_eraseinfo; + nh->n_type = NT_ERASE_INFO; + } + if (!write_cache(cd_header, note, note_header_size)) + return FALSE; + + /* Write eraseinfo Note name */ + memset(buf, 0, sizeof(buf)); + memcpy(buf, ERASEINFO_NOTE_NAME, ERASEINFO_NOTE_NAME_BYTES); + if (!write_cache(cd_header, buf, + roundup(ERASEINFO_NOTE_NAME_BYTES, 4))) + return FALSE; + + info->offset_eraseinfo = cd_header->offset; + if (!write_eraseinfo(cd_header, &size_eraseinfo)) + return FALSE; + + /* + * The actual eraseinfo written may be less than pre-calculated size. + * Hence fill up the rest of size with zero's. + */ + if (size_eraseinfo < info->size_eraseinfo) + write_cache_zero(cd_header, + info->size_eraseinfo - size_eraseinfo); + + DEBUG_MSG("offset_eraseinfo: %lx, size_eraseinfo: %ld\n", + info->offset_eraseinfo, info->size_eraseinfo); + + return TRUE; +} + +int write_kdump_eraseinfo(struct cache_data *cd_page) { off_t offset_eraseinfo; @@ -7525,6 +7647,8 @@ writeout_dumpfile(void) goto out; if (!write_elf_pages(&cd_header, &cd_page)) goto out; + if (!write_elf_eraseinfo(&cd_header)) + goto out; } else { if (!write_kdump_header()) goto out; diff -Nrup kexec-tools-2.0.0.orig/makedumpfile-1.3.5/makedumpfile.h kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.h --- kexec-tools-2.0.0.orig/makedumpfile-1.3.5/makedumpfile.h 2012-01-02 17:20:53.000000000 +0800 +++ kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.h 2012-01-02 17:21:28.000000000 +0800 @@ -507,6 +507,22 @@ do { \ #define MAX_SIZE_STR_LEN (21) /* + * ELF note section for erase information + * + * According to elf.h the unused values are 0x15(21) through 0xff. The value + * range 0x1XX, 0x2XX and 0x3XX is been used for PPC, i386 and s390 + * respectively. + * + * Using 0xff to be on safer side so that any new Elf Note addition in elf.h + * after 0x15 value would not clash. + */ +#ifndef NT_ERASE_INFO +#define NT_ERASE_INFO (0xff) /* Contains erased information. */ +#endif +#define ERASEINFO_NOTE_NAME "ERASEINFO" +#define ERASEINFO_NOTE_NAME_BYTES (sizeof(ERASEINFO_NOTE_NAME)) + +/* * The value of dependence on machine */ #define PAGE_OFFSET (info->page_offset) @@ -945,6 +961,7 @@ struct DumpInfo { * ELF NOTE section in dump memory image info: */ off_t offset_note; + off_t offset_note_dumpfile; unsigned long size_note; /*