OSDN Git Service

* config/m68k/m68k.h (REGISTER_NAMES): Prefix each name with
[pf3gnuchains/gcc-fork.git] / gcc / coverage.c
index 5926a7e..6d6f3b8 100644 (file)
@@ -1,6 +1,6 @@
 /* Read and write coverage files, and associated functionality.
    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
-   2000, 2001, 2003  Free Software Foundation, Inc.
+   2000, 2001, 2003, 2004 Free Software Foundation, Inc.
    Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
    based on some ideas from Dain Samples of UC Berkeley.
    Further mangling by Bob Manson, Cygnus Support.
@@ -49,8 +49,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 struct function_list
 {
-  struct function_list *next;   /* next function */
-  unsigned ident;               /* function ident */
+  struct function_list *next;   /* next function */
+  unsigned ident;               /* function ident */
   unsigned checksum;            /* function checksum */
   unsigned n_ctrs[GCOV_COUNTERS];/* number of counters.  */
 };
@@ -61,7 +61,7 @@ typedef struct counts_entry
   /* We hash by  */
   unsigned ident;
   unsigned ctr;
-  
+
   /* Store  */
   unsigned checksum;
   gcov_type *counts;
@@ -69,7 +69,7 @@ typedef struct counts_entry
 
   /* Workspace */
   struct counts_entry *chain;
-  
+
 } counts_entry_t;
 
 static struct function_list *functions_head = 0;
@@ -81,7 +81,7 @@ static unsigned prg_ctr_mask; /* Mask of counter types generated.  */
 static unsigned prg_n_ctrs[GCOV_COUNTERS]; /* Total counters allocated.  */
 
 /* Counter information for current function.  */
-static unsigned fn_ctr_mask; /* Mask of counters used. */
+static unsigned fn_ctr_mask; /* Mask of counters used.  */
 static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated.  */
 static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base.  */
 
@@ -104,23 +104,22 @@ static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIO
 static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
 
 /* Forward declarations.  */
-static hashval_t htab_counts_entry_hash PARAMS ((const void *));
-static int htab_counts_entry_eq PARAMS ((const void *, const void *));
-static void htab_counts_entry_del PARAMS ((void *));
-static void read_counts_file PARAMS ((void));
-static unsigned compute_checksum PARAMS ((void));
-static unsigned checksum_string PARAMS ((unsigned, const char *));
-static tree build_fn_info_type PARAMS ((unsigned));
-static tree build_fn_info_value PARAMS ((const struct function_list *, tree));
-static tree build_ctr_info_type PARAMS ((void));
-static tree build_ctr_info_value PARAMS ((unsigned, tree));
-static tree build_gcov_info PARAMS ((void));
-static void create_coverage PARAMS ((void));
+static hashval_t htab_counts_entry_hash (const void *);
+static int htab_counts_entry_eq (const void *, const void *);
+static void htab_counts_entry_del (void *);
+static void read_counts_file (void);
+static unsigned compute_checksum (void);
+static unsigned coverage_checksum_string (unsigned, const char *);
+static tree build_fn_info_type (unsigned);
+static tree build_fn_info_value (const struct function_list *, tree);
+static tree build_ctr_info_type (void);
+static tree build_ctr_info_value (unsigned, tree);
+static tree build_gcov_info (void);
+static void create_coverage (void);
 
 \f
 static hashval_t
-htab_counts_entry_hash (of)
-     const void *of;
+htab_counts_entry_hash (const void *of)
 {
   const counts_entry_t *entry = of;
 
@@ -128,9 +127,7 @@ htab_counts_entry_hash (of)
 }
 
 static int
-htab_counts_entry_eq (of1, of2)
-     const void *of1;
-     const void *of2;
+htab_counts_entry_eq (const void *of1, const void *of2)
 {
   const counts_entry_t *entry1 = of1;
   const counts_entry_t *entry2 = of2;
@@ -139,8 +136,7 @@ htab_counts_entry_eq (of1, of2)
 }
 
 static void
