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;
}