Merged in latest RS6000 diffs from Metin G. Ozisik.
authorPer Bothner <per@bothner.com>
Sun, 29 Mar 1992 22:33:35 +0000 (22:33 +0000)
committerPer Bothner <per@bothner.com>
Sun, 29 Mar 1992 22:33:35 +0000 (22:33 +0000)
19 files changed:
gdb/.Sanitize
gdb/ChangeLog
gdb/breakpoint.c
gdb/buildsym.c
gdb/config/rs6000.mt
gdb/infrun.c
gdb/main.c
gdb/minsyms.c
gdb/printcmd.c
gdb/rs6000-tdep.c
gdb/rs6000-xdep.c
gdb/symfile.c
gdb/tm-rs6000.h
gdb/utils.c
gdb/xcoffexec.c
gdb/xcoffread.c
gdb/xcoffsolib.c [new file with mode: 0644]
gdb/xcoffsolib.h [new file with mode: 0644]
gdb/xm-rs6000.h

index 2b0492945cbcd0b6d9f99e6a577417d1c05f53ec..0377eff23aa1fc907a4ac56f1a3a35e714e8a5ee 100644 (file)
@@ -241,6 +241,8 @@ vax-pinsn.c
 vx-share
 xcoffexec.c
 xcoffread.c
+xcoffsolib.c
+xcoffsolib.h
 xm-3b1.h
 xm-m88k.h
 xm-altos.h
index 094aa4de63c7d5f7f55f840c93c7eb7a4c0f4ab6..803ef3944a9bfbd1208d7d67a2e981b2c50a72cf 100644 (file)
@@ -1,3 +1,10 @@
+Sun Mar 29 14:16:22 1992  Per Bothner  (bothner@cygnus.com)
+
+       * Merged in latest RS6000 diffs from Metin G. Ozisik.
+       * xcoffsolib.c, xcoffsolib.h:  New files, from Metin.
+       * Various files: Changed #ifdef IBM6000 to IBM6000_HOST
+       or IBM6000_TARGET as (approximately) appropriate.
+
 Sat Mar 28 13:00:10 1992  Fred Fish  (fnf@cygnus.com)
 
        * objfiles.h (OBJF_SYMS):  Define flag bit for objfile flags.
index b9aef04c6573e1ba75f4b4697344ff282c1f0759..ab30a6718e8d2eaba2b611bced28a3334631a37b 100644 (file)
@@ -17,9 +17,8 @@ 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.  */
 
-#include <stdio.h>
-#include <ctype.h>
 #include "defs.h"
+#include <ctype.h>
 #include "symtab.h"
 #include "frame.h"
 #include "breakpoint.h"
@@ -2270,8 +2269,12 @@ breakpoint_re_set ()
   create_longjmp_breakpoint("siglongjmp");
   create_longjmp_breakpoint(NULL);
 
+#if 0
+  /* Took this out (temporaliy at least), since it produces an extra 
+     blank line at startup. This messes up the gdbtests. -PB */
   /* Blank line to finish off all those mention() messages we just printed.  */
   printf_filtered ("\n");
+#endif
 }
 \f
 /* Set ignore-count of breakpoint number BPTNUM to COUNT.
@@ -2693,3 +2696,35 @@ an expression changes.");
            "Status of all watchpoints, or watchpoint number NUMBER.\n\
 Second column is \"y\" for enabled watchpoints, \"n\" for disabled.");
 }
+
+#ifdef IBM6000_HOST
+/* Where should this function go? It is used by AIX only. FIXME. */
+
+/* Breakpoint address relocation used to be done in breakpoint_re_set(). That
+   approach the following problem:
+
+     before running the program, if a file is list, then a breakpoint is
+     set (just the line number), then if we switch into another file and run
+     the program, just a line number as a breakpoint address was not
+     descriptive enough and breakpoint was ending up in a different file's
+     similar line. 
+
+  I don't think any other platform has this breakpoint relocation problem, so this
+  is not an issue for other platforms. */
+   
+void
+fixup_breakpoints (low, high, delta)
+  CORE_ADDR low;
+  CORE_ADDR high;
+  CORE_ADDR delta;
+{
+  struct breakpoint *b;
+  extern struct breakpoint *breakpoint_chain;
+
+  ALL_BREAKPOINTS (b)
+    {
+     if (b->address >= low && b->address <= high)
+       b->address += delta;
+    }
+}
+#endif
index eab5cb6f2160f78a446cde72857dbdc3a504eebb..a104eb58dca03e31011c48c165fd65b816faf5c0 100644 (file)
@@ -726,7 +726,7 @@ patch_block_stabs (symbols, stabs, objfile)
          struct symbol *sym = find_symbol_in_list (symbols, name, pp-name);
          if (!sym)
            {
-#ifndef IBM6000
+#ifndef IBM6000_TARGET
              printf ("ERROR! stab symbol not found!\n");       /* FIXME */
 #endif
            }
@@ -882,7 +882,7 @@ end_symtab (end_addr, sort_pending, sort_linevec, objfile)
        symtab->free_code = free_linetable;
        symtab->free_ptr = 0;
 
-#if 0 /* defined(IBM6000) */
+#ifdef IBM6000_TARGET
        /* In case we need to duplicate symbol tables (to represent include
           files), and in case our system needs relocation, we want to
           relocate the main symbol table node only (for the main file,
@@ -898,11 +898,11 @@ end_symtab (end_addr, sort_pending, sort_linevec, objfile)
       free (subfile);
     }
 
-#if 0 /* defined(IBM6000) */
+#ifdef IBM6000_TARGET
   /* all include symbol tables are non-relocatable, except the main source
      file's. */
-  if (symtab_list)
-    symtab_list->nonreloc = FALSE;
+  if (symtab)
+    symtab->nonreloc = FALSE;
 #endif
 
   if (type_vector)
@@ -1863,7 +1863,7 @@ read_type (pp, objfile)
     case '*':
       type1 = read_type (pp, objfile);
 /* FIXME -- we should be doing smash_to_XXX types here.  */
