dwarf2out multiple CU patch

Jason Merrill jason@redhat.com
Mon Aug 28 17:20:00 GMT 2000


Here's a cleaned-up version of the multiple CU patch.  I've left the
flag in for the moment, off by default, in order to get this code into
CVS so Daniel can work with it.

Daniel, when will your gdb changes to support FORM_ref_addr go in?  I
can't really test this until that happens.

I left out the olddie_offset stuff because things that get pubnames
only go in the main CU, so we can just process that one last and leave
the offsets alone.

I also left out your changes to the code that decides whether or not
to use an external reference because I don't see why they are
necessary.  The current code uses an external reference iff the offset
of the target is 0, as that indicates that the target is in another
CU.

gcc:
2000-08-28  Daniel Berlin  <dberlin@redhat.com>

	* dwarf2out.c (DIE_LABEL_PREFIX): Remove leading "__".
	(print_die): If we don't know the offset of the
	target die, try the symbol.  Add a trailing newline.
	(reverse_all_dies): New fn.
	(dwarf2out_finish): Call it.
	(break_out_includes): Reorganize for clarity.
	(add_sibling_attributes): Don't call reverse_die_lists.
	(output_comp_unit): Rename from output_comdat_comp_unit.  Use for
	primary CU, too.
	* flags.h: Add flag_eliminate_dwarf2_dups.
	* toplev.c (f_options): Support -feliminate-dwarf2-dups.

2000-08-28  Jason Merrill  <jason@redhat.com>

	* dwarf2.h (DW_TAG_GNU_BINCL, DW_TAG_GNU_EINCL): New tags.
	* dwarf2out.c: #include "md5.h".
	(DIE_LABEL_PREFIX): New macro.
	(dw_val_struct): Add 'external' flag to val_die_ref.
	(add_AT_die_ref, AT_ref): Adjust.
	(AT_ref_external, set_AT_ref_external): New fns.
	(build_abbrev_table): Call set_AT_ref_external.
	(value_format): Call AT_ref_external.
	(die_struct): Add die_symbol field.
	(new_die): Clear it.
	(dwarf_tag_name): Handle BINCL/EINCL.
	(dwarf2out_start_source_file): Add BINCL DIE.
	(dwarf2out_end_source_file): Add EINCL DIE.
	(push_new_compile_unit, pop_compile_unit, clear_die_sizes): New fns.
	(loc_checksum, attr_checksum, die_checksum): New fns.
	(is_type_die, is_comdat_die, is_symbol_die): New fns.
	(compute_section_prefix, assign_symbol_names): New fns.
	(gen_internal_sym, output_die_symbol, output_symbolic_ref): New fns.
	(output_die): Call output_die_symbol and AT_ref_external.
	(output_comdat_comp_unit): New fn, split out from...
	(dwarf2out_finish): ...here.  Also call add_sibling_attributes for 
	secondary CUs.
	(output_pubnames, output_aranges): Abort if we see entries from
	secondary CUs.
	* toplev.h: Declare file_name_nondirectory.
	* toplev.c (file_name_nondirectory): New fn, moved from C++ frontend.
	(rest_of_type_compilation): Call dwarf2out_decl if at toplevel.
	(debug_start_source_file): Call dwarf2out_start_source_file
	regardless of debug verbosity.
	(debug_end_source_file): Similarly.
	* tree.h: Declare clean_symbol_name.
	* tree.c (clean_symbol_name): Split out from...
	(get_file_function_name_long): ...here.

	* dwarf2out.c (new_loc_descr): Use calloc.
	(splice_child_die): Remove the die from the right parent.
	(gen_struct_or_union_die): Don't add AT_name to a specification DIE.

gcc/cp:
2000-08-28  Jason Merrill  <jason@redhat.com>

	* lex.c (file_name_nondirectory): Move to toplev.c.

libiberty:
2000-08-28  Jason Merrill  <jason@redhat.com>

	* Makefile.in (REQUIRED_OFILES): Add md5.o.
	(CFILES): Add md5.c.
	* md5.c: New file.

include:
2000-08-28  Jason Merrill  <jason@redhat.com>

	* md5.h: New file.

Index: gcc/dwarf2.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarf2.h,v
retrieving revision 1.15
diff -c -p -r1.15 dwarf2.h
*** gcc/dwarf2.h	2000/08/03 22:41:38	1.15
--- gcc/dwarf2.h	2000/08/28 23:43:26
*************** enum dwarf_tag
*** 88,94 ****
      /* GNU extensions */
      DW_TAG_format_label = 0x4101,	/* for FORTRAN 77 and Fortran 90 */
      DW_TAG_function_template = 0x4102,	/* for C++ */
!     DW_TAG_class_template = 0x4103	/* for C++ */
    };
  
  #define DW_TAG_lo_user	0x4080
--- 88,96 ----
      /* GNU extensions */
      DW_TAG_format_label = 0x4101,	/* for FORTRAN 77 and Fortran 90 */
      DW_TAG_function_template = 0x4102,	/* for C++ */
!     DW_TAG_class_template = 0x4103,	/* for C++ */
!     DW_TAG_GNU_BINCL = 0x4104,
!     DW_TAG_GNU_EINCL = 0x4105
    };
  
  #define DW_TAG_lo_user	0x4080
Index: gcc/dwarf2out.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarf2out.c,v
retrieving revision 1.198
diff -c -p -r1.198 dwarf2out.c
*** gcc/dwarf2out.c	2000/08/28 23:07:55	1.198
--- gcc/dwarf2out.c	2000/08/28 23:43:33
*************** the Free Software Foundation, 59 Temple 
*** 23,31 ****
  Boston, MA 02111-1307, USA.  */
  
  /* TODO: Implement .debug_str handling, and share entries somehow.
- 	 Eliminate duplicates by putting common info in a separate section
- 	   to be collected by the linker and referring to it with
- 	   DW_FORM_ref_addr.
  	 Emit .debug_line header even when there are no functions, since
  	   the file numbers are used by .debug_info.  Alternately, leave
  	   out locations for types and decls.
--- 23,28 ----
*************** Boston, MA 02111-1307, USA.  */
*** 56,61 ****
--- 53,59 ----
  #include "toplev.h"
  #include "varray.h"
  #include "ggc.h"
+ #include "md5.h"
  #include "tm_p.h"
  
  /* Decide whether we want to emit frame unwind information for the current
*************** static void def_cfa_1		 	PARAMS ((const 
*** 303,308 ****
--- 301,307 ----
  #define FDE_AFTER_SIZE_LABEL	"LSFDE"
  #define FDE_END_LABEL		"LEFDE"
  #define FDE_LENGTH_LABEL	"LLFDE"
+ #define DIE_LABEL_PREFIX	"DW"
  
  /* Definitions of defaults for various types of primitive assembly language
     output operations.  These may be overridden from within the tm.h file,
*************** typedef struct dw_val_struct
*** 2124,2130 ****
        long unsigned val_unsigned;
        dw_long_long_const val_long_long;
        dw_float_const val_float;
!       dw_die_ref val_die_ref;
        unsigned val_fde_index;
        char *val_str;
        char *val_lbl_id;
--- 2123,2132 ----
        long unsigned val_unsigned;
        dw_long_long_const val_long_long;
        dw_float_const val_float;
!       struct {
! 	dw_die_ref die;
! 	int external;
!       } val_die_ref;
        unsigned val_fde_index;
        char *val_str;
        char *val_lbl_id;
*************** dw_attr_node;
*** 2995,3000 ****
--- 2997,3003 ----
  typedef struct die_struct
  {
    enum dwarf_tag die_tag;
+   char *die_symbol;
    dw_attr_ref die_attr;
    dw_die_ref die_parent;
    dw_die_ref die_child;
*************** static void equate_decl_number_to_die	PA
*** 3338,3357 ****
--- 3341,3378 ----
  static void print_spaces		PARAMS ((FILE *));
  static void print_die			PARAMS ((dw_die_ref, FILE *));
  static void print_dwarf_line_table	PARAMS ((FILE *));
+ static void reverse_die_lists		PARAMS ((dw_die_ref));
+ static void reverse_all_dies		PARAMS ((dw_die_ref));
+ static dw_die_ref push_new_compile_unit PARAMS ((dw_die_ref, dw_die_ref));
+ static dw_die_ref pop_compile_unit	PARAMS ((dw_die_ref));
+ static void loc_checksum	 PARAMS ((dw_loc_descr_ref, struct md5_ctx *));
+ static void attr_checksum 	      PARAMS ((dw_attr_ref, struct md5_ctx *));
+ static void die_checksum	       PARAMS ((dw_die_ref, struct md5_ctx *));
+ static void compute_section_prefix	PARAMS ((dw_die_ref));
+ static int is_type_die			PARAMS ((dw_die_ref));
+ static int is_comdat_die 		PARAMS ((dw_die_ref));
+ static int is_symbol_die 		PARAMS ((dw_die_ref));
+ static char *gen_internal_sym 		PARAMS ((void));
+ static void assign_symbol_names		PARAMS ((dw_die_ref));
+ static void break_out_includes		PARAMS ((dw_die_ref));
  static void add_sibling_attributes	PARAMS ((dw_die_ref));
  static void build_abbrev_table		PARAMS ((dw_die_ref));
  static unsigned long size_of_string	PARAMS ((const char *));
  static int constant_size		PARAMS ((long unsigned));
  static unsigned long size_of_die	PARAMS ((dw_die_ref));
  static void calc_die_sizes		PARAMS ((dw_die_ref));
+ static void clear_die_sizes		PARAMS ((dw_die_ref));
  static unsigned long size_of_line_prolog PARAMS ((void));
  static unsigned long size_of_pubnames	PARAMS ((void));
  static unsigned long size_of_aranges	PARAMS ((void));
  static enum dwarf_form value_format	PARAMS ((dw_attr_ref));
  static void output_value_format		PARAMS ((dw_attr_ref));
  static void output_abbrev_section	PARAMS ((void));
+ static void output_die_symbol		PARAMS ((dw_die_ref));
+ static void output_symbolic_ref		PARAMS ((dw_die_ref));
  static void output_die			PARAMS ((dw_die_ref));
  static void output_compilation_unit_header PARAMS ((void));
+ static void output_comp_unit		PARAMS ((dw_die_ref));
  static const char *dwarf2_name		PARAMS ((tree, int));
  static void add_pubname			PARAMS ((tree, dw_die_ref));
  static void output_pubnames		PARAMS ((void));
*************** static void gen_type_die_for_member	PARA
*** 3441,3447 ****
  static void gen_abstract_function	PARAMS ((tree));
  static rtx save_rtx			PARAMS ((rtx));
  static void splice_child_die		PARAMS ((dw_die_ref, dw_die_ref));
- static void reverse_die_lists		PARAMS ((dw_die_ref));
  
  /* Section names used to hold DWARF debugging information.  */
  #ifndef DEBUG_INFO_SECTION
