[PATCH] Implement new `info core mappings' command

Sergio Durigan Junior
2011-10-26T20:50:19Z

Hello there,

This patch is the revival of:

http://sourceware.org/ml/gdb-patches/2008-12/msg00322.html

It's been a while since I wanted to work on this again, and hopefully
get it upstream. I re-read the above thread, tried to address all the
comments, rewrote some things, wrote testcase & doc & NEWS, and that's
it.

What this patch does is implement a new `info' command, called `info
core', and then implement a sub-command called `info core mappings'.
This was heavily based on the existing `info proc mappings'. The code
iterates over the corefile's sections and, using some heuristics, match
the ones containing useful information for displaying a memory mapping
of the process. If the corefile section we're examining is empty, then
it tries to search this information at ELF program headers, which is
almost always the used solution.

One thing I am not sure is where to put the entry for this command on
the documentation. I decided to put it below `info proc', but I'd be
glad if you could give your opinions.

Reviews are welcome, as usual. Thanks!

Sergio.

2011-10-26 Sergio Durigan Junior <sergiodj@redhat.com>

Implement `info core mappings'.
* NEWS: Mention new `info core mappings' command.
* corefile.c: Include a bunch of header files needed to implement
the `info core mappings'.
(print_proc_map_iter): New function.
(print_core_map): Likewise.
(info_core_cmd): Likewise.
(_initialize_core): Add new `info core' command.

2011-10-26 Sergio Durigan Junior <sergiodj@redhat.com>

Implement `info core mappings'.
* gdb.texinfo: Add documentation for `info core mappings'.

2011-10-26 Sergio Durigan Junior <sergiodj@redhat.com>

Implement `info core mappings'.
* gdb.base/corefile.exp: Add test for `info core mappings'.

diff --git a/gdb/NEWS b/gdb/NEWS
index 5cdb63e..6f8feaa 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@

*** Changes since GDB 7.3.1

+* GDB has a new `info core mappings' command. It displays the memory
+ regions in a corefile, similar to `info pro mappings' command.
+
* GDB has two new commands: "set remote hardware-watchpoint-length-limit"
and "show remote hardware-watchpoint-length-limit". These allows to
set or show the maximum length limit (in bytes) of a remote
diff --git a/gdb/corefile.c b/gdb/corefile.c
index ce3b755..af5a065 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -24,17 +24,23 @@
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
+#include <ctype.h>
#include "inferior.h"
#include "symtab.h"
+#include "gdbarch.h"
+#include "arch-utils.h"
#include "command.h"
#include "gdbcmd.h"
#include "bfd.h"
+#include "elf-bfd.h"
+#include "elf/internal.h"
#include "target.h"
#include "gdbcore.h"
#include "dis-asm.h"
#include "gdb_stat.h"
#include "completer.h"
#include "exceptions.h"
+#include "objfiles.h"

/* Local function declarations. */

@@ -83,6 +89,186 @@ core_file_command (char *filename, int from_tty)
}
\f

