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.
The patch is attached in plaintext below

Thanks,
Kyle
---------

>From 3c42074f9e99e6b5ca840b9ee9e965fb69122ef1 Mon Sep 17 00:00:00 2001
From: Kyle ZENG <jkjh1jk...@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 <jkjh1jk...@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

Reply via email to