File elfdump-Support-makedumpfile-flattened-dumps.patch of Package libkdumpfile.36085

From: Petr Tesarik <petr@tesarici.cz>
Date: Fri, 27 Sep 2024 10:42:26 +0200
Subject: elfdump: Support makedumpfile flattened dumps
References: bsc#1223399
Upstream: merged
Git-commit: b76dc429a4d3d09fbb227fd84135cccc6bf5ee8d

Allow to read ELF dumps in the flattened format, which can be produced with
"makedumpfile -E -F".

Extend the elf-basic test to accept extra parameters for mkelf. Add a
derived test which sets "flattened = yes" and call it elf-basic-flat.

[ ptesarik: Drop tests and NEWS. Tests would require backporting
  many additional patches, and NEWS is pointless. ]
Signed-off-by: Petr Tesarik <ptesarik@suse.com>
---
 src/kdumpfile/elfdump.c |  125 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 86 insertions(+), 39 deletions(-)
 create mode 100755 tests/elf-basic-flat

--- a/src/kdumpfile/elfdump.c
+++ b/src/kdumpfile/elfdump.c
@@ -138,6 +138,9 @@ struct elfdump_priv {
 
 	/** File offset of Xen page map (xc_core) */
 	off_t xen_map_offset;
+
+	/** File offset mappings for flattened files. */
+	struct flattened_map *flatmap;
 };
 
 static void elf_cleanup(struct kdump_shared *shared);
@@ -165,6 +168,44 @@ mach2arch(unsigned mach, int elfclass)
 	}
 }
 
