]> gcc.gnu.org Git - gcc.git/commitdiff
[multiple changes]
authorJason Merrill <jason@redhat.com>
Tue, 29 Aug 2000 00:29:29 +0000 (20:29 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 29 Aug 2000 00:29:29 +0000 (20:29 -0400)
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.

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

        * cp-tree.h (LOCAL_CLASS_P): New macro.
        * class.c (finish_struct_1): Use it.

From-SVN: r36022

16 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/lex.c
gcc/dwarf2.h
gcc/dwarf2out.c
gcc/flags.h
gcc/toplev.c
gcc/toplev.h
gcc/tree.c
gcc/tree.h
include/ChangeLog
include/md5.h [new file with mode: 0644]
libiberty/ChangeLog
libiberty/Makefile.in
libiberty/md5.c [new file with mode: 0644]

index 8f0617f4fcb9e6493e7730fd515ab91f0849ae8b..c9224cfdd7640a8fee55be71751449de5133102c 100644 (file)
@@ -1,3 +1,10 @@
+2000-08-28  Jason Merrill  <jason@redhat.com>
+
+       * lex.c (file_name_nondirectory): Move to toplev.c.
+
+       * cp-tree.h (LOCAL_CLASS_P): New macro.
+       * class.c (finish_struct_1): Use it.
+
 2000-08-27  Alex Samuel  <samuel@codesourcery.com>
 
        * mangle.c (CLASSTYPE_TEMPLATE_ID_P): Remove unexplained voodoo.
index 2834154f3d829b419044e2b575d3154ce51b0a3b..dfbdc94a78b89b441b56ae4996efed73c0f4aaed 100644 (file)
@@ -5200,7 +5200,7 @@ finish_struct_1 (t)
   maybe_suppress_debug_info (t);
 
   /* Finish debugging output for this type.  */
-  rest_of_type_compilation (t, toplevel_bindings_p ());
+  rest_of_type_compilation (t, ! LOCAL_CLASS_P (t));
 }
 
 /* When T was built up, the member declarations were added in reverse
index aa77ab10a9a7c7e109c3fbc72db1867ea096b331..cc5046921f967426caa4e0e64fea2b25f1f8c623 100644 (file)
@@ -2224,6 +2224,11 @@ struct lang_decl
   (DECL_CONTEXT (NODE) \
    && TREE_CODE (DECL_CONTEXT (NODE)) == FUNCTION_DECL)
 
+/* 1 iff NODE is function-local, but for types.  */
+#define LOCAL_CLASS_P(NODE)                            \
+  (TYPE_CONTEXT (NODE)                                 \
+   && TREE_CODE (TYPE_CONTEXT (NODE)) == FUNCTION_DECL)
+
 /* For a NAMESPACE_DECL: the list of using namespace directives
    The PURPOSE is the used namespace, the value is the namespace
    that is the common ancestor. */
index 964bd569cf18fe83eb125b0c32730b94462b94b2..94679b4c718f8d69e41ada2e2eda9e3ef5c26bce 100644 (file)
@@ -96,21 +96,6 @@ static int is_extended_char PARAMS ((int));
 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;
index 2e2b9fe5b45b82920321302e876fcd9e0478d421..5b6082845475221ce0c7fba7e24aa5a8819b8191 100644 (file)
@@ -88,7 +88,9 @@ enum dwarf_tag
     /* 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_class_template = 0x4103,    /* for C++ */
+    DW_TAG_GNU_BINCL = 0x4104,
+    DW_TAG_GNU_EINCL = 0x4105
   };
 
 #define DW_TAG_lo_user 0x4080
index cc121e1283411bdba997d0130fa0a1c6d7a8dbfb..69e03955704abad964cddbf216d599792845332c 100644 (file)
@@ -23,9 +23,6 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
 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.
@@ -56,6 +53,7 @@ Boston, MA 02111-1307, USA.  */
 #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
@@ -303,6 +301,7 @@ static void def_cfa_1                       PARAMS ((const char *, dw_cfa_location *));
 #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,
@@ -2124,7 +2123,10 @@ typedef struct dw_val_struct
       long unsigned val_unsigned;
       dw_long_long_const val_long_long;
       dw_float_const val_float;
-      dw_die_ref val_die_ref;
+      struct {
+       dw_die_ref die;
+       int external;
+      } val_die_ref;
       unsigned val_fde_index;
       char *val_str;
       char *val_lbl_id;
