2002-01-03 Michael Snyder <msnyder@redhat.com>

Implement a "generate-core-file" command in gdb, save target state.
	* gcore.c: New file.  Implement new command 'generate-core-file'.
	Save a corefile image of the current state of the inferior.
	* linux-proc.c: Add linux-specific code for saving corefiles.
	* target.h (struct target_ops): Add new target vectors for saving
	corefiles; to_find_memory_regions and to_make_corefile_notes.
	(target_find_memory_regions): New macro.
	(target_make_corefile_notes): New macro.
	* target.c (update_current_target): Inherit new target methods.
	(dummy_find_memory_regions): New place-holder method.
	(dummy_make_corefile_notes): New place-holder method.
	(init_dummy_target): Initialize new dummy target vectors.
	* exec.c (exec_set_find_memory_regions): New function.
	Allow the exec_ops vector for memory regions to be taken over.
	(exec_make_note_section): New function, target vector method.
	* defs.h (exec_set_find_memory_regions): Export prototype.
	* procfs.c (proc_find_memory_regions): New function, corefile method.
	(procfs_make_note_section): New function, corefile method.
	(init_procfs_ops): Set new target vector pointers.
	(find_memory_regions_callback): New function.
	(procfs_do_thread_registers): New function.
	(procfs_corefile_thread_callback): New function.
	* sol-thread.c (sol_find_memory_regions): New function.
	(sol_make_note_section): New function.
	(init_sol_thread_ops): Initialize new target vectors.
	* inftarg.c (inftarg_set_find_memory_regions): New function.
	Allow to_find_memory_regions vector to be taken over.
	(inftarg_set_make_corefile_notes): New function.
	Allow to_make_corefile_notes vector to be taken over.
	* thread-db.c (thread_db_new_objfile): Don't activate thread-db
	interface layer if not target_has_execution (may be a corefile).
	* config/i386/linux.mh: Add gcore.o to NATDEPFILES.
	* config/sparc/sun4sol2.mh: Ditto.
	* config/alpha/alpha-linux.mh: Ditto.
	* config/arm/linux.mh: Ditto.
	* config/i386/x86-64linux.mh: Ditto.
	* config/ia64/linux.mh: Ditto.
	* config/m68k/linux.mh: Ditto.
	* config/mips/linux.mh: Ditto.
	* config/powerpc/linux.mh: Ditto.
	* config/sparc/linux.mh: Ditto.
This commit is contained in:
Michael Snyder
2002-01-09 00:37:02 +00:00
parent 30070dac97
commit be4d133316
20 changed files with 1145 additions and 56 deletions

View File

@ -1,3 +1,47 @@
2002-01-03 Michael Snyder <msnyder@redhat.com>
Implement a "generate-core-file" command in gdb, save target state.
* gcore.c: New file. Implement new command 'generate-core-file'.
Save a corefile image of the current state of the inferior.
* linux-proc.c: Add linux-specific code for saving corefiles.
* target.h (struct target_ops): Add new target vectors for saving
corefiles; to_find_memory_regions and to_make_corefile_notes.
(target_find_memory_regions): New macro.
(target_make_corefile_notes): New macro.
* target.c (update_current_target): Inherit new target methods.
(dummy_find_memory_regions): New place-holder method.
(dummy_make_corefile_notes): New place-holder method.
(init_dummy_target): Initialize new dummy target vectors.
* exec.c (exec_set_find_memory_regions): New function.
Allow the exec_ops vector for memory regions to be taken over.
(exec_make_note_section): New function, target vector method.
* defs.h (exec_set_find_memory_regions): Export prototype.
* procfs.c (proc_find_memory_regions): New function, corefile method.
(procfs_make_note_section): New function, corefile method.
(init_procfs_ops): Set new target vector pointers.
(find_memory_regions_callback): New function.
(procfs_do_thread_registers): New function.
(procfs_corefile_thread_callback): New function.
* sol-thread.c (sol_find_memory_regions): New function.
(sol_make_note_section): New function.
(init_sol_thread_ops): Initialize new target vectors.
* inftarg.c (inftarg_set_find_memory_regions): New function.
Allow to_find_memory_regions vector to be taken over.
(inftarg_set_make_corefile_notes): New function.
Allow to_make_corefile_notes vector to be taken over.
* thread-db.c (thread_db_new_objfile): Don't activate thread-db
interface layer if not target_has_execution (may be a corefile).
* config/i386/linux.mh: Add gcore.o to NATDEPFILES.
* config/sparc/sun4sol2.mh: Ditto.
* config/alpha/alpha-linux.mh: Ditto.
* config/arm/linux.mh: Ditto.
* config/i386/x86-64linux.mh: Ditto.
* config/ia64/linux.mh: Ditto.
* config/m68k/linux.mh: Ditto.
* config/mips/linux.mh: Ditto.
* config/powerpc/linux.mh: Ditto.
* config/sparc/linux.mh: Ditto.
2002-01-07 Michael Snyder <msnyder@redhat.com>
* arm-linux-nat.c: Remove references to regcache.c internal data

