1132718Skan/* Read and write coverage files, and associated functionality.
2132718Skan   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
3169689Skan   2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
4132718Skan   Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
5132718Skan   based on some ideas from Dain Samples of UC Berkeley.
6132718Skan   Further mangling by Bob Manson, Cygnus Support.
7132718Skan   Further mangled by Nathan Sidwell, CodeSourcery
8132718Skan
9132718SkanThis file is part of GCC.
10132718Skan
11132718SkanGCC is free software; you can redistribute it and/or modify it under
12132718Skanthe terms of the GNU General Public License as published by the Free
13132718SkanSoftware Foundation; either version 2, or (at your option) any later
14132718Skanversion.
15132718Skan
16132718SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
17132718SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
18132718SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19132718Skanfor more details.
20132718Skan
21132718SkanYou should have received a copy of the GNU General Public License
22132718Skanalong with GCC; see the file COPYING.  If not, write to the Free
23169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
24169689Skan02110-1301, USA.  */
25132718Skan
26132718Skan
27132718Skan#define GCOV_LINKAGE
28132718Skan
29132718Skan#include "config.h"
30132718Skan#include "system.h"
31132718Skan#include "coretypes.h"
32132718Skan#include "tm.h"
33132718Skan#include "rtl.h"
34132718Skan#include "tree.h"
35132718Skan#include "flags.h"
36132718Skan#include "output.h"
37132718Skan#include "regs.h"
38132718Skan#include "expr.h"
39132718Skan#include "function.h"
40132718Skan#include "toplev.h"
41132718Skan#include "ggc.h"
42132718Skan#include "coverage.h"
43132718Skan#include "langhooks.h"
44132718Skan#include "hashtab.h"
45169689Skan#include "tree-iterator.h"
46169689Skan#include "cgraph.h"
47132718Skan
48132718Skan#include "gcov-io.c"
49132718Skan
50132718Skanstruct function_list
51132718Skan{
52132718Skan  struct function_list *next;	 /* next function */
53132718Skan  unsigned ident;		 /* function ident */
54132718Skan  unsigned checksum;	         /* function checksum */
55132718Skan  unsigned n_ctrs[GCOV_COUNTERS];/* number of counters.  */
56132718Skan};
57132718Skan
58132718Skan/* Counts information for a function.  */
59132718Skantypedef struct counts_entry
60132718Skan{
61132718Skan  /* We hash by  */
62132718Skan  unsigned ident;
63132718Skan  unsigned ctr;
64132718Skan
65132718Skan  /* Store  */
66132718Skan  unsigned checksum;
67132718Skan  gcov_type *counts;
68132718Skan  struct gcov_ctr_summary summary;
69132718Skan
70132718Skan  /* Workspace */
71132718Skan  struct counts_entry *chain;
72132718Skan
73132718Skan} counts_entry_t;
74132718Skan
75132718Skanstatic struct function_list *functions_head = 0;
76132718Skanstatic struct function_list **functions_tail = &functions_head;
77132718Skanstatic unsigned no_coverage = 0;
78132718Skan
79132718Skan/* Cumulative counter information for whole program.  */
80132718Skanstatic unsigned prg_ctr_mask; /* Mask of counter types generated.  */
81132718Skanstatic unsigned prg_n_ctrs[GCOV_COUNTERS]; /* Total counters allocated.  */
82132718Skan
83132718Skan/* Counter information for current function.  */
84132718Skanstatic unsigned fn_ctr_mask; /* Mask of counters used.  */
85132718Skanstatic unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated.  */
86132718Skanstatic unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base.  */
87132718Skan
88132718Skan/* Name of the output file for coverage output file.  */
89132718Skanstatic char *bbg_file_name;
90132718Skanstatic unsigned bbg_file_opened;
91132718Skanstatic int bbg_function_announced;
92132718Skan
93132718Skan/* Name of the count data file.  */
94132718Skanstatic char *da_file_name;
95132718Skan
96132718Skan/* Hash table of count data.  */
97132718Skanstatic htab_t counts_hash = NULL;
98132718Skan
99169689Skan/* Trees representing the counter table arrays.  */
100169689Skanstatic GTY(()) tree tree_ctr_tables[GCOV_COUNTERS];
101169689Skan
102169689Skan/* The names of the counter tables.  Not used if we're
103169689Skan   generating counters at tree level.  */
104132718Skanstatic GTY(()) rtx ctr_labels[GCOV_COUNTERS];
105132718Skan
106132718Skan/* The names of merge functions for counters.  */
107132718Skanstatic const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
108132718Skanstatic const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
109132718Skan
110132718Skan/* Forward declarations.  */
111132718Skanstatic hashval_t htab_counts_entry_hash (const void *);
112132718Skanstatic int htab_counts_entry_eq (const void *, const void *);
113132718Skanstatic void htab_counts_entry_del (void *);
114132718Skanstatic void read_counts_file (void);
115132718Skanstatic unsigned compute_checksum (void);
116132718Skanstatic unsigned coverage_checksum_string (unsigned, const char *);
117132718Skanstatic tree build_fn_info_type (unsigned);
118132718Skanstatic tree build_fn_info_value (const struct function_list *, tree);
119132718Skanstatic tree build_ctr_info_type (void);
120132718Skanstatic tree build_ctr_info_value (unsigned, tree);
121132718Skanstatic tree build_gcov_info (void);
122132718Skanstatic void create_coverage (void);
123169689Skan
124169689Skan/* Return the type node for gcov_type.  */
125132718Skan
126169689Skantree
127169689Skanget_gcov_type (void)
128169689Skan{
129169689Skan  return lang_hooks.types.type_for_size (GCOV_TYPE_SIZE, false);
130169689Skan}
131169689Skan
132169689Skan/* Return the type node for gcov_unsigned_t.  */
133169689Skan
134169689Skanstatic tree
135169689Skanget_gcov_unsigned_t (void)
136169689Skan{
137169689Skan  return lang_hooks.types.type_for_size (32, true);
138169689Skan}
139132718Skan
140132718Skanstatic hashval_t
141132718Skanhtab_counts_entry_hash (const void *of)
142132718Skan{
143132718Skan  const counts_entry_t *entry = of;
144132718Skan
145132718Skan  return entry->ident * GCOV_COUNTERS + entry->ctr;
146132718Skan}
147132718Skan
148132718Skanstatic int
149132718Skanhtab_counts_entry_eq (const void *of1, const void *of2)
150132718Skan{
151132718Skan  const counts_entry_t *entry1 = of1;
152132718Skan  const counts_entry_t *entry2 = of2;
153132718Skan
154132718Skan  return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
155132718Skan}
156132718Skan
157132718Skanstatic void
158132718Skanhtab_counts_entry_del (void *of)
159132718Skan{
160132718Skan  counts_entry_t *entry = of;
161132718Skan
162132718Skan  free (entry->counts);
163132718Skan  free (entry);
164132718Skan}
165132718Skan
166132718Skan/* Read in the counts file, if available.  */
167132718Skan
168132718Skanstatic void
169132718Skanread_counts_file (void)
170132718Skan{
171132718Skan  gcov_unsigned_t fn_ident = 0;
172132718Skan  gcov_unsigned_t checksum = -1;
173132718Skan  counts_entry_t *summaried = NULL;
174132718Skan  unsigned seen_summary = 0;
175132718Skan  gcov_unsigned_t tag;
176132718Skan  int is_error = 0;
177132718Skan
178132718Skan  if (!gcov_open (da_file_name, 1))
179132718Skan    return;
180132718Skan
181132718Skan  if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
182132718Skan    {
183169689Skan      warning (0, "%qs is not a gcov data file", da_file_name);
184132718Skan      gcov_close ();
185132718Skan      return;
186132718Skan    }
187132718Skan  else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
188132718Skan    {
189132718Skan      char v[4], e[4];
190132718Skan
191132718Skan      GCOV_UNSIGNED2STRING (v, tag);
192132718Skan      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
193132718Skan
194169689Skan      warning (0, "%qs is version %q.*s, expected version %q.*s",
195161651Skan 	       da_file_name, 4, v, 4, e);
196132718Skan      gcov_close ();
197132718Skan      return;
198132718Skan    }
199132718Skan
200132718Skan  /* Read and discard the stamp.  */
201132718Skan  gcov_read_unsigned ();
202132718Skan
203132718Skan  counts_hash = htab_create (10,
204132718Skan			     htab_counts_entry_hash, htab_counts_entry_eq,
205132718Skan			     htab_counts_entry_del);
206132718Skan  while ((tag = gcov_read_unsigned ()))
207132718Skan    {
208132718Skan      gcov_unsigned_t length;
209132718Skan      gcov_position_t offset;
210132718Skan
211132718Skan      length = gcov_read_unsigned ();
212132718Skan      offset = gcov_position ();
213132718Skan      if (tag == GCOV_TAG_FUNCTION)
214132718Skan	{
215132718Skan	  fn_ident = gcov_read_unsigned ();
216132718Skan	  checksum = gcov_read_unsigned ();
217132718Skan	  if (seen_summary)
218132718Skan	    {
219132718Skan	      /* We have already seen a summary, this means that this
220132718Skan		 new function begins a new set of program runs. We
221132718Skan		 must unlink the summaried chain.  */
222132718Skan	      counts_entry_t *entry, *chain;
223132718Skan
224132718Skan	      for (entry = summaried; entry; entry = chain)
225132718Skan		{
226132718Skan		  chain = entry->chain;
227132718Skan		  entry->chain = NULL;
228132718Skan		}
229132718Skan	      summaried = NULL;
230132718Skan	      seen_summary = 0;
231132718Skan	    }
232132718Skan	}
233132718Skan      else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
234132718Skan	{
235132718Skan	  counts_entry_t *entry;
236132718Skan	  struct gcov_summary summary;
237132718Skan
238132718Skan	  gcov_read_summary (&summary);
239132718Skan	  seen_summary = 1;
240132718Skan	  for (entry = summaried; entry; entry = entry->chain)
241132718Skan	    {
242132718Skan	      struct gcov_ctr_summary *csum = &summary.ctrs[entry->ctr];
243132718Skan
244132718Skan	      entry->summary.runs += csum->runs;
245132718Skan	      entry->summary.sum_all += csum->sum_all;
246132718Skan	      if (entry->summary.run_max < csum->run_max)
247132718Skan		entry->summary.run_max = csum->run_max;
248132718Skan	      entry->summary.sum_max += csum->sum_max;
249132718Skan	    }
250132718Skan	}
251132718Skan      else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
252132718Skan	{
253132718Skan	  counts_entry_t **slot, *entry, elt;
254132718Skan	  unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
255132718Skan	  unsigned ix;
256132718Skan
257132718Skan	  elt.ident = fn_ident;
258132718Skan	  elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
259132718Skan
260132718Skan	  slot = (counts_entry_t **) htab_find_slot
261132718Skan	    (counts_hash, &elt, INSERT);
262132718Skan	  entry = *slot;
263132718Skan	  if (!entry)
264132718Skan	    {
265169689Skan	      *slot = entry = XCNEW (counts_entry_t);
266132718Skan	      entry->ident = elt.ident;
267132718Skan	      entry->ctr = elt.ctr;
268132718Skan	      entry->checksum = checksum;
269132718Skan	      entry->summary.num = n_counts;
270169689Skan	      entry->counts = XCNEWVEC (gcov_type, n_counts);
271132718Skan	    }
272132718Skan	  else if (entry->checksum != checksum)
273132718Skan	    {
274169689Skan	      error ("coverage mismatch for function %u while reading execution counters",
275132718Skan		     fn_ident);
276132718Skan	      error ("checksum is %x instead of %x", entry->checksum, checksum);
277132718Skan	      htab_delete (counts_hash);
278132718Skan	      break;
279132718Skan	    }
280132718Skan	  else if (entry->summary.num != n_counts)
281132718Skan	    {
282169689Skan	      error ("coverage mismatch for function %u while reading execution counters",
283132718Skan		     fn_ident);
284132718Skan	      error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
285132718Skan	      htab_delete (counts_hash);
286132718Skan	      break;
287132718Skan	    }
288132718Skan	  else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
289132718Skan	    {
290132718Skan	      error ("cannot merge separate %s counters for function %u",
291132718Skan		     ctr_names[elt.ctr], fn_ident);
292132718Skan	      goto skip_merge;
293132718Skan	    }
294132718Skan
295132718Skan	  if (elt.ctr < GCOV_COUNTERS_SUMMABLE
296132718Skan	      /* This should always be true for a just allocated entry,
297132718Skan		 and always false for an existing one. Check this way, in
298132718Skan		 case the gcov file is corrupt.  */
299132718Skan	      && (!entry->chain || summaried != entry))
300132718Skan	    {
301132718Skan	      entry->chain = summaried;
302132718Skan	      summaried = entry;
303132718Skan	    }
304132718Skan	  for (ix = 0; ix != n_counts; ix++)
305132718Skan	    entry->counts[ix] += gcov_read_counter ();
306132718Skan	skip_merge:;
307132718Skan	}
308132718Skan      gcov_sync (offset, length);
309132718Skan      if ((is_error = gcov_is_error ()))
310169689Skan	{
311169689Skan	  error (is_error < 0 ? "%qs has overflowed" : "%qs is corrupted",
312169689Skan		 da_file_name);
313169689Skan	  htab_delete (counts_hash);
314169689Skan	  break;
315169689Skan	}
316132718Skan    }
317132718Skan
318132718Skan  gcov_close ();
319132718Skan}
320132718Skan
321132718Skan/* Returns the counters for a particular tag.  */
322132718Skan
323132718Skangcov_type *
324132718Skanget_coverage_counts (unsigned counter, unsigned expected,
325132718Skan		     const struct gcov_ctr_summary **summary)
326132718Skan{
327132718Skan  counts_entry_t *entry, elt;
328132718Skan  gcov_unsigned_t checksum = -1;
329132718Skan
330132718Skan  /* No hash table, no counts.  */
331132718Skan  if (!counts_hash)
332132718Skan    {
333132718Skan      static int warned = 0;
334132718Skan
335132718Skan      if (!warned++)
336169689Skan	inform ((flag_guess_branch_prob
337169689Skan		 ? "file %s not found, execution counts estimated"
338169689Skan		 : "file %s not found, execution counts assumed to be zero"),
339132718Skan		da_file_name);
340132718Skan      return NULL;
341132718Skan    }
342132718Skan
343132718Skan  elt.ident = current_function_funcdef_no + 1;
344132718Skan  elt.ctr = counter;
345132718Skan  entry = htab_find (counts_hash, &elt);
346132718Skan  if (!entry)
347132718Skan    {
348169689Skan      warning (0, "no coverage for function %qs found", IDENTIFIER_POINTER
349132718Skan	       (DECL_ASSEMBLER_NAME (current_function_decl)));
350132718Skan      return 0;
351132718Skan    }
352132718Skan
353132718Skan  checksum = compute_checksum ();
354132718Skan  if (entry->checksum != checksum)
355132718Skan    {
356169689Skan      error ("coverage mismatch for function %qs while reading counter %qs",
357132718Skan	     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
358132718Skan	     ctr_names[counter]);
359132718Skan      error ("checksum is %x instead of %x", entry->checksum, checksum);
360132718Skan      return 0;
361132718Skan    }
362132718Skan  else if (entry->summary.num != expected)
363132718Skan    {
364169689Skan      error ("coverage mismatch for function %qs while reading counter %qs",
365132718Skan	     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
366132718Skan	     ctr_names[counter]);
367132718Skan      error ("number of counters is %d instead of %d", entry->summary.num, expected);
368132718Skan      return 0;
369132718Skan    }
370132718Skan
371132718Skan  if (summary)
372132718Skan    *summary = &entry->summary;
373132718Skan
374132718Skan  return entry->counts;
375132718Skan}
376132718Skan
377132718Skan/* Allocate NUM counters of type COUNTER. Returns nonzero if the
378132718Skan   allocation succeeded.  */
379132718Skan
380132718Skanint
381132718Skancoverage_counter_alloc (unsigned counter, unsigned num)
382132718Skan{
383132718Skan  if (no_coverage)
384132718Skan    return 0;
385132718Skan
386132718Skan  if (!num)
387132718Skan    return 1;
388132718Skan
389169689Skan  if (!tree_ctr_tables[counter])
390132718Skan    {
391169689Skan      /* Generate and save a copy of this so it can be shared.  Leave
392169689Skan	 the index type unspecified for now; it will be set after all
393169689Skan	 functions have been compiled.  */
394132718Skan      char buf[20];
395169689Skan      tree gcov_type_node = get_gcov_type ();
396169689Skan      tree gcov_type_array_type
397169689Skan        = build_array_type (gcov_type_node, NULL_TREE);
398169689Skan      tree_ctr_tables[counter]
399169689Skan        = build_decl (VAR_DECL, NULL_TREE, gcov_type_array_type);
400169689Skan      TREE_STATIC (tree_ctr_tables[counter]) = 1;
401132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1);
402169689Skan      DECL_NAME (tree_ctr_tables[counter]) = get_identifier (buf);
403169689Skan      DECL_ALIGN (tree_ctr_tables[counter]) = TYPE_ALIGN (gcov_type_node);
404132718Skan    }
405132718Skan  fn_b_ctrs[counter] = fn_n_ctrs[counter];
406132718Skan  fn_n_ctrs[counter] += num;
407132718Skan  fn_ctr_mask |= 1 << counter;
408132718Skan  return 1;
409132718Skan}
410132718Skan
411169689Skan/* Generate a tree to access COUNTER NO.  */
412132718Skan
413169689Skantree
414169689Skantree_coverage_counter_ref (unsigned counter, unsigned no)
415132718Skan{
416169689Skan  tree gcov_type_node = get_gcov_type ();
417132718Skan
418169689Skan  gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
419132718Skan  no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
420132718Skan
421169689Skan  /* "no" here is an array index, scaled to bytes later.  */
422169689Skan  return build4 (ARRAY_REF, gcov_type_node, tree_ctr_tables[counter],
423169689Skan		 build_int_cst (NULL_TREE, no), NULL, NULL);
424132718Skan}
425132718Skan
426132718Skan/* Generate a checksum for a string.  CHKSUM is the current
427132718Skan   checksum.  */
428132718Skan
429132718Skanstatic unsigned
430132718Skancoverage_checksum_string (unsigned chksum, const char *string)
431132718Skan{
432132718Skan  char *dup = NULL;
433259405Spfg  char *ptr;
434132718Skan
435132718Skan  /* Look for everything that looks if it were produced by
436259563Spfg     get_file_function_name and zero out the second part
437132718Skan     that may result from flag_random_seed.  This is not critical
438132718Skan     as the checksums are used only for sanity checking.  */
439259405Spfg#define GLOBAL_PREFIX "_GLOBAL__"
440259405Spfg#define TRAILING_N "N_"
441259405Spfg#define ISCAPXDIGIT(a) (((a) >= '0' && (a) <= '9') || ((a) >= 'A' && (a) <= 'F'))
442259405Spfg  if ((ptr = strstr (string, GLOBAL_PREFIX)))
443132718Skan    {
444259405Spfg      /* Skip _GLOBAL__. */
445259405Spfg      ptr += strlen (GLOBAL_PREFIX);
446132718Skan
447259405Spfg      /* Skip optional N_ (in case __GLOBAL_N__). */
448259405Spfg      if (!strncmp (ptr, TRAILING_N, strlen (TRAILING_N)))
449259405Spfg          ptr += strlen (TRAILING_N);
450259405Spfg      /* At this point, ptr should point after "_GLOBAL__N_" or "_GLOBAL__". */
451169689Skan
452259405Spfg      while ((ptr = strchr (ptr, '_')) != NULL)
453259405Spfg        {
454259405Spfg          int y;
455259405Spfg          /* For every "_" in the rest of the string,
456259405Spfg             try the follwing pattern matching */
457259405Spfg
458259405Spfg          /* Skip over '_'. */
459259405Spfg          ptr++;
460259405Spfg#define NDIGITS (8)
461259405Spfg          /* Try matching the pattern:
462259405Spfg             <8-digit hex>_<8-digit hex>
463259405Spfg             The second number is randomly generated
464259405Spfg             so we want to mask it out before computing the checksum. */
465259405Spfg          for (y = 0; *ptr != 0 && y < NDIGITS; y++, ptr++)
466259405Spfg              if (!ISCAPXDIGIT (*ptr))
467259405Spfg                  break;
468259405Spfg          if (y != NDIGITS || *ptr != '_')
469259405Spfg              continue;
470259405Spfg          /* Skip over '_' again. */
471259405Spfg          ptr++;
472259405Spfg          for (y = 0; *ptr != 0 && y < NDIGITS; y++, ptr++)
473259405Spfg              if (!ISCAPXDIGIT (*ptr))
474259405Spfg                  break;
475259405Spfg
476259405Spfg          if (y == NDIGITS)
477259405Spfg            {
478259405Spfg              /* We have a match.
479259405Spfg                 Duplicate the string and mask out
480259405Spfg                 the second 8-digit number. */
481259405Spfg              dup = xstrdup (string);
482259405Spfg              ptr = dup + (ptr - string);
483259405Spfg              for(y = -NDIGITS - 1 ; y < 0; y++)
484259405Spfg                {
485259405Spfg                  ptr[y] = '0';
486259405Spfg                }
487259405Spfg              ptr = dup;
488259405Spfg              break;
489259405Spfg            }
490259405Spfg        }
491259405Spfg        /* "ptr" should be NULL if we couldn't find the match
492259405Spfg           (strchr will return NULL if no match is found),
493259405Spfg           or it should point to dup which contains the string
494259405Spfg           with the random part masked. */
495132718Skan    }
496132718Skan
497259405Spfg  chksum = crc32_string (chksum, (ptr) ? ptr : string);
498259405Spfg
499132718Skan  if (dup)
500259405Spfg      free (dup);
501132718Skan
502132718Skan  return chksum;
503132718Skan}
504132718Skan
505132718Skan/* Compute checksum for the current function.  We generate a CRC32.  */
506132718Skan
507132718Skanstatic unsigned
508132718Skancompute_checksum (void)
509132718Skan{
510169689Skan  expanded_location xloc
511169689Skan    = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
512169689Skan  unsigned chksum = xloc.line;
513132718Skan
514169689Skan  chksum = coverage_checksum_string (chksum, xloc.file);
515132718Skan  chksum = coverage_checksum_string
516132718Skan    (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
517132718Skan
518132718Skan  return chksum;
519132718Skan}
520132718Skan
521132718Skan/* Begin output to the graph file for the current function.
522132718Skan   Opens the output file, if not already done. Writes the
523132718Skan   function header, if not already done. Returns nonzero if data
524132718Skan   should be output.  */
525132718Skan
526132718Skanint
527132718Skancoverage_begin_output (void)
528132718Skan{
529132718Skan  if (no_coverage)
530132718Skan    return 0;
531132718Skan
532132718Skan  if (!bbg_function_announced)
533132718Skan    {
534169689Skan      expanded_location xloc
535169689Skan	= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
536132718Skan      unsigned long offset;
537132718Skan
538132718Skan      if (!bbg_file_opened)
539132718Skan	{
540132718Skan	  if (!gcov_open (bbg_file_name, -1))
541132718Skan	    error ("cannot open %s", bbg_file_name);
542132718Skan	  else
543132718Skan	    {
544132718Skan	      gcov_write_unsigned (GCOV_NOTE_MAGIC);
545132718Skan	      gcov_write_unsigned (GCOV_VERSION);
546132718Skan	      gcov_write_unsigned (local_tick);
547132718Skan	    }
548132718Skan	  bbg_file_opened = 1;
549132718Skan	}
550132718Skan
551132718Skan      /* Announce function */
552132718Skan      offset = gcov_write_tag (GCOV_TAG_FUNCTION);
553132718Skan      gcov_write_unsigned (current_function_funcdef_no + 1);
554132718Skan      gcov_write_unsigned (compute_checksum ());
555132718Skan      gcov_write_string (IDENTIFIER_POINTER
556132718Skan			 (DECL_ASSEMBLER_NAME (current_function_decl)));
557169689Skan      gcov_write_string (xloc.file);
558169689Skan      gcov_write_unsigned (xloc.line);
559132718Skan      gcov_write_length (offset);
560132718Skan
561132718Skan      bbg_function_announced = 1;
562132718Skan    }
563132718Skan  return !gcov_is_error ();
564132718Skan}
565132718Skan
566132718Skan/* Finish coverage data for the current function. Verify no output
567132718Skan   error has occurred.  Save function coverage counts.  */
568132718Skan
569132718Skanvoid
570132718Skancoverage_end_function (void)
571132718Skan{
572132718Skan  unsigned i;
573132718Skan
574132718Skan  if (bbg_file_opened > 1 && gcov_is_error ())
575132718Skan    {
576169689Skan      warning (0, "error writing %qs", bbg_file_name);
577132718Skan      bbg_file_opened = -1;
578132718Skan    }
579132718Skan
580132718Skan  if (fn_ctr_mask)
581132718Skan    {
582132718Skan      struct function_list *item;
583132718Skan
584169689Skan      item = XNEW (struct function_list);
585132718Skan
586132718Skan      *functions_tail = item;
587132718Skan      functions_tail = &item->next;
588132718Skan
589132718Skan      item->next = 0;
590132718Skan      item->ident = current_function_funcdef_no + 1;
591132718Skan      item->checksum = compute_checksum ();
592132718Skan      for (i = 0; i != GCOV_COUNTERS; i++)
593132718Skan	{
594132718Skan	  item->n_ctrs[i] = fn_n_ctrs[i];
595132718Skan	  prg_n_ctrs[i] += fn_n_ctrs[i];
596132718Skan	  fn_n_ctrs[i] = fn_b_ctrs[i] = 0;
597132718Skan	}
598132718Skan      prg_ctr_mask |= fn_ctr_mask;
599132718Skan      fn_ctr_mask = 0;
600132718Skan    }
601132718Skan  bbg_function_announced = 0;
602132718Skan}
603132718Skan
604132718Skan/* Creates the gcov_fn_info RECORD_TYPE.  */
605132718Skan
606132718Skanstatic tree
607132718Skanbuild_fn_info_type (unsigned int counters)
608132718Skan{
609169689Skan  tree type = lang_hooks.types.make_type (RECORD_TYPE);
610132718Skan  tree field, fields;
611132718Skan  tree array_type;
612132718Skan
613132718Skan  /* ident */
614169689Skan  fields = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
615132718Skan
616132718Skan  /* checksum */
617169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
618132718Skan  TREE_CHAIN (field) = fields;
619132718Skan  fields = field;
620132718Skan
621169689Skan  array_type = build_int_cst (NULL_TREE, counters - 1);
622169689Skan  array_type = build_index_type (array_type);
623169689Skan  array_type = build_array_type (get_gcov_unsigned_t (), array_type);
624132718Skan
625132718Skan  /* counters */
626132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, array_type);
627132718Skan  TREE_CHAIN (field) = fields;
628132718Skan  fields = field;
629132718Skan
630132718Skan  finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
631132718Skan
632132718Skan  return type;
633132718Skan}
634132718Skan
635132718Skan/* Creates a CONSTRUCTOR for a gcov_fn_info. FUNCTION is
636132718Skan   the function being processed and TYPE is the gcov_fn_info
637132718Skan   RECORD_TYPE.  */
638132718Skan
639132718Skanstatic tree
640132718Skanbuild_fn_info_value (const struct function_list *function, tree type)
641132718Skan{
642132718Skan  tree value = NULL_TREE;
643132718Skan  tree fields = TYPE_FIELDS (type);
644132718Skan  unsigned ix;
645132718Skan  tree array_value = NULL_TREE;
646132718Skan
647132718Skan  /* ident */
648169689Skan  value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (),
649169689Skan					     function->ident), value);
650132718Skan  fields = TREE_CHAIN (fields);
651132718Skan
652132718Skan  /* checksum */
653169689Skan  value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (),
654169689Skan					     function->checksum), value);
655132718Skan  fields = TREE_CHAIN (fields);
656132718Skan
657132718Skan  /* counters */
658132718Skan  for (ix = 0; ix != GCOV_COUNTERS; ix++)
659132718Skan    if (prg_ctr_mask & (1 << ix))
660132718Skan      {
661169689Skan	tree counters = build_int_cstu (get_gcov_unsigned_t (),
662169689Skan					function->n_ctrs[ix]);
663132718Skan
664132718Skan	array_value = tree_cons (NULL_TREE, counters, array_value);
665132718Skan      }
666132718Skan
667169689Skan  /* FIXME: use build_constructor directly.  */
668169689Skan  array_value = build_constructor_from_list (TREE_TYPE (fields),
669169689Skan					     nreverse (array_value));
670132718Skan  value = tree_cons (fields, array_value, value);
671132718Skan
672169689Skan  /* FIXME: use build_constructor directly.  */
673169689Skan  value = build_constructor_from_list (type, nreverse (value));
674132718Skan
675132718Skan  return value;
676132718Skan}
677132718Skan
678132718Skan/* Creates the gcov_ctr_info RECORD_TYPE.  */
679132718Skan
680132718Skanstatic tree
681132718Skanbuild_ctr_info_type (void)
682132718Skan{
683169689Skan  tree type = lang_hooks.types.make_type (RECORD_TYPE);
684132718Skan  tree field, fields = NULL_TREE;
685169689Skan  tree gcov_ptr_type = build_pointer_type (get_gcov_type ());
686132718Skan  tree gcov_merge_fn_type;
687132718Skan
688132718Skan  /* counters */
689169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
690132718Skan  TREE_CHAIN (field) = fields;
691132718Skan  fields = field;
692132718Skan
693132718Skan  /* values */
694132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
695132718Skan  TREE_CHAIN (field) = fields;
696132718Skan  fields = field;
697132718Skan
698132718Skan  /* merge */
699132718Skan  gcov_merge_fn_type =
700132718Skan    build_function_type_list (void_type_node,
701169689Skan			      gcov_ptr_type, get_gcov_unsigned_t (),
702132718Skan			      NULL_TREE);
703132718Skan  field = build_decl (FIELD_DECL, NULL_TREE,
704132718Skan		      build_pointer_type (gcov_merge_fn_type));
705132718Skan  TREE_CHAIN (field) = fields;
706132718Skan  fields = field;
707132718Skan
708132718Skan  finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
709132718Skan
710132718Skan  return type;
711132718Skan}
712132718Skan
713132718Skan/* Creates a CONSTRUCTOR for a gcov_ctr_info. COUNTER is
714132718Skan   the counter being processed and TYPE is the gcov_ctr_info
715132718Skan   RECORD_TYPE.  */
716132718Skan
717132718Skanstatic tree
718132718Skanbuild_ctr_info_value (unsigned int counter, tree type)
719132718Skan{
720132718Skan  tree value = NULL_TREE;
721132718Skan  tree fields = TYPE_FIELDS (type);
722132718Skan  tree fn;
723132718Skan
724132718Skan  /* counters */
725132718Skan  value = tree_cons (fields,
726169689Skan		     build_int_cstu (get_gcov_unsigned_t (),
727169689Skan				     prg_n_ctrs[counter]),
728132718Skan		     value);
729132718Skan  fields = TREE_CHAIN (fields);
730132718Skan
731132718Skan  if (prg_n_ctrs[counter])
732132718Skan    {
733169689Skan      tree array_type;
734132718Skan
735169689Skan      array_type = build_int_cstu (get_gcov_unsigned_t (),
736169689Skan				   prg_n_ctrs[counter] - 1);
737169689Skan      array_type = build_index_type (array_type);
738132718Skan      array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
739132718Skan				     array_type);
740132718Skan
741169689Skan      TREE_TYPE (tree_ctr_tables[counter]) = array_type;
742169689Skan      DECL_SIZE (tree_ctr_tables[counter]) = TYPE_SIZE (array_type);
743169689Skan      DECL_SIZE_UNIT (tree_ctr_tables[counter]) = TYPE_SIZE_UNIT (array_type);
744169689Skan      assemble_variable (tree_ctr_tables[counter], 0, 0, 0);
745132718Skan
746132718Skan      value = tree_cons (fields,
747169689Skan			 build1 (ADDR_EXPR, TREE_TYPE (fields),
748169689Skan					    tree_ctr_tables[counter]),
749132718Skan			 value);
750132718Skan    }
751132718Skan  else
752132718Skan    value = tree_cons (fields, null_pointer_node, value);
753132718Skan  fields = TREE_CHAIN (fields);
754132718Skan
755132718Skan  fn = build_decl (FUNCTION_DECL,
756132718Skan		   get_identifier (ctr_merge_functions[counter]),
757132718Skan		   TREE_TYPE (TREE_TYPE (fields)));
758132718Skan  DECL_EXTERNAL (fn) = 1;
759132718Skan  TREE_PUBLIC (fn) = 1;
760132718Skan  DECL_ARTIFICIAL (fn) = 1;
761132718Skan  TREE_NOTHROW (fn) = 1;
762132718Skan  value = tree_cons (fields,
763132718Skan		     build1 (ADDR_EXPR, TREE_TYPE (fields), fn),
764132718Skan		     value);
765132718Skan
766169689Skan  /* FIXME: use build_constructor directly.  */
767169689Skan  value = build_constructor_from_list (type, nreverse (value));
768132718Skan
769132718Skan  return value;
770132718Skan}
771132718Skan
772132718Skan/* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a
773132718Skan   CONSTRUCTOR.  */
774132718Skan
775132718Skanstatic tree
776132718Skanbuild_gcov_info (void)
777132718Skan{
778132718Skan  unsigned n_ctr_types, ix;
779132718Skan  tree type, const_type;
780132718Skan  tree fn_info_type, fn_info_value = NULL_TREE;
781132718Skan  tree fn_info_ptr_type;
782132718Skan  tree ctr_info_type, ctr_info_ary_type, ctr_info_value = NULL_TREE;
783132718Skan  tree field, fields = NULL_TREE;
784132718Skan  tree value = NULL_TREE;
785132718Skan  tree filename_string;
786132718Skan  char *filename;
787132718Skan  int filename_len;
788132718Skan  unsigned n_fns;
789132718Skan  const struct function_list *fn;
790132718Skan  tree string_type;
791132718Skan
792132718Skan  /* Count the number of active counters.  */
793132718Skan  for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++)
794132718Skan    if (prg_ctr_mask & (1 << ix))
795132718Skan      n_ctr_types++;
796132718Skan
797169689Skan  type = lang_hooks.types.make_type (RECORD_TYPE);
798132718Skan  const_type = build_qualified_type (type, TYPE_QUAL_CONST);
799132718Skan
800132718Skan  /* Version ident */
801169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
802132718Skan  TREE_CHAIN (field) = fields;
803132718Skan  fields = field;
804169689Skan  value = tree_cons (field, build_int_cstu (TREE_TYPE (field), GCOV_VERSION),
805132718Skan		     value);
806132718Skan
807132718Skan  /* next -- NULL */
808132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type));
809132718Skan  TREE_CHAIN (field) = fields;
810132718Skan  fields = field;
811132718Skan  value = tree_cons (field, null_pointer_node, value);
812132718Skan
813132718Skan  /* stamp */
814169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
815132718Skan  TREE_CHAIN (field) = fields;
816132718Skan  fields = field;
817169689Skan  value = tree_cons (field, build_int_cstu (TREE_TYPE (field), local_tick),
818132718Skan		     value);
819132718Skan
820132718Skan  /* Filename */
821132718Skan  string_type = build_pointer_type (build_qualified_type (char_type_node,
822132718Skan						    TYPE_QUAL_CONST));
823132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, string_type);
824132718Skan  TREE_CHAIN (field) = fields;
825132718Skan  fields = field;
826132718Skan  filename = getpwd ();
827132718Skan  filename = (filename && da_file_name[0] != '/'
828132718Skan	      ? concat (filename, "/", da_file_name, NULL)
829132718Skan	      : da_file_name);
830132718Skan  filename_len = strlen (filename);
831132718Skan  filename_string = build_string (filename_len + 1, filename);
832132718Skan  if (filename != da_file_name)
833132718Skan    free (filename);
834169689Skan  TREE_TYPE (filename_string) = build_array_type
835169689Skan    (char_type_node, build_index_type
836169689Skan     (build_int_cst (NULL_TREE, filename_len)));
837132718Skan  value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string),
838132718Skan		     value);
839132718Skan
840132718Skan  /* Build the fn_info type and initializer.  */
841132718Skan  fn_info_type = build_fn_info_type (n_ctr_types);
842132718Skan  fn_info_ptr_type = build_pointer_type (build_qualified_type
843132718Skan					 (fn_info_type, TYPE_QUAL_CONST));
844132718Skan  for (fn = functions_head, n_fns = 0; fn; fn = fn->next, n_fns++)
845132718Skan    fn_info_value = tree_cons (NULL_TREE,
846132718Skan			       build_fn_info_value (fn, fn_info_type),
847132718Skan			       fn_info_value);
848132718Skan  if (n_fns)
849132718Skan    {
850132718Skan      tree array_type;
851132718Skan
852169689Skan      array_type = build_index_type (build_int_cst (NULL_TREE, n_fns - 1));
853132718Skan      array_type = build_array_type (fn_info_type, array_type);
854132718Skan
855169689Skan      /* FIXME: use build_constructor directly.  */
856169689Skan      fn_info_value = build_constructor_from_list (array_type,
857169689Skan						   nreverse (fn_info_value));
858132718Skan      fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
859132718Skan    }
860132718Skan  else
861132718Skan    fn_info_value = null_pointer_node;
862132718Skan
863132718Skan  /* number of functions */
864169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
865132718Skan  TREE_CHAIN (field) = fields;
866132718Skan  fields = field;
867132718Skan  value = tree_cons (field,
868169689Skan		     build_int_cstu (get_gcov_unsigned_t (), n_fns),
869132718Skan		     value);
870132718Skan
871132718Skan  /* fn_info table */
872132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type);
873132718Skan  TREE_CHAIN (field) = fields;
874132718Skan  fields = field;
875132718Skan  value = tree_cons (field, fn_info_value, value);
876132718Skan
877132718Skan  /* counter_mask */
878169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
879132718Skan  TREE_CHAIN (field) = fields;
880132718Skan  fields = field;
881132718Skan  value = tree_cons (field,
882169689Skan		     build_int_cstu (get_gcov_unsigned_t (), prg_ctr_mask),
883132718Skan		     value);
884132718Skan
885132718Skan  /* counters */
886132718Skan  ctr_info_type = build_ctr_info_type ();
887169689Skan  ctr_info_ary_type = build_index_type (build_int_cst (NULL_TREE,
888169689Skan						       n_ctr_types));
889132718Skan  ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type);
890132718Skan  for (ix = 0; ix != GCOV_COUNTERS; ix++)
891132718Skan    if (prg_ctr_mask & (1 << ix))
892132718Skan      ctr_info_value = tree_cons (NULL_TREE,
893132718Skan				  build_ctr_info_value (ix, ctr_info_type),
894132718Skan				  ctr_info_value);
895169689Skan  /* FIXME: use build_constructor directly.  */
896169689Skan  ctr_info_value = build_constructor_from_list (ctr_info_ary_type,
897169689Skan				                nreverse (ctr_info_value));
898132718Skan
899132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, ctr_info_ary_type);
900132718Skan  TREE_CHAIN (field) = fields;
901132718Skan  fields = field;
902132718Skan  value = tree_cons (field, ctr_info_value, value);
903132718Skan
904132718Skan  finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
905132718Skan
906169689Skan  /* FIXME: use build_constructor directly.  */
907169689Skan  value = build_constructor_from_list (type, nreverse (value));
908132718Skan
909132718Skan  return value;
910132718Skan}
911132718Skan
912132718Skan/* Write out the structure which libgcov uses to locate all the
913132718Skan   counters.  The structures used here must match those defined in
914132718Skan   gcov-io.h.  Write out the constructor to call __gcov_init.  */
915132718Skan
916132718Skanstatic void
917132718Skancreate_coverage (void)
918132718Skan{
919169689Skan  tree gcov_info, gcov_init, body, t;
920169689Skan  char name_buf[32];
921132718Skan
922132718Skan  no_coverage = 1; /* Disable any further coverage.  */
923132718Skan
924132718Skan  if (!prg_ctr_mask)
925132718Skan    return;
926132718Skan
927169689Skan  t = build_gcov_info ();
928132718Skan
929169689Skan  gcov_info = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (t));
930132718Skan  TREE_STATIC (gcov_info) = 1;
931169689Skan  ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
932169689Skan  DECL_NAME (gcov_info) = get_identifier (name_buf);
933169689Skan  DECL_INITIAL (gcov_info) = t;
934132718Skan
935132718Skan  /* Build structure.  */
936132718Skan  assemble_variable (gcov_info, 0, 0, 0);
937132718Skan
938169689Skan  /* Build a decl for __gcov_init.  */
939169689Skan  t = build_pointer_type (TREE_TYPE (gcov_info));
940169689Skan  t = build_function_type_list (void_type_node, t, NULL);
941169689Skan  t = build_decl (FUNCTION_DECL, get_identifier ("__gcov_init"), t);
942169689Skan  TREE_PUBLIC (t) = 1;
943169689Skan  DECL_EXTERNAL (t) = 1;
944169689Skan  gcov_init = t;
945132718Skan
946169689Skan  /* Generate a call to __gcov_init(&gcov_info).  */
947169689Skan  body = NULL;
948169689Skan  t = build_fold_addr_expr (gcov_info);
949169689Skan  t = tree_cons (NULL, t, NULL);
950169689Skan  t = build_function_call_expr (gcov_init, t);
951169689Skan  append_to_statement_list (t, &body);
952132718Skan
953169689Skan  /* Generate a constructor to run it.  */
954169689Skan  cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
955132718Skan}
956132718Skan
957132718Skan/* Perform file-level initialization. Read in data file, generate name
958132718Skan   of graph file.  */
959132718Skan
960132718Skanvoid
961132718Skancoverage_init (const char *filename)
962132718Skan{
963132718Skan  int len = strlen (filename);
964132718Skan
965132718Skan  /* Name of da file.  */
966169689Skan  da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX) + 1);
967132718Skan  strcpy (da_file_name, filename);
968132718Skan  strcat (da_file_name, GCOV_DATA_SUFFIX);
969132718Skan
970132718Skan  /* Name of bbg file.  */
971169689Skan  bbg_file_name = XNEWVEC (char, len + strlen (GCOV_NOTE_SUFFIX) + 1);
972132718Skan  strcpy (bbg_file_name, filename);
973132718Skan  strcat (bbg_file_name, GCOV_NOTE_SUFFIX);
974132718Skan
975132718Skan  read_counts_file ();
976132718Skan}
977132718Skan
978132718Skan/* Performs file-level cleanup.  Close graph file, generate coverage
979132718Skan   variables and constructor.  */
980132718Skan
981132718Skanvoid
982132718Skancoverage_finish (void)
983132718Skan{
984132718Skan  create_coverage ();
985132718Skan  if (bbg_file_opened)
986132718Skan    {
987132718Skan      int error = gcov_close ();
988132718Skan
989132718Skan      if (error)
990132718Skan	unlink (bbg_file_name);
991132718Skan      if (!local_tick)
992132718Skan	/* Only remove the da file, if we cannot stamp it. If we can
993132718Skan	   stamp it, libgcov will DTRT.  */
994132718Skan	unlink (da_file_name);
995132718Skan    }
996132718Skan}
997132718Skan
998132718Skan#include "gt-coverage.h"
999