-#if 0
+#ifdef IBM6000_TARGET
     /* postponed type decoration should be allowed. */
     if (typenums[1] > 0 && typenums[1] < type_vector_length &&
        (type = type_vector[typenums[1]])) {
index 85441c78d903ddc5f5eb9cb35375d99eb41a55b7..a818fea14acd55f49b68448c3ebf45a3885289ec 100644 (file)
@@ -18,5 +18,5 @@
 # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
 #TDEPFILES= exec.o rs6k-pinsn.o rs6k-tdep.o
-TDEPFILES= rs6000-pinsn.o rs6000-tdep.o
+TDEPFILES= rs6000-pinsn.o rs6000-tdep.o xcoffsolib.o
 TM_FILE= tm-rs6000.h
index 051682f7a770ca99e429c06e45f9f7184062f7eb..9bd4d3e327fdada2ccab004da061f64c621355f5 100644 (file)
@@ -191,6 +191,12 @@ extern struct target_ops child_ops;        /* In inftarg.c */
 #define        SKIP_TRAMPOLINE_CODE(pc)        0
 #endif
 
+/* For SVR4 shared libraries, each call goes through a small piece of
+   trampoline code in the ".init" section.  IN_SOLIB_TRAMPOLINE evaluates
+   to nonzero if we are current stopped in one of these. */
+#ifndef IN_SOLIB_TRAMPOLINE
+#define IN_SOLIB_TRAMPOLINE(pc,name)   0
+#endif
 
 #ifdef TDESC
 #include "tdesc.h"
@@ -791,6 +797,14 @@ wait_for_inferior ()
 
       target_wait (&w);
 
+#ifdef SIGTRAP_STOP_AFTER_LOAD
+
+      /* Somebody called load(2), and it gave us a "trap signal after load".
+         Ignore it gracefully. */
+
+      SIGTRAP_STOP_AFTER_LOAD (w);
+#endif
+
       /* See if the process still exists; clean up if it doesn't.  */
       if (WIFEXITED (w))
        {
@@ -1201,10 +1215,11 @@ wait_for_inferior ()
 
          /* ==> See comments at top of file on this algorithm.  <==*/
          
-         if (stop_pc == stop_func_start
-                  && (stop_func_start != prev_func_start
-                      || prologue_pc != stop_func_start
-                      || stop_sp != prev_sp))
+         if ((stop_pc == stop_func_start
+              || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name))
+             && (stop_func_start != prev_func_start
+                 || prologue_pc != stop_func_start
+                 || stop_sp != prev_sp))
            {
              /* It's a subroutine call.
                 (0)  If we are not stepping over any calls ("stepi"), we
index 8543c3b463bb359c351e0d0e9853d5985ac2430e..35465258576f777f2039c3b1fac4d72ad61e51b0 100644 (file)
@@ -1216,6 +1216,10 @@ init_signals ()
   if (signal (SIGHUP, do_nothing) != SIG_IGN)
     signal (SIGHUP, disconnect);
   signal (SIGFPE, float_handler);
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+  signal (SIGWINCH, SIGWINCH_HANDLER);
+#endif
 }
 \f
 /* Read one line from the command input stream `instream'
index d3f6c7ba4673f2e6bd81ecc4579cf8f79f777ea1..760ea75d461825d4a78b77544516e1e762668a7a 100644 (file)
@@ -130,7 +130,7 @@ lookup_minimal_symbol (name, objf)
   struct objfile *objfile;
   struct minimal_symbol *msymbol;
   struct minimal_symbol *found_symbol = NULL;
-#ifdef IBM6000
+#ifdef IBM6000_TARGET
   struct minimal_symbol *trampoline_symbol = NULL;
 #endif
 
@@ -147,13 +147,13 @@ lookup_minimal_symbol (name, objf)
            {
              if (strcmp (msymbol -> name, name) == 0)
                {
+#ifdef IBM6000_TARGET
 /* I *think* all platforms using shared libraries (and trampoline code)
  * will suffer this problem. Consider a case where there are 5 shared
  * libraries, each referencing `foo' with a trampoline entry. When someone
  * wants to put a breakpoint on `foo' and the only info we have is minimal
  * symbol vector, we want to use the real `foo', rather than one of those
  * trampoline entries. MGO */  
-#ifdef IBM6000
          /* If a trampoline symbol is found, we prefer to keep looking
             for the *real* symbol. If the actual symbol not found,
             then we'll use the trampoline entry. Sorry for the machine
@@ -173,7 +173,7 @@ lookup_minimal_symbol (name, objf)
            }
        }
     }
-#ifdef IBM6000
+#ifdef IBM6000_TARGET
   return found_symbol ? found_symbol : trampoline_symbol;
 #endif
 
@@ -232,6 +232,7 @@ lookup_minimal_symbol_by_pc (pc)
 
             Warning: this code is trickier than it would appear at first. */
 
+         /* Should also requires that pc is <= end of objfile.  FIXME! */
          if (pc >= msymbol[lo].address)
            {
              while (msymbol[hi].address > pc)
index d2d867ae2cf8c78bed956a409dcfb0568db15dcd..db0394eb93c9bee1f9562a09826a9832ce494ffd 100644 (file)
@@ -17,9 +17,8 @@ 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.  */
 
-#include <stdio.h>
-#include <string.h>
 #include "defs.h"
+#include <string.h>
 #include "frame.h"
 #include "symtab.h"
 #include "gdbtypes.h"
@@ -1555,7 +1554,7 @@ print_frame_args (func, fi, num, stream)
         two entries (one a parameter, one a register or local), and the one
         we want is the non-parm, which lookup_symbol will find for
         us.  After this, sym could be any SYMBOL_CLASS...  */
-#ifdef IBM6000
+#ifdef IBM6000_TARGET
       /* AIX/RS6000 implements a concept of traceback tables, in which case
          it creates nameless parameters. Looking for those parameter symbols
         will result in an error. */
index fea31f10ae36af78c1295ffebf74231f6140eb8d..1a26ab2e3ac000ad90db1ae8d7ca7ed7f7f94599 100644 (file)
@@ -187,6 +187,15 @@ int pc;
   if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
     pc += 4;
     op = read_memory_integer (pc, 4);
+
+    /* At this point, make sure this is not a trampoline function
+       (a function that simply calls another functions, and nothing else).
+       If the next is not a nop, this branch was part of the function
+       prologue. */
+
+    if (op == 0x4def7b82 ||            /* crorc 15, 15, 15 */
+       op == 0x0)
+      return pc - 4;                   /* don't skip over this branch */
   }
 
   if ((op & 0xfc1f0000) == 0xbc010000) { /* stm Rx, NUM(r1) */
@@ -546,6 +555,14 @@ function_frame_info (pc, fdata)
   if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
     pc += 4;
     op = read_memory_integer (pc, 4);
+    /* At this point, make sure this is not a trampoline function
+       (a function that simply calls another functions, and nothing else).
+       If the next is not a nop, this branch was part of the function
+       prologue. */
+
+    if (op == 0x4def7b82 ||            /* crorc 15, 15, 15 */
+       op == 0x0)
+      return;                          /* prologue is over */
   }
 
   if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
index c8c0c1d12a8e8c9152e0ec39f6e9e5db95d6fefc..6fb8469d6f65588e144bc06b8f78048bb5472fc8 100644 (file)
@@ -510,6 +510,10 @@ exec_one_dummy_insn ()
 }
 
 
+#if 0
+
+   *** not needed anymore ***
+
 /* Return the number of initial trap signals we need to ignore once the inferior
    process starts running. This will be `2' for aix-3.1, `3' for aix-3.2 */
 
@@ -530,3 +534,4 @@ aix_starting_inferior_traps ()
   else
     return 3;
 }
