[RFC makedumpfile: add userinfo elf section 2/4] elf: add new "userinfo" ELF section to traverse debug information

Ivan Khoronzhuk ivan.khoronzhuk at gmail.com
Wed Dec 1 05:47:28 PST 2021


It's only for elf dumpfile, for compressed version should be added in
separate file. It adds new note section to the NOTE segment.

Signed-off-by: Ivan Khoronzhuk <ikhoronz at cisco.com>
---
 elf_info.h     |   3 +
 makedumpfile.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++-
 makedumpfile.h |  10 ++++
 3 files changed, 167 insertions(+), 1 deletion(-)

diff --git a/elf_info.h b/elf_info.h
index d5416b3..ca96935 100644
--- a/elf_info.h
+++ b/elf_info.h
@@ -25,6 +25,9 @@
 #define ERASEINFO_NOTE_NAME		"ERASEINFO"
 #define ERASEINFO_NOTE_NAME_BYTES	(sizeof(ERASEINFO_NOTE_NAME))
 
+#define USERINFO_NOTE_NAME		"USERINFO"
+#define USERINFO_NOTE_NAME_BYTES	(sizeof(USERINFO_NOTE_NAME))
+
 #define MAX_SIZE_NHDR	MAX(sizeof(Elf64_Nhdr), sizeof(Elf32_Nhdr))
 
 int get_elf64_phdr(int fd, char *filename, int index, Elf64_Phdr *phdr);
diff --git a/makedumpfile.c b/makedumpfile.c
index 6b62b92..6b6b4d2 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -1396,6 +1396,23 @@ open_dump_file(void)
 	return TRUE;
 }
 
+int
+open_userinfo_file(void)
+{
+	FILE *file_userinfo;
+
+	if (info->flag_flatten || info->flag_dry_run ||
+	    !info->flag_insert_userinfo) {
+		file_userinfo = NULL;
+	} else if ((file_userinfo = fopen(info->name_userinfo, "r")) < 0) {
+		ERRMSG("Can't open the userinfo file(%s). %s\n",
+		    info->name_userinfo, strerror(errno));
+		return FALSE;
+	}
+	info->file_userinfo = file_userinfo;
+	return TRUE;
+}
+
 int
 check_file_is_writable(const char *path)
 {
@@ -7080,12 +7097,26 @@ write_elf_phdr(struct cache_data *cd_hdr, Elf64_Phdr *load)
 	return TRUE;
 }
 
+unsigned long
+get_size_userinfo(void)
+{
+	unsigned long size_userinfo = 0;
+
+	if (info->file_userinfo) {
+		fseek(info->file_userinfo, 0, SEEK_END);
+		size_userinfo = ftell(info->file_userinfo);
+		fseek(info->file_userinfo, 0, SEEK_SET);
+	}
+
+	return size_userinfo;
+}
+
 int
 write_elf_header(struct cache_data *cd_header)
 {
 	int i, num_loads_dumpfile, phnum;
 	off_t offset_note_memory, offset_note_dumpfile;
-	size_t size_note, size_eraseinfo = 0;
+	size_t size_note, size_eraseinfo = 0, size_userinfo;
 	Elf64_Ehdr ehdr64;
 	Elf32_Ehdr ehdr32;
 	Elf64_Phdr note;
@@ -7148,6 +7179,13 @@ write_elf_header(struct cache_data *cd_header)
 	 */
 	info->size_elf_eraseinfo = size_eraseinfo;
 
+	size_userinfo = get_size_userinfo();
+	/*
+	 * Store the size_userinfo for later use in write_elf_userinfo()
+	 * function.
+	 */
+	info->size_elf_userinfo = size_userinfo;
+
 	/*
 	 * Write a PT_NOTE header.
 	 */
@@ -7224,6 +7262,19 @@ write_elf_header(struct cache_data *cd_header)
 					roundup(size_eraseinfo, 4);
 	}
 
+	/*
+	 * Modify the note size in PT_NOTE header to accomodate userinfo data.
+	 * Userinfo will be written later.
+	 */
+	if (info->size_elf_userinfo) {
+		if (is_elf64_memory())
+			note.p_filesz += sizeof(Elf64_Nhdr);
+		else
+			note.p_filesz += sizeof(Elf32_Nhdr);
+		note.p_filesz += roundup(USERINFO_NOTE_NAME_BYTES, 4) +
+					roundup(size_userinfo, 4);
+	}
+
 	if (!write_elf_phdr(cd_header, &note))
 		goto out;
 
@@ -8892,6 +8943,27 @@ out:
 	return ret;
 }
 
