]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
2002-01-03 Michael Snyder <msnyder@redhat.com>
authorMichael Snyder <msnyder@vmware.com>
Wed, 9 Jan 2002 00:37:02 +0000 (00:37 +0000)
committerMichael Snyder <msnyder@vmware.com>
Wed, 9 Jan 2002 00:37:02 +0000 (00:37 +0000)
Implement a "generate-core-file" command in gdb, save target state.
* gcore.c: New file.  Implement new command 'generate-core-file'.
Save a corefile image of the current state of the inferior.
* linux-proc.c: Add linux-specific code for saving corefiles.
* target.h (struct target_ops): Add new target vectors for saving
corefiles; to_find_memory_regions and to_make_corefile_notes.
(target_find_memory_regions): New macro.
(target_make_corefile_notes): New macro.
* target.c (update_current_target): Inherit new target methods.
(dummy_find_memory_regions): New place-holder method.
(dummy_make_corefile_notes): New place-holder method.
(init_dummy_target): Initialize new dummy target vectors.
* exec.c (exec_set_find_memory_regions): New function.
Allow the exec_ops vector for memory regions to be taken over.
(exec_make_note_section): New function, target vector method.
* defs.h (exec_set_find_memory_regions): Export prototype.
* procfs.c (proc_find_memory_regions): New function, corefile method.
(procfs_make_note_section): New function, corefile method.
(init_procfs_ops): Set new target vector pointers.
(find_memory_regions_callback): New function.
(procfs_do_thread_registers): New function.
(procfs_corefile_thread_callback): New function.
* sol-thread.c (sol_find_memory_regions): New function.
(sol_make_note_section): New function.
(init_sol_thread_ops): Initialize new target vectors.
* inftarg.c (inftarg_set_find_memory_regions): New function.
Allow to_find_memory_regions vector to be taken over.
(inftarg_set_make_corefile_notes): New function.
Allow to_make_corefile_notes vector to be taken over.
* thread-db.c (thread_db_new_objfile): Don't activate thread-db
interface layer if not target_has_execution (may be a corefile).
* config/i386/linux.mh: Add gcore.o to NATDEPFILES.
* config/sparc/sun4sol2.mh: Ditto.
* config/alpha/alpha-linux.mh: Ditto.
* config/arm/linux.mh: Ditto.
* config/i386/x86-64linux.mh: Ditto.
* config/ia64/linux.mh: Ditto.
* config/m68k/linux.mh: Ditto.
* config/mips/linux.mh: Ditto.
* config/powerpc/linux.mh: Ditto.
* config/sparc/linux.mh: Ditto.

20 files changed:
gdb/ChangeLog
gdb/config/alpha/alpha-linux.mh
gdb/config/arm/linux.mh
gdb/config/i386/linux.mh
gdb/config/i386/x86-64linux.mh
gdb/config/ia64/linux.mh
gdb/config/m68k/linux.mh
gdb/config/mips/linux.mh
gdb/config/powerpc/linux.mh
gdb/config/sparc/linux.mh
gdb/config/sparc/sun4sol2.mh
gdb/defs.h
gdb/exec.c
gdb/gcore.c [new file with mode: 0644]
gdb/inftarg.c
gdb/linux-proc.c
gdb/procfs.c
gdb/sol-thread.c
gdb/target.c
gdb/target.h

index ae1bbae263e3c5e5732b599b84f36a20f911a48a..49eac086f711e571452ec7159746d8823545229f 100644 (file)
@@ -1,3 +1,47 @@
+2002-01-03  Michael Snyder  <msnyder@redhat.com>
+
+       Implement a "generate-core-file" command in gdb, save target state.
+       * gcore.c: New file.  Implement new command 'generate-core-file'.
+       Save a corefile image of the current state of the inferior.
+       * linux-proc.c: Add linux-specific code for saving corefiles.
+       * target.h (struct target_ops): Add new target vectors for saving
+       corefiles; to_find_memory_regions and to_make_corefile_notes.
+       (target_find_memory_regions): New macro.
+       (target_make_corefile_notes): New macro.
+       * target.c (update_current_target): Inherit new target methods.
+       (dummy_find_memory_regions): New place-holder method.
+       (dummy_make_corefile_notes): New place-holder method.
+       (init_dummy_target): Initialize new dummy target vectors.
+       * exec.c (exec_set_find_memory_regions): New function.
+       Allow the exec_ops vector for memory regions to be taken over.
+       (exec_make_note_section): New function, target vector method.
+       * defs.h (exec_set_find_memory_regions): Export prototype.
+       * procfs.c (proc_find_memory_regions): New function, corefile method.
+       (procfs_make_note_section): New function, corefile method.
+       (init_procfs_ops): Set new target vector pointers.
+       (find_memory_regions_callback): New function.
+       (procfs_do_thread_registers): New function.
+       (procfs_corefile_thread_callback): New function.
+       * sol-thread.c (sol_find_memory_regions): New function.
+       (sol_make_note_section): New function.
+       (init_sol_thread_ops): Initialize new target vectors.
+       * inftarg.c (inftarg_set_find_memory_regions): New function.
+       Allow to_find_memory_regions vector to be taken over.
+       (inftarg_set_make_corefile_notes): New function.
+       Allow to_make_corefile_notes vector to be taken over.
+       * thread-db.c (thread_db_new_objfile): Don't activate thread-db
+       interface layer if not target_has_execution (may be a corefile).
+       * config/i386/linux.mh: Add gcore.o to NATDEPFILES.
+       * config/sparc/sun4sol2.mh: Ditto.
+       * config/alpha/alpha-linux.mh: Ditto.
+       * config/arm/linux.mh: Ditto.
+       * config/i386/x86-64linux.mh: Ditto.
+       * config/ia64/linux.mh: Ditto.
+       * config/m68k/linux.mh: Ditto.
+       * config/mips/linux.mh: Ditto.
+       * config/powerpc/linux.mh: Ditto.
+       * config/sparc/linux.mh: Ditto.
+
 2002-01-07  Michael Snyder  <msnyder@redhat.com>
 
        * arm-linux-nat.c: Remove references to regcache.c internal data
index 0fe3c48dc354954abb8a2fa9c20cb86cfcc356b5..1aad9446c29d7d59af0f7b160e66e53e58803ed5 100644 (file)
@@ -3,7 +3,7 @@ XDEPFILES=
 XM_FILE= xm-alphalinux.h
 NAT_FILE= nm-linux.h
 NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o linux-proc.o \
-       fork-child.o proc-service.o thread-db.o lin-lwp.o
+       fork-child.o proc-service.o thread-db.o lin-lwp.o gcore.o
 
 LOADLIBES = -ldl -rdynamic
 
index 8b386fb17080e255c186e4f260959af0ba27deb7..8c9f530b98f007d8e4ef686bcb5515eefc5419b9 100644 (file)
@@ -5,7 +5,7 @@ XDEPFILES=
 
 NAT_FILE= nm-linux.h
 NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o      \
-       core-regset.o arm-linux-nat.o linux-proc.o              \
+       core-regset.o arm-linux-nat.o linux-proc.o gcore.o      \
        proc-service.o thread-db.o lin-lwp.o
 
 LOADLIBES= -ldl -rdynamic