+#endif
index 9b50d6f2d1ab6d99da7a91a9af883e14bf2b7c1d..3cfe4ea18bb237fedea5b5cda62999b061abe03d 100644 (file)
@@ -803,7 +803,7 @@ reread_symbols ()
 the_big_top:
   for (objfile = object_files; objfile; objfile = objfile->next) {
     if (objfile->obfd) {
-#ifdef IBM6000
+#ifdef IBM6000_TARGET
      /* If this object is from a shared library, then you should
         stat on the library name, not member name. */
 
index 64720585ca425aa9584005fc2dbca42680f55c47..b99deb3cf0358147ff3941e0988ace409a7ea9f4 100644 (file)
@@ -45,6 +45,11 @@ extern int   symtab_relocated;
   if (!symtab_relocated && !inferior_pid && (PC) >  TEXT_SEGMENT_BASE) \
     (PC) -= ( TEXT_SEGMENT_BASE + text_adjustment (exec_bfd));
 
+/* Load segment of a given pc value. */
+
+#define        PC_LOAD_SEGMENT(PC)     pc_load_segment_name(PC)
+
+
 /* Conversion between a register number in stab string to actual register num. */
 
 #define        STAB_REG_TO_REGNUM(value)       (value)
@@ -131,11 +136,37 @@ extern int aix_loadInfoTextIndex;
   } while (0)
        
 
+#if 0
+   The following comment is not correct anymore. AIX has a trap signal
+   that might be sent with a "stopped after a load" status. This might
+   show up when the inferior is just started, or anytime inferior
+   loads something else. It is incorrect to try to skip over it *only* in
+   startup-time. It always has to be ignored and should not be mixed up
+   with breakpoint traps. See the macro SIGTRAP_STOP_AFTER_LOAD and its 
+   usage in infrun.c.
+
 /* In aix, number of the trap signals we need to skip over once the
    inferior process starts running is different in version 3.1 and 3.2.
    This will be 2 for version 3.1x, 3 for version 3.2x. */
 
 #define        START_INFERIOR_TRAPS_EXPECTED   aix_starting_inferior_traps ()
+#endif /* 0 */
+
+#define        START_INFERIOR_TRAPS_EXPECTED   2
+
+/* AIX might return a sigtrap, with a "stop after load" status. It should
+   be ignored by gdb, shouldn't be mixed up with breakpoint traps. */
+
+#define SIGTRAP_STOP_AFTER_LOAD(W)     \
+ if ( (W) == 0x57c ) {                 \
+   if (breakpoints_inserted) {         \
+     mark_breakpoints_out ();          \
+     insert_breakpoints ();            \
+     insert_step_breakpoint ();                \
+   }                                   \
+   resume (0, 0);                      \
+   continue;                           \
+ }
 
 /* In aixcoff, we cannot process line numbers when we see them. This is
    mainly because we don't know the boundaries of the include files. So,
@@ -442,12 +473,7 @@ extern unsigned int rs6000_struct_return_address;
 
 #define        INIT_EXTRA_FRAME_INFO(fromleaf, fi)     \
        fi->initial_sp = 0;             \
-       fi->cache_fsr = 0;              \
-       if (fromleaf) {                 \
-         int tmp = 0;                  \
-         read_memory ((fi)->frame, &tmp, sizeof (int));        \
-         (fi)->frame = tmp;            \
-       }
+       fi->cache_fsr = 0;
 
 #define FRAME_SAVED_PC(FRAME)          \
        read_memory_integer (read_memory_integer ((FRAME)->frame, 4)+8, 4)
@@ -587,7 +613,35 @@ extern unsigned int rs6000_struct_return_address;
 #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, using_gcc) \
        fix_call_dummy(dummyname, pc, fun, nargs, type)
 
+
+/* Signal handler for SIGWINCH `window size changed'. */
+
+#define        SIGWINCH_HANDLER  aix_resizewindow
+extern void    aix_resizewindow ();
+
+/* `lines_per_page' and `chars_per_line' are local to utils.c. Rectify this. */
+
+#define        SIGWINCH_HANDLER_BODY   \
+                                                                       \
+/* Respond to SIGWINCH `window size changed' signal, and reset GDB's   \
+   window settings approproatelt. */                                   \
+                                                                       \
+void                                           \
+aix_resizewindow ()                            \
+{                                              \
+  int fd = fileno (stdout);                    \
+  if (isatty (fd)) {                           \
+    int val;                                   \
+                                               \
+    val = atoi (termdef (fd, 'l'));            \
+    if (val > 0)                               \
+      lines_per_page = val;                    \
+    val = atoi (termdef (fd, 'c'));            \
+    if (val > 0)                               \
+      chars_per_line = val;                    \
+  }                                            \
+}
+
+
 /* Flag for machine-specific stuff in shared files.  FIXME */
-#ifndef IBM6000
-#define IBM6000
-#endif
+#define IBM6000_TARGET
index 24fd9ea98b69b3a8f5f207c19e48ce94789f0ad4..974f2ce374f61d4700cb160c45e39904d1afe92d 100644 (file)
@@ -1323,6 +1323,12 @@ _initialize_utils ()
       }
   }
 
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+
+  /* If tere is a better way to determine window size, use it. */
+  SIGWINCH_HANDLER ();
+#endif
+
   /* If the output is not a terminal, don't paginate it.  */
   if (!ISATTY (stdout))
     lines_per_page = UINT_MAX;
