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  int i;
433132718Skan  char *dup = NULL;
434132718Skan
435132718Skan  /* Look for everything that looks if it were produced by
436132718Skan     get_file_function_name_long 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.  */
439132718Skan  for (i = 0; string[i]; i++)
440132718Skan    {
441169689Skan      int offset = 0;
442169689Skan      if (!strncmp (string + i, "_GLOBAL__N_", 11))
443169689Skan      offset = 11;
444132718Skan      if (!strncmp (string + i, "_GLOBAL__", 9))
445169689Skan      offset = 9;
446132718Skan
447169689Skan      /* C++ namespaces do have scheme:
448169689Skan         _GLOBAL__N_<filename>_<wrongmagicnumber>_<magicnumber>functionname
449169689Skan       since filename might contain extra underscores there seems
450169689Skan       to be no better chance then walk all possible offsets looking
451169689Skan       for magicnuber.  */
452169689Skan      if (offset)
453169689Skan	{
454169689Skan	  for (i = i + offset; string[i]; i++)
455169689Skan	    if (string[i]=='_')
456169689Skan	      {
457169689Skan		int y;
458169689Skan
459169689Skan		for (y = 1; y < 9; y++)
460169689Skan		  if (!(string[i + y] >= '0' && string[i + y] <= '9')
461169689Skan		      && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
462169689Skan		    break;
463169689Skan		if (y != 9 || string[i + 9] != '_')
464169689Skan		  continue;
465169689Skan		for (y = 10; y < 18; y++)
466169689Skan		  if (!(string[i + y] >= '0' && string[i + y] <= '9')
467169689Skan		      && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
468169689Skan		    break;
469169689Skan		if (y != 18)
470169689Skan		  continue;
471169689Skan		if (!dup)
472169689Skan		  string = dup = xstrdup (string);
473169689Skan		for (y = 10; y < 18; y++)
474169689Skan		  dup[i + y] = '0';
475169689Skan	      }
476169689Skan	  break;
477169689Skan	}
478132718Skan    }
479132718Skan
480132718Skan  chksum = crc32_string (chksum, string);
481132718Skan  if (dup)
482132718Skan    free (dup);
483132718Skan
484132718Skan  return chksum;
485132718Skan}
486132718Skan
487132718Skan/* Compute checksum for the current function.  We generate a CRC32.  */
488132718Skan
489132718Skanstatic unsigned
490132718Skancompute_checksum (void)
491132718Skan{
492169689Skan  expanded_location xloc
493169689Skan    = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
494169689Skan  unsigned chksum = xloc.line;
495132718Skan
496169689Skan  chksum = coverage_checksum_string (chksum, xloc.file);
497132718Skan  chksum = coverage_checksum_string
498132718Skan    (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
499132718Skan
500132718Skan  return chksum;
501132718Skan}
502132718Skan
503132718Skan/* Begin output to the graph file for the current function.
504132718Skan   Opens the output file, if not already done. Writes the
505132718Skan   function header, if not already done. Returns nonzero if data
506132718Skan   should be output.  */
507132718Skan
508132718Skanint
509132718Skancoverage_begin_output (void)
510132718Skan{
511132718Skan  if (no_coverage)
512132718Skan    return 0;
513132718Skan
514132718Skan  if (!bbg_function_announced)
515132718Skan    {
516169689Skan      expanded_location xloc
517169689Skan	= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
518132718Skan      unsigned long offset;
519132718Skan
520132718Skan      if (!bbg_file_opened)
521132718Skan	{
522132718Skan	  if (!gcov_open (bbg_file_name, -1))
523132718Skan	    error ("cannot open %s", bbg_file_name);
524132718Skan	  else
525132718Skan	    {
526132718Skan	      gcov_write_unsigned (GCOV_NOTE_MAGIC);
527132718Skan	      gcov_write_unsigned (GCOV_VERSION);
528132718Skan	      gcov_write_unsigned (local_tick);
529132718Skan	    }
530132718Skan	  bbg_file_opened = 1;
531132718Skan	}
532132718Skan
533132718Skan      /* Announce function */
534132718Skan      offset = gcov_write_tag (GCOV_TAG_FUNCTION);
535132718Skan      gcov_write_unsigned (current_function_funcdef_no + 1);
536132718Skan      gcov_write_unsigned (compute_checksum ());
537132718Skan      gcov_write_string (IDENTIFIER_POINTER
538132718Skan			 (DECL_ASSEMBLER_NAME (current_function_decl)));
539169689Skan      gcov_write_string (xloc.file);
540169689Skan      gcov_write_unsigned (xloc.line);
541132718Skan      gcov_write_length (offset);
542132718Skan
543132718Skan      bbg_function_announced = 1;
544132718Skan    }
545132718Skan  return !gcov_is_error ();
546132718Skan}
547132718Skan
548132718Skan/* Finish coverage data for the current function. Verify no output
549132718Skan   error has occurred.  Save function coverage counts.  */
550132718Skan
551132718Skanvoid
552132718Skancoverage_end_function (void)
553132718Skan{
554132718Skan  unsigned i;
555132718Skan
556132718Skan  if (bbg_file_opened > 1 && gcov_is_error ())
557132718Skan    {
558169689Skan      warning (0, "error writing %qs", bbg_file_name);
559132718Skan      bbg_file_opened = -1;
560132718Skan    }
561132718Skan
562132718Skan  if (fn_ctr_mask)
563132718Skan    {
564132718Skan      struct function_list *item;
565132718Skan
566169689Skan      item = XNEW (struct function_list);
567132718Skan
568132718Skan      *functions_tail = item;
569132718Skan      functions_tail = &item->next;
570132718Skan
571132718Skan      item->next = 0;
572132718Skan      item->ident = current_function_funcdef_no + 1;
573132718Skan      item->checksum = compute_checksum ();
574132718Skan      for (i = 0; i != GCOV_COUNTERS; i++)
575132718Skan	{
576132718Skan	  item->n_ctrs[i] = fn_n_ctrs[i];
577132718Skan	  prg_n_ctrs[i] += fn_n_ctrs[i];
578132718Skan	  fn_n_ctrs[i] = fn_b_ctrs[i] = 0;
579132718Skan	}
580132718Skan      prg_ctr_mask |= fn_ctr_mask;
581132718Skan      fn_ctr_mask = 0;
582132718Skan    }
583132718Skan  bbg_function_announced = 0;
584132718Skan}
585132718Skan
586132718Skan/* Creates the gcov_fn_info RECORD_TYPE.  */
587132718Skan
588132718Skanstatic tree
589132718Skanbuild_fn_info_type (unsigned int counters)
590132718Skan{
591169689Skan  tree type = lang_hooks.types.make_type (RECORD_TYPE);
592132718Skan  tree field, fields;
593132718Skan  tree array_type;
594132718Skan
595132718Skan  /* ident */
596169689Skan  fields = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
597132718Skan
598132718Skan  /* checksum */
599169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
600132718Skan  TREE_CHAIN (field) = fields;
601132718Skan  fields = field;
602132718Skan
603169689Skan  array_type = build_int_cst (NULL_TREE, counters - 1);
604169689Skan  array_type = build_index_type (array_type);
605169689Skan  array_type = build_array_type (get_gcov_unsigned_t (), array_type);
606132718Skan
607132718Skan  /* counters */
608132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, array_type);
609132718Skan  TREE_CHAIN (field) = fields;
610132718Skan  fields = field;
611132718Skan
612132718Skan  finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
613132718Skan
614132718Skan  return type;
615132718Skan}
616132718Skan
617132718Skan/* Creates a CONSTRUCTOR for a gcov_fn_info. FUNCTION is
618132718Skan   the function being processed and TYPE is the gcov_fn_info
619132718Skan   RECORD_TYPE.  */
620132718Skan
621132718Skanstatic tree
622132718Skanbuild_fn_info_value (const struct function_list *function, tree type)
623132718Skan{
624132718Skan  tree value = NULL_TREE;
625132718Skan  tree fields = TYPE_FIELDS (type);
626132718Skan  unsigned ix;
627132718Skan  tree array_value = NULL_TREE;
628132718Skan
629132718Skan  /* ident */
630169689Skan  value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (),
631169689Skan					     function->ident), value);
632132718Skan  fields = TREE_CHAIN (fields);
633132718Skan
634132718Skan  /* checksum */
635169689Skan  value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (),
636169689Skan					     function->checksum), value);
637132718Skan  fields = TREE_CHAIN (fields);
638132718Skan
639132718Skan  /* counters */
640132718Skan  for (ix = 0; ix != GCOV_COUNTERS; ix++)
641132718Skan    if (prg_ctr_mask & (1 << ix))
642132718Skan      {
643169689Skan	tree counters = build_int_cstu (get_gcov_unsigned_t (),
644169689Skan					function->n_ctrs[ix]);
645132718Skan
646132718Skan	array_value = tree_cons (NULL_TREE, counters, array_value);
647132718Skan      }
648132718Skan
649169689Skan  /* FIXME: use build_constructor directly.  */
650169689Skan  array_value = build_constructor_from_list (TREE_TYPE (fields),
651169689Skan					     nreverse (array_value));
652132718Skan  value = tree_cons (fields, array_value, value);
653132718Skan
654169689Skan  /* FIXME: use build_constructor directly.  */
655169689Skan  value = build_constructor_from_list (type, nreverse (value));
656132718Skan
657132718Skan  return value;
658132718Skan}
659132718Skan
660132718Skan/* Creates the gcov_ctr_info RECORD_TYPE.  */
661132718Skan
662132718Skanstatic tree
663132718Skanbuild_ctr_info_type (void)
664132718Skan{
665169689Skan  tree type = lang_hooks.types.make_type (RECORD_TYPE);
666132718Skan  tree field, fields = NULL_TREE;
667169689Skan  tree gcov_ptr_type = build_pointer_type (get_gcov_type ());
668132718Skan  tree gcov_merge_fn_type;
669132718Skan
670132718Skan  /* counters */
671169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
672132718Skan  TREE_CHAIN (field) = fields;
673132718Skan  fields = field;
674132718Skan
675132718Skan  /* values */
676132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
677132718Skan  TREE_CHAIN (field) = fields;
678132718Skan  fields = field;
679132718Skan
680132718Skan  /* merge */
681132718Skan  gcov_merge_fn_type =
682132718Skan    build_function_type_list (void_type_node,
683169689Skan			      gcov_ptr_type, get_gcov_unsigned_t (),
684132718Skan			      NULL_TREE);
685132718Skan  field = build_decl (FIELD_DECL, NULL_TREE,
686132718Skan		      build_pointer_type (gcov_merge_fn_type));
687132718Skan  TREE_CHAIN (field) = fields;
688132718Skan  fields = field;
689132718Skan
690132718Skan  finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
691132718Skan
692132718Skan  return type;
693132718Skan}
694132718Skan
695132718Skan/* Creates a CONSTRUCTOR for a gcov_ctr_info. COUNTER is
696132718Skan   the counter being processed and TYPE is the gcov_ctr_info
697132718Skan   RECORD_TYPE.  */
698132718Skan
699132718Skanstatic tree
700132718Skanbuild_ctr_info_value (unsigned int counter, tree type)
701132718Skan{
702132718Skan  tree value = NULL_TREE;
703132718Skan  tree fields = TYPE_FIELDS (type);
704132718Skan  tree fn;
705132718Skan
706132718Skan  /* counters */
707132718Skan  value = tree_cons (fields,
708169689Skan		     build_int_cstu (get_gcov_unsigned_t (),
709169689Skan				     prg_n_ctrs[counter]),
710132718Skan		     value);
711132718Skan  fields = TREE_CHAIN (fields);
712132718Skan
713132718Skan  if (prg_n_ctrs[counter])
714132718Skan    {
715169689Skan      tree array_type;
716132718Skan
717169689Skan      array_type = build_int_cstu (get_gcov_unsigned_t (),
718169689Skan				   prg_n_ctrs[counter] - 1);
719169689Skan      array_type = build_index_type (array_type);
720132718Skan      array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
721132718Skan				     array_type);
722132718Skan
723169689Skan      TREE_TYPE (tree_ctr_tables[counter]) = array_type;
724169689Skan      DECL_SIZE (tree_ctr_tables[counter]) = TYPE_SIZE (array_type);
725169689Skan      DECL_SIZE_UNIT (tree_ctr_tables[counter]) = TYPE_SIZE_UNIT (array_type);
726169689Skan      assemble_variable (tree_ctr_tables[counter], 0, 0, 0);
727132718Skan
728132718Skan      value = tree_cons (fields,
729169689Skan			 build1 (ADDR_EXPR, TREE_TYPE (fields),
730169689Skan					    tree_ctr_tables[counter]),
731132718Skan			 value);
732132718Skan    }
733132718Skan  else
734132718Skan    value = tree_cons (fields, null_pointer_node, value);
735132718Skan  fields = TREE_CHAIN (fields);
736132718Skan
737132718Skan  fn = build_decl (FUNCTION_DECL,
738132718Skan		   get_identifier (ctr_merge_functions[counter]),
739132718Skan		   TREE_TYPE (TREE_TYPE (fields)));
740132718Skan  DECL_EXTERNAL (fn) = 1;
741132718Skan  TREE_PUBLIC (fn) = 1;
742132718Skan  DECL_ARTIFICIAL (fn) = 1;
743132718Skan  TREE_NOTHROW (fn) = 1;
744132718Skan  value = tree_cons (fields,
745132718Skan		     build1 (ADDR_EXPR, TREE_TYPE (fields), fn),
746132718Skan		     value);
747132718Skan
748169689Skan  /* FIXME: use build_constructor directly.  */
749169689Skan  value = build_constructor_from_list (type, nreverse (value));
750132718Skan
751132718Skan  return value;
752132718Skan}
753132718Skan
754132718Skan/* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a
755132718Skan   CONSTRUCTOR.  */
756132718Skan
757132718Skanstatic tree
758132718Skanbuild_gcov_info (void)
759132718Skan{
760132718Skan  unsigned n_ctr_types, ix;
761132718Skan  tree type, const_type;
762132718Skan  tree fn_info_type, fn_info_value = NULL_TREE;
763132718Skan  tree fn_info_ptr_type;
764132718Skan  tree ctr_info_type, ctr_info_ary_type, ctr_info_value = NULL_TREE;
765132718Skan  tree field, fields = NULL_TREE;
766132718Skan  tree value = NULL_TREE;
767132718Skan  tree filename_string;
768132718Skan  char *filename;
769132718Skan  int filename_len;
770132718Skan  unsigned n_fns;
771132718Skan  const struct function_list *fn;
772132718Skan  tree string_type;
773132718Skan
774132718Skan  /* Count the number of active counters.  */
775132718Skan  for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++)
776132718Skan    if (prg_ctr_mask & (1 << ix))
777132718Skan      n_ctr_types++;
778132718Skan
779169689Skan  type = lang_hooks.types.make_type (RECORD_TYPE);
780132718Skan  const_type = build_qualified_type (type, TYPE_QUAL_CONST);
781132718Skan
782132718Skan  /* Version ident */
783169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
784132718Skan  TREE_CHAIN (field) = fields;
785132718Skan  fields = field;
786169689Skan  value = tree_cons (field, build_int_cstu (TREE_TYPE (field), GCOV_VERSION),
787132718Skan		     value);
788132718Skan
789132718Skan  /* next -- NULL */
790132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type));
791132718Skan  TREE_CHAIN (field) = fields;
792132718Skan  fields = field;
793132718Skan  value = tree_cons (field, null_pointer_node, value);
794132718Skan
795132718Skan  /* stamp */
796169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
797132718Skan  TREE_CHAIN (field) = fields;
798132718Skan  fields = field;
799169689Skan  value = tree_cons (field, build_int_cstu (TREE_TYPE (field), local_tick),
800132718Skan		     value);
801132718Skan
802132718Skan  /* Filename */
803132718Skan  string_type = build_pointer_type (build_qualified_type (char_type_node,
804132718Skan						    TYPE_QUAL_CONST));
805132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, string_type);
806132718Skan  TREE_CHAIN (field) = fields;
807132718Skan  fields = field;
808132718Skan  filename = getpwd ();
809132718Skan  filename = (filename && da_file_name[0] != '/'
810132718Skan	      ? concat (filename, "/", da_file_name, NULL)
811132718Skan	      : da_file_name);
812132718Skan  filename_len = strlen (filename);
813132718Skan  filename_string = build_string (filename_len + 1, filename);
814132718Skan  if (filename != da_file_name)
815132718Skan    free (filename);
816169689Skan  TREE_TYPE (filename_string) = build_array_type
817169689Skan    (char_type_node, build_index_type
818169689Skan     (build_int_cst (NULL_TREE, filename_len)));
819132718Skan  value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string),
820132718Skan		     value);
821132718Skan
822132718Skan  /* Build the fn_info type and initializer.  */
823132718Skan  fn_info_type = build_fn_info_type (n_ctr_types);
824132718Skan  fn_info_ptr_type = build_pointer_type (build_qualified_type
825132718Skan					 (fn_info_type, TYPE_QUAL_CONST));
826132718Skan  for (fn = functions_head, n_fns = 0; fn; fn = fn->next, n_fns++)
827132718Skan    fn_info_value = tree_cons (NULL_TREE,
828132718Skan			       build_fn_info_value (fn, fn_info_type),
829132718Skan			       fn_info_value);
830132718Skan  if (n_fns)
831132718Skan    {
832132718Skan      tree array_type;
833132718Skan
834169689Skan      array_type = build_index_type (build_int_cst (NULL_TREE, n_fns - 1));
835132718Skan      array_type = build_array_type (fn_info_type, array_type);
836132718Skan
837169689Skan      /* FIXME: use build_constructor directly.  */
838169689Skan      fn_info_value = build_constructor_from_list (array_type,
839169689Skan						   nreverse (fn_info_value));
840132718Skan      fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
841132718Skan    }
842132718Skan  else
843132718Skan    fn_info_value = null_pointer_node;
844132718Skan
845132718Skan  /* number of functions */
846169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
847132718Skan  TREE_CHAIN (field) = fields;
848132718Skan  fields = field;
849132718Skan  value = tree_cons (field,
850169689Skan		     build_int_cstu (get_gcov_unsigned_t (), n_fns),
851132718Skan		     value);
852132718Skan
853132718Skan  /* fn_info table */
854132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type);
855132718Skan  TREE_CHAIN (field) = fields;
856132718Skan  fields = field;
857132718Skan  value = tree_cons (field, fn_info_value, value);
858132718Skan
859132718Skan  /* counter_mask */
860169689Skan  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
861132718Skan  TREE_CHAIN (field) = fields;
862132718Skan  fields = field;
863132718Skan  value = tree_cons (field,
864169689Skan		     build_int_cstu (get_gcov_unsigned_t (), prg_ctr_mask),
865132718Skan		     value);
866132718Skan
867132718Skan  /* counters */
868132718Skan  ctr_info_type = build_ctr_info_type ();
869169689Skan  ctr_info_ary_type = build_index_type (build_int_cst (NULL_TREE,
870169689Skan						       n_ctr_types));
871132718Skan  ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type);
872132718Skan  for (ix = 0; ix != GCOV_COUNTERS; ix++)
873132718Skan    if (prg_ctr_mask & (1 << ix))
874132718Skan      ctr_info_value = tree_cons (NULL_TREE,
875132718Skan				  build_ctr_info_value (ix, ctr_info_type),
876132718Skan				  ctr_info_value);
877169689Skan  /* FIXME: use build_constructor directly.  */
878169689Skan  ctr_info_value = build_constructor_from_list (ctr_info_ary_type,
879169689Skan				                nreverse (ctr_info_value));
880132718Skan
881132718Skan  field = build_decl (FIELD_DECL, NULL_TREE, ctr_info_ary_type);
882132718Skan  TREE_CHAIN (field) = fields;
883132718Skan  fields = field;
884132718Skan  value = tree_cons (field, ctr_info_value, value);
885132718Skan
886132718Skan  finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
887132718Skan
888169689Skan  /* FIXME: use build_constructor directly.  */
889169689Skan  value = build_constructor_from_list (type, nreverse (value));
890132718Skan
891132718Skan  return value;
892132718Skan}
893132718Skan
894132718Skan/* Write out the structure which libgcov uses to locate all the
895132718Skan   counters.  The structures used here must match those defined in
896132718Skan   gcov-io.h.  Write out the constructor to call __gcov_init.  */
897132718Skan
898132718Skanstatic void
899132718Skancreate_coverage (void)
900132718Skan{
901169689Skan  tree gcov_info, gcov_init, body, t;
902169689Skan  char name_buf[32];
903132718Skan
904132718Skan  no_coverage = 1; /* Disable any further coverage.  */
905132718Skan
906132718Skan  if (!prg_ctr_mask)
907132718Skan    return;
908132718Skan
909169689Skan  t = build_gcov_info ();
910132718Skan
911169689Skan  gcov_info = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (t));
912132718Skan  TREE_STATIC (gcov_info) = 1;
913169689Skan  ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
914169689Skan  DECL_NAME (gcov_info) = get_identifier (name_buf);
915169689Skan  DECL_INITIAL (gcov_info) = t;
916132718Skan
917132718Skan  /* Build structure.  */
918132718Skan  assemble_variable (gcov_info, 0, 0, 0);
919132718Skan
920169689Skan  /* Build a decl for __gcov_init.  */
921169689Skan  t = build_pointer_type (TREE_TYPE (gcov_info));
922169689Skan  t = build_function_type_list (void_type_node, t, NULL);
923169689Skan  t = build_decl (FUNCTION_DECL, get_identifier ("__gcov_init"), t);
924169689Skan  TREE_PUBLIC (t) = 1;
925169689Skan  DECL_EXTERNAL (t) = 1;
926169689Skan  gcov_init = t;
927132718Skan
928169689Skan  /* Generate a call to __gcov_init(&gcov_info).  */
929169689Skan  body = NULL;
930169689Skan  t = build_fold_addr_expr (gcov_info);
931169689Skan  t = tree_cons (NULL, t, NULL);
932169689Skan  t = build_function_call_expr (gcov_init, t);
933169689Skan  append_to_statement_list (t, &body);
934132718Skan
935169689Skan  /* Generate a constructor to run it.  */
936169689Skan  cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
937132718Skan}
938132718Skan
939132718Skan/* Perform file-level initialization. Read in data file, generate name
940132718Skan   of graph file.  */
941132718Skan
942132718Skanvoid
943132718Skancoverage_init (const char *filename)
944132718Skan{
945132718Skan  int len = strlen (filename);
946132718Skan
947132718Skan  /* Name of da file.  */
948169689Skan  da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX) + 1);
949132718Skan  strcpy (da_file_name, filename);
950132718Skan  strcat (da_file_name, GCOV_DATA_SUFFIX);
951132718Skan
952132718Skan  /* Name of bbg file.  */
953169689Skan  bbg_file_name = XNEWVEC (char, len + strlen (GCOV_NOTE_SUFFIX) + 1);
954132718Skan  strcpy (bbg_file_name, filename);
955132718Skan  strcat (bbg_file_name, GCOV_NOTE_SUFFIX);
956132718Skan
957132718Skan  read_counts_file ();
958132718Skan}
959132718Skan
960132718Skan/* Performs file-level cleanup.  Close graph file, generate coverage
961132718Skan   variables and constructor.  */
962132718Skan
963132718Skanvoid
964132718Skancoverage_finish (void)
965132718Skan{
966132718Skan  create_coverage ();
967132718Skan  if (bbg_file_opened)
968132718Skan    {
969132718Skan      int error = gcov_close ();
970132718Skan
971132718Skan      if (error)
972132718Skan	unlink (bbg_file_name);
973132718Skan      if (!local_tick)
974132718Skan	/* Only remove the da file, if we cannot stamp it. If we can
975132718Skan	   stamp it, libgcov will DTRT.  */
976132718Skan	unlink (da_file_name);
977132718Skan    }
978132718Skan}
979132718Skan
980132718Skan#include "gt-coverage.h"
981