--- 3462,3467 ----
*************** dwarf_tag_name (tag)
*** 3728,3733 ****
--- 3748,3757 ----
        return "DW_TAG_function_template";
      case DW_TAG_class_template:
        return "DW_TAG_class_template";
+     case DW_TAG_GNU_BINCL:
+       return "DW_TAG_GNU_BINCL";
+     case DW_TAG_GNU_EINCL:
+       return "DW_TAG_GNU_EINCL";
      default:
        return "DW_TAG_<unknown>";
      }
*************** decl_class_context (decl)
*** 4079,4085 ****
  }
  
  /* Add an attribute/value pair to a DIE.  We build the lists up in reverse
!    addition order, and correct that in add_sibling_attributes.  */
  
  static inline void
  add_dwarf_attr (die, attr)
--- 4103,4109 ----
  }
  
  /* Add an attribute/value pair to a DIE.  We build the lists up in reverse
!    addition order, and correct that in reverse_all_dies.  */
  
  static inline void
  add_dwarf_attr (die, attr)
*************** add_AT_die_ref (die, attr_kind, targ_die
*** 4264,4270 ****
    attr->dw_attr_next = NULL;
    attr->dw_attr = attr_kind;
    attr->dw_attr_val.val_class = dw_val_class_die_ref;
!   attr->dw_attr_val.v.val_die_ref = targ_die;
    add_dwarf_attr (die, attr);
  }
  
--- 4288,4295 ----
    attr->dw_attr_next = NULL;
    attr->dw_attr = attr_kind;
    attr->dw_attr_val.val_class = dw_val_class_die_ref;
!   attr->dw_attr_val.v.val_die_ref.die = targ_die;
!   attr->dw_attr_val.v.val_die_ref.external = 0;
    add_dwarf_attr (die, attr);
  }
  
*************** AT_ref (a)
*** 4274,4284 ****
       register dw_attr_ref a;
  {
    if (a && AT_class (a) == dw_val_class_die_ref)
!     return a->dw_attr_val.v.val_die_ref;
  
    abort ();
  }
  
  /* Add an FDE reference attribute value to a DIE.  */
  
  static inline void
--- 4299,4332 ----
       register dw_attr_ref a;
  {
    if (a && AT_class (a) == dw_val_class_die_ref)
!     return a->dw_attr_val.v.val_die_ref.die;
  
    abort ();
  }
  
+ static inline int AT_ref_external PARAMS ((dw_attr_ref));
+ static inline int
+ AT_ref_external (a)
+      register dw_attr_ref a;
+ {
+   if (a && AT_class (a) == dw_val_class_die_ref)
+     return a->dw_attr_val.v.val_die_ref.external;
+ 
+   return 0;
+ }
+ 
+ static inline void set_AT_ref_external PARAMS ((dw_attr_ref, int));
+ static inline void
+ set_AT_ref_external (a, i)
+      register dw_attr_ref a;
+      int i;
+ {
+   if (a && AT_class (a) == dw_val_class_die_ref)
+     a->dw_attr_val.v.val_die_ref.external = i;
+   else
+     abort ();
+ }
+ 
  /* Add an FDE reference attribute value to a DIE.  */
  
  static inline void
*************** remove_children (die)
*** 4611,4617 ****
  }
  
  /* Add a child DIE below its parent.  We build the lists up in reverse
!    addition order, and correct that in add_sibling_attributes.  */
  
  static inline void
  add_child_die (die, child_die)
--- 4659,4665 ----
  }
  
  /* Add a child DIE below its parent.  We build the lists up in reverse
!    addition order, and correct that in reverse_all_dies.  */
  
  static inline void
  add_child_die (die, child_die)
*************** new_die (tag_value, parent_die)
*** 4677,4682 ****
--- 4725,4731 ----
    die->die_parent = NULL;
    die->die_sib = NULL;
    die->die_attr = NULL;
+   die->die_symbol = NULL;
  
    if (parent_die != NULL)
      add_child_die (parent_die, die);
*************** print_die (die, outfile)
*** 4822,4828 ****
  	  break;
  	case dw_val_class_die_ref:
  	  if (AT_ref (a) != NULL)
! 	    fprintf (outfile, "die -> %lu", AT_ref (a)->die_offset);
  	  else
  	    fprintf (outfile, "die -> <null>");
  	  break;
--- 4871,4882 ----
  	  break;
  	case dw_val_class_die_ref:
  	  if (AT_ref (a) != NULL)
! 	    {
! 	      if (AT_ref (a)->die_offset == 0)
! 		fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol);
! 	      else
! 		fprintf (outfile, "die -> %lu", AT_ref (a)->die_offset);
! 	    }
  	  else
  	    fprintf (outfile, "die -> <null>");
  	  break;
*************** print_die (die, outfile)
*** 4851,4856 ****
--- 4905,4912 ----
  
        print_indent -= 4;
      }
+   if (print_indent == 0)
+     fprintf (outfile, "\n");
  }
  
  /* Print the contents of the source code line number correspondence table.
*************** reverse_die_lists (die)
*** 4925,4944 ****
    die->die_child = cp;
  }
  
! /* Traverse the DIE, reverse its lists of attributes and children, and
!    add a sibling attribute if it may have the effect of speeding up
!    access to siblings.  To save some space, avoid generating sibling
!    attributes for DIE's without children.  */
  
  static void
! add_sibling_attributes (die)
       register dw_die_ref die;
  {
    register dw_die_ref c;
  
    reverse_die_lists (die);
  
!   if (die != comp_unit_die && die->die_sib && die->die_child != NULL)
      /* Add the sibling link to the front of the attribute list.  */
      add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
  
--- 4981,5363 ----
    die->die_child = cp;
  }
  
! /* reverse_die_lists only reverses the single die you pass it. Since
!    we used to reverse all dies in add_sibling_attributes, which runs
!    through all the dies, it would reverse all the dies.  Now, however,
!    since we don't call reverse_die_lists in add_sibling_attributes, we
!    need a routine to recursively reverse all the dies. This is that
!    routine.  */
  
  static void