@@ -1350,3 +1356,9 @@ _initialize_utils ()
                  &setprintlist),
      &showprintlist);
 }
+
+/* Machine specific function to handle SIGWINCH signal. */
+
+#ifdef  SIGWINCH_HANDLER_BODY
+        SIGWINCH_HANDLER_BODY
+#endif
index 8588ffb17330482b69ecd539c91aceb63613c076..d64dec4df64dea955dcd32a8fbdf2bcc275ebaed 100644 (file)
@@ -40,6 +40,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "objfiles.h"
 
 #include "libbfd.h"            /* BFD internals (sigh!)  FIXME */
+#include "xcoffsolib.h"
 
 /* Prototypes for local functions */
 
@@ -68,6 +69,7 @@ extern void symbol_file_command ();
 static void exec_files_info();
 extern struct objfile *lookup_objfile_bfd ();
 
+#if 0
 /*
  * the vmap struct is used to describe the virtual address space of
  * the target we are manipulating.  The first entry is always the "exec"
@@ -96,6 +98,9 @@ struct vmap_and_bfd {
 };
 
 static struct vmap *vmap;      /* current vmap                         */
+#endif /* 0 */
+
+struct vmap *vmap;             /* current vmap */
 
 extern struct target_ops exec_ops;
 
@@ -320,6 +325,7 @@ map_vmap (bfd *bf, bfd *arch)
   struct objfile *obj;
 
   vp = (void*) xmalloc (sizeof (*vp));
+  bzero (vp, sizeof (*vp));
   vp->nxt = 0;
   vp->bfd = bf;
   vp->name = bfd_get_filename(arch ? arch : bf);
@@ -332,7 +338,14 @@ map_vmap (bfd *bf, bfd *arch)
   obj = lookup_objfile_bfd (bf);
   if (exec_bfd && !obj) {
     obj = allocate_objfile (bf, 0);
+
+#if 0
+    This is only needed if we want to load shared libraries no matter what.
+    Since we provide the choice of incremental loading of shared objects now,
+    we don't have to load them as default anymore.
+    
     syms_from_objfile (obj, 0, 0, 0);
+#endif
   }
 
   /* find the end of the list, and append. */
@@ -436,8 +449,8 @@ struct stat *vip;
          if (fstat(fileno(io), &si) < 0)
            fatal("cannot fstat BFD for sym");
          
-         if (si.st_dev != vip->st_dev
-             || si.st_ino != vip->st_ino)
+         if (vip && (si.st_dev != vip->st_dev
+             || si.st_ino != vip->st_ino))
            continue;
        }
        
@@ -717,59 +730,61 @@ register struct ld_info *ldi;
                      , name);
 retry:
        for (got_one = 0, vp = vmap; vp; vp = vp->nxt) {
-               FILE *io;
+         FILE *io;
+
+         /* First try to find a `vp', which is the same as in ldinfo.
+            If not the same, just continue and grep the next `vp'. If same,
+            relocate its tstart, tend, dstart, dend values. If no such `vp'
+            found, get out of this for loop, add this ldi entry as a new vmap
+            (add_vmap) and come back, fins its `vp' and so on... */
+
+         /* The filenames are not always sufficient to match on. */
 
-               /* The filenames are not always sufficient to match on. */
-               if ((name[0] == "/"
-                   && !eq(name, vp->name))
-                   || (memb[0] && !eq(memb, vp->member)))
-                       continue;
+         if ((name[0] == "/" && !eq(name, vp->name))
+               || (memb[0] && !eq(memb, vp->member)))
+           continue;
 
-               /* totally opaque! */
-               io = bfd_cache_lookup(vp->bfd);
-               if (!io)
-                       fatal("cannot find BFD's iostream for %s"
-                             , vp->name);
+         io = bfd_cache_lookup(vp->bfd);               /* totally opaque! */
+         if (!io)
+           fatal("cannot find BFD's iostream for %s", vp->name);
 
-               /* see if we are referring to the same file */
-               if (fstat(fileno(io), &vi) < 0)
-                       fatal("cannot fstat BFD for %s", vp->name);
+         /* see if we are referring to the same file */
 
-               if (ii.st_dev != vi.st_dev || ii.st_ino != vi.st_ino)
-                       continue;
+         if (fstat(fileno(io), &vi) < 0)
+           fatal("cannot fstat BFD for %s", vp->name);
 
-               if (!retried)
-                   close(ldi->ldinfo_fd);
+         if (ii.st_dev != vi.st_dev || ii.st_ino != vi.st_ino)
+           continue;
 
-               ++got_one;
+         if (!retried)
+           close(ldi->ldinfo_fd);
 
-               /* found a corresponding VMAP. remap! */
-               ostart = vp->tstart;
+         ++got_one;
 
-               vp->tstart = ldi->ldinfo_textorg;
-               vp->tend   = vp->tstart + ldi->ldinfo_textsize;
-               vp->dstart = ldi->ldinfo_dataorg;
-               vp->dend   = vp->dstart + ldi->ldinfo_datasize;
+         /* found a corresponding VMAP. remap! */
+         ostart = vp->tstart;
 
-               if (vp->tadj) {
-                 vp->tstart += vp->tadj;
-                 vp->tend   += vp->tadj;
-               }
+         vp->tstart = ldi->ldinfo_textorg;
+         vp->tend   = vp->tstart + ldi->ldinfo_textsize;
+         vp->dstart = ldi->ldinfo_dataorg;
+         vp->dend   = vp->dstart + ldi->ldinfo_datasize;
 
-               /* relocate symbol table(s). */
-               vmap_symtab(vp, ostart, &vi);
+         if (vp->tadj) {
+           vp->tstart += vp->tadj;
+           vp->tend   += vp->tadj;
+         }
+
+         /* relocate symbol table(s). */
+         vmap_symtab(vp, ostart, &vi);
 
-               /* there may be more, so we don't break out of the loop. */
+         /* there may be more, so we don't break out of the loop. */
        }
 
