xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/libgcov-driver.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /* Routines required for instrumenting a program.  */
2 /* Compile this one with gcc.  */
3 /* Copyright (C) 1989-2019 Free Software Foundation, Inc.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20 
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 <http://www.gnu.org/licenses/>.  */
25 
26 #include "libgcov.h"
27 #include "gcov-io.h"
28 
29 #if defined(inhibit_libc)
30 /* If libc and its header files are not available, provide dummy functions.  */
31 
32 #if defined(L_gcov)
33 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
34 #endif
35 
36 #else /* inhibit_libc */
37 
38 #include <string.h>
39 #if GCOV_LOCKED
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <sys/stat.h>
43 #endif
44 
45 #ifdef L_gcov
46 
47 /* A utility function for outputting errors.  */
48 static int gcov_error (const char *, ...);
49 
50 #if !IN_GCOV_TOOL
51 static void gcov_error_exit (void);
52 #endif
53 
54 #include "gcov-io.c"
55 
56 #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
57 
58 struct gcov_fn_buffer
59 {
60   struct gcov_fn_buffer *next;
61   unsigned fn_ix;
62   struct gcov_fn_info info;
63   /* note gcov_fn_info ends in a trailing array.  */
64 };
65 
66 struct gcov_summary_buffer
67 {
68   struct gcov_summary_buffer *next;
69   struct gcov_summary summary;
70 };
71 
72 /* A struct that bundles all the related information about the
73    gcda filename.  */
74 
75 struct gcov_filename
76 {
77   char *filename;  /* filename buffer */
78   int strip; /* leading chars to strip from filename */
79   char *prefix; /* prefix string */
80 };
81 
82 static struct gcov_fn_buffer *
83 free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
84               unsigned limit)
85 {
86   struct gcov_fn_buffer *next;
87   unsigned ix, n_ctr = 0;
88 
89   if (!buffer)
90     return 0;
91   next = buffer->next;
92 
93   for (ix = 0; ix != limit; ix++)
94     if (gi_ptr->merge[ix])
95       free (buffer->info.ctrs[n_ctr++].values);
96   free (buffer);
97   return next;
98 }
99 
100 static struct gcov_fn_buffer **
101 buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
102                 struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
103 {
104   unsigned n_ctrs = 0, ix = 0;
105   struct gcov_fn_buffer *fn_buffer;
106   unsigned len;
107 
108   for (ix = GCOV_COUNTERS; ix--;)
109     if (gi_ptr->merge[ix])
110       n_ctrs++;
111 
112   len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
113   fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
114 
115   if (!fn_buffer)
116     goto fail;
117 
118   fn_buffer->next = 0;
119   fn_buffer->fn_ix = fn_ix;
120   fn_buffer->info.ident = gcov_read_unsigned ();
121   fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
122   fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
123 
124   for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
125     {
126       gcov_unsigned_t length;
127       gcov_type *values;
128 
129       if (!gi_ptr->merge[ix])
130         continue;
131 
132       if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
133         {
134           len = 0;
135           goto fail;
136         }
137 
138       length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
139       len = length * sizeof (gcov_type);
140       values = (gcov_type *) xmalloc (len);
141       if (!values)
142         goto fail;
143 
144       fn_buffer->info.ctrs[n_ctrs].num = length;
145       fn_buffer->info.ctrs[n_ctrs].values = values;
146 
147       while (length--)
148         *values++ = gcov_read_counter ();
149       n_ctrs++;
150     }
151 
152   *end_ptr = fn_buffer;
153   return &fn_buffer->next;
154 
155 fail:
156   gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
157               len ? "cannot allocate" : "counter mismatch", len ? len : ix);
158 
159   return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
160 }
161 
162 /* Convert VERSION into a string description and return the it.
163    BUFFER is used for storage of the string.  The code should be
164    aligned wit gcov-iov.c.  */
165 
166 static char *
167 gcov_version_string (char *buffer, char version[4])
168 {
169   if (version[0] < 'A' || version[0] > 'Z'
170       || version[1] < '0' || version[1] > '9'
171       || version[2] < '0' || version[2] > '9')
172     sprintf (buffer, "(unknown)");
173   else
174     {
175       unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
176       unsigned minor = version[2] - '0';
177       sprintf (buffer, "%u.%u (%s)", major, minor,
178 	       version[3] == '*' ? "release" : "experimental");
179     }
180   return buffer;
181 }
182 
183 /* Check if VERSION of the info block PTR matches libgcov one.
184    Return 1 on success, or zero in case of versions mismatch.
185    If FILENAME is not NULL, its value used for reporting purposes
186    instead of value from the info block.  */
187 
188 static int
189 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
190               const char *filename)
191 {
192   if (version != GCOV_VERSION)
193     {
194       char v[4], e[4];
195       char version_string[128], expected_string[128];
196 
197       GCOV_UNSIGNED2STRING (v, version);
198       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
199 
200       gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
201 		  "got %s (%.4s)\n",
202 		  filename? filename : ptr->filename,
203 		  gcov_version_string (expected_string, e), e,
204 		  gcov_version_string (version_string, v), v);
205       return 0;
206     }
207   return 1;
208 }
209 
210 /* buffer for the fn_data from another program.  */
211 static struct gcov_fn_buffer *fn_buffer;
212 
213 /* Including system dependent components. */
214 #include "libgcov-driver-system.c"
215 
216 /* This function merges counters in GI_PTR to an existing gcda file.
217    Return 0 on success.
218    Return -1 on error. In this case, caller will goto read_fatal.  */
219 
220 static int
221 merge_one_data (const char *filename,
222 		struct gcov_info *gi_ptr,
223 		struct gcov_summary *summary)
224 {
225   gcov_unsigned_t tag, length;
226   unsigned t_ix;
227   int f_ix = -1;
228   int error = 0;
229   struct gcov_fn_buffer **fn_tail = &fn_buffer;
230 
231   length = gcov_read_unsigned ();
232   if (!gcov_version (gi_ptr, length, filename))
233     return -1;
234 
235   length = gcov_read_unsigned ();
236   if (length != gi_ptr->stamp)
237     {
238       /* Read from a different compilation.  Overwrite the file.  */
239       gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
240 		  "with a different timestamp\n", filename);
241       return 0;
242     }
243 
244   tag = gcov_read_unsigned ();
245   if (tag != GCOV_TAG_OBJECT_SUMMARY)
246     goto read_mismatch;
247   length = gcov_read_unsigned ();
248   gcc_assert (length > 0);
249   gcov_read_summary (summary);
250 
251   tag = gcov_read_unsigned ();
252   /* Merge execution counts for each function.  */
253   for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
254        f_ix++, tag = gcov_read_unsigned ())
255     {
256       const struct gcov_ctr_info *ci_ptr;
257       const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
258 
259       if (tag != GCOV_TAG_FUNCTION)
260         goto read_mismatch;
261 
262       length = gcov_read_unsigned ();
263       if (!length)
264         /* This function did not appear in the other program.
265            We have nothing to merge.  */
266         continue;
267 
268       if (length != GCOV_TAG_FUNCTION_LENGTH)
269         goto read_mismatch;
270 
271       if (!gfi_ptr || gfi_ptr->key != gi_ptr)
272         {
273           /* This function appears in the other program.  We
274              need to buffer the information in order to write
275              it back out -- we'll be inserting data before
276              this point, so cannot simply keep the data in the
277              file.  */
278           fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
279           if (!fn_tail)
280             goto read_mismatch;
281           continue;
282         }
283 
284       length = gcov_read_unsigned ();
285       if (length != gfi_ptr->ident)
286         goto read_mismatch;
287 
288       length = gcov_read_unsigned ();
289       if (length != gfi_ptr->lineno_checksum)
290         goto read_mismatch;
291 
292       length = gcov_read_unsigned ();
293       if (length != gfi_ptr->cfg_checksum)
294         goto read_mismatch;
295 
296       ci_ptr = gfi_ptr->ctrs;
297       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
298         {
299           gcov_merge_fn merge = gi_ptr->merge[t_ix];
300 
301           if (!merge)
302             continue;
303 
304           tag = gcov_read_unsigned ();
305           length = gcov_read_unsigned ();
306           if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
307               || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
308             goto read_mismatch;
309           (*merge) (ci_ptr->values, ci_ptr->num);
310           ci_ptr++;
311         }
312       if ((error = gcov_is_error ()))
313         goto read_error;
314     }
315 
316   if (tag)
317     {
318     read_mismatch:;
319       gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
320                   filename, f_ix >= 0 ? "function" : "summary",
321                   f_ix < 0 ? -1 - f_ix : f_ix);
322       return -1;
323     }
324   return 0;
325 
326 read_error:
327   gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
328               error < 0 ? "Overflow": "Error");
329   return -1;
330 }
331 
332 /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
333    the case of appending to an existing file, SUMMARY_POS will be non-zero.
334    We will write the file starting from SUMMAY_POS.  */
335 
336 static void
337 write_one_data (const struct gcov_info *gi_ptr,
338 		const struct gcov_summary *prg_p)
339 {
340   unsigned f_ix;
341 
342   gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
343   gcov_write_unsigned (gi_ptr->stamp);
344 
345   /* Generate whole program statistics.  */
346   gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
347 
348   /* Write execution counts for each function.  */
349   for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
350     {
351       unsigned buffered = 0;
352       const struct gcov_fn_info *gfi_ptr;
353       const struct gcov_ctr_info *ci_ptr;
354       gcov_unsigned_t length;
355       unsigned t_ix;
356 
357       if (fn_buffer && fn_buffer->fn_ix == f_ix)
358         {
359           /* Buffered data from another program.  */
360           buffered = 1;
361           gfi_ptr = &fn_buffer->info;
362           length = GCOV_TAG_FUNCTION_LENGTH;
363         }
364       else
365         {
366           gfi_ptr = gi_ptr->functions[f_ix];
367           if (gfi_ptr && gfi_ptr->key == gi_ptr)
368             length = GCOV_TAG_FUNCTION_LENGTH;
369           else
370                 length = 0;
371         }
372 
373       gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
374       if (!length)
375         continue;
376 
377       gcov_write_unsigned (gfi_ptr->ident);
378       gcov_write_unsigned (gfi_ptr->lineno_checksum);
379       gcov_write_unsigned (gfi_ptr->cfg_checksum);
380 
381       ci_ptr = gfi_ptr->ctrs;
382       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
383         {
384           gcov_unsigned_t n_counts;
385           gcov_type *c_ptr;
386 
387           if (!gi_ptr->merge[t_ix])
388             continue;
389 
390           n_counts = ci_ptr->num;
391           gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
392                                  GCOV_TAG_COUNTER_LENGTH (n_counts));
393           c_ptr = ci_ptr->values;
394           while (n_counts--)
395             gcov_write_counter (*c_ptr++);
396           ci_ptr++;
397         }
398       if (buffered)
399         fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
400     }
401 
402   gcov_write_unsigned (0);
403 }
404 
405 /* Helper function for merging summary.  */
406 
407 static void
408 merge_summary (int run_counted, struct gcov_summary *summary,
409 	      gcov_type run_max)
410 {
411   if (!run_counted)
412     {
413       summary->runs++;
414       summary->sum_max += run_max;
415     }
416 }
417 
418 /* Sort N entries in VALUE_ARRAY in descending order.
419    Each entry in VALUE_ARRAY has two values. The sorting
420    is based on the second value.  */
421 
422 GCOV_LINKAGE  void
423 gcov_sort_n_vals (gcov_type *value_array, int n)
424 {
425   int j, k;
426 
427   for (j = 2; j < n; j += 2)
428     {
429       gcov_type cur_ent[2];
430 
431       cur_ent[0] = value_array[j];
432       cur_ent[1] = value_array[j + 1];
433       k = j - 2;
434       while (k >= 0 && value_array[k + 1] < cur_ent[1])
435         {
436           value_array[k + 2] = value_array[k];
437           value_array[k + 3] = value_array[k+1];
438           k -= 2;
439         }
440       value_array[k + 2] = cur_ent[0];
441       value_array[k + 3] = cur_ent[1];
442     }
443 }
444 
445 /* Sort the profile counters for all indirect call sites. Counters
446    for each call site are allocated in array COUNTERS.  */
447 
448 static void
449 gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
450 {
451   int i;
452   gcov_type *values;
453   int n = counters->num;
454 
455   gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
456   values = counters->values;
457 
458   for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
459     {
460       gcov_type *value_array = &values[i + 1];
461       gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
462     }
463 }
464 
465 /* Sort topn indirect_call profile counters in GI_PTR.  */
466 
467 static void
468 gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
469 {
470   unsigned int i;
471   int f_ix;
472   const struct gcov_fn_info *gfi_ptr;
473   const struct gcov_ctr_info *ci_ptr;
474 
475   if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV])
476     return;
477 
478   for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
479     {
480       gfi_ptr = gi_ptr->functions[f_ix];
481       ci_ptr = gfi_ptr->ctrs;
482       for (i = 0; i < GCOV_COUNTERS; i++)
483         {
484           if (!gi_ptr->merge[i])
485             continue;
486           if (i == GCOV_COUNTER_ICALL_TOPNV)
487             {
488               gcov_sort_icall_topn_counter (ci_ptr);
489               break;
490             }
491           ci_ptr++;
492         }
493     }
494 }
495 
496 /* Dump the coverage counts for one gcov_info object. We merge with existing
497    counts when possible, to avoid growing the .da files ad infinitum. We use
498    this program's checksum to make sure we only accumulate whole program
499    statistics to the correct summary. An object file might be embedded
500    in two separate programs, and we must keep the two program
501    summaries separate.  */
502 
503 static void
504 dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
505 	       unsigned run_counted, gcov_type run_max)
506 {
507   struct gcov_summary summary = {};
508   int error;
509   gcov_unsigned_t tag;
510 
511   fn_buffer = 0;
512 
513   gcov_sort_topn_counter_arrays (gi_ptr);
514 
515   error = gcov_exit_open_gcda_file (gi_ptr, gf);
516   if (error == -1)
517     return;
518 
519   tag = gcov_read_unsigned ();
520   if (tag)
521     {
522       /* Merge data from file.  */
523       if (tag != GCOV_DATA_MAGIC)
524         {
525 	  gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
526 		      gf->filename);
527           goto read_fatal;
528         }
529       error = merge_one_data (gf->filename, gi_ptr, &summary);
530       if (error == -1)
531         goto read_fatal;
532     }
533 
534   gcov_rewrite ();
535 
536   merge_summary (run_counted, &summary, run_max);
537 
538   write_one_data (gi_ptr, &summary);
539   /* fall through */
540 
541 read_fatal:;
542   while (fn_buffer)
543     fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
544 
545   if ((error = gcov_close ()))
546     gcov_error (error  < 0 ?
547 		GCOV_PROF_PREFIX "Overflow writing\n" :
548 		GCOV_PROF_PREFIX "Error writing\n",
549                 gf->filename);
550 }
551 
552 
553 /* Dump all the coverage counts for the program. It first computes program
554    summary and then traverses gcov_list list and dumps the gcov_info
555    objects one by one.  */
556 
557 #if !IN_GCOV_TOOL
558 static
559 #endif
560 void
561 gcov_do_dump (struct gcov_info *list, int run_counted)
562 {
563   struct gcov_info *gi_ptr;
564   struct gcov_filename gf;
565 
566   /* Compute run_max of this program run.  */
567   gcov_type run_max = 0;
568   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
569     for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
570       {
571 	const struct gcov_ctr_info *cinfo
572 	  = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
573 
574 	for (unsigned i = 0; i < cinfo->num; i++)
575 	  if (run_max < cinfo->values[i])
576 	    run_max = cinfo->values[i];
577       }
578 
579   allocate_filename_struct (&gf);
580 
581   /* Now merge each file.  */
582   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
583     {
584       dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
585       free (gf.filename);
586     }
587 
588   free (gf.prefix);
589 }
590 
591 #if IN_GCOV_TOOL
592 const char *
593 __attribute__ ((unused))
594 gcov_get_filename (struct gcov_info *list)
595 {
596   return list->filename;
597 }
598 #endif
599 
600 #if !IN_GCOV_TOOL
601 void
602 __gcov_dump_one (struct gcov_root *root)
603 {
604   if (root->dumped)
605     return;
606 
607   gcov_do_dump (root->list, root->run_counted);
608 
609   root->dumped = 1;
610   root->run_counted = 1;
611 }
612 
613 /* Per-dynamic-object gcov state.  */
614 struct gcov_root __gcov_root;
615 
616 /* Exactly one of these will be live in the process image.  */
617 struct gcov_master __gcov_master =
618   {GCOV_VERSION, 0};
619 
620 void
621 __gcov_exit (void)
622 {
623   __gcov_dump_one (&__gcov_root);
624   if (__gcov_root.next)
625     __gcov_root.next->prev = __gcov_root.prev;
626   if (__gcov_root.prev)
627     __gcov_root.prev->next = __gcov_root.next;
628   else
629     __gcov_master.root = __gcov_root.next;
630 
631   gcov_error_exit ();
632 }
633 
634 /* Add a new object file onto the bb chain.  Invoked automatically
635   when running an object file's global ctors.  */
636 
637 void
638 __gcov_init (struct gcov_info *info)
639 {
640   if (!info->version || !info->n_functions)
641     return;
642   if (gcov_version (info, info->version, 0))
643     {
644       if (!__gcov_root.list)
645 	{
646 	  /* Add to master list and at exit function.  */
647 	  if (gcov_version (NULL, __gcov_master.version, "<master>"))
648 	    {
649 	      __gcov_root.next = __gcov_master.root;
650 	      if (__gcov_master.root)
651 		__gcov_master.root->prev = &__gcov_root;
652 	      __gcov_master.root = &__gcov_root;
653 	    }
654 	}
655 
656       info->next = __gcov_root.list;
657       __gcov_root.list = info;
658     }
659 }
660 #endif /* !IN_GCOV_TOOL */
661 #endif /* L_gcov */
662 #endif /* inhibit_libc */
663