[multiple changes]

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
This commit is contained in:
Jason Merrill 2000-08-28 20:29:29 -04:00 committed by Jason Merrill
parent 5de0e8d4e0
commit 881c6935bf
16 changed files with 1228 additions and 68 deletions

View 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.

View 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

View 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. */

View 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;

View 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

View 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)
}
/* 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,10 +4981,370 @@ 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
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;
{
#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)
@ -4936,9 +5352,8 @@ add_sibling_attributes (die)
{
register dw_die_ref c;
reverse_die_lists (die);
if (die != comp_unit_die && die->die_sib && die->die_child != NULL)
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. */

View 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;

View 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

View 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));

View 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);
}

View File

@ -2435,6 +2435,7 @@ extern tree builtin_function PARAMS ((const char *, tree, int,
/* 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));

View 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.

146
include/md5.h Normal file
View File

@ -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

View 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

View 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

419
libiberty/md5.c Normal file
View File

@ -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;
}