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]

[RFA] New "generate-core-file" command, supercedes previous


OK, this submission supercedes the previous one for the gcore command.
The command is now called "generate-core-files", with gcore as an alias.

This patch can now generate multi-threaded corefiles both on solaris
and on linux.  The host makefile fragments for sparc-solaris and for
i386-linux have been updated to bring in the new code.  The new code
will not affect any other targets until their makefile fragmemts are
modified to pull it in.  It should work as-is for any flavor of 
Solaris or Linux, but I've only tested sparc and i386 respectively.

As before, there is a patch for bfd appended, which has not yet
been approved by the bfd/binutils maintainers.

I'm now ready to formally request approval -- though there's still
room for improvement, I believe it's mature enough to check in.


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-gcore.c: New file.  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 and linux-gcore.o to NATDEPFILES.
	* config/sparc/sun4sol2.mh: Add gcore.o to NATDEPFILES.

2001-12-30  Michael Snyder  <msnyder@redhat.com>

	* gdb.base/huge.exp: New test.  Print a very large target data object.
	(skip_huge_test): New test variable.  Define if you want to skip this
	test.  The test reads an 8 megabyte data object from the target, so it
	might be very time consuming on remote targets with a slow connection.
	* gdb.base/huge.c: New file.  Test case for above.

Index: gcore.c
===================================================================
RCS file: gcore.c
diff -N gcore.c
*** /dev/null	Tue May  5 13:32:27 1998
--- gcore.c	Thu Jan  3 17:38:42 2002
***************
*** 0 ****
--- 1,476 ----
+ /* Generate a core file for the inferior process.
+    Copyright 2001 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, 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 ()));
+ 	}
+     }
+   /* Clean-ups will close the output file and free malloc memory. */
+   do_cleanups (old_chain);
+   return;
+ }
+ 
+ static unsigned long
+ default_gcore_mach (void)
+ {
+   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)
+ {
+   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;
+   value_ptr 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: linux-gcore.c
===================================================================
RCS file: linux-gcore.c
diff -N linux-gcore.c
*** /dev/null	Tue May  5 13:32:27 1998
--- linux-gcore.c	Thu Jan  3 17:38:42 2002
***************
*** 0 ****
--- 1,218 ----
+ /* Generate a core file for the inferior process -- Linux version.
+    Copyright 2001 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 "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. */
+ 
+ 
+ /* Function: linux_find_memory_regions
+  */
+ 
+ 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[80];
+   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");
+ 	}
+     }
+ 
+   return 0;
+ }
+ 
+ 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;
+   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));
+   return note_data;
+ }
+ 
+ struct linux_corefile_thread_data {
+   bfd  *obfd;
+   char *note_data;
+   int  *note_size;
+ };
+ 
+ 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;
+ }
+ 
+ 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_gcore (void)
+ {
+   inftarg_set_find_memory_regions (linux_find_memory_regions);
+   inftarg_set_make_corefile_notes (linux_make_note_section);
+ }
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/04 01:38:42
*************** 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: 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/04 01:38:42
*************** 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,5817 ----
  {
    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);
+   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/04 01:38:42
*************** 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: 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/04 01:38:42
*************** update_current_target (void)
*** 607,612 ****
--- 607,614 ----
        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 ****
