This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: New Target Hook for recording gcc switches


Hi Guys,

  I am seeking approval for the attached patch.  It adds a new target
  hook to gcc.  The hook, called TARGET_ASM_RECORD_GCC_SWITCHES,
  allows the backend to record the gcc command line switches and
  enabled options that are in effect whilst the assembly output file
  is being generated.  This is similar to the behaviour of the
  -fverbose-asm switch, but it is more flexible in that the backend
  can choose how to format the information.

  The motivation for this patch is a second patch to follow which
  allows extra switches to be read from an environment variable and
  inserted into GCC's command line.  I realise that this second patch
  might be controversial, but it was specifically requested by a
  customer.  This first patch is here so that object files can record
  the exact switches that were used to create them, thus aiding
  debugging when the displayed command line cannot be relied upon to
  show how GCC was invoked.

  The patch also includes an example implementation of the target hook
  for the mn10300 target.  In this implementation only the command line
  switches are recorded, not the enabled options.  They are recorded
  as strings into a mergeable section so that when object files are
  combined the command line information does not unnecessarily inflate
  the size of the resulting binary.

  Tested without any regressions on an x86 native toolchain and an
  mn10300-elf cross toolchain.

  Can I apply this patch please ?

Cheers
    Nick

gcc/ChangeLog    
2005-11-11  Nick Clifton  <nickc@redhat.com>

	* target.h (enum print_switch_type): Define.
        (print_fn_type): Define.
        (struct gcc_target): Add record_gcc_switches field to asm_out
        sub-structure.
	* target-def.h (TARGET_ASM_RECORD_GCC_SWITCHES): Provide
	default defintion.
        (TARGET_ASM_OUT): Add TARGET_ASM_RECORD_GCC_SWITCHES.
        * toplev.c (print_single_switch): Reorganise to take a
        print_fn_type paramter.
        (print_switch_values): Likewise.
        (print_to_asm_out_file): New function.
        (print_to_stderr): New function.
        (init_asm_output): If record_gcc_switches is defined in the
        targetm structure then use it to print the switch values,
        otherwise use print_to_asm_out_file or print_to_stderr.
        * doc/tm.texi: Document the new target hook.
        
        * config/gcc/mn10300.c (TARGET_ASM_RECORD_GCC_SWITCHES):
        Define.
        (mn10300_override_options): If -fverbose-asm has been enabled
        then disable the record_gcc_switches function.
        (mn10300_print_gcc_option): New helper function that prints a
        single gcc switch to the assembler output file.
        (mn10300_record_gcc_switches): New function.  Records gcc
        switches to a mergeable section called .GCC-command-line.

Index: gcc/target-def.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target-def.h,v
retrieving revision 1.134
diff -c -3 -p -r1.134 target-def.h
*** gcc/target-def.h	12 Oct 2005 20:54:48 -0000	1.134
--- gcc/target-def.h	11 Nov 2005 16:52:10 -0000
*************** Foundation, 51 Franklin Street, Fifth Fl
*** 205,210 ****
--- 205,214 ----
  #define TARGET_ASM_OUTPUT_DWARF_DTPREL NULL
  #endif
  