-       /*
-        * if there was no matching *vp, we must perforce create
-        * the sucker(s)
-        */
-       if (!got_one && !retried) {
-               add_vmap(ldi);
-               ++retried;
-               goto retry;
+       /* if there was no matching *vp, we must perforce create the sucker(s) */
+       if (!got_one && !retried) {
+         add_vmap(ldi);
+         ++retried;
+         goto retry;
        }
   } while (ldi->ldinfo_next
         && (ldi = (void *) (ldi->ldinfo_next + (char *) ldi)));
@@ -894,18 +909,21 @@ exec_files_info (t)
   if (!vp)
     return;
 
-  printf("\n\tMapping info for file `%s'.\n", vp->name);
-  printf("\t  %8.8s   %8.8s %8.8s %s\n",
-                       "start", "end", "section", "file(member)");
+  printf("\tMapping info for file `%s'.\n", vp->name);
+
+  printf("\t  %8.8s   %8.8s   %8.8s   %8.8s %8.8s %s\n",
+    "tstart", "tend", "dstart", "dend", "section", "file(member)");
 
   for (; vp; vp = vp->nxt)
-       printf("\t0x%8.8x 0x%8.8x %s%s%s%s\n",
-               vp->tstart,
-               vp->tend,
-               vp->name,
-               vp->member ? "(" : "",
-               vp->member,
-               vp->member ? ")" : "");
+     printf("\t0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x %s%s%s%s\n",
+       vp->tstart,
+       vp->tend,
+       vp->dstart,
+       vp->dend,
+       vp->name,
+       *vp->member ? "(" : "",
+       vp->member,
+       *vp->member ? ")" : "");
 }
 
 #ifdef DAMON
index 93fe780004c4fe835ad5a31196bc71cdf9f40852..a677f7bcb41a8df1f73ca86006e4269b0be422b7 100644 (file)
@@ -22,7 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "defs.h"
 #include "bfd.h"
 
-#ifdef IBM6000
+#ifdef IBM6000_HOST
 /* Native only:  Need struct tbtable in <sys/debug.h>. */
 
 /* AIX COFF names have a preceeding dot `.' */
@@ -38,7 +38,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/file.h>
 #endif
 #include <sys/stat.h>
-/*#include <linenum.h>*/
 #include <sys/debug.h>
 
 #include "symtab.h"
@@ -51,6 +50,19 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "libcoff.h"           /* FIXME, internal data from BFD */
 #include "coff/rs6000.h"       /* FIXME, raw file-format guts of xcoff */
 
+
+/* Define this if you want gdb use the old xcoff symbol processing. This
+   way it won't use common `define_symbol()' function and Sun dbx stab
+   string grammar. And likely it won't be able to do G++ debugging. */
+
+/* #define     NO_DEFINE_SYMBOL 1 */
+
+/* Define this if you want gdb to ignore typdef stabs. This was needed for
+   one of Transarc, to reduce the size of the symbol table. Types won't be
+   recognized, but tag names will be. */
+
+/* #define     NO_TYPES  1 */
+
 /* Simplified internal version of coff symbol table information */
 
 struct coff_symbol {
@@ -942,7 +954,8 @@ retrieve_traceback (abfd, textsec, cs, size)
   if (ALLOCED)                                         \
     namestr = (NAME) + 1;                      \
   else {                                       \
-    namestr = obstack_copy0 (&objfile->symbol_obstack, (NAME) + 1, strlen ((NAME)+1)); \
+    (NAME) = namestr =                                 \
+    obstack_copy0 (&objfile->symbol_obstack, (NAME) + 1, strlen ((NAME)+1)); \
     (ALLOCED) = 1;                                             \
   }                                                            \
   prim_record_minimal_symbol (namestr, (ADDR), (TYPE));                \
@@ -1012,6 +1025,8 @@ read_xcoff_symtab (objfile, nsyms)
   long fcn_line_offset;
   size_t size;
 
+  struct coff_symbol fcn_stab_saved;
+
   /* fcn_cs_saved is global because process_xcoff_symbol needs it. */
   union internal_auxent fcn_aux_saved;
   struct type *fcn_type_saved = NULL;
@@ -1293,8 +1308,30 @@ function_entry_point:
            /* record trampoline code entries as mst_unknown symbol. When we
               lookup mst symbols, we will choose mst_text over mst_unknown. */
 
+#if 1
+           /* After the implementation of incremental loading of shared
+              libraries, we don't want to access trampoline entries. This
+              approach has a consequence of the necessity to bring the whole 
+              shared library at first, in order do anything with it (putting
+              breakpoints, using malloc, etc). On the other side, this is
+              consistient with gdb's behaviour on a SUN platform. */
+
+           /* Trying to prefer *real* function entry over its trampoline,
+              by assigning `mst_unknown' type to trampoline entries fails.
+              Gdb treats those entries as chars. FIXME. */
+
+           /* Recording this entry is necessary. Single stepping relies on
+              this vector to get an idea about function address boundaries. */
+
+           prim_record_minimal_symbol (0, cs->c_value, mst_unknown);
+#else
+
+           /* record trampoline code entries as mst_unknown symbol. When we
+              lookup mst symbols, we will choose mst_text over mst_unknown. */
+
            RECORD_MINIMAL_SYMBOL (cs->c_name, cs->c_value, mst_unknown,
                                   symname_alloced);
+#endif
            continue;
          }
          break;