--- 1463,1484 ----
    /* 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 ****
--- 1495,1502 ----
    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/04 01:38:42
*************** 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: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.69
diff -c -3 -p -r1.69 defs.h
*** defs.h	2001/12/21 22:32:37	1.69
--- defs.h	2002/01/04 01:38:42
*************** extern void exec_set_section_offsets (bf
*** 775,780 ****
--- 775,787 ----
  				      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: 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/04 01:38:42
*************** init_child_ops (void)
*** 812,817 ****
--- 812,835 ----
    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: thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/thread-db.c,v
retrieving revision 1.18
diff -c -3 -p -r1.18 thread-db.c
*** thread-db.c	2001/10/13 15:04:02	1.18
--- thread-db.c	2002/01/04 01:38:43
*************** thread_db_new_objfile (struct objfile *o
*** 482,487 ****
--- 482,490 ----
  {
    td_err_e err;
  
+   if (!target_has_execution)
+     goto quit;	/* may be a corefile? */
+ 
    if (objfile == NULL)
      {
        /* All symbols have been discarded.  If the thread_db target is
Index: config/i386/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux.mh,v
retrieving revision 1.8
diff -c -3 -p -r1.8 linux.mh
*** linux.mh	2001/07/31 19:22:57	1.8
--- linux.mh	2002/01/04 01:38:43
*************** XDEPFILES=
*** 6,12 ****
  NAT_FILE= nm-linux.h
  NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
  	core-aout.o i386-nat.o i386-linux-nat.o i387-nat.o \
! 	proc-service.o thread-db.o lin-lwp.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 \
  	core-aout.o i386-nat.o i386-linux-nat.o i387-nat.o \
! 	proc-service.o thread-db.o lin-lwp.o gcore.o linux-gcore.o
  
  # The dynamically loaded libthread_db needs access to symbols in the
  # gdb executable.
Index: config/sparc/sun4sol2.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/sun4sol2.mh,v
retrieving revision 1.5
diff -c -3 -p -r1.5 sun4sol2.mh
*** sun4sol2.mh	2001/03/10 06:17:24	1.5
--- sun4sol2.mh	2002/01/04 01:38:43
*************** XM_CLIBS= -lsocket -lnsl
*** 6,12 ****
  
  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
  
  # /usr/include/v9 is needed only by core-sol2.c when including 
  # v9/sys/privregs.h, or rather the headers it in turn includes.
--- 6,13 ----
  
  NAT_FILE= nm-sun4sol2.h
  NATDEPFILES= corelow.o core-sol2.o solib.o solib-svr4.o solib-legacy.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: testsuite/gdb.base/huge.c
===================================================================
RCS file: huge.c
diff -N huge.c
*** /dev/null	Tue May  5 13:32:27 1998
--- huge.c	Thu Jan  3 17:38:43 2002
***************
*** 0 ****
--- 1,19 ----
+ /*
+  * Test GDB's ability to read a very large data object from target memory.
+  */
+ 
+ /* 
+  * A value that will produce a target data object 
+  * large enough to crash GDB.  0x200000 is big enough
+  * on Linux, other systems may need a larger number.
+  */
+ 
+ #define CRASH_GDB 0x200000
+ 
+ static int a[CRASH_GDB], b[CRASH_GDB];
+ 
+ main()
+ {
+   memcpy (a, b, sizeof (a));
+   return 0;
+ }
Index: testsuite/gdb.base/huge.exp
===================================================================
RCS file: huge.exp
diff -N huge.exp
*** /dev/null	Tue May  5 13:32:27 1998
--- huge.exp	Thu Jan  3 17:38:43 2002
***************
*** 0 ****
--- 1,57 ----
+ # Copyright 2001 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)
+ 
+ if $tracelevel then {
+ 	strace $tracelevel
+ }
+ 
+ set prms_id 0
+ set bug_id 0
+ 
+ # Define if you want to skip this test
+ # (could be very time-consuming on remote targets with slow connection).
+ #
+ if [target_info exists gdb,skip_huge_test] {
+     return;
+ }
+ 
+ set testfile "huge"
+ 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}
+ 
+ set timeout 30
+ 
+ if { ! [ runto main ] } then {
+     gdb_suppress_entire_file "Run to main failed, so all tests in this file will automatically fail."
+ }
+ 
+ gdb_test "print a" ".1 = .0 .repeats \[0123456789\]+ times.." "print a very large data object"
+ 

2001-12-26  Michael Snyder  <msnyder@redhat.com>

	Add capability to write corefile note sections, for gdb.
	* elf.c (elfcore_write_note): New function.
	(elfcore_write_prpsinfo): New function.
	(elfcore_write_prstatus): New function.
	(elfcore_write_pstatus): New function.
	(elfcore_write_prfpreg): New function.

Index: elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.117
diff -c -3 -p -r1.117 elf.c
*** elf.c	2001/12/19 05:16:47	1.117
--- elf.c	2001/12/26 20:14:02
*************** elfcore_grok_netbsd_note (abfd, note)
*** 6485,6490 ****
--- 6485,6621 ----
          }
      }
      /* NOTREACHED */