@@ -2995,6 +2997,7 @@ dw_attr_node;
 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;
@@ -3338,20 +3341,38 @@ static void equate_decl_number_to_die   PARAMS ((tree, dw_die_ref));
 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));
@@ -3441,7 +3462,6 @@ static void gen_type_die_for_member       PARAMS ((tree, tree, dw_die_ref));
 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
@@ -3728,6 +3748,10 @@ dwarf_tag_name (tag)
       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>";
     }
@@ -4079,7 +4103,7 @@ decl_class_context (decl)
 }
 \f
 /* Add an attribute/value pair to a DIE.  We build the lists up in reverse
-   addition order, and correct that in add_sibling_attributes.  */
+   addition order, and correct that in reverse_all_dies.  */
 
 static inline void
 add_dwarf_attr (die, attr)
@@ -4264,7 +4288,8 @@ add_AT_die_ref (die, attr_kind, targ_die)
   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;
+  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);
 }
 
@@ -4274,11 +4299,34 @@ AT_ref (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;
+    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
@@ -4611,7 +4659,7 @@ remove_children (die)
 }
 
 /* Add a child DIE below its parent.  We build the lists up in reverse
-   addition order, and correct that in add_sibling_attributes.  */
+   addition order, and correct that in reverse_all_dies.  */
 
 static inline void
 add_child_die (die, child_die)
@@ -4677,6 +4725,7 @@ new_die (tag_value, parent_die)
   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);
@@ -4822,7 +4871,12 @@ print_die (die, outfile)
          break;
        case dw_val_class_die_ref:
          if (AT_ref (a) != NULL)
-           fprintf (outfile, "die -> %lu", AT_ref (a)->die_offset);
+           {
+             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;
@@ -4851,6 +4905,8 @@ print_die (die, outfile)
 
       print_indent -= 4;
     }
+  if (print_indent == 0)
+    fprintf (outfile, "\n");
 }
 
 /* Print the contents of the source code line number correspondence table.
@@ -4925,20 +4981,379 @@ reverse_die_lists (die)
   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.  */
+/* 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
-add_sibling_attributes (die)
+reverse_all_dies (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)
+  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;
+{
+#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);
 
@@ -4960,6 +5375,20 @@ build_abbrev_table (die)
   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];
@@ -5130,6 +5559,20 @@ calc_die_sizes (die)
     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.  */
 
@@ -5250,7 +5693,10 @@ value_format (a)
     case dw_val_class_flag:
       return DW_FORM_flag;
     case dw_val_class_die_ref:
-      return DW_FORM_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:
@@ -5333,6 +5779,39 @@ output_abbrev_section ()
   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.  */
 
@@ -5344,6 +5823,11 @@ output_die (die)
   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)",
@@ -5457,7 +5941,10 @@ output_die (die)
          break;
 
        case dw_val_class_die_ref:
-         ASM_OUTPUT_DWARF_DATA (asm_out_file, AT_ref (a)->die_offset);
+         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:
@@ -5547,6 +6034,44 @@ output_compilation_unit_header ()
   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.  */
@@ -5622,6 +6147,10 @@ output_pubnames ()
     {
       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);
@@ -5735,6 +6264,10 @@ output_aranges ()
     {
       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
@@ -10134,6 +10667,12 @@ void
 dwarf2out_start_source_file (filename)
      register const char *filename ATTRIBUTE_UNUSED;
 {
+  if (flag_eliminate_dwarf2_dups)
+    {
+      /* 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
@@ -10142,6 +10681,11 @@ dwarf2out_start_source_file (filename)
 void
 dwarf2out_end_source_file ()
 {
+  if (flag_eliminate_dwarf2_dups)
+    {
+      /* 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
@@ -10291,9 +10835,19 @@ dwarf2out_finish ()
      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.  */
+  /* 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);
@@ -10339,22 +10893,17 @@ dwarf2out_finish ()
     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);
-  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)
     {
       /* Output public names table.  */
index de5b099d6c03a220bdad66604331bad3bc25cfae..a294c37de200f10fac6803503eff7b7c99884242 100644 (file)
@@ -577,3 +577,7 @@ extern enum graph_dump_types graph_dump_format;
    string identifying the compiler.  */
 
 extern int flag_no_ident;
+
+/* Nonzero means we should do dwarf2 duplicate elimination.  */
+
+extern int flag_eliminate_dwarf2_dups;
index bbe752d730f38791a5bf7b985e16344768b6a1a1..0d5d4f21ee78f7a0424837b8e673445df6dd0c4a 100644 (file)
@@ -422,6 +422,10 @@ tree (*lang_expand_constant) PARAMS ((tree)) = 0;
 
 void (*incomplete_decl_finalize_hook) PARAMS ((tree)) = 0;
 
+/* Nonzero if doing dwarf2 duplicate elimination.  */
+
+int flag_eliminate_dwarf2_dups = 0;
+
 /* Nonzero if generating code to do profiling.  */
 
 int profile_flag = 0;
@@ -944,6 +948,8 @@ const char *user_label_prefix;
 
 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,
@@ -1656,6 +1662,21 @@ strip_off_ending (name, len)
     }
 }
 
+/* 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
@@ -2560,6 +2581,10 @@ rest_of_type_compilation (type, toplev)
 #ifdef SDB_DEBUGGING_INFO
   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);
 }
@@ -4973,8 +4998,7 @@ debug_start_source_file (filename)
     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)
+  if (write_symbols == DWARF2_DEBUG)
     dwarf2out_start_source_file (filename);
 #endif /* DWARF2_DEBUGGING_INFO  */
 #ifdef SDB_DEBUGGING_INFO
@@ -5000,8 +5024,7 @@ debug_end_source_file (lineno)
     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)
+  if (write_symbols == DWARF2_DEBUG)
     dwarf2out_end_source_file ();
 #endif /* DWARF2_DEBUGGING_INFO  */
 #ifdef SDB_DEBUGGING_INFO
index d61c5bfcf8d2c62fa5d94b408d9b9413414bfcee..fdfa6730b9396acf3d4fb413c4ab86b024293c2e 100644 (file)
@@ -35,6 +35,7 @@ extern int read_integral_parameter    PARAMS ((const char *, const char *,
                                                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 6ef5dd30ff0f1e4449d99cccbf4bd29b2c0b6d4b..23612b356055f8de2ff41df9e81dd6201f197b3e 100644 (file)
@@ -5386,6 +5386,26 @@ append_random_chars (template)
   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.  */
@@ -5431,19 +5451,7 @@ get_file_function_name_long (type)
 
   /* 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 = '_';
-    }
+    clean_symbol_name (buf + 11);
 
   return get_identifier (buf);
 }
index 067af986a267274f2e9b70ab1dfea1b3fb23ee28..80bb787b7c9a742ae503196435c0657a25065282 100644 (file)
@@ -2435,6 +2435,7 @@ extern tree builtin_function                      PARAMS ((const char *, tree, int,
 \f
 /* 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 b31a6550393b39bab9f6bc47ffb3a36929fe933a..6c68319a244386c640f6871e5322e370f9730952 100644 (file)
@@ -1,3 +1,7 @@
+2000-08-28  Jason Merrill  <jason@redhat.com>
+
+       * md5.h: New file.
+
 2000-08-24  Greg McGary  <greg@mcgary.org>
 
        * libiberty.h (ARRAY_SIZE): New macro.
diff --git a/include/md5.h b/include/md5.h
new file mode 100644 (file)
index 0000000..ad97efc
--- /dev/null
@@ -0,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
index 44ca8085351aa86a1aaa8e9743cfbec1573ea909..6849b0019e8aca14f69afc178d32c46bef5dbd2b 100644 (file)
@@ -1,3 +1,9 @@
+2000-08-28  Jason Merrill  <jason@redhat.com>
+
+       * Makefile.in (REQUIRED_OFILES): Add md5.o.
+       (CFILES): Add md5.c.
+       * md5.c: New file.
+
 2000-08-27  Alex Samuel  <samuel@codesourcery.com>
 
        * cp-demangle.c (demangle_name): Initialize template_p in local
index 242fde7841bb97d94d4cc6d823186d27c9a00200..c46d9dd1b56359763026a8d2db7f2791371eb90f 100644 (file)
@@ -128,7 +128,7 @@ CFILES = asprintf.c alloca.c argv.c atexit.c basename.c bcmp.c bcopy.c            \
        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      \
+       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  \
@@ -140,7 +140,7 @@ CFILES = asprintf.c alloca.c argv.c atexit.c basename.c bcmp.c bcopy.c            \
 # 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   \
+       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
diff --git a/libiberty/md5.c b/libiberty/md5.c
new file mode 100644 (file)
index 0000000..d742c54
--- /dev/null
@@ -0,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;
+}
This page took 0.131165 seconds and 5 git commands to generate.