+/** Read buffer from an ELF dump file.
+ * @param flatmap  Flattened offset map.
+ * @param buf      Target I/O buffer.
+ * @param len      Length of data.
+ * @param pos      File position.
+ * @returns        Error status.
+ *
+ * Read data from an ELF dump file. If the file is flattened, interpret
+ * @p pos as if it was already rearranged.
+ */
+static inline kdump_status
+elfdump_pread(struct flattened_map *flatmap, void *buf, size_t len,
+	      off_t pos)
+{
+	return flatmap_isflattened(flatmap)
+		? flatmap_pread(flatmap, buf, len, pos)
+		: fcache_pread(flatmap->fcache, buf, len, pos);
+}
+
+/** Get a contiguous data chunk from an ELF dump file.
+ * @param flatmap  Flattened offset map.
+ * @param fch      File cache chunk, updated on success.
+ * @param len      Length of data.
+ * @param pos      File position.
+ * @returns        Error status.
+ *
+ * Get a contiguous data chunk from an ELF dump file. If the file is
+ * flattened, interpret @p pos as if it was already rearranged.
+ */
+static inline kdump_status
+elfdump_get_chunk(struct flattened_map *flatmap, struct fcache_chunk *fch,
+		  size_t len, off_t pos)
+{
+	return flatmap_isflattened(flatmap)
+		? flatmap_get_chunk(flatmap, fch, len, pos)
+		: fcache_get_chunk(flatmap->fcache, fch, len, pos);
+}
+
 /**  Find the LOAD segment that is closest to a physical address.
  * @param edp	 ELF dump private data.
  * @param paddr	 Requested physical address.
@@ -260,8 +301,7 @@ elf_read_page(kdump_ctx_t *ctx, struct p
 			if (size > loadaddr + pls->filesz - addr)
 				size = loadaddr + pls->filesz - addr;
 
-			status = fcache_pread(ctx->shared->fcache,
-					      p, size, pos);
+			status = elfdump_pread(edp->flatmap, p, size, pos);
 			if (status != KDUMP_OK)
 				goto err_read;
 			p += size;
@@ -334,8 +374,8 @@ elf_get_page(kdump_ctx_t *ctx, struct pa
 		return cache_get_page(ctx, pio, elf_read_page);
 
 	mutex_lock(&ctx->shared->cache_lock);
-	status = fcache_get_chunk(ctx->shared->fcache, &pio->chunk, sz,
-				  pls->file_offset + addr - loadaddr);
+	status = elfdump_get_chunk(edp->flatmap, &pio->chunk, sz,
+				   pls->file_offset + addr - loadaddr);
 	mutex_unlock(&ctx->shared->cache_lock);
 	return status;
 }
@@ -745,7 +785,7 @@ xc_p2m_first_step(addrxlat_step_t *step,
 
 	pos = edp->xen_map_offset + idx * sizeof(struct xen_p2m);
 	mutex_lock(&shared->cache_lock);
-	status = fcache_pread(shared->fcache, &p2m, sizeof p2m, pos);
+	status = elfdump_pread(edp->flatmap, &p2m, sizeof p2m, pos);
 	mutex_unlock(&shared->cache_lock);
 	if (status != KDUMP_OK)
 		return addrxlat_ctx_err(step->ctx, ADDRXLAT_ERR_NODATA,
@@ -783,7 +823,7 @@ xc_m2p_first_step(addrxlat_step_t *step,
 
 	pos = edp->xen_map_offset + idx * sizeof(struct xen_p2m);
 	mutex_lock(&shared->cache_lock);
-	status = fcache_pread(shared->fcache, &p2m, sizeof p2m, pos);
+	status = elfdump_pread(edp->flatmap, &p2m, sizeof p2m, pos);
 	mutex_unlock(&shared->cache_lock);
 	if (status != KDUMP_OK)
 		return addrxlat_ctx_err(step->ctx, ADDRXLAT_ERR_NODATA,
@@ -887,8 +927,8 @@ xc_get_page(kdump_ctx_t *ctx, struct pag
 	offset = edp->xen_pages_offset + ((off_t)idx << get_page_shift(ctx));
 
 	mutex_lock(&ctx->shared->cache_lock);
-	status = fcache_get_chunk(ctx->shared->fcache, &pio->chunk,
-				  get_page_size(ctx), offset);
+	status = elfdump_get_chunk(edp->flatmap, &pio->chunk,
+				   get_page_size(ctx), offset);
 	mutex_unlock(&ctx->shared->cache_lock);
 	return status;
 }
@@ -988,8 +1028,8 @@ init_strtab(kdump_ctx_t *ctx, unsigned s
 	if (!edp->strtab)
 		return KDUMP_ERR_SYSTEM;
 
-	status = fcache_pread(ctx->shared->fcache, edp->strtab,
-			      ps->size, ps->file_offset);
+	status = elfdump_pread(edp->flatmap, edp->strtab, ps->size,
+			       ps->file_offset);
 	if (status != KDUMP_OK) {
 		free(edp->strtab);
 		edp->strtab = NULL;
@@ -1027,9 +1067,9 @@ init_elf32(kdump_ctx_t *ctx, Elf32_Ehdr
 	if (offset != 0 && (shnum == 0 || phnum == PN_XNUM)) {
 		Elf32_Shdr *sect;
 
-		ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-				       dump16toh(ctx, ehdr->e_shentsize),
-				       offset);
+		ret = elfdump_get_chunk(edp->flatmap, &fch,
+					dump16toh(ctx, ehdr->e_shentsize),
+					offset);
 		if (ret != KDUMP_OK)
 			return set_error(ctx, ret,
 					 "Cannot read ELF %s #%d at %llu",
@@ -1059,8 +1099,7 @@ init_elf32(kdump_ctx_t *ctx, Elf32_Ehdr
 		Elf32_Phdr *prog;
 		struct load_segment *pls;
 
-		ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-				       entsz, offset);
+		ret = elfdump_get_chunk(edp->flatmap, &fch, entsz, offset);
 		if (ret != KDUMP_OK)
 			return set_error(ctx, ret,
 					 "Cannot read ELF %s #%" PRIu32 " at %llu",
@@ -1087,8 +1126,7 @@ init_elf32(kdump_ctx_t *ctx, Elf32_Ehdr
 	for (i = 0; i < shnum; ++i) {
 		Elf32_Shdr *sect;
 
-		ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-				       entsz, offset);
+		ret = elfdump_get_chunk(edp->flatmap, &fch, entsz, offset);
 		if (ret != KDUMP_OK)
 			return set_error(ctx, ret,
 					 "Cannot read ELF %s #%" PRIu32 " at %llu",
@@ -1129,9 +1167,9 @@ init_elf64(kdump_ctx_t *ctx, Elf64_Ehdr
 	if (offset != 0 && (shnum == 0 || phnum == PN_XNUM)) {
 		Elf64_Shdr *sect;
 
-		ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-				       dump16toh(ctx, ehdr->e_shentsize),
-				       offset);
+		ret = elfdump_get_chunk(edp->flatmap, &fch,
+					dump16toh(ctx, ehdr->e_shentsize),
+					offset);
 		if (ret != KDUMP_OK)
 			return set_error(ctx, ret,
 					 "Cannot read ELF %s #%d at %llu",
@@ -1161,8 +1199,7 @@ init_elf64(kdump_ctx_t *ctx, Elf64_Ehdr
 		Elf64_Phdr *prog;
 		struct load_segment *pls;
 
-		ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-				       entsz, offset);
+		ret = elfdump_get_chunk(edp->flatmap, &fch, entsz, offset);
 		if (ret != KDUMP_OK)
 			return set_error(ctx, ret,
 					 "Cannot read ELF %s #%" PRIu64 " at %llu",
@@ -1189,8 +1226,7 @@ init_elf64(kdump_ctx_t *ctx, Elf64_Ehdr
 	for (i = 0; i < shnum; ++i) {
 		Elf64_Shdr *sect;
 
-		ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-				       entsz, offset);
+		ret = elfdump_get_chunk(edp->flatmap, &fch, entsz, offset);
 		if (ret != KDUMP_OK)
 			return set_error(ctx, ret,
 					 "Cannot read ELF %s #%" PRIu64 " at %llu",
@@ -1226,8 +1262,8 @@ walk_elf_notes(kdump_ctx_t *ctx, walk_no
 	for (i = 0; i < edp->num_note_segments; ++i) {
 		struct load_segment *seg = edp->note_segments + i;
 
-		ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-				       seg->filesz, seg->file_offset);
+		ret = elfdump_get_chunk(edp->flatmap, &fch, seg->filesz,
+					seg->file_offset);
 		if (ret != KDUMP_OK)
 			return set_error(ctx, ret,
 					 "Cannot read ELF notes at %llu",
@@ -1369,8 +1405,8 @@ open_common(kdump_ctx_t *ctx)
 				return set_error(ctx, ret,
 						 "Cannot create Xen PFN map");
 		} else if (!strcmp(name, ".note.Xen")) {
-			ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-					       sect->size, sect->file_offset);
+			ret = elfdump_get_chunk(edp->flatmap, &fch, sect->size,
+						sect->file_offset);
 			if (ret != KDUMP_OK)
 				return set_error(ctx, ret,
 						 "Cannot read '%s'", name);
@@ -1380,8 +1416,8 @@ open_common(kdump_ctx_t *ctx)
 				return set_error(ctx, ret,
 						 "Cannot process Xen notes");
 		} else if (!strcmp(name, ".xen_prstatus")) {
-			ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-					       sect->size, sect->file_offset);
+			ret = elfdump_get_chunk(edp->flatmap, &fch, sect->size,
+						sect->file_offset);
 			if (ret != KDUMP_OK)
 				return set_error(ctx, ret,
 						 "Cannot read '%s'", name);
@@ -1413,21 +1449,15 @@ open_common(kdump_ctx_t *ctx)
 static kdump_status
 do_probe(kdump_ctx_t *ctx, void *hdr)
 {
+	struct elfdump_priv *edp = ctx->shared->fmtdata;
 	unsigned char *eheader = hdr;
 	Elf32_Ehdr *elf32 = hdr;
 	Elf64_Ehdr *elf64 = hdr;
-	struct elfdump_priv *edp;
 
 	if (memcmp(eheader, ELFMAG, SELFMAG))
 		return set_error(ctx, KDUMP_NOPROBE,
 				 "Invalid ELF signature");
 
-	edp = calloc(1, sizeof *edp);
-	if (!edp)
-		return set_error(ctx, KDUMP_ERR_SYSTEM,
-				 "Cannot allocate ELF dump private data");
-	ctx->shared->fmtdata = edp;
-
 	switch (eheader[EI_DATA]) {
 	case ELFDATA2LSB:
 		set_byte_order(ctx, KDUMP_LITTLE_ENDIAN);
@@ -1462,11 +1492,27 @@ do_probe(kdump_ctx_t *ctx, void *hdr)
 static kdump_status
 elf_probe(kdump_ctx_t *ctx)
 {
+	struct elfdump_priv *edp;
 	struct fcache_chunk fch;
 	kdump_status ret;
 
-	ret = fcache_get_chunk(ctx->shared->fcache, &fch,
-			       sizeof(Elf64_Ehdr), 0);
+	edp = calloc(1, sizeof *edp);
+	if (!edp)
+		return set_error(ctx, KDUMP_ERR_SYSTEM,
+				 "Cannot allocate ELF dump private data");
+	ctx->shared->fmtdata = edp;
+
+	edp->flatmap = flatmap_alloc();
+	if (!edp->flatmap)
+		return set_error(ctx, KDUMP_ERR_SYSTEM,
+				 "Cannot allocate %s",
+				 "flattened dump maps");
+
+	ret = flatmap_init(edp->flatmap, ctx);
+	if (ret != KDUMP_OK)
+		return ret;
+
+	ret = elfdump_get_chunk(edp->flatmap, &fch, sizeof(Elf64_Ehdr), 0);
 	if (ret != KDUMP_OK)
 		return set_error(ctx, ret, "Cannot read dump header");
 
@@ -1498,6 +1544,7 @@ elf_cleanup(struct kdump_shared *shared)
 			free(edp->strtab);
 		pfn2idx_map_free(&edp->xen_pfnmap);
 		pfn2idx_map_free(&edp->xen_mfnmap);
+		flatmap_free(edp->flatmap);
 		free(edp);
 		shared->fmtdata = NULL;
 	}
openSUSE Build Service is sponsored by