index 50d24458229a6fef358257d65bcaefd64e5f4a6d..e3fb5ed9730d6b071203105b51a3b2b70cd44a91 100644 (file)
@@ -6,7 +6,7 @@ XDEPFILES=
 NAT_FILE= nm-linux.h
 NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o linux-proc.o \
        core-aout.o i386-nat.o i386-linux-nat.o i387-nat.o \
-       proc-service.o thread-db.o lin-lwp.o linux-proc.o 
+       proc-service.o thread-db.o lin-lwp.o linux-proc.o gcore.o
 
 # The dynamically loaded libthread_db needs access to symbols in the
 # gdb executable.
index f9f31fcdf0dd5bbdccb178f4ce906701710250c2..d6a8a70d9ddd13f5ec7e6dff92bd55f5b8c581bd 100644 (file)
@@ -6,6 +6,7 @@ XDEPFILES=
 NAT_FILE= nm-x86-64.h
 NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
        core-aout.o i386-nat.o x86-64-nat.o x86-64-linux-nat.o \
-       i387-nat.o proc-service.o thread-db.o lin-lwp.o linux-proc.o 
+       i387-nat.o proc-service.o thread-db.o lin-lwp.o \
+       linux-proc.o gcore.o 
 
 LOADLIBES = -ldl -rdynamic
index 48268d731e3921ce5acb054401109878a0848acc..5be42706f2203362c7ac01c279828e3b1e5b4a7f 100644 (file)
@@ -4,7 +4,7 @@ XM_FILE= xm-linux.h
 XDEPFILES=
 
 NAT_FILE= nm-linux.h
-NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
+NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o gcore.o \
        core-aout.o core-regset.o ia64-linux-nat.o linux-proc.o \
        proc-service.o thread-db.o lin-lwp.o
 
index aa5121b737bbc3e3a2db5d3cacb2ada9e00b85ee..e8ea7652244f5c9a9911e6d47f0d645ea46ef144 100644 (file)
@@ -5,7 +5,7 @@ XDEPFILES=
 
 NAT_FILE= nm-linux.h
 NATDEPFILES= infptrace.o inftarg.o fork-child.o \
-       corelow.o core-aout.o m68klinux-nat.o linux-proc.o \
+       corelow.o core-aout.o m68klinux-nat.o linux-proc.o gcore.o \
        proc-service.o thread-db.o lin-lwp.o 
 
 # The dynamically loaded libthread_db needs access to symbols in the
index 47ad1eec9d1ac4e0d0f41bcda52d8e08a7ad2e45..eb3ec149684edb66f176ffdf43e66ba6c5e6a981 100644 (file)
@@ -3,6 +3,6 @@ XDEPFILES=
 XM_FILE= xm-linux.h
 NAT_FILE= nm-linux.h
 NATDEPFILES= infptrace.o inftarg.o fork-child.o mips-linux-nat.o \
-       thread-db.o lin-lwp.o proc-service.o linux-proc.o
+       thread-db.o lin-lwp.o proc-service.o linux-proc.o gcore.o
 
 LOADLIBES = -ldl -rdynamic
index 7f04a48b3d2e398964b81304ae46647f5d37e306..e49f700912f1983dc404b9ae5a65aac0635e2aa7 100644 (file)
@@ -6,7 +6,8 @@ XM_CLIBS=
 
 NAT_FILE= nm-linux.h
 NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o linux-proc.o \
-core-regset.o ppc-linux-nat.o proc-service.o thread-db.o lin-lwp.o
+       core-regset.o ppc-linux-nat.o proc-service.o thread-db.o lin-lwp.o \
+       gcore.o
 
 LOADLIBES = -ldl -rdynamic
 
index e63b2e604e56c5f338175db2fbcdac8ca2182b5d..30a97a698ff289618710e6c8fa68f4432541fc5e 100644 (file)
@@ -5,7 +5,8 @@ XDEPFILES=
 
 NAT_FILE= nm-linux.h
 NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o sparc-nat.o \
-       proc-service.o thread-db.o lin-lwp.o sparc-linux-nat.o linux-proc.o
+       proc-service.o thread-db.o lin-lwp.o sparc-linux-nat.o \
+       linux-proc.o gcore.o 
 
 # The dynamically loaded libthread_db needs access to symbols in the
 # gdb executable.
index 8063e1698a4defac7278b18557d10ba58032387b..edcef48358c2ebf2a39c376862df3aec3661c37d 100644 (file)
@@ -6,7 +6,8 @@ XM_CLIBS= -lsocket -lnsl
 
 NAT_FILE= nm-sun4sol2.h
 NATDEPFILES= corelow.o core-sol2.o solib.o solib-svr4.o solib-legacy.o \
-       fork-child.o procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
+       fork-child.o procfs.o gcore.o \
+       proc-api.o proc-events.o proc-flags.o proc-why.o
 
 # /usr/include/v9 is needed only by core-sol2.c when including 
 # v9/sys/privregs.h, or rather the headers it in turn includes.
index 461ab314e4fe095a24622ca5e86926babbc8e895..9957aa19fc638775c48c0731ee4208e81a230da0 100644 (file)
@@ -1,7 +1,7 @@
 /* *INDENT-OFF* */ /* ATTR_FORMAT confuses indent, avoid running it for now */
 /* Basic, host-specific, and target-specific definitions for GDB.
    Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
-   1997, 1998, 1999, 2000, 2001
+   1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -775,6 +775,13 @@ extern void exec_set_section_offsets (bfd_signed_vma text_off,
                                      bfd_signed_vma data_off,
                                      bfd_signed_vma bss_off);
 
+/* Take over the 'find_mapped_memory' vector from exec.c. */
+extern void exec_set_find_memory_regions (int (*) (int (*) (CORE_ADDR, 
+                                                           unsigned long, 
+                                                           int, int, int, 
+                                                           void *),
+                                                  void *));
+
 /* From findvar.c */
 
 extern int read_relative_register_raw_bytes (int, char *);
index 6e4e85b4a1269d4a101c965231569a0fe41ddac5..404617e0116a118679a428ac928de22991539849 100644 (file)
@@ -1,6 +1,6 @@
 /* Work with executable files, for GDB. 
    Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001
+   1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -685,10 +685,24 @@ ignore (CORE_ADDR addr, char *contents)
   return 0;
 }
 
+/* Find mapped memory. */
+
+extern void
+exec_set_find_memory_regions (int (*func) (int (*) (CORE_ADDR, 
+                                                   unsigned long, 
+                                                   int, int, int, 
+                                                   void *),
+                                          void *))
+{
+  exec_ops.to_find_memory_regions = func;
+}
+
+static char *exec_make_note_section (bfd *, int *);
+
 /* Fill in the exec file target vector.  Very few entries need to be
    defined.  */
 
-void
+static void
 init_exec_ops (void)
 {
   exec_ops.to_shortname = "exec";
@@ -708,6 +722,7 @@ Specify the filename of the executable file.";
   exec_ops.to_clone_and_follow_inferior = find_default_clone_and_follow_inferior;
   exec_ops.to_stratum = file_stratum;
   exec_ops.to_has_memory = 1;
+  exec_ops.to_make_corefile_notes = exec_make_note_section;
   exec_ops.to_magic = OPS_MAGIC;
 }
 
