Replacing a bogus file with a semi-bogus one (sharing through devo).
[deliverable/binutils-gdb.git] / gdb / state.c
index b6ce398015b4444379d2008b3f24622617a884a9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,777 +0,0 @@
-/* Support for dumping and reloading various pieces of GDB's internal state.
-   Copyright 1992 Free Software Foundation, Inc.
-   Contributed by Cygnus Support, using pieces from other GDB modules.
-
-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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-/* This file provides support for dumping and then later reloading various
-   portions of gdb's internal state.  It was originally implemented to
-   support a need for mapping in an image of gdb's symbol table from an
-   external file, where this image was created by an external program, such
-   as an incremental linker.  However, it was generalized to enable future
-   support for dumping and reloading various other useful pieces of gdb's
-   internal state.
-
-   State files have a fairly simple form which is intended to be easily
-   extensible.  The basic format is:
-
-       <file-header> <state-data> <form-tree>
-
-   Where:
-
-        file-header    A simple file-header containing a magic number
-                       so that gdb (and other readers) can quickly
-                       determine what kind of file this is, and a file
-                       offset to the root of the form-tree.
-
-       state-data      The "raw" state-data that is referenced by nodes
-                       in the form-tree.
-
-       form-tree       A tree of arbitrarily sized nodes containing
-                       information about gdb's internal state, and
-                       possibly referencing data in the state-data section
-                       of the file.  Resembles DWARF in some respects.
-
-   When writing a state file, a hole is left for the file-header at the
-   beginning of the file, the state data is written immediately after the
-   file header (while storing the file offsets and sizes back into the
-   internal form-tree along the way), the form-tree itself is written
-   at the end of the file, and then the file header is written by seeking
-   back to the beginning of the file.  This order is required because
-   the form tree contains file offsets and sizes in the state data portion
-   of the file, and the file header contains the file offset to the start
-   of the form tree.
-
-   Readers simply open the file, validate the magic number, seek to the
-   root of the form-tree, and walk the tree looking for the information that
-   they are interested in (and ignoring things that they aren't, or don't
-   understand).
-
-   */
-
-
-#include <stdio.h>
-#include "defs.h"
-#include "symtab.h"
-#include "bfd.h"
-#include "symfile.h"
-#include "state.h"
-
-#ifndef SEEK_SET
-#define SEEK_SET 0
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END 2
-#endif
-
-/* Inside the state file, the form-tree consists of a series of
-   form-tree entries (FTE's).  The parent/child/sibling relationships
-   are implied by the ordering and by an explicit sibling reference
-   in FTE's that have siblings.
-
-   Specifically, given two sequential FTE's, say A and B, if B immediately
-   follows A, and A does not have a sibling reference to B, then B is
-   the first child of A.  Otherwise B must be a sibling of A and A must
-   have a sibling reference for it.
-
-   Each FTE is simply an array of long integers, with at least three
-   members.  This form was chosen over a packed data form for simplicity
-   in access, not having to worry about the relative sizes of the different
-   integers (short, int, long), and not having to worry about alignment
-   constraints.  Also in the name of simplicity, every FTE has a sibling
-   reference slot reserved for it, even if there are no siblings.
-
-   The first value in an FTE is the size of the FTE in bytes, including
-   the size value itself.  The second entry contains a tag which indicates
-   the type of the FTE.  The third entry is a sibling reference, which either
-   refers to a valid sibling node or is zero.  Following is zero or more
-   attributes, each of which consists of one or more long values. */
-
-/* Tag names and codes. */
-
-#define TAG_padding    0x0000          /* Padding */
-#define TAG_objfile    0x0001          /* Dumped objfile */
-
-/* Form names, codes, and macros. */
-
-#define FORM_ABSREF    0x01            /* Next long is absolute file offset */
-#define FORM_RELREF    0x02            /* Next long is relative file offset */
-#define FORM_IVAL      0x03            /* Next long is int value */
-#define FORM_ADDR      0x04            /* Next long is mem addr */
-
-#define FORM_MASK      0xFF
-#define FORM_X(atr)    ((atr) & FORM_MASK)
-
-/* Attribute names and codes. */
-
-#define AT_sibling     (0x0100 | FORM_RELREF)  /* Reference to sibling node */
-#define AT_name                (0x0200 | FORM_ABSREF)  /* Reference to a string */
-#define AT_offset      (0x0300 | FORM_ABSREF)  /* Reference to generic data */
-#define AT_size                (0x0400 | FORM_IVAL)
-#define AT_addr                (0x0500 | FORM_ADDR)
-#define AT_aux_addr    (0x0600 | FORM_ADDR)
-
-/* */
-
-static void
-load_symbols PARAMS ((FILE *));
-
-static void
-dump_state_command PARAMS ((char *, int));
-
-static void
-load_state_command PARAMS ((char *, int));
-
-#ifdef HAVE_MMAP
-
-static void
-write_header PARAMS ((sfd *));
-
-static void
-write_formtree PARAMS ((sfd *));
-
-static void
-write_objfile_state PARAMS ((sfd *));
-
-static void
-free_subtree PARAMS ((struct formnode *));
-
-static void
-size_subtree PARAMS ((struct formnode *));
-
-#endif
-
-struct formnode *formtree = NULL;
-
-/* ARGSUSED */
-static void
-load_symbols (statefile)
-     FILE *statefile;
-{
-
-#if 0
-  /* Discard old symbols.  FIXME: This is essentially symbol_file_command's
-     body when there is no name.  Make it a common function that is
-     called from each place. */
-
-  if (symfile_objfile)
-    {
-      free_objfile (symfile_objfile);
-    }
-  symfile_objfile = NULL;
-#endif
-
-#if 0 && defined (HAVE_MMAP)
-  if (mtop > mbase)
-    {
-      warning ("internal error: mbase (%08x) != mtop (%08x)",
-              mbase, mtop);
-      munmap (mbase, mtop - mbase);
-    }
-#endif /* HAVE_MMAP */
-
-  /* Getting new symbols may change our opinion about what is frameless. */
-
-  reinit_frame_cache ();
-
-}
-
-#ifdef HAVE_MMAP
-
-/* Allocate a form node */
-
-static struct formnode *
-alloc_formnode ()
-{
-  struct formnode *fnp;
-
-  fnp = (struct formnode *) xmalloc (sizeof (struct formnode));
-  (void) memset (fnp, 0, sizeof (struct formnode));
-  fnp -> sibling = formtree;
-  formtree = fnp;
-  return (fnp);
-}
-
-/* Recursively walk a form-tree from the specified node, freeing
-   nodes from the bottom up.  The concept is pretty simple, just free
-   all the child nodes, then all the sibling nodes, then the node
-   itself. */
-
-static void
-free_subtree (fnp)
-     struct formnode *fnp;
-{
-  if (fnp != NULL)
-    {
-      free_subtree (fnp -> child);
-      free_subtree (fnp -> sibling);
-      if (fnp -> nodedata != NULL)
-       {
-         free (fnp -> nodedata);
-       }
-      free (fnp);
-    }
-}
-
-/* Recursively walk a form-tree from the specified node, computing the
-   size of each subtree from the bottom up.
-
-   At each node, the file space that will be consumed by the subtree
-   rooted in that node is the sum of all the subtrees rooted in each
-   child node plus the size of the node itself.
-
-   Thus for each node, we size the child subtrees, add to that our
-   size, contribute this size towards the size of any parent node, and
-   then ask any of our siblings to do the same.
-
-   Also, once we know the size of any subtree rooted at this node, we
-   can initialize the offset to the sibling node (if any).
-
-   Since every form-tree node must have valid nodedata at this point,
-   we detect and report a warning for any node that doesn't. */
-
-static void
-size_subtree (fnp)
-     struct formnode *fnp;
-{
-  long *lp;
-
-  if (fnp != NULL)
-    {
-      if (fnp -> nodedata == NULL)
-       {
-         warning ("internal error -- empty form node");
-       }
-      else
-       {
-         size_subtree (fnp -> child);
-         fnp -> treesize += *(long *) fnp -> nodedata;
-         if (fnp -> parent != NULL)
-           {
-             fnp -> parent -> treesize += fnp -> treesize;
-           }
-         if (fnp -> sibling)
-           {
-             size_subtree (fnp -> sibling);
-             lp = (long *) (fnp -> nodedata + 2 * sizeof (long));
-             *lp = fnp -> treesize;
-           }
-       }
-    }
-}
-
-/* Recursively walk a form-tree from the specified node, writing
-   nodes from the top down. */
-
-static void
-write_subtree (fnp, asfd)
-     struct formnode *fnp;
-     sfd *asfd;
-{
-  if (fnp != NULL)
-    {
-      if (fnp -> nodedata != NULL)
-       {
-         fwrite (fnp -> nodedata, *(long *) fnp -> nodedata, 1, asfd -> fp);
-       }
-      write_subtree (fnp -> child, asfd);
-      write_subtree (fnp -> sibling, asfd);
-    }
-}
-
-/* Free the entire current formtree.  Called via do_cleanups, regardless
-   of whether there is an error or not. */
-
-static void
-free_formtree ()
-{
-  free_subtree (formtree);
-  formtree = NULL;
-}
-
-/* Write out the file header.  Generally this is done last, even though
-   it is located at the start of the file, since we need to have file
-   offset to where the annotated form tree was written, and it's size. */
-
-static void
-write_header (asfd)
-     sfd *asfd;
-{
-  fseek (asfd -> fp, 0L, SEEK_SET);
-  fwrite ((char *) &asfd -> hdr, sizeof (asfd -> hdr), 1, asfd -> fp);
-}
-
-/* Write out the annotated form tree.  We should already have written out
-   the state data, and noted the file offsets and sizes in each node of
-   the form tree that references part of the state data.
-
-   The form tree can be written anywhere in the file where there is room
-   for it.  Since there is always room at the end of the file, we write
-   it there.  We also need to record the file offset to the start of the
-   form tree, and it's size, for future use when writing the file header.
-
-   In order to compute the sibling references, we need to know, at
-   each node, how much space will be consumed when all of that node's
-   children nodes have been written.  Thus we walk the tree, computing
-   the sizes of the subtrees from the bottom up.  At any node, the
-   offset from the start of that node to the start of the sibling node
-   is simply the size of the node plus the size of the subtree rooted
-   in that node. */
-
-static void
-write_formtree (asfd)
-     sfd *asfd;
-{
-  size_subtree (formtree);
-  fseek (asfd -> fp, 0L, SEEK_END);
-  asfd -> hdr.sf_ftoff = ftell (asfd -> fp);
-  write_subtree (formtree, asfd);
-  asfd -> hdr.sf_ftsize = ftell (asfd -> fp) - asfd -> hdr.sf_ftoff;
-}
-
-/* Note that we currently only support having one objfile with dumpable
-   state. */
-
-static void
-write_objfile_state (asfd)
-     sfd *asfd;
-{
-  struct objfile *objfile;
-  struct formnode *fnp;
-  PTR base;
-  PTR breakval;
-  long *lp;
-  unsigned int ftesize;
-  long ftebuf[64];
-  long foffset;
-
-  /* First walk through the objfile list looking for the first objfile
-     that is dumpable. */
-
-  for (objfile = object_files; objfile != NULL; objfile = objfile -> next)
-    {
-      if (objfile -> flags & OBJF_DUMPABLE)
-       {
-         break;
-       }
-    }
-
-  if (objfile == NULL)
-    {
-      warning ("no dumpable objfile was found");
-    }
-  else
-    {
-      fnp = alloc_formnode ();
-      lp = ftebuf;
-
-      lp++;                    /* Skip FTE size slot, filled in at the end. */
-      *lp++ = TAG_objfile;     /* This is an objfile FTE */
-      *lp++ = 0;               /* Zero the sibling reference slot. */
-
-      /* Build an AT_name attribute for the objfile's name, and write
-        the name into the state data. */
-
-      *lp++ = AT_name;
-      *lp++ = (long) ftell (asfd -> fp);
-      fwrite (objfile -> name, strlen (objfile -> name) + 1, 1, asfd -> fp);
-
-      /* Build an AT_addr attribute for the virtual address to which the
-        objfile data is mapped (and needs to be remapped when read in). */
-
-      base = mmap_base ();
-      *lp++ = AT_addr;
-      *lp++ = (long) base;
-
-      /* Build an AT_aux_addr attribute for the address of the objfile
-        structure itself, within the dumpable data.  When we read the objfile
-        back in, we use this address as the pointer the "struct objfile". */
-
-      *lp++ = AT_aux_addr;
-      *lp++ = (long) objfile;
-
-      /* Reposition in state file to next paging boundry so we can mmap the
-        dumpable objfile data when we reload it. */
-
-      foffset = (long) mmap_page_align ((PTR) ftell (asfd -> fp));
-      fseek (asfd -> fp, foffset, SEEK_SET);
-
-      /* Build an AT_offset attribute for the offset in the state file to
-        the start of the dumped objfile data. */
-
-      *lp++ = AT_offset;
-      *lp++ = (long) ftell (asfd -> fp);
-
-      /* Build an AT_size attribute for the size of the dumped objfile data. */
-
-      breakval = mmap_sbrk (0);
-      *lp++ = AT_size;
-      *lp++ = breakval - base;
-
-      /* Write the dumpable data. */ 
-
-      fwrite ((char *) base, breakval - base, 1, asfd -> fp);
-
-      /* Now finish up the FTE by filling in the size slot based on
-        how much of the ftebuf we have used, allocate some memory for
-        it hung off the form tree node, and copy it there. */
-
-      ftebuf[0] = (lp - ftebuf) * sizeof (ftebuf[0]);
-      fnp -> nodedata = (char *) xmalloc (ftebuf[0]);
-      memcpy (fnp -> nodedata, ftebuf, ftebuf[0]);
-    }
-}
-
-static void
-load_state_command (arg_string, from_tty)
-     char *arg_string;
-     int from_tty;
-{
-  char *filename;
-  char **argv;
-  FILE *fp;
-  struct cleanup *cleanups;
-  
-  dont_repeat ();
-
-  if (arg_string == NULL)
-    {
-      error ("load-state takes a file name and optional state specifiers");
-    }
-  else if ((argv = buildargv (arg_string)) == NULL)
-    {
-      fatal ("virtual memory exhausted.", 0);
-    }
-  cleanups = make_cleanup (freeargv, argv);
-
-  filename = tilde_expand (*argv);
-  make_cleanup (free, filename);
-
-  if ((fp = fopen (filename, "r")) == NULL)
-    {
-      perror_with_name (filename);
-    }
-  make_cleanup (fclose, fp);
-  immediate_quit++;
-
-  while (*++argv != NULL)
-    {
-      if (strcmp (*argv, "symbols") == 0)
-       {
-         if (from_tty
-             && !query ("load symbol table state from file \"%s\"? ",
-                        filename))
-           {
-             error ("Not confirmed.");
-           }
-         load_symbols (fp);
-       }
-      else
-       {
-         error ("unknown state specifier '%s'", *argv);
-       }
-    }
-  immediate_quit--;
-  do_cleanups (cleanups);
-}
-
-/* ARGSUSED */
-static void
-dump_state_command (arg_string, from_tty)
-     char *arg_string;
-     int from_tty;
-{
-  char *filename;
-  char **argv;
-  sfd *asfd;
-  struct cleanup *cleanups;
-  
-  dont_repeat ();
-
-  if (arg_string == NULL)
-    {
-      error ("dump-state takes a file name and state specifiers");
-    }
-  else if ((argv = buildargv (arg_string)) == NULL)
-    {
-      fatal ("virtual memory exhausted.", 0);
-    }
-  cleanups = make_cleanup (freeargv, argv);
-
-  filename = tilde_expand (*argv);
-  make_cleanup (free, filename);
-
-  /* Now attempt to create a fresh state file. */
-
-  if ((asfd = sfd_fopen (filename, "w")) == NULL)
-    {
-      perror_with_name (filename);
-    }
-  make_cleanup (sfd_fclose, asfd);
-  make_cleanup (free_formtree, NULL);
-  immediate_quit++;
-
-  /* Now that we have an open and initialized state file, seek to the
-     proper offset to start writing state data and the process the
-     arguments.  For each argument, write the state data and initialize
-     a form-tree node for each piece of state data. */
-
-  fseek (asfd -> fp, sizeof (sf_hdr), SEEK_SET);
-  while (*++argv != NULL)
-    {
-      if (strcmp (*argv, "objfile") == 0)
-       {
-         write_objfile_state (asfd);
-       }
-      else
-       {
-         error ("unknown state specifier '%s'", *argv);
-       }
-
-    }
-
-  /* We have written any state data.  All that is left to do now is
-     write the form-tree and the file header. */
-
-  write_formtree (asfd);
-  write_header (asfd);
-
-  immediate_quit--;
-  do_cleanups (cleanups);
-}
-
-static char *
-find_fte_by_walk (thisfte, endfte, tag)
-     char *thisfte;
-     char *endfte;
-     long tag;
-{
-  char *found = NULL;
-  char *nextfte;
-  long thistag;
-  long thissize;
-  long siboffset;
-
-  while (thisfte < endfte)
-    {
-      if ((thistag = *(long *)(thisfte + sizeof (long))) == tag)
-       {
-         found = thisfte;
-         break;
-       }
-      else
-       {
-         thissize =  *(long *)(thisfte);
-         siboffset = *(long *)(thisfte + (2 * sizeof (long)));
-         nextfte = thisfte + (siboffset != 0 ? siboffset : thissize);
-         found = find_fte_by_walk (thisfte + thissize, nextfte, tag);
-         thisfte = nextfte;
-       }
-    }
-  return (found);
-}
-
-/* Walk the form-tree looking for a specific FTE type.  Returns the first
-   one found that matches the specified tag. */
-
-static char *
-find_fte (asfd, tag)
-     sfd *asfd;
-     long tag;
-{
-  char *ftbase;
-  char *ftend;
-  char *ftep;
-  char *found = NULL;
-
-  if (fseek (asfd -> fp, asfd -> hdr.sf_ftoff, SEEK_SET) == 0)
-    {
-      ftbase = xmalloc (asfd -> hdr.sf_ftsize);
-      ftend = ftbase + asfd -> hdr.sf_ftsize;
-      if (fread (ftbase, asfd -> hdr.sf_ftsize, 1, asfd -> fp) == 1)
-       {
-         ftep = find_fte_by_walk (ftbase, ftend, tag);
-         if (ftep != NULL)
-           {
-             found = xmalloc (*(long *)ftep);
-             memcpy (found, ftep, (int) *(long *)ftep);
-           }
-       }
-      free (ftbase);
-    }
-  return (found);
-}
-
-struct objfile *
-objfile_from_statefile (asfd)
-     sfd *asfd;
-{
-  struct objfile *objfile = NULL;
-  char *ftep;
-  long *thisattr;
-  long *endattr;
-  PTR base;
-  long foffset;
-  long mapsize;
-
-  ftep = find_fte (asfd, TAG_objfile);
-  thisattr = (long *) (ftep + 3 * sizeof (long));
-  endattr = (long *) (ftep + *(long *)ftep);
-  while (thisattr < endattr)
-    {
-      switch (*thisattr++)
-       {
-         case AT_name:
-           /* Ignore for now */
-           thisattr++;
-           break;
-         case AT_addr:
-           base = (PTR) *thisattr++;
-           break;
-         case AT_aux_addr:
-           objfile = (struct objfile *) *thisattr++;
-           break;
-         case AT_offset:
-           foffset = *thisattr++;
-           break;
-         case AT_size:
-           mapsize = *thisattr++;
-           break;
-       }
-    }
-  if (mmap_remap (base, mapsize, (int) fileno (asfd -> fp), foffset) != base)
-    {
-      print_sys_errmsg (asfd -> filename, errno);
-      error ("mapping failed");
-    }
-
-  return (objfile);
-}
-
-#else
-
-struct objfile *
-objfile_from_statefile (asfd)
-     sfd *asfd;
-{
-  error ("this version of gdb doesn't support reloading symtabs from state files");
-}
-
-#endif /* HAVE_MMAP */
-
-/* Close a state file, freeing all memory that was used by the state
-   file descriptor, closing the raw file pointer, etc. */
-
-void
-sfd_fclose (asfd)
-     sfd *asfd;
-{
-  if (asfd != NULL)
-    {
-      if (asfd -> fp != NULL)
-       {
-         fclose (asfd -> fp);
-       }
-      if (asfd -> filename != NULL)
-       {
-         free (asfd -> filename);
-       }
-      free (asfd);
-    }
-}
-
-/* Given the name of a possible statefile, and flags to use to open it,
-   try to open the file and prepare it for use.
-
-   If the flags contain 'r', then we want to read an existing state
-   file, so attempt to read in the state file header and determine if this
-   is a valid state file.  If not, return NULL.
-
-   Returns a pointer to a properly initialized state file descriptor if
-   successful. */
-
-sfd *
-sfd_fopen (name, flags)
-     char *name;
-     char *flags;
-{
-  int success = 0;
-  sfd *asfd;
-
-  asfd = (sfd *) xmalloc (sizeof (sfd));
-  (void) memset (asfd, 0, sizeof (sfd));
-  asfd -> filename = xmalloc (strlen (name) + 1);
-  (void) strcpy (asfd -> filename, name);
-
-  if ((asfd -> fp = fopen (asfd -> filename, flags)) != NULL)
-    {
-      /* We have the file, now see if we are reading an existing file
-        or writing to a new file.  We don't currently support "rw". */
-      if (strchr (flags, 'r') != NULL)
-       {
-         if (fread ((char *) &asfd -> hdr, sizeof (asfd -> hdr), 1,
-                    asfd -> fp) == 1)
-           {
-             if (SF_GOOD_MAGIC (asfd))
-               {
-                 success = 1;
-               }
-           }
-       }
-      else
-       {
-         /* This is a new state file.  Initialize various things. */
-         asfd -> hdr.sf_mag0 = SF_MAG0;
-         asfd -> hdr.sf_mag1 = SF_MAG1;
-         asfd -> hdr.sf_mag2 = SF_MAG2;
-         asfd -> hdr.sf_mag3 = SF_MAG3;
-         success = 1;
-       }
-    }
-
-  if (!success)
-    {
-      sfd_fclose (asfd);
-      asfd = NULL;
-    }
-  return (asfd);
-  
-}
-
-\f
-void
-_initialize_state ()
-{
-
-#ifdef HAVE_MMAP
-
-  add_com ("load-state", class_support, load_state_command,
-   "Load some saved gdb state from FILE.\n\
-Select and load some portion of gdb's saved state from the specified file.\n\
-The dump-state command may be used to save various portions of gdb's\n\
-internal state.");
-
-  add_com ("dump-state", class_support, dump_state_command,
-   "Dump some of gdb's state to FILE.\n\
-Select and dump some portion of gdb's internal state to the specified file.\n\
-The load-state command may be used to reload various portions of gdb's\n\
-internal state from the file.");
-
-#endif /* HAVE_MMAP */
-
-}
This page took 0.030464 seconds and 4 git commands to generate.