This patch adds support for adding NT_FILE note in the ELF coredump.
It follows what's defined in readelf.
Let me know if there is any issue with the patch.
From 3c42074f9e99e6b5ca840b9ee9e965fb69122ef1 Mon Sep 17 00:00:00 2001
From: Kyle ZENG <
jkjh1jkjh1@gmail.com>
Date: Mon, 11 Jan 2021 21:54:09 -0700
Subject: [PATCH] add NT_FILE note for ELF core dump
Signed-off-by: Kyle ZENG <
jkjh1jkjh1@gmail.com>
---
include/elf.h | 1 +
linux-user/elfload.c | 92 ++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 90 insertions(+), 3 deletions(-)
diff --git a/include/elf.h b/include/elf.h
index 7a418ee..f701fd9 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1645,6 +1645,7 @@ typedef struct elf64_shdr {
#define NT_TASKSTRUCT 4
#define NT_AUXV 6
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
+#define NT_FILE 0x46494c45 /* copied from gdb/include/elf/common.h */
#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */
#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */
#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 (lower half) */
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index a640507..c095c0c 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -3317,6 +3317,13 @@ struct target_elf_prpsinfo {
char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
};
+struct target_ntfile_entry {
+ abi_ulong vm_start;
+ abi_ulong vm_end;
+ abi_ulong page_offset;
+ char *path;
+};
+
/* Here is the structure in which status of each thread is captured. */
struct elf_thread_status {
QTAILQ_ENTRY(elf_thread_status) ets_link;
@@ -3677,6 +3684,84 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
}
}
+static void fill_ntfile_note(struct memelfnote *note, TaskState *ts)
+{
+ GSList *map_info = read_self_maps();
+ GSList *s;
+ int count = 0;
+ int data_size = sizeof(abi_long)*2; // reserve space for num_map_entry and page_size
+ struct target_ntfile_entry *entries = NULL;
+
+ // grab memory mapping first
+ for (s = map_info; s; s = g_slist_next(s)) {
+ MapInfo *e = (MapInfo *) s->data;
+
+ if (h2g_valid(e->start)) {
+ unsigned long min = e->start;
+ unsigned long max = e->end;
+ int flags = page_get_flags(h2g(min));
+ const char *path;
+
+ max = h2g_valid(max - 1) ?
+ max : (uintptr_t) g2h(GUEST_ADDR_MAX) + 1;
+
+ if (page_check_range(h2g(min), max - min, flags) == -1) {
+ continue;
+ }
+
+ if (h2g(min) == ts->info->stack_limit) {
+ path = "[stack]";
+ } else {
+ path = e->path;
+ }
+
+ count++;
+ entries = realloc(entries, sizeof(struct target_ntfile_entry)*count);
+ struct target_ntfile_entry *entry = &entries[count-1];
+ memset(entry, 0, sizeof(*entry));
+
+ data_size += sizeof(abi_long)*3 + strlen(path) + 1;
+ entry->vm_start = h2g(min);
+ entry->vm_end = h2g(max - 1) + 1;
+ entry->page_offset = e->offset;
+ entry->path = strdup(path);
+ }
+ }
+
+ // prepare the memory mapping in NT_FILE format
+ char *ptr;
+ int idx = 0;
+ ptr = (char *)g_malloc0(data_size);
+ abi_long *long_ptr = (abi_long *)ptr;
+
+ // memory mappings
+ long_ptr[idx++] = count; // number of map entries
+ long_ptr[idx++] = TARGET_PAGE_SIZE; // target page size
+ for(int i=0; i<count; i++) {
+ struct target_ntfile_entry *entry = &entries[i];
+ long_ptr[idx++] = entry->vm_start;
+ long_ptr[idx++] = entry->vm_end;
+ long_ptr[idx++] = entry->page_offset;
+ }
+
+ // path names
+ idx *= sizeof(abi_long);
+ for(int i=0; i<count; i++) {
+ struct target_ntfile_entry *entry = &entries[i];
+ int path_size = strlen(entry->path);
+ strcpy(&ptr[idx], entry->path);
+ idx += path_size + 1;
+ free(entry->path);
+ }
+
+ // write it out
+ fill_note(note, "CORE", NT_FILE, data_size, ptr);
+
+ // cleanup
+ free(entries);
+ free_self_maps(map_info);
+}
+
/*
* Constructs name of coredump file. We have following convention
* for the name:
@@ -3807,7 +3892,7 @@ static void init_note_info(struct elf_note_info *info)
static int fill_note_info(struct elf_note_info *info,
long signr, const CPUArchState *env)
{
-#define NUMNOTES 3
+#define NUMNOTES 4
CPUState *cpu = env_cpu((CPUArchState *)env);
TaskState *ts = (TaskState *)cpu->opaque;
int i;
@@ -3824,7 +3909,7 @@ static int fill_note_info(struct elf_note_info *info,
/*
* First fill in status (and registers) of current thread
- * including process info & aux vector.
+ * including process info, aux vector & memory mapping.
*/
fill_prstatus(info->prstatus, ts, signr);
elf_core_copy_regs(&info->prstatus->pr_reg, env);
@@ -3834,7 +3919,8 @@ static int fill_note_info(struct elf_note_info *info,
fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
sizeof (*info->psinfo), info->psinfo);
fill_auxv_note(&info->notes[2], ts);
- info->numnote = 3;
+ fill_ntfile_note(&info->notes[3], ts);
+ info->numnote = NUMNOTES;
info->notes_size = 0;
for (i = 0; i < info->numnote; i++)
--
2.17.1