198944Sobrien/* Generate a core file for the inferior process.
298944Sobrien
3130803Smarcel   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4130803Smarcel
598944Sobrien   This file is part of GDB.
698944Sobrien
798944Sobrien   This program is free software; you can redistribute it and/or modify
898944Sobrien   it under the terms of the GNU General Public License as published by
998944Sobrien   the Free Software Foundation; either version 2 of the License, or
1098944Sobrien   (at your option) any later version.
1198944Sobrien
1298944Sobrien   This program is distributed in the hope that it will be useful,
1398944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1498944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1598944Sobrien   GNU General Public License for more details.
1698944Sobrien
1798944Sobrien   You should have received a copy of the GNU General Public License
1898944Sobrien   along with this program; if not, write to the Free Software
1998944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2098944Sobrien   Boston, MA 02111-1307, USA.  */
2198944Sobrien
2298944Sobrien#include "defs.h"
23130803Smarcel#include "elf-bfd.h"
24130803Smarcel#include "infcall.h"
2598944Sobrien#include "inferior.h"
2698944Sobrien#include "gdbcore.h"
27130803Smarcel#include "objfiles.h"
2898944Sobrien#include "symfile.h"
2998944Sobrien
30130803Smarcel#include "cli/cli-decode.h"
3198944Sobrien
32130803Smarcel#include "gdb_assert.h"
3398944Sobrien
34130803Smarcelstatic char *default_gcore_target (void);
35130803Smarcelstatic enum bfd_architecture default_gcore_arch (void);
36130803Smarcelstatic unsigned long default_gcore_mach (void);
37130803Smarcelstatic int gcore_memory_sections (bfd *);
38130803Smarcel
39130803Smarcel/* Generate a core file from the inferior process.  */
40130803Smarcel
4198944Sobrienstatic void
4298944Sobriengcore_command (char *args, int from_tty)
4398944Sobrien{
4498944Sobrien  struct cleanup *old_chain;
4598944Sobrien  char *corefilename, corefilename_buffer[40];
4698944Sobrien  asection *note_sec = NULL;
4798944Sobrien  bfd *obfd;
4898944Sobrien  void *note_data = NULL;
4998944Sobrien  int note_size = 0;
5098944Sobrien
5198944Sobrien  /* No use generating a corefile without a target process.  */
52130803Smarcel  if (!target_has_execution)
5398944Sobrien    noprocess ();
5498944Sobrien
5598944Sobrien  if (args && *args)
5698944Sobrien    corefilename = args;
5798944Sobrien  else
5898944Sobrien    {
5998944Sobrien      /* Default corefile name is "core.PID".  */
6098944Sobrien      sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_ptid));
6198944Sobrien      corefilename = corefilename_buffer;
6298944Sobrien    }
6398944Sobrien
6498944Sobrien  if (info_verbose)
65130803Smarcel    fprintf_filtered (gdb_stdout,
6698944Sobrien		      "Opening corefile '%s' for output.\n", corefilename);
6798944Sobrien
68130803Smarcel  /* Open the output file.  */
69130803Smarcel  obfd = bfd_openw (corefilename, default_gcore_target ());
70130803Smarcel  if (!obfd)
71130803Smarcel    error ("Failed to open '%s' for output.", corefilename);
7298944Sobrien
73130803Smarcel  /* Need a cleanup that will close the file (FIXME: delete it?).  */
7498944Sobrien  old_chain = make_cleanup_bfd_close (obfd);
7598944Sobrien
7698944Sobrien  bfd_set_format (obfd, bfd_core);
7798944Sobrien  bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ());
7898944Sobrien
79130803Smarcel  /* An external target method must build the notes section.  */
80130803Smarcel  note_data = target_make_corefile_notes (obfd, &note_size);
8198944Sobrien
82130803Smarcel  /* Create the note section.  */
8398944Sobrien  if (note_data != NULL && note_size != 0)
8498944Sobrien    {
85130803Smarcel      note_sec = bfd_make_section_anyway (obfd, "note0");
86130803Smarcel      if (note_sec == NULL)
87130803Smarcel	error ("Failed to create 'note' section for corefile: %s",
8898944Sobrien	       bfd_errmsg (bfd_get_error ()));
8998944Sobrien
9098944Sobrien      bfd_set_section_vma (obfd, note_sec, 0);
91130803Smarcel      bfd_set_section_flags (obfd, note_sec,
9298944Sobrien			     SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC);
9398944Sobrien      bfd_set_section_alignment (obfd, note_sec, 0);
9498944Sobrien      bfd_set_section_size (obfd, note_sec, note_size);
9598944Sobrien    }
9698944Sobrien
97130803Smarcel  /* Now create the memory/load sections.  */
9898944Sobrien  if (gcore_memory_sections (obfd) == 0)
9998944Sobrien    error ("gcore: failed to get corefile memory sections from target.");
10098944Sobrien
101130803Smarcel  /* Write out the contents of the note section.  */
10298944Sobrien  if (note_data != NULL && note_size != 0)
10398944Sobrien    {
10498944Sobrien      if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
105130803Smarcel	warning ("writing note section (%s)", bfd_errmsg (bfd_get_error ()));
10698944Sobrien    }
10798944Sobrien
108130803Smarcel  /* Succeeded.  */
109130803Smarcel  fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename);
11098944Sobrien
111130803Smarcel  /* Clean-ups will close the output file and free malloc memory.  */
11298944Sobrien  do_cleanups (old_chain);
11398944Sobrien  return;
11498944Sobrien}
11598944Sobrien
11698944Sobrienstatic unsigned long
11798944Sobriendefault_gcore_mach (void)
11898944Sobrien{
119130803Smarcel#if 1	/* See if this even matters...  */
12098944Sobrien  return 0;
12198944Sobrien#else
12298944Sobrien#ifdef TARGET_ARCHITECTURE
123130803Smarcel  const struct bfd_arch_info *bfdarch = TARGET_ARCHITECTURE;
12498944Sobrien
12598944Sobrien  if (bfdarch != NULL)
12698944Sobrien    return bfdarch->mach;
12798944Sobrien#endif /* TARGET_ARCHITECTURE */
12898944Sobrien  if (exec_bfd == NULL)
12998944Sobrien    error ("Can't find default bfd machine type (need execfile).");
13098944Sobrien
13198944Sobrien  return bfd_get_mach (exec_bfd);
13298944Sobrien#endif /* 1 */
13398944Sobrien}
13498944Sobrien
13598944Sobrienstatic enum bfd_architecture
13698944Sobriendefault_gcore_arch (void)
13798944Sobrien{
13898944Sobrien#ifdef TARGET_ARCHITECTURE
13998944Sobrien  const struct bfd_arch_info * bfdarch = TARGET_ARCHITECTURE;
14098944Sobrien
14198944Sobrien  if (bfdarch != NULL)
14298944Sobrien    return bfdarch->arch;
14398944Sobrien#endif
14498944Sobrien  if (exec_bfd == NULL)
14598944Sobrien    error ("Can't find bfd architecture for corefile (need execfile).");
14698944Sobrien
14798944Sobrien  return bfd_get_arch (exec_bfd);
14898944Sobrien}
14998944Sobrien
15098944Sobrienstatic char *
15198944Sobriendefault_gcore_target (void)
15298944Sobrien{
153130803Smarcel  /* FIXME: This may only work for ELF targets.  */
15498944Sobrien  if (exec_bfd == NULL)
15598944Sobrien    return NULL;
15698944Sobrien  else
15798944Sobrien    return bfd_get_target (exec_bfd);
15898944Sobrien}
15998944Sobrien
160130803Smarcel/* Derive a reasonable stack segment by unwinding the target stack,
161130803Smarcel   and store its limits in *BOTTOM and *TOP.  Return non-zero if
162130803Smarcel   successful.  */
16398944Sobrien
164130803Smarcelstatic int
165130803Smarcelderive_stack_segment (bfd_vma *bottom, bfd_vma *top)
16698944Sobrien{
16798944Sobrien  struct frame_info *fi, *tmp_fi;
16898944Sobrien
169130803Smarcel  gdb_assert (bottom);
170130803Smarcel  gdb_assert (top);
17198944Sobrien
172130803Smarcel  /* Can't succeed without stack and registers.  */
17398944Sobrien  if (!target_has_stack || !target_has_registers)
174130803Smarcel    return 0;
17598944Sobrien
176130803Smarcel  /* Can't succeed without current frame.  */
177130803Smarcel  fi = get_current_frame ();
178130803Smarcel  if (fi == NULL)
179130803Smarcel    return 0;
18098944Sobrien
181130803Smarcel  /* Save frame pointer of TOS frame.  */
182130803Smarcel  *top = get_frame_base (fi);
183130803Smarcel  /* If current stack pointer is more "inner", use that instead.  */
18498944Sobrien  if (INNER_THAN (read_sp (), *top))
18598944Sobrien    *top = read_sp ();
18698944Sobrien
187130803Smarcel  /* Find prev-most frame.  */
18898944Sobrien  while ((tmp_fi = get_prev_frame (fi)) != NULL)
18998944Sobrien    fi = tmp_fi;
19098944Sobrien
191130803Smarcel  /* Save frame pointer of prev-most frame.  */
192130803Smarcel  *bottom = get_frame_base (fi);
19398944Sobrien
194130803Smarcel  /* Now canonicalize their order, so that BOTTOM is a lower address
195130803Smarcel     (as opposed to a lower stack frame).  */
19698944Sobrien  if (*bottom > *top)
19798944Sobrien    {
198130803Smarcel      bfd_vma tmp_vma;
199130803Smarcel
20098944Sobrien      tmp_vma = *top;
20198944Sobrien      *top = *bottom;
20298944Sobrien      *bottom = tmp_vma;
20398944Sobrien    }
20498944Sobrien
205130803Smarcel  return 1;
20698944Sobrien}
20798944Sobrien
208130803Smarcel/* Derive a reasonable heap segment for ABFD by looking at sbrk and
209130803Smarcel   the static data sections.  Store its limits in *BOTTOM and *TOP.
210130803Smarcel   Return non-zero if successful.  */
211130803Smarcel
21298944Sobrienstatic int
213130803Smarcelderive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top)
21498944Sobrien{
21598944Sobrien  bfd_vma top_of_data_memory = 0;
21698944Sobrien  bfd_vma top_of_heap = 0;
21798944Sobrien  bfd_size_type sec_size;
21898944Sobrien  struct value *zero, *sbrk;
21998944Sobrien  bfd_vma sec_vaddr;
22098944Sobrien  asection *sec;
22198944Sobrien
222130803Smarcel  gdb_assert (bottom);
223130803Smarcel  gdb_assert (top);
22498944Sobrien
225130803Smarcel  /* This function depends on being able to call a function in the
226130803Smarcel     inferior.  */
22798944Sobrien  if (!target_has_execution)
228130803Smarcel    return 0;
22998944Sobrien
230130803Smarcel  /* The following code assumes that the link map is arranged as
231130803Smarcel     follows (low to high addresses):
23298944Sobrien
233130803Smarcel     ---------------------------------
234130803Smarcel     | text sections                 |
235130803Smarcel     ---------------------------------
236130803Smarcel     | data sections (including bss) |
237130803Smarcel     ---------------------------------
238130803Smarcel     | heap                          |
239130803Smarcel     --------------------------------- */
240130803Smarcel
24198944Sobrien  for (sec = abfd->sections; sec; sec = sec->next)
24298944Sobrien    {
243130803Smarcel      if (bfd_get_section_flags (abfd, sec) & SEC_DATA
244130803Smarcel	  || strcmp (".bss", bfd_section_name (abfd, sec)) == 0)
24598944Sobrien	{
24698944Sobrien	  sec_vaddr = bfd_get_section_vma (abfd, sec);
247218822Sdim	  sec_size = bfd_get_section_size (sec);
24898944Sobrien	  if (sec_vaddr + sec_size > top_of_data_memory)
24998944Sobrien	    top_of_data_memory = sec_vaddr + sec_size;
25098944Sobrien	}
25198944Sobrien    }
252130803Smarcel
25398944Sobrien  /* Now get the top-of-heap by calling sbrk in the inferior.  */
254130803Smarcel  if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL)
255130803Smarcel    {
256130803Smarcel      sbrk = find_function_in_inferior ("sbrk");
257130803Smarcel      if (sbrk == NULL)
258130803Smarcel	return 0;
259130803Smarcel    }
260130803Smarcel  else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL)
261130803Smarcel    {
262130803Smarcel      sbrk = find_function_in_inferior ("_sbrk");
263130803Smarcel      if (sbrk == NULL)
264130803Smarcel	return 0;
265130803Smarcel    }
266130803Smarcel  else
26798944Sobrien    return 0;
268130803Smarcel
269130803Smarcel  zero = value_from_longest (builtin_type_int, 0);
270130803Smarcel  gdb_assert (zero);
271130803Smarcel  sbrk = call_function_by_hand (sbrk, 1, &zero);
272130803Smarcel  if (sbrk == NULL)
27398944Sobrien    return 0;
27498944Sobrien  top_of_heap = value_as_long (sbrk);
27598944Sobrien
276130803Smarcel  /* Return results.  */
27798944Sobrien  if (top_of_heap > top_of_data_memory)
27898944Sobrien    {
27998944Sobrien      *bottom = top_of_data_memory;
28098944Sobrien      *top = top_of_heap;
281130803Smarcel      return 1;
28298944Sobrien    }
28398944Sobrien
284130803Smarcel  /* No additional heap space needs to be saved.  */
285130803Smarcel  return 0;
28698944Sobrien}
28798944Sobrien
28898944Sobrienstatic void
28998944Sobrienmake_output_phdrs (bfd *obfd, asection *osec, void *ignored)
29098944Sobrien{
29198944Sobrien  int p_flags = 0;
29298944Sobrien  int p_type;
29398944Sobrien
29498944Sobrien  /* FIXME: these constants may only be applicable for ELF.  */
295130803Smarcel  if (strncmp (bfd_section_name (obfd, osec), "load", 4) == 0)
29698944Sobrien    p_type = PT_LOAD;
29798944Sobrien  else
29898944Sobrien    p_type = PT_NOTE;
29998944Sobrien
30098944Sobrien  p_flags |= PF_R;	/* Segment is readable.  */
30198944Sobrien  if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY))
30298944Sobrien    p_flags |= PF_W;	/* Segment is writable.  */
30398944Sobrien  if (bfd_get_section_flags (obfd, osec) & SEC_CODE)
30498944Sobrien    p_flags |= PF_X;	/* Segment is executable.  */
30598944Sobrien
306130803Smarcel  bfd_record_phdr (obfd, p_type, 1, p_flags, 0, 0, 0, 0, 1, &osec);
30798944Sobrien}
30898944Sobrien
309130803Smarcelstatic int
310130803Smarcelgcore_create_callback (CORE_ADDR vaddr, unsigned long size,
311130803Smarcel		       int read, int write, int exec, void *data)
31298944Sobrien{
313130803Smarcel  bfd *obfd = data;
31498944Sobrien  asection *osec;
315130803Smarcel  flagword flags = SEC_ALLOC | SEC_HAS_CONTENTS | SEC_LOAD;
31698944Sobrien
317130803Smarcel  /* If the memory segment has no permissions set, ignore it, otherwise
318130803Smarcel     when we later try to access it for read/write, we'll get an error
319130803Smarcel     or jam the kernel.  */
320130803Smarcel  if (read == 0 && write == 0 && exec == 0)
32198944Sobrien    {
322130803Smarcel      if (info_verbose)
323130803Smarcel        {
324130803Smarcel          fprintf_filtered (gdb_stdout, "Ignore segment, %s bytes at 0x%s\n",
325130803Smarcel                           paddr_d (size), paddr_nz (vaddr));
326130803Smarcel        }
327130803Smarcel
328130803Smarcel      return 0;
32998944Sobrien    }
33098944Sobrien
331130803Smarcel  if (write == 0)
33298944Sobrien    {
333130803Smarcel      /* See if this region of memory lies inside a known file on disk.
334130803Smarcel	 If so, we can avoid copying its contents by clearing SEC_LOAD.  */
335130803Smarcel      struct objfile *objfile;
336130803Smarcel      struct obj_section *objsec;
33798944Sobrien
338130803Smarcel      ALL_OBJSECTIONS (objfile, objsec)
339130803Smarcel	{
340130803Smarcel	  bfd *abfd = objfile->obfd;
341130803Smarcel	  asection *asec = objsec->the_bfd_section;
342130803Smarcel	  bfd_vma align = (bfd_vma) 1 << bfd_get_section_alignment (abfd,
343130803Smarcel								    asec);
344130803Smarcel	  bfd_vma start = objsec->addr & -align;
345130803Smarcel	  bfd_vma end = (objsec->endaddr + align - 1) & -align;
346130803Smarcel	  /* Match if either the entire memory region lies inside the
347130803Smarcel	     section (i.e. a mapping covering some pages of a large
348130803Smarcel	     segment) or the entire section lies inside the memory region
349130803Smarcel	     (i.e. a mapping covering multiple small sections).
35098944Sobrien
351130803Smarcel	     This BFD was synthesized from reading target memory,
352130803Smarcel	     we don't want to omit that.  */
353130803Smarcel	  if (((vaddr >= start && vaddr + size <= end)
354130803Smarcel	       || (start >= vaddr && end <= vaddr + size))
355130803Smarcel	      && !(bfd_get_file_flags (abfd) & BFD_IN_MEMORY))
356130803Smarcel	    {
357130803Smarcel	      flags &= ~SEC_LOAD;
358130803Smarcel	      goto keep;	/* break out of two nested for loops */
359130803Smarcel	    }
360130803Smarcel	}
36198944Sobrien
362130803Smarcel    keep:
36398944Sobrien      flags |= SEC_READONLY;
36498944Sobrien    }
365130803Smarcel
36698944Sobrien  if (exec)
367130803Smarcel    flags |= SEC_CODE;
368130803Smarcel  else
369130803Smarcel    flags |= SEC_DATA;
370130803Smarcel
371130803Smarcel  osec = bfd_make_section_anyway (obfd, "load");
372130803Smarcel  if (osec == NULL)
37398944Sobrien    {
374130803Smarcel      warning ("Couldn't make gcore segment: %s",
375130803Smarcel	       bfd_errmsg (bfd_get_error ()));
376130803Smarcel      return 1;
37798944Sobrien    }
378130803Smarcel
379130803Smarcel  if (info_verbose)
38098944Sobrien    {
381130803Smarcel      fprintf_filtered (gdb_stdout, "Save segment, %s bytes at 0x%s\n",
382130803Smarcel			paddr_d (size), paddr_nz (vaddr));
38398944Sobrien    }
38498944Sobrien
385130803Smarcel  bfd_set_section_size (obfd, osec, size);
386130803Smarcel  bfd_set_section_vma (obfd, osec, vaddr);
387130803Smarcel  bfd_section_lma (obfd, osec) = 0; /* ??? bfd_set_section_lma?  */
388130803Smarcel  bfd_set_section_flags (obfd, osec, flags);
389130803Smarcel  return 0;
39098944Sobrien}
39198944Sobrien
39298944Sobrienstatic int
393130803Smarcelobjfile_find_memory_regions (int (*func) (CORE_ADDR, unsigned long,
394130803Smarcel					  int, int, int, void *),
39598944Sobrien			     void *obfd)
39698944Sobrien{
397130803Smarcel  /* Use objfile data to create memory sections.  */
39898944Sobrien  struct objfile *objfile;
39998944Sobrien  struct obj_section *objsec;
40098944Sobrien  bfd_vma temp_bottom, temp_top;
40198944Sobrien
402130803Smarcel  /* Call callback function for each objfile section.  */
40398944Sobrien  ALL_OBJSECTIONS (objfile, objsec)
40498944Sobrien    {
40598944Sobrien      bfd *ibfd = objfile->obfd;
40698944Sobrien      asection *isec = objsec->the_bfd_section;
40798944Sobrien      flagword flags = bfd_get_section_flags (ibfd, isec);
40898944Sobrien      int ret;
40998944Sobrien
41098944Sobrien      if ((flags & SEC_ALLOC) || (flags & SEC_LOAD))
41198944Sobrien	{
41298944Sobrien	  int size = bfd_section_size (ibfd, isec);
41398944Sobrien	  int ret;
41498944Sobrien
415130803Smarcel	  ret = (*func) (objsec->addr, bfd_section_size (ibfd, isec),
416130803Smarcel			 1, /* All sections will be readable.  */
417130803Smarcel			 (flags & SEC_READONLY) == 0, /* Writable.  */
418130803Smarcel			 (flags & SEC_CODE) != 0, /* Executable.  */
419130803Smarcel			 obfd);
420130803Smarcel	  if (ret != 0)
42198944Sobrien	    return ret;
42298944Sobrien	}
42398944Sobrien    }
42498944Sobrien
425130803Smarcel  /* Make a stack segment.  */
42698944Sobrien  if (derive_stack_segment (&temp_bottom, &temp_top))
427130803Smarcel    (*func) (temp_bottom, temp_top - temp_bottom,
428130803Smarcel	     1, /* Stack section will be readable.  */
429130803Smarcel	     1, /* Stack section will be writable.  */
430130803Smarcel	     0, /* Stack section will not be executable.  */
43198944Sobrien	     obfd);
43298944Sobrien
43398944Sobrien  /* Make a heap segment. */
43498944Sobrien  if (derive_heap_segment (exec_bfd, &temp_bottom, &temp_top))
435130803Smarcel    (*func) (temp_bottom, temp_top - temp_bottom,
436130803Smarcel	     1, /* Heap section will be readable.  */
437130803Smarcel	     1, /* Heap section will be writable.  */
438130803Smarcel	     0, /* Heap section will not be executable.  */
43998944Sobrien	     obfd);
440130803Smarcel
44198944Sobrien  return 0;
44298944Sobrien}
44398944Sobrien
44498944Sobrienstatic void
44598944Sobriengcore_copy_callback (bfd *obfd, asection *osec, void *ignored)
44698944Sobrien{
44798944Sobrien  bfd_size_type size = bfd_section_size (obfd, osec);
44898944Sobrien  struct cleanup *old_chain = NULL;
44998944Sobrien  void *memhunk;
45098944Sobrien
451130803Smarcel  /* Read-only sections are marked; we don't have to copy their contents.  */
452130803Smarcel  if ((bfd_get_section_flags (obfd, osec) & SEC_LOAD) == 0)
453130803Smarcel    return;
45498944Sobrien
455130803Smarcel  /* Only interested in "load" sections.  */
456130803Smarcel  if (strncmp ("load", bfd_section_name (obfd, osec), 4) != 0)
457130803Smarcel    return;
458130803Smarcel
459130803Smarcel  memhunk = xmalloc (size);
460130803Smarcel  /* ??? This is crap since xmalloc should never return NULL.  */
461130803Smarcel  if (memhunk == NULL)
46298944Sobrien    error ("Not enough memory to create corefile.");
46398944Sobrien  old_chain = make_cleanup (xfree, memhunk);
46498944Sobrien
465130803Smarcel  if (target_read_memory (bfd_section_vma (obfd, osec),
46698944Sobrien			  memhunk, size) != 0)
467130803Smarcel    warning ("Memory read failed for corefile section, %s bytes at 0x%s\n",
468130803Smarcel	     paddr_d (size), paddr (bfd_section_vma (obfd, osec)));
46998944Sobrien  if (!bfd_set_section_contents (obfd, osec, memhunk, 0, size))
470130803Smarcel    warning ("Failed to write corefile contents (%s).",
47198944Sobrien	     bfd_errmsg (bfd_get_error ()));
47298944Sobrien
473130803Smarcel  do_cleanups (old_chain);	/* Frees MEMHUNK.  */
47498944Sobrien}
47598944Sobrien
47698944Sobrienstatic int
47798944Sobriengcore_memory_sections (bfd *obfd)
47898944Sobrien{
47998944Sobrien  if (target_find_memory_regions (gcore_create_callback, obfd) != 0)
480130803Smarcel    return 0;			/* FIXME: error return/msg?  */
48198944Sobrien
482130803Smarcel  /* Record phdrs for section-to-segment mapping.  */
48398944Sobrien  bfd_map_over_sections (obfd, make_output_phdrs, NULL);
48498944Sobrien
485130803Smarcel  /* Copy memory region contents.  */
48698944Sobrien  bfd_map_over_sections (obfd, gcore_copy_callback, NULL);
48798944Sobrien
488130803Smarcel  return 1;
48998944Sobrien}
49098944Sobrien
49198944Sobrienvoid
49298944Sobrien_initialize_gcore (void)
49398944Sobrien{
49498944Sobrien  add_com ("generate-core-file", class_files, gcore_command,
495130803Smarcel	   "\
496130803SmarcelSave a core file with the current state of the debugged process.\n\
49798944SobrienArgument is optional filename.  Default filename is 'core.<process_id>'.");
49898944Sobrien
49998944Sobrien  add_com_alias ("gcore", "generate-core-file", class_files, 1);
50098944Sobrien  exec_set_find_memory_regions (objfile_find_memory_regions);
50198944Sobrien}
502