[RFC][PATCH] coredump: save timestamp in ELF core

From: Rustam Kovhaev
Date: Sat Sep 25 2021 - 13:15:41 EST


Hello Alexander and linux-fsdevel@,

I would like to propose saving a new note with timestamp in core file.
I do not know whether this is a good idea or not, and I would appreciate
your feedback.

Sometimes (unfortunately) I have to review windows user-space cores in
windbg, and there is one feature I would like to have in gdb.
In windbg there is a .time command that prints timestamp when core was
taken.

This might sound like a fixed problem, kernel's core_pattern can have
%t, and there are user-space daemons that write timestamp in the
report/journal file (apport/systemd-coredump), and sometimes it is
possible to correctly guess timestamp from btime/mtime file attribute,
and all of the above does indeed solve the problem most of the time.

But quite often, especially while researching hangs and not crashes,
when dump is written by gdb/gcore, I get only core.PID file and some
application log for research and there is no way to figure out when
exactly the core was taken.

I have posted a RFC patch to gdb-patches too [1] and I am copying
gdb-patches@ and binutils@ on this RFC.
Thank you!

[1] https://sourceware.org/pipermail/gdb-patches/2021-July/181163.html

Signed-off-by: Rustam Kovhaev <rkovhaev@xxxxxxxxx>
---
fs/binfmt_elf.c | 30 ++++++++++++++++++++++++++++++
include/uapi/linux/elf.h | 1 +
2 files changed, 31 insertions(+)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 69d900a8473d..f54ada303959 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1594,6 +1594,18 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata);
}

+static int fill_time_note(struct memelfnote *note)
+{
+ time64_t *time;
+
+ time = kvmalloc(sizeof(*time), GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(time))
+ return -ENOMEM;
+ *time = ktime_get_real_seconds();
+ fill_note(note, "CORE", NT_TIME, sizeof(*time), time);
+ return 0;
+}
+
#define MAX_FILE_NOTE_SIZE (4*1024*1024)
/*
* Format of NT_FILE note:
@@ -1704,6 +1716,7 @@ struct elf_note_info {
struct memelfnote signote;
struct memelfnote auxv;
struct memelfnote files;
+ struct memelfnote time;
user_siginfo_t csigdata;
size_t size;
int thread_notes;
@@ -1877,6 +1890,9 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
if (fill_files_note(&info->files) == 0)
info->size += notesize(&info->files);

+ if (fill_time_note(&info->time) == 0)
+ info->size += notesize(&info->time);
+
return 1;
}

@@ -1910,6 +1926,9 @@ static int write_note_info(struct elf_note_info *info,
if (first && info->files.data &&
!writenote(&info->files, cprm))
return 0;
+ if (first && info->time.data &&
+ !writenote(&info->time, cprm))
+ return 0;

for (i = 1; i < info->thread_notes; ++i)
if (t->notes[i].data &&
@@ -1937,6 +1956,7 @@ static void free_note_info(struct elf_note_info *info)
}
kfree(info->psinfo.data);
kvfree(info->files.data);
+ kvfree(info->time.data);
}

#else
@@ -1984,6 +2004,7 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
struct elf_note_info {
struct memelfnote *notes;
struct memelfnote *notes_files;
+ struct memelfnote *note_time;
struct elf_prstatus *prstatus; /* NT_PRSTATUS */
struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */
struct list_head thread_list;
@@ -2074,6 +2095,12 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
if (info->prstatus->pr_fpvalid)
fill_note(info->notes + info->numnote++,
"CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
+
+ if (fill_time_note(info->notes + info->numnote) == 0) {
+ info->note_time = info->notes + info->numnote;
+ info->numnote++;
+ }
+
return 1;
}

@@ -2122,6 +2149,9 @@ static void free_note_info(struct elf_note_info *info)
if (info->notes_files)
kvfree(info->notes_files->data);

+ if (info->note_time)
+ kvfree(info->note_time->data);
+
kfree(info->prstatus);
kfree(info->psinfo);
kfree(info->notes);
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index 61bf4774b8f2..e9256b8b8da9 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -375,6 +375,7 @@ typedef struct elf64_shdr {
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
#define NT_AUXV 6
+#define NT_TIME 9
/*
* Note to userspace developers: size of NT_SIGINFO note may increase
* in the future to accomodate more fields, don't assume it is fixed!
--
2.30.2