+/* Helper function for `print_core_map'. It is used to iterate
+ over the corefile's sections and print proper information about
+ memory-mappings.
+
+ BFD is the bfd used to get the sections.
+ SECT is the current section being "visited".
+ OBJ is not used. */
+
+static void
+print_proc_map_iter (bfd *bfd, asection *sect, void *obj)
+{
+ /* We're interested in matching sections' names beginning with
+ `load', because they are the sections containing information
+ about the process' memory regions. */
+ static const char *proc_map_match = "load";
+ int proc_map_match_size = strlen (proc_map_match);
+ /* Flag to indicate whether we have found something. */
+ int found = 0;
+ /* The section's size. */
+ bfd_size_type secsize;
+ /* We have to know the bitness of this architecture. */
+ int bitness;
+ /* We'll use these later. They are basically used for iterating
+ over every objfile in the system so that we can find needed
+ information about the memory region being examinated. */
+ struct obj_section *s = NULL;
+ struct objfile *objfile = NULL;
+ /* Fields to be printed for the proc map. */
+ unsigned long start = 0, end = 0;
+ unsigned int size = 0;
+ char *filename = NULL;
+
+ if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
+ /* This section is not useful. */
+ return;
+
+ bitness = gdbarch_addr_bit (gdbarch_from_bfd (bfd));
+
+ /* Unfortunately, some sections in the corefile don't have any
+ content inside. This is bad because we need to print, among
+ other things, its final address in the memory (which is
+ impossible to know if we don't have a size). That's why we
+ first need to check if the section's got anything inside it. */
+ secsize = bfd_section_size (bfd, sect);
+
+ if (secsize == 0)
+ {
+ /* Ok, the section is empty. In this case, we must look inside
+ ELF's Program Header, because (at least) there we have
+ information about the section's size. That's what we're doing
+ here. */
+ Elf_Internal_Phdr *p = elf_tdata (bfd)->phdr;
+ if (p != NULL)
+ {
+ int i;
+ unsigned int n = elf_elfheader (bfd)->e_phnum;
+ for (i = 0; i < n; i++, p++)
+ /* For each entry in the Program Header, we have to
+ check if the section's initial address is equal to
+ the entry's virtual address. If it is, then we
+ have just found the section's entry in the Program
+ Header, and can use the entry's information to
+ complete missing data from the section. */
+ if (sect->vma == p->p_vaddr)
+ {
+ found = 1;
+ break;
+ }
+ if (found)
+ secsize = p->p_memsz;
+ }
+ }
+
+ size = secsize;
+ start = sect->vma;
+ end = (unsigned long) (sect->vma + size);
+
+ /* Now begins a new part of the work. We still don't have complete
+ information about the memory region. For example, we still need
+ to know the filename which is represented by the region. Such
+ info can be gathered from the objfile's data structure, and for
+ that we must iterate over all the objsections and check if the
+ objsection's initial address is inside the section we have at hand.
+ If it is, then we can use this specific objsection to obtain the
+ missing data. */
+ found = 0;
+ ALL_OBJSECTIONS (objfile, s)
+ if (obj_section_addr (s) >= start
+ && obj_section_addr (s) <= end)
+ {
+ found = 1;
+ break;
+ }
+
+ if (found)
+ filename = s->objfile->name;
+
+ if (bitness == 32)
+ printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
+ start,
+ end,
+ (int) size,
+ filename ? filename : "");
+ else
+ printf_filtered (" %#18lx %#18lx %#10x %7s\n",
+ start,
+ end,
+ (int) size,
+ filename ? filename : "");
+}
+
+/* Implements the `info proc map' command when the user has provided
+ a corefile. */
+
+static void
+print_core_map (void)
+{
+ const char *exe;
+ int bitness;
+
+ gdb_assert (core_bfd != NULL);
+
+ bitness = gdbarch_addr_bit (gdbarch_from_bfd (core_bfd));
+
+ /* Getting the executable name. */
+ exe = bfd_core_file_failing_command (core_bfd);
+
+ printf_filtered (_("exe = '%s'\n"), exe);
+ printf_filtered (_("Mapped address spaces:\n\n"));
+ if (bitness == 32)
+ printf_filtered ("\t%10s %10s %10s %7s\n",
+ "Start Addr",
+ " End Addr",
+ " Size", "objfile");
+ else
+ printf_filtered (" %18s %18s %10s %7s\n",
+ "Start Addr",
+ " End Addr",
+ " Size", "objfile");
+
+ bfd_map_over_sections (core_bfd,
+ print_proc_map_iter,
+ NULL);
+}
+
+/* Implement the `info core' command. */
+
+static void
+info_core_cmd (char *args, int from_tty)
+{
+ char **argv = NULL;
+ int mappings_f = 1;
+ int all = 0;
+
+ if (!core_bfd)
+ error (_("You are not using a corefile at the moment."));
+
+ if (args)
+ {
+ /* Break up 'args' into an argv array. */
+ argv = gdb_buildargv (args);
+ make_cleanup_freeargv (argv);
+ }
+ while (argv != NULL && *argv != NULL)
+ {
+ if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
+ {
+ mappings_f = 1;
+ }
+ else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
+ {
+ all = 1;
+ }
+ argv++;
+ }
+
+ if (mappings_f || all)
+ print_core_map ();
+}
+
/* If there are two or more functions that wish to hook into
exec_file_command, this function will call all of the hook
functions. */
@@ -450,6 +636,11 @@ _initialize_core (void)
{
struct cmd_list_element *c;

+ add_info ("core", info_core_cmd, _("\
+Show information about a corefile.\n\
+Specify any of the following keywords for detailed info:\n\
+ mappings -- list of mapped memory regions."));
+
c = add_cmd ("core-file", class_files, core_file_command, _("\
Use FILE as core dump for examining memory and registers.\n\
No arg means have no core file. This command has been superseded by the\n\
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b451a6a..92e06f3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17655,6 +17655,13 @@ value; etc. For more information, see the @samp{proc} man page
Show all the information about the process described under all of the
above @code{info proc} subcommands.

+@kindex info core
+@cindex core dump file
+@item info core
+@item info core mappings
+@cindex memory address space mappings
+Report the memory address space ranges accessible in the core file.
+
@ignore
@comment These sub-options of 'info proc' were not included when
@comment procfs.c was re-written. Keep their descriptions around
diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
index 5b0cdf1..190281c 100644
--- a/gdb/testsuite/gdb.base/corefile.exp
+++ b/gdb/testsuite/gdb.base/corefile.exp
@@ -171,6 +171,13 @@ gdb_test_multiple "x/8bd buf2" "$test" {
}
}

+# Test the `info core mapping' command.
+set ws "\[ \t\]+"
+set test "test info core mapping"
+gdb_test "info core mapping" \
+ ".*Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}.*" \
+ $test
+
# test reinit_frame_cache

gdb_load ${binfile}