@@ -1348,6 +1385,7 @@ function_entry_point:
 
     case C_FUN:
 
+#ifdef NO_DEFINE_SYMBOL
       /* For a function stab, just save its type in `fcn_type_saved', and leave
         it for the `.bf' processing. */
       {
@@ -1362,6 +1400,9 @@ function_entry_point:
 
        fcn_type_saved = lookup_function_type (read_type (&pp, objfile));
       }
+#else
+      fcn_stab_saved = *cs;
+#endif
       break;
     
 
@@ -1430,6 +1471,8 @@ function_entry_point:
        mark_first_line (fcn_line_offset, cs->c_symnum);
 
        new = push_context (0, fcn_start_addr);
+
+#ifdef NO_DEFINE_SYMBOL
        new->name = process_xcoff_symbol (&fcn_cs_saved, objfile);
 
        /* Between a function symbol and `.bf', there always will be a function
@@ -1443,6 +1486,10 @@ function_entry_point:
          SYMBOL_TYPE (new->name) = fcn_type_saved;
          fcn_type_saved = NULL;
        }
+#else
+       new->name = define_symbol 
+               (fcn_cs_saved.c_value, fcn_stab_saved.c_name, 0, 0, objfile);
+#endif
       }
       else if (strcmp (cs->c_name, ".ef") == 0) {
 
@@ -1610,6 +1657,8 @@ process_xcoff_symbol (cs, objfile)
 #endif
 
     case C_DECL:                       /* a type decleration?? */
+
+#if defined(NO_TYPEDEFS) || defined(NO_DEFINE_SYMBOL)
        qq =  (char*) strchr (name, ':');
        if (!qq)                        /* skip if there is no ':' */
          return NULL;
@@ -1637,7 +1686,32 @@ process_xcoff_symbol (cs, objfile)
                                obsavestring (name, qq-name,
                                              &objfile->symbol_obstack);
        }
-       ttype = SYMBOL_TYPE (sym) = read_type (&pp, objfile);
+       ttype = SYMBOL_TYPE (sym) = read_type (&pp);
+
+       /* if there is no name for this typedef, you don't have to keep its
+          symbol, since nobody could ask for it. Otherwise, build a symbol
+          and add it into symbol_list. */
+
+       if (nameless)
+         return;
+
+#ifdef NO_TYPEDEFS
+       /* Transarc wants to eliminate type definitions from the symbol table.
+          Limited debugging capabilities, but faster symbol table processing
+          and less memory usage. Note that tag definitions (starting with
+          'T') will remain intact. */
+
+       if (qq[1] != 'T' && (!TYPE_NAME (ttype) || *(TYPE_NAME (ttype)) == '\0')) {
+
+         if (SYMBOL_NAME (sym))
+             TYPE_NAME (ttype) = SYMBOL_NAME (sym);
+         else
+             TYPE_NAME (ttype) = obsavestring (name, qq-name);
+
+         return;
+       }
+
+#endif /* !NO_TYPEDEFS */
 
        /* read_type() will return null if type (or tag) definition was
           unnnecessarily duplicated. Also, if the symbol doesn't have a name,
@@ -1651,58 +1725,58 @@ process_xcoff_symbol (cs, objfile)
           symbol, since nobody could ask for it. Otherwise, build a symbol
           and add it into symbol_list. */
 
-       if (!nameless) {
-         if (qq[1] == 'T')
+       if (qq[1] == 'T')
            SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
-         else if (qq[1] == 't')
+       else if (qq[1] == 't')
            SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
-         else {
-           printf ("ERROR: Unrecognized stab string.\n");
+       else {
+           warning ("Unrecognized stab string.\n");
            return NULL;
-         }
+       }
 
-         SYMBOL_CLASS (sym) = LOC_TYPEDEF;
-         if (!SYMBOL_NAME (sym))
-           SYMBOL_NAME (sym) = obsavestring (name, qq-name,
-                                             &objfile->symbol_obstack);
+       SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+       if (!SYMBOL_NAME (sym))
+           SYMBOL_NAME (sym) = obsavestring (name, qq-name);
 
-         SYMBOL_DUP (sym, sym2);
-         add_symbol_to_list 
+       SYMBOL_DUP (sym, sym2);
+       add_symbol_to_list 
             (sym2, within_function ? &local_symbols : &file_symbols);
 
-         /* For a combination of struct and type, add one more symbol
-            for the type. */
+       /* For a combination of struct and type, add one more symbol
+          for the type. */
 
-         if (struct_and_type_combined) {
+       if (struct_and_type_combined) {
            SYMBOL_DUP (sym, sym2);
            SYMBOL_NAMESPACE (sym2) = VAR_NAMESPACE;
            add_symbol_to_list 
               (sym2, within_function ? &local_symbols : &file_symbols);
-         }
-       }
+       }
 
-       /* assign a name to the type node. */
+       /*  assign a name to the type node. */
 
