This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Add command 'generate-core-file'


OK, after moving the gcore functionality from linux-gcore.c to 
linux-proc.c, I'm going to commit this.  Here is the patch as
committed.  Hopefully I haven't left anything out.
Eli, I owe you some docs.

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-08  Michael Snyder  <msnyder@redhat.com>

	* gdb.base/gcore.exp: New test for generate-core-file command.
	* gdb.base/gcore.c: Testcase for above.
	* gdb.threads/gcore-thread.exp: New test for gcore (threaded).

Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.71
diff -c -3 -p -r1.71 defs.h
*** defs.h	2002/01/05 22:06:38	1.71
--- defs.h	2002/01/08 23:50:49
***************
*** 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
     Free Software Foundation, Inc.
  
     This file is part of GDB.
--- 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, 2002
     Free Software Foundation, Inc.
  
     This file is part of GDB.
*************** extern char *symtab_to_filename (struct 
*** 774,779 ****
--- 774,786 ----
  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 */
  
Index: exec.c
===================================================================
RCS file: /cvs/src/src/gdb/exec.c,v
retrieving revision 1.15
diff -c -3 -p -r1.15 exec.c
*** exec.c	2001/11/06 23:38:14	1.15
--- exec.c	2002/01/08 23:50:49
***************
*** 1,6 ****
  /* Work with executable files, for GDB. 
     Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
!    1998, 1999, 2000, 2001
     Free Software Foundation, Inc.
  
     This file is part of GDB.
--- 1,6 ----
  /* Work with executable files, for GDB. 
     Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
!    1998, 1999, 2000, 2001, 2002
     Free Software Foundation, Inc.
  
     This file is part of GDB.
*************** ignore (CORE_ADDR addr, char *contents)
*** 685,694 ****
    return 0;
  }
  
  /* Fill in the exec file target vector.  Very few entries need to be
     defined.  */
  
! void
  init_exec_ops (void)
  {
    exec_ops.to_shortname = "exec";
--- 685,708 ----
    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.  */
  
! static void
  init_exec_ops (void)
  {
    exec_ops.to_shortname = "exec";
*************** Specify the filename of the executable f
*** 708,713 ****
--- 722,728 ----
    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;
  }
  
*************** file itself are wrong.  Each section mus
*** 751,754 ****
--- 766,800 ----
       &showlist);
  
    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;
  }
Index: gcore.c
===================================================================
RCS file: gcore.c
diff -N gcore.c
*** /dev/null	Tue May  5 13:32:27 1998
--- gcore.c	Tue Jan  8 15:50:49 2002
***************
*** 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: gregset.h
===================================================================
RCS file: /cvs/src/src/gdb/gregset.h,v
retrieving revision 1.2
diff -c -3 -p -r1.2 gregset.h
*** gregset.h	2000/08/27 21:37:16	1.2
--- gregset.h	2002/01/08 23:50:49
***************
*** 1,5 ****
  /* Interface for functions using gregset and fpregset types.
!    Copyright 2000 Free Software Foundation, Inc.
  
     This file is part of GDB.
  
--- 1,5 ----
  /* Interface for functions using gregset and fpregset types.
!    Copyright 2000, 2002 Free Software Foundation, Inc.
  
     This file is part of GDB.
  
*************** extern void supply_fpregset (gdb_fpregse
*** 51,55 ****
--- 51,69 ----
  
  extern void fill_gregset (gdb_gregset_t *gregs, int regno);
  extern void fill_fpregset (gdb_fpregset_t *fpregs, int regno);
+ 
+ #ifdef HAVE_PTRACE_GETFPXREGS
+ /* Linux/i386: Copy register values between GDB's internal register cache
+    and the i386 extended floating point registers.  */
+ 
+ #ifndef GDB_FPXREGSET_T
+ #define GDB_FPXREGSET_T elf_fpxregset_t
+ #endif
+ 
+ typedef GDB_FPXREGSET_T gdb_fpxregset_t;
+ 
+ extern void supply_fpxregset (gdb_fpxregset_t *fpxregs);
+ extern void fill_fpxregset (gdb_fpxregset_t *fpxregs, int regno);
+ #endif
  
  #endif
