RFC: implement 'info proc mappings' for core files

Tom Tromey tromey@redhat.com
Fri Nov 2 18:42:00 GMT 2012


I'm CCing the binutils list because this patch, like my previous one,
needs a small addition to elfcore_grok_note, this time to make the
NT_FILE note's data available to gdb.

This patch implements "info proc mappings" and "info proc exe" for core
files.  It also changes gdb to write the NT_FILE note from "gcore".

I think most of the implementation is pretty straightforward.  I added a
new arch hook so that the core file code could get this information, and
rearranged info_proc_cmd_1 a little (and target_info_proc) to handle
this new scenario.  For writing the note, I refactored
linux_find_memory_regions to pass all the needed information to the
callback.

Built and regtested on x86-64 Fedora 16.  New test case included.  I
also tried it manually on a core file containing an NT_FILE note made by
a recent Linux kernel.

On the binutils side, I applied the elf.c patch, rebuilt, and ran the
gas, ld, and binutils test suites.

Tom

>From 135963cd4815a7b70347dd6e64d5c91933cda64f Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Tue, 30 Oct 2012 09:38:17 -0600
Subject: [PATCH 4/4] implement info proc mappings/exe for core

	* elf.c (elfcore_grok_note) <NT_FILE>: New case.

	* corelow.c (core_info_proc): New function.
	(init_core_ops): Set to_info_proc.
	* gdbarch.c, gdbarch.h: Rebuild.
	* gdbarch.sh (core_info_proc): New method.
	* infcmd.c (info_proc_cmd_1): Invoke target_info_proc first.
	* linux-tdep.c (linux_core_info_proc_mappings)
	(linux_core_info_proc): New functions.
	(linux_find_memory_region_ftype): New typedef.
	(linux_find_memory_regions_full): New function, from
	linux_find_memory_regions.
	(struct linux_find_memory_regions_data): New.
	(linux_find_memory_regions_thunk): New function.
	(linux_find_memory_regions): Rewrite.
	(struct linux_make_mappings_data): New.
	(linux_make_mappings_callback)
	(linux_make_mappings_corefile_notes): New functions.
	(linux_make_corefile_notes): Call linux_make_mappings_corefile_notes.
	(linux_init_abi): Call set_gdbarch_core_info_proc.
	* target.c (target_info_proc): Return 'int'.
	* target.h (target_info_proc): Update.

	* gdb.base/info-proc.exp: Add core file tests.
---
 bfd/elf.c                            |    4 +
 gdb/corelow.c                        |   12 ++
 gdb/gdbarch.c                        |   33 ++++
 gdb/gdbarch.h                        |    8 +
 gdb/gdbarch.sh                       |    3 +
 gdb/infcmd.c                         |   11 +-
 gdb/linux-tdep.c                     |  301 +++++++++++++++++++++++++++++++++-
 gdb/target.c                         |    6 +-
 gdb/target.h                         |    7 +-
 gdb/testsuite/gdb.base/info-proc.exp |   14 ++
 10 files changed, 387 insertions(+), 12 deletions(-)

diff --git a/bfd/elf.c b/bfd/elf.c
index 4465f48..7d5ee37 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -8605,6 +8605,10 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
 	return TRUE;
       }
 
+    case NT_FILE:
+      return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.file",
+					      note);
+
     case NT_SIGINFO:
       return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo",
 					      note);
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 99611ba..1645858 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -927,6 +927,17 @@ core_has_registers (struct target_ops *ops)
   return (core_bfd != NULL);
 }
 
+/* Implement the to_info_proc method.  */
+
+static void
+core_info_proc (struct target_ops *ops, char *args, enum info_proc_what request)
+{
+  struct gdbarch *gdbarch = get_current_arch ();
+
+  if (gdbarch_core_info_proc_p (gdbarch))
+    gdbarch_core_info_proc (gdbarch, args, request);
+}
+
 /* Fill in core_ops with its defined operations and properties.  */
 
 static void