View File

@ -3,7 +3,7 @@ XDEPFILES=
XM_FILE= xm-alphalinux.h
NAT_FILE= nm-linux.h
NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o linux-proc.o \
fork-child.o proc-service.o thread-db.o lin-lwp.o
fork-child.o proc-service.o thread-db.o lin-lwp.o gcore.o
LOADLIBES = -ldl -rdynamic

View File

@ -5,7 +5,7 @@ XDEPFILES=
NAT_FILE= nm-linux.h
NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
core-regset.o arm-linux-nat.o linux-proc.o \
core-regset.o arm-linux-nat.o linux-proc.o gcore.o \
proc-service.o thread-db.o lin-lwp.o
LOADLIBES= -ldl -rdynamic

View File

@ -6,7 +6,7 @@ XDEPFILES=
NAT_FILE= nm-linux.h
NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o linux-proc.o \
core-aout.o i386-nat.o i386-linux-nat.o i387-nat.o \
proc-service.o thread-db.o lin-lwp.o linux-proc.o
proc-service.o thread-db.o lin-lwp.o linux-proc.o gcore.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.

View File

@ -6,6 +6,7 @@ XDEPFILES=
NAT_FILE= nm-x86-64.h
NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
core-aout.o i386-nat.o x86-64-nat.o x86-64-linux-nat.o \
i387-nat.o proc-service.o thread-db.o lin-lwp.o linux-proc.o
i387-nat.o proc-service.o thread-db.o lin-lwp.o \
linux-proc.o gcore.o
LOADLIBES = -ldl -rdynamic

View File

@ -4,7 +4,7 @@ XM_FILE= xm-linux.h
XDEPFILES=
NAT_FILE= nm-linux.h
NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o gcore.o \
core-aout.o core-regset.o ia64-linux-nat.o linux-proc.o \
proc-service.o thread-db.o lin-lwp.o

View File

@ -5,7 +5,7 @@ XDEPFILES=
NAT_FILE= nm-linux.h
NATDEPFILES= infptrace.o inftarg.o fork-child.o \
corelow.o core-aout.o m68klinux-nat.o linux-proc.o \
corelow.o core-aout.o m68klinux-nat.o linux-proc.o gcore.o \
proc-service.o thread-db.o lin-lwp.o
# The dynamically loaded libthread_db needs access to symbols in the

View File

@ -3,6 +3,6 @@ XDEPFILES=
XM_FILE= xm-linux.h
NAT_FILE= nm-linux.h
NATDEPFILES= infptrace.o inftarg.o fork-child.o mips-linux-nat.o \
thread-db.o lin-lwp.o proc-service.o linux-proc.o
thread-db.o lin-lwp.o proc-service.o linux-proc.o gcore.o
LOADLIBES = -ldl -rdynamic

View File

@ -6,7 +6,8 @@ XM_CLIBS=
NAT_FILE= nm-linux.h
NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o linux-proc.o \
core-regset.o ppc-linux-nat.o proc-service.o thread-db.o lin-lwp.o
core-regset.o ppc-linux-nat.o proc-service.o thread-db.o lin-lwp.o \
gcore.o
LOADLIBES = -ldl -rdynamic