@@ -752,3 +767,34 @@ file itself are wrong.  Each section must be changed separately.  The\n\
 
   add_target (&exec_ops);
 }
+
+static char *
+exec_make_note_section (bfd *obfd, int *note_size)
+{
+  struct cleanup *old_chain;
+  char fname[16] = {'\0'};
+  char psargs[80] = {'\0'};
+  char *note_data = NULL;
+
+  if (get_exec_file (0))
+    {
+      strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
+      strncpy (psargs, get_exec_file (0), 
+              sizeof (psargs));
+      if (get_inferior_args ())
+       {
+         strncat (psargs, " ", 
+                  sizeof (psargs) - strlen (psargs));
+         strncat (psargs, get_inferior_args (), 
+                  sizeof (psargs) - strlen (psargs));
+       }
+
+      note_data = (char *) elfcore_write_prpsinfo (obfd, 
+                                                  note_data, 
+                                                  note_size, 
+                                                  fname, 
+                                                  psargs);
+      make_cleanup (xfree, note_data);
+    }
+  return note_data;
+}
diff --git a/gdb/gcore.c b/gdb/gcore.c
new file mode 100644 (file)
index 0000000..48ed6a3
--- /dev/null
@@ -0,0 +1,493 @@
+/* Generate a core file for the inferior process.
+   Copyright 2001, 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "command.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "elf-bfd.h"
+#include <sys/procfs.h>
+#include "symfile.h"
+#include "objfiles.h"
+
+static char                  *default_gcore_target (void);
+static enum bfd_architecture  default_gcore_arch (void);
+static unsigned long          default_gcore_mach (void);
+static int                    gcore_memory_sections (bfd *);
+
+/* Function: gcore_command
+   Generate a core file from the inferior process.  */
+
+static void
+gcore_command (char *args, int from_tty)
+{
+  struct cleanup *old_chain;
+  char *corefilename, corefilename_buffer[40];
+  asection *note_sec;
+  bfd *obfd;
+  void *note_data = NULL;
+  int note_size = 0;
+
+  /* No use generating a corefile without a target process.  */
+  if (!(target_has_execution))
+    noprocess ();
+
+  if (args && *args)
+    corefilename = args;
+  else
+    {
+      /* Default corefile name is "core.PID".  */
+      sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_ptid));
+      corefilename = corefilename_buffer;
+    }
+
+  if (info_verbose)
+    fprintf_filtered (gdb_stdout, 
+                     "Opening corefile '%s' for output.\n", corefilename);
+
+  /* Open the output file. */
+  if (!(obfd = bfd_openw (corefilename, NULL /*default_gcore_target ()*/)))
+    {
+      error ("Failed to open '%s' for output.", corefilename);
+    }
+
+  /* Need a cleanup that will close the file (FIXME: delete it?). */
+  old_chain = make_cleanup_bfd_close (obfd);
+
+  bfd_set_format (obfd, bfd_core);
+  bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ());
+
+  /* An external target method must build the notes section. */
+  note_data = (char *) target_make_corefile_notes (obfd, &note_size);
+
+  /* Create the note section. */
+  if (note_data != NULL && note_size != 0)
+    {
+      if ((note_sec = bfd_make_section_anyway (obfd, "note0")) == NULL)
+       error ("Failed to create 'note' section for corefile: %s", 
+              bfd_errmsg (bfd_get_error ()));
+
+      bfd_set_section_vma (obfd, note_sec, 0);
+      bfd_set_section_flags (obfd, note_sec, 
+                            SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC);
+      bfd_set_section_alignment (obfd, note_sec, 0);
+      bfd_set_section_size (obfd, note_sec, note_size);
+    }
+
+  /* Now create the memory/load sections. */
+  if (gcore_memory_sections (obfd) == 0)
+    error ("gcore: failed to get corefile memory sections from target.");
+
+  /* Write out the contents of the note section. */
+  if (note_data != NULL && note_size != 0)
+    {
+      if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
+       {
+         warning ("writing note section (%s)", 
+                  bfd_errmsg (bfd_get_error ()));
+       }
+    }
+
+  /* Succeeded. */
+  fprintf_filtered (gdb_stdout, 
+                   "Saved corefile %s\n", corefilename);
+
+  /* Clean-ups will close the output file and free malloc memory. */
+  do_cleanups (old_chain);
+  return;
+}
+
+static unsigned long
+default_gcore_mach (void)
+{
+#ifdef TARGET_ARCHITECTURE
+  const struct bfd_arch_info * bfdarch = TARGET_ARCHITECTURE;
+
+  if (bfdarch != NULL)
+    return bfdarch->mach;
+#endif
+  if (exec_bfd == NULL)
+    error ("Can't find default bfd machine type (need execfile).");
+
+  return bfd_get_mach (exec_bfd);
+}
+
+static enum bfd_architecture
+default_gcore_arch (void)
+{
+#ifdef TARGET_ARCHITECTURE
+  const struct bfd_arch_info * bfdarch = TARGET_ARCHITECTURE;
+
+  if (bfdarch != NULL)
+    return bfdarch->arch;
+#endif
+  if (exec_bfd == NULL)
+    error ("Can't find bfd architecture for corefile (need execfile).");
+
+  return bfd_get_arch (exec_bfd);
+}
+
+static char *
+default_gcore_target (void)
+{
+  /* FIXME -- this may only work for ELF targets.  */
+  if (exec_bfd == NULL)
+    error ("Can't find default bfd target for corefile (need execfile).");
+
+  return bfd_get_target (exec_bfd);
+}
+
+/*
+ * Default method for stack segment (preemptable by target).
+ */
+
+static int (*override_derive_stack_segment) (bfd_vma *, bfd_vma *);
+
+extern void
+preempt_derive_stack_segment (int (*override_func) (bfd_vma *, bfd_vma *))
+{
+  override_derive_stack_segment = override_func;
+}
+
+/* Function: default_derive_stack_segment
+   Derive a reasonable stack segment by unwinding the target stack. 
+   
+   Returns 0 for failure, 1 for success.  */
+
+static int 
+default_derive_stack_segment (bfd_vma *bottom, bfd_vma *top)
+{
+  bfd_vma tmp_vma;
+  struct frame_info *fi, *tmp_fi;
+
+  if (bottom == NULL || top == NULL)
+    return 0;  /* Paranoia. */
+
+  if (!target_has_stack || !target_has_registers)
+    return 0;  /* Can't succeed without stack and registers. */
+
+  if ((fi = get_current_frame ()) == NULL)
+    return 0;  /* Can't succeed without current frame. */
+
+  /* Save frame pointer of TOS frame. */
+  *top = fi->frame;
+  /* If current stack pointer is more "inner", use that instead. */
+  if (INNER_THAN (read_sp (), *top))
+    *top = read_sp ();
+
+  /* Find prev-most frame. */
+  while ((tmp_fi = get_prev_frame (fi)) != NULL)
+    fi = tmp_fi;
+
+  /* Save frame pointer of prev-most frame. */
+  *bottom = fi->frame;
+
+  /* Now canonicalize their order, so that 'bottom' is a lower address
+   (as opposed to a lower stack frame). */
+  if (*bottom > *top)
+    {
+      tmp_vma = *top;
+      *top = *bottom;
+      *bottom = tmp_vma;
+    }
+
+  return 1;    /* success */
+}
+
+static int
+derive_stack_segment (bfd_vma *bottom, bfd_vma *top)
+{
+  if (override_derive_stack_segment)
+    return override_derive_stack_segment (bottom, top);
+  else
+    return default_derive_stack_segment (bottom, top);
+}
+
+/*
+ * Default method for heap segment (preemptable by target).
+ */
+
+static int (*override_derive_heap_segment) (bfd *, bfd_vma *, bfd_vma *);
+
+extern void
+preempt_derive_heap_segment (int (*override_func) (bfd *, 
+                                                  bfd_vma *, bfd_vma *))
+{
+  override_derive_heap_segment = override_func;
+}
+
+/* Function: default_derive_heap_segment
+   Derive a reasonable heap segment by looking at sbrk and
+   the static data sections.
+   
+   Returns 0 for failure, 1 for success.  */
+
+static int 
+default_derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top)
+{
+  bfd_vma top_of_data_memory = 0;
+  bfd_vma top_of_heap = 0;
+  bfd_size_type sec_size;
+  struct value *zero, *sbrk;
+  bfd_vma sec_vaddr;
+  asection *sec;
+
+  if (bottom == NULL || top == NULL)
+    return 0;          /* Paranoia. */
+
+  if (!target_has_execution)
+    return 0;          /* This function depends on being able
+                          to call a function in the inferior.  */
+
+  /* Assumption: link map is arranged as follows (low to high addresses):
+     text sections
+     data sections (including bss)
+     heap
+  */
+
+  for (sec = abfd->sections; sec; sec = sec->next)
+    {
+      if (bfd_get_section_flags (abfd, sec) & SEC_DATA ||
+         strcmp (".bss", bfd_get_section_name (abfd, sec)) == 0)
+       {
+         sec_vaddr = bfd_get_section_vma (abfd, sec);
+         sec_size = bfd_get_section_size_before_reloc (sec);
+         if (sec_vaddr + sec_size > top_of_data_memory)
+           top_of_data_memory = sec_vaddr + sec_size;
+       }
+    }
+  /* Now get the top-of-heap by calling sbrk in the inferior.  */
+  if ((sbrk = find_function_in_inferior ("sbrk")) == NULL)
+    return 0;
+  if ((zero = value_from_longest (builtin_type_int, (LONGEST) 0)) == NULL)
+    return 0;
+  if ((sbrk = call_function_by_hand (sbrk, 1, &zero)) == NULL)
+    return 0;
+  top_of_heap = value_as_long (sbrk);
+
+  /* Return results. */
+  if (top_of_heap > top_of_data_memory)
+    {
+      *bottom = top_of_data_memory;
+      *top = top_of_heap;
+      return 1;        /* success */
+    }
+  else
+    return 0;  /* No additional heap space needs to be saved. */
+}
+
+static int
+derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top)
+{
+  if (override_derive_heap_segment)
+    return override_derive_heap_segment (abfd, bottom, top);
+  else
+    return default_derive_heap_segment (abfd, bottom, top);
+}
+
+/* ARGSUSED */
+static void
+make_output_phdrs (bfd *obfd, asection *osec, void *ignored)
+{
+  int p_flags = 0;
+  int p_type;
+
+  /* FIXME: these constants may only be applicable for ELF.  */
+  if (strncmp (osec->name, "load", 4) == 0)
+    p_type = PT_LOAD;
+  else
+    p_type = PT_NOTE;
+
+  p_flags |= PF_R;     /* Segment is readable.  */
+  if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY))
+    p_flags |= PF_W;   /* Segment is writable.  */
+  if (bfd_get_section_flags (obfd, osec) & SEC_CODE)
+    p_flags |= PF_X;   /* Segment is executable.  */
+
+  bfd_record_phdr (obfd, p_type, 1, p_flags, 0, 0, 
+                  0, 0, 1, &osec);
+}
+
+static asection *
+make_mem_sec (bfd *obfd, 
+             bfd_vma addr, 
+             bfd_size_type size, 
+             unsigned int flags, 
+             unsigned int alignment)
+{
+  asection *osec;
+
+  if ((osec = bfd_make_section_anyway (obfd, "load")) == NULL)
+    {
+      warning ("Couldn't make gcore segment: %s",
+              bfd_errmsg (bfd_get_error ()));
+      return NULL;
+    }
+
+  if (info_verbose)
+    {
+      fprintf_filtered (gdb_stdout, 
+                       "Save segment, %ld bytes at 0x%s\n",
+                       size, paddr_nz (addr));
+    }
+
+  bfd_set_section_size (obfd, osec, size);
+  bfd_set_section_vma (obfd, osec, addr);
+  osec->lma = 0;       /* FIXME: there should be a macro for this! */
+  bfd_set_section_alignment (obfd, osec, alignment);
+  bfd_set_section_flags (obfd, osec, 
+                        flags | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS);
+  return osec;
+}
+
+static int
+gcore_create_callback (CORE_ADDR vaddr, 
+                      unsigned long size,
+                      int read, int write, int exec, 
+                      void *data)
+{
+  flagword flags = 0;
+
+  if (write == 0)
+    {
+      flags |= SEC_READONLY;
+      /* Set size == zero for readonly sections. */
+      size = 0;
+    }
+  if (exec)
+    {
+      flags |= SEC_CODE;
+    }
+  else
+    {
+      flags |= SEC_DATA;
+    }
+
+  return ((make_mem_sec ((bfd *) data, vaddr, size, flags, 0)) == NULL);
+}
+
+static int
+objfile_find_memory_regions (int (*func) (CORE_ADDR, 
+                                         unsigned long,
+                                         int, int, int,
+                                          void *), 
+                            void *obfd)
+{
+  /* Use objfile data to create memory sections. */
+  struct objfile *objfile;
+  struct obj_section *objsec;
+  bfd_vma temp_bottom, temp_top;
+
+  /* Call callback function for each objfile section. */
+  ALL_OBJSECTIONS (objfile, objsec)
+    {
+      bfd *ibfd = objfile->obfd;
+      asection *isec = objsec->the_bfd_section;
+      flagword flags = bfd_get_section_flags (ibfd, isec);
+      int ret;
+
+      if ((flags & SEC_ALLOC) || (flags & SEC_LOAD))
+       {
+         int size = bfd_section_size (ibfd, isec);
+         int ret;
+
+         if ((ret = (*func) (objsec->addr, 
+                             bfd_section_size (ibfd, isec), 
+                             1, /* All sections will be readable.  */
+                             (flags & SEC_READONLY) == 0, /* writable */
+                             (flags & SEC_CODE) != 0, /* executable */
+                             obfd)) != 0)
+           return ret;
+       }
+    }
+
+  /* Make a stack segment. */
+  if (derive_stack_segment (&temp_bottom, &temp_top))
+    (*func) (temp_bottom, 
+            temp_top - temp_bottom, 
+            1, /* Stack section will be readable */
+            1, /* Stack section will be writable */
+            0, /* Stack section will not be executable */
+            obfd);
+
+  /* Make a heap segment. */
+  if (derive_heap_segment (exec_bfd, &temp_bottom, &temp_top))
+    (*func) (temp_bottom, 
+            temp_top - temp_bottom, 
+            1, /* Heap section will be readable */
+            1, /* Heap section will be writable */
+            0, /* Heap section will not be executable */
+            obfd);
+  return 0;
+}
+
+static void
+gcore_copy_callback (bfd *obfd, asection *osec, void *ignored)
+{
+  bfd_size_type size = bfd_section_size (obfd, osec);
+  struct cleanup *old_chain = NULL;
+  void *memhunk;
+
+  if (size == 0)
+    return;    /* Read-only sections are marked as zero-size.
+                  We don't have to copy their contents. */
+  if (strncmp ("load", bfd_get_section_name (obfd, osec), 4) != 0)
+    return;    /* Only interested in "load" sections. */
+
+  if ((memhunk = xmalloc (size)) == NULL)
+    error ("Not enough memory to create corefile.");
+  old_chain = make_cleanup (xfree, memhunk);
+
+  if (target_read_memory (bfd_section_vma (obfd, osec), 
+                         memhunk, size) != 0)
+    warning ("Memory read failed for corefile section, %ld bytes at 0x%s\n",
+            (long) size, paddr (bfd_section_vma (obfd, osec)));
+  if (!bfd_set_section_contents (obfd, osec, memhunk, 0, size))
+    warning ("Failed to write corefile contents (%s).", 
+            bfd_errmsg (bfd_get_error ()));
+
+  do_cleanups (old_chain);     /* frees the xmalloc buffer */
+}
+
+static int
+gcore_memory_sections (bfd *obfd)
+{
+  if (target_find_memory_regions (gcore_create_callback, obfd) != 0)
+    return 0;  /* FIXME error return/msg? */
+
+  /* Record phdrs for section-to-segment mapping. */
+  bfd_map_over_sections (obfd, make_output_phdrs, NULL);
+
+  /* Copy memory region contents. */
+  bfd_map_over_sections (obfd, gcore_copy_callback, NULL);
+
+  return 1;    /* success */
+}
+
+void
+_initialize_gcore (void)
+{
+  add_com ("generate-core-file", class_files, gcore_command,
+          "Save a core file with the current state of the debugged process.\n\
+Argument is optional filename.  Default filename is 'core.<process_id>'.");
+
+  add_com_alias ("gcore", "generate-core-file", class_files, 1);
+  exec_set_find_memory_regions (objfile_find_memory_regions);
+}
index 6b370304da4251135e57c6037a5f65299a8ec6a0..9035310c4947f1f5b9638f534f62f2975c8bff84 100644 (file)
@@ -1,5 +1,6 @@
 /* Target-vector operations for controlling Unix child processes, for GDB.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 
+   2000, 2002
    Free Software Foundation, Inc.
    Contributed by Cygnus Support.
 
@@ -812,6 +813,24 @@ init_child_ops (void)
   child_ops.to_magic = OPS_MAGIC;
 }
 
+/* Take over the 'find_mapped_memory' vector from inftarg.c. */
+extern void 
+inftarg_set_find_memory_regions (int (*func) (int (*) (CORE_ADDR, 
+                                                      unsigned long, 
+                                                      int, int, int, 
+                                                      void *),
+                                             void *))
+{
+  child_ops.to_find_memory_regions = func;
+}
+
+/* Take over the 'make_corefile_notes' vector from inftarg.c. */
+extern void 
+inftarg_set_make_corefile_notes (char * (*func) (bfd *, int *))
+{
+  child_ops.to_make_corefile_notes = func;
+}
+
 void
 _initialize_inftarg (void)
 {
index 4e259230f931733ba510a27d81a4aea71aa212c0..4d48b8d16ea4a9a380ac7346cff1bbece019fb40 100644 (file)
@@ -1,5 +1,5 @@
-/* Generate a core file for the inferior process -- Linux version.
-   Copyright 2001 Free Software Foundation, Inc.
+/* Linux-specific methods for using the /proc file system.
+   Copyright 2001, 2002 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
+#include "inferior.h"
 #include <sys/param.h> /* for MAXPATHLEN */
+#include <sys/procfs.h>
+#include "gregset.h"   /* for gregset */
+#include "gdbcore.h"   /* for get_exec_file */
+#include "gdbthread.h" /* for struct thread_info etc. */
+#include "elf-bfd.h"
+
+/* Function: child_pid_to_exec_file
+ *
+ * Accepts an integer pid
+ * Returns a string representing a file that can be opened
+ * to get the symbols for the child process.
+ */
 
 char *
 child_pid_to_exec_file (int pid)
@@ -30,3 +43,229 @@ child_pid_to_exec_file (int pid)
   /* FIXME use readlink to get the real name. */
   return fname;
 }