@@ -953,6 +964,7 @@ init_core_ops (void)
   core_ops.to_has_memory = core_has_memory;
   core_ops.to_has_stack = core_has_stack;
   core_ops.to_has_registers = core_has_registers;
+  core_ops.to_info_proc = core_info_proc;
   core_ops.to_magic = OPS_MAGIC;
 
   if (core_target)
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 6bc57af..da37eff 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -284,6 +284,7 @@ struct gdbarch
   int has_dos_based_file_system;
   gdbarch_gen_return_address_ftype *gen_return_address;
   gdbarch_info_proc_ftype *info_proc;
+  gdbarch_core_info_proc_ftype *core_info_proc;
   gdbarch_iterate_over_objfiles_in_search_order_ftype *iterate_over_objfiles_in_search_order;
 };
 
@@ -453,6 +454,7 @@ struct gdbarch startup_gdbarch =
   0,  /* has_dos_based_file_system */
   default_gen_return_address,  /* gen_return_address */
   0,  /* info_proc */
+  0,  /* core_info_proc */
   default_iterate_over_objfiles_in_search_order,  /* iterate_over_objfiles_in_search_order */
   /* startup_gdbarch() */
 };
@@ -755,6 +757,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of has_dos_based_file_system, invalid_p == 0 */
   /* Skip verify of gen_return_address, invalid_p == 0 */
   /* Skip verify of info_proc, has predicate.  */
+  /* Skip verify of core_info_proc, has predicate.  */
   /* Skip verify of iterate_over_objfiles_in_search_order, invalid_p == 0 */
   buf = ui_file_xstrdup (log, &length);
   make_cleanup (xfree, buf);
@@ -873,6 +876,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: convert_register_p = <%s>\n",
                       host_address_to_string (gdbarch->convert_register_p));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_core_info_proc_p() = %d\n",
+                      gdbarch_core_info_proc_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: core_info_proc = <%s>\n",
+                      host_address_to_string (gdbarch->core_info_proc));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_core_pid_to_str_p() = %d\n",
                       gdbarch_core_pid_to_str_p (gdbarch));
   fprintf_unfiltered (file,
@@ -4275,6 +4284,30 @@ set_gdbarch_info_proc (struct gdbarch *gdbarch,
   gdbarch->info_proc = info_proc;
 }
 
+int
+gdbarch_core_info_proc_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->core_info_proc != NULL;
+}
+
+void
+gdbarch_core_info_proc (struct gdbarch *gdbarch, char *args, enum info_proc_what what)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->core_info_proc != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_core_info_proc called\n");
+  gdbarch->core_info_proc (gdbarch, args, what);
+}
+
+void
+set_gdbarch_core_info_proc (struct gdbarch *gdbarch,
+                            gdbarch_core_info_proc_ftype core_info_proc)
+{
+  gdbarch->core_info_proc = core_info_proc;
+}
+
 void
 gdbarch_iterate_over_objfiles_in_search_order (struct gdbarch *gdbarch, iterate_over_objfiles_in_search_order_cb_ftype *cb, void *cb_data, struct objfile *current_objfile)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 696bf14..a887acf 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1192,6 +1192,14 @@ typedef void (gdbarch_info_proc_ftype) (struct gdbarch *gdbarch, char *args, enu
 extern void gdbarch_info_proc (struct gdbarch *gdbarch, char *args, enum info_proc_what what);
 extern void set_gdbarch_info_proc (struct gdbarch *gdbarch, gdbarch_info_proc_ftype *info_proc);
 
+/* Implement the "info proc" command for core files. */
+
+extern int gdbarch_core_info_proc_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_core_info_proc_ftype) (struct gdbarch *gdbarch, char *args, enum info_proc_what what);
+extern void gdbarch_core_info_proc (struct gdbarch *gdbarch, char *args, enum info_proc_what what);
+extern void set_gdbarch_core_info_proc (struct gdbarch *gdbarch, gdbarch_core_info_proc_ftype *core_info_proc);
+
 /* Iterate over all objfiles in the order that makes the most sense
    for the architecture to make global symbol searches.
   
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index e3e6329..be18e3b 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -943,6 +943,9 @@ m:void:gen_return_address:struct agent_expr *ax, struct axs_value *value, CORE_A
 # Implement the "info proc" command.
 M:void:info_proc:char *args, enum info_proc_what what:args, what
 
+# Implement the "info proc" command for core files.
+M:void:core_info_proc:char *args, enum info_proc_what what:args, what
+
 # Iterate over all objfiles in the order that makes the most sense
 # for the architecture to make global symbol searches.
 #
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index fd035df..6e32bfc 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2865,10 +2865,13 @@ info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 {
   struct gdbarch *gdbarch = get_current_arch ();
 
-  if (gdbarch_info_proc_p (gdbarch))
-    gdbarch_info_proc (gdbarch, args, what);
-  else
-    target_info_proc (args, what);
+  if (!target_info_proc (args, what))
+    {
+      if (gdbarch_info_proc_p (gdbarch))
+	gdbarch_info_proc (gdbarch, args, what);
+      else
+	error (_("Not supported on this target."));
+    }
 }
 
 /* Implement `info proc' when given without any futher parameters.  */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index f02d510..5e110f1 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -30,6 +30,8 @@
 #include "elf-bfd.h"            /* for elfcore_write_* */
 #include "inferior.h"
 #include "cli/cli-utils.h"