! reverse_all_dies (die)
       register dw_die_ref die;
  {
    register dw_die_ref c;
  
    reverse_die_lists (die);
+ 
+   for (c = die->die_child; c; c = c->die_sib)
+     reverse_all_dies (c);
+ }
+ 
+ /* Start a new compilation unit DIE for an include file.  OLD_UNIT is
+    the CU for the enclosing include file, if any.  BINCL_DIE is the
+    DW_TAG_GNU_BINCL DIE that marks the start of the DIEs for this
+    include file.  */
+ 
+ static dw_die_ref
+ push_new_compile_unit (old_unit, bincl_die)
+      dw_die_ref old_unit, bincl_die;
+ {
+   const char *filename = get_AT_string (bincl_die, DW_AT_name);
+   dw_die_ref new_unit = gen_compile_unit_die (filename);
+   new_unit->die_sib = old_unit;
+   return new_unit;
+ }
+ 
+ /* Close an include-file CU and reopen the enclosing one.  */
+ 
+ static dw_die_ref
+ pop_compile_unit (old_unit)
+      dw_die_ref old_unit;
+ {
+   dw_die_ref new_unit = old_unit->die_sib;
+   old_unit->die_sib = NULL;
+   return new_unit;
+ }
+ 
+ #define PROCESS(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
+ #define PROCESS_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO), ctx)
+ 
+ /* Calculate the checksum of a location expression.  */
+ 
+ static inline void
+ loc_checksum (loc, ctx)
+      dw_loc_descr_ref loc;
+      struct md5_ctx *ctx;
+ {
+   PROCESS (loc->dw_loc_opc);
+   PROCESS (loc->dw_loc_oprnd1);
+   PROCESS (loc->dw_loc_oprnd2);
+ }
+ 
+ /* Calculate the checksum of an attribute.  */
+ 
+ static void
+ attr_checksum (at, ctx)
+      dw_attr_ref at;
+      struct md5_ctx *ctx;
+ {
+   dw_loc_descr_ref loc;
+   rtx r;
+ 
+   PROCESS (at->dw_attr);
+ 
+   /* We don't care about differences in file numbering.  */
+   if (at->dw_attr == DW_AT_decl_file)
+     return;
+ 
+   switch (AT_class (at))
+     {
+     case dw_val_class_const:
+       PROCESS (at->dw_attr_val.v.val_int);
+       break;
+     case dw_val_class_unsigned_const:
+       PROCESS (at->dw_attr_val.v.val_unsigned);
+       break;
+     case dw_val_class_long_long:
+       PROCESS (at->dw_attr_val.v.val_long_long);
+       break;
+     case dw_val_class_float:
+       PROCESS (at->dw_attr_val.v.val_float);
+       break;
+     case dw_val_class_flag:
+       PROCESS (at->dw_attr_val.v.val_flag);
+       break;
+ 
+     case dw_val_class_str:
+       PROCESS_STRING (AT_string (at));
+       break;
+     case dw_val_class_addr:
+       r = AT_addr (at);
+       switch (GET_CODE (r))
+ 	{
+ 	case SYMBOL_REF:
+ 	  PROCESS_STRING (XSTR (r, 0));
+ 	  break;
+ 
+ 	default:
+ 	  abort ();
+ 	}
+       break;
+ 
+     case dw_val_class_loc:
+       for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
+ 	loc_checksum (loc, ctx);
+       break;
+ 
+     case dw_val_class_die_ref:
+       if (AT_ref (at)->die_offset)
+ 	PROCESS (AT_ref (at)->die_offset);
+       /* FIXME else use target die name or something.  */
+ 
+     case dw_val_class_fde_ref:
+     case dw_val_class_lbl_id:
+     case dw_val_class_lbl_offset:
+ 
+     default:
+       break;
+     }
+ }
+ 
+ /* Calculate the checksum of a DIE.  */
+ 
+ static void
+ die_checksum (die, ctx)
+      dw_die_ref die;
+      struct md5_ctx *ctx;
+ {
+   dw_die_ref c;
+   dw_attr_ref a;
+ 
+   PROCESS (die->die_tag);
+ 
+   for (a = die->die_attr; a; a = a->dw_attr_next)
+     attr_checksum (a, ctx);
+ 
+   for (c = die->die_child; c; c = c->die_sib)
+     die_checksum (c, ctx);
+ }
+ 
+ #undef PROCESS
+ #undef PROCESS_STRING
+ 
+ /* The prefix to attach to symbols on DIEs in the current comdat debug
+    info section.  */
+ static char *comdat_symbol_id;
+ 
+ /* The index of the current symbol within the current comdat CU.  */
+ static unsigned int comdat_symbol_number;
+ 
+ /* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
+    children, and set comdat_symbol_id accordingly.  */
+ 
+ static void
+ compute_section_prefix (unit_die)
+      dw_die_ref unit_die;
+ {
+   char *p, *name;
+   int i;
+   unsigned char checksum[16];
+   struct md5_ctx ctx;
+ 
+   md5_init_ctx (&ctx);
+   die_checksum (unit_die, &ctx);
+   md5_finish_ctx (&ctx, checksum);
+ 
+   p = file_name_nondirectory (get_AT_string (unit_die, DW_AT_name));
+   name = (char *) alloca (strlen (p) + 64);
+   sprintf (name, "%s.", p);
+ 
+   clean_symbol_name (name);
+ 
+   p = name + strlen (name);
+   for (i = 0; i < 4; ++i)
+     {
+       sprintf (p, "%.2x", checksum[i]);
+       p += 2;
+     }
+ 
+   comdat_symbol_id = unit_die->die_symbol = xstrdup (name);
+   comdat_symbol_number = 0;
+ }
+ 
+ /* Returns nonzero iff DIE represents a type, in the sense of TYPE_P.  */
+ 
+ static int
+ is_type_die (die)
+      dw_die_ref die;
+ {
+   switch (die->die_tag)
+     {
+     case DW_TAG_array_type:
+     case DW_TAG_class_type:
+     case DW_TAG_enumeration_type:
+     case DW_TAG_pointer_type:
+     case DW_TAG_reference_type:
+     case DW_TAG_string_type:
+     case DW_TAG_structure_type:
+     case DW_TAG_subroutine_type:
+     case DW_TAG_union_type:
+     case DW_TAG_ptr_to_member_type:
+     case DW_TAG_set_type:
+     case DW_TAG_subrange_type:
+     case DW_TAG_base_type:
+     case DW_TAG_const_type:
+     case DW_TAG_file_type:
+     case DW_TAG_packed_type:
+     case DW_TAG_volatile_type:
+       return 1;
+     default:
+       return 0;
+     }
+ }
+ 
+ /* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU.
+    Basically, we want to choose the bits that are likely to be shared between
+    compilations (types) and leave out the bits that are specific to individual
+    compilations (functions).  */
+ 
+ static int
+ is_comdat_die (c)
+      dw_die_ref c;
+ {
+   /* FIXME disable */
+   if (1)
+     return 0;
+ 
+ #if 1
+   /* I think we want to leave base types and __vtbl_ptr_type in the
+      main CU, as we do for stabs.  The advantage is a greater
+      likelihood of sharing between objects that don't include headers
+      in the same order (and therefore would put the base types in a
+      different comdat).  jason 8/28/00 */
+   if (c->die_tag == DW_TAG_base_type)
+     return 0;
+ 
+   if (c->die_tag == DW_TAG_pointer_type
+       || c->die_tag == DW_TAG_reference_type
+       || c->die_tag == DW_TAG_const_type
+       || c->die_tag == DW_TAG_volatile_type)
+     {
+       dw_die_ref t = get_AT_ref (c, DW_AT_type);
+       return t ? is_comdat_die (t) : 0;
+     }
+ #endif
+ 
+   return is_type_die (c);
+ }
+ 
+ /* Returns 1 iff C is the sort of DIE that might be referred to from another
+    compilation unit.  */
+ 
+ static int
+ is_symbol_die (c)
+      dw_die_ref c;
+ {
+   if (is_type_die (c))
+     return 1;
+   if (get_AT (c, DW_AT_declaration)
+       && ! get_AT (c, DW_AT_specification))
+     return 1;
+   return 0;
+ }
+ 
+ static char *
+ gen_internal_sym ()
+ {
+   char buf[256];
+   static int label_num;
+   ASM_GENERATE_INTERNAL_LABEL (buf, "LDIE", label_num++);
+   return xstrdup (buf);
+ }
+ 
+ /* Assign symbols to all worthy DIEs under DIE.  */
+ 
+ static void
+ assign_symbol_names (die)
+      register dw_die_ref die;
+ {
+   register dw_die_ref c;
+ 
+   if (is_symbol_die (die))
+     {
+       if (comdat_symbol_id)
+ 	{
+ 	  char *p = alloca (strlen (comdat_symbol_id) + 64);
+ 	  sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
+ 		   comdat_symbol_id, comdat_symbol_number++);
+ 	  die->die_symbol = xstrdup (p);
+ 	}
+       else
+ 	die->die_symbol = gen_internal_sym ();
+     }
+ 
+   for (c = die->die_child; c != NULL; c = c->die_sib)
+     assign_symbol_names (c);
+ }
+ 
+ /* Traverse the DIE (which is always comp_unit_die), and set up
+    additional compilation units for each of the include files we see
+    bracketed by BINCL/EINCL.  */
+ 
+ static void
+ break_out_includes (die)
+      register dw_die_ref die;
+ {
+   dw_die_ref *ptr;
+   register dw_die_ref unit = NULL;
+   limbo_die_node *node;
+ 
+   for (ptr = &(die->die_child); *ptr; )
+     {
+       register dw_die_ref c = *ptr;
+ 
+       if (c->die_tag == DW_TAG_GNU_BINCL
+ 	  || c->die_tag == DW_TAG_GNU_EINCL
+ 	  || (unit && is_comdat_die (c)))
+ 	{
+ 	  /* This DIE is for a secondary CU; remove it from the main one.  */
+ 	  *ptr = c->die_sib;
+ 
+ 	  if (c->die_tag == DW_TAG_GNU_BINCL)
+ 	    {
+ 	      unit = push_new_compile_unit (unit, c);
+ 	      free_die (c);
+ 	    }
+ 	  else if (c->die_tag == DW_TAG_GNU_EINCL)
+ 	    {
+ 	      unit = pop_compile_unit (unit);
+ 	      free_die (c);
+ 	    }
+ 	  else
+ 	    add_child_die (unit, c);
+ 	}
+       else
+ 	{
+ 	  /* Leave this DIE in the main CU.  */
+ 	  ptr = &(c->die_sib);
+ 	  continue;
+ 	}
+     }
+ 
+ #if 0
+   /* We can only use this in debugging, since the frontend doesn't check
+      to make sure that we leave every include file we enter.  */     
+   if (unit != NULL)
+     abort ();
+ #endif
+ 
+   assign_symbol_names (die);
+   for (node = limbo_die_list; node; node = node->next)
+     {
+       compute_section_prefix (node->die);
+       assign_symbol_names (node->die);
+     }
+ }
+ 
+ /* Traverse the DIE and add a sibling attribute if it may have the
+    effect of speeding up access to siblings.  To save some space,
+    avoid generating sibling attributes for DIE's without children.  */
+ 
+ static void
+ add_sibling_attributes (die)
+      register dw_die_ref die;
+ {
+   register dw_die_ref c;
  
!   if (die->die_tag != DW_TAG_compile_unit
!       && die->die_sib && die->die_child != NULL)
      /* Add the sibling link to the front of the attribute list.  */
      add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
  
*************** build_abbrev_table (die)
*** 4960,4965 ****
--- 5379,5398 ----
    register unsigned long n_alloc;
    register dw_die_ref c;
    register dw_attr_ref d_attr, a_attr;
+ 
+   /* Scan the DIE references, and mark as external any that refer to
+      DIEs from other CUs (i.e. those with cleared die_offset).  */
+   for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
+     {
+       if (AT_class (d_attr) == dw_val_class_die_ref
+ 	  && AT_ref (d_attr)->die_offset == 0)
+ 	{
+ 	  if (AT_ref (d_attr)->die_symbol == 0)
+ 	    abort ();
+ 	  set_AT_ref_external (d_attr, 1);
+ 	}
+     }
+ 
    for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
      {
        register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
*************** calc_die_sizes (die)
*** 5130,5135 ****
--- 5563,5582 ----
      next_die_offset += 1;
  }
  
+ /* Clear the offsets and sizes for a die and its children.  We do this so
+    that we know whether or not a reference needs to use FORM_ref_addr; only
+    DIEs in the same CU will have non-zero offsets available.  */
+ 
+ static void
+ clear_die_sizes (die)
+      dw_die_ref die;
+ {
+   register dw_die_ref c;
+   die->die_offset = 0;
+   for (c = die->die_child; c; c = c->die_sib)
+     clear_die_sizes (c);
+ }
+ 
  /* Return the size of the line information prolog generated for the
     compilation unit.  */
  
*************** value_format (a)
*** 5250,5256 ****
      case dw_val_class_flag:
        return DW_FORM_flag;
      case dw_val_class_die_ref:
!       return DW_FORM_ref;
      case dw_val_class_fde_ref:
        return DW_FORM_data;
      case dw_val_class_lbl_id:
--- 5697,5706 ----
      case dw_val_class_flag:
        return DW_FORM_flag;
      case dw_val_class_die_ref:
!       if (AT_ref_external (a))
! 	return DW_FORM_ref_addr;
!       else
! 	return DW_FORM_ref;
      case dw_val_class_fde_ref:
        return DW_FORM_data;
      case dw_val_class_lbl_id:
*************** output_abbrev_section ()
*** 5333,5338 ****
--- 5783,5821 ----
    fprintf (asm_out_file, "\t%s\t0\n", ASM_BYTE_OP);
  }
  