+/*
+ * Traverse through userinfo nodes and write it to the o/p dumpfile.
+ */
+int
+write_userinfo(struct cache_data *cd_page)
+{
+	char buf[BUFSIZE_FGETS];
+	int len;
+
+	while (fgets(buf, BUFSIZE_FGETS, info->file_userinfo)) {
+		len = strlen(buf);
+		if (!len)
+			break;
+
+		if (!write_cache(cd_page, buf, len))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
 int
 write_elf_eraseinfo(struct cache_data *cd_header)
 {
@@ -8957,6 +9029,64 @@ write_elf_eraseinfo(struct cache_data *cd_header)
 	return TRUE;
 }
 
+static int
+write_elf_userinfo(struct cache_data *cd_header)
+{
+	char note[MAX_SIZE_NHDR];
+	char buf[USERINFO_NOTE_NAME_BYTES + 4];
+	off_t offset_userinfo;
+	unsigned long note_header_size, size_note;
+
+	DEBUG_MSG("user info size: %lu\n", info->size_elf_userinfo);
+
+	if (!info->size_elf_userinfo)
+		return TRUE;
+
+	DEBUG_MSG("Writing user info...\n");
+
+	/* calculate the userinfo ELF note offset */
+	get_pt_note(NULL, &size_note);
+	cd_header->offset = info->offset_note_dumpfile +
+				roundup(size_note, 4) +
+				roundup(info->size_elf_eraseinfo, 4);
+
+	/* Write userinfo ELF note header. */
+	memset(note, 0, sizeof(note));
+	if (is_elf64_memory()) {
+		Elf64_Nhdr *nh = (Elf64_Nhdr *)note;
+
+		note_header_size = sizeof(Elf64_Nhdr);
+		nh->n_namesz = USERINFO_NOTE_NAME_BYTES;
+		nh->n_descsz = info->size_elf_userinfo;
+		nh->n_type = 0;
+	} else {
+		Elf32_Nhdr *nh = (Elf32_Nhdr *)note;
+
+		note_header_size = sizeof(Elf32_Nhdr);
+		nh->n_namesz = USERINFO_NOTE_NAME_BYTES;
+		nh->n_descsz = info->size_elf_userinfo;
+		nh->n_type = 0;
+	}
+	if (!write_cache(cd_header, note, note_header_size))
+		return FALSE;
+
+	/* Write userinfo Note name */
+	memset(buf, 0, sizeof(buf));
+	memcpy(buf, USERINFO_NOTE_NAME, USERINFO_NOTE_NAME_BYTES);
+	if (!write_cache(cd_header, buf,
+				roundup(USERINFO_NOTE_NAME_BYTES, 4)))
+		return FALSE;
+
+	offset_userinfo = cd_header->offset;
+	if (!write_userinfo(cd_header))
+		return FALSE;
+
+	DEBUG_MSG("offset_userinfo: %llx, size_userinfo: %ld\n",
+		(unsigned long long)offset_userinfo, info->size_elf_userinfo);
+
+	return TRUE;
+}
+
 int
 write_kdump_eraseinfo(struct cache_data *cd_page)
 {
@@ -9260,6 +9390,18 @@ close_dump_file(void)
 	info->fd_dumpfile = -1;
 }
 
+void
+close_userinfo_file(void)
+{
+	if (info->flag_flatten || info->flag_dry_run)
+		return;
+
+	if (fclose(info->file_userinfo) < 0)
+		ERRMSG("Can't close the userinfo file(%s). %s\n",
+		    info->name_userinfo, strerror(errno));
+	info->file_userinfo = NULL;
+}
+
 void
 close_dump_bitmap(void)
 {
@@ -10193,6 +10335,9 @@ writeout_dumpfile(void)
 	if (!open_dump_file())
 		return FALSE;
 
+	if (!open_userinfo_file())
+		return FALSE;
+
 	if (info->flag_flatten) {
 		if (!write_start_flat_header())
 			return FALSE;
@@ -10211,6 +10356,8 @@ writeout_dumpfile(void)
 				goto write_cache_enospc;
 		if (!write_elf_eraseinfo(&cd_header))
 			goto out;
+		if (!write_elf_userinfo(&cd_header))
+			goto out;
 	} else {
 		if (!write_kdump_header())
 			goto out;
@@ -10235,6 +10382,7 @@ out:
 	free_cache_data(&cd_page);
 
 	close_dump_file();
+	close_userinfo_file();
 
 	if ((ret == FALSE) && info->flag_nospace)
 		return NOSPACE;
@@ -11693,6 +11841,7 @@ static struct option longopts[] = {
 	{"check-params", no_argument, NULL, OPT_CHECK_PARAMS},
 	{"dry-run", no_argument, NULL, OPT_DRY_RUN},
 	{"show-stats", no_argument, NULL, OPT_SHOW_STATS},
+	{"userinfo", required_argument, NULL, OPT_USERINFO},
 	{0, 0, 0, 0}
 };
 
@@ -11821,6 +11970,10 @@ main(int argc, char *argv[])
 		case OPT_COMPRESS_ZSTD:
 			info->flag_compress = DUMP_DH_COMPRESSED_ZSTD;
 			break;
+		case OPT_USERINFO:
+			info->flag_insert_userinfo = 1;
+			info->name_userinfo = optarg;
+			break;
 		case OPT_XEN_PHYS_START:
 			info->xen_phys_start = strtoul(optarg, NULL, 0);
 			break;
diff --git a/makedumpfile.h b/makedumpfile.h
index d583249..b28b0a5 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1359,6 +1359,7 @@ struct DumpInfo {
 	int		flag_elf_dumpfile;   /* flag of creating ELF dumpfile */
 	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_show_usage;     /* flag of showing usage */
 	int		flag_show_version;   /* flag of showing version */
 	int		flag_check_params;   /* only check parameters */
@@ -1469,6 +1470,9 @@ struct DumpInfo {
 	int			fd_xen_syms;
 	char			*name_xen_syms;
 
+	FILE			*file_userinfo;
+	char			*name_userinfo;
+
 	/*
 	 * Dump memory image info:
 	 */
@@ -1512,6 +1516,11 @@ struct DumpInfo {
 	 */
 	unsigned long           size_elf_eraseinfo;
 
+	/*
+	 * userinfo in dump memory image info:
+	 */
+	unsigned long           size_elf_userinfo;
+
 	/*
 	 * for Xen extraction
 	 */
@@ -2481,6 +2490,7 @@ struct elf_prstatus {
 #define OPT_EXCLUDE_XEN_DOM     'X'
 #define OPT_VMLINUX             'x'
 #define OPT_COMPRESS_ZSTD       'z'
+#define OPT_USERINFO            'u'
 #define OPT_START               256
 #define OPT_SPLIT               OPT_START+0
 #define OPT_REASSEMBLE          OPT_START+1
-- 
2.20.1




More information about the kexec mailing list