[RFA/RFC] New GDB command for dropping a 'child' corefile

Michael Snyder msnyder@cygnus.com
Fri Dec 28 16:13:00 GMT 2001


This is quite a big patch, so I wanted to get it out in front of
people early, even though it's a little bit preliminary.

The idea is to implement a general method for allowing GDB to create a
corefile image of the current state of the child process.  There are,
of course, lots of ways of doing that, so this is just a start, with
hopefully enough built-in flexability to be extended to other
platforms as we go.

For instance, I've only implemented ELF corefiles, but there is no
special elfishness in the main gcore.c module: just generic bfd calls.
If there turns out to be conflict with other flavors of corefile, we
may have to split out an elf-gcore module from a (say) som-gcore
module -- but I'm hopeful that elf will serve well enough for a
variety of targets.

I've also only done a full implementation for /proc systems, but I
hope to have an implementation for linux soon, and I'm hopeful that
what I've done will extend well to other systems, including even
embedded and simulator systems.  This patch does include a general
method for deducing the mapped memory regions from symbol information
(without any kernel help), which should be useful for non-procfs
systems.  Again, I'm putting this out early in order to get early
comments and feedback.

This patch includes another patch to procfs.c which I've just
submitted today (which hasn't been approved or checked in yet).
I can resubmit this patch separately after that patch goes in.

This patch also includes a patch to the bfd library which I've
submitted separately to the binutils maintainers.  That part
isn't necessarily to be approved here (though feedback is
welcome): it's in here for completeness.

Using this code, I've been able to drop a corefile from a running
child process on Solaris 2.6, which was very similar to a corefile
generated by the kernel.  I was then able to load the corefile into
GDB and debug the saved process state, just like I would with a
kernel-generated corefile (including the symbols and memory from
shared libraries).

Questions and comments eagerly awaited.

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

	Add 'gcore' command for creating a corefile image of the inferior.
	* gcore.c: New file.
	* target.h (to_find_memory_regions): New target vector for gcore.
	(to_make_corefile_notes): Ditto.
	(target_find_memory_regions): New macro.
	(target_make_corefile_notes): Ditto.
	* target.c (update_current_target): Inherit new target_ops vectors.
	(dummy_find_memory_regions): New place-holder method.
	(dummy_make_corefile_notes): Ditto.
	(init_dummy_target): Set new dummy target vectors.
	* exec.c (exec_set_find_memory_regions): New function.
	Allow exec_ops target vector to be set from outside.
	(exec_make_note_section): New method (minimal implementation).
	(init_exec_ops): Make static.  Set new target vectors.
	* defs.h (exec_set_find_memory_regions): Export.
	* procfs.c (proc_find_memory_regions): New target method.
	(find_memory_regions_callback): New function, callback for above.
	(procfs_make_note_section): New target method.
	(init_procfs_ops): Set new target vectors.
	
	Abstract the functionality of iterating over mapped memory
	regions into a general purpose iterator function.
	* procfs.c (iterate_over_mappings): New function, general purpose 
	iterator for memory sections.
	(proc_iterate_over_mappings): Reimplement using iterate_over_mappings.
	(solib_mappings_callback): New function, callback for above.
	(info_proc_mappings): Reimpliment using iterate_over_mappings.
	(info_mappings_callback): New function, callback for above.

	* procfs.c (proc_set_watchpoint): Add cast to suppress warning.

Index: gcore.c
===================================================================
RCS file: gcore.c
diff -N gcore.c
*** /dev/null	Tue May  5 13:32:27 1998
--- gcore.c	Fri Dec 28 15:46:21 2001
***************
*** 0 ****
--- 1,473 ----
+ /* 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)
+     printf_filtered ("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 ("gcore", class_files, gcore_command,
+ 	   "Save a core file with the current state of the debugged process.");
+ 
+   exec_set_find_memory_regions (objfile_find_memory_regions);
+ }
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	2001/12/28 23:46:21
*************** 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: 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	2001/12/28 23:46:21
*************** 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: 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	2001/12/28 23:46:22
*************** 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: 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	2001/12/28 23:46:22
*************** 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.33
diff -c -3 -p -r1.33 procfs.c
*** procfs.c	2001/12/28 19:47:08	1.33
--- procfs.c	2001/12/28 23:46:22
*************** 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_set_watchpoint (procinfo *pi, CORE_
*** 2848,2854 ****
    prwatch_t *pwatch;
  
    pwatch            = (prwatch_t *) &arg.watch;
!   pwatch->pr_vaddr  = address_to_host_pointer (addr);
    pwatch->pr_size   = len;
    pwatch->pr_wflags = wflags;
  #if defined(NEW_PROC_API) && defined (PCWATCH)
--- 2858,2868 ----
    prwatch_t *pwatch;
  
    pwatch            = (prwatch_t *) &arg.watch;
! #ifdef PCAGENT	/* Horrible hack: only defined on Solaris 2.6+ */
!   pwatch->pr_vaddr  = (uintptr_t) address_to_host_pointer (addr);
! #else
!   pwatch->pr_vaddr  = (caddr_t) address_to_host_pointer (addr);
! #endif
    pwatch->pr_size   = len;
    pwatch->pr_wflags = wflags;
  #if defined(NEW_PROC_API) && defined (PCWATCH)
*************** proc_set_watchpoint (procinfo *pi, CORE_
*** 2865,2979 ****
  #endif
  }
  
- /*
-  * Function: proc_iterate_over_mappings
-  *
-  * Given a pointer to a function, call that function once for every
-  * mapped address space in the process.  The callback function 
-  * receives an open file descriptor for the file corresponding to
-  * that mapped address space (if there is one), and the base address
-  * of the mapped space.  Quit when the callback function returns a
-  * nonzero value, or at teh end of the mappings.
-  *
-  * Returns: the first non-zero return value of the callback function,
-  * or zero.
-  */
- 
- int
- proc_iterate_over_mappings (int (*func) (int, CORE_ADDR))
- {
-   struct prmap *map;
-   procinfo *pi;
- #ifndef NEW_PROC_API	/* avoid compiler warning */
-   int nmaps = 0;
-   int i;
- #else
-   int map_fd;
-   char pathname[MAX_PROC_NAME_SIZE];
- #endif
-   int funcstat = 0;
-   int fd;
- 
-   pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
- 
- #ifdef NEW_PROC_API
-   /* Open map fd.  */
-   sprintf (pathname, "/proc/%d/map", pi->pid);
-   if ((map_fd = open_with_retry (pathname, O_RDONLY)) < 0)
-     proc_error (pi, "proc_iterate_over_mappings (open)", __LINE__);
- 
-   /* Make sure it gets closed again.  */
-   make_cleanup_close (map_fd);
- 
-   /* Allocate space for mapping (lifetime only for this function). */
-   map = alloca (sizeof (struct prmap));
- 
-   /* Now read the mappings from the file, 
-      open a file descriptor for those that have a name, 
-      and call the callback function.  */
-   while (read (map_fd, 
- 	       (void *) map, 
- 	       sizeof (struct prmap)) == sizeof (struct prmap))
-     {
-       char name[MAX_PROC_NAME_SIZE + sizeof (map->pr_mapname)];
- 
-       if (map->pr_vaddr == 0 && map->pr_size == 0)
- 	break;		/* sanity */
- 
-       if (map->pr_mapname[0] == 0)
- 	{
- 	  fd = -1;	/* no map file */
- 	}
-       else
- 	{
- 	  sprintf (name, "/proc/%d/object/%s", pi->pid, map->pr_mapname);
- 	  /* Note: caller's responsibility to close this fd!  */
- 	  fd = open_with_retry (name, O_RDONLY);
- 	  /* Note: we don't test the above call for failure;
- 	     we just pass the FD on as given.  Sometimes there is 
- 	     no file, so the ioctl may return failure, but that's
- 	     not a problem.  */
- 	}
- 
-       /* Stop looping if the callback returns non-zero.  */
-       if ((funcstat = (*func) (fd, (CORE_ADDR) map->pr_vaddr)) != 0)
- 	break;
-     }  
- #else
-   /* Get the number of mapping entries.  */
-   if (ioctl (pi->ctl_fd, PIOCNMAP, &nmaps) < 0)
-     proc_error (pi, "proc_iterate_over_mappings (PIOCNMAP)", __LINE__);
- 
-   /* Allocate space for mappings (lifetime only this function).  */
-   map = (struct prmap *) alloca ((nmaps + 1) * sizeof (struct prmap));
- 
-   /* Read in all the mappings.  */
-   if (ioctl (pi->ctl_fd, PIOCMAP, map) < 0)
-     proc_error (pi, "proc_iterate_over_mappings (PIOCMAP)", __LINE__);
- 
-   /* Now loop through the mappings, open an fd for each, and
-      call the callback function.  */
-   for (i = 0; 
-        i < nmaps && map[i].pr_size != 0; 
-        i++)
-     {
-       /* Note: caller's responsibility to close this fd!  */
-       fd = ioctl (pi->ctl_fd, PIOCOPENM, &map[i].pr_vaddr);
-       /* Note: we don't test the above call for failure;
- 	 we just pass the FD on as given.  Sometimes there is 
- 	 no file, so the ioctl may return failure, but that's
- 	 not a problem.  */
- 
-       /* Stop looping if the callback returns non-zero.  */
-       funcstat = (*func) (fd, host_pointer_to_address (map[i].pr_vaddr));
-       if (funcstat != 0)
- 	break;
-     }
- #endif
- 
-   return funcstat;
- }
- 
  #ifdef TM_I386SOL2_H		/* Is it hokey to use this? */
  
  #include <sys/sysi86.h>
--- 2879,2884 ----
*************** procfs_find_LDT_entry (ptid_t ptid)
*** 5308,5313 ****
--- 5213,5429 ----
  #endif /* TM_I386SOL2_H */
  
  /*
+  * Memory Mappings Functions:
+  */
+ 
+ /* 
+  * Function: iterate_over_mappings
+  *
+  * Call a callback function once for each mapping, passing it the mapping,
+  * an optional secondary callback function, and some optional opaque data.
+  * Quit and return the first non-zero value returned from the callback.
+  *
+  * Arguments:
+  *   pi   -- procinfo struct for the process to be mapped.
+  *   func -- callback function to be called by this iterator.
+  *   data -- optional opaque data to be passed to the callback function.
+  *   child_func -- optional secondary function pointer to be passed
+  *                 to the child function.
+  *
+  * Return: First non-zero return value from the callback function, 
+  *         or zero.
+  */
+ 
+ static int
+ iterate_over_mappings (procinfo *pi, int (*child_func) (), void *data, 
+ 		       int (*func) (struct prmap *map, 
+ 				    int (*child_func) (), 
+ 				    void *data))
+ {
+   char pathname[MAX_PROC_NAME_SIZE];
+   struct prmap *prmaps;
+   struct prmap *prmap;
+   int funcstat;
+   int map_fd;
+   int nmap;
+ #ifdef NEW_PROC_API
+   struct stat sbuf;
+ #endif
+ 
+   /* Get the number of mappings, allocate space, 
+      and read the mappings into prmaps.  */
+ #ifdef NEW_PROC_API
+   /* Open map fd. */
+   sprintf (pathname, "/proc/%d/map", pi->pid);
+   if ((map_fd = open (pathname, O_RDONLY)) < 0)
+     proc_error (pi, "iterate_over_mappings (open)", __LINE__);
+ 
+   /* Make sure it gets closed again. */
+   make_cleanup_close (map_fd);
+ 
+   /* Use stat to determine the file size, and compute 
+      the number of prmap_t objects it contains.  */
+   if (fstat (map_fd, &sbuf) != 0)
+     proc_error (pi, "iterate_over_mappings (fstat)", __LINE__);
+ 
+   nmap = sbuf.st_size / sizeof (prmap_t);
+   prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
+   if (read (map_fd, (char *) prmaps, nmap * sizeof (*prmaps))
+       != (nmap * sizeof (*prmaps)))
+     proc_error (pi, "iterate_over_mappings (read)", __LINE__);
+ #else
+   /* Use ioctl command PIOCNMAP to get number of mappings.  */
+   if (ioctl (pi->ctl_fd, PIOCNMAP, &nmap) != 0)
+     proc_error (pi, "iterate_over_mappings (PIOCNMAP)", __LINE__);
+ 
+   prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
+   if (ioctl (pi->ctl_fd, PIOCMAP, prmaps) != 0)
+     proc_error (pi, "iterate_over_mappings (PIOCMAP)", __LINE__);
+ #endif
+ 
+   for (prmap = prmaps; nmap > 0; prmap++, nmap--)
+     if ((funcstat = (*func) (prmap, child_func, data)) != 0)
+       return funcstat;
+ 
+   return 0;
+ }
+ 
+ /*
+  * Function: solib_mappings_callback
+  *
+  * Calls the supplied callback function once for each mapped address 
+  * space in the process.  The callback function  receives an open 
+  * file descriptor for the file corresponding to that mapped 
+  * address space (if there is one), and the base address of the 
+  * mapped space.  Quit when the callback function returns a
+  * nonzero value, or at teh end of the mappings.
+  *
+  * Returns: the first non-zero return value of the callback function,
+  * or zero.
+  */
+ 
+ int solib_mappings_callback (struct prmap *map, 
+ 			     int (*func) (int, CORE_ADDR),
+ 			     void *data)
+ {
+   procinfo *pi = data;
+   int fd;
+ 
+ #ifdef NEW_PROC_API
+   char name[MAX_PROC_NAME_SIZE + sizeof (map->pr_mapname)];
+ 
+   if (map->pr_vaddr == 0 && map->pr_size == 0)
+     return -1;		/* sanity */
+ 
+   if (map->pr_mapname[0] == 0)
+     {
+       fd = -1;	/* no map file */
+     }
+   else
+     {
+       sprintf (name, "/proc/%d/object/%s", pi->pid, map->pr_mapname);
+       /* Note: caller's responsibility to close this fd!  */
+       fd = open_with_retry (name, O_RDONLY);
+       /* Note: we don't test the above call for failure;
+ 	 we just pass the FD on as given.  Sometimes there is 
+ 	 no file, so the open may return failure, but that's
+ 	 not a problem.  */
+     }
+ #else
+   fd = ioctl (pi->ctl_fd, PIOCOPENM, &map->pr_vaddr);
+   /* Note: we don't test the above call for failure;
+      we just pass the FD on as given.  Sometimes there is 
+      no file, so the ioctl may return failure, but that's
+      not a problem.  */
+ #endif
+   return (*func) (fd, (CORE_ADDR) map->pr_vaddr);
+ }
+ 
+ /*
+  * Function: proc_iterate_over_mappings
+  *
+  * Uses the unified "iterate_over_mappings" function
+  * to implement the exported interface to solib-svr4.c.
+  *
+  * Given a pointer to a function, call that function once for every
+  * mapped address space in the process.  The callback function 
+  * receives an open file descriptor for the file corresponding to
+  * that mapped address space (if there is one), and the base address
+  * of the mapped space.  Quit when the callback function returns a
+  * nonzero value, or at teh end of the mappings.
+  *
+  * Returns: the first non-zero return value of the callback function,
+  * or zero.
+  */
+ 
+ int
+ proc_iterate_over_mappings (int (*func) (int, CORE_ADDR))
+ {
+   procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ 
+   return iterate_over_mappings (pi, func, pi, solib_mappings_callback);
+ }
+ 
+ /*
+  * Function: find_memory_regions_callback
+  *
+  * Implements the to_find_memory_regions method.
+  * Calls an external function for each memory region.
+  * External function will have the signiture:
+  *
+  *   int callback (CORE_ADDR vaddr, 
+  *                 unsigned long size, 
+  *                 int read, int write, int execute, 
+  *                 void *data);
+  *
+  * Returns the integer value returned by the callback.
+  */
+ 
+ static int
+ find_memory_regions_callback (struct prmap *map, 
+ 			      int (*func) (CORE_ADDR, 
+ 					   unsigned long, 
+ 					   int, int, int, 
+ 					   void *),
+ 			      void *data)
+ {
+   return (*func) (host_pointer_to_address ((void *) map->pr_vaddr),
+ 		  map->pr_size, 
+ 		  (map->pr_mflags & MA_READ) != 0,
+ 		  (map->pr_mflags & MA_WRITE) != 0,
+ 		  (map->pr_mflags & MA_EXEC) != 0, 
+ 		  data);
+ }
+ 
+ /*
+  * Function: proc_find_memory_regions
+  *
+  * External interface.  Calls a callback function once for each
+  * mapped memory region in the child process, passing as arguments
+  *	CORE_ADDR virtual_address,
+  *	unsigned long size, 
+  *	int read, 	TRUE if region is readable by the child
+  *	int write, 	TRUE if region is writable by the child
+  *	int execute	TRUE if region is executable by the child.
+  * 
+  * Stops iterating and returns the first non-zero value
+  * returned by the callback.
+  */
+ 
+ static int
+ proc_find_memory_regions (int (*func) (CORE_ADDR, 
+ 				       unsigned long, 
+ 				       int, int, int, 
+ 				       void *), 
+ 			  void *data)
+ {
+   procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ 
+   return iterate_over_mappings (pi, func, data, 
+ 				find_memory_regions_callback);
+ }
+ 
+ /*
   * Function: mappingflags
   *
   * Returns an ascii representation of a memory mapping's flags.
*************** mappingflags (flags)
*** 5340,5345 ****
--- 5456,5492 ----
  }
  
  /*
+  * Function: info_mappings_callback
+  *
+  * Callback function, does the actual work for 'info proc mappings'.
+  */
+ 
+ /* ARGSUSED */
+ static int
+ info_mappings_callback (struct prmap *map, int (*ignore) (), void *unused)
+ {
+   char *data_fmt_string;
+ 
+   if (TARGET_ADDR_BIT == 32)
+     data_fmt_string   = "\t%#10lx %#10lx %#10x %#10x %7s\n";
+   else
+     data_fmt_string   = "  %#18lx %#18lx %#10x %#10x %7s\n";
+ 
+   printf_filtered (data_fmt_string, 
+ 		   (unsigned long) map->pr_vaddr,
+ 		   (unsigned long) map->pr_vaddr + map->pr_size - 1,
+ 		   map->pr_size,
+ #ifdef PCAGENT	/* Horrible hack: only defined on Solaris 2.6+ */
+ 		   (unsigned int) map->pr_offset, 
+ #else
+ 		   map->pr_off,
+ #endif
+ 		   mappingflags (map->pr_mflags));
+ 
+   return 0;
+ }
+ 
+ /*
   * Function: info_proc_mappings
   *
   * Implement the "info proc mappings" subcommand.
*************** mappingflags (flags)
*** 5348,5406 ****
  static void
  info_proc_mappings (procinfo *pi, int summary)
  {
!   char *header_fmt_string, *data_fmt_string;
!   char pathname[MAX_PROC_NAME_SIZE];
!   struct prmap *prmaps;
!   struct prmap *prmap;
!   int map_fd;
!   int nmap;
! #ifdef NEW_PROC_API
!   struct stat sbuf;
! #endif
  
    if (TARGET_PTR_BIT == 32)
!     {
!       header_fmt_string = "\t%10s %10s %10s %10s %7s\n";
!       data_fmt_string   = "\t%#10lx %#10lx %#10x %#10x %7s\n";
!     }
    else
!     {
!       header_fmt_string = "  %18s %18s %10s %10s %7s\n";
!       data_fmt_string   = "  %#18lx %#18lx %#10x %#10x %7s\n";
!     }
  
    if (summary)
      return;	/* No output for summary mode. */
  
-   /* Get the number of mappings, allocate space, 
-      and read the mappings into prmaps.  */
- #ifdef NEW_PROC_API
-   /* Open map fd. */
-   sprintf (pathname, "/proc/%d/map", pi->pid);
-   if ((map_fd = open (pathname, O_RDONLY)) < 0)
-     return;		/* Can't open map file. */
-   /* Make sure it gets closed again. */
-   make_cleanup_close (map_fd);
- 
-   /* Use stat to determine the file size, and compute 
-      the number of prmap_t objects it contains.  */
-   if (fstat (map_fd, &sbuf) != 0)
-     return;		/* Can't stat file.  */
- 
-   nmap = sbuf.st_size / sizeof (prmap_t);
-   prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
-   if (read (map_fd, (char *) prmaps, nmap * sizeof (*prmaps))
-       != (nmap * sizeof (*prmaps)))
-     return;		/* Can't read file. */
- #else
-   /* Use ioctl command PIOCNMAP to get number of mappings.  */
-   if (ioctl (pi->ctl_fd, PIOCNMAP, &nmap) != 0)
-     return;	/* Can't get number of mappings.  */
-   prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
-   if (ioctl (pi->ctl_fd, PIOCMAP, prmaps) != 0)
-     return;	/* Can't read mappings. */
- #endif
- 
    printf_filtered ("Mapped address spaces:\n\n");
    printf_filtered (header_fmt_string, 
  		   "Start Addr",
--- 5495,5510 ----
  static void
  info_proc_mappings (procinfo *pi, int summary)
  {
!   char *header_fmt_string;
  
    if (TARGET_PTR_BIT == 32)
!     header_fmt_string = "\t%10s %10s %10s %10s %7s\n";
    else
!     header_fmt_string = "  %18s %18s %10s %10s %7s\n";
  
    if (summary)
      return;	/* No output for summary mode. */
  
    printf_filtered ("Mapped address spaces:\n\n");
    printf_filtered (header_fmt_string, 
  		   "Start Addr",
*************** info_proc_mappings (procinfo *pi, int su
*** 5409,5428 ****
  		   "    Offset",
  		   "Flags");
  
!   for (prmap = prmaps; nmap > 0; prmap++, nmap--)
!     {
!       printf_filtered (data_fmt_string, 
! 		       (unsigned long) prmap->pr_vaddr,
! 		       (unsigned long) prmap->pr_vaddr
! 		       + prmap->pr_size - 1,
! 		       prmap->pr_size,
! #ifdef PCAGENT		/* Gross hack: only defined on Solaris 2.6+ */
! 		       (unsigned int) prmap->pr_offset, 
! #else
! 		       prmap->pr_off,
! #endif
! 		       mappingflags (prmap->pr_mflags));
!     }
    printf_filtered ("\n");
  }
  
--- 5513,5519 ----
  		   "    Offset",
  		   "Flags");
  
!   iterate_over_mappings (pi, NULL, NULL, info_mappings_callback);
    printf_filtered ("\n");
  }
  
*************** procfs_first_available (void)
*** 5628,5630 ****
--- 5719,5775 ----
  {
    return pid_to_ptid (procinfo_list ? procinfo_list->pid : -1);
  }
+ 
+ /* ===================  GCORE .NOTE "MODULE" =================== */
+ 
+ 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;
+ 
+   fill_gregset (&gregs, -1);
+   note_data = (char *) elfcore_write_prstatus (obfd, 
+ 					       note_data, 
+ 					       note_size, 
+ 					       PIDGET (inferior_ptid), 
+ 					       proc_cursig (pi), 
+ 					       &gregs);
+ 
+   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);
+ 
+   fill_fpregset (&fpregs, -1);
+   note_data = (char *) elfcore_write_prfpreg (obfd, 
+ 					      note_data, 
+ 					      note_size, 
+ 					      &fpregs, 
+ 					      sizeof (fpregs));
+ 
+   make_cleanup (xfree, note_data);
+   return note_data;
+ }
+ 
+ /* ===================  END GCORE .NOTE "MODULE" =================== */


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/28 23:55:58
*************** elfcore_grok_psinfo (abfd, note)
*** 6074,6080 ****
    if (note->descsz == sizeof (elfcore_psinfo_t))
      {
        elfcore_psinfo_t psinfo;
! 
        memcpy (&psinfo, note->descdata, sizeof (psinfo));
  
        elf_tdata (abfd)->core_program
--- 6074,6080 ----
    if (note->descsz == sizeof (elfcore_psinfo_t))
      {
        elfcore_psinfo_t psinfo;
!   
        memcpy (&psinfo, note->descdata, sizeof (psinfo));
  
        elf_tdata (abfd)->core_program
*************** elfcore_grok_note (abfd, note)
*** 6366,6372 ****
  
      case NT_PRXFPREG:		/* Linux SSE extension */
        if (note->namesz == 5
! 	  && ! strcmp (note->namedata, "LINUX"))
  	return elfcore_grok_prxfpreg (abfd, note);
        else
  	return true;
--- 6366,6372 ----
  
      case NT_PRXFPREG:		/* Linux SSE extension */
        if (note->namesz == 5
! 	  && ! strncmp (note->namedata, "LINUX", 5))
  	return elfcore_grok_prxfpreg (abfd, note);
        else
  	return true;
*************** elfcore_grok_netbsd_note (abfd, note)
*** 6485,6490 ****
--- 6485,6623 ----
          }
      }
      /* 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 (bfd *, char *, int *, pid_t, int, void *);
+ 
+ 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



More information about the Gdb-patches mailing list