+ #ifndef TARGET_ASM_RECORD_GCC_SWITCHES
+ #define TARGET_ASM_RECORD_GCC_SWITCHES NULL
+ #endif
+ 
  #define TARGET_ASM_ALIGNED_INT_OP				\
  		       {TARGET_ASM_ALIGNED_HI_OP,		\
  			TARGET_ASM_ALIGNED_SI_OP,		\
*************** Foundation, 51 Franklin Street, Fifth Fl
*** 248,253 ****
--- 252,258 ----
                          TARGET_ASM_FILE_END,			\
  			TARGET_ASM_EXTERNAL_LIBCALL,            \
                          TARGET_ASM_MARK_DECL_PRESERVED,		\
+ 			TARGET_ASM_RECORD_GCC_SWITCHES,		\
  			TARGET_ASM_OUTPUT_DWARF_DTPREL}
  
  /* Scheduler hooks.  All of these default to null pointers, which
Index: gcc/target.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target.h,v
retrieving revision 1.145
diff -c -3 -p -r1.145 target.h
*** gcc/target.h	12 Oct 2005 20:54:48 -0000	1.145
--- gcc/target.h	11 Nov 2005 16:52:10 -0000
*************** Foundation, 51 Franklin Street, Fifth Fl
*** 50,55 ****
--- 50,68 ----
  #include "tm.h"
  #include "insn-modes.h"
  
+ /* Types used by the record_gcc_switches() target function.  */
+ typedef enum
+ {
+   SWITCH_TYPE_PASSED,		/* A switch passed on the command line.  */
+   SWITCH_TYPE_ENABLED,		/* An option that is currently enabled.  */
+   SWITCH_TYPE_DESCRIPTIVE,	/* Descriptive text, not a switch or option.  */
+   SWITCH_TYPE_LINE_START,	/* Please emit any necessary text at the start of a line.  */
+   SWITCH_TYPE_LINE_END		/* Please emit a line terminator.  */
+ }
+ print_switch_type;
+ 
+ typedef int (* print_fn_type) (print_switch_type, const char *);
+ 
  struct stdarg_info;
  
  struct gcc_target
*************** struct gcc_target
*** 183,191 ****
  	linker to not dead code strip this symbol.  */
      void (*mark_decl_preserved) (const char *);
  
      /* Output a DTP-relative reference to a TLS symbol.  */
      void (*output_dwarf_dtprel) (FILE *file, int size, rtx x);
- 
    } asm_out;
  
    /* Functions relating to instruction scheduling.  */
--- 196,206 ----
  	linker to not dead code strip this symbol.  */
      void (*mark_decl_preserved) (const char *);
  
+     /* Output a record of the command line switches that have been passed.  */
+     print_fn_type record_gcc_switches;
+ 
      /* Output a DTP-relative reference to a TLS symbol.  */
      void (*output_dwarf_dtprel) (FILE *file, int size, rtx x);
    } asm_out;
  
    /* Functions relating to instruction scheduling.  */
Index: gcc/toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.977
diff -c -3 -p -r1.977 toplev.c
*** gcc/toplev.c	11 Oct 2005 06:19:54 -0000	1.977
--- gcc/toplev.c	11 Nov 2005 16:52:11 -0000
*************** static void crash_signal (int) ATTRIBUTE
*** 111,122 ****
  static void setup_core_dumping (void);
  static void compile_file (void);
  
- static int print_single_switch (FILE *, int, int, const char *,
- 				const char *, const char *,
- 				const char *, const char *);
- static void print_switch_values (FILE *, int, int, const char *,
- 				 const char *, const char *);
- 
  /* Nonzero to dump debug info whilst parsing (-dy option).  */
  static int set_yydebug;
  
--- 111,116 ----
*************** print_version (FILE *file, const char *i
*** 1132,1175 ****
  	   PARAM_VALUE (GGC_MIN_EXPAND), PARAM_VALUE (GGC_MIN_HEAPSIZE));
  }
  
  /* Print an option value and return the adjusted position in the line.
!    ??? We don't handle error returns from fprintf (disk full); presumably
!    other code will catch a disk full though.  */
  
  static int
! print_single_switch (FILE *file, int pos, int max,
! 		     const char *indent, const char *sep, const char *term,
! 		     const char *type, const char *name)
! {
!   /* The ultrix fprintf returns 0 on success, so compute the result we want
!      here since we need it for the following test.  */
!   int len = strlen (sep) + strlen (type) + strlen (name);
  
    if (pos != 0
!       && pos + len > max)
      {
!       fprintf (file, "%s", term);
        pos = 0;
      }
    if (pos == 0)
!     {
!       fprintf (file, "%s", indent);
!       pos = strlen (indent);
!     }
!   fprintf (file, "%s%s%s", sep, type, name);
!   pos += len;
!   return pos;
  }
  
! /* Print active target switches to FILE.
     POS is the current cursor position and MAX is the size of a "line".
     Each line begins with INDENT and ends with TERM.
     Each switch is separated from the next by SEP.  */
  
  static void