+#include "arch-utils.h"
+#include "gdb_obstack.h"
 
 #include <ctype.h>
 
@@ -533,11 +535,149 @@ linux_info_proc (struct gdbarch *gdbarch, char *args,
     }
 }
 
+/* Implement "info proc mappings" for a corefile.  */
+
+static void
+linux_core_info_proc_mappings (struct gdbarch *gdbarch, char *args)
+{
+  asection *section;
+  ULONGEST count, page_size;
+  unsigned char *descdata, *filenames, *descend, *contents;
+  size_t note_size;
+  unsigned int addr_size_bits, addr_size;
+  struct cleanup *cleanup;
+  struct gdbarch *core_gdbarch = gdbarch_from_bfd (core_bfd);
+
+  section = bfd_get_section_by_name (core_bfd, ".note.linuxcore.file");
+  if (section == NULL)
+    {
+      warning (_("unable to find mappings in core file"));
+      return;
+    }
+
+  if (gdbarch_addr_bit (core_gdbarch) == 32 && sizeof (ULONGEST) < 8)
+    error (_("cannot decode 64-bit core note in 32-bit gdb"));
+
+  addr_size_bits = gdbarch_addr_bit (core_gdbarch);
+  addr_size = addr_size_bits / 8;
+  note_size = bfd_get_section_size (section);
+
+  if (note_size < 2 * addr_size)
+    error (_("malformed core note - too short for header"));
+
+  contents = xmalloc (note_size);
+  cleanup = make_cleanup (xfree, contents);
+  if (!bfd_get_section_contents (core_bfd, section, contents, 0, note_size))
+    error (_("could not get core note contents"));
+
+  descdata = contents;
+  descend = descdata + note_size;
+
+  if (descdata[note_size - 1] != '\0')
+    error (_("malformed note - does not end with \\0"));
+
+  count = bfd_get (addr_size_bits, core_bfd, descdata);
+  descdata += addr_size;
+
+  page_size = bfd_get (addr_size_bits, core_bfd, descdata);
+  descdata += addr_size;
+
+  if (note_size < 2 * addr_size + count * 3 * addr_size)
+    error (_("malformed note - too short for supplied file count"));
+
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (gdbarch_addr_bit (gdbarch) == 32)
+    {
+      printf_filtered ("\t%10s %10s %10s %10s %s\n",
+		       "Start Addr",
+		       "  End Addr",
+		       "      Size", "    Offset", "objfile");
+    }
+  else
+    {
+      printf_filtered ("  %18s %18s %10s %10s %s\n",
+		       "Start Addr",
+		       "  End Addr",
+		       "      Size", "    Offset", "objfile");
+    }
+
+  filenames = descdata + count * 3 * addr_size;
+  while (--count > 0)
+    {
+      ULONGEST start, end, file_ofs;
+
+      if (filenames == descend)
+	error (_("malformed note - filenames end too early"));
+
+      start = bfd_get (addr_size_bits, core_bfd, descdata);
+      descdata += addr_size;
+      end = bfd_get (addr_size_bits, core_bfd, descdata);
+      descdata += addr_size;
+      file_ofs = bfd_get (addr_size_bits, core_bfd, descdata);
+      descdata += addr_size;
+
+      file_ofs *= page_size;
+
+      if (gdbarch_addr_bit (gdbarch) == 32)
+	printf_filtered ("\t%10s %10s %10s %10s %s\n",
+			 paddress (gdbarch, start),
+			 paddress (gdbarch, end),
+			 hex_string (end - start),
+			 hex_string (file_ofs),
+			 filenames);
+      else
+	printf_filtered ("  %18s %18s %10s %10s %s\n",
+			 paddress (gdbarch, start),
+			 paddress (gdbarch, end),
+			 hex_string (end - start),
+			 hex_string (file_ofs),
+			 filenames);
+
+      filenames += 1 + strlen ((char *) filenames);
+    }
+
+  do_cleanups (cleanup);
+}
+
+/* Implement "info proc" for a corefile.  */
+
+static void
+linux_core_info_proc (struct gdbarch *gdbarch, char *args,
+		      enum info_proc_what what)
+{
+  int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
+  int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
+
+  if (exe_f)
+    {
+      const char *exe;
+
+      exe = bfd_core_file_failing_command (core_bfd);
+      if (exe != NULL)
+	printf_filtered ("exe = '%s'\n", exe);
+      else
+	warning (_("unable to find command name in core file"));
+    }
+
+  if (mappings_f)
+    linux_core_info_proc_mappings (gdbarch, args);
+
+  if (!exe_f && !mappings_f)
+    error (_("unable to handle request"));
+}
+
+typedef int (*linux_find_memory_region_ftype) (ULONGEST vaddr, ULONGEST size,
+					       ULONGEST offset, ULONGEST inode,
+					       int read, int write,
+					       int exec, int modified,
+					       const char *filename,
+					       void *data);
+
 /* List memory regions in the inferior for a corefile.  */
 
 static int