+
+/* Function: linux_find_memory_regions
+ *
+ * Fills the "to_find_memory_regions" target vector.
+ * Lists the memory regions in the inferior for a corefile.
+ */
+
+static int
+linux_find_memory_regions (int (*func) (CORE_ADDR, 
+                                       unsigned long,
+                                       int, int, int,
+                                       void *), 
+                          void *obfd)
+{
+  long long pid = PIDGET (inferior_ptid);
+  char procfilename[MAXPATHLEN];
+  FILE *procfile;
+  long long addr, endaddr, size, offset, inode;
+  char perms[8], dev[8], filename[MAXPATHLEN];
+  int read, write, exec;
+  int ret;
+
+  /* Compose the filename for the /proc memory map, and open it. */
+  sprintf (procfilename, "/proc/%lld/maps", pid);
+  if ((procfile = fopen (procfilename, "r")) == NULL)
+    error ("Could not open %s\n", procfilename);
+
+  if (info_verbose)
+    fprintf_filtered (gdb_stdout, 
+                     "Reading memory regions from %s\n", procfilename);
+
+  /* Read the first memory segment descriptor from the maps file.  */
+  ret = fscanf (procfile, "%llx-%llx %s %llx %s %llx", 
+               &addr, &endaddr, perms, &offset, dev, &inode);
+  if (inode)
+    fscanf (procfile, " %s\n", filename);
+  else
+    {
+      filename[0] = '\0';
+      fscanf (procfile, "\n");
+    }
+
+  /* Now iterate until end-of-file. */
+  while (ret > 0 && ret != EOF)
+    {
+      size = endaddr - addr;
+
+      /* Get the segment's permissions.  */
+      read  = (strchr (perms, 'r') != 0);
+      write = (strchr (perms, 'w') != 0);
+      exec  = (strchr (perms, 'x') != 0);
+
+      if (info_verbose)
+       {
+         fprintf_filtered (gdb_stdout, 
+                           "Save segment, %lld bytes at 0x%s (%c%c%c)", 
+                           size, paddr_nz (addr), 
+                           read  ? 'r' : ' ', 
+                           write ? 'w' : ' ',
+                           exec  ? 'x' : ' ');
+         if (filename && filename[0])
+           fprintf_filtered (gdb_stdout, 
+                             " for %s", filename);
+         fprintf_filtered (gdb_stdout, "\n");
+       }
+
+      /* Invoke the callback function to create the corefile segment. */
+      func (addr, size, read, write, exec, obfd);
+
+      /* Read the next memory region.  */
+      filename[0] = '\0';
+      ret = fscanf (procfile, "%llx-%llx %s %llx %s %llx", 
+                   &addr, &endaddr, perms, &offset, dev, &inode);
+      if (inode)
+       fscanf (procfile, " %s\n", filename);
+      else
+       {
+         filename[0] = '\0';
+         fscanf (procfile, "\n");
+       }
+    }
+
+  fclose (procfile);
+  return 0;
+}
+
+/* Function: linux_do_thread_registers
+ *
+ * Records the thread's register state for the corefile note section.
+ */
+
+static char *
+linux_do_thread_registers (bfd *obfd, ptid_t ptid, 
+                          char *note_data, int *note_size)
+{
+  gdb_gregset_t gregs;
+  gdb_fpregset_t fpregs;
+#ifdef HAVE_PTRACE_GETFPXREGS
+  gdb_fpxregset_t fpxregs;
+#endif
+  unsigned long merged_pid = ptid_get_tid (ptid) << 16 | ptid_get_pid (ptid);
+
+  fill_gregset (&gregs, -1);
+  note_data = (char *) elfcore_write_prstatus (obfd, 
+                                              note_data, 
+                                              note_size, 
+                                              merged_pid, 
+                                              stop_signal, 
+                                              &gregs);
+
+  fill_fpregset (&fpregs, -1);
+  note_data = (char *) elfcore_write_prfpreg (obfd, 
+                                             note_data, 
+                                             note_size, 
+                                             &fpregs, 
+                                             sizeof (fpregs));
+#ifdef HAVE_PTRACE_GETFPXREGS
+  fill_fpxregset (&fpxregs, -1);
+  note_data = (char *) elfcore_write_prxfpreg (obfd, 
+                                              note_data, 
+                                              note_size, 
+                                              &fpxregs, 
+                                              sizeof (fpxregs));
+#endif
+  return note_data;
+}
+
+struct linux_corefile_thread_data {
+  bfd  *obfd;
+  char *note_data;
+  int  *note_size;
+};
+
+/* Function: linux_corefile_thread_callback
+ * 
+ * Called by gdbthread.c once per thread.
+ * Records the thread's register state for the corefile note section.
+ */
+
+static int
+linux_corefile_thread_callback (struct thread_info *ti, void *data)
+{
+  struct linux_corefile_thread_data *args = data;
+  ptid_t saved_ptid = inferior_ptid;
+
+  inferior_ptid = ti->ptid;
+  registers_changed ();
+  target_fetch_registers (-1); /* FIXME should not be necessary; 
+                                  fill_gregset should do it automatically. */
+  args->note_data = linux_do_thread_registers (args->obfd, 
+                                              ti->ptid, 
+                                              args->note_data, 
+                                              args->note_size);
+  inferior_ptid = saved_ptid;
+  registers_changed ();
+  target_fetch_registers (-1); /* FIXME should not be necessary; 
+                                  fill_gregset should do it automatically. */
+  return 0;
+}
+
+/* Function: linux_make_note_section
+ *
+ * Fills the "to_make_corefile_note" target vector.
+ * Builds the note section for a corefile, and returns it 
+ * in a malloc buffer. 
+ */
+
+static char *
+linux_make_note_section (bfd *obfd, int *note_size)
+{
+  struct linux_corefile_thread_data thread_args;
+  struct cleanup *old_chain;
+  char fname[16] = {'\0'};
+  char psargs[80] = {'\0'};
+  char *note_data = NULL;
+  ptid_t current_ptid = inferior_ptid;
+
+  if (get_exec_file (0))
+    {
+      strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
+      strncpy (psargs, get_exec_file (0), 
+              sizeof (psargs));
+      if (get_inferior_args ())
+       {
+         strncat (psargs, " ", 
+                  sizeof (psargs) - strlen (psargs));
+         strncat (psargs, get_inferior_args (), 
+                  sizeof (psargs) - strlen (psargs));
+       }
+      note_data = (char *) elfcore_write_prpsinfo (obfd, 
+                                                  note_data, 
+                                                  note_size, 
+                                                  fname, 
+                                                  psargs);
+    }
+
+  /* Dump information for threads.  */
+  thread_args.obfd = obfd;
+  thread_args.note_data = note_data;
+  thread_args.note_size = note_size;
+  iterate_over_threads (linux_corefile_thread_callback, &thread_args);
+  if (thread_args.note_data == note_data)
+    {
+      /* iterate_over_threads didn't come up with any threads;
+        just use inferior_ptid. */
+      note_data = linux_do_thread_registers (obfd, inferior_ptid, 
+                                            note_data, note_size);
+    }
+  else
+    {
+      note_data = thread_args.note_data;
+    }
+
+  make_cleanup (xfree, note_data);
+  return note_data;
+}
+
+void
+_initialize_linux_proc (void)
+{
+  extern void inftarg_set_find_memory_regions ();
+  extern void inftarg_set_make_corefile_notes ();
+
+  inftarg_set_find_memory_regions (linux_find_memory_regions);
+  inftarg_set_make_corefile_notes (linux_make_note_section);
+}
index 32b4e6054f31cab045af393b69adfd29e0545d6d..1714970e961674397333d54f9e1c2d2370098834 100644 (file)
@@ -1,5 +1,5 @@
 /* Machine independent support for SVR4 /proc (process file system) for GDB.
-   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    Written by Michael Snyder at Cygnus Solutions.
    Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
 
@@ -127,52 +127,62 @@ static int procfs_thread_alive (ptid_t);
 void procfs_find_new_threads (void);
 char *procfs_pid_to_str (ptid_t);
 
+static int proc_find_memory_regions (int (*) (CORE_ADDR, 
+                                             unsigned long, 
+                                             int, int, int, 
+                                             void *), 
+                                    void *);
+
+static char * procfs_make_note_section (bfd *, int *);
+
 struct target_ops procfs_ops;          /* the target vector */
 
 static void
 init_procfs_ops (void)
 {
-  procfs_ops.to_shortname          = "procfs";
-  procfs_ops.to_longname           = "Unix /proc child process";
-  procfs_ops.to_doc                = 
+  procfs_ops.to_shortname           = "procfs";
+  procfs_ops.to_longname            = "Unix /proc child process";
+  procfs_ops.to_doc                 
     "Unix /proc child process (started by the \"run\" command).";
-  procfs_ops.to_open               = procfs_open;
-  procfs_ops.to_can_run            = procfs_can_run;
-  procfs_ops.to_create_inferior    = procfs_create_inferior;
-  procfs_ops.to_kill               = procfs_kill_inferior;
-  procfs_ops.to_mourn_inferior     = procfs_mourn_inferior;
-  procfs_ops.to_attach             = procfs_attach;
-  procfs_ops.to_detach             = procfs_detach;
-  procfs_ops.to_wait               = procfs_wait;
-  procfs_ops.to_resume             = procfs_resume;
-  procfs_ops.to_prepare_to_store   = procfs_prepare_to_store;
-  procfs_ops.to_fetch_registers    = procfs_fetch_registers;
-  procfs_ops.to_store_registers    = procfs_store_registers;
-  procfs_ops.to_xfer_memory        = procfs_xfer_memory;
-  procfs_ops.to_insert_breakpoint  =  memory_insert_breakpoint;
-  procfs_ops.to_remove_breakpoint  =  memory_remove_breakpoint;
-  procfs_ops.to_notice_signals     = procfs_notice_signals;
-  procfs_ops.to_files_info         = procfs_files_info;
-  procfs_ops.to_stop               = procfs_stop;
-
-  procfs_ops.to_terminal_init      = terminal_init_inferior;
-  procfs_ops.to_terminal_inferior  = terminal_inferior;
+  procfs_ops.to_open                = procfs_open;
+  procfs_ops.to_can_run             = procfs_can_run;
+  procfs_ops.to_create_inferior     = procfs_create_inferior;
+  procfs_ops.to_kill                = procfs_kill_inferior;
+  procfs_ops.to_mourn_inferior      = procfs_mourn_inferior;
+  procfs_ops.to_attach              = procfs_attach;
+  procfs_ops.to_detach              = procfs_detach;
+  procfs_ops.to_wait                = procfs_wait;
+  procfs_ops.to_resume              = procfs_resume;
+  procfs_ops.to_prepare_to_store    = procfs_prepare_to_store;
+  procfs_ops.to_fetch_registers     = procfs_fetch_registers;
+  procfs_ops.to_store_registers     = procfs_store_registers;
+  procfs_ops.to_xfer_memory         = procfs_xfer_memory;
+  procfs_ops.to_insert_breakpoint   =  memory_insert_breakpoint;
+  procfs_ops.to_remove_breakpoint   =  memory_remove_breakpoint;
+  procfs_ops.to_notice_signals      = procfs_notice_signals;
+  procfs_ops.to_files_info          = procfs_files_info;
+  procfs_ops.to_stop                = procfs_stop;
+
+  procfs_ops.to_terminal_init       = terminal_init_inferior;
+  procfs_ops.to_terminal_inferior   = terminal_inferior;
   procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output;
-  procfs_ops.to_terminal_ours      = terminal_ours;
-  procfs_ops.to_terminal_info      = child_terminal_info;
-
-  procfs_ops.to_find_new_threads   = procfs_find_new_threads;
-  procfs_ops.to_thread_alive       = procfs_thread_alive;
-  procfs_ops.to_pid_to_str         = procfs_pid_to_str;
-
-  procfs_ops.to_has_all_memory     = 1;
-  procfs_ops.to_has_memory         = 1;
-  procfs_ops.to_has_execution      = 1;
-  procfs_ops.to_has_stack          = 1;
-  procfs_ops.to_has_registers      = 1;
-  procfs_ops.to_stratum            = process_stratum;
-  procfs_ops.to_has_thread_control = tc_schedlock;
-  procfs_ops.to_magic              = OPS_MAGIC;
+  procfs_ops.to_terminal_ours       = terminal_ours;
+  procfs_ops.to_terminal_info       = child_terminal_info;
+
+  procfs_ops.to_find_new_threads    = procfs_find_new_threads;
+  procfs_ops.to_thread_alive        = procfs_thread_alive;
+  procfs_ops.to_pid_to_str          = procfs_pid_to_str;
+
+  procfs_ops.to_has_all_memory      = 1;
+  procfs_ops.to_has_memory          = 1;
+  procfs_ops.to_has_execution       = 1;
+  procfs_ops.to_has_stack           = 1;
+  procfs_ops.to_has_registers       = 1;
+  procfs_ops.to_stratum             = process_stratum;
+  procfs_ops.to_has_thread_control  = tc_schedlock;
+  procfs_ops.to_find_memory_regions = proc_find_memory_regions;
+  procfs_ops.to_make_corefile_notes = procfs_make_note_section;
+  procfs_ops.to_magic               = OPS_MAGIC;
 }
 
 /* =================== END, TARGET_OPS "MODULE" =================== */