! print_switch_values (FILE *file, int pos, int max,
! 		     const char *indent, const char *sep, const char *term)
  {
    size_t j;
    const char **p;
  
--- 1126,1232 ----
  	   PARAM_VALUE (GGC_MIN_EXPAND), PARAM_VALUE (GGC_MIN_HEAPSIZE));
  }
  
+ #ifdef ASM_COMMENT_START
+ static int
+ print_to_asm_out_file (print_switch_type type, const char * text)
+ {
+   bool prepend_sep = true;
+ 
+   switch (type)
+     {
+     case SWITCH_TYPE_LINE_END:
+       putc ('\n', asm_out_file);
+       return 1;
+ 
+     case SWITCH_TYPE_LINE_START:
+       fputs (ASM_COMMENT_START, asm_out_file);
+       return strlen (ASM_COMMENT_START);
+ 
+     case SWITCH_TYPE_DESCRIPTIVE:
+       if (ASM_COMMENT_START[0] == 0)
+ 	prepend_sep = false;
+       /* Drop through.  */
+     case SWITCH_TYPE_PASSED:
+     case SWITCH_TYPE_ENABLED:
+       if (prepend_sep)
+ 	fputc (' ', asm_out_file);
+       fprintf (asm_out_file, text);
+       /* No need to return the length here as
+ 	 print_single_switch has already done it.  */
+       return 0;
+ 
+     default:
+       return -1;
+     }
+ }
+ #endif
+ 
+ static int
+ print_to_stderr (print_switch_type type, const char * text)
+ {
+   switch (type)
+     {
+     case SWITCH_TYPE_LINE_END:
+       putc ('\n', stderr);
+       return 1;
+ 
+     case SWITCH_TYPE_LINE_START:
+       return 0;
+       
+     case SWITCH_TYPE_PASSED:
+     case SWITCH_TYPE_ENABLED:
+       fputc (' ', stderr);
+       /* Drop through.  */
+ 
+     case SWITCH_TYPE_DESCRIPTIVE:
+       fprintf (stderr, text);
+       /* No need to return the length here as
+ 	 print_single_switch has already done it.  */
+       return 0;
+ 
+     default:
+       return -1;
+     }
+ }
+ 
  /* Print an option value and return the adjusted position in the line.
!    ??? print_fn doesn't handle errors, eg disk full; presumably other
!    code will catch a disk full though.  */
  
  static int
! print_single_switch (print_fn_type print_fn,
! 		     int pos,
! 		     print_switch_type type,
! 		     const char * text)
! {
!   /* The ultrix fprintf returns 0 on success, so compute the result
!      we want here since we need it for the following test.  The +1
!      is for the seperator character that will probably be emitted.  */
!   int len = strlen (text) + 1;
  
    if (pos != 0
!       && pos + len > MAX_LINE)
      {
!       print_fn (SWITCH_TYPE_LINE_END, NULL);
        pos = 0;
      }
+ 
    if (pos == 0)
!     pos += print_fn (SWITCH_TYPE_LINE_START, NULL);
! 
!   print_fn (type, text);
!   return pos + len;
  }
  
! /* Print active target switches using PRINT_FN.
     POS is the current cursor position and MAX is the size of a "line".
     Each line begins with INDENT and ends with TERM.
     Each switch is separated from the next by SEP.  */
  
  static void
