public inbox for gdb@sourceware.org
 help / color / mirror / Atom feed
* [RFC] a prototype checkpoint-restart using core files
@ 2005-11-03  1:35 Michael Snyder
  2005-11-07  0:19 ` Daniel Jacobowitz
  2005-11-16  0:37 ` Stan Shebs
  0 siblings, 2 replies; 16+ messages in thread
From: Michael Snyder @ 2005-11-03  1:35 UTC (permalink / raw)
  To: gdb, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1519 bytes --]

Folks, this isn't for commit, just for discussion.

Attached is an experimental patch that adds a command
"restore-core-file" or "rcore", which is the inverse of
"generate-core-file" (gcore).  Instead of copying the
memory and register state of a process into a file,
it takes an existing corefile, and copies its memory
and register state into the child process.

The idea was to experiment with the concept of doing
checkpoint and restore, by using a corefile as the
checkpoint file.  Obviously it has limitations --
it doesn't save any kernel state, I/O state etc.
Just user state.

But it turns out that if you avoid those limitations,
it works!  As a conservative rule of thumb, you can
go back to an earlier state so long as you don't cross
a system call.  And in practice there are lots of
system calls that can be regarded as "stateless",
or that change only user state -- so you can cross
those.

I've only tried it on Linux, but it seems to me that
it should be pretty portable, at least to hosts for
which 'gcore' works.

This may be useful for anyone who wants to experiment
with the idea of checkpoint and restart, get a feel
for how it would work in practice, and look for
"gotchas" where the sudden state change might interfere
with something else in gdb.  For a "real" checkpoint
and restart facility, we would probably want to handle
some amount of kernel state and I/O state, but
gcore/rcore might even be somewhat useful as-is
(at least to a knowledgeable user who understands
their limitations).




[-- Attachment #2: rcore.diff --]
[-- Type: text/plain, Size: 4948 bytes --]

Index: gcore.c
===================================================================
RCS file: /cvs/src/src/gdb/gcore.c,v
retrieving revision 1.17
diff -p -r1.17 gcore.c
*** gcore.c	15 Feb 2005 15:49:10 -0000	1.17
--- gcore.c	3 Nov 2005 01:19:53 -0000
*************** gcore_memory_sections (bfd *obfd)
*** 488,493 ****
--- 488,621 ----
    return 1;
  }
  