View File

@ -5,7 +5,8 @@ XDEPFILES=
NAT_FILE= nm-linux.h
NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o sparc-nat.o \
proc-service.o thread-db.o lin-lwp.o sparc-linux-nat.o linux-proc.o
proc-service.o thread-db.o lin-lwp.o sparc-linux-nat.o \
linux-proc.o gcore.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.

View File

@ -6,7 +6,8 @@ XM_CLIBS= -lsocket -lnsl
NAT_FILE= nm-sun4sol2.h
NATDEPFILES= corelow.o core-sol2.o solib.o solib-svr4.o solib-legacy.o \
fork-child.o procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
fork-child.o procfs.o gcore.o \
proc-api.o proc-events.o proc-flags.o proc-why.o
# /usr/include/v9 is needed only by core-sol2.c when including
# v9/sys/privregs.h, or rather the headers it in turn includes.

View File

@ -1,7 +1,7 @@
/* *INDENT-OFF* */ /* ATTR_FORMAT confuses indent, avoid running it for now */
/* Basic, host-specific, and target-specific definitions for GDB.
Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
1997, 1998, 1999, 2000, 2001
1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
This file is part of GDB.
@ -775,6 +775,13 @@ extern void exec_set_section_offsets (bfd_signed_vma text_off,
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 *);

View File

@ -1,6 +1,6 @@
/* Work with executable files, for GDB.
Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
1998, 1999, 2000, 2001
1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
This file is part of GDB.
@ -685,10 +685,24 @@ ignore (CORE_ADDR addr, char *contents)
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. */
void
static void
init_exec_ops (void)
{
exec_ops.to_shortname = "exec";
@ -708,6 +722,7 @@ Specify the filename of the executable file.";
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;
}
@ -752,3 +767,34 @@ file itself are wrong. Each section must be changed separately. The\n\
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;
}

493
gdb/gcore.c Normal file
View File

