diff options
author | Stan Shebs <shebs@codesourcery.com> | 1995-05-11 02:01:22 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1995-05-11 02:01:22 +0000 |
commit | 19405856a16f83ee28958ee6c9d6e44b1feceff6 (patch) | |
tree | e9616ecff6a37eaa0c61a4d5f874e6a03db62d5f /gdb/state.c | |
parent | dea16e4dba6da5a7c9593606f99056c14631280f (diff) | |
download | gdb-19405856a16f83ee28958ee6c9d6e44b1feceff6.zip gdb-19405856a16f83ee28958ee6c9d6e44b1feceff6.tar.gz gdb-19405856a16f83ee28958ee6c9d6e44b1feceff6.tar.bz2 |
Blasting old junk
Diffstat (limited to 'gdb/state.c')
-rw-r--r-- | gdb/state.c | 775 |
1 files changed, 0 insertions, 775 deletions
diff --git a/gdb/state.c b/gdb/state.c index 64f86d6..e69de29 100644 --- a/gdb/state.c +++ b/gdb/state.c @@ -1,775 +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 "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, FOPEN_RB)) == NULL) - { - perror_with_name (filename); - } - make_cleanup (fclose, fp); - immediate_quit++; - - while (*++argv != NULL) - { - if (STREQ (*argv, "symbols")) - { - 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, FOPEN_WB)) == 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 (STREQ (*argv, "objfile")) - { - 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); - -} - - -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 */ - -} |