diff options
author | Michael Snyder <msnyder@vmware.com> | 2009-08-07 01:19:25 +0000 |
---|---|---|
committer | Michael Snyder <msnyder@vmware.com> | 2009-08-07 01:19:25 +0000 |
commit | c1e716589087ef0cabfca58a16da3b160c204000 (patch) | |
tree | c602c4983bba6f28964c478eaf7ab6729cd1a036 | |
parent | 8a4187307c62c8580ef16a02b6d9d9cc5459aff8 (diff) | |
download | gdb-c1e716589087ef0cabfca58a16da3b160c204000.zip gdb-c1e716589087ef0cabfca58a16da3b160c204000.tar.gz gdb-c1e716589087ef0cabfca58a16da3b160c204000.tar.bz2 |
2009-08-06 Michael Snyder <msnyder@msnyder-server.eng.vmware.com>
* gcore.c (create_gcore_bfd): New function, abstracted
from gcore_command for export.
(write_gcore_file): New function, abstracted from
gcore_command for export.
(gcore_command): Call helper functions (above).
(call_target_sbrk): New function, abstracted from
derive_heap_segment.
(derive_heap_segment): Call helper function (above).
(load_core_segments): New function.
(load_corefile): New function.
(rcore_command): New function.
(_initialize_gcore): Add new command "restore-core-file".
-rw-r--r-- | gdb/ChangeLog | 17 | ||||
-rw-r--r-- | gdb/gcore.c | 365 |
2 files changed, 321 insertions, 61 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b68d82e..4a4f06b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +2009-08-06 Michael Snyder <msnyder@msnyder-server.eng.vmware.com> + + * gcore.c (create_gcore_bfd): New function, abstracted + from gcore_command for export. + (write_gcore_file): New function, abstracted from + gcore_command for export. + (gcore_command): Call helper functions (above). + + (call_target_sbrk): New function, abstracted from + derive_heap_segment. + (derive_heap_segment): Call helper function (above). + + (load_core_segments): New function. + (load_corefile): New function. + (rcore_command): New function. + (_initialize_gcore): Add new command "restore-core-file". + 2009-08-06 Michael Snyder <msnyder@vmware.com> * record.c (record_goto_checkpoint): Call record_exec_entry. diff --git a/gdb/gcore.c b/gdb/gcore.c index 5bc38e2..80cf2c6 100644 --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -25,6 +25,8 @@ #include "gdbcore.h" #include "objfiles.h" #include "symfile.h" +#include "arch-utils.h" +#include "completer.h" #include "cli/cli-decode.h" @@ -40,45 +42,27 @@ static enum bfd_architecture default_gcore_arch (void); static unsigned long default_gcore_mach (void); static int gcore_memory_sections (bfd *); -/* Generate a core file from the inferior process. */ +/* create_gcore_bfd -- helper for gcore_command (exported). */ -static void -gcore_command (char *args, int from_tty) +extern bfd * +create_gcore_bfd (char *filename) { - struct cleanup *old_chain; - char *corefilename, corefilename_buffer[40]; - asection *note_sec = NULL; - 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. */ - obfd = bfd_openw (corefilename, default_gcore_target ()); + bfd *obfd = bfd_openw (filename, default_gcore_target ()); if (!obfd) - 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); - + error (_("Failed to open '%s' for output."), filename); bfd_set_format (obfd, bfd_core); bfd_set_arch_mach (obfd, default_gcore_arch (), default_gcore_mach ()); + return obfd; +} + +/* write_gcore_file -- helper for gcore_command (exported). */ + +extern void +write_gcore_file (bfd *obfd) +{ + void *note_data = NULL; + int note_size = 0; + asection *note_sec = NULL; /* An external target method must build the notes section. */ note_data = target_make_corefile_notes (obfd, ¬e_size); @@ -107,8 +91,46 @@ gcore_command (char *args, int from_tty) 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 ())); + warning (_("writing note section (%s)"), + bfd_errmsg (bfd_get_error ())); } +} + +/* gcore_command -- implements the '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]; + bfd *obfd; + + /* 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. */ + obfd = create_gcore_bfd (corefilename); + + /* Need a cleanup that will close the file (FIXME: delete it?). */ + old_chain = make_cleanup_bfd_close (obfd); + + /* Call worker function. */ + write_gcore_file (obfd); /* Succeeded. */ fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename); @@ -212,6 +234,47 @@ derive_stack_segment (bfd_vma *bottom, bfd_vma *top) return 1; } +static bfd_vma +call_target_sbrk (int sbrk_arg) +{ + struct objfile *sbrk_objf; + struct gdbarch *gdbarch; + bfd_vma top_of_heap; + struct value *target_sbrk_arg; + struct value *sbrk_fn, *ret; + bfd_vma tmp; + + if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL) + { + sbrk_fn = find_function_in_inferior ("sbrk", &sbrk_objf); + if (sbrk_fn == NULL) + return (bfd_vma) 0; + } + else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL) + { + sbrk_fn = find_function_in_inferior ("_sbrk", &sbrk_objf); + if (sbrk_fn == NULL) + return (bfd_vma) 0; + } + else + return (bfd_vma) 0; + + gdbarch = get_objfile_arch (sbrk_objf); + target_sbrk_arg = value_from_longest (builtin_type (gdbarch)->builtin_int, + sbrk_arg); + gdb_assert (target_sbrk_arg); + ret = call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg); + if (ret == NULL) + return (bfd_vma) 0; + + tmp = value_as_long (ret); + if ((LONGEST) tmp <= 0 || (LONGEST) tmp == 0xffffffff) + return (bfd_vma) 0; + + top_of_heap = tmp; + return top_of_heap; +} + /* Derive a reasonable heap segment for ABFD by looking at sbrk and the static data sections. Store its limits in *BOTTOM and *TOP. Return non-zero if successful. */ @@ -219,12 +282,10 @@ derive_stack_segment (bfd_vma *bottom, bfd_vma *top) static int derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top) { - struct objfile *sbrk_objf; struct gdbarch *gdbarch; 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; @@ -259,29 +320,9 @@ derive_heap_segment (bfd *abfd, bfd_vma *bottom, bfd_vma *top) } } - /* Now get the top-of-heap by calling sbrk in the inferior. */ - if (lookup_minimal_symbol ("sbrk", NULL, NULL) != NULL) - { - sbrk = find_function_in_inferior ("sbrk", &sbrk_objf); - if (sbrk == NULL) - return 0; - } - else if (lookup_minimal_symbol ("_sbrk", NULL, NULL) != NULL) - { - sbrk = find_function_in_inferior ("_sbrk", &sbrk_objf); - if (sbrk == NULL) - return 0; - } - else - return 0; - - gdbarch = get_objfile_arch (sbrk_objf); - zero = value_from_longest (builtin_type (gdbarch)->builtin_int, 0); - gdb_assert (zero); - sbrk = call_function_by_hand (sbrk, 1, &zero); - if (sbrk == NULL) + top_of_heap = call_target_sbrk (0); + if (top_of_heap == (bfd_vma) 0) return 0; - top_of_heap = value_as_long (sbrk); /* Return results. */ if (top_of_heap > top_of_data_memory) @@ -299,13 +340,15 @@ static void make_output_phdrs (bfd *obfd, asection *osec, void *ignored) { int p_flags = 0; - int p_type; + int p_type = 0; /* FIXME: these constants may only be applicable for ELF. */ if (strncmp (bfd_section_name (obfd, osec), "load", 4) == 0) p_type = PT_LOAD; - else + else if (strncmp (bfd_section_name (obfd, osec), "note", 4) == 0) p_type = PT_NOTE; + else + p_type = PT_NULL; p_flags |= PF_R; /* Segment is readable. */ if (!(bfd_get_section_flags (obfd, osec) & SEC_READONLY)) @@ -516,16 +559,216 @@ gcore_memory_sections (bfd *obfd) return 1; } +struct load_core_args_params { + int from_tty; + bfd_vma top_of_heap; +}; + +static void +load_core_segments (bfd *abfd, asection *asect, void *arg) +{ + struct load_core_args_params *params = arg; + struct cleanup *old_chain; + char *memhunk; + int ret; + + if ((bfd_section_size (abfd, asect) > 0) && + (bfd_get_section_flags (abfd, asect) & SEC_LOAD) && + !(bfd_get_section_flags (abfd, asect) & SEC_READONLY)) + { + if (info_verbose && params->from_tty) + { + printf_filtered (_("Load core section %s"), + bfd_section_name (abfd, asect)); + printf_filtered (_(", vma 0x%08lx to 0x%08lx"), + (unsigned long) bfd_section_vma (abfd, asect), + (unsigned long) bfd_section_vma (abfd, asect) + + (int) bfd_section_size (abfd, asect)); + printf_filtered (_(", size = %d"), + (int) bfd_section_size (abfd, asect)); + printf_filtered (_(".\n")); + } + /* Fixme cleanup? */ + memhunk = xmalloc (bfd_section_size (abfd, asect)); + bfd_get_section_contents (abfd, asect, memhunk, 0, + bfd_section_size (abfd, asect)); + if ((ret = target_write_memory (bfd_section_vma (abfd, asect), + memhunk, + bfd_section_size (abfd, asect))) != 0) + { + print_sys_errmsg ("load_core_segments", ret); + if ((LONGEST) params->top_of_heap < + (LONGEST) bfd_section_vma (abfd, asect) + + (LONGEST) bfd_section_size (abfd, asect)) + { + int increment = bfd_section_vma (abfd, asect) + + bfd_section_size (abfd, asect) - params->top_of_heap; + + params->top_of_heap = call_target_sbrk (increment); + if (params->top_of_heap == 0) + error ("sbrk failed, TOH = 0x%08lx", params->top_of_heap); + else + printf_filtered ("Increase TOH to 0x%08lx and retry.\n", + (unsigned long) params->top_of_heap); + if (target_write_memory (bfd_section_vma (abfd, asect), + memhunk, + bfd_section_size (abfd, asect)) != 0) + { + error ("Nope, still failed."); + } + } + } + xfree (memhunk); + } +} + +#include <fcntl.h> +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#include "regcache.h" +#include "regset.h" + +extern bfd * +load_corefile (char *filename, int from_tty) +{ + struct load_core_args_params params; + struct bfd_section *regsect; + const struct regset *regset; + struct regcache *regcache; + struct cleanup *old_chain; + struct gdbarch *gdbarch; + char *scratch_path; + int scratch_chan; + char *contents; + bfd *core_bfd; + int size; + + scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename, + O_BINARY | O_RDONLY | O_LARGEFILE, &scratch_path); + if (scratch_chan < 0) + perror_with_name (filename); + + core_bfd = bfd_fdopenr (scratch_path, gnutarget, scratch_chan); + old_chain = make_cleanup_bfd_close (core_bfd); + if (!core_bfd) + perror_with_name (scratch_path); + + if (!bfd_check_format (core_bfd, bfd_core)) + error (_("\"%s\" is not a core file: %s"), + filename, bfd_errmsg (bfd_get_error ())); + + params.from_tty = from_tty; + params.top_of_heap = call_target_sbrk (0); + if (params.top_of_heap == 0) + error (_("Couldn't get sbrk.")); + + bfd_map_over_sections (core_bfd, load_core_segments, (void *) ¶ms); + /* Now need to get/set registers. */ + regsect = bfd_get_section_by_name (core_bfd, ".reg"); + + if (!regsect) + error (_("Couldn't find .reg section.")); + + size = bfd_section_size (core_bfd, regsect); + contents = alloca (size); + bfd_get_section_contents (core_bfd, regsect, contents, 0, size); + + /* See FIXME kettenis/20031023 comment in corelow.c */ + gdbarch = gdbarch_from_bfd (core_bfd); + + if (gdbarch && gdbarch_regset_from_core_section_p (gdbarch)) + { + regset = gdbarch_regset_from_core_section (gdbarch, ".reg", size); + if (!regset) + error (_("Failed to allocate regset.")); + + registers_changed (); + regcache = get_current_regcache (); + regset->supply_regset (regset, regcache, -1, contents, size); + reinit_frame_cache (); + target_store_registers (regcache, -1); + } + else + error (_("Failed to get regset from core section")); + + discard_cleanups (old_chain); + return core_bfd; +} + +static void +rcore_command (char *args, int from_tty) +{ + extern void nullify_last_target_wait_ptid (void); + char *corefilename, corefilename_buffer[40]; + struct cleanup *old_chain; + static int rcore_warned; + bfd *core_bfd; + + /* Can't restore a corefile without a target process. */ + if (!target_has_execution) + noprocess (); + + /* Experimental warning. Remove upon confidence. */ + if (!rcore_warned) + { + warning ("This command is experimental, and may have dire\n\ +and unexpected results! Proceed at your own risk."); + if (!query ("Are you sure you want to go there? ")) + { + fputs_filtered ("Cancelled at user request.\n", gdb_stdout); + return; + } + else + { + fputs_filtered ("Very well. Warning will not be repeated.\n", + gdb_stdout); + } + } + rcore_warned = 1; + + 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 input.\n"), corefilename); + + core_bfd = load_corefile (corefilename, from_tty); + old_chain = make_cleanup_bfd_close (core_bfd); + + reinit_frame_cache (); + nullify_last_target_wait_ptid (); + print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); + /* Cleanups will close bfd etc. */ + do_cleanups (old_chain); +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_gcore; void _initialize_gcore (void) { + struct cmd_list_element *c; + 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); + + c = add_com ("restore-core-file", class_obscure, rcore_command, _("\ +Restore the machine state from a core file into the debugged process.\n\ +Argument is optional filename. Default filename is 'core.<process_id>'.")); + set_cmd_completer (c, filename_completer); + add_com_alias ("rcore", "restore-core-file", class_obscure, 1); } |