[RFC PATCH] Add a new 'info proc time' subcommand of 'info proc'.

Rustam Kovhaev via Gdb-patches
2021-07-27T22:09:08Z

Sometimes (unfortunately) I have to review windows user-space cores in
windbg, and there is one feature that I really want to implement in gdb,
but I don't know whether it is a good idea or not, and why it has not
yet been implemented in gdb.

In wdbg there is a .time command that gives me time when core was taken.
I could not find the same functionality in gdb and in elf core.
I know about kernel core_pattern and timestamp, and there are user-space
daemons that write the timestamp, and sometimes if I am lucky I can get
timestamp from modified/created file attributes and this solves the
problem most of the time, but quite often I get only core.PID file +
some app log and there is no way for me to figure out when exactly the
core was taken.

Current patch does not take into account lots of things like endianness,
cpu archs other than x86, other code paths, etc, and there is also
kernel side to modify and coordinate, but it does work in my lab, and I
was pretty happy to learn a little bit about the project.

This command displays a timestamp when core was taken.

include/
* elf/common.h (NT_TIME): new define
bfd/
* elf.c (elfcore_grok_note): create new pseudosection
.note.linuxcore.time for NT_TIME note.
gdb/
* defs.h (IP_TIME): new define.
* infcmd.c (info_proc_cmd_time): add new function.
* linux-tdep.c (linux_make_corefile_notes): save NT_TIME
note.
(_initialize_infcmd): register 'info proc time' command.
binutils/
* readelf.c (get_note_type): handle NT_TIME note.

Signed-off-by: Rustam Kovhaev <rkovhaev@gmail.com>
---
bfd/elf.c | 4 ++++
binutils/readelf.c | 2 ++
gdb/defs.h | 3 +++
gdb/infcmd.c | 12 ++++++++++++
gdb/linux-tdep.c | 29 ++++++++++++++++++++++++++++-
include/elf/common.h | 1 +
6 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/bfd/elf.c b/bfd/elf.c
index de5abafabf0..2fd1b24ba3f 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -10678,6 +10678,10 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)

case NT_MEMTAG:
return elfcore_make_memtag_note_section (abfd, note, 0);
+
+ case NT_TIME:
+ return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.time",
+ note);
}
}

diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5682837ed7b..a6c4e020945 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18738,6 +18738,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
if (filedata->file_header.e_type == ET_CORE)
switch (e_type)
{
+ case NT_TIME:
+ return _("NT_TIME (timestamp)");
case NT_AUXV:
return _("NT_AUXV (auxiliary vector)");
case NT_PRSTATUS:
diff --git a/gdb/defs.h b/gdb/defs.h
index 6dea4099554..51f0d123586 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -398,6 +398,9 @@ enum info_proc_what
/* * Display `info proc files'. */
IP_FILES,

+ /* * Display `info proc time'. */
+ IP_TIME,
+
/* * Display all of the above. */
IP_ALL
};
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index c183b60e81a..154f284c2db 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2934,6 +2934,14 @@ info_proc_cmd_files (const char *args, int from_tty)
info_proc_cmd_1 (args, IP_FILES, from_tty);
}

+/* Implement `info proc time'. */
+
+static void
+info_proc_cmd_time (const char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_TIME, from_tty);
+}
+
/* Implement `info proc all'. */

static void
@@ -3288,6 +3296,10 @@ List absolute filename for executable of the specified process."),
List files opened by the specified process."),
&info_proc_cmdlist);

+ add_cmd ("time", class_info, info_proc_cmd_time, _("\
+Print timestamp when core was taken."),
+ &info_proc_cmdlist);
+
add_cmd ("all", class_info, info_proc_cmd_all, _("\
List all available info about the specified process."),
&info_proc_cmdlist);
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 637d3d36a0b..40d9e53c133 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -1192,6 +1192,23 @@ linux_read_core_file_mappings (struct gdbarch *gdbarch,
}
}

+/* Implement "info proc time" for a corefile. */
+
+static void linux_core_info_proc_time ()
+{
+ size_t note_size;
+ time_t timestamp;
+ asection *section = bfd_get_section_by_name (core_bfd, ".note.linuxcore.time");
+ if (section == nullptr)
+ return;
+
+ note_size = bfd_section_size (section);
+ if (sizeof(timestamp) < note_size)
+ return;
+ if (bfd_get_section_contents (core_bfd, section, &timestamp, 0, note_size))
+ printf_filtered ("core was taken at %s", ctime (&timestamp));
+}
+
/* Implement "info proc mappings" for a corefile. */

static void
@@ -1244,6 +1261,7 @@ linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
{
int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
+ int time_f = (what == IP_TIME);

if (exe_f)
{
@@ -1259,7 +1277,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
if (mappings_f)
linux_core_info_proc_mappings (gdbarch, args);

- if (!exe_f && !mappings_f)
+ if (time_f)
+ linux_core_info_proc_time();
+
+ if (!exe_f && !mappings_f && !time_f)
error (_("unable to handle request"));
}

@@ -1984,10 +2005,16 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
{
struct elf_internal_linux_prpsinfo prpsinfo;
gdb::unique_xmalloc_ptr<char> note_data;
+ time_t now;

if (! gdbarch_iterate_over_regset_sections_p (gdbarch))
return NULL;

+ now = time(NULL);
+ note_data.reset (elfcore_write_note (obfd, note_data.release (),
+ note_size, "CORE", NT_TIME,
+ &now, sizeof(now)));
+
if (linux_fill_prpsinfo (&prpsinfo))
{
if (gdbarch_ptr_bit (gdbarch) == 64)
diff --git a/include/elf/common.h b/include/elf/common.h
index 0d381f0d27b..51a50d025a0 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -593,6 +593,7 @@
#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
#define NT_TASKSTRUCT 4 /* Contains copy of task struct */
#define NT_AUXV 6 /* Contains copy of Elfxx_auxv_t */
+#define NT_TIME 9 /* Contains time when core was taken */
#define NT_PRXFPREG 0x46e62b7f /* Contains a user_xfpregs_struct; */
/* note name must be "LINUX". */
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
--
2.30.2