! print_switch_values (print_fn_type print_fn)
  {
+   int pos = 0;
    size_t j;
    const char **p;
  
*************** print_switch_values (FILE *file, int pos
*** 1178,1222 ****
    randomize ();
  
    /* Print the options as passed.  */
!   pos = print_single_switch (file, pos, max, indent, *indent ? " " : "", term,
! 			     _("options passed: "), "");
  
    for (p = &save_argv[1]; *p != NULL; p++)
!     if (**p == '-')
!       {
! 	/* Ignore these.  */
! 	if (strcmp (*p, "-o") == 0)
! 	  {
! 	    if (p[1] != NULL)
! 	      p++;
  	    continue;
- 	  }
- 	if (strcmp (*p, "-quiet") == 0)
- 	  continue;
- 	if (strcmp (*p, "-version") == 0)
- 	  continue;
- 	if ((*p)[1] == 'd')
- 	  continue;
  
! 	pos = print_single_switch (file, pos, max, indent, sep, term, *p, "");
!       }
    if (pos > 0)
!     fprintf (file, "%s", term);
  
    /* Print the -f and -m options that have been enabled.
       We don't handle language specific options but printing argv
       should suffice.  */
  
!   pos = print_single_switch (file, 0, max, indent, *indent ? " " : "", term,
! 			     _("options enabled: "), "");
  
    for (j = 0; j < cl_options_count; j++)
      if ((cl_options[j].flags & CL_REPORT)
  	&& option_enabled (j) > 0)
!       pos = print_single_switch (file, pos, max, indent, sep, term,
! 				 "", cl_options[j].opt_text);
  
!   fprintf (file, "%s", term);
  }
  
  /* Open assembly code output file.  Do this even if -fsyntax-only is
--- 1235,1285 ----
    randomize ();
  
    /* Print the options as passed.  */
!   pos = print_single_switch (print_fn, pos,
! 			     SWITCH_TYPE_DESCRIPTIVE, _("options passed: "));
  
    for (p = &save_argv[1]; *p != NULL; p++)
!     {
!       if (**p == '-')
! 	{
! 	  /* Ignore these.  */
! 	  if (strcmp (*p, "-o") == 0
! 	      || strcmp (*p, "-dumpbase") == 0
! 	      || strcmp (*p, "-auxbase") == 0)
! 	    {
! 	      if (p[1] != NULL)
! 		p++;
! 	      continue;
! 	    }
! 
! 	  if (strcmp (*p, "-quiet") == 0
! 	      || strcmp (*p, "-version") == 0)
  	    continue;
  
! 	  if ((*p)[1] == 'd')
! 	    continue;
! 	}
! 
!       pos = print_single_switch (print_fn, pos, SWITCH_TYPE_PASSED, *p);
!     }
! 
    if (pos > 0)
!     print_fn (SWITCH_TYPE_LINE_END, NULL);
  
    /* Print the -f and -m options that have been enabled.
       We don't handle language specific options but printing argv
       should suffice.  */
  
!   pos = print_single_switch (print_fn, 0,
! 			     SWITCH_TYPE_DESCRIPTIVE, _("options enabled: "));
  
    for (j = 0; j < cl_options_count; j++)
      if ((cl_options[j].flags & CL_REPORT)
  	&& option_enabled (j) > 0)
!       pos = print_single_switch (print_fn, pos,
! 				 SWITCH_TYPE_ENABLED, cl_options[j].opt_text);
  
!   print_fn (SWITCH_TYPE_LINE_END, NULL);
  }
  
  /* Open assembly code output file.  Do this even if -fsyntax-only is
*************** init_asm_output (const char *name)
*** 1251,1263 ****
      {
        targetm.asm_out.file_start ();
  
  #ifdef ASM_COMMENT_START
!       if (flag_verbose_asm)
  	{
  	  /* Print the list of options in effect.  */
  	  print_version (asm_out_file, ASM_COMMENT_START);
! 	  print_switch_values (asm_out_file, 0, MAX_LINE,
! 			       ASM_COMMENT_START, " ", "\n");
  	  /* Add a blank line here so it appears in assembler output but not
  	     screen output.  */
  	  fprintf (asm_out_file, "\n");
--- 1314,1331 ----
      {
        targetm.asm_out.file_start ();
  
+       if (targetm.asm_out.record_gcc_switches)
+ 	{
+ 	  targetm.asm_out.record_gcc_switches (SWITCH_TYPE_DESCRIPTIVE, NULL);
+ 	  print_switch_values (targetm.asm_out.record_gcc_switches);
+ 	  targetm.asm_out.record_gcc_switches (SWITCH_TYPE_DESCRIPTIVE, NULL);
+ 	}
  #ifdef ASM_COMMENT_START
!       else if (flag_verbose_asm)
  	{
  	  /* Print the list of options in effect.  */
  	  print_version (asm_out_file, ASM_COMMENT_START);
! 	  print_switch_values (print_to_asm_out_file);
  	  /* Add a blank line here so it appears in assembler output but not
  	     screen output.  */
  	  fprintf (asm_out_file, "\n");
*************** process_options (void)
*** 1612,1618 ****
      {
        print_version (stderr, "");
        if (! quiet_flag)
! 	print_switch_values (stderr, 0, MAX_LINE, "", " ", "\n");
      }
  
    if (flag_syntax_only)
--- 1680,1686 ----
      {
        print_version (stderr, "");
        if (! quiet_flag)
! 	print_switch_values (print_to_stderr);
      }
  
    if (flag_syntax_only)
Index: gcc/config/i386/winnt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/winnt.c,v
retrieving revision 1.85
diff -c -3 -p -r1.85 winnt.c
*** gcc/config/i386/winnt.c	12 Oct 2005 20:54:49 -0000	1.85
--- gcc/config/i386/winnt.c	11 Nov 2005 16:52:13 -0000
*************** i386_pe_mark_dllimport (tree decl)
*** 277,283 ****
    SYMBOL_REF_DECL (symref) = decl;
    newrtl = gen_rtx_MEM (Pmode,symref);
    XEXP (DECL_RTL (decl), 0) = newrtl;
- 
    DECL_DLLIMPORT_P (decl) = 1;
  }
  
--- 277,282 ----
Index: gcc/config/mn10300/mn10300.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mn10300/mn10300.c,v
retrieving revision 1.82
diff -c -3 -p -r1.82 mn10300.c
*** gcc/config/mn10300/mn10300.c	22 Sep 2005 00:10:26 -0000	1.82
--- gcc/config/mn10300/mn10300.c	11 Nov 2005 16:52:14 -0000
*************** static bool mn10300_pass_by_reference (C
*** 79,84 ****
--- 79,85 ----
  				       tree, bool);
  static int mn10300_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
  				      tree, bool);
+ static int mn10300_record_gcc_switches (print_switch_type, const char *);
  
  /* Initialize the GCC target structure.  */
  #undef TARGET_ASM_ALIGNED_HI_OP
