Previously were added the ability to save userinfo data to separate ELF note subsection. This patch adds read mechanism. The command to retrieve user specific information: makedumpfile -U userinfofile dumpfile. Signed-off-by: Ivan Khoronzhuk <ikhoronz@xxxxxxxxx> --- makedumpfile.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++ makedumpfile.h | 2 + 2 files changed, 226 insertions(+) diff --git a/makedumpfile.c b/makedumpfile.c index 6b6b4d2..0d29b87 100644 --- a/makedumpfile.c +++ b/makedumpfile.c @@ -1519,6 +1519,60 @@ open_files_for_generating_vmcoreinfo(void) return TRUE; } +int +open_files_for_generating_userinfo(void) +{ + FILE *file_userinfo; + int fd; + + if ((file_userinfo = fopen(info->name_userinfo, "w+")) < 0) { + ERRMSG("Can't open the userinfo file(%s). %s\n", + info->name_userinfo, strerror(errno)); + return FALSE; + } + + info->file_userinfo = file_userinfo; + + if ((fd = open(info->name_dumpfile, O_RDONLY)) < 0) { + ERRMSG("Can't open the dump file(%s). %s\n", + info->name_dumpfile, strerror(errno)); + return FALSE; + } + info->fd_dumpfile = fd; + + return TRUE; +} + +int +get_phdr_dumpfile(int index, Elf64_Phdr *phdr) +{ + Elf32_Phdr phdr32; + + if (is_elf64_memory()) { /* ELF64 */ + if (!get_elf64_phdr(info->fd_dumpfile, info->name_dumpfile, + index, phdr)) { + ERRMSG("Can't find Phdr %d.\n", index); + return FALSE; + } + } else { + if (!get_elf32_phdr(info->fd_dumpfile, info->name_dumpfile, + index, &phdr32)) { + ERRMSG("Can't find Phdr %d.\n", index); + return FALSE; + } + memset(phdr, 0, sizeof(Elf64_Phdr)); + phdr->p_type = phdr32.p_type; + phdr->p_flags = phdr32.p_flags; + phdr->p_offset = phdr32.p_offset; + phdr->p_vaddr = phdr32.p_vaddr; + phdr->p_paddr = phdr32.p_paddr; + phdr->p_filesz = phdr32.p_filesz; + phdr->p_memsz = phdr32.p_memsz; + phdr->p_align = phdr32.p_align; + } + return TRUE; +} + /* * Open the following file when it rearranges the dump data. * - dump file @@ -4758,6 +4812,122 @@ read_cache(struct cache_data *cd) return TRUE; } +int +copy_userinfo(struct cache_data *cd) +{ + size_t buf_size, size; + char buf[BUFSIZE_FGETS]; + + cd->buf = buf; + buf_size = info->size_elf_userinfo; + + while (buf_size > 0) { + size = buf_size >= BUFSIZE_FGETS ? BUFSIZE_FGETS : buf_size; + + cd->cache_size = size; + if (!read_cache(cd)) + return FALSE; + + if (fwrite(cd->buf, size, 1, info->file_userinfo) != size) + return FALSE; + + buf_size -= BUFSIZE_FGETS; + } + + return TRUE; +} + +int +generate_userinfo(void) +{ + char buf[USERINFO_NOTE_NAME_BYTES]; + size_t nhdr_size, size_note; + off_t userinfo_offset = 0; + Elf64_Phdr note_phdr; + struct cache_data ui; + Elf64_Ehdr ehdr64; + Elf32_Ehdr ehdr32; + int i, phnum; + off_t offset; + void *note; + + if (!info->flag_elf_dumpfile) + return FALSE; + + if (is_elf64_memory()) { /* ELF64 */ + if (!get_elf64_ehdr(info->fd_dumpfile, info->name_dumpfile, + &ehdr64)) { + ERRMSG("Can't get ehdr64.\n"); + return FALSE; + } + phnum = ehdr64.e_phnum; + + } else { /* ELF32 */ + if (!get_elf32_ehdr(info->fd_dumpfile, info->name_dumpfile, + &ehdr32)) { + ERRMSG("Can't get ehdr32.\n"); + return FALSE; + } + phnum = ehdr32.e_phnum; + } + + for (i = 0; i < phnum; i++) { + if (!get_phdr_dumpfile(i, ¬e_phdr)) + return FALSE; + + if (note_phdr.p_type == PT_NOTE) + break; + } + + if (note_phdr.p_type != PT_NOTE) { + ERRMSG("Can't get a PT_NOTE header.\n"); + return FALSE; + } + + size_note = note_phdr.p_filesz; + ui.offset = note_phdr.p_offset; + ui.fd = info->fd_dumpfile; + ui.file_name = info->name_dumpfile; + ui.buf = buf; + + nhdr_size = is_elf64_memory() ? sizeof(Elf64_Nhdr) : + sizeof(Elf32_Nhdr); + + ui.cache_size = nhdr_size + USERINFO_NOTE_NAME_BYTES; + + /* find userinfo section */ + while (size_note > 0) { + if (!read_cache(&ui)) + return FALSE; + + note = ui.buf; + if (strcmp(note + nhdr_size, USERINFO_NOTE_NAME) == 0) { + userinfo_offset = ui.offset; + info->size_elf_userinfo = note_descsz(note); + break; + } + + offset = offset_next_note(note); + size_note -= offset; + + /* set next pnhdr */ + ui.offset += note_descsz(note); + } + + if (!userinfo_offset) { + ERRMSG("Can't get a USERINFO header.\n"); + return FALSE; + } + + ui.offset = userinfo_offset; + + if (!copy_userinfo(&ui)) + return FALSE; + + return TRUE; +} + + int is_bigendian(void) { @@ -9450,6 +9620,15 @@ close_files_for_generating_vmcoreinfo(void) return TRUE; } +int +close_files_for_generating_userinfo(void) +{ + close_dump_file(); + close_userinfo_file(); + + return TRUE; +} + /* * Close the following file when it rearranges the dump data. * - dump file @@ -9458,6 +9637,7 @@ int close_files_for_rearranging_dumpdata(void) { close_dump_file(); + close_userinfo_file(); return TRUE; } @@ -11302,6 +11482,23 @@ check_param_for_rearranging_dumpdata(int argc, char *argv[]) return TRUE; } +int +check_param_for_creating_userinfo_file(int argc, char *argv[]) +{ + if (argc != optind + 1) + return FALSE; + + if (info->flag_compress || info->dump_level + || info->flag_elf_dumpfile || info->flag_read_vmcoreinfo + || info->name_vmlinux || info->name_xen_syms + || info->flag_flatten || info->flag_generate_vmcoreinfo + || info->flag_exclude_xen_dom || info->flag_rearrange) + return FALSE; + + info->name_dumpfile = argv[optind]; + return TRUE; +} + /* * Parameters for reassembling multiple dumpfiles into one dumpfile. */ @@ -11974,6 +12171,10 @@ main(int argc, char *argv[]) info->flag_insert_userinfo = 1; info->name_userinfo = optarg; break; + case OPT_GENERATE_USERINFO: + info->flag_generate_userinfo = 1; + info->name_userinfo = optarg; + break; case OPT_XEN_PHYS_START: info->xen_phys_start = strtoul(optarg, NULL, 0); break; @@ -12097,6 +12298,29 @@ main(int argc, char *argv[]) MSG("\n"); MSG("The vmcoreinfo is saved to %s.\n", info->name_vmcoreinfo); + } else if (info->flag_generate_userinfo) { + if (!check_param_for_creating_userinfo_file(argc, argv)) { + MSG("Commandline parameter is invalid.\n"); + MSG("Try `makedumpfile --help' for more information.\n"); + goto out; + } + if (info->flag_check_params) + goto check_ok; + + if (!check_file_is_writable(info->name_userinfo)) + goto out; + + if (!open_files_for_generating_userinfo()) + goto out; + + if (!generate_userinfo()) + goto out; + + if (!close_files_for_generating_userinfo()) + goto out; + + MSG("\n"); + MSG("The userinfo file is saved to %s.\n", info->name_userinfo); } else if (info->flag_rearrange) { if (!check_param_for_rearranging_dumpdata(argc, argv)) { diff --git a/makedumpfile.h b/makedumpfile.h index b28b0a5..26f44c9 100644 --- a/makedumpfile.h +++ b/makedumpfile.h @@ -1360,6 +1360,7 @@ struct DumpInfo { int flag_generate_vmcoreinfo;/* flag of generating vmcoreinfo file */ int flag_read_vmcoreinfo; /* flag of reading vmcoreinfo file */ int flag_insert_userinfo; /* flag of inserting userinfo file into ELF note section */ + int flag_generate_userinfo; /* flag of inserting userinfo file into ELF note section */ int flag_show_usage; /* flag of showing usage */ int flag_show_version; /* flag of showing version */ int flag_check_params; /* only check parameters */ @@ -2491,6 +2492,7 @@ struct elf_prstatus { #define OPT_VMLINUX 'x' #define OPT_COMPRESS_ZSTD 'z' #define OPT_USERINFO 'u' +#define OPT_GENERATE_USERINFO 'U' #define OPT_START 256 #define OPT_SPLIT OPT_START+0 #define OPT_REASSEMBLE OPT_START+1 -- 2.20.1 _______________________________________________ kexec mailing list kexec@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/kexec