@ -0,0 +1,493 @@
/* Generate a core file for the inferior process.
Copyright 2001, 2002 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "command.h"
#include "inferior.h"
#include "gdbcore.h"
#include "elf-bfd.h"
#include <sys/procfs.h>
#include "symfile.h"
#include "objfiles.h"
static char *default_gcore_target (void);
static enum bfd_architecture default_gcore_arch (void);
static unsigned long default_gcore_mach (void);
static int gcore_memory_sections (bfd *);
/* Function: gcore_command
Generate a core file from the inferior process. */
static void
gcore_command (char *args, int from_tty)
{
struct cleanup *old_chain;
char *corefilename, corefilename_buffer[40];
asection *note_sec;
bfd *obfd;
void *note_data = NULL;
int note_size = 0;
/* No use generating a corefile without a target process. */
if (!(target_has_execution))
noprocess ();
if (args && *args)
corefilename = args;
else
{
/* Default corefile name is "core.PID". */
sprintf (corefilename_buffer, "core.%d", PIDGET (inferior_ptid));
corefilename = corefilename_buffer;
}
if (info_verbose)
fprintf_filtered (gdb_stdout,
"Opening corefile '%s' for output.\n", corefilename);
/* Open the output file. */
if (!(obfd = bfd_openw (corefilename, NULL /*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 ()));
}
}
/* Succeeded. */
fprintf_filtered (gdb_stdout,
"Saved corefile %s\n", corefilename);
/* Clean-ups will close the output file and free malloc memory. */
do_cleanups (old_chain);
return;
}
static unsigned long
default_gcore_mach (void)
{
#ifdef TARGET_ARCHITECTURE
const struct bfd_arch_info * bfdarch = TARGET_ARCHITECTURE;
if (bfdarch != NULL)
return bfdarch->mach;
#endif
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)
{
#ifdef TARGET_ARCHITECTURE
const struct bfd_arch_info * bfdarch = TARGET_ARCHITECTURE;
if (bfdarch != NULL)
return bfdarch->arch;
#endif
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;
struct value *zero, *sbrk;
bfd_vma sec_vaddr;
asection *sec;
if (bottom == NULL || top == NULL)
return 0; /* Paranoia. */
if (!target_has_execution)
return 0; /* This function depends on being able
to call a function in the inferior. */
/* Assumption: link map is arranged as follows (low to high addresses):
text sections
data sections (including bss)
heap
*/
for (sec = abfd->sections; sec; sec = sec->next)
{
if (bfd_get_section_flags (abfd, sec) & SEC_DATA ||
strcmp (".bss", bfd_get_section_name (abfd, sec)) == 0)
{
sec_vaddr = bfd_get_section_vma (abfd, sec);
sec_size = bfd_get_section_size_before_reloc (sec);
if (sec_vaddr + sec_size > top_of_data_memory)
top_of_data_memory = sec_vaddr + sec_size;
}
}
/* Now get the top-of-heap by calling sbrk in the inferior. */
if ((sbrk = find_function_in_inferior ("sbrk")) == NULL)
return 0;
if ((zero = value_from_longest (builtin_type_int, (LONGEST) 0)) == NULL)
return 0;
if ((sbrk = call_function_by_hand (sbrk, 1, &zero)) == NULL)
return 0;
top_of_heap = value_as_long (sbrk);
/* Return results. */
if (top_of_heap > top_of_data_memory)
{
*bottom = top_of_data_memory;
*top = top_of_heap;
return 1; /* success */
}
else
return 0; /* No additional heap space needs to be saved. */
}
static int
derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top)
{
if (override_derive_heap_segment)
return override_derive_heap_segment (abfd, bottom, top);
else
return default_derive_heap_segment (abfd, bottom, top);
}
/* ARGSUSED */
static void
make_output_phdrs (bfd *obfd, asection *osec, void *ignored)
{
int p_flags = 0;
int p_type;
/* FIXME: these constants may only be applicable for ELF. */
if (strncmp (osec->name, "load", 4) == 0)
p_type = PT_LOAD;
else
p_type = PT_NOTE;
p_flags |= PF_R; /* Segment is readable. */
if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY))
p_flags |= PF_W; /* Segment is writable. */
if (bfd_get_section_flags (obfd, osec) & SEC_CODE)
p_flags |= PF_X; /* Segment is executable. */
bfd_record_phdr (obfd, p_type, 1, p_flags, 0, 0,
0, 0, 1, &osec);
}
static asection *
make_mem_sec (bfd *obfd,
bfd_vma addr,
bfd_size_type size,
unsigned int flags,
unsigned int alignment)
{
asection *osec;
if ((osec = bfd_make_section_anyway (obfd, "load")) == NULL)
{
warning ("Couldn't make gcore segment: %s",
bfd_errmsg (bfd_get_error ()));
return NULL;
}
if (info_verbose)
{
fprintf_filtered (gdb_stdout,
"Save segment, %ld bytes at 0x%s\n",
size, paddr_nz (addr));
}
bfd_set_section_size (obfd, osec, size);
bfd_set_section_vma (obfd, osec, addr);
osec->lma = 0; /* FIXME: there should be a macro for this! */
bfd_set_section_alignment (obfd, osec, alignment);
bfd_set_section_flags (obfd, osec,
flags | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS);
return osec;
}
static int
gcore_create_callback (CORE_ADDR vaddr,
unsigned long size,
int read, int write, int exec,
void *data)
{
flagword flags = 0;
if (write == 0)
{
flags |= SEC_READONLY;
/* Set size == zero for readonly sections. */
size = 0;
}
if (exec)
{
flags |= SEC_CODE;
}
else
{
flags |= SEC_DATA;
}
return ((make_mem_sec ((bfd *) data, vaddr, size, flags, 0)) == NULL);
}
static int
objfile_find_memory_regions (int (*func) (CORE_ADDR,
unsigned long,
int, int, int,
void *),
void *obfd)
{
/* Use objfile data to create memory sections. */
struct objfile *objfile;
struct obj_section *objsec;
bfd_vma temp_bottom, temp_top;
/* Call callback function for each objfile section. */
ALL_OBJSECTIONS (objfile, objsec)
{
bfd *ibfd = objfile->obfd;
asection *isec = objsec->the_bfd_section;
flagword flags = bfd_get_section_flags (ibfd, isec);
int ret;
if ((flags & SEC_ALLOC) || (flags & SEC_LOAD))
{
int size = bfd_section_size (ibfd, isec);
int ret;
if ((ret = (*func) (objsec->addr,
bfd_section_size (ibfd, isec),
1, /* All sections will be readable. */
(flags & SEC_READONLY) == 0, /* writable */
(flags & SEC_CODE) != 0, /* executable */
obfd)) != 0)
return ret;
}
}
/* Make a stack segment. */
if (derive_stack_segment (&temp_bottom, &temp_top))
(*func) (temp_bottom,
temp_top - temp_bottom,
1, /* Stack section will be readable */
1, /* Stack section will be writable */
0, /* Stack section will not be executable */
obfd);
/* Make a heap segment. */
if (derive_heap_segment (exec_bfd, &temp_bottom, &temp_top))
(*func) (temp_bottom,
temp_top - temp_bottom,
1, /* Heap section will be readable */
1, /* Heap section will be writable */
0, /* Heap section will not be executable */
obfd);
return 0;
}
static void
gcore_copy_callback (bfd *obfd, asection *osec, void *ignored)
{
bfd_size_type size = bfd_section_size (obfd, osec);
struct cleanup *old_chain = NULL;
void *memhunk;
if (size == 0)
return; /* Read-only sections are marked as zero-size.
We don't have to copy their contents. */
if (strncmp ("load", bfd_get_section_name (obfd, osec), 4) != 0)
return; /* Only interested in "load" sections. */
if ((memhunk = xmalloc (size)) == NULL)
error ("Not enough memory to create corefile.");
old_chain = make_cleanup (xfree, memhunk);
if (target_read_memory (bfd_section_vma (obfd, osec),
memhunk, size) != 0)
warning ("Memory read failed for corefile section, %ld bytes at 0x%s\n",
(long) size, paddr (bfd_section_vma (obfd, osec)));
if (!bfd_set_section_contents (obfd, osec, memhunk, 0, size))
warning ("Failed to write corefile contents (%s).",
bfd_errmsg (bfd_get_error ()));
do_cleanups (old_chain); /* frees the xmalloc buffer */
}
static int
gcore_memory_sections (bfd *obfd)
{
if (target_find_memory_regions (gcore_create_callback, obfd) != 0)
return 0; /* FIXME error return/msg? */
/* Record phdrs for section-to-segment mapping. */
bfd_map_over_sections (obfd, make_output_phdrs, NULL);
/* Copy memory region contents. */
bfd_map_over_sections (obfd, gcore_copy_callback, NULL);
return 1; /* success */
}
void
_initialize_gcore (void)
{
add_com ("generate-core-file", class_files, gcore_command,
"Save a core file with the current state of the debugged process.\n\
Argument is optional filename. Default filename is 'core.<process_id>'.");
add_com_alias ("gcore", "generate-core-file", class_files, 1);
exec_set_find_memory_regions (objfile_find_memory_regions);
}