@@ -5354,6 +5364,65 @@ proc_iterate_over_mappings (int (*func) (int, CORE_ADDR))
   return iterate_over_mappings (pi, func, pi, solib_mappings_callback);
 }
 
+/*
+ * Function: find_memory_regions_callback
+ *
+ * Implements the to_find_memory_regions method.
+ * Calls an external function for each memory region.
+ * External function will have the signiture:
+ *
+ *   int callback (CORE_ADDR vaddr, 
+ *                 unsigned long size, 
+ *                 int read, int write, int execute, 
+ *                 void *data);
+ *
+ * Returns the integer value returned by the callback.
+ */
+
+static int
+find_memory_regions_callback (struct prmap *map, 
+                             int (*func) (CORE_ADDR, 
+                                          unsigned long, 
+                                          int, int, int, 
+                                          void *),
+                             void *data)
+{
+  return (*func) (host_pointer_to_address ((void *) map->pr_vaddr),
+                 map->pr_size, 
+                 (map->pr_mflags & MA_READ) != 0,
+                 (map->pr_mflags & MA_WRITE) != 0,
+                 (map->pr_mflags & MA_EXEC) != 0, 
+                 data);
+}
+
+/*
+ * Function: proc_find_memory_regions
+ *
+ * External interface.  Calls a callback function once for each
+ * mapped memory region in the child process, passing as arguments
+ *     CORE_ADDR virtual_address,
+ *     unsigned long size, 
+ *     int read,       TRUE if region is readable by the child
+ *     int write,      TRUE if region is writable by the child
+ *     int execute     TRUE if region is executable by the child.
+ * 
+ * Stops iterating and returns the first non-zero value
+ * returned by the callback.
+ */
+
+static int
+proc_find_memory_regions (int (*func) (CORE_ADDR, 
+                                      unsigned long, 
+                                      int, int, int, 
+                                      void *), 
+                         void *data)
+{
+  procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+
+  return iterate_over_mappings (pi, func, data, 
+                               find_memory_regions_callback);
+}
+
 /*
  * Function: mappingflags
  *
@@ -5650,3 +5719,109 @@ procfs_first_available (void)
 {
   return pid_to_ptid (procinfo_list ? procinfo_list->pid : -1);
 }
+
+/* ===================  GCORE .NOTE "MODULE" =================== */
+
+static char *
+procfs_do_thread_registers (bfd *obfd, ptid_t ptid, 
+                           char *note_data, int *note_size)
+{
+  gdb_gregset_t gregs;
+  gdb_fpregset_t fpregs;
+  unsigned long merged_pid;
+
+  merged_pid = TIDGET (ptid) << 16 | PIDGET (ptid);
+
+  fill_gregset (&gregs, -1);
+  note_data = (char *) elfcore_write_prstatus (obfd,
+                                               note_data,
+                                               note_size,
+                                              merged_pid, 
+                                              stop_signal,
+                                               &gregs);
+  fill_fpregset (&fpregs, -1);
+  note_data = (char *) elfcore_write_prfpreg (obfd,
+                                             note_data,
+                                             note_size,
+                                             &fpregs,
+                                             sizeof (fpregs));
+  return note_data;
+}
+
+struct procfs_corefile_thread_data {
+  bfd *obfd;
+  char *note_data;
+  int *note_size;
+};
+
+static int
+procfs_corefile_thread_callback (struct thread_info *ti, void *data)
+{
+  struct procfs_corefile_thread_data *args = data;
+  procinfo *pi = find_procinfo (PIDGET (ti->ptid), TIDGET (ti->ptid));
+
+  if (pi != NULL && TIDGET (ti->ptid) != 0)
+    {
+      ptid_t saved_ptid = inferior_ptid;
+      inferior_ptid = ti->ptid;
+      args->note_data = procfs_do_thread_registers (args->obfd, ti->ptid, 
+                                                   args->note_data, 
+                                                   args->note_size);
+      inferior_ptid = saved_ptid;
+    }
+  return 0;
+}
+
+static char *
+procfs_make_note_section (bfd *obfd, int *note_size)
+{
+  struct cleanup *old_chain;
+  gdb_gregset_t gregs;
+  gdb_fpregset_t fpregs;
+  char fname[16] = {'\0'};
+  char psargs[80] = {'\0'};
+  procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+  char *note_data = NULL;
+  struct procfs_corefile_thread_data thread_args;
+
+  if (get_exec_file (0))
+    {
+      strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
+      strncpy (psargs, get_exec_file (0), 
+              sizeof (psargs));
+      if (get_inferior_args ())
+       {
+         strncat (psargs, " ", 
+                  sizeof (psargs) - strlen (psargs));
+         strncat (psargs, get_inferior_args (), 
+                  sizeof (psargs) - strlen (psargs));
+       }
+    }
+
+  note_data = (char *) elfcore_write_prpsinfo (obfd, 
+                                              note_data, 
+                                              note_size, 
+                                              fname, 
+                                              psargs);
+
+  thread_args.obfd = obfd;
+  thread_args.note_data = note_data;
+  thread_args.note_size = note_size;
+  iterate_over_threads (procfs_corefile_thread_callback, &thread_args);
+  if (thread_args.note_data == note_data)
+    {
+      /* iterate_over_threads didn't come up with any threads;
+        just use inferior_ptid. */
+      note_data = procfs_do_thread_registers (obfd, inferior_ptid, 
+                                             note_data, note_size);
+    }
+  else
+    {
+      note_data = thread_args.note_data;
+    }
+
+  make_cleanup (xfree, note_data);
+  return note_data;
+}
+
+/* ===================  END GCORE .NOTE "MODULE" =================== */
index 18b812ccbee20cdec1823ece2ba7ee513c84cec1..50caed39d99a8539b9b2201af37ba0a2f8c92497 100644 (file)
@@ -1,5 +1,5 @@
 /* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -1510,6 +1510,22 @@ info_solthreads (char *args, int from_tty)
                    TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
 }
 
+static int
+sol_find_memory_regions (int (*func) (CORE_ADDR, 
+                                     unsigned long, 
+                                     int, int, int, 
+                                     void *), 
+                        void *data)
+{
+  return procfs_ops.to_find_memory_regions (func, data);
+}
+
+static char *
+sol_make_note_section (bfd *obfd, int *note_size)
+{
+  return procfs_ops.to_make_corefile_notes (obfd, note_size);
+}
+
 static int
 ignore (CORE_ADDR addr, char *contents)
 {
@@ -1561,6 +1577,8 @@ init_sol_thread_ops (void)
   sol_thread_ops.to_has_thread_control = tc_none;
   sol_thread_ops.to_sections = 0;
   sol_thread_ops.to_sections_end = 0;
+  sol_thread_ops.to_find_memory_regions = sol_find_memory_regions;
+  sol_thread_ops.to_make_corefile_notes = sol_make_note_section;
   sol_thread_ops.to_magic = OPS_MAGIC;
 }
 
index 1a8723c37e569cd2b1a3918329a0805631e88038..1af88838f2b2755923fbd31d06b0c50d2e1254f1 100644 (file)
@@ -1,6 +1,7 @@
 /* Select target systems and architectures at runtime for GDB.
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001 Free Software Foundation, Inc.
+   2000, 2001, 2002
+   Free Software Foundation, Inc.
    Contributed by Cygnus Support.
 
    This file is part of GDB.
@@ -607,6 +608,8 @@ update_current_target (void)
       INHERIT (to_is_async_p, t);
       INHERIT (to_async, t);
       INHERIT (to_async_mask_value, t);
+      INHERIT (to_find_memory_regions, t);
+      INHERIT (to_make_corefile_notes, t);
       INHERIT (to_magic, t);
 
 #undef INHERIT
@@ -1461,6 +1464,22 @@ normal_target_post_startup_inferior (ptid_t ptid)
   /* This space intentionally left blank. */
 }
 