-htab_counts_entry_del (of)
-     void *of;
+htab_counts_entry_del (void *of)
 {
   counts_entry_t *entry = of;
 
@@ -151,49 +147,48 @@ htab_counts_entry_del (of)
 /* Read in the counts file, if available.  */
 
 static void
-read_counts_file ()
+read_counts_file (void)
 {
   gcov_unsigned_t fn_ident = 0;
-  gcov_unsigned_t version, checksum = -1;
-  unsigned ix;
+  gcov_unsigned_t checksum = -1;
   counts_entry_t *summaried = NULL;
   unsigned seen_summary = 0;
-  
+  gcov_unsigned_t tag;
+  int is_error = 0;
+
   if (!gcov_open (da_file_name, 1))
     return;
-  
-  if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
+
+  if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
     {
       warning ("`%s' is not a gcov data file", da_file_name);
       gcov_close ();
       return;
     }
-  else if ((version = gcov_read_unsigned ()) != GCOV_VERSION)
+  else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
     {
       char v[4], e[4];
-      gcov_unsigned_t required = GCOV_VERSION;
-      
-      for (ix = 4; ix--; required >>= 8, version >>= 8)
-       {
-         v[ix] = version;
-         e[ix] = required;
-       }
+
+      GCOV_UNSIGNED2STRING (v, tag);
+      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
+
       warning ("`%s' is version `%.4s', expected version `%.4s'",
-              da_file_name, v, e);
+              da_file_name, v, e);
       gcov_close ();
       return;
     }
+
+  /* Read and discard the stamp.  */
+  gcov_read_unsigned ();
   
   counts_hash = htab_create (10,
                             htab_counts_entry_hash, htab_counts_entry_eq,
                             htab_counts_entry_del);
-  while (!gcov_is_eof ())
+  while ((tag = gcov_read_unsigned ()))
     {
-      gcov_unsigned_t tag, length;
+      gcov_unsigned_t length;
       gcov_position_t offset;
-      int error;
-      
-      tag = gcov_read_unsigned ();
+
       length = gcov_read_unsigned ();
       offset = gcov_position ();
       if (tag == GCOV_TAG_FUNCTION)
@@ -206,7 +201,7 @@ read_counts_file ()
                 new function begins a new set of program runs. We
                 must unlink the summaried chain.  */
              counts_entry_t *entry, *chain;
-             
+
              for (entry = summaried; entry; entry = chain)
                {
                  chain = entry->chain;
@@ -220,13 +215,13 @@ read_counts_file ()
        {
          counts_entry_t *entry;
          struct gcov_summary summary;
-         
+
          gcov_read_summary (&summary);
          seen_summary = 1;
          for (entry = summaried; entry; entry = entry->chain)
            {
              struct gcov_ctr_summary *csum = &summary.ctrs[entry->ctr];
-             
+
              entry->summary.runs += csum->runs;
              entry->summary.sum_all += csum->sum_all;
              if (entry->summary.run_max < csum->run_max)
@@ -237,7 +232,7 @@ read_counts_file ()
       else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
        {
          counts_entry_t **slot, *entry, elt;
-         unsigned n_counts = length / 8;
+         unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
          unsigned ix;
 
          elt.ident = fn_ident;
@@ -255,24 +250,33 @@ read_counts_file ()
              entry->summary.num = n_counts;
              entry->counts = xcalloc (n_counts, sizeof (gcov_type));
            }
-         else if (entry->checksum != checksum
-                  || entry->summary.num != n_counts)
+         else if (entry->checksum != checksum)
+           {
+             error ("coverage mismatch for function %u while reading execution counters.",
+                    fn_ident);
+             error ("checksum is %x instead of %x", entry->checksum, checksum);
+             htab_delete (counts_hash);
+             break;
+           }
+         else if (entry->summary.num != n_counts)
            {
-             warning ("coverage mismatch for function %u", fn_ident);
+             error ("coverage mismatch for function %u while reading execution counters.",
+                    fn_ident);
+             error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
              htab_delete (counts_hash);
              break;
            }
          else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
            {
-             warning ("cannot merge separate %s counters for function %u",
-                      ctr_names[elt.ctr], fn_ident);
+             error ("cannot merge separate %s counters for function %u",
+                    ctr_names[elt.ctr], fn_ident);
              goto skip_merge;
            }
 
          if (elt.ctr < GCOV_COUNTERS_SUMMABLE
              /* This should always be true for a just allocated entry,
-                and always false for an existing one. Check this way, in
-                case the gcov file is corrupt.  */
+                and always false for an existing one. Check this way, in
+                case the gcov file is corrupt.  */
              && (!entry->chain || summaried != entry))
            {
              entry->chain = summaried;
@@ -283,13 +287,15 @@ read_counts_file ()
        skip_merge:;
        }
       gcov_sync (offset, length);
-      if ((error = gcov_is_error ()))
-       {
-         warning (error < 0 ? "`%s' has overflowed" : "`%s' is corrupted",
-                  da_file_name);
-         htab_delete (counts_hash);
-         break;
-       }
+      if ((is_error = gcov_is_error ()))
+       break;
+    }
+
+  if (!gcov_is_eof ())
+    {
+      error (is_error < 0 ? "`%s' has overflowed" : "`%s' is corrupted",
+            da_file_name);
+      htab_delete (counts_hash);
     }
 
   gcov_close ();
@@ -302,15 +308,18 @@ get_coverage_counts (unsigned counter, unsigned expected,
                     const struct gcov_ctr_summary **summary)
 {
   counts_entry_t *entry, elt;
+  gcov_unsigned_t checksum = -1;
 
-  /* No hash table, no counts. */
+  /* No hash table, no counts.  */
   if (!counts_hash)
     {
       static int warned = 0;
 
       if (!warned++)
-       warning ("file %s not found, execution counts assumed to be zero",
-                da_file_name);
+       inform ((flag_guess_branch_prob
+                ? "file %s not found, execution counts estimated"
+                : "file %s not found, execution counts assumed to be zero"),
+               da_file_name);
       return NULL;
     }
 
@@ -323,22 +332,32 @@ get_coverage_counts (unsigned counter, unsigned expected,
               (DECL_ASSEMBLER_NAME (current_function_decl)));
       return 0;
     }
-  
-  if (expected != entry->summary.num
-      || compute_checksum () != entry->checksum)
+
+  checksum = compute_checksum ();
+  if (entry->checksum != checksum)
     {
-      warning ("coverage mismatch for `%s'", IDENTIFIER_POINTER
-              (DECL_ASSEMBLER_NAME (current_function_decl)));
-      return NULL;
+      error ("coverage mismatch for function '%s' while reading counter '%s'.",
+            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
+            ctr_names[counter]);
+      error ("checksum is %x instead of %x", entry->checksum, checksum);
+      return 0;
     }
-  
+  else if (entry->summary.num != expected)
+    {
+      error ("coverage mismatch for function '%s' while reading counter '%s'.",
+            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
+            ctr_names[counter]);
+      error ("number of counters is %d instead of %d", entry->summary.num, expected);
+      return 0;
+    }
+
   if (summary)
     *summary = &entry->summary;
 
   return entry->counts;
 }
 
-/* Allocate NUM counters of type COUNTER. Returns non-zero if the
+/* Allocate NUM counters of type COUNTER. Returns nonzero if the
    allocation succeeded.  */
 
 int
@@ -346,17 +365,18 @@ coverage_counter_alloc (unsigned counter, unsigned num)
 {
   if (no_coverage)
     return 0;
-  
+
   if (!num)
     return 1;
-  
+
   if (!ctr_labels[counter])
     {
       /* Generate and save a copy of this so it can be shared.  */
       char buf[20];
-      
+
       ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1);
       ctr_labels[counter] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+      SYMBOL_REF_FLAGS (ctr_labels[counter]) = SYMBOL_FLAG_LOCAL;
     }
   fn_b_ctrs[counter] = fn_n_ctrs[counter];
   fn_n_ctrs[counter] += num;
@@ -384,39 +404,68 @@ coverage_counter_ref (unsigned counter, unsigned no)
 }
 \f
 /* Generate a checksum for a string.  CHKSUM is the current
-   checksum. */
+   checksum.  */
 
 static unsigned
-checksum_string (unsigned chksum, const char *string)
+coverage_checksum_string (unsigned chksum, const char *string)
 {
-  do
+  int i;
+  char *dup = NULL;
+
+  /* Look for everything that looks if it were produced by
+     get_file_function_name_long and zero out the second part
+     that may result from flag_random_seed.  This is not critical
+     as the checksums are used only for sanity checking.  */
+  for (i = 0; string[i]; i++)
     {
-      unsigned value = *string << 24;
-      unsigned ix;
-
-      for (ix = 8; ix--; value <<= 1)
-       {
-         unsigned feedback;
-         
-         feedback = (value ^ chksum) & 0x80000000 ? 0x04c11db7 : 0;
-         chksum <<= 1;
-         chksum ^= feedback;
-       }
+      if (!strncmp (string + i, "_GLOBAL__", 9))
+       for (i = i + 9; string[i]; i++)
+         if (string[i]=='_')
+           {
+             int y;
+             unsigned seed;
+
+             for (y = 1; y < 9; y++)
+               if (!(string[i + y] >= '0' && string[i + y] <= '9')
+                   && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
+                 break;
+             if (y != 9 || string[i + 9] != '_')
+               continue;
+             for (y = 10; y < 18; y++)
+               if (!(string[i + y] >= '0' && string[i + y] <= '9')
+                   && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
+                 break;
+             if (y != 18)
+               continue;
+             if (!sscanf (string + i + 10, "%X", &seed))
+               abort ();
+             if (seed != crc32_string (0, flag_random_seed))
+               continue;
+             string = dup = xstrdup (string);
+             for (y = 10; y < 18; y++)
+               dup[i + y] = '0';
+             break;
+           }
+      break;
     }
-  while (*string++);
-  
+
+  chksum = crc32_string (chksum, string);
+  if (dup)
+    free (dup);
+
   return chksum;
 }
 
 /* Compute checksum for the current function.  We generate a CRC32.  */
 
 static unsigned
-compute_checksum ()
+compute_checksum (void)
 {
   unsigned chksum = DECL_SOURCE_LINE (current_function_decl);
 
-  chksum = checksum_string (chksum, DECL_SOURCE_FILE (current_function_decl));
-  chksum = checksum_string
+  chksum = coverage_checksum_string (chksum,
+                                    DECL_SOURCE_FILE (current_function_decl));
+  chksum = coverage_checksum_string
     (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
 
   return chksum;
@@ -424,33 +473,34 @@ compute_checksum ()
 \f
 /* Begin output to the graph file for the current function.
    Opens the output file, if not already done. Writes the
-   function header, if not already done. Returns non-zero if data
+   function header, if not already done. Returns nonzero if data
    should be output.  */
 
 int
-coverage_begin_output ()
+coverage_begin_output (void)
 {
   if (no_coverage)
     return 0;
-  
+
   if (!bbg_function_announced)
     {
       const char *file = DECL_SOURCE_FILE (current_function_decl);
       unsigned line = DECL_SOURCE_LINE (current_function_decl);
       unsigned long offset;
-      
+
       if (!bbg_file_opened)
        {
          if (!gcov_open (bbg_file_name, -1))
            error ("cannot open %s", bbg_file_name);
          else
            {
-             gcov_write_unsigned (GCOV_GRAPH_MAGIC);
+             gcov_write_unsigned (GCOV_NOTE_MAGIC);
              gcov_write_unsigned (GCOV_VERSION);
+             gcov_write_unsigned (local_tick);
            }
          bbg_file_opened = 1;
        }
-      
+
       /* Announce function */
       offset = gcov_write_tag (GCOV_TAG_FUNCTION);
       gcov_write_unsigned (current_function_funcdef_no + 1);
@@ -470,12 +520,12 @@ coverage_begin_output ()
    error has occurred.  Save function coverage counts.  */
 
 void
-coverage_end_function ()
+coverage_end_function (void)
 {
   unsigned i;
-  
+
   if (bbg_file_opened > 1 && gcov_is_error ())
-    {  
+    {
       warning ("error writing `%s'", bbg_file_name);
       bbg_file_opened = -1;
     }
@@ -483,12 +533,12 @@ coverage_end_function ()
   if (fn_ctr_mask)
     {
       struct function_list *item;
-      
+
       item = xmalloc (sizeof (struct function_list));
-      
+
       *functions_tail = item;
       functions_tail = &item->next;
-       
+
       item->next = 0;
       item->ident = current_function_funcdef_no + 1;
       item->checksum = compute_checksum ();
@@ -507,13 +557,12 @@ coverage_end_function ()
 /* Creates the gcov_fn_info RECORD_TYPE.  */
 
 static tree
-build_fn_info_type (counters)
-     unsigned counters;
+build_fn_info_type (unsigned int counters)
 {
   tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
   tree field, fields;
   tree array_type;
-  
+
   /* ident */
   fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
 
@@ -524,7 +573,7 @@ build_fn_info_type (counters)
 
   array_type = build_index_type (build_int_2 (counters - 1, 0));
   array_type = build_array_type (unsigned_type_node, array_type);
-  
+
   /* counters */
   field = build_decl (FIELD_DECL, NULL_TREE, array_type);
   TREE_CHAIN (field) = fields;
@@ -540,51 +589,49 @@ build_fn_info_type (counters)
    RECORD_TYPE.  */
 
 static tree
-build_fn_info_value (function, type)
-     const struct function_list *function;
-     tree type;
+build_fn_info_value (const struct function_list *function, tree type)
 {
   tree value = NULL_TREE;
   tree fields = TYPE_FIELDS (type);
   unsigned ix;
   tree array_value = NULL_TREE;
-  
+
   /* ident */
   value = tree_cons (fields,
                     convert (unsigned_intSI_type_node,
                              build_int_2 (function->ident, 0)),
                     value);
   fields = TREE_CHAIN (fields);
-  
+
   /* checksum */
   value = tree_cons (fields,
                     convert (unsigned_intSI_type_node,
                              build_int_2 (function->checksum, 0)),
                     value);
   fields = TREE_CHAIN (fields);
-  
+
   /* counters */
   for (ix = 0; ix != GCOV_COUNTERS; ix++)
     if (prg_ctr_mask & (1 << ix))
       {
        tree counters = convert (unsigned_type_node,
                                 build_int_2 (function->n_ctrs[ix], 0));
-       
+
        array_value = tree_cons (NULL_TREE, counters, array_value);
       }
-  
+
   array_value = build_constructor (TREE_TYPE (fields), nreverse (array_value));
   value = tree_cons (fields, array_value, value);
 
   value = build_constructor (type, nreverse (value));
-  
+
   return value;
 }
 
 /* Creates the gcov_ctr_info RECORD_TYPE.  */
 
 static tree
-build_ctr_info_type ()
+build_ctr_info_type (void)
 {
   tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
   tree field, fields = NULL_TREE;
@@ -621,9 +668,7 @@ build_ctr_info_type ()
    RECORD_TYPE.  */
 
 static tree
-build_ctr_info_value (counter, type)
-     unsigned counter;
-     tree type;
+build_ctr_info_value (unsigned int counter, tree type)
 {
   tree value = NULL_TREE;
   tree fields = TYPE_FIELDS (type);
@@ -639,16 +684,16 @@ build_ctr_info_value (counter, type)
   if (prg_n_ctrs[counter])
     {
       tree array_type, array;
-      
+
       array_type = build_index_type (build_int_2 (prg_n_ctrs[counter] - 1, 0));
       array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
                                     array_type);
-      
-      array = build (VAR_DECL, array_type, NULL_TREE, NULL_TREE);
+
+      array = build_decl (VAR_DECL, NULL_TREE, array_type);
       TREE_STATIC (array) = 1;
       DECL_NAME (array) = get_identifier (XSTR (ctr_labels[counter], 0));
       assemble_variable (array, 0, 0, 0);
-      
+
       value = tree_cons (fields,
                         build1 (ADDR_EXPR, TREE_TYPE (fields), array),
                         value);
@@ -669,7 +714,7 @@ build_ctr_info_value (counter, type)
                     value);
 
   value = build_constructor (type, nreverse (value));
-  
+
   return value;
 }
 
@@ -677,7 +722,7 @@ build_ctr_info_value (counter, type)
    CONSTRUCTOR.  */
 
 static tree
-build_gcov_info ()
+build_gcov_info (void)
 {
   unsigned n_ctr_types, ix;
   tree type, const_type;
@@ -692,15 +737,15 @@ build_gcov_info ()
   unsigned n_fns;
   const struct function_list *fn;
   tree string_type;
-  
+
   /* Count the number of active counters.  */
   for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++)
     if (prg_ctr_mask & (1 << ix))
       n_ctr_types++;
-  
+
   type = (*lang_hooks.types.make_type) (RECORD_TYPE);
   const_type = build_qualified_type (type, TYPE_QUAL_CONST);
-  
+
   /* Version ident */
   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
   TREE_CHAIN (field) = fields;
@@ -708,13 +753,21 @@ build_gcov_info ()
   value = tree_cons (field, convert (unsigned_intSI_type_node,
                                     build_int_2 (GCOV_VERSION, 0)),
                     value);
-  
+
   /* next -- NULL */
   field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type));
   TREE_CHAIN (field) = fields;
   fields = field;
   value = tree_cons (field, null_pointer_node, value);
-  
+
+  /* stamp */
+  field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
+  TREE_CHAIN (field) = fields;
+  fields = field;
+  value = tree_cons (field, convert (unsigned_intSI_type_node,
+                                    build_int_2 (local_tick, 0)),
+                    value);
+
   /* Filename */
   string_type = build_pointer_type (build_qualified_type (char_type_node,
                                                    TYPE_QUAL_CONST));
@@ -734,7 +787,7 @@ build_gcov_info ()
                            build_index_type (build_int_2 (filename_len, 0)));
   value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string),
                     value);
-  
+
   /* Build the fn_info type and initializer.  */
   fn_info_type = build_fn_info_type (n_ctr_types);
   fn_info_ptr_type = build_pointer_type (build_qualified_type
@@ -749,13 +802,13 @@ build_gcov_info ()
 
       array_type = build_index_type (build_int_2 (n_fns - 1, 0));
       array_type = build_array_type (fn_info_type, array_type);
-      
+
       fn_info_value = build_constructor (array_type, nreverse (fn_info_value));
       fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
     }
   else
     fn_info_value = null_pointer_node;
-  
+
   /* number of functions */
   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
   TREE_CHAIN (field) = fields;
@@ -763,7 +816,7 @@ build_gcov_info ()
   value = tree_cons (field,
                     convert (unsigned_type_node, build_int_2 (n_fns, 0)),
                     value);
-  
+
   /* fn_info table */
   field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type);
   TREE_CHAIN (field) = fields;
@@ -778,7 +831,7 @@ build_gcov_info ()
                     convert (unsigned_type_node,
                              build_int_2 (prg_ctr_mask, 0)),
                     value);
-  
+
   /* counters */
   ctr_info_type = build_ctr_info_type ();
   ctr_info_ary_type = build_index_type (build_int_2 (n_ctr_types, 0));
@@ -795,11 +848,11 @@ build_gcov_info ()
   TREE_CHAIN (field) = fields;
   fields = field;
   value = tree_cons (field, ctr_info_value, value);
-  
+
   finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
 
   value = build_constructor (type, nreverse (value));
-  
+
   return value;
 }
 
@@ -808,7 +861,7 @@ build_gcov_info ()
    gcov-io.h.  Write out the constructor to call __gcov_init.  */
 
 static void
-create_coverage ()
+create_coverage (void)
 {
   tree gcov_info, gcov_info_value;
   char name[20];
@@ -817,20 +870,19 @@ create_coverage ()
   rtx gcov_info_address;
 
   no_coverage = 1; /* Disable any further coverage.  */
-  
+
   if (!prg_ctr_mask)
     return;
-  
+
   gcov_info_value = build_gcov_info ();
 
-  gcov_info = build (VAR_DECL, TREE_TYPE (gcov_info_value),
-                    NULL_TREE, NULL_TREE);
+  gcov_info = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (gcov_info_value));
   DECL_INITIAL (gcov_info) = gcov_info_value;
 
   TREE_STATIC (gcov_info) = 1;
   ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
   DECL_NAME (gcov_info) = get_identifier (name);
-  
+
   /* Build structure.  */
   assemble_variable (gcov_info, 0, 0, 0);
 
@@ -853,19 +905,18 @@ create_coverage ()
   rest_of_decl_compilation (ctor, 0, 1, 0);
   announce_function (ctor);
   current_function_decl = ctor;
-  DECL_INITIAL (ctor) = error_mark_node;
   make_decl_rtl (ctor, NULL);
-  init_function_start (ctor, input_filename, input_line);
-  (*lang_hooks.decls.pushlevel) (0);
+  init_function_start (ctor);
   expand_function_start (ctor, 0);
-
   /* Actually generate the code to call __gcov_init.  */
   gcov_info_address = force_reg (Pmode, XEXP (DECL_RTL (gcov_info), 0));
   emit_library_call (gcov_init_libfunc, LCT_NORMAL, VOIDmode, 1,
                     gcov_info_address, Pmode);
 
-  expand_function_end (input_filename, input_line, 0);
-  (*lang_hooks.decls.poplevel) (1, 0, 1);
+  expand_function_end ();
+  /* Create a dummy BLOCK.  */
+  DECL_INITIAL (ctor) = make_node (BLOCK);
+  TREE_USED (DECL_INITIAL (ctor)) = 1;
 
   rest_of_compilation (ctor);
 
@@ -879,23 +930,22 @@ create_coverage ()
 }
 \f
 /* Perform file-level initialization. Read in data file, generate name
-   of graph file. */
+   of graph file.  */
 
 void
-coverage_init (filename)
-  const char *filename;
+coverage_init (const char *filename)
 {
   int len = strlen (filename);
 
   /* Name of da file.  */
-  da_file_name = (char *) xmalloc (len + strlen (GCOV_DATA_SUFFIX) + 1);
+  da_file_name = xmalloc (len + strlen (GCOV_DATA_SUFFIX) + 1);
   strcpy (da_file_name, filename);
   strcat (da_file_name, GCOV_DATA_SUFFIX);
-  
+
   /* Name of bbg file.  */
-  bbg_file_name = (char *) xmalloc (len + strlen (GCOV_GRAPH_SUFFIX) + 1);
+  bbg_file_name = xmalloc (len + strlen (GCOV_NOTE_SUFFIX) + 1);
   strcpy (bbg_file_name, filename);
-  strcat (bbg_file_name, GCOV_GRAPH_SUFFIX);
+  strcat (bbg_file_name, GCOV_NOTE_SUFFIX);
 
   read_counts_file ();
 }
@@ -904,22 +954,18 @@ coverage_init (filename)
    variables and constructor.  */
 
 void
-coverage_finish ()
+coverage_finish (void)
 {
   create_coverage ();
   if (bbg_file_opened)
     {
       int error = gcov_close ();
-      
+
       if (error)
        unlink (bbg_file_name);
-#if SELF_COVERAGE
-      /* If the compiler is instrumented, we should not
-         unconditionally remove the counts file, because we might be
-         recompiling ourselves. The .da files are all removed during
-         copying the stage1 files.  */
-      if (error)
-#endif
+      if (!local_tick)
+       /* Only remove the da file, if we cannot stamp it. If we can
+          stamp it, libgcov will DTRT.  */
        unlink (da_file_name);
     }
 }