xref: /dflybsd-src/contrib/gdb-7/gdb/gcore.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* Generate a core file for the inferior process.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 2001-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This file is part of GDB.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert    (at your option) any later version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
155796c8dcSSimon Schubert    GNU General Public License for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
195796c8dcSSimon Schubert 
205796c8dcSSimon Schubert #include "defs.h"
215796c8dcSSimon Schubert #include "elf-bfd.h"
225796c8dcSSimon Schubert #include "infcall.h"
235796c8dcSSimon Schubert #include "inferior.h"
245796c8dcSSimon Schubert #include "gdbcore.h"
255796c8dcSSimon Schubert #include "objfiles.h"
26cf7f2e2dSJohn Marino #include "solib.h"
275796c8dcSSimon Schubert #include "symfile.h"
28cf7f2e2dSJohn Marino #include "arch-utils.h"
29cf7f2e2dSJohn Marino #include "completer.h"
30cf7f2e2dSJohn Marino #include "gcore.h"
315796c8dcSSimon Schubert #include "cli/cli-decode.h"
325796c8dcSSimon Schubert #include "gdb_assert.h"
33cf7f2e2dSJohn Marino #include <fcntl.h>
34cf7f2e2dSJohn Marino #include "regcache.h"
35cf7f2e2dSJohn Marino #include "regset.h"
36*ef5ccd6cSJohn Marino #include "gdb_bfd.h"
375796c8dcSSimon Schubert 
385796c8dcSSimon Schubert /* The largest amount of memory to read from the target at once.  We
395796c8dcSSimon Schubert    must throttle it to limit the amount of memory used by GDB during
405796c8dcSSimon Schubert    generate-core-file for programs with large resident data.  */
415796c8dcSSimon Schubert #define MAX_COPY_BYTES (1024 * 1024)
425796c8dcSSimon Schubert 
435796c8dcSSimon Schubert static const char *default_gcore_target (void);
445796c8dcSSimon Schubert static enum bfd_architecture default_gcore_arch (void);
455796c8dcSSimon Schubert static unsigned long default_gcore_mach (void);
465796c8dcSSimon Schubert static int gcore_memory_sections (bfd *);
475796c8dcSSimon Schubert 
48cf7f2e2dSJohn Marino /* create_gcore_bfd -- helper for gcore_command (exported).
49cf7f2e2dSJohn Marino    Open a new bfd core file for output, and return the handle.  */
505796c8dcSSimon Schubert 
51cf7f2e2dSJohn Marino bfd *
create_gcore_bfd(char * filename)52cf7f2e2dSJohn Marino create_gcore_bfd (char *filename)
535796c8dcSSimon Schubert {
54*ef5ccd6cSJohn Marino   bfd *obfd = gdb_bfd_openw (filename, default_gcore_target ());
555796c8dcSSimon Schubert 
565796c8dcSSimon Schubert   if (!obfd)
57cf7f2e2dSJohn Marino     error (_("Failed to open '%s' for output."), filename);
585796c8dcSSimon Schubert   bfd_set_format (obfd, bfd_core);
595796c8dcSSimon Schubert   bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ());
60cf7f2e2dSJohn Marino   return obfd;
61cf7f2e2dSJohn Marino }
62cf7f2e2dSJohn Marino 
63cf7f2e2dSJohn Marino /* write_gcore_file -- helper for gcore_command (exported).
64cf7f2e2dSJohn Marino    Compose and write the corefile data to the core file.  */
65cf7f2e2dSJohn Marino 
66cf7f2e2dSJohn Marino 
67cf7f2e2dSJohn Marino void
write_gcore_file(bfd * obfd)68cf7f2e2dSJohn Marino write_gcore_file (bfd *obfd)
69cf7f2e2dSJohn Marino {
70cf7f2e2dSJohn Marino   void *note_data = NULL;
71cf7f2e2dSJohn Marino   int note_size = 0;
72cf7f2e2dSJohn Marino   asection *note_sec = NULL;
735796c8dcSSimon Schubert 
745796c8dcSSimon Schubert   /* An external target method must build the notes section.  */
75*ef5ccd6cSJohn Marino   /* FIXME: uweigand/2011-10-06: All architectures that support core file
76*ef5ccd6cSJohn Marino      generation should be converted to gdbarch_make_corefile_notes; at that
77*ef5ccd6cSJohn Marino      point, the target vector method can be removed.  */
78*ef5ccd6cSJohn Marino   if (!gdbarch_make_corefile_notes_p (target_gdbarch ()))
795796c8dcSSimon Schubert     note_data = target_make_corefile_notes (obfd, &note_size);
80*ef5ccd6cSJohn Marino   else
81*ef5ccd6cSJohn Marino     note_data = gdbarch_make_corefile_notes (target_gdbarch (), obfd, &note_size);
82*ef5ccd6cSJohn Marino 
83*ef5ccd6cSJohn Marino   if (note_data == NULL || note_size == 0)
84*ef5ccd6cSJohn Marino     error (_("Target does not support core file generation."));
855796c8dcSSimon Schubert 
865796c8dcSSimon Schubert   /* Create the note section.  */
875796c8dcSSimon Schubert   note_sec = bfd_make_section_anyway_with_flags (obfd, "note0",
885796c8dcSSimon Schubert 						 SEC_HAS_CONTENTS
895796c8dcSSimon Schubert 						 | SEC_READONLY
905796c8dcSSimon Schubert 						 | SEC_ALLOC);
915796c8dcSSimon Schubert   if (note_sec == NULL)
925796c8dcSSimon Schubert     error (_("Failed to create 'note' section for corefile: %s"),
935796c8dcSSimon Schubert 	   bfd_errmsg (bfd_get_error ()));
945796c8dcSSimon Schubert 
955796c8dcSSimon Schubert   bfd_set_section_vma (obfd, note_sec, 0);
965796c8dcSSimon Schubert   bfd_set_section_alignment (obfd, note_sec, 0);
975796c8dcSSimon Schubert   bfd_set_section_size (obfd, note_sec, note_size);
985796c8dcSSimon Schubert 
995796c8dcSSimon Schubert   /* Now create the memory/load sections.  */
1005796c8dcSSimon Schubert   if (gcore_memory_sections (obfd) == 0)
1015796c8dcSSimon Schubert     error (_("gcore: failed to get corefile memory sections from target."));
1025796c8dcSSimon Schubert 
1035796c8dcSSimon Schubert   /* Write out the contents of the note section.  */
1045796c8dcSSimon Schubert   if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
105*ef5ccd6cSJohn Marino     warning (_("writing note section (%s)"), bfd_errmsg (bfd_get_error ()));
106cf7f2e2dSJohn Marino }
107cf7f2e2dSJohn Marino 
108cf7f2e2dSJohn Marino static void
do_bfd_delete_cleanup(void * arg)109cf7f2e2dSJohn Marino do_bfd_delete_cleanup (void *arg)
110cf7f2e2dSJohn Marino {
111cf7f2e2dSJohn Marino   bfd *obfd = arg;
112cf7f2e2dSJohn Marino   const char *filename = obfd->filename;
113cf7f2e2dSJohn Marino 
114*ef5ccd6cSJohn Marino   gdb_bfd_unref (arg);
115cf7f2e2dSJohn Marino   unlink (filename);
116cf7f2e2dSJohn Marino }
117cf7f2e2dSJohn Marino 
118cf7f2e2dSJohn Marino /* gcore_command -- implements the 'gcore' command.
119cf7f2e2dSJohn Marino    Generate a core file from the inferior process.  */
120cf7f2e2dSJohn Marino 
121cf7f2e2dSJohn Marino static void
gcore_command(char * args,int from_tty)122cf7f2e2dSJohn Marino gcore_command (char *args, int from_tty)
123cf7f2e2dSJohn Marino {
124cf7f2e2dSJohn Marino   struct cleanup *old_chain;
125cf7f2e2dSJohn Marino   char *corefilename, corefilename_buffer[40];
126cf7f2e2dSJohn Marino   bfd *obfd;
127cf7f2e2dSJohn Marino 
128cf7f2e2dSJohn Marino   /* No use generating a corefile without a target process.  */
129cf7f2e2dSJohn Marino   if (!target_has_execution)
130cf7f2e2dSJohn Marino     noprocess ();
131cf7f2e2dSJohn Marino 
132cf7f2e2dSJohn Marino   if (args && *args)
133cf7f2e2dSJohn Marino     corefilename = args;
134cf7f2e2dSJohn Marino   else
135cf7f2e2dSJohn Marino     {
136cf7f2e2dSJohn Marino       /* Default corefile name is "core.PID".  */
137*ef5ccd6cSJohn Marino       xsnprintf (corefilename_buffer, sizeof (corefilename_buffer),
138*ef5ccd6cSJohn Marino 		 "core.%d", PIDGET (inferior_ptid));
139cf7f2e2dSJohn Marino       corefilename = corefilename_buffer;
140cf7f2e2dSJohn Marino     }
141cf7f2e2dSJohn Marino 
142cf7f2e2dSJohn Marino   if (info_verbose)
143cf7f2e2dSJohn Marino     fprintf_filtered (gdb_stdout,
144cf7f2e2dSJohn Marino 		      "Opening corefile '%s' for output.\n", corefilename);
145cf7f2e2dSJohn Marino 
146cf7f2e2dSJohn Marino   /* Open the output file.  */
147cf7f2e2dSJohn Marino   obfd = create_gcore_bfd (corefilename);
148cf7f2e2dSJohn Marino 
149cf7f2e2dSJohn Marino   /* Need a cleanup that will close and delete the file.  */
150cf7f2e2dSJohn Marino   old_chain = make_cleanup (do_bfd_delete_cleanup, obfd);
151cf7f2e2dSJohn Marino 
152cf7f2e2dSJohn Marino   /* Call worker function.  */
153cf7f2e2dSJohn Marino   write_gcore_file (obfd);
1545796c8dcSSimon Schubert 
1555796c8dcSSimon Schubert   /* Succeeded.  */
1565796c8dcSSimon Schubert   fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename);
1575796c8dcSSimon Schubert 
158cf7f2e2dSJohn Marino   discard_cleanups (old_chain);
159*ef5ccd6cSJohn Marino   gdb_bfd_unref (obfd);
1605796c8dcSSimon Schubert }
1615796c8dcSSimon Schubert 
1625796c8dcSSimon Schubert static unsigned long
default_gcore_mach(void)1635796c8dcSSimon Schubert default_gcore_mach (void)
1645796c8dcSSimon Schubert {
1655796c8dcSSimon Schubert #if 1	/* See if this even matters...  */
1665796c8dcSSimon Schubert   return 0;
1675796c8dcSSimon Schubert #else
1685796c8dcSSimon Schubert 
169*ef5ccd6cSJohn Marino   const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (target_gdbarch ());
1705796c8dcSSimon Schubert 
1715796c8dcSSimon Schubert   if (bfdarch != NULL)
1725796c8dcSSimon Schubert     return bfdarch->mach;
1735796c8dcSSimon Schubert   if (exec_bfd == NULL)
1745796c8dcSSimon Schubert     error (_("Can't find default bfd machine type (need execfile)."));
1755796c8dcSSimon Schubert 
1765796c8dcSSimon Schubert   return bfd_get_mach (exec_bfd);
1775796c8dcSSimon Schubert #endif /* 1 */
1785796c8dcSSimon Schubert }
1795796c8dcSSimon Schubert 
1805796c8dcSSimon Schubert static enum bfd_architecture
default_gcore_arch(void)1815796c8dcSSimon Schubert default_gcore_arch (void)
1825796c8dcSSimon Schubert {
183*ef5ccd6cSJohn Marino   const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (target_gdbarch ());
1845796c8dcSSimon Schubert 
1855796c8dcSSimon Schubert   if (bfdarch != NULL)
1865796c8dcSSimon Schubert     return bfdarch->arch;
1875796c8dcSSimon Schubert   if (exec_bfd == NULL)
1885796c8dcSSimon Schubert     error (_("Can't find bfd architecture for corefile (need execfile)."));
1895796c8dcSSimon Schubert 
1905796c8dcSSimon Schubert   return bfd_get_arch (exec_bfd);
1915796c8dcSSimon Schubert }
1925796c8dcSSimon Schubert 
1935796c8dcSSimon Schubert static const char *
default_gcore_target(void)1945796c8dcSSimon Schubert default_gcore_target (void)
1955796c8dcSSimon Schubert {
1965796c8dcSSimon Schubert   /* The gdbarch may define a target to use for core files.  */
197*ef5ccd6cSJohn Marino   if (gdbarch_gcore_bfd_target_p (target_gdbarch ()))
198*ef5ccd6cSJohn Marino     return gdbarch_gcore_bfd_target (target_gdbarch ());
1995796c8dcSSimon Schubert 
2005796c8dcSSimon Schubert   /* Otherwise, try to fall back to the exec_bfd target.  This will probably
2015796c8dcSSimon Schubert      not work for non-ELF targets.  */
2025796c8dcSSimon Schubert   if (exec_bfd == NULL)
2035796c8dcSSimon Schubert     return NULL;
2045796c8dcSSimon Schubert   else
2055796c8dcSSimon Schubert     return bfd_get_target (exec_bfd);
2065796c8dcSSimon Schubert }
2075796c8dcSSimon Schubert 
2085796c8dcSSimon Schubert /* Derive a reasonable stack segment by unwinding the target stack,
2095796c8dcSSimon Schubert    and store its limits in *BOTTOM and *TOP.  Return non-zero if
2105796c8dcSSimon Schubert    successful.  */
2115796c8dcSSimon Schubert 
2125796c8dcSSimon Schubert static int
derive_stack_segment(bfd_vma * bottom,bfd_vma * top)2135796c8dcSSimon Schubert derive_stack_segment (bfd_vma *bottom, bfd_vma *top)
2145796c8dcSSimon Schubert {
2155796c8dcSSimon Schubert   struct frame_info *fi, *tmp_fi;
2165796c8dcSSimon Schubert 
2175796c8dcSSimon Schubert   gdb_assert (bottom);
2185796c8dcSSimon Schubert   gdb_assert (top);
2195796c8dcSSimon Schubert 
2205796c8dcSSimon Schubert   /* Can't succeed without stack and registers.  */
2215796c8dcSSimon Schubert   if (!target_has_stack || !target_has_registers)
2225796c8dcSSimon Schubert     return 0;
2235796c8dcSSimon Schubert 
2245796c8dcSSimon Schubert   /* Can't succeed without current frame.  */
2255796c8dcSSimon Schubert   fi = get_current_frame ();
2265796c8dcSSimon Schubert   if (fi == NULL)
2275796c8dcSSimon Schubert     return 0;
2285796c8dcSSimon Schubert 
2295796c8dcSSimon Schubert   /* Save frame pointer of TOS frame.  */
2305796c8dcSSimon Schubert   *top = get_frame_base (fi);
2315796c8dcSSimon Schubert   /* If current stack pointer is more "inner", use that instead.  */
2325796c8dcSSimon Schubert   if (gdbarch_inner_than (get_frame_arch (fi), get_frame_sp (fi), *top))
2335796c8dcSSimon Schubert     *top = get_frame_sp (fi);
2345796c8dcSSimon Schubert 
2355796c8dcSSimon Schubert   /* Find prev-most frame.  */
2365796c8dcSSimon Schubert   while ((tmp_fi = get_prev_frame (fi)) != NULL)
2375796c8dcSSimon Schubert     fi = tmp_fi;
2385796c8dcSSimon Schubert 
2395796c8dcSSimon Schubert   /* Save frame pointer of prev-most frame.  */
2405796c8dcSSimon Schubert   *bottom = get_frame_base (fi);
2415796c8dcSSimon Schubert 
2425796c8dcSSimon Schubert   /* Now canonicalize their order, so that BOTTOM is a lower address
2435796c8dcSSimon Schubert      (as opposed to a lower stack frame).  */
2445796c8dcSSimon Schubert   if (*bottom > *top)
2455796c8dcSSimon Schubert     {
2465796c8dcSSimon Schubert       bfd_vma tmp_vma;
2475796c8dcSSimon Schubert 
2485796c8dcSSimon Schubert       tmp_vma = *top;
2495796c8dcSSimon Schubert       *top = *bottom;
2505796c8dcSSimon Schubert       *bottom = tmp_vma;
2515796c8dcSSimon Schubert     }
2525796c8dcSSimon Schubert 
2535796c8dcSSimon Schubert   return 1;
2545796c8dcSSimon Schubert }
2555796c8dcSSimon Schubert 
256cf7f2e2dSJohn Marino /* call_target_sbrk --
257cf7f2e2dSJohn Marino    helper function for derive_heap_segment.  */
258cf7f2e2dSJohn Marino 
259cf7f2e2dSJohn Marino static bfd_vma
call_target_sbrk(int sbrk_arg)260cf7f2e2dSJohn Marino call_target_sbrk (int sbrk_arg)
261cf7f2e2dSJohn Marino {
262cf7f2e2dSJohn Marino   struct objfile *sbrk_objf;
263cf7f2e2dSJohn Marino   struct gdbarch *gdbarch;
264cf7f2e2dSJohn Marino   bfd_vma top_of_heap;
265cf7f2e2dSJohn Marino   struct value *target_sbrk_arg;
266cf7f2e2dSJohn Marino   struct value *sbrk_fn, *ret;
267cf7f2e2dSJohn Marino   bfd_vma tmp;
268cf7f2e2dSJohn Marino 
269cf7f2e2dSJohn Marino   if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL)
270cf7f2e2dSJohn Marino     {
271cf7f2e2dSJohn Marino       sbrk_fn = find_function_in_inferior ("sbrk", &sbrk_objf);
272cf7f2e2dSJohn Marino       if (sbrk_fn == NULL)
273cf7f2e2dSJohn Marino 	return (bfd_vma) 0;
274cf7f2e2dSJohn Marino     }
275cf7f2e2dSJohn Marino   else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL)
276cf7f2e2dSJohn Marino     {
277cf7f2e2dSJohn Marino       sbrk_fn = find_function_in_inferior ("_sbrk", &sbrk_objf);
278cf7f2e2dSJohn Marino       if (sbrk_fn == NULL)
279cf7f2e2dSJohn Marino 	return (bfd_vma) 0;
280cf7f2e2dSJohn Marino     }
281cf7f2e2dSJohn Marino   else
282cf7f2e2dSJohn Marino     return (bfd_vma) 0;
283cf7f2e2dSJohn Marino 
284cf7f2e2dSJohn Marino   gdbarch = get_objfile_arch (sbrk_objf);
285cf7f2e2dSJohn Marino   target_sbrk_arg = value_from_longest (builtin_type (gdbarch)->builtin_int,
286cf7f2e2dSJohn Marino 					sbrk_arg);
287cf7f2e2dSJohn Marino   gdb_assert (target_sbrk_arg);
288cf7f2e2dSJohn Marino   ret = call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg);
289cf7f2e2dSJohn Marino   if (ret == NULL)
290cf7f2e2dSJohn Marino     return (bfd_vma) 0;
291cf7f2e2dSJohn Marino 
292cf7f2e2dSJohn Marino   tmp = value_as_long (ret);
293cf7f2e2dSJohn Marino   if ((LONGEST) tmp <= 0 || (LONGEST) tmp == 0xffffffff)
294cf7f2e2dSJohn Marino     return (bfd_vma) 0;
295cf7f2e2dSJohn Marino 
296cf7f2e2dSJohn Marino   top_of_heap = tmp;
297cf7f2e2dSJohn Marino   return top_of_heap;
298cf7f2e2dSJohn Marino }
299cf7f2e2dSJohn Marino 
3005796c8dcSSimon Schubert /* Derive a reasonable heap segment for ABFD by looking at sbrk and
3015796c8dcSSimon Schubert    the static data sections.  Store its limits in *BOTTOM and *TOP.
3025796c8dcSSimon Schubert    Return non-zero if successful.  */
3035796c8dcSSimon Schubert 
3045796c8dcSSimon Schubert static int
derive_heap_segment(bfd * abfd,bfd_vma * bottom,bfd_vma * top)3055796c8dcSSimon Schubert derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top)
3065796c8dcSSimon Schubert {
3075796c8dcSSimon Schubert   bfd_vma top_of_data_memory = 0;
3085796c8dcSSimon Schubert   bfd_vma top_of_heap = 0;
3095796c8dcSSimon Schubert   bfd_size_type sec_size;
3105796c8dcSSimon Schubert   bfd_vma sec_vaddr;
3115796c8dcSSimon Schubert   asection *sec;
3125796c8dcSSimon Schubert 
3135796c8dcSSimon Schubert   gdb_assert (bottom);
3145796c8dcSSimon Schubert   gdb_assert (top);
3155796c8dcSSimon Schubert 
3165796c8dcSSimon Schubert   /* This function depends on being able to call a function in the
3175796c8dcSSimon Schubert      inferior.  */
3185796c8dcSSimon Schubert   if (!target_has_execution)
3195796c8dcSSimon Schubert     return 0;
3205796c8dcSSimon Schubert 
3215796c8dcSSimon Schubert   /* The following code assumes that the link map is arranged as
3225796c8dcSSimon Schubert      follows (low to high addresses):
3235796c8dcSSimon Schubert 
3245796c8dcSSimon Schubert      ---------------------------------
3255796c8dcSSimon Schubert      | text sections                 |
3265796c8dcSSimon Schubert      ---------------------------------
3275796c8dcSSimon Schubert      | data sections (including bss) |
3285796c8dcSSimon Schubert      ---------------------------------
3295796c8dcSSimon Schubert      | heap                          |
3305796c8dcSSimon Schubert      --------------------------------- */
3315796c8dcSSimon Schubert 
3325796c8dcSSimon Schubert   for (sec = abfd->sections; sec; sec = sec->next)
3335796c8dcSSimon Schubert     {
3345796c8dcSSimon Schubert       if (bfd_get_section_flags (abfd, sec) & SEC_DATA
3355796c8dcSSimon Schubert 	  || strcmp (".bss", bfd_section_name (abfd, sec)) == 0)
3365796c8dcSSimon Schubert 	{
3375796c8dcSSimon Schubert 	  sec_vaddr = bfd_get_section_vma (abfd, sec);
3385796c8dcSSimon Schubert 	  sec_size = bfd_get_section_size (sec);
3395796c8dcSSimon Schubert 	  if (sec_vaddr + sec_size > top_of_data_memory)
3405796c8dcSSimon Schubert 	    top_of_data_memory = sec_vaddr + sec_size;
3415796c8dcSSimon Schubert 	}
3425796c8dcSSimon Schubert     }
3435796c8dcSSimon Schubert 
344cf7f2e2dSJohn Marino   top_of_heap = call_target_sbrk (0);
345cf7f2e2dSJohn Marino   if (top_of_heap == (bfd_vma) 0)
3465796c8dcSSimon Schubert     return 0;
3475796c8dcSSimon Schubert 
3485796c8dcSSimon Schubert   /* Return results.  */
3495796c8dcSSimon Schubert   if (top_of_heap > top_of_data_memory)
3505796c8dcSSimon Schubert     {
3515796c8dcSSimon Schubert       *bottom = top_of_data_memory;
3525796c8dcSSimon Schubert       *top = top_of_heap;
3535796c8dcSSimon Schubert       return 1;
3545796c8dcSSimon Schubert     }
3555796c8dcSSimon Schubert 
3565796c8dcSSimon Schubert   /* No additional heap space needs to be saved.  */
3575796c8dcSSimon Schubert   return 0;
3585796c8dcSSimon Schubert }
3595796c8dcSSimon Schubert 
3605796c8dcSSimon Schubert static void
make_output_phdrs(bfd * obfd,asection * osec,void * ignored)3615796c8dcSSimon Schubert make_output_phdrs (bfd *obfd, asection *osec, void *ignored)
3625796c8dcSSimon Schubert {
3635796c8dcSSimon Schubert   int p_flags = 0;
364cf7f2e2dSJohn Marino   int p_type = 0;
3655796c8dcSSimon Schubert 
3665796c8dcSSimon Schubert   /* FIXME: these constants may only be applicable for ELF.  */
3675796c8dcSSimon Schubert   if (strncmp (bfd_section_name (obfd, osec), "load", 4) == 0)
3685796c8dcSSimon Schubert     p_type = PT_LOAD;
369cf7f2e2dSJohn Marino   else if (strncmp (bfd_section_name (obfd, osec), "note", 4) == 0)
3705796c8dcSSimon Schubert     p_type = PT_NOTE;
371cf7f2e2dSJohn Marino   else
372cf7f2e2dSJohn Marino     p_type = PT_NULL;
3735796c8dcSSimon Schubert 
3745796c8dcSSimon Schubert   p_flags |= PF_R;	/* Segment is readable.  */
3755796c8dcSSimon Schubert   if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY))
3765796c8dcSSimon Schubert     p_flags |= PF_W;	/* Segment is writable.  */
3775796c8dcSSimon Schubert   if (bfd_get_section_flags (obfd, osec) & SEC_CODE)
3785796c8dcSSimon Schubert     p_flags |= PF_X;	/* Segment is executable.  */
3795796c8dcSSimon Schubert 
3805796c8dcSSimon Schubert   bfd_record_phdr (obfd, p_type, 1, p_flags, 0, 0, 0, 0, 1, &osec);
3815796c8dcSSimon Schubert }
3825796c8dcSSimon Schubert 
383*ef5ccd6cSJohn Marino /* find_memory_region_ftype implementation.  DATA is 'bfd *' for the core file
384*ef5ccd6cSJohn Marino    GDB is creating.  */
385*ef5ccd6cSJohn Marino 
3865796c8dcSSimon Schubert static int
gcore_create_callback(CORE_ADDR vaddr,unsigned long size,int read,int write,int exec,int modified,void * data)387*ef5ccd6cSJohn Marino gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read,
388*ef5ccd6cSJohn Marino 		       int write, int exec, int modified, void *data)
3895796c8dcSSimon Schubert {
3905796c8dcSSimon Schubert   bfd *obfd = data;
3915796c8dcSSimon Schubert   asection *osec;
3925796c8dcSSimon Schubert   flagword flags = SEC_ALLOC | SEC_HAS_CONTENTS | SEC_LOAD;
3935796c8dcSSimon Schubert 
3945796c8dcSSimon Schubert   /* If the memory segment has no permissions set, ignore it, otherwise
3955796c8dcSSimon Schubert      when we later try to access it for read/write, we'll get an error
3965796c8dcSSimon Schubert      or jam the kernel.  */
397*ef5ccd6cSJohn Marino   if (read == 0 && write == 0 && exec == 0 && modified == 0)
3985796c8dcSSimon Schubert     {
3995796c8dcSSimon Schubert       if (info_verbose)
4005796c8dcSSimon Schubert         {
4015796c8dcSSimon Schubert           fprintf_filtered (gdb_stdout, "Ignore segment, %s bytes at %s\n",
402*ef5ccd6cSJohn Marino                             plongest (size), paddress (target_gdbarch (), vaddr));
4035796c8dcSSimon Schubert         }
4045796c8dcSSimon Schubert 
4055796c8dcSSimon Schubert       return 0;
4065796c8dcSSimon Schubert     }
4075796c8dcSSimon Schubert 
408*ef5ccd6cSJohn Marino   if (write == 0 && modified == 0 && !solib_keep_data_in_core (vaddr, size))
4095796c8dcSSimon Schubert     {
4105796c8dcSSimon Schubert       /* See if this region of memory lies inside a known file on disk.
4115796c8dcSSimon Schubert 	 If so, we can avoid copying its contents by clearing SEC_LOAD.  */
4125796c8dcSSimon Schubert       struct objfile *objfile;
4135796c8dcSSimon Schubert       struct obj_section *objsec;
4145796c8dcSSimon Schubert 
4155796c8dcSSimon Schubert       ALL_OBJSECTIONS (objfile, objsec)
4165796c8dcSSimon Schubert 	{
4175796c8dcSSimon Schubert 	  bfd *abfd = objfile->obfd;
4185796c8dcSSimon Schubert 	  asection *asec = objsec->the_bfd_section;
4195796c8dcSSimon Schubert 	  bfd_vma align = (bfd_vma) 1 << bfd_get_section_alignment (abfd,
4205796c8dcSSimon Schubert 								    asec);
4215796c8dcSSimon Schubert 	  bfd_vma start = obj_section_addr (objsec) & -align;
4225796c8dcSSimon Schubert 	  bfd_vma end = (obj_section_endaddr (objsec) + align - 1) & -align;
423cf7f2e2dSJohn Marino 
4245796c8dcSSimon Schubert 	  /* Match if either the entire memory region lies inside the
4255796c8dcSSimon Schubert 	     section (i.e. a mapping covering some pages of a large
4265796c8dcSSimon Schubert 	     segment) or the entire section lies inside the memory region
4275796c8dcSSimon Schubert 	     (i.e. a mapping covering multiple small sections).
4285796c8dcSSimon Schubert 
4295796c8dcSSimon Schubert 	     This BFD was synthesized from reading target memory,
4305796c8dcSSimon Schubert 	     we don't want to omit that.  */
4315796c8dcSSimon Schubert 	  if (((vaddr >= start && vaddr + size <= end)
4325796c8dcSSimon Schubert 	       || (start >= vaddr && end <= vaddr + size))
4335796c8dcSSimon Schubert 	      && !(bfd_get_file_flags (abfd) & BFD_IN_MEMORY))
4345796c8dcSSimon Schubert 	    {
435c50c785cSJohn Marino 	      flags &= ~(SEC_LOAD | SEC_HAS_CONTENTS);
436c50c785cSJohn Marino 	      goto keep;	/* Break out of two nested for loops.  */
4375796c8dcSSimon Schubert 	    }
4385796c8dcSSimon Schubert 	}
4395796c8dcSSimon Schubert 
440*ef5ccd6cSJohn Marino     keep:;
4415796c8dcSSimon Schubert     }
4425796c8dcSSimon Schubert 
443*ef5ccd6cSJohn Marino   if (write == 0)
444*ef5ccd6cSJohn Marino     flags |= SEC_READONLY;
445*ef5ccd6cSJohn Marino 
4465796c8dcSSimon Schubert   if (exec)
4475796c8dcSSimon Schubert     flags |= SEC_CODE;
4485796c8dcSSimon Schubert   else
4495796c8dcSSimon Schubert     flags |= SEC_DATA;
4505796c8dcSSimon Schubert 
4515796c8dcSSimon Schubert   osec = bfd_make_section_anyway_with_flags (obfd, "load", flags);
4525796c8dcSSimon Schubert   if (osec == NULL)
4535796c8dcSSimon Schubert     {
4545796c8dcSSimon Schubert       warning (_("Couldn't make gcore segment: %s"),
4555796c8dcSSimon Schubert 	       bfd_errmsg (bfd_get_error ()));
4565796c8dcSSimon Schubert       return 1;
4575796c8dcSSimon Schubert     }
4585796c8dcSSimon Schubert 
4595796c8dcSSimon Schubert   if (info_verbose)
4605796c8dcSSimon Schubert     {
4615796c8dcSSimon Schubert       fprintf_filtered (gdb_stdout, "Save segment, %s bytes at %s\n",
462*ef5ccd6cSJohn Marino 			plongest (size), paddress (target_gdbarch (), vaddr));
4635796c8dcSSimon Schubert     }
4645796c8dcSSimon Schubert 
4655796c8dcSSimon Schubert   bfd_set_section_size (obfd, osec, size);
4665796c8dcSSimon Schubert   bfd_set_section_vma (obfd, osec, vaddr);
4675796c8dcSSimon Schubert   bfd_section_lma (obfd, osec) = 0; /* ??? bfd_set_section_lma?  */
4685796c8dcSSimon Schubert   return 0;
4695796c8dcSSimon Schubert }
4705796c8dcSSimon Schubert 
4715796c8dcSSimon Schubert static int
objfile_find_memory_regions(find_memory_region_ftype func,void * obfd)472c50c785cSJohn Marino objfile_find_memory_regions (find_memory_region_ftype func, void *obfd)
4735796c8dcSSimon Schubert {
4745796c8dcSSimon Schubert   /* Use objfile data to create memory sections.  */
4755796c8dcSSimon Schubert   struct objfile *objfile;
4765796c8dcSSimon Schubert   struct obj_section *objsec;
4775796c8dcSSimon Schubert   bfd_vma temp_bottom, temp_top;
4785796c8dcSSimon Schubert 
4795796c8dcSSimon Schubert   /* Call callback function for each objfile section.  */
4805796c8dcSSimon Schubert   ALL_OBJSECTIONS (objfile, objsec)
4815796c8dcSSimon Schubert     {
4825796c8dcSSimon Schubert       bfd *ibfd = objfile->obfd;
4835796c8dcSSimon Schubert       asection *isec = objsec->the_bfd_section;
4845796c8dcSSimon Schubert       flagword flags = bfd_get_section_flags (ibfd, isec);
4855796c8dcSSimon Schubert 
486*ef5ccd6cSJohn Marino       /* Separate debug info files are irrelevant for gcore.  */
487*ef5ccd6cSJohn Marino       if (objfile->separate_debug_objfile_backlink != NULL)
488*ef5ccd6cSJohn Marino 	continue;
489*ef5ccd6cSJohn Marino 
4905796c8dcSSimon Schubert       if ((flags & SEC_ALLOC) || (flags & SEC_LOAD))
4915796c8dcSSimon Schubert 	{
4925796c8dcSSimon Schubert 	  int size = bfd_section_size (ibfd, isec);
4935796c8dcSSimon Schubert 	  int ret;
4945796c8dcSSimon Schubert 
495cf7f2e2dSJohn Marino 	  ret = (*func) (obj_section_addr (objsec), size,
4965796c8dcSSimon Schubert 			 1, /* All sections will be readable.  */
4975796c8dcSSimon Schubert 			 (flags & SEC_READONLY) == 0, /* Writable.  */
4985796c8dcSSimon Schubert 			 (flags & SEC_CODE) != 0, /* Executable.  */
499*ef5ccd6cSJohn Marino 			 1, /* MODIFIED is unknown, pass it as true.  */
5005796c8dcSSimon Schubert 			 obfd);
5015796c8dcSSimon Schubert 	  if (ret != 0)
5025796c8dcSSimon Schubert 	    return ret;
5035796c8dcSSimon Schubert 	}
5045796c8dcSSimon Schubert     }
5055796c8dcSSimon Schubert 
5065796c8dcSSimon Schubert   /* Make a stack segment.  */
5075796c8dcSSimon Schubert   if (derive_stack_segment (&temp_bottom, &temp_top))
5085796c8dcSSimon Schubert     (*func) (temp_bottom, temp_top - temp_bottom,
5095796c8dcSSimon Schubert 	     1, /* Stack section will be readable.  */
5105796c8dcSSimon Schubert 	     1, /* Stack section will be writable.  */
5115796c8dcSSimon Schubert 	     0, /* Stack section will not be executable.  */
512*ef5ccd6cSJohn Marino 	     1, /* Stack section will be modified.  */
5135796c8dcSSimon Schubert 	     obfd);
5145796c8dcSSimon Schubert 
5155796c8dcSSimon Schubert   /* Make a heap segment.  */
5165796c8dcSSimon Schubert   if (derive_heap_segment (exec_bfd, &temp_bottom, &temp_top))
5175796c8dcSSimon Schubert     (*func) (temp_bottom, temp_top - temp_bottom,
5185796c8dcSSimon Schubert 	     1, /* Heap section will be readable.  */
5195796c8dcSSimon Schubert 	     1, /* Heap section will be writable.  */
5205796c8dcSSimon Schubert 	     0, /* Heap section will not be executable.  */
521*ef5ccd6cSJohn Marino 	     1, /* Heap section will be modified.  */
5225796c8dcSSimon Schubert 	     obfd);
5235796c8dcSSimon Schubert 
5245796c8dcSSimon Schubert   return 0;
5255796c8dcSSimon Schubert }
5265796c8dcSSimon Schubert 
5275796c8dcSSimon Schubert static void
gcore_copy_callback(bfd * obfd,asection * osec,void * ignored)5285796c8dcSSimon Schubert gcore_copy_callback (bfd *obfd, asection *osec, void *ignored)
5295796c8dcSSimon Schubert {
5305796c8dcSSimon Schubert   bfd_size_type size, total_size = bfd_section_size (obfd, osec);
5315796c8dcSSimon Schubert   file_ptr offset = 0;
5325796c8dcSSimon Schubert   struct cleanup *old_chain = NULL;
5335796c8dcSSimon Schubert   void *memhunk;
5345796c8dcSSimon Schubert 
5355796c8dcSSimon Schubert   /* Read-only sections are marked; we don't have to copy their contents.  */
5365796c8dcSSimon Schubert   if ((bfd_get_section_flags (obfd, osec) & SEC_LOAD) == 0)
5375796c8dcSSimon Schubert     return;
5385796c8dcSSimon Schubert 
5395796c8dcSSimon Schubert   /* Only interested in "load" sections.  */
5405796c8dcSSimon Schubert   if (strncmp ("load", bfd_section_name (obfd, osec), 4) != 0)
5415796c8dcSSimon Schubert     return;
5425796c8dcSSimon Schubert 
5435796c8dcSSimon Schubert   size = min (total_size, MAX_COPY_BYTES);
5445796c8dcSSimon Schubert   memhunk = xmalloc (size);
5455796c8dcSSimon Schubert   old_chain = make_cleanup (xfree, memhunk);
5465796c8dcSSimon Schubert 
5475796c8dcSSimon Schubert   while (total_size > 0)
5485796c8dcSSimon Schubert     {
5495796c8dcSSimon Schubert       if (size > total_size)
5505796c8dcSSimon Schubert 	size = total_size;
5515796c8dcSSimon Schubert 
5525796c8dcSSimon Schubert       if (target_read_memory (bfd_section_vma (obfd, osec) + offset,
5535796c8dcSSimon Schubert 			      memhunk, size) != 0)
5545796c8dcSSimon Schubert 	{
555c50c785cSJohn Marino 	  warning (_("Memory read failed for corefile "
556c50c785cSJohn Marino 		     "section, %s bytes at %s."),
5575796c8dcSSimon Schubert 		   plongest (size),
558*ef5ccd6cSJohn Marino 		   paddress (target_gdbarch (), bfd_section_vma (obfd, osec)));
5595796c8dcSSimon Schubert 	  break;
5605796c8dcSSimon Schubert 	}
5615796c8dcSSimon Schubert       if (!bfd_set_section_contents (obfd, osec, memhunk, offset, size))
5625796c8dcSSimon Schubert 	{
5635796c8dcSSimon Schubert 	  warning (_("Failed to write corefile contents (%s)."),
5645796c8dcSSimon Schubert 		   bfd_errmsg (bfd_get_error ()));
5655796c8dcSSimon Schubert 	  break;
5665796c8dcSSimon Schubert 	}
5675796c8dcSSimon Schubert 
5685796c8dcSSimon Schubert       total_size -= size;
5695796c8dcSSimon Schubert       offset += size;
5705796c8dcSSimon Schubert     }
5715796c8dcSSimon Schubert 
5725796c8dcSSimon Schubert   do_cleanups (old_chain);	/* Frees MEMHUNK.  */
5735796c8dcSSimon Schubert }
5745796c8dcSSimon Schubert 
5755796c8dcSSimon Schubert static int
gcore_memory_sections(bfd * obfd)5765796c8dcSSimon Schubert gcore_memory_sections (bfd *obfd)
5775796c8dcSSimon Schubert {
578*ef5ccd6cSJohn Marino   /* Try gdbarch method first, then fall back to target method.  */
579*ef5ccd6cSJohn Marino   if (!gdbarch_find_memory_regions_p (target_gdbarch ())
580*ef5ccd6cSJohn Marino       || gdbarch_find_memory_regions (target_gdbarch (),
581*ef5ccd6cSJohn Marino 				      gcore_create_callback, obfd) != 0)
582*ef5ccd6cSJohn Marino     {
5835796c8dcSSimon Schubert       if (target_find_memory_regions (gcore_create_callback, obfd) != 0)
5845796c8dcSSimon Schubert 	return 0;			/* FIXME: error return/msg?  */
585*ef5ccd6cSJohn Marino     }
5865796c8dcSSimon Schubert 
5875796c8dcSSimon Schubert   /* Record phdrs for section-to-segment mapping.  */
5885796c8dcSSimon Schubert   bfd_map_over_sections (obfd, make_output_phdrs, NULL);
5895796c8dcSSimon Schubert 
5905796c8dcSSimon Schubert   /* Copy memory region contents.  */
5915796c8dcSSimon Schubert   bfd_map_over_sections (obfd, gcore_copy_callback, NULL);
5925796c8dcSSimon Schubert 
5935796c8dcSSimon Schubert   return 1;
5945796c8dcSSimon Schubert }
5955796c8dcSSimon Schubert 
5965796c8dcSSimon Schubert /* Provide a prototype to silence -Wmissing-prototypes.  */
5975796c8dcSSimon Schubert extern initialize_file_ftype _initialize_gcore;
5985796c8dcSSimon Schubert 
5995796c8dcSSimon Schubert void
_initialize_gcore(void)6005796c8dcSSimon Schubert _initialize_gcore (void)
6015796c8dcSSimon Schubert {
6025796c8dcSSimon Schubert   add_com ("generate-core-file", class_files, gcore_command, _("\
6035796c8dcSSimon Schubert Save a core file with the current state of the debugged process.\n\
6045796c8dcSSimon Schubert Argument is optional filename.  Default filename is 'core.<process_id>'."));
6055796c8dcSSimon Schubert 
6065796c8dcSSimon Schubert   add_com_alias ("gcore", "generate-core-file", class_files, 1);
6075796c8dcSSimon Schubert   exec_set_find_memory_regions (objfile_find_memory_regions);
6085796c8dcSSimon Schubert }
609