-linux_find_memory_regions (struct gdbarch *gdbarch,
-			   find_memory_region_ftype func, void *obfd)
+linux_find_memory_regions_full (struct gdbarch *gdbarch,
+				linux_find_memory_region_ftype func, void *obfd)
 {
   char filename[100];
   gdb_byte *data;
@@ -606,7 +746,8 @@ linux_find_memory_regions (struct gdbarch *gdbarch,
 	    modified = 1;
 
 	  /* Invoke the callback function to create the corefile segment.  */
-	  func (addr, endaddr - addr, read, write, exec, modified, obfd);
+	  func (addr, endaddr - addr, offset, inode,
+		read, write, exec, modified, filename, obfd);
 	}
 
       do_cleanups (cleanup);
@@ -616,6 +757,51 @@ linux_find_memory_regions (struct gdbarch *gdbarch,
   return 1;
 }
 
+/* A structure for passing information through
+   linux_find_memory_regions_full.  */
+
+struct linux_find_memory_regions_data
+{
+  /* The original callback.  */
+
+  find_memory_region_ftype func;
+
+  /* The original datum.  */
+
+  void *obfd;
+};
+
+/* A callback for linux_find_memory_regions that converts between the
+   "full"-style callback and find_memory_region_ftype.  */
+
+static int
+linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
+				 ULONGEST offset, ULONGEST inode,
+				 int read, int write, int exec, int modified,
+				 const char *filename, void *arg)
+{
+  struct linux_find_memory_regions_data *data = arg;
+
+  return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+}
+
+/* A variant of linux_find_memory_regions_full that is suitable as the
+   gdbarch find_memory_regions method.  */
+
+static int
+linux_find_memory_regions (struct gdbarch *gdbarch,
+			   find_memory_region_ftype func, void *obfd)
+{
+  struct linux_find_memory_regions_data data;
+
+  data.func = func;
+  data.obfd = obfd;
+
+  return linux_find_memory_regions_full (gdbarch,
+					 linux_find_memory_regions_thunk,
+					 &data);
+}
+
 /* Determine which signal stopped execution.  */
 
 static int