+ /* OK now, I want to add a new command to read a corefile, 
+    and restore its state into the inferior process.  Obviously
+    dangerous, probably want to make certain that they are 
+    actually the same process!  But we can put that off till
+    later.  Let's see what's required.  This should actually
+    be pretty easy.  */
+ 
+ static void
+ load_core_sections (bfd *abfd, asection *asect, void *arg)
+ {
+   unsigned long from_tty = (unsigned long) arg;
+   char *memhunk;
+ 
+   if ((bfd_section_size (abfd, asect) > 0) &&
+       (bfd_get_section_flags (abfd, asect) & SEC_LOAD))
+     {
+       if (info_verbose && from_tty)
+ 	{
+ 	  printf_filtered (_("Load core section %s"), 
+ 			   bfd_section_name (abfd, asect));
+ 	  printf_filtered (_(", address 0x%08lx"), 
+ 			   (unsigned long) bfd_section_vma (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));
+       target_write_memory (bfd_section_vma (abfd, asect), 
+ 			   memhunk, 
+ 			   bfd_section_size (abfd, asect));
+       xfree (memhunk);
+     }
+ }
+ 
+ #include <fcntl.h>
+ #ifndef O_BINARY
+ #define O_BINARY 0
+ #endif
+ 
+ #include "regcache.h"
+ #include "regset.h"
+ 
+ static void
+ rcore_command (char *args, int from_tty)
+ {
+   /* corelow.c core_open */
+   /* scratch_chan = open (filename)
+      temp_bfd = bfd_fdopenr (filename, gnutarget, scratch_chan)
+      bfd_check_format (temp_bfd, bfd_core)
+      build_section_table (core_bfd, to_sections, to_sections_end)
+      bfd_map_over_sections (core_bfd, myfunc)
+      myfunc will check for loadable, contents, and size, 
+      and then write the section contents into memory at vma.
+   */
+   char *corefilename, corefilename_buffer[40], *scratch_path;
+   int  scratch_chan;
+   bfd  *core_bfd;
+ 
+   /* Can't restore 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 input.\n"), corefilename);
+ 
+   scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, corefilename, 
+ 			O_BINARY | O_RDONLY | O_LARGEFILE, 0, &scratch_path);
+   if (scratch_chan < 0)
+     perror_with_name (corefilename);
+ 
+   core_bfd = bfd_fdopenr (scratch_path, gnutarget, scratch_chan);
+   if (!core_bfd)
+     perror_with_name (scratch_path);
+ 
+   if (!bfd_check_format (core_bfd, bfd_core))
+     {
+       make_cleanup_bfd_close (core_bfd);
+       error (_("\"%s\" is not a core file: %s"), 
+ 	     corefilename, bfd_errmsg (bfd_get_error ()));
+     }
+ 
+   bfd_map_over_sections (core_bfd, load_core_sections, (void *) from_tty);
+   /* Now need to get/set registers.  */
+   {
+     struct bfd_section *regsect = bfd_get_section_by_name (core_bfd, ".reg");
+     char *contents;
+     int size;
+ 
+     if (!regsect)
+       error (_("Couldn't find .reg section."));
+ 
+     size = bfd_section_size (core_bfd, regsect);
+     contents = xmalloc (size);
+     bfd_get_section_contents (core_bfd, regsect, contents, 0, size);
+ 
+     if (gdbarch_regset_from_core_section_p (current_gdbarch))
+       {
+ 	const struct regset *regset;
+ 
+ 	regset = gdbarch_regset_from_core_section (current_gdbarch, 
+ 						   ".reg", size);
+ 	if (!regset)
+ 	  error (_("Failed to allocate regset."));
+ 
+ 	registers_changed ();
+ 	regset->supply_regset (regset, current_regcache, 
+ 			       -1, contents, size);
+ 	reinit_frame_cache ();
+ 	target_store_registers (-1);
+       }
+   }
+ 
+   bfd_close (core_bfd);
+ }
+ 
  void
  _initialize_gcore (void)
  {
*************** Argument is optional filename.  Default 
*** 497,500 ****
--- 625,633 ----
  
    add_com_alias ("gcore", "generate-core-file", class_files, 1);
    exec_set_find_memory_regions (objfile_find_memory_regions);
+ 
+   add_com ("restore-core-file", class_files, 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>'."));
+   add_com_alias ("rcore", "restore-core-file", class_files, 1);
  }

^ permalink raw reply	[flat|nested] 16+ messages in thread
* Re: [RFC] a prototype checkpoint-restart using core files
@ 2005-11-18  3:37 Michael Snyder
  0 siblings, 0 replies; 16+ messages in thread
From: Michael Snyder @ 2005-11-18  3:37 UTC (permalink / raw)
  To: Stan Shebs; +Cc: GDB Patches, gdb

Stan Shebs wrote:
 > Michael Snyder wrote:

 >> Folks, this isn't for commit, just for discussion.
 >>
 >> Attached is an experimental patch that adds a command
 >> "restore-core-file" or "rcore", which is the inverse of
 >> "generate-core-file" (gcore).  Instead of copying the
 >> memory and register state of a process into a file,
 >> it takes an existing corefile, and copies its memory
 >> and register state into the child process.
 >
 > My prototype is even lamer :-) I use target read/write
 > operations to collect state - but it can step backwards.

Don't beat up on yourself -- gcore works by using
target read and write.  It's just a convenient
file format for saving target state.

 > An improved version in the works uses vfork() to make
 > core images more cheaply.

Aha!  Linux fork is similar to vfork, in that it does
not immediately make a copy of user memory.  Did you
have a chance to look at my later patch based on fork?

 > One idea I've considered is getting the OS to set up
 > some kind of notification at system calls, and then use
 > it to warn the user who tries to resume the inferior
 > after rolling back.

Yeah, ptrace on linux provides such a notification.
I know you don't have ptrace on your OS, but you might
think about mimicing the ptrace user interface, if only
so that you don't have to design one of your own.  ;-)

Stan, do you remember the trace/replay utility that
Michael Chastain invented?  I was thinking that would
come in pretty handy in this context.

Michael

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2005-11-18  3:37 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-11-03  1:35 [RFC] a prototype checkpoint-restart using core files Michael Snyder
2005-11-07  0:19 ` Daniel Jacobowitz
2005-11-07  4:40   ` Eli Zaretskii
2005-11-07 18:57     ` Mark Kettenis
2005-11-07 19:07       ` Daniel Jacobowitz
2005-11-07 19:50         ` Michael Snyder
2005-11-07 20:22         ` Mark Kettenis
2005-11-07 20:26           ` Daniel Jacobowitz
2005-11-07 23:56             ` Michael Snyder
2005-11-08  0:34               ` Soam Vasani
2005-11-08  0:43                 ` Michael Snyder
2005-11-07 19:43       ` Michael Snyder
2005-11-07 20:56       ` Eli Zaretskii
2005-11-08  0:10         ` Michael Snyder
2005-11-16  0:37 ` Stan Shebs
2005-11-18  3:37 Michael Snyder

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).