Index: i386-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v
retrieving revision 1.33
diff -c -3 -p -r1.33 i386-linux-nat.c
*** i386-linux-nat.c	2001/12/27 19:52:31	1.33
--- i386-linux-nat.c	2002/01/08 23:50:49
***************
*** 1,5 ****
  /* Native-dependent code for Linux/x86.
!    Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
  
     This file is part of GDB.
  
--- 1,5 ----
  /* Native-dependent code for Linux/x86.
!    Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
  
     This file is part of GDB.
  
*************** static void store_fpregs (int tid, int r
*** 452,458 ****
  /* Fill GDB's register array with the floating-point and SSE register
     values in *FPXREGSETP.  */
  
! static void
  supply_fpxregset (elf_fpxregset_t *fpxregsetp)
  {
    i387_supply_fxsave ((char *) fpxregsetp);
--- 452,458 ----
  /* Fill GDB's register array with the floating-point and SSE register
     values in *FPXREGSETP.  */
  
! void
  supply_fpxregset (elf_fpxregset_t *fpxregsetp)
  {
    i387_supply_fxsave ((char *) fpxregsetp);
*************** supply_fpxregset (elf_fpxregset_t *fpxre
*** 462,468 ****
     *FPXREGSETP with the value in GDB's register array.  If REGNO is
     -1, do this for all registers.  */
  
! static void
  fill_fpxregset (elf_fpxregset_t *fpxregsetp, int regno)
  {
    i387_fill_fxsave ((char *) fpxregsetp, regno);
--- 462,468 ----
     *FPXREGSETP with the value in GDB's register array.  If REGNO is
     -1, do this for all registers.  */
  
! void
  fill_fpxregset (elf_fpxregset_t *fpxregsetp, int regno)
  {
    i387_fill_fxsave ((char *) fpxregsetp, regno);
Index: inftarg.c
===================================================================
RCS file: /cvs/src/src/gdb/inftarg.c,v
retrieving revision 1.7
diff -c -3 -p -r1.7 inftarg.c
*** inftarg.c	2001/05/04 04:15:25	1.7
--- inftarg.c	2002/01/08 23:50:49
***************
*** 1,5 ****
  /* Target-vector operations for controlling Unix child processes, for GDB.
!    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000
     Free Software Foundation, Inc.
     Contributed by Cygnus Support.
  
--- 1,6 ----
  /* Target-vector operations for controlling Unix child processes, for GDB.
!    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 
!    2000, 2002
     Free Software Foundation, Inc.
     Contributed by Cygnus Support.
  
*************** init_child_ops (void)
*** 810,815 ****
--- 811,834 ----
    child_ops.to_has_registers = 1;
    child_ops.to_has_execution = 1;
    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
Index: linux-proc.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-proc.c,v
retrieving revision 1.1
diff -c -3 -p -r1.1 linux-proc.c
*** linux-proc.c	2002/01/08 22:09:46	1.1
--- linux-proc.c	2002/01/08 23:50:49
***************
*** 1,5 ****
! /* Generate a core file for the inferior process -- Linux version.
!    Copyright 2001 Free Software Foundation, Inc.
  
     This file is part of GDB.
  
--- 1,5 ----
! /* Linux-specific methods for using the /proc file system.
!    Copyright 2001, 2002 Free Software Foundation, Inc.
  
     This file is part of GDB.
  
***************
*** 19,26 ****
--- 19,39 ----
     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)
  {
*************** child_pid_to_exec_file (int pid)
*** 29,32 ****
--- 42,271 ----
    sprintf (fname, "/proc/%d/exe", 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: procfs.c
===================================================================
RCS file: /cvs/src/src/gdb/procfs.c,v
retrieving revision 1.34
diff -c -3 -p -r1.34 procfs.c
*** procfs.c	2002/01/03 20:50:25	1.34
--- procfs.c	2002/01/08 23:50:50
***************
*** 1,5 ****
  /* Machine independent support for SVR4 /proc (process file system) for GDB.
!    Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
     Written by Michael Snyder at Cygnus Solutions.
     Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
  
--- 1,5 ----
  /* Machine independent support for SVR4 /proc (process file system) for GDB.
!    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.
  
*************** static int procfs_thread_alive (ptid_t);
*** 127,178 ****
  void procfs_find_new_threads (void);
  char *procfs_pid_to_str (ptid_t);
  
  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                = 
      "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_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;
  }
  
  /* =================== END, TARGET_OPS "MODULE" =================== */
--- 127,188 ----
  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                 = 
      "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_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_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" =================== */
*************** proc_iterate_over_mappings (int (*func) 
*** 5355,5360 ****
--- 5365,5429 ----
  }
  
  /*
+  * 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
   *
   * Returns an ascii representation of a memory mapping's flags.
*************** procfs_first_available (void)
*** 5650,5652 ****
--- 5719,5827 ----
  {
    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: sol-thread.c
===================================================================
RCS file: /cvs/src/src/gdb/sol-thread.c,v
retrieving revision 1.28
diff -c -3 -p -r1.28 sol-thread.c
*** sol-thread.c	2001/11/01 16:17:08	1.28
--- sol-thread.c	2002/01/08 23:50:50
***************
*** 1,5 ****
  /* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
!    Copyright 1996, 1997, 1998, 1999, 2000, 2001
     Free Software Foundation, Inc.
  
     This file is part of GDB.
--- 1,5 ----
  /* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
!    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
     Free Software Foundation, Inc.
  
     This file is part of GDB.
*************** info_solthreads (char *args, int from_tt
*** 1511,1516 ****
--- 1511,1532 ----
  }
  
  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)
  {
    return 0;
*************** init_sol_thread_ops (void)
*** 1561,1566 ****
--- 1577,1584 ----
    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: solib.c
===================================================================
RCS file: /cvs/src/src/gdb/solib.c,v
retrieving revision 1.47
diff -c -3 -p -r1.47 solib.c
*** solib.c	2002/01/08 18:55:26	1.47
--- solib.c	2002/01/08 23:50:50
***************
*** 1,6 ****
  /* Handle shared libraries for GDB, the GNU Debugger.
     Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
!    2000, 2001
     Free Software Foundation, Inc.
  
     This file is part of GDB.
--- 1,6 ----
  /* Handle shared libraries for GDB, the GNU Debugger.
     Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
!    2000, 2001, 2002
     Free Software Foundation, Inc.
  
     This file is part of GDB.
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.29
diff -c -3 -p -r1.29 target.c
*** target.c	2001/12/05 22:32:57	1.29
--- target.c	2002/01/08 23:50:50
***************
*** 1,6 ****
  /* 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.
     Contributed by Cygnus Support.
  
     This file is part of GDB.
--- 1,7 ----
  /* Select target systems and architectures at runtime for GDB.
     Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
!    2000, 2001, 2002
!    Free Software Foundation, Inc.
     Contributed by Cygnus Support.
  
     This file is part of GDB.
*************** update_current_target (void)
*** 607,612 ****
--- 608,615 ----
        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
*************** normal_target_post_startup_inferior (pti
*** 1461,1466 ****
--- 1464,1485 ----
    /* 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.  */
  
*************** init_dummy_target (void)
*** 1477,1482 ****
--- 1496,1503 ----
    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;
  }
  
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.21
diff -c -3 -p -r1.21 target.h
*** target.h	2001/11/21 02:01:29	1.21
--- target.h	2002/01/08 23:50:50
***************
*** 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.
     Contributed by Cygnus Support.  Written by John Gilmore.
  
     This file is part of GDB.
--- 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, 2002 Free Software Foundation, Inc.
     Contributed by Cygnus Support.  Written by John Gilmore.
  
     This file is part of GDB.
*************** struct target_ops
*** 313,318 ****
--- 313,324 ----
      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?
       */
*************** extern void (*target_new_objfile_hook) (
*** 998,1003 ****
--- 1004,1026 ----
  
  #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.  */
  
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.148
diff -c -3 -p -r1.148 Makefile.in
*** Makefile.in	2002/01/08 22:09:46	1.148
--- Makefile.in	2002/01/08 23:50:50
***************
*** 1,5 ****
  # Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
! # 1999, 2000, 2001 Free Software Foundation, Inc.
  
  # This file is part of GDB.
  
--- 1,5 ----
  # Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
! # 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
  
  # This file is part of GDB.
  
Index: config/alpha/alpha-linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/alpha/alpha-linux.mh,v
retrieving revision 1.7
diff -c -3 -p -r1.7 alpha-linux.mh
*** alpha-linux.mh	2002/01/08 22:09:47	1.7
--- alpha-linux.mh	2002/01/08 23:50:50
*************** XDEPFILES=
*** 3,9 ****
  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
  
  LOADLIBES = -ldl -rdynamic
  
--- 3,9 ----
  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 gcore.o
  
  LOADLIBES = -ldl -rdynamic
  
Index: config/arm/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/arm/linux.mh,v
retrieving revision 1.8
diff -c -3 -p -r1.8 linux.mh
*** linux.mh	2002/01/08 22:09:47	1.8
--- linux.mh	2002/01/08 23:50:50
*************** XDEPFILES=
*** 5,11 ****
  
  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		\
  	proc-service.o thread-db.o lin-lwp.o
  
  LOADLIBES= -ldl -rdynamic
--- 5,11 ----
  
  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 gcore.o	\
  	proc-service.o thread-db.o lin-lwp.o
  
  LOADLIBES= -ldl -rdynamic
Index: config/i386/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux.mh,v
retrieving revision 1.9
diff -c -3 -p -r1.9 linux.mh
*** linux.mh	2002/01/08 22:09:48	1.9
--- linux.mh	2002/01/08 23:50:50
*************** XDEPFILES=
*** 6,12 ****
  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 
  
  # The dynamically loaded libthread_db needs access to symbols in the
  # gdb executable.
--- 6,12 ----
  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 gcore.o
  
  # The dynamically loaded libthread_db needs access to symbols in the
  # gdb executable.
Index: config/i386/x86-64linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/x86-64linux.mh,v
retrieving revision 1.2
diff -c -3 -p -r1.2 x86-64linux.mh
*** x86-64linux.mh	2002/01/08 22:09:48	1.2
--- x86-64linux.mh	2002/01/08 23:50:50
*************** XDEPFILES=
*** 6,11 ****
  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 
  
  LOADLIBES = -ldl -rdynamic
--- 6,12 ----
  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 gcore.o 
  
  LOADLIBES = -ldl -rdynamic
Index: config/ia64/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/ia64/linux.mh,v
retrieving revision 1.10
diff -c -3 -p -r1.10 linux.mh
*** linux.mh	2002/01/08 22:09:48	1.10
--- linux.mh	2002/01/08 23:50:50
*************** XM_FILE= xm-linux.h
*** 4,10 ****
  XDEPFILES=
  
  NAT_FILE= nm-linux.h
! NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
  	core-aout.o core-regset.o ia64-linux-nat.o linux-proc.o \
  	proc-service.o thread-db.o lin-lwp.o
  
--- 4,10 ----
  XDEPFILES=
  
  NAT_FILE= nm-linux.h
! 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: config/m68k/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/m68k/linux.mh,v
retrieving revision 1.7
diff -c -3 -p -r1.7 linux.mh
*** linux.mh	2002/01/08 22:09:49	1.7
--- linux.mh	2002/01/08 23:50:50
*************** XDEPFILES=
*** 5,11 ****
  
  NAT_FILE= nm-linux.h
  NATDEPFILES= infptrace.o inftarg.o fork-child.o \
! 	corelow.o core-aout.o m68klinux-nat.o linux-proc.o \
  	proc-service.o thread-db.o lin-lwp.o 
  
  # The dynamically loaded libthread_db needs access to symbols in the
--- 5,11 ----
  
  NAT_FILE= nm-linux.h
  NATDEPFILES= infptrace.o inftarg.o fork-child.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: config/mips/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/mips/linux.mh,v
retrieving revision 1.2
diff -c -3 -p -r1.2 linux.mh
*** linux.mh	2002/01/08 22:09:49	1.2
--- linux.mh	2002/01/08 23:50:50
*************** XDEPFILES=
*** 3,8 ****
  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
  
  LOADLIBES = -ldl -rdynamic
--- 3,8 ----
  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 gcore.o
  
  LOADLIBES = -ldl -rdynamic
Index: config/powerpc/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/powerpc/linux.mh,v
retrieving revision 1.8
diff -c -3 -p -r1.8 linux.mh
*** linux.mh	2002/01/08 22:09:49	1.8
--- linux.mh	2002/01/08 23:50:50
*************** XM_CLIBS=
*** 6,12 ****
  
  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
  
  LOADLIBES = -ldl -rdynamic
  
--- 6,13 ----
  
  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 \
! 	gcore.o
  
  LOADLIBES = -ldl -rdynamic
  
Index: config/sparc/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/linux.mh,v
retrieving revision 1.5
diff -c -3 -p -r1.5 linux.mh
*** linux.mh	2002/01/08 22:09:50	1.5
--- linux.mh	2002/01/08 23:50:50
*************** XDEPFILES=
*** 5,11 ****
  
  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
  
  # The dynamically loaded libthread_db needs access to symbols in the
  # gdb executable.
--- 5,12 ----
  
  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 gcore.o 
  
  # The dynamically loaded libthread_db needs access to symbols in the
  # gdb executable.
Index: testsuite/gdb.base/gcore.exp
===================================================================
RCS file: gcore.exp
diff -N gcore.exp
*** /dev/null	Tue May  5 13:32:27 1998
--- gcore.exp	Tue Jan  8 15:52:53 2002
***************
*** 0 ****
--- 1,220 ----
+ # Copyright 2002 Free Software Foundation, Inc.
+ 
+ # 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.  
+ 
+ # Please email any bugs, comments, and/or additions to this file to:
+ # bug-gdb@prep.ai.mit.edu
+ 
+ # This file was written by Michael Snyder (msnyder@redhat.com)
+ # This is a test for the gdb command "generate-core-file".
+ 
+ if $tracelevel then {
+ 	strace $tracelevel
+ }
+ 
+ set prms_id 0
+ set bug_id 0
+ 
+ set testfile "gcore"
+ set srcfile  ${testfile}.c
+ set binfile  ${objdir}/${subdir}/${testfile}
+ 
+ if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+      gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+ }
+ 
+ # Start with a fresh gdb.
+ 
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+ 
+ # Does this gdb support gcore?
+ send_gdb "help gcore\n"
+ gdb_expect {
+     -re "Undefined command: .gcore.*$gdb_prompt $" {
+ 	# gcore command not supported -- nothing to test here.
+ 	unsupported "gdb does not support gcore on this target"
+ 	return -1;
+     }
+     -re "Save a core file .*$gdb_prompt $" {
+ 	pass "help gcore"
+     }
+     -re ".*$gdb_prompt $" {
+ 	fail "help gcore"
+     }
+     timeout {
+ 	fail "help gcore (timeout)"
+     }
+ }
+ 
+ if { ! [ runto main ] } then {
+     gdb_suppress_entire_file "Run to main failed, so all tests in this file will automatically fail."
+ }
+ 
+ proc capture_command_output { command prefix } {
+     global gdb_prompt
+     global expect_out
+ 
+     set output_string ""
+     send_gdb "$command\n"
+     gdb_expect {
+ 	-re "${command}\[\r\n\]+${prefix}(.*)\[\r\n\]+$gdb_prompt $" {
+ 	    set output_string $expect_out(1,string)
+ 	}
+ 	default {
+ 	    fail "capture_command_output failed on $command."
+ 	}
+     }
+     return $output_string
+ }
+ 
+ gdb_test "break terminal_func" "Breakpoint .* at .*${srcfile}, line .*" \
+ 	"set breakpoint at terminal_func"
+ 
+ gdb_test "continue" "Breakpoint .*, terminal_func.*" \
+ 	"continue to terminal_func"
+ 
+ set print_prefix ".\[0123456789\]* = "
+ 
+ set pre_corefile_backtrace [capture_command_output "backtrace" ""]
+ set pre_corefile_regs [capture_command_output "info registers" ""]
+ set pre_corefile_allregs [capture_command_output "info all-reg" ""]
+ set pre_corefile_static_array \
+ 	[capture_command_output "print static_array" "$print_prefix"]
+ set pre_corefile_uninit_array \
+ 	[capture_command_output "print un_initialized_array" "$print_prefix"]
+ set pre_corefile_heap_string \
+ 	[capture_command_output "print heap_string" "$print_prefix"]
+ set pre_corefile_local_array \
+ 	[capture_command_output "print array_func::local_array" "$print_prefix"]
+ set pre_corefile_extern_array \
+ 	[capture_command_output "print extern_array" "$print_prefix"]
+ 
+ gdb_test "gcore ${objdir}/${subdir}/gcore.test" \
+ 	"Saved corefile ${objdir}/${subdir}/gcore.test" \
+ 	"save a corefile"
+ 
+ # Now restart gdb and load the corefile.
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+ 
+ send_gdb "core ${objdir}/${subdir}/gcore.test\n"
+ gdb_expect {
+     -re ".* is not a core dump:.*$gdb_prompt $" {
+ 	fail "re-load generated corefile (bad file format)"
+ 	# No use proceeding from here.
+ 	return;	
+     }
+     -re ".*: No such file or directory.*$gdb_prompt $" {
+ 	fail "re-load generated corefile (file not found)"
+ 	# No use proceeding from here.
+ 	return;	
+     }
+     -re ".*Couldn't find .* registers in core file.*$gdb_prompt $" {
+ 	fail "re-load generated corefile (incomplete note section)"
+     }
+     -re "Core was generated by .*$gdb_prompt $" {
+ 	pass "re-load generated corefile"
+     }
+     -re ".*$gdb_prompt $" {
+ 	fail "re-load generated corefile"
+     }
+     timeout {
+ 	fail "re-load generated corefile (timeout)"
+     }
+ }
+ 
+ send_gdb "where\n"
+ gdb_expect_list "where in corefile" ".*$gdb_prompt $" {
+     ".*\[\r\n\]+#0 .* terminal_func \\(\\) at "
+     ".*\[\r\n\]+#1 .* array_func \\(\\) at "
+     ".*\[\r\n\]+#2 .* factorial_func \\(value=1\\) at "
+     ".*\[\r\n\]+#3 .* factorial_func \\(value=2\\) at "
+     ".*\[\r\n\]+#4 .* factorial_func \\(value=3\\) at "
+     ".*\[\r\n\]+#5 .* factorial_func \\(value=4\\) at "
+     ".*\[\r\n\]+#6 .* factorial_func \\(value=5\\) at "
+     ".*\[\r\n\]+#7 .* factorial_func \\(value=6\\) at "
+     ".*\[\r\n\]+#8 .* main \\(.*\\) at "
+ }
+ 
+ set post_corefile_regs [capture_command_output "info registers" ""]
+ if ![string compare $pre_corefile_regs $post_corefile_regs] then {
+     pass "corefile restored general registers"
+ } else {
+     fail "corefile restored general registers:\npre: $pre_corefile_regs\npost: $post_corefile_regs\n"
+ }
+ 
+ set post_corefile_allregs [capture_command_output "info all-reg" ""]
+ if ![string compare $pre_corefile_allregs $post_corefile_allregs] then {
+     pass "corefile restored all registers"
+ } else {
+     fail "corefile restored all registers:\npre: $pre_corefile_allregs\npost: $post_corefile_allregs\n"
+ }
+ 
+ set post_corefile_extern_array \
+ 	[capture_command_output "print extern_array" "$print_prefix"]
+ pass "extern_array = $post_corefile_extern_array"
+ if ![string compare $pre_corefile_extern_array $post_corefile_extern_array]  {
+     pass "corefile restored extern array"
+ } else {
+     fail "corefile restored extern array"
+ }
+ 
+ set post_corefile_static_array \
+ 	[capture_command_output "print static_array" "$print_prefix"]
+ pass "static_array = $post_corefile_static_array"
+ if ![string compare $pre_corefile_static_array $post_corefile_static_array]  {
+     pass "corefile restored static array"
+ } else {
+     fail "corefile restored static array"
+ }
+ 
+ set post_corefile_uninit_array \
+ 	[capture_command_output "print un_initialized_array" "$print_prefix"]
+ pass "uninit_array = $post_corefile_uninit_array"
+ if ![string compare $pre_corefile_uninit_array $post_corefile_uninit_array]  {
+     pass "corefile restored un-initialized array"
+ } else {
+     fail "corefile restored un-initialized array"
+ }
+ 
+ set post_corefile_heap_string \
+ 	[capture_command_output "print heap_string" "$print_prefix"]
+ pass "heap_string = $post_corefile_heap_string"
+ if ![string compare $pre_corefile_heap_string $post_corefile_heap_string]  {
+     pass "corefile restored heap array"
+ } else {
+     fail "corefile restored heap array"
+ }
+ 
+ set post_corefile_local_array \
+ 	[capture_command_output "print array_func::local_array" "$print_prefix"]
+ pass "local_array = $post_corefile_local_array"
+ if ![string compare $pre_corefile_local_array $post_corefile_local_array]  {
+     pass "corefile restored stack array"
+ } else {
+     fail "corefile restored stack array"
+ }
+ 
+ set post_corefile_backtrace [capture_command_output "backtrace" ""]
+ if ![string compare $pre_corefile_backtrace $post_corefile_backtrace]  {
+     pass "corefile restored backtrace"
+ } else {
+     fail "corefile restored backtrace"
+ }
Index: testsuite/gdb.base/gcore.c
===================================================================
RCS file: gcore.c
diff -N gcore.c
*** /dev/null	Tue May  5 13:32:27 1998
--- gcore.c	Tue Jan  8 15:52:53 2002
***************
*** 0 ****
--- 1,52 ----
+ /*
+  * Test GDB's ability to save and reload a corefile.
+  */
+ 
+ #include <stdlib.h>
+ 
+ int extern_array[4] = {1, 2, 3, 4};
+ static int static_array[4] = {5, 6, 7, 8};
+ static int un_initialized_array[4];
+ static char *heap_string;
+ 
+ void 
+ terminal_func ()
+ {
+   return;
+ }
+ 
+ void
+ array_func ()
+ {
+   int local_array[4];
+   int i;
+ 
+   heap_string = (char *) malloc (80);
+   strcpy (heap_string, "I'm a little teapot, short and stout...");
+   for (i = 0; i < 4; i++)
+     {
+       un_initialized_array[i] = extern_array[i] + 8;
+       local_array[i] = extern_array[i] + 12;
+     }
+   terminal_func ();
+ }
+ 
+ #ifdef PROTOTYPES
+ int factorial_func (int value)
+ #else
+ int factorial_func (value)
+      int value;
+ #endif
+ {
+   if (value > 1) {
+     value *= factorial_func (value - 1);
+   }
+   array_func ();
+   return (value);
+ }
+ 
+ main()
+ {
+   factorial_func (6);
+   return 0;
+ }
Index: testsuite/gdb.threads/gcore-thread.exp
===================================================================
RCS file: gcore-thread.exp
diff -N gcore-thread.exp
*** /dev/null	Tue May  5 13:32:27 1998
--- gcore-thread.exp	Tue Jan  8 15:52:53 2002
***************
*** 0 ****
--- 1,186 ----
+ # Copyright 2002 Free Software Foundation, Inc.
+ 
+ # 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.  
+ 
+ # Please email any bugs, comments, and/or additions to this file to:
+ # bug-gdb@prep.ai.mit.edu
+ 
+ # This file was written by Michael Snyder (msnyder@redhat.com)
+ # This is a test for the gdb command "generate-core-file".
+ 
+ if $tracelevel then {
+ 	strace $tracelevel
+ }
+ 
+ set prms_id 0
+ set bug_id 0
+ 
+ # Single-threaded test case
+ set testfile "pthreads"
+ set srcfile  ${testfile}.c
+ set binfile  ${objdir}/${subdir}/${testfile}
+ 
+ set built_binfile 0
+ if [istarget "*-*-linux"] then {
+     set target_cflags "-D_MIT_POSIX_THREADS"
+ } else {
+     set target_cflags ""
+ }
+ set why_msg "unrecognized error"
+ foreach lib {-lpthreads -lpthread -lthread} {
+     set options "debug"
+     lappend options "incdir=${objdir}/${subdir}"
+     lappend options "libs=$lib"
+     set ccout [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $options]
+     switch -regexp -- $ccout {
+ 	".*no posix threads support.*" {
+ 	    set why_msg "missing threads include file"
+ 	    break
+ 	}
+ 	".*cannot open -lpthread.*" {
+ 	    set why_msg "missing runtime threads library"
+ 	}
+ 	".*Can't find library for -lpthread.*" {
+ 	    set why_msg "missing runtime threads library"
+ 	}
+ 	{^$} {
+ 	    pass "successfully compiled posix threads test case"
+ 	    set built_binfile 1
+ 	    break
+ 	}
+     }
+ }
+ if {$built_binfile == "0"} {
+     unsupported "Couldn't compile ${srcfile}, ${why_msg}"
+     return -1
+ }
+ 
+ # Now we can proceed with the real testing.
+ 
+ # Start with a fresh gdb.
+ 
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+ 
+ # regexp for "horizontal" text (i.e. doesn't include newline or
+ # carriage return)
+ set horiz "\[^\n\r\]*"
+ 
+ # regexp for newline
+ set nl "\[\r\n\]+"
+ 
+ set timeout 30
+ 
+ send_gdb "help gcore\n"
+ gdb_expect {
+     -re "Undefined command: .gcore.*$gdb_prompt $" {
+ 	# gcore command not supported -- nothing to test here.
+ 	unsupported "gdb does not support gcore on this target"
+ 	return -1;
+     }
+     -re "Save a core file .*$gdb_prompt $" {
+ 	pass "help gcore"
+     }
+     -re ".*$gdb_prompt $" {
+ 	fail "help gcore"
+     }
+     timeout {
+ 	fail "help gcore (timeout)"
+     }
+ }
+ 
+ if { ! [ runto main ] } then {
+     gdb_suppress_entire_file "Run to main failed, so all tests in this file will automatically fail."
+ }
+ 
+ send_gdb "info threads\n"
+ gdb_expect {
+     -re ".* main .*$gdb_prompt $" {
+ 	# OK, threads are supported.
+     }
+     -re "${nl}$gdb_prompt $" {
+ 	unsupported "gdb does not support threads on this target"
+ 	return -1;
+     }
+ }
+ 
+ # Make sure thread 1 is running
+ delete_breakpoints
+ gdb_breakpoint "thread1"
+ gdb_test "continue" "Continuing.*Breakpoint.* thread1 .*" "thread 1 is running"
+ 
+ # Make sure thread 2 is running
+ delete_breakpoints
+ gdb_breakpoint "thread2"
+ gdb_test "continue" "Continuing.*Breakpoint.* thread2 .*" "thread 2 is running"
+ 
+ # Drop corefile
+ gdb_test "gcore ${objdir}/${subdir}/gcore.test" \
+ 	"Saved corefile ${objdir}/${subdir}/gcore.test" \
+ 	"save a corefile"
+ 
+ # Now restart gdb and load the corefile.
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+ 
+ send_gdb "core ${objdir}/${subdir}/gcore.test\n"
+ gdb_expect {
+     -re ".* is not a core dump:.*$gdb_prompt $" {
+ 	fail "re-load generated corefile (bad file format)"
+ 	# No use proceeding from here.
+ 	return;	
+     }
+     -re ".*: No such file or directory.*$gdb_prompt $" {
+ 	fail "re-load generated corefile (file not found)"
+ 	# No use proceeding from here.
+ 	return;	
+     }
+     -re ".*Couldn't find .* registers in core file.*$gdb_prompt $" {
+ 	fail "re-load generated corefile (incomplete note section)"
+     }
+     -re "Core was generated by .*$gdb_prompt $" {
+ 	pass "re-load generated corefile"
+     }
+     -re ".*$gdb_prompt $" {
+ 	fail "re-load generated corefile"
+     }
+     timeout {
+ 	fail "re-load generated corefile (timeout)"
+     }
+ }
+ 
+ # FIXME: now what can we test about the thread state?
+ # We do not know for certain that there should be at least 
+ # three threads, because who knows what kind of many-to-one
+ # mapping various OS's may do?  Let's assume that there must
+ # be at least two threads:
+ 
+ gdb_test "info threads" ".*${nl}  2 ${horiz}${nl}\\* 1 .*" \
+ 	"corefile contains at least two threads"
+ 
+ # One thread in the corefile should be in the "thread2" function.
+ 
+ gdb_test "info threads" ".* thread2 .*" \
+ 	"a corefile thread is executing thread2"
+ 
+ # The thread2 thread should be marked as the current thread.
+ 
+ gdb_test "info threads" ".*${nl}\\* ${horiz} thread2 .*" \
+ 	"thread2 is current thread in corefile"
+ 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]