-       if (!nameless && (!TYPE_NAME (ttype) || *(TYPE_NAME (ttype)) == '\0')) {
+       if (!TYPE_NAME (ttype) || *(TYPE_NAME (ttype)) == '\0') {
          if (struct_and_type_combined)
            TYPE_NAME (ttype) = SYMBOL_NAME (sym);
-         
-/*       else if  (SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE) */
          else if  (qq[1] == 'T')               /* struct namespace */
            TYPE_NAME (ttype) = concat (
                TYPE_CODE (ttype) == TYPE_CODE_UNION ? "union " :
                TYPE_CODE (ttype) == TYPE_CODE_STRUCT? "struct " : "enum ",
                SYMBOL_NAME (sym), NULL);
        }
-
        break;
 
+#else /* !NO_DEFINE_SYMBOL */
+       return define_symbol (cs->c_value, cs->c_name, 0, 0, objfile);
+#endif
+
     case C_GSYM:
       add_stab_to_list (name, &global_stabs);
       break;
 
     case C_PSYM:
     case C_RPSYM:
+
+#ifdef NO_DEFINE_SYMBOL
        if (*name == ':' || (pp = (char *) strchr (name, ':')) == NULL)
          return NULL;
        SYMBOL_NAME (sym) = obsavestring (name, pp-name, &objfile -> symbol_obstack);
@@ -1712,8 +1786,15 @@ process_xcoff_symbol (cs, objfile)
        SYMBOL_DUP (sym, sym2);
        add_symbol_to_list (sym2, &local_symbols);
        break;
+#else
+       sym = define_symbol (cs->c_value, cs->c_name, 0, 0, objfile);
+       SYMBOL_CLASS (sym) = (cs->c_sclass == C_PSYM) ? LOC_ARG : LOC_REGPARM;
+       return sym;
+#endif
 
     case C_STSYM:
+
+#ifdef NO_DEFINE_SYMBOL
        if (*name == ':' || (pp = (char *) strchr (name, ':')) == NULL)
          return NULL;
        SYMBOL_NAME (sym) = obsavestring (name, pp-name, &objfile -> symbol_obstack);
@@ -1725,6 +1806,20 @@ process_xcoff_symbol (cs, objfile)
        add_symbol_to_list 
           (sym2, within_function ? &local_symbols : &file_symbols);
        break;
+#else
+       /* If we are going to use Sun dbx's define_symbol(), we need to
+          massage our stab string a little. Change 'V' type to 'S' to be
+          comparible with Sun. */
+
+       if (*name == ':' || (pp = (char *) index (name, ':')) == NULL)
+         return NULL;
+
+       ++pp;
+       if (*pp == 'V') *pp = 'S';
+       sym = define_symbol (cs->c_value, cs->c_name, 0, 0, objfile);
+       SYMBOL_VALUE (sym) += static_block_base;
+       return sym;
+#endif
 
     case C_LSYM:
        if (*name == ':' || (pp = (char *) strchr (name, ':')) == NULL)
@@ -1768,6 +1863,8 @@ process_xcoff_symbol (cs, objfile)
       break;
 
     case C_RSYM:
+
+#ifdef NO_DEFINE_SYMBOL
        pp = (char*) strchr (name, ':');
        SYMBOL_CLASS (sym) = LOC_REGISTER;
        SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (cs->c_value);
@@ -1788,9 +1885,19 @@ process_xcoff_symbol (cs, objfile)
        SYMBOL_DUP (sym, sym2);
        add_symbol_to_list (sym2, &local_symbols);
        break;
+#else
+       if (pp) {
+         sym = define_symbol (cs->c_value, cs->c_name, 0, 0, objfile);
+         return sym;
+       }
+       else {
+         warning ("A non-stab C_RSYM needs special handling.");
+         return NULL;
+       }
+#endif
 
     default    :
-      printf ("ERROR: Unexpected storage class: %d.\n", cs->c_sclass);
+      warning ("Unexpected storage class: %d.", cs->c_sclass);
       return NULL;
     }
   }
@@ -2198,7 +2305,8 @@ aixcoff_symfile_read (objfile, addr, mainline)
 
   read_xcoff_symtab(objfile, num_symbols);
 
-  make_cleanup (free_debugsection, 0);
+  /* Free debug section. */
+  free_debugsection ();
 
   /* Sort symbols alphabetically within each block.  */
   sort_syms ();
@@ -2241,7 +2349,8 @@ _initialize_xcoffread ()
        struct s *p;
      };
 */
-#if 0
+
+
 /* Smash TYPE to be a type of pointers to TO_TYPE.
    If TO_TYPE is not permanent and has no pointer-type yet,
    record TYPE as its pointer-type.  */
@@ -2250,7 +2359,7 @@ void
 smash_to_pointer_type (type, to_type)
      struct type *type, *to_type;
 {
-  int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
+/*  int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM); */
   
   bzero (type, sizeof (struct type));
   TYPE_TARGET_TYPE (type) = to_type;
@@ -2261,33 +2370,34 @@ smash_to_pointer_type (type, to_type)
 /* ??? TYPE_TARGET_TYPE and TYPE_MAIN_VARIANT are the same. You can't do
   this. It will break the target type!!!
   TYPE_MAIN_VARIANT (type) = type;
-*/
 
   if (type_permanent)
     TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+*/
 
-  if (TYPE_POINTER_TYPE (to_type) == 0
+  if (TYPE_POINTER_TYPE (to_type) == 0)
+#if 0
       && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
          || type_permanent))
+#endif /* 0 */
     {
       TYPE_POINTER_TYPE (to_type) = type;
     }
 }
-#endif
 
-#else /* IBM6000 */
+#else /* IBM6000_HOST */
 struct type *
 builtin_type (pp)
 char **pp;
 {
     fatal ("internals eror: builtin_type called!");
 }
-#endif /* IBM6000 */
+#endif /* IBM6000_HOST */
 
 
 #define DEBUG 1
 