@@ -712,6 +898,110 @@ linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
   return note_data;
 }
 
+/* This is used to pass information from
+   linux_make_mappings_corefile_notes through
+   linux_find_memory_regions_full.  */
+
+struct linux_make_mappings_data
+{
+  /* Number of files mapped.  */
+  ULONGEST file_count;
+
+  /* The obstack for the main part of the data.  */
+  struct obstack *data_obstack;
+
+  /* The filename obstack.  */
+  struct obstack *filename_obstack;
+
+  /* The architecture's "long" type.  */
+  struct type *long_type;
+};
+
+/* A callback for linux_find_memory_regions_full that updates the
+   mappings data for linux_make_mappings_corefile_notes.  */
+
+static int
+linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size,
+			      ULONGEST offset, ULONGEST inode,
+			      int read, int write, int exec, int modified,
+			      const char *filename, void *data)
+{
+  struct linux_make_mappings_data *map_data = data;
+  gdb_byte buf[sizeof (ULONGEST)];
+
+  if (*filename == '\0' || inode == 0)
+    return 0;
+
+  ++map_data->file_count;
+
+  pack_long (buf, map_data->long_type, vaddr);
+  obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
+  pack_long (buf, map_data->long_type, vaddr + size);
+  obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
+  pack_long (buf, map_data->long_type, offset);
+  obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
+
+  obstack_grow_str0 (map_data->filename_obstack, filename);
+
+  return 0;
+}
+
+/* Write the file mapping data to the core file, if possible.  OBFD is
+   the output BFD.  NOTE_DATA is the current note data, and NOTE_SIZE
+   is a pointer to the note size.  Returns the new NOTE_DATA and
+   updates NOTE_SIZE.  */
+
+static char *
+linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
+				    char *note_data, int *note_size)
+{
+  struct cleanup *cleanup;
+  struct obstack data_obstack, filename_obstack;
+  struct linux_make_mappings_data mapping_data;
+  struct type *long_type
+    = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch), 0, "long");
+  gdb_byte buf[sizeof (ULONGEST)];
+
+  obstack_init (&data_obstack);
+  cleanup = make_cleanup_obstack_free (&data_obstack);
+  obstack_init (&filename_obstack);
+  make_cleanup_obstack_free (&filename_obstack);
+
+  mapping_data.file_count = 0;
+  mapping_data.data_obstack = &data_obstack;
+  mapping_data.filename_obstack = &filename_obstack;
+  mapping_data.long_type = long_type;
+
+  /* Reserve space for the count.  */
+  obstack_blank (&data_obstack, TYPE_LENGTH (long_type));
+  /* We always write the page size as 1 since we have no good way to
+     determine the correct value.  */
+  pack_long (buf, long_type, 1);
+  obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type));
+
+  linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback,
+				  &mapping_data);
+
+  if (mapping_data.file_count != 0)
+    {
+      /* Write the count to the obstack.  */
+      pack_long (obstack_base (&data_obstack), long_type,
+		 mapping_data.file_count);
+
+      /* Copy the filenames to the data obstack.  */
+      obstack_grow (&data_obstack, obstack_base (&filename_obstack),
+		    obstack_object_size (&filename_obstack));
+
+      note_data = elfcore_write_note (obfd, note_data, note_size,
+				      "CORE", NT_FILE,
+				      obstack_base (&data_obstack),
+				      obstack_object_size (&data_obstack));
+    }
+
+  do_cleanups (cleanup);
+  return note_data;
+}
+
 /* Records the thread's register state for the corefile note
    section.  */
 