View File

@ -1,5 +1,6 @@
/* Target-vector operations for controlling Unix child processes, for GDB.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
2000, 2002
Free Software Foundation, Inc.
Contributed by Cygnus Support.
@ -812,6 +813,24 @@ init_child_ops (void)
child_ops.to_magic = OPS_MAGIC;
}
/* Take over the 'find_mapped_memory' vector from inftarg.c. */
extern void
inftarg_set_find_memory_regions (int (*func) (int (*) (CORE_ADDR,
unsigned long,
int, int, int,
void *),
void *))
{
child_ops.to_find_memory_regions = func;
}
/* Take over the 'make_corefile_notes' vector from inftarg.c. */
extern void
inftarg_set_make_corefile_notes (char * (*func) (bfd *, int *))
{
child_ops.to_make_corefile_notes = func;
}
void
_initialize_inftarg (void)
{

View File

@ -1,5 +1,5 @@
/* Generate a core file for the inferior process -- Linux version.
Copyright 2001 Free Software Foundation, Inc.
/* Linux-specific methods for using the /proc file system.
Copyright 2001, 2002 Free Software Foundation, Inc.
This file is part of GDB.
@ -19,7 +19,20 @@
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "inferior.h"
#include <sys/param.h> /* for MAXPATHLEN */
#include <sys/procfs.h>
#include "gregset.h" /* for gregset */
#include "gdbcore.h" /* for get_exec_file */
#include "gdbthread.h" /* for struct thread_info etc. */
#include "elf-bfd.h"
/* Function: child_pid_to_exec_file
*
* Accepts an integer pid
* Returns a string representing a file that can be opened
* to get the symbols for the child process.
*/
char *
child_pid_to_exec_file (int pid)
@ -30,3 +43,229 @@ child_pid_to_exec_file (int pid)
/* FIXME use readlink to get the real name. */
return fname;
}
/* Function: linux_find_memory_regions
*
* Fills the "to_find_memory_regions" target vector.
* Lists the memory regions in the inferior for a corefile.
*/
static int
linux_find_memory_regions (int (*func) (CORE_ADDR,
unsigned long,
int, int, int,
void *),
void *obfd)
{
long long pid = PIDGET (inferior_ptid);
char procfilename[MAXPATHLEN];
FILE *procfile;
long long addr, endaddr, size, offset, inode;
char perms[8], dev[8], filename[MAXPATHLEN];
int read, write, exec;
int ret;
/* Compose the filename for the /proc memory map, and open it. */
sprintf (procfilename, "/proc/%lld/maps", pid);
if ((procfile = fopen (procfilename, "r")) == NULL)
error ("Could not open %s\n", procfilename);
if (info_verbose)
fprintf_filtered (gdb_stdout,
"Reading memory regions from %s\n", procfilename);
/* Read the first memory segment descriptor from the maps file. */
ret = fscanf (procfile, "%llx-%llx %s %llx %s %llx",
&addr, &endaddr, perms, &offset, dev, &inode);
if (inode)
fscanf (procfile, " %s\n", filename);
else
{
filename[0] = '\0';
fscanf (procfile, "\n");
}
/* Now iterate until end-of-file. */
while (ret > 0 && ret != EOF)
{
size = endaddr - addr;
/* Get the segment's permissions. */
read = (strchr (perms, 'r') != 0);
write = (strchr (perms, 'w') != 0);
exec = (strchr (perms, 'x') != 0);
if (info_verbose)
{
fprintf_filtered (gdb_stdout,
"Save segment, %lld bytes at 0x%s (%c%c%c)",
size, paddr_nz (addr),
read ? 'r' : ' ',
write ? 'w' : ' ',
exec ? 'x' : ' ');
if (filename && filename[0])
fprintf_filtered (gdb_stdout,
" for %s", filename);
fprintf_filtered (gdb_stdout, "\n");
}
/* Invoke the callback function to create the corefile segment. */
func (addr, size, read, write, exec, obfd);
/* Read the next memory region. */
filename[0] = '\0';
ret = fscanf (procfile, "%llx-%llx %s %llx %s %llx",
&addr, &endaddr, perms, &offset, dev, &inode);
if (inode)
fscanf (procfile, " %s\n", filename);
else
{
filename[0] = '\0';
fscanf (procfile, "\n");
}
}
fclose (procfile);
return 0;
}
/* Function: linux_do_thread_registers
*
* Records the thread's register state for the corefile note section.
*/
static char *
linux_do_thread_registers (bfd *obfd, ptid_t ptid,
char *note_data, int *note_size)
{
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
#ifdef HAVE_PTRACE_GETFPXREGS
gdb_fpxregset_t fpxregs;
#endif
unsigned long merged_pid = ptid_get_tid (ptid) << 16 | ptid_get_pid (ptid);
fill_gregset (&gregs, -1);
note_data = (char *) elfcore_write_prstatus (obfd,
note_data,
note_size,
merged_pid,
stop_signal,
&gregs);
fill_fpregset (&fpregs, -1);
note_data = (char *) elfcore_write_prfpreg (obfd,
note_data,
note_size,
&fpregs,
sizeof (fpregs));
#ifdef HAVE_PTRACE_GETFPXREGS
fill_fpxregset (&fpxregs, -1);
note_data = (char *) elfcore_write_prxfpreg (obfd,
note_data,
note_size,
&fpxregs,
sizeof (fpxregs));
#endif
return note_data;
}
struct linux_corefile_thread_data {
bfd *obfd;
char *note_data;
int *note_size;
};
/* Function: linux_corefile_thread_callback
*
* Called by gdbthread.c once per thread.
* Records the thread's register state for the corefile note section.
*/
static int
linux_corefile_thread_callback (struct thread_info *ti, void *data)
{
struct linux_corefile_thread_data *args = data;
ptid_t saved_ptid = inferior_ptid;
inferior_ptid = ti->ptid;
registers_changed ();
target_fetch_registers (-1); /* FIXME should not be necessary;
fill_gregset should do it automatically. */
args->note_data = linux_do_thread_registers (args->obfd,
ti->ptid,
args->note_data,
args->note_size);
inferior_ptid = saved_ptid;
registers_changed ();
target_fetch_registers (-1); /* FIXME should not be necessary;
fill_gregset should do it automatically. */
return 0;
}
/* Function: linux_make_note_section
*
* Fills the "to_make_corefile_note" target vector.
* Builds the note section for a corefile, and returns it
* in a malloc buffer.
*/
static char *
linux_make_note_section (bfd *obfd, int *note_size)
{
struct linux_corefile_thread_data thread_args;
struct cleanup *old_chain;
char fname[16] = {'\0'};
char psargs[80] = {'\0'};
char *note_data = NULL;
ptid_t current_ptid = inferior_ptid;
if (get_exec_file (0))
{
strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
strncpy (psargs, get_exec_file (0),
sizeof (psargs));
if (get_inferior_args ())
{
strncat (psargs, " ",
sizeof (psargs) - strlen (psargs));
strncat (psargs, get_inferior_args (),
sizeof (psargs) - strlen (psargs));
}
note_data = (char *) elfcore_write_prpsinfo (obfd,
note_data,
note_size,
fname,
psargs);
}
/* Dump information for threads. */
thread_args.obfd = obfd;
thread_args.note_data = note_data;
thread_args.note_size = note_size;
iterate_over_threads (linux_corefile_thread_callback, &thread_args);
if (thread_args.note_data == note_data)
{
/* iterate_over_threads didn't come up with any threads;
just use inferior_ptid. */
note_data = linux_do_thread_registers (obfd, inferior_ptid,
note_data, note_size);
}
else
{
note_data = thread_args.note_data;
}
make_cleanup (xfree, note_data);
return note_data;
}
void
_initialize_linux_proc (void)
{
extern void inftarg_set_find_memory_regions ();
extern void inftarg_set_make_corefile_notes ();
inftarg_set_find_memory_regions (linux_find_memory_regions);
inftarg_set_make_corefile_notes (linux_make_note_section);
}