-#if defined (DEBUG) && defined (IBM6000)       /* Needs both defined */
+#if defined (DEBUG) && defined (IBM6000_HOST)  /* Needs both defined */
 void
 dump_strtbl ()
 {
diff --git a/gdb/xcoffsolib.c b/gdb/xcoffsolib.c
new file mode 100644 (file)
index 0000000..0ad8432
--- /dev/null
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ldr.h>
+
+#include "defs.h"
+#include "bfd.h"
+/*#include "libbfd.h"          /* BFD internals (sigh!)  FIXME */
+#include "xcoffsolib.h"
+
+
+extern struct symtab *current_source_symtab;
+extern int           current_source_line;
+
+
+/* The real work of adding a shared library file to the symtab and
+   the section list.  */
+
+void
+solib_add (arg_string, from_tty, target)
+     char *arg_string;
+     int from_tty;
+     struct target_ops *target;
+{      
+  char *val;
+  struct vmap *vp = vmap;
+  struct objfile *obj;
+  struct symtab *saved_symtab;
+  int saved_line;
+
+  int loaded = 0;                      /* true if any shared obj loaded */
+  int matched = 0;                     /* true if any shared obj matched */
+
+  if (arg_string == 0)
+      re_comp (".");
+  else if (val = (char *) re_comp (arg_string)) {
+      error ("Invalid regexp: %s", val);
+  }
+  if (!vp || !vp->nxt)
+    return;
+
+  /* save current symbol table and line number, in case they get changed
+     in symbol loading process. */
+  saved_symtab = current_source_symtab;
+  saved_line = current_source_line;
+
+  /* skip over the first vmap, it is the main program, always loaded. */
+  vp = vp->nxt;
+
+  for (; vp; vp = vp->nxt) {
+
+    if (re_exec (vp->name) || (*vp->member && re_exec (vp->member))) {
+
+      matched = 1;
+
+      /* if already loaded, continue with the next one. */
+      if (vp->loaded) {
+       
+       printf ("%s%s%s%s: already loaded.\n",
+         *vp->member ? "(" : "",
+         vp->member,
+         *vp->member ? ") " : "",
+         vp->name);
+       continue;
+      }
+
+      printf ("Loading  %s%s%s%s...",
+         *vp->member ? "(" : "",
+         vp->member,
+         *vp->member ? ") " : "",
+         vp->name);
+      fflush (stdout);
+
+       obj = lookup_objfile_bfd (vp->bfd);
+       if (!obj) {
+         warning ("\nObj structure for the shared object not found. Loading failed.");
+         continue;
+       }
+
+       syms_from_objfile (obj, 0, 0);
+       vmap_symtab (vp, 0, 0);
+       printf ("Done.\n");
+       loaded = vp->loaded = 1;
+    }
+  }
+  /* if any shared object is loaded, then misc_func_vector needs sorting. */
+  if (loaded) {
+#if 0
+    sort_misc_function_vector ();
+#endif
+    current_source_symtab = saved_symtab;
+    current_source_line = saved_line;
+
+    /* Getting new symbols might change our opinion about what is frameless.
+       Is this correct?? FIXME. */
+/*    reinit_frame_cache(); */
+  }
+  else if (!matched)
+    printf ("No matching shared object found.\n");
+
+}
+
+
+/* Return the module name of a given text address. Note that returned buffer
+   is not persistent. */
+
+char *
+pc_load_segment_name (addr)
+CORE_ADDR addr;
+{
+   static char buffer [BUFSIZ];
+   struct vmap *vp = vmap;
+
+   buffer [0] = buffer [1] = '\0';
+   for (; vp; vp = vp->nxt)
+     if (vp->tstart <= addr && addr < vp->tend) {
+       if (*vp->member) {
+         buffer [0] = '(';
+         strcat (&buffer[1], vp->member);
+         strcat (buffer, ")");
+       }
+       strcat (buffer, vp->name);
+       return buffer;
+     }
+   return "(unknown load module)";
+}
+
+
+solib_info (ldi)
+register struct ld_info *ldi;
+{
+
+   struct vmap *vp = vmap;
+
+   if (!vp || !vp->nxt) {
+     printf("No shared libraries loaded at this time.\n");     
+     return;
+   }
+
+   /* skip over the first vmap, it is the main program, always loaded. */
+   vp = vp->nxt;
+
+   printf ("\
+Text Range             Data Range              Syms    Shared Object Library\n");
+
+   for (; vp; vp = vp->nxt) {
+
+     printf ("0x%08x-0x%08x    0x%08x-0x%08x   %s      %s%s%s%s\n",
+       vp->tstart, vp->tend,
+       vp->dstart, vp->dend,
+       vp->loaded ? "Yes" : "No ",
+       *vp->member ? "(" : "",
+       vp->member,
+       *vp->member ? ") " : "",
+       vp->name);
+   }
+}
+
+
+void
+sharedlibrary_command (args, from_tty)
+  char *args;
+  int from_tty;
+{
+  dont_repeat();
+  solib_add (args, from_tty, (struct target_ops *)0);
+}
+
+void
+_initialize_solib()
+{
+
+  add_com("sharedlibrary", class_files, sharedlibrary_command,
+          "Load shared object library symbols for files matching REGEXP.");
+  add_info("sharedlibrary", solib_info, 
+          "Status of loaded shared object libraries");
+}
diff --git a/gdb/xcoffsolib.h b/gdb/xcoffsolib.h
new file mode 100644 (file)
index 0000000..9e5e4ef
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+   the vmap struct is used to describe the virtual address space of
+   the target we are manipulating.  The first entry is always the "exec"
+   file.  Subsequent entries correspond to other objects that are
+   mapped into the address space of a process created from the "exec" file.
+   These are either in response to exec()ing the file, in which case all
+   shared libraries are loaded, or a "load" system call, followed by the
+   user's issuance of a "load" command. */
+
+struct vmap {
+       struct vmap *nxt;       /* ^ to next in chain                   */
+       bfd *bfd;               /* BFD for mappable object library      */
+       char *name;             /* ^ to object file name                */
+       char *member;           /* ^ to member name                     */
+       CORE_ADDR tstart;       /* virtual addr where member is mapped  */
+       CORE_ADDR tend;         /* virtual upper bound of member        */
+       CORE_ADDR tadj;         /* heuristically derived adjustment     */
+       CORE_ADDR dstart;       /* virtual address of data start        */
+       CORE_ADDR dend;         /* vitrual address of data end          */
+
+       CORE_ADDR ostart;       /* objext start ???                     */
+       unsigned  loaded:1;     /* True if symbols are loaded           */
+       unsigned  reloced:1;    /* True, if symbols relocated           */
+       unsigned  padding:14;
+};
+
+
+struct vmap_and_bfd {
+  bfd *pbfd;
+  struct vmap *pvmap;
+};
+
+extern struct vmap *vmap;
index ab594317de00275c909922564e46bad9ebe697bc..f75cead2b9ab28322726c97dd82ebe8ea29fcbd2 100644 (file)
@@ -72,9 +72,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define CPLUS_MARKER '.'
 
 /* Flag for machine-specific stuff in shared files.  FIXME */
-#ifndef IBM6000
-#define IBM6000
-#endif
+#define IBM6000_HOST
 
 /* /usr/include/stdlib.h always uses void* and void,
    even when __STDC__ isn't defined. */
This page took 0.045794 seconds and 4 git commands to generate.