*************** static int mn10300_arg_partial_bytes (CU
*** 116,121 ****
--- 117,126 ----
  #undef TARGET_EXPAND_BUILTIN_SAVEREGS
  #define TARGET_EXPAND_BUILTIN_SAVEREGS mn10300_builtin_saveregs
  
+ #undef  TARGET_ASM_RECORD_GCC_SWITCHES
+ #define TARGET_ASM_RECORD_GCC_SWITCHES mn10300_record_gcc_switches
+ 
+ 
  static void mn10300_encode_section_info (tree, rtx, int);
  struct gcc_target targetm = TARGET_INITIALIZER;
  
*************** mn10300_override_options (void)
*** 148,153 ****
--- 153,164 ----
  {
    if (TARGET_AM33)
      target_flags &= ~MASK_MULT_BUG;
+ 
+   /* If the user has requested a verbose assembler file then disable the
+      recording of gcc command line switches - this would just record a
+      duplicate set of information.  */
+   if (flag_verbose_asm)
+     targetm.asm_out.record_gcc_switches = NULL;
  }
  
  static void
*************** mn10300_encode_section_info (tree decl, 
*** 2126,2128 ****
--- 2137,2227 ----
    if (flag_pic)
      SYMBOL_REF_FLAG (symbol) = (*targetm.binds_local_p) (decl);
  }
+ 
+ /* Print a command line option to the assembler output file.
+    If the option contains any double quote chracters, escape them.  */
+ 
+ static void
+ mn10300_print_gcc_option (const char * option)
+ {
+   char * quote;
+ 
+   while ((quote = strchr (option, '"')) != NULL)
+     {
+       if (quote > option)
+ 	fprintf (asm_out_file, "%.*s", quote - option, option);
+       fputs ("\\\"", asm_out_file);
+       option = quote + 1;
+     }
+ 
+   if (* option)
+     fputs (option, asm_out_file);
+ }
+ 
+ static int
+ mn10300_record_gcc_switches (print_switch_type type, const char * name)
+ {
+   /* This variable is used as part of a simplistic heuristic to detect
+      command line switches which take an argument:
+ 
+        "If a command line option does not start with a dash then
+         it is an argument for the previous command line option."
+ 
+      This fails in the case of the command line option which is the name
+      of the file to compile, but otherwise it is pretty reasonable.  */
+   static bool previous_newline_omitted = FALSE;
+ 
+   switch (type)
+     {
+     case SWITCH_TYPE_PASSED:
+       if (* name != '-')
+ 	{
+ 	  if (previous_newline_omitted)
+ 	    fputs (" ", asm_out_file);
+ 	  else
+ 	    fputs ("\t.ascii \"", asm_out_file);
+ 
+ 	  mn10300_print_gcc_option (name);
+ 	  fputs ("\\0\\n\"\n", asm_out_file);
+ 
+ 	  previous_newline_omitted = FALSE;
+ 	}
+       else
+ 	{
+ 	  if (previous_newline_omitted)
+ 	    fputs ("\\0\\n\"\n", asm_out_file);
+ 	  fputs ("\t.ascii \"", asm_out_file);
+ 	  mn10300_print_gcc_option (name);
+ 
+ 	  previous_newline_omitted = TRUE;
+ 	}
+       break;
+ 
+     case SWITCH_TYPE_DESCRIPTIVE:
+       if (name == NULL)
+ 	{
+ 	  /* Distinguish between invocations where name is NULL.  */
+ 	  static bool started = false;
+ 
+ 	  if (started)
+ 	    {
+ 	      if (previous_newline_omitted)
+ 		fputs ("\\0\\n\"\n", asm_out_file);
+ 	    }
+ 	  else
+ 	    {
+ 	      named_section_flags (".GCC-command-line",
+ 				   SECTION_DEBUG
+ 				   | SECTION_MERGE
+ 				   | SECTION_STRINGS
+ 				   | (SECTION_ENTSIZE | 1));
+ 	      started = true;
+ 	    }
+ 	}
+ 
+     default:
+       break;
+     }
+   
+   return 0;
+ }
Index: gcc/doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.447
diff -c -3 -p -r1.447 tm.texi
*** gcc/doc/tm.texi	12 Oct 2005 20:54:49 -0000	1.447
--- gcc/doc/tm.texi	11 Nov 2005 16:52:20 -0000
*************** need to override this if your target has
*** 6274,6279 ****
--- 6274,6317 ----
  set via @code{__attribute__}.
  @end deftypefn
  
+ @deftypefn {Target Hook} {int} TARGET_ASM_RECORD_GCC_SWITCHES (print_switch_type @var{type}, const char * @var{text})
+ Provides the target with the ability to record the gcc command line
+ switches that have been passed to the compiler, and options that are
+ enabled.  The @var{type} argument specifies what is being recorded.
+ It can take the following values:
+ 
+ @table @gcctabopt
+ @item SWITCH_TYPE_PASSED
+ @var{text} is a command line switch that has been set by the user.
+ 
+ @item SWITCH_TYPE_ENABLED
+ @var{text} is an option which has been enabled.  This might be as a
+ direct result of a command line switch, or because it is enabled by
+ default or because it has been enabled as a side effect of a different
+ command line switch.  (For example the way the @option{-O2} switch
+ enables various different individual optimization passes).
+ 
+ @item SWITCH_TYPE_DESCRIPTIVE
+ @var{text} is either NULL or some descriptive text which can usually
+ be ignored.  If @var{text} is NULL then it is being used to warn the
+ target hook that either recording is starting or ending.  The first
+ time @var{type} is SWITCH_TYPE_DESCRIPTIVE and @var{text} is NULL, the
+ warning is for start up and the second time the warning is for
+ wind down.  This feature is to allow the target hook to make any
+ necessary preparations before it starts to record switches and to
+ perform any necessary tidying up after it has finished recording
+ switches.
+ 
+ @item SWITCH_TYPE_LINE_START
+ This is a request to emit a line start sequence.  This can be ignored
+ by this target hook.
+ 
+ @item  SWITCH_TYPE_LINE_END
+ This is a request to emit a line end sequence.  This can be ignored
+ by this target hook.
+ @end table
+ @end deftypefn
+ 
  @need 2000
  @node Data Output
  @subsection Output of Data

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]