* RFC: implement 'info proc mappings' for core files
@ 2012-11-02 18:42 Tom Tromey
2012-11-03 3:45 ` Sergio Durigan Junior
[not found] ` <m3vcdnjqn5.fsf__5583.70666481114$1351914377$gmane$org@redhat.com>
0 siblings, 2 replies; 9+ messages in thread
From: Tom Tromey @ 2012-11-02 18:42 UTC (permalink / raw)
To: gdb-patches; +Cc: Binutils Development
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
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: RFC: implement 'info proc mappings' for core files
2012-11-02 18:42 RFC: implement 'info proc mappings' for core files Tom Tromey
@ 2012-11-03 3:45 ` Sergio Durigan Junior
[not found] ` <m3vcdnjqn5.fsf__5583.70666481114$1351914377$gmane$org@redhat.com>
1 sibling, 0 replies; 9+ messages in thread
From: Sergio Durigan Junior @ 2012-11-03 3:45 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches, Binutils Development
On Friday, November 02 2012, Tom Tromey wrote:
> 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".
Wow, I totally forgot about this feature. In fact, I thought Ulrich's
patch had already implemented it! If I knew it hadn't been implemented,
I would have sent my patches again :-). Shame on me.
Anyway, thanks for implementing this!
--
Sergio
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: RFC: implement 'info proc mappings' for core files
[not found] ` <m3vcdnjqn5.fsf__5583.70666481114$1351914377$gmane$org@redhat.com>
@ 2012-11-05 14:11 ` Tom Tromey
[not found] ` <871ug8nnqw.fsf__31325.5512774505$1352124723$gmane$org@fleche.redhat.com>
1 sibling, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2012-11-05 14:11 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches, Binutils Development
>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
Sergio> Wow, I totally forgot about this feature. In fact, I thought Ulrich's
Sergio> patch had already implemented it! If I knew it hadn't been implemented,
Sergio> I would have sent my patches again :-). Shame on me.
I totally forgot there were patches in this area, too :(
I will dig them up and look at them.
Tom
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: RFC: implement 'info proc mappings' for core files
[not found] ` <871ug8nnqw.fsf__31325.5512774505$1352124723$gmane$org@fleche.redhat.com>
@ 2012-11-05 21:48 ` Tom Tromey
2012-11-20 20:05 ` Tom Tromey
0 siblings, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2012-11-05 21:48 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
Sergio> Wow, I totally forgot about this feature. In fact, I thought Ulrich's
Sergio> patch had already implemented it! If I knew it hadn't been implemented,
Sergio> I would have sent my patches again :-). Shame on me.
Tom> I totally forgot there were patches in this area, too :(
Tom> I will dig them up and look at them.
Well, ouch. Here are the threads I found
http://sourceware.org/ml/gdb-patches/2008-12/msg00322.html
http://sourceware.org/ml/gdb-patches/2011-11/msg00101.html
http://sourceware.org/ml/gdb-patches/2011-12/msg00018.html
If you look through the monthly archives there are some detached
sub-threads as well.
I found it pretty hard to find the conclusion. IIUC what actually went
in was a patch to have gdbserver read the remote /proc entries and serve
them up verbatim, for parsing locally.
For those opposed to "info proc" working on core files, if you are still
opposed, let me know. I guess I can resurrect Sergio's "info core"
command.
Tom
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: RFC: implement 'info proc mappings' for core files
2012-11-05 21:48 ` Tom Tromey
@ 2012-11-20 20:05 ` Tom Tromey
2012-11-20 20:16 ` Eli Zaretskii
2012-12-03 9:29 ` Jan Kratochvil
0 siblings, 2 replies; 9+ messages in thread
From: Tom Tromey @ 2012-11-20 20:05 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Tom> For those opposed to "info proc" working on core files, if you are still
Tom> opposed, let me know. I guess I can resurrect Sergio's "info core"
Tom> command.
Here's a version of the patch that just updates the documentation to
follow the code.
The reason I think supporting a subset of "info proc" for core files is
a reasonable thing to do is that we're basically viewing a snapshot of
the relevant parts of /proc as written out when the process died.
This needs a doc review.
Tom
* elf.c (elfcore_grok_note) <NT_FILE>: New case.
* NEWS: Mention "info proc" and core files.
* 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.
* gdb.texinfo (SVR4 Process Information): Mention core files.
---
bfd/elf.c | 4 +
gdb/NEWS | 2 +
gdb/corelow.c | 12 ++
gdb/doc/gdb.texinfo | 18 ++-
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 ++
12 files changed, 400 insertions(+), 19 deletions(-)
diff --git a/bfd/elf.c b/bfd/elf.c
index b8bb6d3..980a651 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/NEWS b/gdb/NEWS
index 5e3f54d..776d62c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -18,6 +18,8 @@
* The 'ptype' and 'whatis' commands now accept an argument to control
type formatting.
+* 'info proc' now works on some core files.
+
* Python scripting
** Vectors can be created with gdb.Type.vector.
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/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c953d81..af70025 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18599,13 +18599,17 @@ modern FreeBSD systems.
Many versions of SVR4 and compatible systems provide a facility called
@samp{/proc} that can be used to examine the image of a running
-process using file-system subroutines. If @value{GDBN} is configured
-for an operating system with this facility, the command @code{info
-proc} is available to report information about the process running
-your program, or about any process running on your system. @code{info
-proc} works only on SVR4 systems that include the @code{procfs} code.
-This includes, as of this writing, @sc{gnu}/Linux, OSF/1 (Digital
-Unix), Solaris, Irix, and Unixware, but not HP-UX, for example.
+process using file-system subroutines.
+
+If @value{GDBN} is configured for an operating system with this
+facility, the command @code{info proc} is available to report
+information about the process running your program, or about any
+process running on your system. This includes, as of this writing,
+@sc{gnu}/Linux, OSF/1 (Digital Unix), Solaris, Irix, and Unixware, but
+not HP-UX, for example.
+
+This command may also work on core files that were created on a system
+that has the @samp{/proc} facility.
@table @code
@kindex info proc
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 09576b1..d585813 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() */
};
@@ -754,6 +756,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);
@@ -872,6 +875,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,
@@ -4274,6 +4283,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 df09553..c52f83b 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1200,6 +1200,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 4b11f92..a07bad7 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 7a08e31..85862ec 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 dbeed36..f0de785 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 5015e51..ebd8085 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 7907ee1..a832ef8 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
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: RFC: implement 'info proc mappings' for core files
2012-11-20 20:05 ` Tom Tromey
@ 2012-11-20 20:16 ` Eli Zaretskii
2012-12-03 9:29 ` Jan Kratochvil
1 sibling, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2012-11-20 20:16 UTC (permalink / raw)
To: Tom Tromey; +Cc: sergiodj, gdb-patches
> From: Tom Tromey <tromey@redhat.com>
> Cc: gdb-patches@sourceware.org
> Date: Tue, 20 Nov 2012 13:05:33 -0700
>
> Here's a version of the patch that just updates the documentation to
> follow the code.
>
> The reason I think supporting a subset of "info proc" for core files is
> a reasonable thing to do is that we're basically viewing a snapshot of
> the relevant parts of /proc as written out when the process died.
>
> This needs a doc review.
The documentation parts are OK. Thanks.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: RFC: implement 'info proc mappings' for core files
2012-11-20 20:05 ` Tom Tromey
2012-11-20 20:16 ` Eli Zaretskii
@ 2012-12-03 9:29 ` Jan Kratochvil
2012-12-03 17:26 ` Tom Tromey
1 sibling, 1 reply; 9+ messages in thread
From: Jan Kratochvil @ 2012-12-03 9:29 UTC (permalink / raw)
To: Tom Tromey; +Cc: Sergio Durigan Junior, gdb-patches
On Tue, 20 Nov 2012 21:05:33 +0100, Tom Tromey wrote:
> 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 ();
> +
It was not much clear to me first:
/* As this is core file target here we call core_info_proc from gdbarch, not
info_proc. Despite we are target_info_proc implementation. */
> + 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)
> --- 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
> +
Here maybe a comment
# There exists only target_info_proc but there are two gdbarch methods for it.
> # Iterate over all objfiles in the order that makes the most sense
> # for the architecture to make global symbol searches.
> #
[...]
> --- 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"));
Here you probably meant gdbarch_addr_bit == 64.
But there was a discussion with pending patch GDB cannot be compiled without
"long long" anyway resulting in:
[patch] Require long long for GDB [Re: [patch] Compilation regression on older gcc + 32-bit host]
Message-ID: <20120531154019.GA16401@host2.jankratochvil.net>
http://sourceware.org/ml/gdb-patches/2012-05/msg01094.html
I should check in that patch but it had no more comments.
So 'sizeof (ULONGEST) < 8' can never happen.
> +
> + 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"));
[...]
> +typedef int (*linux_find_memory_region_ftype) (ULONGEST vaddr, ULONGEST size,
*_ftype named typedefs in GDB are without the pointer.
> + 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;
[...]
> +/* A callback for linux_find_memory_regions_full that updates the
> + mappings data for linux_make_mappings_corefile_notes. */
> +
And here could be then
static linux_find_memory_region_ftype linux_make_mappings_callback;
To (also) see in editor all the instances of that *_ftype.
> +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)
> +{
[...]
Thanks,
Jan
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: RFC: implement 'info proc mappings' for core files
2012-12-03 9:29 ` Jan Kratochvil
@ 2012-12-03 17:26 ` Tom Tromey
2012-12-14 15:17 ` Tom Tromey
0 siblings, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2012-12-03 17:26 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Sergio Durigan Junior, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> Here you probably meant gdbarch_addr_bit == 64.
Oops. Thanks.
Jan> But there was a discussion with pending patch GDB cannot be
Jan> compiled without "long long" anyway resulting in:
Jan> [patch] Require long long for GDB [Re: [patch] Compilation
Jan> regression on older gcc + 32-bit host]
Jan> Message-ID: <20120531154019.GA16401@host2.jankratochvil.net>
Jan> http://sourceware.org/ml/gdb-patches/2012-05/msg01094.html
Jan> I should check in that patch but it had no more comments.
Jan> So 'sizeof (ULONGEST) < 8' can never happen.
I replaced it with a static assert.
I think this version addresses all your comments.
Tom
* elf.c (elfcore_grok_note) <NT_FILE>: New case.
* NEWS: Mention "info proc" and core files.
* 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.
* gdb.texinfo (SVR4 Process Information): Mention core files.
diff --git a/bfd/elf.c b/bfd/elf.c
index a936636..538829b 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -8625,6 +8625,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/NEWS b/gdb/NEWS
index 3b09e5f..cc4cc83 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -18,6 +18,8 @@
* The 'ptype' and 'whatis' commands now accept an argument to control
type formatting.
+* 'info proc' now works on some core files.
+
* Python scripting
** Vectors can be created with gdb.Type.vector.
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 99611ba..589f231 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -927,6 +927,19 @@ 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 ();
+
+ /* Since this is the core file target, call the 'core_info_proc'
+ method on gdbarch, not 'info_proc'. */
+ 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 +966,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/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9ffdb77..49367b0 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18649,13 +18649,17 @@ modern FreeBSD systems.
Many versions of SVR4 and compatible systems provide a facility called
@samp{/proc} that can be used to examine the image of a running
-process using file-system subroutines. If @value{GDBN} is configured
-for an operating system with this facility, the command @code{info
-proc} is available to report information about the process running
-your program, or about any process running on your system. @code{info
-proc} works only on SVR4 systems that include the @code{procfs} code.
-This includes, as of this writing, @sc{gnu}/Linux, OSF/1 (Digital
-Unix), Solaris, Irix, and Unixware, but not HP-UX, for example.
+process using file-system subroutines.
+
+If @value{GDBN} is configured for an operating system with this
+facility, the command @code{info proc} is available to report
+information about the process running your program, or about any
+process running on your system. This includes, as of this writing,
+@sc{gnu}/Linux, OSF/1 (Digital Unix), Solaris, Irix, and Unixware, but
+not HP-UX, for example.
+
+This command may also work on core files that were created on a system
+that has the @samp{/proc} facility.
@table @code
@kindex info proc
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 6ae453e..32fe26b 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -283,6 +283,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;
};
@@ -451,6 +452,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() */
};
@@ -750,6 +752,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);
@@ -868,6 +871,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,
@@ -4250,6 +4259,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 3d9dc79..572aca3 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1193,6 +1193,16 @@ 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. Noe that there
+ are two "info_proc"-like methods on gdbarch -- one for core files,
+ one for live targets. */
+
+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 81a70b0..123fc1a 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -940,6 +940,11 @@ 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. Noe that there
+# are two "info_proc"-like methods on gdbarch -- one for core files,
+# one for live targets.
+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 db9b9b5..4e38725 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2883,10 +2883,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 dbeed36..d5ad6e3 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);
+ /* We assume this for reading 64-bit core files. */
+ gdb_static_assert (sizeof (ULONGEST) >= 8);
+
+ section = bfd_get_section_by_name (core_bfd, ".note.linuxcore.file");
+ if (section == NULL)
+ {
+ warning (_("unable to find mappings in core file"));
+ return;
+ }
+
+ 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,112 @@ 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;
+};
+
+static linux_find_memory_region_ftype linux_make_mappings_callback;
+
+/* 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 +1215,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 +1245,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 5015e51..ebd8085 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 7907ee1..a832ef8 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"
+ }
+}
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: RFC: implement 'info proc mappings' for core files
2012-12-03 17:26 ` Tom Tromey
@ 2012-12-14 15:17 ` Tom Tromey
0 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2012-12-14 15:17 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Sergio Durigan Junior, gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Tom> I replaced it with a static assert.
Tom> I think this version addresses all your comments.
I'm checking this in now.
Tom
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2012-12-14 15:17 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-02 18:42 RFC: implement 'info proc mappings' for core files Tom Tromey
2012-11-03 3:45 ` Sergio Durigan Junior
[not found] ` <m3vcdnjqn5.fsf__5583.70666481114$1351914377$gmane$org@redhat.com>
2012-11-05 14:11 ` Tom Tromey
[not found] ` <871ug8nnqw.fsf__31325.5512774505$1352124723$gmane$org@fleche.redhat.com>
2012-11-05 21:48 ` Tom Tromey
2012-11-20 20:05 ` Tom Tromey
2012-11-20 20:16 ` Eli Zaretskii
2012-12-03 9:29 ` Jan Kratochvil
2012-12-03 17:26 ` Tom Tromey
2012-12-14 15:17 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox