xref: /openbsd-src/gnu/usr.bin/binutils/gdb/gcore.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1b725ae77Skettenis /* Generate a core file for the inferior process.
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4b725ae77Skettenis 
5b725ae77Skettenis    This file is part of GDB.
6b725ae77Skettenis 
7b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
8b725ae77Skettenis    it under the terms of the GNU General Public License as published by
9b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
10b725ae77Skettenis    (at your option) any later version.
11b725ae77Skettenis 
12b725ae77Skettenis    This program is distributed in the hope that it will be useful,
13b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
14b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15b725ae77Skettenis    GNU General Public License for more details.
16b725ae77Skettenis 
17b725ae77Skettenis    You should have received a copy of the GNU General Public License
18b725ae77Skettenis    along with this program; if not, write to the Free Software
19b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
20b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
21b725ae77Skettenis 
22b725ae77Skettenis #include "defs.h"
23b725ae77Skettenis #include "elf-bfd.h"
24b725ae77Skettenis #include "infcall.h"
25b725ae77Skettenis #include "inferior.h"
26b725ae77Skettenis #include "gdbcore.h"
27b725ae77Skettenis #include "objfiles.h"
28b725ae77Skettenis #include "symfile.h"
29b725ae77Skettenis 
30b725ae77Skettenis #include "cli/cli-decode.h"
31b725ae77Skettenis 
32b725ae77Skettenis #include "gdb_assert.h"
33b725ae77Skettenis 
34b725ae77Skettenis static char *default_gcore_target (void);
35b725ae77Skettenis static enum bfd_architecture default_gcore_arch (void);
36b725ae77Skettenis static unsigned long default_gcore_mach (void);
37b725ae77Skettenis static int gcore_memory_sections (bfd *);
38b725ae77Skettenis 
39b725ae77Skettenis /* Generate a core file from the inferior process.  */
40b725ae77Skettenis 
41b725ae77Skettenis static void
gcore_command(char * args,int from_tty)42b725ae77Skettenis gcore_command (char *args, int from_tty)
43b725ae77Skettenis {
44b725ae77Skettenis   struct cleanup *old_chain;
45b725ae77Skettenis   char *corefilename, corefilename_buffer[40];
46b725ae77Skettenis   asection *note_sec = NULL;
47b725ae77Skettenis   bfd *obfd;
48b725ae77Skettenis   void *note_data = NULL;
49b725ae77Skettenis   int note_size = 0;
50b725ae77Skettenis 
51b725ae77Skettenis   /* No use generating a corefile without a target process.  */
52b725ae77Skettenis   if (!target_has_execution)
53b725ae77Skettenis     noprocess ();
54b725ae77Skettenis 
55b725ae77Skettenis   if (args && *args)
56b725ae77Skettenis     corefilename = args;
57b725ae77Skettenis   else
58b725ae77Skettenis     {
59b725ae77Skettenis       /* Default corefile name is "core.PID".  */
60b725ae77Skettenis       sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_ptid));
61b725ae77Skettenis       corefilename = corefilename_buffer;
62b725ae77Skettenis     }
63b725ae77Skettenis 
64b725ae77Skettenis   if (info_verbose)
65b725ae77Skettenis     fprintf_filtered (gdb_stdout,
66b725ae77Skettenis 		      "Opening corefile '%s' for output.\n", corefilename);
67b725ae77Skettenis 
68b725ae77Skettenis   /* Open the output file.  */
69b725ae77Skettenis   obfd = bfd_openw (corefilename, default_gcore_target ());
70b725ae77Skettenis   if (!obfd)
71b725ae77Skettenis     error ("Failed to open '%s' for output.", corefilename);
72b725ae77Skettenis 
73b725ae77Skettenis   /* Need a cleanup that will close the file (FIXME: delete it?).  */
74b725ae77Skettenis   old_chain = make_cleanup_bfd_close (obfd);
75b725ae77Skettenis 
76b725ae77Skettenis   bfd_set_format (obfd, bfd_core);
77b725ae77Skettenis   bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ());
78b725ae77Skettenis 
79b725ae77Skettenis   /* An external target method must build the notes section.  */
80b725ae77Skettenis   note_data = target_make_corefile_notes (obfd, &note_size);
81b725ae77Skettenis 
82b725ae77Skettenis   /* Create the note section.  */
83b725ae77Skettenis   if (note_data != NULL && note_size != 0)
84b725ae77Skettenis     {
85b725ae77Skettenis       note_sec = bfd_make_section_anyway (obfd, "note0");
86b725ae77Skettenis       if (note_sec == NULL)
87b725ae77Skettenis 	error ("Failed to create 'note' section for corefile: %s",
88b725ae77Skettenis 	       bfd_errmsg (bfd_get_error ()));
89b725ae77Skettenis 
90b725ae77Skettenis       bfd_set_section_vma (obfd, note_sec, 0);
91b725ae77Skettenis       bfd_set_section_flags (obfd, note_sec,
92b725ae77Skettenis 			     SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC);
93b725ae77Skettenis       bfd_set_section_alignment (obfd, note_sec, 0);
94b725ae77Skettenis       bfd_set_section_size (obfd, note_sec, note_size);
95b725ae77Skettenis     }
96b725ae77Skettenis 
97b725ae77Skettenis   /* Now create the memory/load sections.  */
98b725ae77Skettenis   if (gcore_memory_sections (obfd) == 0)
99b725ae77Skettenis     error ("gcore: failed to get corefile memory sections from target.");
100b725ae77Skettenis 
101b725ae77Skettenis   /* Write out the contents of the note section.  */
102b725ae77Skettenis   if (note_data != NULL && note_size != 0)
103b725ae77Skettenis     {
104b725ae77Skettenis       if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
105b725ae77Skettenis 	warning ("writing note section (%s)", bfd_errmsg (bfd_get_error ()));
106b725ae77Skettenis     }
107b725ae77Skettenis 
108b725ae77Skettenis   /* Succeeded.  */
109b725ae77Skettenis   fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename);
110b725ae77Skettenis 
111b725ae77Skettenis   /* Clean-ups will close the output file and free malloc memory.  */
112b725ae77Skettenis   do_cleanups (old_chain);
113b725ae77Skettenis   return;
114b725ae77Skettenis }
115b725ae77Skettenis 
116b725ae77Skettenis static unsigned long
default_gcore_mach(void)117b725ae77Skettenis default_gcore_mach (void)
118b725ae77Skettenis {
119b725ae77Skettenis #if 1	/* See if this even matters...  */
120b725ae77Skettenis   return 0;
121b725ae77Skettenis #else
122b725ae77Skettenis #ifdef TARGET_ARCHITECTURE
123b725ae77Skettenis   const struct bfd_arch_info *bfdarch = TARGET_ARCHITECTURE;
124b725ae77Skettenis 
125b725ae77Skettenis   if (bfdarch != NULL)
126b725ae77Skettenis     return bfdarch->mach;
127b725ae77Skettenis #endif /* TARGET_ARCHITECTURE */
128b725ae77Skettenis   if (exec_bfd == NULL)
129b725ae77Skettenis     error ("Can't find default bfd machine type (need execfile).");
130b725ae77Skettenis 
131b725ae77Skettenis   return bfd_get_mach (exec_bfd);
132b725ae77Skettenis #endif /* 1 */
133b725ae77Skettenis }
134b725ae77Skettenis 
135b725ae77Skettenis static enum bfd_architecture
default_gcore_arch(void)136b725ae77Skettenis default_gcore_arch (void)
137b725ae77Skettenis {
138b725ae77Skettenis #ifdef TARGET_ARCHITECTURE
139b725ae77Skettenis   const struct bfd_arch_info * bfdarch = TARGET_ARCHITECTURE;
140b725ae77Skettenis 
141b725ae77Skettenis   if (bfdarch != NULL)
142b725ae77Skettenis     return bfdarch->arch;
143b725ae77Skettenis #endif
144b725ae77Skettenis   if (exec_bfd == NULL)
145b725ae77Skettenis     error ("Can't find bfd architecture for corefile (need execfile).");
146b725ae77Skettenis 
147b725ae77Skettenis   return bfd_get_arch (exec_bfd);
148b725ae77Skettenis }
149b725ae77Skettenis 
150b725ae77Skettenis static char *
default_gcore_target(void)151b725ae77Skettenis default_gcore_target (void)
152b725ae77Skettenis {
153b725ae77Skettenis   /* FIXME: This may only work for ELF targets.  */
154b725ae77Skettenis   if (exec_bfd == NULL)
155b725ae77Skettenis     return NULL;
156b725ae77Skettenis   else
157b725ae77Skettenis     return bfd_get_target (exec_bfd);
158b725ae77Skettenis }
159b725ae77Skettenis 
160b725ae77Skettenis /* Derive a reasonable stack segment by unwinding the target stack,
161b725ae77Skettenis    and store its limits in *BOTTOM and *TOP.  Return non-zero if
162b725ae77Skettenis    successful.  */
163b725ae77Skettenis 
164b725ae77Skettenis static int
derive_stack_segment(bfd_vma * bottom,bfd_vma * top)165b725ae77Skettenis derive_stack_segment (bfd_vma *bottom, bfd_vma *top)
166b725ae77Skettenis {
167b725ae77Skettenis   struct frame_info *fi, *tmp_fi;
168b725ae77Skettenis 
169b725ae77Skettenis   gdb_assert (bottom);
170b725ae77Skettenis   gdb_assert (top);
171b725ae77Skettenis 
172b725ae77Skettenis   /* Can't succeed without stack and registers.  */
173b725ae77Skettenis   if (!target_has_stack || !target_has_registers)
174b725ae77Skettenis     return 0;
175b725ae77Skettenis 
176b725ae77Skettenis   /* Can't succeed without current frame.  */
177b725ae77Skettenis   fi = get_current_frame ();
178b725ae77Skettenis   if (fi == NULL)
179b725ae77Skettenis     return 0;
180b725ae77Skettenis 
181b725ae77Skettenis   /* Save frame pointer of TOS frame.  */
182b725ae77Skettenis   *top = get_frame_base (fi);
183b725ae77Skettenis   /* If current stack pointer is more "inner", use that instead.  */
184b725ae77Skettenis   if (INNER_THAN (read_sp (), *top))
185b725ae77Skettenis     *top = read_sp ();
186b725ae77Skettenis 
187b725ae77Skettenis   /* Find prev-most frame.  */
188b725ae77Skettenis   while ((tmp_fi = get_prev_frame (fi)) != NULL)
189b725ae77Skettenis     fi = tmp_fi;
190b725ae77Skettenis 
191b725ae77Skettenis   /* Save frame pointer of prev-most frame.  */
192b725ae77Skettenis   *bottom = get_frame_base (fi);
193b725ae77Skettenis 
194b725ae77Skettenis   /* Now canonicalize their order, so that BOTTOM is a lower address
195b725ae77Skettenis      (as opposed to a lower stack frame).  */
196b725ae77Skettenis   if (*bottom > *top)
197b725ae77Skettenis     {
198b725ae77Skettenis       bfd_vma tmp_vma;
199b725ae77Skettenis 
200b725ae77Skettenis       tmp_vma = *top;
201b725ae77Skettenis       *top = *bottom;
202b725ae77Skettenis       *bottom = tmp_vma;
203b725ae77Skettenis     }
204b725ae77Skettenis 
205b725ae77Skettenis   return 1;
206b725ae77Skettenis }
207b725ae77Skettenis 
208b725ae77Skettenis /* Derive a reasonable heap segment for ABFD by looking at sbrk and
209b725ae77Skettenis    the static data sections.  Store its limits in *BOTTOM and *TOP.
210b725ae77Skettenis    Return non-zero if successful.  */
211b725ae77Skettenis 
212b725ae77Skettenis static int
derive_heap_segment(bfd * abfd,bfd_vma * bottom,bfd_vma * top)213b725ae77Skettenis derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top)
214b725ae77Skettenis {
215b725ae77Skettenis   bfd_vma top_of_data_memory = 0;
216b725ae77Skettenis   bfd_vma top_of_heap = 0;
217b725ae77Skettenis   bfd_size_type sec_size;
218b725ae77Skettenis   struct value *zero, *sbrk;
219b725ae77Skettenis   bfd_vma sec_vaddr;
220b725ae77Skettenis   asection *sec;
221b725ae77Skettenis 
222b725ae77Skettenis   gdb_assert (bottom);
223b725ae77Skettenis   gdb_assert (top);
224b725ae77Skettenis 
225b725ae77Skettenis   /* This function depends on being able to call a function in the
226b725ae77Skettenis      inferior.  */
227b725ae77Skettenis   if (!target_has_execution)
228b725ae77Skettenis     return 0;
229b725ae77Skettenis 
230b725ae77Skettenis   /* The following code assumes that the link map is arranged as
231b725ae77Skettenis      follows (low to high addresses):
232b725ae77Skettenis 
233b725ae77Skettenis      ---------------------------------
234b725ae77Skettenis      | text sections                 |
235b725ae77Skettenis      ---------------------------------
236b725ae77Skettenis      | data sections (including bss) |
237b725ae77Skettenis      ---------------------------------
238b725ae77Skettenis      | heap                          |
239b725ae77Skettenis      --------------------------------- */
240b725ae77Skettenis 
241b725ae77Skettenis   for (sec = abfd->sections; sec; sec = sec->next)
242b725ae77Skettenis     {
243b725ae77Skettenis       if (bfd_get_section_flags (abfd, sec) & SEC_DATA
244b725ae77Skettenis 	  || strcmp (".bss", bfd_section_name (abfd, sec)) == 0)
245b725ae77Skettenis 	{
246b725ae77Skettenis 	  sec_vaddr = bfd_get_section_vma (abfd, sec);
247*11efff7fSkettenis 	  sec_size = bfd_get_section_size (sec);
248b725ae77Skettenis 	  if (sec_vaddr + sec_size > top_of_data_memory)
249b725ae77Skettenis 	    top_of_data_memory = sec_vaddr + sec_size;
250b725ae77Skettenis 	}
251b725ae77Skettenis     }
252b725ae77Skettenis 
253b725ae77Skettenis   /* Now get the top-of-heap by calling sbrk in the inferior.  */
254b725ae77Skettenis   if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL)
255b725ae77Skettenis     {
256b725ae77Skettenis       sbrk = find_function_in_inferior ("sbrk");
257b725ae77Skettenis       if (sbrk == NULL)
258b725ae77Skettenis 	return 0;
259b725ae77Skettenis     }
260b725ae77Skettenis   else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL)
261b725ae77Skettenis     {
262b725ae77Skettenis       sbrk = find_function_in_inferior ("_sbrk");
263b725ae77Skettenis       if (sbrk == NULL)
264b725ae77Skettenis 	return 0;
265b725ae77Skettenis     }
266b725ae77Skettenis   else
267b725ae77Skettenis     return 0;
268b725ae77Skettenis 
269b725ae77Skettenis   zero = value_from_longest (builtin_type_int, 0);
270b725ae77Skettenis   gdb_assert (zero);
271b725ae77Skettenis   sbrk = call_function_by_hand (sbrk, 1, &zero);
272b725ae77Skettenis   if (sbrk == NULL)
273b725ae77Skettenis     return 0;
274b725ae77Skettenis   top_of_heap = value_as_long (sbrk);
275b725ae77Skettenis 
276b725ae77Skettenis   /* Return results.  */
277b725ae77Skettenis   if (top_of_heap > top_of_data_memory)
278b725ae77Skettenis     {
279b725ae77Skettenis       *bottom = top_of_data_memory;
280b725ae77Skettenis       *top = top_of_heap;
281b725ae77Skettenis       return 1;
282b725ae77Skettenis     }
283b725ae77Skettenis 
284b725ae77Skettenis   /* No additional heap space needs to be saved.  */
285b725ae77Skettenis   return 0;
286b725ae77Skettenis }
287b725ae77Skettenis 
288b725ae77Skettenis static void
make_output_phdrs(bfd * obfd,asection * osec,void * ignored)289b725ae77Skettenis make_output_phdrs (bfd *obfd, asection *osec, void *ignored)
290b725ae77Skettenis {
291b725ae77Skettenis   int p_flags = 0;
292b725ae77Skettenis   int p_type;
293b725ae77Skettenis 
294b725ae77Skettenis   /* FIXME: these constants may only be applicable for ELF.  */
295b725ae77Skettenis   if (strncmp (bfd_section_name (obfd, osec), "load", 4) == 0)
296b725ae77Skettenis     p_type = PT_LOAD;
297b725ae77Skettenis   else
298b725ae77Skettenis     p_type = PT_NOTE;
299b725ae77Skettenis 
300b725ae77Skettenis   p_flags |= PF_R;	/* Segment is readable.  */
301b725ae77Skettenis   if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY))
302b725ae77Skettenis     p_flags |= PF_W;	/* Segment is writable.  */
303b725ae77Skettenis   if (bfd_get_section_flags (obfd, osec) & SEC_CODE)
304b725ae77Skettenis     p_flags |= PF_X;	/* Segment is executable.  */
305b725ae77Skettenis 
306b725ae77Skettenis   bfd_record_phdr (obfd, p_type, 1, p_flags, 0, 0, 0, 0, 1, &osec);
307b725ae77Skettenis }
308b725ae77Skettenis 
309b725ae77Skettenis static int
gcore_create_callback(CORE_ADDR vaddr,unsigned long size,int read,int write,int exec,void * data)310b725ae77Skettenis gcore_create_callback (CORE_ADDR vaddr, unsigned long size,
311b725ae77Skettenis 		       int read, int write, int exec, void *data)
312b725ae77Skettenis {
313b725ae77Skettenis   bfd *obfd = data;
314b725ae77Skettenis   asection *osec;
315b725ae77Skettenis   flagword flags = SEC_ALLOC | SEC_HAS_CONTENTS | SEC_LOAD;
316b725ae77Skettenis 
317b725ae77Skettenis   /* If the memory segment has no permissions set, ignore it, otherwise
318b725ae77Skettenis      when we later try to access it for read/write, we'll get an error
319b725ae77Skettenis      or jam the kernel.  */
320b725ae77Skettenis   if (read == 0 && write == 0 && exec == 0)
321b725ae77Skettenis     {
322b725ae77Skettenis       if (info_verbose)
323b725ae77Skettenis         {
324b725ae77Skettenis           fprintf_filtered (gdb_stdout, "Ignore segment, %s bytes at 0x%s\n",
325b725ae77Skettenis                            paddr_d (size), paddr_nz (vaddr));
326b725ae77Skettenis         }
327b725ae77Skettenis 
328b725ae77Skettenis       return 0;
329b725ae77Skettenis     }
330b725ae77Skettenis 
331b725ae77Skettenis   if (write == 0)
332b725ae77Skettenis     {
333b725ae77Skettenis       /* See if this region of memory lies inside a known file on disk.
334b725ae77Skettenis 	 If so, we can avoid copying its contents by clearing SEC_LOAD.  */
335b725ae77Skettenis       struct objfile *objfile;
336b725ae77Skettenis       struct obj_section *objsec;
337b725ae77Skettenis 
338b725ae77Skettenis       ALL_OBJSECTIONS (objfile, objsec)
339b725ae77Skettenis 	{
340b725ae77Skettenis 	  bfd *abfd = objfile->obfd;
341b725ae77Skettenis 	  asection *asec = objsec->the_bfd_section;
342b725ae77Skettenis 	  bfd_vma align = (bfd_vma) 1 << bfd_get_section_alignment (abfd,
343b725ae77Skettenis 								    asec);
344b725ae77Skettenis 	  bfd_vma start = objsec->addr & -align;
345b725ae77Skettenis 	  bfd_vma end = (objsec->endaddr + align - 1) & -align;
346b725ae77Skettenis 	  /* Match if either the entire memory region lies inside the
347b725ae77Skettenis 	     section (i.e. a mapping covering some pages of a large
348b725ae77Skettenis 	     segment) or the entire section lies inside the memory region
349b725ae77Skettenis 	     (i.e. a mapping covering multiple small sections).
350b725ae77Skettenis 
351b725ae77Skettenis 	     This BFD was synthesized from reading target memory,
352b725ae77Skettenis 	     we don't want to omit that.  */
353b725ae77Skettenis 	  if (((vaddr >= start && vaddr + size <= end)
354b725ae77Skettenis 	       || (start >= vaddr && end <= vaddr + size))
355b725ae77Skettenis 	      && !(bfd_get_file_flags (abfd) & BFD_IN_MEMORY))
356b725ae77Skettenis 	    {
357b725ae77Skettenis 	      flags &= ~SEC_LOAD;
358b725ae77Skettenis 	      goto keep;	/* break out of two nested for loops */
359b725ae77Skettenis 	    }
360b725ae77Skettenis 	}
361b725ae77Skettenis 
362b725ae77Skettenis     keep:
363b725ae77Skettenis       flags |= SEC_READONLY;
364b725ae77Skettenis     }
365b725ae77Skettenis 
366b725ae77Skettenis   if (exec)
367b725ae77Skettenis     flags |= SEC_CODE;
368b725ae77Skettenis   else
369b725ae77Skettenis     flags |= SEC_DATA;
370b725ae77Skettenis 
371b725ae77Skettenis   osec = bfd_make_section_anyway (obfd, "load");
372b725ae77Skettenis   if (osec == NULL)
373b725ae77Skettenis     {
374b725ae77Skettenis       warning ("Couldn't make gcore segment: %s",
375b725ae77Skettenis 	       bfd_errmsg (bfd_get_error ()));
376b725ae77Skettenis       return 1;
377b725ae77Skettenis     }
378b725ae77Skettenis 
379b725ae77Skettenis   if (info_verbose)
380b725ae77Skettenis     {
381b725ae77Skettenis       fprintf_filtered (gdb_stdout, "Save segment, %s bytes at 0x%s\n",
382b725ae77Skettenis 			paddr_d (size), paddr_nz (vaddr));
383b725ae77Skettenis     }
384b725ae77Skettenis 
385b725ae77Skettenis   bfd_set_section_size (obfd, osec, size);
386b725ae77Skettenis   bfd_set_section_vma (obfd, osec, vaddr);
387b725ae77Skettenis   bfd_section_lma (obfd, osec) = 0; /* ??? bfd_set_section_lma?  */
388b725ae77Skettenis   bfd_set_section_flags (obfd, osec, flags);
389b725ae77Skettenis   return 0;
390b725ae77Skettenis }
391b725ae77Skettenis 
392b725ae77Skettenis static int
objfile_find_memory_regions(int (* func)(CORE_ADDR,unsigned long,int,int,int,void *),void * obfd)393b725ae77Skettenis objfile_find_memory_regions (int (*func) (CORE_ADDR, unsigned long,
394b725ae77Skettenis 					  int, int, int, void *),
395b725ae77Skettenis 			     void *obfd)
396b725ae77Skettenis {
397b725ae77Skettenis   /* Use objfile data to create memory sections.  */
398b725ae77Skettenis   struct objfile *objfile;
399b725ae77Skettenis   struct obj_section *objsec;
400b725ae77Skettenis   bfd_vma temp_bottom, temp_top;
401b725ae77Skettenis 
402b725ae77Skettenis   /* Call callback function for each objfile section.  */
403b725ae77Skettenis   ALL_OBJSECTIONS (objfile, objsec)
404b725ae77Skettenis     {
405b725ae77Skettenis       bfd *ibfd = objfile->obfd;
406b725ae77Skettenis       asection *isec = objsec->the_bfd_section;
407b725ae77Skettenis       flagword flags = bfd_get_section_flags (ibfd, isec);
408b725ae77Skettenis       int ret;
409b725ae77Skettenis 
410b725ae77Skettenis       if ((flags & SEC_ALLOC) || (flags & SEC_LOAD))
411b725ae77Skettenis 	{
412b725ae77Skettenis 	  int size = bfd_section_size (ibfd, isec);
413b725ae77Skettenis 	  int ret;
414b725ae77Skettenis 
415b725ae77Skettenis 	  ret = (*func) (objsec->addr, bfd_section_size (ibfd, isec),
416b725ae77Skettenis 			 1, /* All sections will be readable.  */
417b725ae77Skettenis 			 (flags & SEC_READONLY) == 0, /* Writable.  */
418b725ae77Skettenis 			 (flags & SEC_CODE) != 0, /* Executable.  */
419b725ae77Skettenis 			 obfd);
420b725ae77Skettenis 	  if (ret != 0)
421b725ae77Skettenis 	    return ret;
422b725ae77Skettenis 	}
423b725ae77Skettenis     }
424b725ae77Skettenis 
425b725ae77Skettenis   /* Make a stack segment.  */
426b725ae77Skettenis   if (derive_stack_segment (&temp_bottom, &temp_top))
427b725ae77Skettenis     (*func) (temp_bottom, temp_top - temp_bottom,
428b725ae77Skettenis 	     1, /* Stack section will be readable.  */
429b725ae77Skettenis 	     1, /* Stack section will be writable.  */
430b725ae77Skettenis 	     0, /* Stack section will not be executable.  */
431b725ae77Skettenis 	     obfd);
432b725ae77Skettenis 
433b725ae77Skettenis   /* Make a heap segment. */
434b725ae77Skettenis   if (derive_heap_segment (exec_bfd, &temp_bottom, &temp_top))
435b725ae77Skettenis     (*func) (temp_bottom, temp_top - temp_bottom,
436b725ae77Skettenis 	     1, /* Heap section will be readable.  */
437b725ae77Skettenis 	     1, /* Heap section will be writable.  */
438b725ae77Skettenis 	     0, /* Heap section will not be executable.  */
439b725ae77Skettenis 	     obfd);
440b725ae77Skettenis 
441b725ae77Skettenis   return 0;
442b725ae77Skettenis }
443b725ae77Skettenis 
444b725ae77Skettenis static void
gcore_copy_callback(bfd * obfd,asection * osec,void * ignored)445b725ae77Skettenis gcore_copy_callback (bfd *obfd, asection *osec, void *ignored)
446b725ae77Skettenis {
447b725ae77Skettenis   bfd_size_type size = bfd_section_size (obfd, osec);
448b725ae77Skettenis   struct cleanup *old_chain = NULL;
449b725ae77Skettenis   void *memhunk;
450b725ae77Skettenis 
451b725ae77Skettenis   /* Read-only sections are marked; we don't have to copy their contents.  */
452b725ae77Skettenis   if ((bfd_get_section_flags (obfd, osec) & SEC_LOAD) == 0)
453b725ae77Skettenis     return;
454b725ae77Skettenis 
455b725ae77Skettenis   /* Only interested in "load" sections.  */
456b725ae77Skettenis   if (strncmp ("load", bfd_section_name (obfd, osec), 4) != 0)
457b725ae77Skettenis     return;
458b725ae77Skettenis 
459b725ae77Skettenis   memhunk = xmalloc (size);
460b725ae77Skettenis   /* ??? This is crap since xmalloc should never return NULL.  */
461b725ae77Skettenis   if (memhunk == NULL)
462b725ae77Skettenis     error ("Not enough memory to create corefile.");
463b725ae77Skettenis   old_chain = make_cleanup (xfree, memhunk);
464b725ae77Skettenis 
465b725ae77Skettenis   if (target_read_memory (bfd_section_vma (obfd, osec),
466b725ae77Skettenis 			  memhunk, size) != 0)
467b725ae77Skettenis     warning ("Memory read failed for corefile section, %s bytes at 0x%s\n",
468b725ae77Skettenis 	     paddr_d (size), paddr (bfd_section_vma (obfd, osec)));
469b725ae77Skettenis   if (!bfd_set_section_contents (obfd, osec, memhunk, 0, size))
470b725ae77Skettenis     warning ("Failed to write corefile contents (%s).",
471b725ae77Skettenis 	     bfd_errmsg (bfd_get_error ()));
472b725ae77Skettenis 
473b725ae77Skettenis   do_cleanups (old_chain);	/* Frees MEMHUNK.  */
474b725ae77Skettenis }
475b725ae77Skettenis 
476b725ae77Skettenis static int
gcore_memory_sections(bfd * obfd)477b725ae77Skettenis gcore_memory_sections (bfd *obfd)
478b725ae77Skettenis {
479b725ae77Skettenis   if (target_find_memory_regions (gcore_create_callback, obfd) != 0)
480b725ae77Skettenis     return 0;			/* FIXME: error return/msg?  */
481b725ae77Skettenis 
482b725ae77Skettenis   /* Record phdrs for section-to-segment mapping.  */
483b725ae77Skettenis   bfd_map_over_sections (obfd, make_output_phdrs, NULL);
484b725ae77Skettenis 
485b725ae77Skettenis   /* Copy memory region contents.  */
486b725ae77Skettenis   bfd_map_over_sections (obfd, gcore_copy_callback, NULL);
487b725ae77Skettenis 
488b725ae77Skettenis   return 1;
489b725ae77Skettenis }
490b725ae77Skettenis 
491b725ae77Skettenis void
_initialize_gcore(void)492b725ae77Skettenis _initialize_gcore (void)
493b725ae77Skettenis {
494b725ae77Skettenis   add_com ("generate-core-file", class_files, gcore_command,
495b725ae77Skettenis 	   "\
496b725ae77Skettenis Save a core file with the current state of the debugged process.\n\
497b725ae77Skettenis Argument is optional filename.  Default filename is 'core.<process_id>'.");
498b725ae77Skettenis 
499b725ae77Skettenis   add_com_alias ("gcore", "generate-core-file", class_files, 1);
500b725ae77Skettenis   exec_set_find_memory_regions (objfile_find_memory_regions);
501b725ae77Skettenis }
502