+ /* Output a symbol we can use to refer to this DIE from another CU.  */
+ 
+ static inline void
+ output_die_symbol (die)
+      register dw_die_ref die;
+ {
+   char *sym = die->die_symbol;
+ 
+   if (sym == 0)
+     return;
+ 
+   if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0)
+     /* We make these global, not weak; if the target doesn't support
+        .linkonce, it doesn't support combining the sections, so debugging
+        will break.  */
+     ASM_GLOBALIZE_LABEL (asm_out_file, sym);
+   ASM_OUTPUT_LABEL (asm_out_file, sym);
+ }
+ 
+ /* Output a symbolic (i.e. FORM_ref_addr) reference to TARGET_DIE.  */
+ 
+ static inline void
+ output_symbolic_ref (target_die)
+      dw_die_ref target_die;
+ {
+   char *sym = target_die->die_symbol;
+ 
+   if (sym == 0)
+     abort ();
+ 
+   ASM_OUTPUT_DWARF_OFFSET (asm_out_file, sym);
+ }
+ 
  /* Output the DIE and its attributes.  Called recursively to generate
     the definitions of each child DIE.  */
  
*************** output_die (die)
*** 5344,5349 ****
--- 5827,5837 ----
    register dw_die_ref c;
    register unsigned long size;
  
+   /* If someone in another CU might refer to us, set up a symbol for
+      them to point to.  */
+   if (die->die_symbol)
+     output_die_symbol (die);
+ 
    output_uleb128 (die->die_abbrev);
    if (flag_debug_asm)
      fprintf (asm_out_file, " (DIE (0x%lx) %s)",
*************** output_die (die)
*** 5457,5463 ****
  	  break;
  
  	case dw_val_class_die_ref:
! 	  ASM_OUTPUT_DWARF_DATA (asm_out_file, AT_ref (a)->die_offset);
  	  break;
  
  	case dw_val_class_fde_ref:
--- 5945,5954 ----
  	  break;
  
  	case dw_val_class_die_ref:
! 	  if (AT_ref_external (a))
! 	    output_symbolic_ref (AT_ref (a));
! 	  else
! 	    ASM_OUTPUT_DWARF_DATA (asm_out_file, AT_ref (a)->die_offset);
  	  break;
  
  	case dw_val_class_fde_ref:
*************** output_compilation_unit_header ()
*** 5547,5552 ****
--- 6038,6081 ----
    fputc ('\n', asm_out_file);
  }
  
+ /* Output the compilation unit DIE and its children.  */
+ 
+ static void
+ output_comp_unit (die)
+      dw_die_ref die;
+ {
+   char *secname;
+ 
+   if (die->die_child == 0)
+     return;
+ 
+   /* Initialize the beginning DIE offset - and calculate sizes/offsets.   */
+   next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
+   calc_die_sizes (die);
+ 
+   build_abbrev_table (die);
+ 
+   if (die->die_symbol)
+     {
+       secname = (char *) alloca (strlen (die->die_symbol) + 24);
+       sprintf (secname, ".gnu.linkonce.wi.%s", die->die_symbol);
+       die->die_symbol = NULL;
+     }
+   else
+     secname = (char *) DEBUG_INFO_SECTION;
+ 
+   /* Output debugging information.  */
+   fputc ('\n', asm_out_file);
+   ASM_OUTPUT_SECTION (asm_out_file, secname);
+   output_compilation_unit_header ();
+   output_die (die);
+ 
+   /* Leave the sizes on the main CU, since we do it last and we use the
+      sizes in output_pubnames.  */
+   if (die->die_symbol)
+     clear_die_sizes (die);
+ }
+ 
  /* The DWARF2 pubname for a nested thingy looks like "A::f".  The output
     of decl_printable_name for C++ looks like "A::f(int)".  Let's drop the
     argument list, and maybe the scope.  */
*************** output_pubnames ()
*** 5622,5627 ****
--- 6151,6160 ----
      {
        register pubname_ref pub = &pubname_table[i];
  
+       /* We shouldn't see pubnames for DIEs outside of the main CU.  */
+       if (pub->die->die_offset == 0)
+ 	abort ();
+ 
        ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset);
        if (flag_debug_asm)
  	fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START);
*************** output_aranges ()
*** 5735,5740 ****
--- 6268,6277 ----
      {
        dw_die_ref die = arange_table[i];
  
+       /* We shouldn't see aranges for DIEs outside of the main CU.  */
+       if (die->die_offset == 0)
+ 	abort ();
+ 
        if (die->die_tag == DW_TAG_subprogram)
  	ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (die));
        else