+ }
+ 
+ /* Function: elfcore_write_note
+ 
+    Inputs: 
+      buffer to hold note
+      name of note
+      type of note
+      data for note
+      size of data for note
+ 
+    Return:
+    End of buffer containing note.  */
+ 
+ char *elfcore_write_note (bfd *, char *, int *, char *, int, void *, int);
+ 
+ char *
+ elfcore_write_note (abfd, buf, bufsiz, name, type, input, size)
+      bfd  *abfd;
+      char *buf;
+      int  *bufsiz;
+      char *name;
+      int  type;
+      void *input;
+      int  size;
+ {
+   Elf_External_Note *xnp;
+   int namesz = strlen (name);
+   int newspace = BFD_ALIGN (sizeof (Elf_External_Note) + size + namesz - 1, 4);
+   char *p, *dest;
+ 
+   p = realloc (buf, *bufsiz + newspace);
+   dest = p + *bufsiz;
+   *bufsiz += newspace;
+   xnp = (Elf_External_Note *) dest;
+   H_PUT_32 (abfd, namesz, xnp->namesz);
+   H_PUT_32 (abfd, size, xnp->descsz);
+   H_PUT_32 (abfd, type, xnp->type);
+   strcpy (xnp->name, name);
+   memcpy (xnp->name + BFD_ALIGN (namesz, 4), input, size);
+   return p;
+ }
+ 
+ #if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+ char *elfcore_write_prpsinfo (bfd *, char *, int *, char *, char *);
+ 
+ char *
+ elfcore_write_prpsinfo (abfd, buf, bufsiz, fname, psargs)
+      bfd  *abfd;
+      char *buf;
+      int  *bufsiz;
+      char *fname; 
+      char *psargs;
+ {
+   int note_type;
+   char *note_name = "CORE";
+ 
+ #if defined (HAVE_PSINFO_T)
+   psinfo_t  data;
+   note_type = NT_PSINFO;
+ #else
+   prpsinfo_t data;
+   note_type = NT_PRPSINFO;
+ #endif
+ 
+   memset (&data, 0, sizeof (data));
+   strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+   strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+   return elfcore_write_note (abfd, buf, bufsiz, 
+ 			     note_name, note_type, &data, sizeof (data));
+ }
+ #endif	/* PSINFO_T or PRPSINFO_T */
+ 
+ #if defined (HAVE_PRSTATUS_T)
+ char *elfcore_write_prstatus (bfd *, char *, int *, pid_t, int, void *);
+ 
+ char *
+ elfcore_write_prstatus (abfd, buf, bufsiz, pid, cursig, gregs)
+      bfd *abfd;
+      char *buf;
+      int *bufsiz;
+      pid_t pid;
+      int cursig;
+      void *gregs;
+ {
+   prstatus_t prstat;
+   char *note_name = "CORE";
+ 
+   memset (&prstat, 0, sizeof (prstat));
+   prstat.pr_pid = pid;
+   prstat.pr_cursig = cursig;
+   memcpy (prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+   return elfcore_write_note (abfd, buf, bufsiz, 
+ 			     note_name, NT_PRSTATUS, &prstat, sizeof (prstat));
+ }
+ #endif /* HAVE_PRSTATUS_T */
+ 
+ #if defined (HAVE_PSTATUS_T)
+ char *
+ elfcore_write_pstatus (abfd, buf, bufsiz, pid, cursig, gregs)
+      bfd *abfd;
+      char *buf;
+      int *bufsiz;
+      pid_t pid;
+      int cursig;
+      void *gregs;
+ {
+   pstatus_t pstat;
+   char *note_name = "CORE";
+ 
+   memset (&pstat, 0, sizeof (prstat));
+   pstat.pr_pid = pid;
+   memcpy (pstat.pr_reg, gregs, sizeof (pstat.pr_reg));
+   return elfcore_write_note (abfd, buf, bufsiz, 
+ 			     note_name, NT_PSTATUS, &pstat, sizeof (pstat));
+ }
+ #endif /* HAVE_PSTATUS_T */
+ 
+ char *elfcore_write_prfpreg (bfd *, char *, int *, void *, int);
+ 
+ char *
+ elfcore_write_prfpreg (abfd, buf, bufsiz, fpregs, size)
+      bfd  *abfd;
+      char *buf;
+      int  *bufsiz;
+      void *fpregs;
+      int size;
+ {
+   char *note_name = "CORE";
+   return elfcore_write_note (abfd, buf, bufsiz, 
+ 			     note_name, NT_FPREGSET, fpregs, size);
  }
  
  static boolean


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