View File

@ -1,5 +1,5 @@
/* Machine independent support for SVR4 /proc (process file system) for GDB.
Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Written by Michael Snyder at Cygnus Solutions.
Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
@ -127,6 +127,14 @@ static int procfs_thread_alive (ptid_t);
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
@ -172,6 +180,8 @@ init_procfs_ops (void)
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;
}
@ -5354,6 +5364,65 @@ proc_iterate_over_mappings (int (*func) (int, CORE_ADDR))
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
*
@ -5650,3 +5719,109 @@ procfs_first_available (void)
{
return pid_to_ptid (procinfo_list ? procinfo_list->pid : -1);
}
/* =================== GCORE .NOTE "MODULE" =================== */
static char *
procfs_do_thread_registers (bfd *obfd, ptid_t ptid,
char *note_data, int *note_size)
{
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
unsigned long merged_pid;
merged_pid = TIDGET (ptid) << 16 | PIDGET (ptid);
fill_gregset (&gregs, -1);
note_data = (char *) elfcore_write_prstatus (obfd,
note_data,
note_size,
merged_pid,
stop_signal,
&gregs);
fill_fpregset (&fpregs, -1);
note_data = (char *) elfcore_write_prfpreg (obfd,
note_data,
note_size,
&fpregs,
sizeof (fpregs));
return note_data;
}
struct procfs_corefile_thread_data {
bfd *obfd;
char *note_data;
int *note_size;
};
static int
procfs_corefile_thread_callback (struct thread_info *ti, void *data)
{
struct procfs_corefile_thread_data *args = data;
procinfo *pi = find_procinfo (PIDGET (ti->ptid), TIDGET (ti->ptid));
if (pi != NULL && TIDGET (ti->ptid) != 0)
{
ptid_t saved_ptid = inferior_ptid;
inferior_ptid = ti->ptid;
args->note_data = procfs_do_thread_registers (args->obfd, ti->ptid,
args->note_data,
args->note_size);
inferior_ptid = saved_ptid;
}
return 0;
}
static char *
procfs_make_note_section (bfd *obfd, int *note_size)
{
struct cleanup *old_chain;
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
char fname[16] = {'\0'};
char psargs[80] = {'\0'};
procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
char *note_data = NULL;
struct procfs_corefile_thread_data thread_args;
if (get_exec_file (0))
{
strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
strncpy (psargs, get_exec_file (0),
sizeof (psargs));
if (get_inferior_args ())
{
strncat (psargs, " ",
sizeof (psargs) - strlen (psargs));
strncat (psargs, get_inferior_args (),
sizeof (psargs) - strlen (psargs));
}
}
note_data = (char *) elfcore_write_prpsinfo (obfd,
note_data,
note_size,
fname,
psargs);
thread_args.obfd = obfd;
thread_args.note_data = note_data;
thread_args.note_size = note_size;
iterate_over_threads (procfs_corefile_thread_callback, &thread_args);
if (thread_args.note_data == note_data)
{
/* iterate_over_threads didn't come up with any threads;
just use inferior_ptid. */
note_data = procfs_do_thread_registers (obfd, inferior_ptid,
note_data, note_size);
}
else
{
note_data = thread_args.note_data;
}
make_cleanup (xfree, note_data);
return note_data;
}
/* =================== END GCORE .NOTE "MODULE" =================== */