*************** void
*** 10134,10139 ****
--- 10671,10679 ----
  dwarf2out_start_source_file (filename)
       register const char *filename ATTRIBUTE_UNUSED;
  {
+   /* Record the beginning of the file for break_out_includes.  */
+   dw_die_ref bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die);
+   add_AT_string (bincl_die, DW_AT_name, filename);
  }
  
  /* Record the end of a source file, for later output
*************** dwarf2out_start_source_file (filename)
*** 10142,10147 ****
--- 10682,10689 ----
  void
  dwarf2out_end_source_file ()
  {
+   /* Record the end of the file for break_out_includes.  */
+   new_die (DW_TAG_GNU_EINCL, comp_unit_die);
  }
  
  /* Called from check_newline in c-parse.y.  The `buffer' parameter contains
*************** dwarf2out_finish ()
*** 10291,10299 ****
       emit full debugging info for them.  */
    retry_incomplete_types ();
  
!   /* Traverse the DIE's, reverse their lists of attributes and children,
!      and add add sibling attributes to those DIE's that have children.  */
    add_sibling_attributes (comp_unit_die);
  
    /* Output a terminator label for the .text section.  */
    fputc ('\n', asm_out_file);
--- 10833,10851 ----
       emit full debugging info for them.  */
    retry_incomplete_types ();
  
!   /* We need to reverse all the dies before break_out_includes, or
!      we'll see the end of an include file before the beginning.  */
!   reverse_all_dies (comp_unit_die);
! 
!   /* Generate separate CUs for each of the include files we've seen.
!      They will go into limbo_die_list.  */
!   break_out_includes (comp_unit_die);
! 
!   /* Traverse the DIE's and add add sibling attributes to those DIE's
!      that have children.  */
    add_sibling_attributes (comp_unit_die);
+   for (node = limbo_die_list; node; node = node->next)
+     add_sibling_attributes (node->die);
  
    /* Output a terminator label for the .text section.  */
    fputc ('\n', asm_out_file);
*************** dwarf2out_finish ()
*** 10339,10359 ****
      add_AT_unsigned (die, DW_AT_macro_info, 0);
  #endif
  
    /* Output the abbreviation table.  */
    fputc ('\n', asm_out_file);
    ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
-   build_abbrev_table (comp_unit_die);
    output_abbrev_section ();
- 
-   /* Initialize the beginning DIE offset - and calculate sizes/offsets.   */
-   next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
-   calc_die_sizes (comp_unit_die);
- 
-   /* Output debugging information.  */
-   fputc ('\n', asm_out_file);
-   ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION);
-   output_compilation_unit_header ();
-   output_die (comp_unit_die);
  
    if (pubname_table_in_use)
      {
--- 10891,10906 ----
      add_AT_unsigned (die, DW_AT_macro_info, 0);
  #endif
  
+   /* Output all of the compilation units.  We put the main one last so that
+      the offsets are available to output_pubnames.  */
+   for (node = limbo_die_list; node; node = node->next)
+     output_comp_unit (node->die);
+   output_comp_unit (comp_unit_die);
+ 
    /* Output the abbreviation table.  */
    fputc ('\n', asm_out_file);
    ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
    output_abbrev_section ();
  
    if (pubname_table_in_use)
      {
Index: gcc/flags.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flags.h,v
retrieving revision 1.46
diff -c -p -r1.46 flags.h
*** gcc/flags.h	2000/07/30 23:57:55	1.46
--- gcc/flags.h	2000/08/29 00:05:38
*************** extern enum graph_dump_types graph_dump_
*** 577,579 ****
--- 577,583 ----
     string identifying the compiler.  */
  
  extern int flag_no_ident;
+ 
+ /* Nonzero means we should do dwarf2 duplicate elimination.  */
+ 
+ extern int flag_eliminate_dwarf2_dups;
Index: gcc/toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.369
diff -c -p -r1.369 toplev.c
*** gcc/toplev.c	2000/08/28 22:52:30	1.369
--- gcc/toplev.c	2000/08/29 00:05:42
*************** tree (*lang_expand_constant) PARAMS ((tr
*** 422,427 ****
--- 422,431 ----
  
  void (*incomplete_decl_finalize_hook) PARAMS ((tree)) = 0;
  
+ /* Nonzero if doing dwarf2 duplicate elimination.  */
+ 
+ int flag_eliminate_dwarf2dup = 0;
+ 
  /* Nonzero if generating code to do profiling.  */
  
  int profile_flag = 0;
*************** const char *user_label_prefix;
*** 944,949 ****
--- 948,955 ----
  
  lang_independent_options f_options[] =
  {
+   {"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1, 
+    "Perform DWARF2 duplicate elimination"},
    {"float-store", &flag_float_store, 1,
     "Do not store floats in registers" },
    {"volatile", &flag_volatile, 1,
*************** strip_off_ending (name, len)
*** 1656,1661 ****
--- 1662,1682 ----
      }
  }
  
+ /* Given a file name X, return the nondirectory portion.  */
+ 
+ char *
+ file_name_nondirectory (x)
+      const char *x;
+ {
+   char *tmp = (char *) rindex (x, '/');
+   if (DIR_SEPARATOR != '/' && ! tmp)
+     tmp = (char *) rindex (x, DIR_SEPARATOR);
+   if (tmp)
+     return (char *) (tmp + 1);
+   else
+     return (char *) x;
+ }
+ 
  /* Output a quoted string.  */
  
  void
*************** rest_of_type_compilation (type, toplev)
*** 2561,2566 ****
--- 2582,2591 ----
    if (write_symbols == SDB_DEBUG)
      sdbout_symbol (TYPE_STUB_DECL (type), !toplev);
  #endif
+ #ifdef DWARF2_DEBUGGING_INFO
+   if (write_symbols == DWARF2_DEBUG && toplev)
+     dwarf2out_decl (TYPE_STUB_DECL (type));
+ #endif
    timevar_pop (TV_SYMOUT);
  }
  
*************** debug_start_source_file (filename)
*** 4973,4980 ****
      dwarfout_start_new_source_file (filename);
  #endif /* DWARF_DEBUGGING_INFO  */
  #ifdef DWARF2_DEBUGGING_INFO
!   if (debug_info_level == DINFO_LEVEL_VERBOSE
!       && write_symbols == DWARF2_DEBUG)
      dwarf2out_start_source_file (filename);
  #endif /* DWARF2_DEBUGGING_INFO  */
  #ifdef SDB_DEBUGGING_INFO
--- 4998,5004 ----
      dwarfout_start_new_source_file (filename);
  #endif /* DWARF_DEBUGGING_INFO  */
  #ifdef DWARF2_DEBUGGING_INFO
!   if (write_symbols == DWARF2_DEBUG)
      dwarf2out_start_source_file (filename);
  #endif /* DWARF2_DEBUGGING_INFO  */
  #ifdef SDB_DEBUGGING_INFO
*************** debug_end_source_file (lineno)
*** 5000,5007 ****
      dwarfout_resume_previous_source_file (lineno);
  #endif /* DWARF_DEBUGGING_INFO  */
  #ifdef DWARF2_DEBUGGING_INFO
!   if (debug_info_level == DINFO_LEVEL_VERBOSE
!       && write_symbols == DWARF2_DEBUG)
      dwarf2out_end_source_file ();
  #endif /* DWARF2_DEBUGGING_INFO  */
  #ifdef SDB_DEBUGGING_INFO
--- 5024,5030 ----
      dwarfout_resume_previous_source_file (lineno);
  #endif /* DWARF_DEBUGGING_INFO  */
  #ifdef DWARF2_DEBUGGING_INFO
!   if (write_symbols == DWARF2_DEBUG)
      dwarf2out_end_source_file ();
  #endif /* DWARF2_DEBUGGING_INFO  */
  #ifdef SDB_DEBUGGING_INFO
Index: gcc/toplev.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.h,v
retrieving revision 1.45
diff -c -p -r1.45 toplev.h
*** gcc/toplev.h	2000/07/21 07:10:36	1.45
--- gcc/toplev.h	2000/08/28 23:43:42
*************** extern int read_integral_parameter	PARAM
*** 35,40 ****
--- 35,41 ----
  						const int));
  extern int count_error			PARAMS ((int));
  extern void strip_off_ending		PARAMS ((char *, int));
+ extern char *file_name_nondirectory	PARAMS ((const char *));
  extern void print_time			PARAMS ((const char *, long));
  extern void debug_start_source_file	PARAMS ((const char *));
  extern void debug_end_source_file	PARAMS ((unsigned));
Index: gcc/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.c,v
retrieving revision 1.153
diff -c -p -r1.153 tree.c
*** gcc/tree.c	2000/08/05 00:50:00	1.153
--- gcc/tree.c	2000/08/28 23:43:47
*************** append_random_chars (template)
*** 5386,5391 ****
--- 5386,5411 ----
    template[6] = '\0';
  }
  
+ /* P is a string that will be used in a symbol.  Mask out any characters
+    that are not valid in that context.  */
+ 
+ void
+ clean_symbol_name (p)
+      char *p;
+ {
+   for (; *p; p++)
+     if (! ( ISDIGIT(*p)
+ #ifndef NO_DOLLAR_IN_LABEL	/* this for `$'; unlikely, but... -- kr */
+ 	    || *p == '$'
+ #endif
+ #ifndef NO_DOT_IN_LABEL		/* this for `.'; unlikely, but...  */
+ 	    || *p == '.'
+ #endif
+ 	    || ISUPPER(*p)
+ 	    || ISLOWER(*p)))
+       *p = '_';
+ }
+   
  /* Generate a name for a function unique to this translation unit.
     TYPE is some string to identify the purpose of this function to the
     linker or collect2.  */
*************** get_file_function_name_long (type)
*** 5431,5449 ****
  
    /* Don't need to pull weird characters out of global names.  */
    if (p != first_global_object_name)
!     {
!       for (q = buf+11; *q; q++)
! 	if (! ( ISDIGIT(*q)
! #ifndef NO_DOLLAR_IN_LABEL	/* this for `$'; unlikely, but... -- kr */
! 	       || *q == '$'
! #endif
! #ifndef NO_DOT_IN_LABEL		/* this for `.'; unlikely, but...  */
! 	       || *q == '.'
! #endif
! 	       || ISUPPER(*q)
! 	       || ISLOWER(*q)))
! 	  *q = '_';
!     }
  
    return get_identifier (buf);
  }
--- 5451,5457 ----
  
    /* Don't need to pull weird characters out of global names.  */
    if (p != first_global_object_name)
!     clean_symbol_name (buf + 11);
  
    return get_identifier (buf);
  }
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.191
diff -c -p -r1.191 tree.h
*** gcc/tree.h	2000/08/25 00:58:26	1.191
--- gcc/tree.h	2000/08/28 23:43:50
*************** extern tree builtin_function			PARAMS ((
*** 2435,2440 ****
--- 2435,2441 ----
  
  /* In tree.c */
  extern char *perm_calloc			PARAMS ((int, long));
+ extern void clean_symbol_name			PARAMS ((char *));
  extern tree get_file_function_name		PARAMS ((int));
  extern tree get_file_function_name_long 	PARAMS ((const char *));
  extern tree get_set_constructor_bits		PARAMS ((tree, char *, int));
Index: gcc/cp/lex.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/lex.c,v
retrieving revision 1.212
diff -c -p -r1.212 lex.c
*** gcc/cp/lex.c	2000/08/21 10:14:18	1.212
--- gcc/cp/lex.c	2000/08/28 23:44:11
*************** static int is_extended_char PARAMS ((int
*** 96,116 ****
  static int is_extended_char_1 PARAMS ((int));
  static void init_operators PARAMS ((void));
  
- /* Given a file name X, return the nondirectory portion.
-    Keep in mind that X can be computed more than once.  */
- char *
- file_name_nondirectory (x)
-      const char *x;
- {
-   char *tmp = (char *) rindex (x, '/');
-   if (DIR_SEPARATOR != '/' && ! tmp)
-     tmp = (char *) rindex (x, DIR_SEPARATOR);
-   if (tmp)
-     return (char *) (tmp + 1);
-   else
-     return (char *) x;
- }
- 
  /* This obstack is needed to hold text.  It is not safe to use
     TOKEN_BUFFER because `check_newline' calls `yylex'.  */
  struct obstack inline_text_obstack;
--- 96,101 ----
Index: libiberty/Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/libiberty/Makefile.in,v
retrieving revision 1.52
diff -c -p -r1.52 Makefile.in
*** libiberty/Makefile.in	2000/07/26 23:23:24	1.52
--- libiberty/Makefile.in	2000/08/28 23:44:29
*************** CFILES = asprintf.c alloca.c argv.c atex
*** 128,134 ****
  	bzero.c calloc.c choose-temp.c clock.c concat.c cplus-dem.c	      \
          cp-demangle.c dyn-string.c fdmatch.c fnmatch.c getcwd.c		      \
  	getpwd.c getopt.c getopt1.c getpagesize.c getruntime.c		      \
! 	floatformat.c hashtab.c hex.c index.c insque.c memchr.c memcmp.c      \
  	memcpy.c memmove.c memset.c mkstemps.c objalloc.c obstack.c	      \
  	partition.c pexecute.c putenv.c random.c rename.c rindex.c setenv.c   \
  	sigsetmask.c sort.c spaces.c splay-tree.c strcasecmp.c strncasecmp.c  \
--- 128,134 ----
  	bzero.c calloc.c choose-temp.c clock.c concat.c cplus-dem.c	      \
          cp-demangle.c dyn-string.c fdmatch.c fnmatch.c getcwd.c		      \
  	getpwd.c getopt.c getopt1.c getpagesize.c getruntime.c		      \
! 	floatformat.c hashtab.c hex.c index.c insque.c md5.c memchr.c memcmp.c\
  	memcpy.c memmove.c memset.c mkstemps.c objalloc.c obstack.c	      \
  	partition.c pexecute.c putenv.c random.c rename.c rindex.c setenv.c   \
  	sigsetmask.c sort.c spaces.c splay-tree.c strcasecmp.c strncasecmp.c  \
*************** CFILES = asprintf.c alloca.c argv.c atex
*** 140,146 ****
  # These are always included in the library.
  REQUIRED_OFILES = argv.o choose-temp.o concat.o cplus-dem.o cp-demangle.o \
  	dyn-string.o fdmatch.o fnmatch.o getopt.o getopt1.o getpwd.o	  \
! 	getruntime.o hashtab.o hex.o floatformat.o objalloc.o obstack.o	  \
  	partition.o pexecute.o sort.o spaces.o splay-tree.o strerror.o	  \
  	strsignal.o xatexit.o xexit.o xmalloc.o xmemdup.o xstrdup.o	  \
  	xstrerror.o
--- 140,146 ----
  # These are always included in the library.
  REQUIRED_OFILES = argv.o choose-temp.o concat.o cplus-dem.o cp-demangle.o \
  	dyn-string.o fdmatch.o fnmatch.o getopt.o getopt1.o getpwd.o	  \
! 	getruntime.o hashtab.o hex.o floatformat.o md5.o objalloc.o obstack.o \
  	partition.o pexecute.o sort.o spaces.o splay-tree.o strerror.o	  \
  	strsignal.o xatexit.o xexit.o xmalloc.o xmemdup.o xstrdup.o	  \
  	xstrerror.o
Index: libiberty/md5.c
===================================================================
RCS file: md5.c
diff -N md5.c
*** /dev/null	Tue May  5 13:32:27 1998
--- libiberty/md5.c	Mon Aug 28 16:53:15 2000
***************
*** 0 ****
--- 1,419 ----
+ /* md5.c - Functions to compute MD5 message digest of files or memory blocks
+    according to the definition of MD5 in RFC 1321 from April 1992.
+    Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+    NOTE: The canonical source of this file is maintained with the GNU C
+    Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+ 
+    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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+ 
+ /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
+ 
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+ #endif
+ 
+ #include <sys/types.h>
+ 
+ #if STDC_HEADERS || defined _LIBC
+ # include <stdlib.h>
+ # include <string.h>
+ #else
+ # ifndef HAVE_MEMCPY
+ #  define memcpy(d, s, n) bcopy ((s), (d), (n))
+ # endif
+ #endif
+ 
+ #include "md5.h"
+ 
+ #ifdef _LIBC
+ # include <endian.h>
+ # if __BYTE_ORDER == __BIG_ENDIAN
+ #  define WORDS_BIGENDIAN 1
+ # endif
+ #endif
+ 
+ #ifdef WORDS_BIGENDIAN
+ # define SWAP(n)							\
+     (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+ #else
+ # define SWAP(n) (n)
+ #endif
+ 
+ 
+ /* This array contains the bytes used to pad the buffer to the next
+    64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
+ static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
+ 
+ 
+ /* Initialize structure containing state of computation.
+    (RFC 1321, 3.3: Step 3)  */
+ void
+ md5_init_ctx (ctx)
+      struct md5_ctx *ctx;
+ {
+   ctx->A = 0x67452301;
+   ctx->B = 0xefcdab89;
+   ctx->C = 0x98badcfe;
+   ctx->D = 0x10325476;
+ 
+   ctx->total[0] = ctx->total[1] = 0;
+   ctx->buflen = 0;
+ }
+ 
+ /* Put result from CTX in first 16 bytes following RESBUF.  The result
+    must be in little endian byte order.
+ 
+    IMPORTANT: On some systems it is required that RESBUF is correctly
+    aligned for a 32 bits value.  */
+ void *
+ md5_read_ctx (ctx, resbuf)
+      const struct md5_ctx *ctx;
+      void *resbuf;
+ {
+   ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+   ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+   ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+   ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+ 
+   return resbuf;
+ }
+ 
+ /* Process the remaining bytes in the internal buffer and the usual
+    prolog according to the standard and write the result to RESBUF.
+ 
+    IMPORTANT: On some systems it is required that RESBUF is correctly
+    aligned for a 32 bits value.  */
+ void *
+ md5_finish_ctx (ctx, resbuf)
+      struct md5_ctx *ctx;
+      void *resbuf;
+ {
+   /* Take yet unprocessed bytes into account.  */
+   md5_uint32 bytes = ctx->buflen;
+   size_t pad;
+ 
+   /* Now count remaining bytes.  */
+   ctx->total[0] += bytes;
+   if (ctx->total[0] < bytes)
+     ++ctx->total[1];
+ 
+   pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+   memcpy (&ctx->buffer[bytes], fillbuf, pad);
+ 
+   /* Put the 64-bit file length in *bits* at the end of the buffer.  */
+   *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+   *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+ 							(ctx->total[0] >> 29));
+ 
+   /* Process last bytes.  */
+   md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+ 
+   return md5_read_ctx (ctx, resbuf);
+ }
+ 
+ /* Compute MD5 message digest for bytes read from STREAM.  The
+    resulting message digest number will be written into the 16 bytes
+    beginning at RESBLOCK.  */
+ int
+ md5_stream (stream, resblock)
+      FILE *stream;
+      void *resblock;
+ {
+   /* Important: BLOCKSIZE must be a multiple of 64.  */
+ #define BLOCKSIZE 4096
+   struct md5_ctx ctx;
+   char buffer[BLOCKSIZE + 72];
+   size_t sum;
+ 
+   /* Initialize the computation context.  */
+   md5_init_ctx (&ctx);
+ 
+   /* Iterate over full file contents.  */
+   while (1)
+     {
+       /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+ 	 computation function processes the whole buffer so that with the
+ 	 next round of the loop another block can be read.  */
+       size_t n;
+       sum = 0;
+ 
+       /* Read block.  Take care for partial reads.  */
+       do
+ 	{
+ 	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+ 
+ 	  sum += n;
+ 	}
+       while (sum < BLOCKSIZE && n != 0);
+       if (n == 0 && ferror (stream))
+         return 1;
+ 
+       /* If end of file is reached, end the loop.  */
+       if (n == 0)
+ 	break;
+ 
+       /* Process buffer with BLOCKSIZE bytes.  Note that
+ 			BLOCKSIZE % 64 == 0
+        */
+       md5_process_block (buffer, BLOCKSIZE, &ctx);
+     }
+ 
+   /* Add the last bytes if necessary.  */
+   if (sum > 0)
+     md5_process_bytes (buffer, sum, &ctx);
+ 
+   /* Construct result in desired memory.  */
+   md5_finish_ctx (&ctx, resblock);
+   return 0;
+ }
+ 
+ /* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+    result is always in little endian byte order, so that a byte-wise
+    output yields to the wanted ASCII representation of the message
+    digest.  */
+ void *
+ md5_buffer (buffer, len, resblock)
+      const char *buffer;
+      size_t len;
+      void *resblock;
+ {
+   struct md5_ctx ctx;
+ 
+   /* Initialize the computation context.  */
+   md5_init_ctx (&ctx);
+ 
+   /* Process whole buffer but last len % 64 bytes.  */
+   md5_process_bytes (buffer, len, &ctx);
+ 
+   /* Put result in desired memory area.  */
+   return md5_finish_ctx (&ctx, resblock);
+ }
+ 
+ 
+ void
+ md5_process_bytes (buffer, len, ctx)
+      const void *buffer;
+      size_t len;
+      struct md5_ctx *ctx;
+ {
+   /* When we already have some bits in our internal buffer concatenate
+      both inputs first.  */
+   if (ctx->buflen != 0)
+     {
+       size_t left_over = ctx->buflen;
+       size_t add = 128 - left_over > len ? len : 128 - left_over;
+ 
+       memcpy (&ctx->buffer[left_over], buffer, add);
+       ctx->buflen += add;
+ 
+       if (left_over + add > 64)
+ 	{
+ 	  md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
+ 	  /* The regions in the following copy operation cannot overlap.  */
+ 	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ 		  (left_over + add) & 63);
+ 	  ctx->buflen = (left_over + add) & 63;
+ 	}
+ 
+       buffer = (const char *) buffer + add;
+       len -= add;
+     }
+ 
+   /* Process available complete blocks.  */
+   if (len > 64)
+     {
+       md5_process_block (buffer, len & ~63, ctx);
+       buffer = (const char *) buffer + (len & ~63);
+       len &= 63;
+     }
+ 
+   /* Move remaining bytes in internal buffer.  */
+   if (len > 0)
+     {
+       memcpy (ctx->buffer, buffer, len);
+       ctx->buflen = len;
+     }
+ }
+ 
+ 
+ /* These are the four functions used in the four steps of the MD5 algorithm
+    and defined in the RFC 1321.  The first function is a little bit optimized
+    (as found in Colin Plumbs public domain implementation).  */
+ /* #define FF(b, c, d) ((b & c) | (~b & d)) */
+ #define FF(b, c, d) (d ^ (b & (c ^ d)))
+ #define FG(b, c, d) FF (d, b, c)
+ #define FH(b, c, d) (b ^ c ^ d)
+ #define FI(b, c, d) (c ^ (b | ~d))
+ 
+ /* Process LEN bytes of BUFFER, accumulating context into CTX.
+    It is assumed that LEN % 64 == 0.  */
+ 
+ void
+ md5_process_block (buffer, len, ctx)
+      const void *buffer;
+      size_t len;
+      struct md5_ctx *ctx;
+ {
+   md5_uint32 correct_words[16];
+   const md5_uint32 *words = buffer;
+   size_t nwords = len / sizeof (md5_uint32);
+   const md5_uint32 *endp = words + nwords;
+   md5_uint32 A = ctx->A;
+   md5_uint32 B = ctx->B;
+   md5_uint32 C = ctx->C;
+   md5_uint32 D = ctx->D;
+ 
+   /* First increment the byte count.  RFC 1321 specifies the possible
+      length of the file up to 2^64 bits.  Here we only compute the
+      number of bytes.  Do a double word increment.  */
+   ctx->total[0] += len;
+   if (ctx->total[0] < len)
+     ++ctx->total[1];
+ 
+   /* Process all bytes in the buffer with 64 bytes in each round of
+      the loop.  */
+   while (words < endp)
+     {
+       md5_uint32 *cwp = correct_words;
+       md5_uint32 A_save = A;
+       md5_uint32 B_save = B;
+       md5_uint32 C_save = C;
+       md5_uint32 D_save = D;
+ 
+       /* First round: using the given function, the context and a constant
+ 	 the next context is computed.  Because the algorithms processing
+ 	 unit is a 32-bit word and it is determined to work on words in
+ 	 little endian byte order we perhaps have to change the byte order
+ 	 before the computation.  To reduce the work for the next steps
+ 	 we store the swapped words in the array CORRECT_WORDS.  */
+ 
+ #define OP(a, b, c, d, s, T)						\
+       do								\
+         {								\
+ 	  a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;		\
+ 	  ++words;							\
+ 	  CYCLIC (a, s);						\
+ 	  a += b;							\
+         }								\
+       while (0)
+ 
+       /* It is unfortunate that C does not provide an operator for
+ 	 cyclic rotation.  Hope the C compiler is smart enough.  */
+ #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+ 
+       /* Before we start, one word to the strange constants.
+ 	 They are defined in RFC 1321 as
+ 
+ 	 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+        */
+ 
+       /* Round 1.  */
+       OP (A, B, C, D,  7, 0xd76aa478);
+       OP (D, A, B, C, 12, 0xe8c7b756);
+       OP (C, D, A, B, 17, 0x242070db);
+       OP (B, C, D, A, 22, 0xc1bdceee);
+       OP (A, B, C, D,  7, 0xf57c0faf);
+       OP (D, A, B, C, 12, 0x4787c62a);
+       OP (C, D, A, B, 17, 0xa8304613);
+       OP (B, C, D, A, 22, 0xfd469501);
+       OP (A, B, C, D,  7, 0x698098d8);
+       OP (D, A, B, C, 12, 0x8b44f7af);
+       OP (C, D, A, B, 17, 0xffff5bb1);
+       OP (B, C, D, A, 22, 0x895cd7be);
+       OP (A, B, C, D,  7, 0x6b901122);
+       OP (D, A, B, C, 12, 0xfd987193);
+       OP (C, D, A, B, 17, 0xa679438e);
+       OP (B, C, D, A, 22, 0x49b40821);
+ 
+       /* For the second to fourth round we have the possibly swapped words
+ 	 in CORRECT_WORDS.  Redefine the macro to take an additional first
+ 	 argument specifying the function to use.  */
+ #undef OP
+ #define OP(f, a, b, c, d, k, s, T)					\
+       do 								\
+ 	{								\
+ 	  a += f (b, c, d) + correct_words[k] + T;			\
+ 	  CYCLIC (a, s);						\
+ 	  a += b;							\
+ 	}								\
+       while (0)
+ 
+       /* Round 2.  */
+       OP (FG, A, B, C, D,  1,  5, 0xf61e2562);
+       OP (FG, D, A, B, C,  6,  9, 0xc040b340);
+       OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+       OP (FG, B, C, D, A,  0, 20, 0xe9b6c7aa);
+       OP (FG, A, B, C, D,  5,  5, 0xd62f105d);
+       OP (FG, D, A, B, C, 10,  9, 0x02441453);
+       OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+       OP (FG, B, C, D, A,  4, 20, 0xe7d3fbc8);
+       OP (FG, A, B, C, D,  9,  5, 0x21e1cde6);
+       OP (FG, D, A, B, C, 14,  9, 0xc33707d6);
+       OP (FG, C, D, A, B,  3, 14, 0xf4d50d87);
+       OP (FG, B, C, D, A,  8, 20, 0x455a14ed);
+       OP (FG, A, B, C, D, 13,  5, 0xa9e3e905);
+       OP (FG, D, A, B, C,  2,  9, 0xfcefa3f8);
+       OP (FG, C, D, A, B,  7, 14, 0x676f02d9);
+       OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+ 
+       /* Round 3.  */
+       OP (FH, A, B, C, D,  5,  4, 0xfffa3942);
+       OP (FH, D, A, B, C,  8, 11, 0x8771f681);
+       OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+       OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+       OP (FH, A, B, C, D,  1,  4, 0xa4beea44);
+       OP (FH, D, A, B, C,  4, 11, 0x4bdecfa9);
+       OP (FH, C, D, A, B,  7, 16, 0xf6bb4b60);
+       OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+       OP (FH, A, B, C, D, 13,  4, 0x289b7ec6);
+       OP (FH, D, A, B, C,  0, 11, 0xeaa127fa);
+       OP (FH, C, D, A, B,  3, 16, 0xd4ef3085);
+       OP (FH, B, C, D, A,  6, 23, 0x04881d05);
+       OP (FH, A, B, C, D,  9,  4, 0xd9d4d039);
+       OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+       OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+       OP (FH, B, C, D, A,  2, 23, 0xc4ac5665);
+ 
+       /* Round 4.  */
+       OP (FI, A, B, C, D,  0,  6, 0xf4292244);
+       OP (FI, D, A, B, C,  7, 10, 0x432aff97);
+       OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+       OP (FI, B, C, D, A,  5, 21, 0xfc93a039);
+       OP (FI, A, B, C, D, 12,  6, 0x655b59c3);
+       OP (FI, D, A, B, C,  3, 10, 0x8f0ccc92);
+       OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+       OP (FI, B, C, D, A,  1, 21, 0x85845dd1);
+       OP (FI, A, B, C, D,  8,  6, 0x6fa87e4f);
+       OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+       OP (FI, C, D, A, B,  6, 15, 0xa3014314);
+       OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+       OP (FI, A, B, C, D,  4,  6, 0xf7537e82);
+       OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+       OP (FI, C, D, A, B,  2, 15, 0x2ad7d2bb);
+       OP (FI, B, C, D, A,  9, 21, 0xeb86d391);
+ 
+       /* Add the starting values of the context.  */
+       A += A_save;
+       B += B_save;
+       C += C_save;
+       D += D_save;
+     }
+ 
+   /* Put checksum in context given as argument.  */
+   ctx->A = A;
+   ctx->B = B;
+   ctx->C = C;
+   ctx->D = D;
+ }
Index: include/md5.h
===================================================================
RCS file: md5.h
diff -N md5.h
*** /dev/null	Tue May  5 13:32:27 1998
--- include/md5.h	Mon Aug 28 16:53:15 2000
***************
*** 0 ****
--- 1,146 ----
+ /* md5.h - Declaration of functions and data types used for MD5 sum
+    computing library functions.
+    Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+    NOTE: The canonical source of this file is maintained with the GNU C
+    Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+ 
+    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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+ 
+ #ifndef _MD5_H
+ #define _MD5_H 1
+ 
+ #include <stdio.h>
+ 
+ #if defined HAVE_LIMITS_H || _LIBC
+ # include <limits.h>
+ #endif
+ 
+ /* The following contortions are an attempt to use the C preprocessor
+    to determine an unsigned integral type that is 32 bits wide.  An
+    alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+    doing that would require that the configure script compile and *run*
+    the resulting executable.  Locally running cross-compiled executables
+    is usually not possible.  */
+ 
+ #ifdef _LIBC
+ # include <sys/types.h>
+ typedef u_int32_t md5_uint32;
+ #else
+ # if defined __STDC__ && __STDC__
+ #  define UINT_MAX_32_BITS 4294967295U
+ # else
+ #  define UINT_MAX_32_BITS 0xFFFFFFFF
+ # endif
+ 
+ /* If UINT_MAX isn't defined, assume it's a 32-bit type.
+    This should be valid for all systems GNU cares about because
+    that doesn't include 16-bit systems, and only modern systems
+    (that certainly have <limits.h>) have 64+-bit integral types.  */
+ 
+ # ifndef UINT_MAX
+ #  define UINT_MAX UINT_MAX_32_BITS
+ # endif
+ 
+ # if UINT_MAX == UINT_MAX_32_BITS
+    typedef unsigned int md5_uint32;
+ # else
+ #  if USHRT_MAX == UINT_MAX_32_BITS
+     typedef unsigned short md5_uint32;
+ #  else
+ #   if ULONG_MAX == UINT_MAX_32_BITS
+      typedef unsigned long md5_uint32;
+ #   else
+      /* The following line is intended to evoke an error.
+         Using #error is not portable enough.  */
+      "Cannot determine unsigned 32-bit data type."
+ #   endif
+ #  endif
+ # endif
+ #endif
+ 
+ #undef __P
+ #if defined (__STDC__) && __STDC__
+ #define	__P(x) x
+ #else
+ #define	__P(x) ()
+ #endif
+ 
+ /* Structure to save state of computation between the single steps.  */
+ struct md5_ctx
+ {
+   md5_uint32 A;
+   md5_uint32 B;
+   md5_uint32 C;
+   md5_uint32 D;
+ 
+   md5_uint32 total[2];
+   md5_uint32 buflen;
+   char buffer[128];
+ };
+ 
+ /*
+  * The following three functions are build up the low level used in
+  * the functions `md5_stream' and `md5_buffer'.
+  */
+ 
+ /* Initialize structure containing state of computation.
+    (RFC 1321, 3.3: Step 3)  */
+ extern void md5_init_ctx __P ((struct md5_ctx *ctx));
+ 
+ /* Starting with the result of former calls of this function (or the
+    initialization function update the context for the next LEN bytes
+    starting at BUFFER.
+    It is necessary that LEN is a multiple of 64!!! */
+ extern void md5_process_block __P ((const void *buffer, size_t len,
+ 				    struct md5_ctx *ctx));
+ 
+ /* Starting with the result of former calls of this function (or the
+    initialization function update the context for the next LEN bytes
+    starting at BUFFER.
+    It is NOT required that LEN is a multiple of 64.  */
+ extern void md5_process_bytes __P ((const void *buffer, size_t len,
+ 				    struct md5_ctx *ctx));
+ 
+ /* Process the remaining bytes in the buffer and put result from CTX
+    in first 16 bytes following RESBUF.  The result is always in little
+    endian byte order, so that a byte-wise output yields to the wanted
+    ASCII representation of the message digest.
+ 
+    IMPORTANT: On some systems it is required that RESBUF is correctly
+    aligned for a 32 bits value.  */
+ extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+ 
+ 
+ /* Put result from CTX in first 16 bytes following RESBUF.  The result is
+    always in little endian byte order, so that a byte-wise output yields
+    to the wanted ASCII representation of the message digest.
+ 
+    IMPORTANT: On some systems it is required that RESBUF is correctly
+    aligned for a 32 bits value.  */
+ extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+ 
+ 
+ /* Compute MD5 message digest for bytes read from STREAM.  The
+    resulting message digest number will be written into the 16 bytes
+    beginning at RESBLOCK.  */
+ extern int md5_stream __P ((FILE *stream, void *resblock));
+ 
+ /* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+    result is always in little endian byte order, so that a byte-wise
+    output yields to the wanted ASCII representation of the message
+    digest.  */
+ extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
+ 
+ #endif


More information about the Gcc-patches mailing list