1132718Skan/* Routines required for instrumenting a program.  */
2132718Skan/* Compile this one with gcc.  */
3132718Skan/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4169689Skan   2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
5132718Skan
6132718SkanThis file is part of GCC.
7132718Skan
8132718SkanGCC is free software; you can redistribute it and/or modify it under
9132718Skanthe terms of the GNU General Public License as published by the Free
10132718SkanSoftware Foundation; either version 2, or (at your option) any later
11132718Skanversion.
12132718Skan
13132718SkanIn addition to the permissions in the GNU General Public License, the
14132718SkanFree Software Foundation gives you unlimited permission to link the
15132718Skancompiled version of this file into combinations with other programs,
16132718Skanand to distribute those combinations without any restriction coming
17132718Skanfrom the use of this file.  (The General Public License restrictions
18132718Skando apply in other respects; for example, they cover modification of
19132718Skanthe file, and distribution when not linked into a combine
20132718Skanexecutable.)
21132718Skan
22132718SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
23132718SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
24132718SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25132718Skanfor more details.
26132718Skan
27132718SkanYou should have received a copy of the GNU General Public License
28132718Skanalong with GCC; see the file COPYING.  If not, write to the Free
29169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30169689Skan02110-1301, USA.  */
31132718Skan
32132718Skan#include "tconfig.h"
33132718Skan#include "tsystem.h"
34132718Skan#include "coretypes.h"
35132718Skan#include "tm.h"
36132718Skan
37132718Skan#if defined(inhibit_libc)
38132718Skan#define IN_LIBGCOV (-1)
39132718Skan#else
40132718Skan#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
41132718Skan#include <stdio.h>
42132718Skan#define IN_LIBGCOV 1
43132718Skan#if defined(L_gcov)
44132718Skan#define GCOV_LINKAGE /* nothing */
45132718Skan#endif
46132718Skan#endif
47132718Skan#include "gcov-io.h"
48132718Skan
49132718Skan#if defined(inhibit_libc)
50132718Skan/* If libc and its header files are not available, provide dummy functions.  */
51132718Skan
52132718Skan#ifdef L_gcov
53132718Skanvoid __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
54132718Skanvoid __gcov_flush (void) {}
55132718Skan#endif
56132718Skan
57132718Skan#ifdef L_gcov_merge_add
58132718Skanvoid __gcov_merge_add (gcov_type *counters  __attribute__ ((unused)),
59132718Skan		       unsigned n_counters __attribute__ ((unused))) {}
60132718Skan#endif
61132718Skan
62132718Skan#ifdef L_gcov_merge_single
63132718Skanvoid __gcov_merge_single (gcov_type *counters  __attribute__ ((unused)),
64132718Skan			  unsigned n_counters __attribute__ ((unused))) {}
65132718Skan#endif
66132718Skan
67132718Skan#ifdef L_gcov_merge_delta
68132718Skanvoid __gcov_merge_delta (gcov_type *counters  __attribute__ ((unused)),
69132718Skan			 unsigned n_counters __attribute__ ((unused))) {}
70132718Skan#endif
71132718Skan
72132718Skan#else
73132718Skan
74132718Skan#include <string.h>
75132718Skan#if GCOV_LOCKED
76132718Skan#include <fcntl.h>
77132718Skan#include <errno.h>
78132718Skan#include <sys/stat.h>
79132718Skan#endif
80132718Skan
81132718Skan#ifdef L_gcov
82132718Skan#include "gcov-io.c"
83132718Skan
84132718Skan/* Chain of per-object gcov structures.  */
85132718Skanstatic struct gcov_info *gcov_list;
86132718Skan
87132718Skan/* A program checksum allows us to distinguish program data for an
88132718Skan   object file included in multiple programs.  */
89132718Skanstatic gcov_unsigned_t gcov_crc32;
90132718Skan
91169689Skan/* Size of the longest file name. */
92169689Skanstatic size_t gcov_max_filename = 0;
93169689Skan
94169689Skan#ifdef TARGET_POSIX_IO
95169689Skan/* Make sure path component of the given FILENAME exists, create
96169689Skan   missing directories. FILENAME must be writable.
97169689Skan   Returns zero on success, or -1 if an error occurred.  */
98169689Skan
99132718Skanstatic int
100169689Skancreate_file_directory (char *filename)
101132718Skan{
102169689Skan  char *s;
103169689Skan
104169689Skan  for (s = filename + 1; *s != '\0'; s++)
105169689Skan    if (IS_DIR_SEPARATOR(*s))
106169689Skan      {
107169689Skan        char sep = *s;
108169689Skan	*s  = '\0';
109169689Skan
110169689Skan        /* Try to make directory if it doesn't already exist.  */
111169689Skan        if (access (filename, F_OK) == -1
112169689Skan            && mkdir (filename, 0755) == -1
113169689Skan            /* The directory might have been made by another process.  */
114169689Skan	    && errno != EEXIST)
115169689Skan	  {
116169689Skan            fprintf (stderr, "profiling:%s:Cannot create directory\n",
117169689Skan		     filename);
118169689Skan            *s = sep;
119169689Skan	    return -1;
120169689Skan	  };
121169689Skan
122169689Skan	*s = sep;
123169689Skan      };
124169689Skan  return 0;
125169689Skan}
126169689Skan#endif
127169689Skan
128169689Skan/* Check if VERSION of the info block PTR matches libgcov one.
129169689Skan   Return 1 on success, or zero in case of versions mismatch.
130169689Skan   If FILENAME is not NULL, its value used for reporting purposes
131169689Skan   instead of value from the info block.  */
132169689Skan
133169689Skanstatic int
134169689Skangcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
135169689Skan	      const char *filename)
136169689Skan{
137132718Skan  if (version != GCOV_VERSION)
138132718Skan    {
139132718Skan      char v[4], e[4];
140132718Skan
141132718Skan      GCOV_UNSIGNED2STRING (v, version);
142132718Skan      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
143132718Skan
144132718Skan      fprintf (stderr,
145132718Skan	       "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
146169689Skan	       filename? filename : ptr->filename, e, v);
147132718Skan      return 0;
148132718Skan    }
149132718Skan  return 1;
150132718Skan}
151132718Skan
152132718Skan/* Dump the coverage counts. We merge with existing counts when
153132718Skan   possible, to avoid growing the .da files ad infinitum. We use this
154132718Skan   program's checksum to make sure we only accumulate whole program
155132718Skan   statistics to the correct summary. An object file might be embedded
156132718Skan   in two separate programs, and we must keep the two program
157132718Skan   summaries separate.  */
158132718Skan
159132718Skanstatic void
160132718Skangcov_exit (void)
161132718Skan{
162132718Skan  struct gcov_info *gi_ptr;
163132718Skan  struct gcov_summary this_program;
164132718Skan  struct gcov_summary all;
165132718Skan  struct gcov_ctr_summary *cs_ptr;
166132718Skan  const struct gcov_ctr_info *ci_ptr;
167132718Skan  unsigned t_ix;
168132718Skan  gcov_unsigned_t c_num;
169169689Skan  const char *gcov_prefix;
170169689Skan  int gcov_prefix_strip = 0;
171169689Skan  size_t prefix_length;
172169689Skan  char *gi_filename, *gi_filename_up;
173132718Skan
174132718Skan  memset (&all, 0, sizeof (all));
175132718Skan  /* Find the totals for this execution.  */
176132718Skan  memset (&this_program, 0, sizeof (this_program));
177132718Skan  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
178132718Skan    {
179132718Skan      ci_ptr = gi_ptr->counts;
180132718Skan      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
181132718Skan	{
182132718Skan	  if (!((1 << t_ix) & gi_ptr->ctr_mask))
183132718Skan	    continue;
184132718Skan
185132718Skan	  cs_ptr = &this_program.ctrs[t_ix];
186132718Skan	  cs_ptr->num += ci_ptr->num;
187132718Skan	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
188132718Skan	    {
189132718Skan      	      cs_ptr->sum_all += ci_ptr->values[c_num];
190132718Skan	      if (cs_ptr->run_max < ci_ptr->values[c_num])
191132718Skan		cs_ptr->run_max = ci_ptr->values[c_num];
192132718Skan	    }
193132718Skan	  ci_ptr++;
194132718Skan	}
195132718Skan    }
196132718Skan
197169689Skan  /* Get file name relocation prefix.  Non-absolute values are ignored. */
198169689Skan  gcov_prefix = getenv("GCOV_PREFIX");
199169689Skan  if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix))
200169689Skan    {
201169689Skan      /* Check if the level of dirs to strip off specified. */
202169689Skan      char *tmp = getenv("GCOV_PREFIX_STRIP");
203169689Skan      if (tmp)
204169689Skan        {
205169689Skan          gcov_prefix_strip = atoi (tmp);
206169689Skan          /* Do not consider negative values. */
207169689Skan          if (gcov_prefix_strip < 0)
208169689Skan            gcov_prefix_strip = 0;
209169689Skan        }
210169689Skan
211169689Skan      prefix_length = strlen(gcov_prefix);
212169689Skan
213169689Skan      /* Remove an unnecessary trailing '/' */
214169689Skan      if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
215169689Skan	prefix_length--;
216169689Skan    }
217169689Skan  else
218169689Skan    prefix_length = 0;
219169689Skan
220169689Skan  /* Allocate and initialize the filename scratch space.  */
221169689Skan  gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 1);
222169689Skan  if (prefix_length)
223169689Skan    memcpy (gi_filename, gcov_prefix, prefix_length);
224169689Skan  gi_filename_up = gi_filename + prefix_length;
225169689Skan
226132718Skan  /* Now merge each file.  */
227132718Skan  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
228132718Skan    {
229132718Skan      struct gcov_summary this_object;
230132718Skan      struct gcov_summary object, program;
231132718Skan      gcov_type *values[GCOV_COUNTERS];
232132718Skan      const struct gcov_fn_info *fi_ptr;
233132718Skan      unsigned fi_stride;
234132718Skan      unsigned c_ix, f_ix, n_counts;
235132718Skan      struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
236132718Skan      int error = 0;
237132718Skan      gcov_unsigned_t tag, length;
238132718Skan      gcov_position_t summary_pos = 0;
239169689Skan      gcov_position_t eof_pos = 0;
240132718Skan
241132718Skan      memset (&this_object, 0, sizeof (this_object));
242132718Skan      memset (&object, 0, sizeof (object));
243132718Skan
244169689Skan      /* Build relocated filename, stripping off leading
245169689Skan         directories from the initial filename if requested. */
246169689Skan      if (gcov_prefix_strip > 0)
247169689Skan        {
248169689Skan          int level = 0;
249169689Skan          const char *fname = gi_ptr->filename;
250169689Skan          const char *s;
251169689Skan
252169689Skan          /* Skip selected directory levels. */
253169689Skan	  for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
254169689Skan	    if (IS_DIR_SEPARATOR(*s))
255169689Skan	      {
256169689Skan		fname = s;
257169689Skan		level++;
258169689Skan	      };
259169689Skan
260169689Skan          /* Update complete filename with stripped original. */
261169689Skan          strcpy (gi_filename_up, fname);
262169689Skan        }
263169689Skan      else
264169689Skan        strcpy (gi_filename_up, gi_ptr->filename);
265169689Skan
266132718Skan      /* Totals for this object file.  */
267132718Skan      ci_ptr = gi_ptr->counts;
268132718Skan      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
269132718Skan	{
270132718Skan	  if (!((1 << t_ix) & gi_ptr->ctr_mask))
271132718Skan	    continue;
272132718Skan
273132718Skan	  cs_ptr = &this_object.ctrs[t_ix];
274132718Skan	  cs_ptr->num += ci_ptr->num;
275132718Skan	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
276132718Skan	    {
277132718Skan	      cs_ptr->sum_all += ci_ptr->values[c_num];
278132718Skan	      if (cs_ptr->run_max < ci_ptr->values[c_num])
279132718Skan		cs_ptr->run_max = ci_ptr->values[c_num];
280132718Skan	    }
281132718Skan
282132718Skan	  ci_ptr++;
283132718Skan	}
284132718Skan
285132718Skan      c_ix = 0;
286132718Skan      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
287132718Skan	if ((1 << t_ix) & gi_ptr->ctr_mask)
288132718Skan	  {
289132718Skan	    values[c_ix] = gi_ptr->counts[c_ix].values;
290132718Skan	    c_ix++;
291132718Skan	  }
292132718Skan
293132718Skan      /* Calculate the function_info stride. This depends on the
294132718Skan	 number of counter types being measured.  */
295132718Skan      fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
296132718Skan      if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
297132718Skan	{
298132718Skan	  fi_stride += __alignof__ (struct gcov_fn_info) - 1;
299132718Skan	  fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
300132718Skan	}
301132718Skan
302169689Skan      if (!gcov_open (gi_filename))
303132718Skan	{
304169689Skan#ifdef TARGET_POSIX_IO
305169689Skan	  /* Open failed likely due to missed directory.
306169689Skan	     Create directory and retry to open file. */
307169689Skan          if (create_file_directory (gi_filename))
308169689Skan	    {
309169689Skan	      fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
310169689Skan	      continue;
311169689Skan	    }
312169689Skan#endif
313169689Skan	  if (!gcov_open (gi_filename))
314169689Skan	    {
315169689Skan              fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
316169689Skan	      continue;
317169689Skan	    }
318132718Skan	}
319132718Skan
320132718Skan      tag = gcov_read_unsigned ();
321132718Skan      if (tag)
322132718Skan	{
323132718Skan	  /* Merge data from file.  */
324132718Skan	  if (tag != GCOV_DATA_MAGIC)
325132718Skan	    {
326132718Skan	      fprintf (stderr, "profiling:%s:Not a gcov data file\n",
327169689Skan		       gi_filename);
328169689Skan	      goto read_fatal;
329132718Skan	    }
330132718Skan	  length = gcov_read_unsigned ();
331169689Skan	  if (!gcov_version (gi_ptr, length, gi_filename))
332132718Skan	    goto read_fatal;
333132718Skan
334132718Skan	  length = gcov_read_unsigned ();
335132718Skan	  if (length != gi_ptr->stamp)
336169689Skan	    /* Read from a different compilation. Overwrite the file.  */
337169689Skan	    goto rewrite;
338132718Skan
339132718Skan	  /* Merge execution counts for each function.  */
340132718Skan	  for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
341132718Skan	    {
342132718Skan	      fi_ptr = (const struct gcov_fn_info *)
343132718Skan		      ((const char *) gi_ptr->functions + f_ix * fi_stride);
344132718Skan	      tag = gcov_read_unsigned ();
345132718Skan	      length = gcov_read_unsigned ();
346132718Skan
347132718Skan	      /* Check function.  */
348132718Skan	      if (tag != GCOV_TAG_FUNCTION
349132718Skan		  || length != GCOV_TAG_FUNCTION_LENGTH
350132718Skan		  || gcov_read_unsigned () != fi_ptr->ident
351132718Skan		  || gcov_read_unsigned () != fi_ptr->checksum)
352132718Skan		{
353132718Skan		read_mismatch:;
354132718Skan		  fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
355169689Skan			   gi_filename,
356132718Skan			   f_ix + 1 ? "function" : "summaries");
357132718Skan		  goto read_fatal;
358132718Skan		}
359132718Skan
360132718Skan	      c_ix = 0;
361132718Skan	      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
362132718Skan		{
363132718Skan		  gcov_merge_fn merge;
364132718Skan
365132718Skan		  if (!((1 << t_ix) & gi_ptr->ctr_mask))
366132718Skan		    continue;
367132718Skan
368132718Skan		  n_counts = fi_ptr->n_ctrs[c_ix];
369132718Skan		  merge = gi_ptr->counts[c_ix].merge;
370132718Skan
371132718Skan		  tag = gcov_read_unsigned ();
372132718Skan		  length = gcov_read_unsigned ();
373132718Skan		  if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
374132718Skan		      || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
375132718Skan		    goto read_mismatch;
376132718Skan		  (*merge) (values[c_ix], n_counts);
377132718Skan		  values[c_ix] += n_counts;
378132718Skan		  c_ix++;
379132718Skan		}
380132718Skan	      if ((error = gcov_is_error ()))
381132718Skan		goto read_error;
382132718Skan	    }
383132718Skan
384132718Skan	  f_ix = ~0u;
385132718Skan	  /* Check program & object summary */
386132718Skan	  while (1)
387132718Skan	    {
388132718Skan	      int is_program;
389132718Skan
390169689Skan	      eof_pos = gcov_position ();
391132718Skan	      tag = gcov_read_unsigned ();
392132718Skan	      if (!tag)
393132718Skan		break;
394169689Skan
395132718Skan	      length = gcov_read_unsigned ();
396132718Skan	      is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
397132718Skan	      if (length != GCOV_TAG_SUMMARY_LENGTH
398132718Skan		  || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
399132718Skan		goto read_mismatch;
400132718Skan	      gcov_read_summary (is_program ? &program : &object);
401132718Skan	      if ((error = gcov_is_error ()))
402132718Skan		goto read_error;
403132718Skan	      if (is_program && program.checksum == gcov_crc32)
404132718Skan		{
405169689Skan		  summary_pos = eof_pos;
406132718Skan		  goto rewrite;
407132718Skan		}
408132718Skan	    }
409132718Skan	}
410169689Skan      goto rewrite;
411132718Skan
412169689Skan    read_error:;
413169689Skan      fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
414169689Skan	       : "profiling:%s:Error merging\n", gi_filename);
415169689Skan
416169689Skan    read_fatal:;
417169689Skan      gcov_close ();
418169689Skan      continue;
419169689Skan
420132718Skan    rewrite:;
421132718Skan      gcov_rewrite ();
422132718Skan      if (!summary_pos)
423132718Skan	memset (&program, 0, sizeof (program));
424132718Skan
425132718Skan      /* Merge the summaries.  */
426132718Skan      f_ix = ~0u;
427132718Skan      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
428132718Skan	{
429132718Skan	  cs_obj = &object.ctrs[t_ix];
430132718Skan	  cs_tobj = &this_object.ctrs[t_ix];
431132718Skan	  cs_prg = &program.ctrs[t_ix];
432132718Skan	  cs_tprg = &this_program.ctrs[t_ix];
433132718Skan	  cs_all = &all.ctrs[t_ix];
434132718Skan
435132718Skan	  if ((1 << t_ix) & gi_ptr->ctr_mask)
436132718Skan	    {
437132718Skan	      if (!cs_obj->runs++)
438132718Skan		cs_obj->num = cs_tobj->num;
439132718Skan	      else if (cs_obj->num != cs_tobj->num)
440132718Skan		goto read_mismatch;
441132718Skan	      cs_obj->sum_all += cs_tobj->sum_all;
442132718Skan	      if (cs_obj->run_max < cs_tobj->run_max)
443132718Skan		cs_obj->run_max = cs_tobj->run_max;
444132718Skan	      cs_obj->sum_max += cs_tobj->run_max;
445132718Skan
446132718Skan	      if (!cs_prg->runs++)
447132718Skan		cs_prg->num = cs_tprg->num;
448132718Skan	      else if (cs_prg->num != cs_tprg->num)
449132718Skan		goto read_mismatch;
450132718Skan	      cs_prg->sum_all += cs_tprg->sum_all;
451132718Skan	      if (cs_prg->run_max < cs_tprg->run_max)
452132718Skan		cs_prg->run_max = cs_tprg->run_max;
453132718Skan	      cs_prg->sum_max += cs_tprg->run_max;
454132718Skan	    }
455132718Skan	  else if (cs_obj->num || cs_prg->num)
456132718Skan	    goto read_mismatch;
457132718Skan
458132718Skan	  if (!cs_all->runs && cs_prg->runs)
459132718Skan	    memcpy (cs_all, cs_prg, sizeof (*cs_all));
460132718Skan	  else if (!all.checksum
461132718Skan		   && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
462132718Skan		   && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
463132718Skan	    {
464132718Skan	      fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
465169689Skan		       gi_filename, GCOV_LOCKED
466132718Skan		       ? "" : " or concurrent update without locking support");
467132718Skan	      all.checksum = ~0u;
468132718Skan	    }
469132718Skan	}
470132718Skan
471132718Skan      c_ix = 0;
472132718Skan      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
473132718Skan	if ((1 << t_ix) & gi_ptr->ctr_mask)
474132718Skan	  {
475132718Skan	    values[c_ix] = gi_ptr->counts[c_ix].values;
476132718Skan	    c_ix++;
477132718Skan	  }
478132718Skan
479132718Skan      program.checksum = gcov_crc32;
480132718Skan
481132718Skan      /* Write out the data.  */
482132718Skan      gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
483132718Skan      gcov_write_unsigned (gi_ptr->stamp);
484132718Skan
485132718Skan      /* Write execution counts for each function.  */
486132718Skan      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
487132718Skan	{
488132718Skan	  fi_ptr = (const struct gcov_fn_info *)
489132718Skan		  ((const char *) gi_ptr->functions + f_ix * fi_stride);
490132718Skan
491132718Skan	  /* Announce function.  */
492132718Skan	  gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
493132718Skan	  gcov_write_unsigned (fi_ptr->ident);
494132718Skan	  gcov_write_unsigned (fi_ptr->checksum);
495132718Skan
496132718Skan	  c_ix = 0;
497132718Skan	  for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
498132718Skan	    {
499132718Skan	      gcov_type *c_ptr;
500132718Skan
501132718Skan	      if (!((1 << t_ix) & gi_ptr->ctr_mask))
502132718Skan		continue;
503132718Skan
504132718Skan	      n_counts = fi_ptr->n_ctrs[c_ix];
505132718Skan
506132718Skan	      gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
507132718Skan				     GCOV_TAG_COUNTER_LENGTH (n_counts));
508132718Skan	      c_ptr = values[c_ix];
509132718Skan	      while (n_counts--)
510132718Skan		gcov_write_counter (*c_ptr++);
511132718Skan
512132718Skan	      values[c_ix] = c_ptr;
513132718Skan	      c_ix++;
514132718Skan	    }
515132718Skan	}
516132718Skan
517132718Skan      /* Object file summary.  */
518132718Skan      gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
519132718Skan
520132718Skan      /* Generate whole program statistics.  */
521169689Skan      if (eof_pos)
522169689Skan	gcov_seek (eof_pos);
523132718Skan      gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
524169689Skan      if (!summary_pos)
525169689Skan	gcov_write_unsigned (0);
526132718Skan      if ((error = gcov_close ()))
527132718Skan	  fprintf (stderr, error  < 0 ?
528132718Skan		   "profiling:%s:Overflow writing\n" :
529132718Skan		   "profiling:%s:Error writing\n",
530169689Skan		   gi_filename);
531132718Skan    }
532132718Skan}
533132718Skan
534132718Skan/* Add a new object file onto the bb chain.  Invoked automatically
535132718Skan   when running an object file's global ctors.  */
536132718Skan
537132718Skanvoid
538132718Skan__gcov_init (struct gcov_info *info)
539132718Skan{
540132718Skan  if (!info->version)
541132718Skan    return;
542169689Skan  if (gcov_version (info, info->version, 0))
543132718Skan    {
544132718Skan      const char *ptr = info->filename;
545132718Skan      gcov_unsigned_t crc32 = gcov_crc32;
546169689Skan      size_t filename_length =  strlen(info->filename);
547169689Skan
548169689Skan      /* Refresh the longest file name information */
549169689Skan      if (filename_length > gcov_max_filename)
550169689Skan        gcov_max_filename = filename_length;
551169689Skan
552132718Skan      do
553132718Skan	{
554132718Skan	  unsigned ix;
555132718Skan	  gcov_unsigned_t value = *ptr << 24;
556132718Skan
557132718Skan	  for (ix = 8; ix--; value <<= 1)
558132718Skan	    {
559132718Skan	      gcov_unsigned_t feedback;
560132718Skan
561132718Skan	      feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
562132718Skan	      crc32 <<= 1;
563132718Skan	      crc32 ^= feedback;
564132718Skan	    }
565132718Skan	}
566132718Skan      while (*ptr++);
567132718Skan
568132718Skan      gcov_crc32 = crc32;
569132718Skan
570132718Skan      if (!gcov_list)
571132718Skan	atexit (gcov_exit);
572132718Skan
573132718Skan      info->next = gcov_list;
574132718Skan      gcov_list = info;
575132718Skan    }
576132718Skan  info->version = 0;
577132718Skan}
578132718Skan
579132718Skan/* Called before fork or exec - write out profile information gathered so
580132718Skan   far and reset it to zero.  This avoids duplication or loss of the
581132718Skan   profile information gathered so far.  */
582132718Skan
583132718Skanvoid
584132718Skan__gcov_flush (void)
585132718Skan{
586132718Skan  const struct gcov_info *gi_ptr;
587132718Skan
588132718Skan  gcov_exit ();
589132718Skan  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
590132718Skan    {
591132718Skan      unsigned t_ix;
592132718Skan      const struct gcov_ctr_info *ci_ptr;
593132718Skan
594132718Skan      for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
595132718Skan	if ((1 << t_ix) & gi_ptr->ctr_mask)
596132718Skan	  {
597132718Skan	    memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
598132718Skan	    ci_ptr++;
599132718Skan	  }
600132718Skan    }
601132718Skan}
602132718Skan
603132718Skan#endif /* L_gcov */
604132718Skan
605132718Skan#ifdef L_gcov_merge_add
606132718Skan/* The profile merging function that just adds the counters.  It is given
607132718Skan   an array COUNTERS of N_COUNTERS old counters and it reads the same number
608132718Skan   of counters from the gcov file.  */
609132718Skanvoid
610132718Skan__gcov_merge_add (gcov_type *counters, unsigned n_counters)
611132718Skan{
612132718Skan  for (; n_counters; counters++, n_counters--)
613132718Skan    *counters += gcov_read_counter ();
614132718Skan}
615132718Skan#endif /* L_gcov_merge_add */
616132718Skan
617132718Skan#ifdef L_gcov_merge_single
618132718Skan/* The profile merging function for choosing the most common value.
619132718Skan   It is given an array COUNTERS of N_COUNTERS old counters and it
620132718Skan   reads the same number of counters from the gcov file.  The counters
621132718Skan   are split into 3-tuples where the members of the tuple have
622132718Skan   meanings:
623132718Skan
624132718Skan   -- the stored candidate on the most common value of the measured entity
625132718Skan   -- counter
626132718Skan   -- total number of evaluations of the value  */
627132718Skanvoid
628132718Skan__gcov_merge_single (gcov_type *counters, unsigned n_counters)
629132718Skan{
630132718Skan  unsigned i, n_measures;
631132718Skan  gcov_type value, counter, all;
632132718Skan
633169689Skan  gcc_assert (!(n_counters % 3));
634132718Skan  n_measures = n_counters / 3;
635132718Skan  for (i = 0; i < n_measures; i++, counters += 3)
636132718Skan    {
637132718Skan      value = gcov_read_counter ();
638132718Skan      counter = gcov_read_counter ();
639132718Skan      all = gcov_read_counter ();
640132718Skan
641132718Skan      if (counters[0] == value)
642132718Skan	counters[1] += counter;
643132718Skan      else if (counter > counters[1])
644132718Skan	{
645132718Skan	  counters[0] = value;
646132718Skan	  counters[1] = counter - counters[1];
647132718Skan	}
648132718Skan      else
649132718Skan	counters[1] -= counter;
650132718Skan      counters[2] += all;
651132718Skan    }
652132718Skan}
653132718Skan#endif /* L_gcov_merge_single */
654132718Skan
655132718Skan#ifdef L_gcov_merge_delta
656132718Skan/* The profile merging function for choosing the most common
657132718Skan   difference between two consecutive evaluations of the value.  It is
658132718Skan   given an array COUNTERS of N_COUNTERS old counters and it reads the
659132718Skan   same number of counters from the gcov file.  The counters are split
660132718Skan   into 4-tuples where the members of the tuple have meanings:
661132718Skan
662132718Skan   -- the last value of the measured entity
663132718Skan   -- the stored candidate on the most common difference
664132718Skan   -- counter
665132718Skan   -- total number of evaluations of the value  */
666132718Skanvoid
667132718Skan__gcov_merge_delta (gcov_type *counters, unsigned n_counters)
668132718Skan{
669132718Skan  unsigned i, n_measures;
670132718Skan  gcov_type last, value, counter, all;
671132718Skan
672169689Skan  gcc_assert (!(n_counters % 4));
673132718Skan  n_measures = n_counters / 4;
674132718Skan  for (i = 0; i < n_measures; i++, counters += 4)
675132718Skan    {
676132718Skan      last = gcov_read_counter ();
677132718Skan      value = gcov_read_counter ();
678132718Skan      counter = gcov_read_counter ();
679132718Skan      all = gcov_read_counter ();
680132718Skan
681132718Skan      if (counters[1] == value)
682132718Skan	counters[2] += counter;
683132718Skan      else if (counter > counters[2])
684132718Skan	{
685132718Skan	  counters[1] = value;
686132718Skan	  counters[2] = counter - counters[2];
687132718Skan	}
688132718Skan      else
689132718Skan	counters[2] -= counter;
690132718Skan      counters[3] += all;
691132718Skan    }
692132718Skan}
693132718Skan#endif /* L_gcov_merge_delta */
694132718Skan
695169689Skan#ifdef L_gcov_interval_profiler
696169689Skan/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
697169689Skan   corresponding counter in COUNTERS.  If the VALUE is above or below
698169689Skan   the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
699169689Skan   instead.  */
700169689Skan
701169689Skanvoid
702169689Skan__gcov_interval_profiler (gcov_type *counters, gcov_type value,
703169689Skan			  int start, unsigned steps)
704169689Skan{
705169689Skan  gcov_type delta = value - start;
706169689Skan  if (delta < 0)
707169689Skan    counters[steps + 1]++;
708169689Skan  else if (delta >= steps)
709169689Skan    counters[steps]++;
710169689Skan  else
711169689Skan    counters[delta]++;
712169689Skan}
713169689Skan#endif
714169689Skan
715169689Skan#ifdef L_gcov_pow2_profiler
716169689Skan/* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
717169689Skan   COUNTERS[0] is incremented.  */
718169689Skan
719169689Skanvoid
720169689Skan__gcov_pow2_profiler (gcov_type *counters, gcov_type value)
721169689Skan{
722169689Skan  if (value & (value - 1))
723169689Skan    counters[0]++;
724169689Skan  else
725169689Skan    counters[1]++;
726169689Skan}
727169689Skan#endif
728169689Skan
729169689Skan#ifdef L_gcov_one_value_profiler
730169689Skan/* Tries to determine the most common value among its inputs.  Checks if the
731169689Skan   value stored in COUNTERS[0] matches VALUE.  If this is the case, COUNTERS[1]
732169689Skan   is incremented.  If this is not the case and COUNTERS[1] is not zero,
733169689Skan   COUNTERS[1] is decremented.  Otherwise COUNTERS[1] is set to one and
734169689Skan   VALUE is stored to COUNTERS[0].  This algorithm guarantees that if this
735169689Skan   function is called more than 50% of the time with one value, this value
736169689Skan   will be in COUNTERS[0] in the end.
737169689Skan
738169689Skan   In any case, COUNTERS[2] is incremented.  */
739169689Skan
740169689Skanvoid
741169689Skan__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
742169689Skan{
743169689Skan  if (value == counters[0])
744169689Skan    counters[1]++;
745169689Skan  else if (counters[1] == 0)
746169689Skan    {
747169689Skan      counters[1] = 1;
748169689Skan      counters[0] = value;
749169689Skan    }
750169689Skan  else
751169689Skan    counters[1]--;
752169689Skan  counters[2]++;
753169689Skan}
754169689Skan#endif
755169689Skan
756169689Skan#ifdef L_gcov_fork
757169689Skan/* A wrapper for the fork function.  Flushes the accumulated profiling data, so
758169689Skan   that they are not counted twice.  */
759169689Skan
760169689Skanpid_t
761169689Skan__gcov_fork (void)
762169689Skan{
763169689Skan  __gcov_flush ();
764169689Skan  return fork ();
765169689Skan}
766169689Skan#endif
767169689Skan
768169689Skan#ifdef L_gcov_execl
769169689Skan/* A wrapper for the execl function.  Flushes the accumulated profiling data, so
770169689Skan   that they are not lost.  */
771169689Skan
772169689Skanint
773169689Skan__gcov_execl (const char *path, const char *arg, ...)
774169689Skan{
775169689Skan  va_list ap, aq;
776169689Skan  unsigned i, length;
777169689Skan  char **args;
778169689Skan
779169689Skan  __gcov_flush ();
780169689Skan
781169689Skan  va_start (ap, arg);
782169689Skan  va_copy (aq, ap);
783169689Skan
784169689Skan  length = 2;
785169689Skan  while (va_arg (ap, char *))
786169689Skan    length++;
787169689Skan  va_end (ap);
788169689Skan
789169689Skan  args = (char **) alloca (length * sizeof (void *));
790169689Skan  args[0] = (char *) arg;
791169689Skan  for (i = 1; i < length; i++)
792169689Skan    args[i] = va_arg (aq, char *);
793169689Skan  va_end (aq);
794169689Skan
795169689Skan  return execv (path, args);
796169689Skan}
797169689Skan#endif
798169689Skan
799169689Skan#ifdef L_gcov_execlp
800169689Skan/* A wrapper for the execlp function.  Flushes the accumulated profiling data, so
801169689Skan   that they are not lost.  */
802169689Skan
803169689Skanint
804169689Skan__gcov_execlp (const char *path, const char *arg, ...)
805169689Skan{
806169689Skan  va_list ap, aq;
807169689Skan  unsigned i, length;
808169689Skan  char **args;
809169689Skan
810169689Skan  __gcov_flush ();
811169689Skan
812169689Skan  va_start (ap, arg);
813169689Skan  va_copy (aq, ap);
814169689Skan
815169689Skan  length = 2;
816169689Skan  while (va_arg (ap, char *))
817169689Skan    length++;
818169689Skan  va_end (ap);
819169689Skan
820169689Skan  args = (char **) alloca (length * sizeof (void *));
821169689Skan  args[0] = (char *) arg;
822169689Skan  for (i = 1; i < length; i++)
823169689Skan    args[i] = va_arg (aq, char *);
824169689Skan  va_end (aq);
825169689Skan
826169689Skan  return execvp (path, args);
827169689Skan}
828169689Skan#endif
829169689Skan
830169689Skan#ifdef L_gcov_execle
831169689Skan/* A wrapper for the execle function.  Flushes the accumulated profiling data, so
832169689Skan   that they are not lost.  */
833169689Skan
834169689Skanint
835169689Skan__gcov_execle (const char *path, const char *arg, ...)
836169689Skan{
837169689Skan  va_list ap, aq;
838169689Skan  unsigned i, length;
839169689Skan  char **args;
840169689Skan  char **envp;
841169689Skan
842169689Skan  __gcov_flush ();
843169689Skan
844169689Skan  va_start (ap, arg);
845169689Skan  va_copy (aq, ap);
846169689Skan
847169689Skan  length = 2;
848169689Skan  while (va_arg (ap, char *))
849169689Skan    length++;
850169689Skan  va_end (ap);
851169689Skan
852169689Skan  args = (char **) alloca (length * sizeof (void *));
853169689Skan  args[0] = (char *) arg;
854169689Skan  for (i = 1; i < length; i++)
855169689Skan    args[i] = va_arg (aq, char *);
856169689Skan  envp = va_arg (aq, char **);
857169689Skan  va_end (aq);
858169689Skan
859169689Skan  return execve (path, args, envp);
860169689Skan}
861169689Skan#endif
862169689Skan
863169689Skan#ifdef L_gcov_execv
864169689Skan/* A wrapper for the execv function.  Flushes the accumulated profiling data, so
865169689Skan   that they are not lost.  */
866169689Skan
867169689Skanint
868169689Skan__gcov_execv (const char *path, char *const argv[])
869169689Skan{
870169689Skan  __gcov_flush ();
871169689Skan  return execv (path, argv);
872169689Skan}
873169689Skan#endif
874169689Skan
875169689Skan#ifdef L_gcov_execvp
876169689Skan/* A wrapper for the execvp function.  Flushes the accumulated profiling data, so
877169689Skan   that they are not lost.  */
878169689Skan
879169689Skanint
880169689Skan__gcov_execvp (const char *path, char *const argv[])
881169689Skan{
882169689Skan  __gcov_flush ();
883169689Skan  return execvp (path, argv);
884169689Skan}
885169689Skan#endif
886169689Skan
887169689Skan#ifdef L_gcov_execve
888169689Skan/* A wrapper for the execve function.  Flushes the accumulated profiling data, so
889169689Skan   that they are not lost.  */
890169689Skan
891169689Skanint
892169689Skan__gcov_execve (const char *path, char *const argv[], char *const envp[])
893169689Skan{
894169689Skan  __gcov_flush ();
895169689Skan  return execve (path, argv, envp);
896169689Skan}
897169689Skan#endif
898132718Skan#endif /* inhibit_libc */
899