View File

@ -1,5 +1,5 @@
/* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
Copyright 1996, 1997, 1998, 1999, 2000, 2001
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
This file is part of GDB.
@ -1510,6 +1510,22 @@ info_solthreads (char *args, int from_tty)
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
}
static int
sol_find_memory_regions (int (*func) (CORE_ADDR,
unsigned long,
int, int, int,
void *),
void *data)
{
return procfs_ops.to_find_memory_regions (func, data);
}
static char *
sol_make_note_section (bfd *obfd, int *note_size)
{
return procfs_ops.to_make_corefile_notes (obfd, note_size);
}
static int
ignore (CORE_ADDR addr, char *contents)
{
@ -1561,6 +1577,8 @@ init_sol_thread_ops (void)
sol_thread_ops.to_has_thread_control = tc_none;
sol_thread_ops.to_sections = 0;
sol_thread_ops.to_sections_end = 0;
sol_thread_ops.to_find_memory_regions = sol_find_memory_regions;
sol_thread_ops.to_make_corefile_notes = sol_make_note_section;
sol_thread_ops.to_magic = OPS_MAGIC;
}

View File

@ -1,6 +1,7 @@
/* Select target systems and architectures at runtime for GDB.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
2000, 2001 Free Software Foundation, Inc.
2000, 2001, 2002
Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB.
@ -607,6 +608,8 @@ update_current_target (void)
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
@ -1461,6 +1464,22 @@ normal_target_post_startup_inferior (ptid_t ptid)
/* 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. */
@ -1477,6 +1496,8 @@ init_dummy_target (void)
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;
}

View File

@ -1,6 +1,6 @@
/* Interface between GDB and target environments, including files and processes
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
2000, 2001 Free Software Foundation, Inc.
2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by Cygnus Support. Written by John Gilmore.
This file is part of GDB.
@ -313,6 +313,12 @@ struct target_ops
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?
*/
@ -999,6 +1005,23 @@ extern void (*target_new_objfile_hook) (struct objfile *);
#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. */
#ifndef TARGET_SYMFILE_POSTREAD