+/* Error-catcher for target_find_memory_regions */
+/* ARGSUSED */
+static int dummy_find_memory_regions (int (*ignore1) (), void *ignore2)
+{
+  error ("No target.");
+  return 0;
+}
+
+/* Error-catcher for target_make_corefile_notes */
+/* ARGSUSED */
+static char * dummy_make_corefile_notes (bfd *ignore1, int *ignore2)
+{
+  error ("No target.");
+  return NULL;
+}
+
 /* Set up the handful of non-empty slots needed by the dummy target
    vector.  */
 
@@ -1477,6 +1496,8 @@ init_dummy_target (void)
   dummy_target.to_clone_and_follow_inferior = find_default_clone_and_follow_inferior;
   dummy_target.to_pid_to_str = normal_pid_to_str;
   dummy_target.to_stratum = dummy_stratum;
+  dummy_target.to_find_memory_regions = dummy_find_memory_regions;
+  dummy_target.to_make_corefile_notes = dummy_make_corefile_notes;
   dummy_target.to_magic = OPS_MAGIC;
 }
 \f
index 18635d2484fe76a2f558724ca1a56ab868330e60..3d17becdfd1719957495340080feedd58dec6fa4 100644 (file)
@@ -1,6 +1,6 @@
 /* Interface between GDB and target environments, including files and processes
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001 Free Software Foundation, Inc.
+   2000, 2001, 2002 Free Software Foundation, Inc.
    Contributed by Cygnus Support.  Written by John Gilmore.
 
    This file is part of GDB.
@@ -313,6 +313,12 @@ struct target_ops
     void (*to_async) (void (*cb) (enum inferior_event_type, void *context),
                      void *context);
     int to_async_mask_value;
+    int (*to_find_memory_regions) (int (*) (CORE_ADDR, 
+                                           unsigned long, 
+                                           int, int, int, 
+                                           void *), 
+                                  void *);
+    char * (*to_make_corefile_notes) (bfd *, int *);
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -999,6 +1005,23 @@ extern void (*target_new_objfile_hook) (struct objfile *);
 #define target_pid_to_exec_file(pid) \
      (current_target.to_pid_to_exec_file) (pid)
 
+/*
+ * Iterator function for target memory regions.
+ * Calls a callback function once for each memory region 'mapped'
+ * in the child process.  Defined as a simple macro rather than
+ * as a function macro so that it can be tested for nullity.  
+ */
+
+#define target_find_memory_regions(FUNC, DATA) \
+     (current_target.to_find_memory_regions) (FUNC, DATA)
+
+/*
+ * Compose corefile .note section.
+ */
+
+#define target_make_corefile_notes(BFD, SIZE_P) \
+     (current_target.to_make_corefile_notes) (BFD, SIZE_P)
+
 /* Hook to call target-dependent code after reading in a new symbol table.  */
 
 #ifndef TARGET_SYMFILE_POSTREAD