@@ -923,6 +1213,10 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size,
   if (!note_data)
     return NULL;
 
+  /* File mappings.  */
+  note_data = linux_make_mappings_corefile_notes (gdbarch, obfd,
+						  note_data, note_size);
+
   make_cleanup (xfree, note_data);
   return note_data;
 }
@@ -949,6 +1243,7 @@ linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   set_gdbarch_core_pid_to_str (gdbarch, linux_core_pid_to_str);
   set_gdbarch_info_proc (gdbarch, linux_info_proc);
+  set_gdbarch_core_info_proc (gdbarch, linux_core_info_proc);
   set_gdbarch_find_memory_regions (gdbarch, linux_find_memory_regions);
   set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes_1);
   set_gdbarch_has_shared_address_space (gdbarch,
diff --git a/gdb/target.c b/gdb/target.c
index 62de336..e9dda7e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3144,7 +3144,7 @@ target_supports_non_stop (void)
 
 /* Implement the "info proc" command.  */
 
-void
+int
 target_info_proc (char *args, enum info_proc_what what)
 {
   struct target_ops *t;
@@ -3167,11 +3167,11 @@ target_info_proc (char *args, enum info_proc_what what)
 	    fprintf_unfiltered (gdb_stdlog,
 				"target_info_proc (\"%s\", %d)\n", args, what);
 
-	  return;
+	  return 1;
 	}
     }
 
-  error (_("Not supported on this target."));
+  return 0;
 }
 
 static int
diff --git a/gdb/target.h b/gdb/target.h
index 382dacb..0e420a3 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -976,9 +976,12 @@ extern void target_store_registers (struct regcache *regcache, int regs);
 
 struct address_space *target_thread_address_space (ptid_t);
 
-/* Implement the "info proc" command.  */
+/* Implement the "info proc" command.  This returns one if the request
+   was handled, and zero otherwise.  It can also throw an exception if
+   an error was encountered while attempting to handle the
+   request.  */
 
-void target_info_proc (char *, enum info_proc_what);
+int target_info_proc (char *, enum info_proc_what);
 
 /* Returns true if this target can debug multiple processes
    simultaneously.  */
diff --git a/gdb/testsuite/gdb.base/info-proc.exp b/gdb/testsuite/gdb.base/info-proc.exp
index 1cefb6d..0ac0b6e 100644
--- a/gdb/testsuite/gdb.base/info-proc.exp
+++ b/gdb/testsuite/gdb.base/info-proc.exp
@@ -68,3 +68,17 @@ gdb_test "info proc" "process ${decimal}.*" "info proc with process"
 gdb_test "info proc mapping" \
 	".*Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}${ws}${hex}.*" \
 	"info proc mapping"
+
+if {[istarget "*-*-linux*"]} {
+    set gcorefile [standard_output_file $testfile.gcore]
+    if {[gdb_gcore_cmd $gcorefile "save a core file"]} {
+	clean_restart $binfile
+
+	gdb_test "core $gcorefile" "Core was generated by.*" \
+	    "core [file tail $gcorefile]"
+
+	gdb_test "info proc mapping" \
+	    ".*Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}${ws}${hex}.*" \
+	    "info proc mapping with core file"
+    }
+}
-- 
1.7.7.6



More information about the Binutils mailing list