1 /* Routines required for instrumenting a program.  */
2 /* Compile this one with gcc.  */
3 /* Copyright (C) 1989-2020 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)
__gcov_init(struct gcov_info * p)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 *
free_fn_data(const struct gcov_info * gi_ptr,struct gcov_fn_buffer * buffer,unsigned limit)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 **
buffer_fn_data(const char * filename,const struct gcov_info * gi_ptr,struct gcov_fn_buffer ** end_ptr,unsigned fn_ix)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 *
gcov_version_string(char * buffer,char version[4])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
gcov_version(struct gcov_info * ptr,gcov_unsigned_t version,const char * filename)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 /* Prune TOP N value COUNTERS.  It's needed in order to preserve
217    reproducibility of builds.  */
218 
219 static void
prune_topn_counter(gcov_type * counters,gcov_type all)220 prune_topn_counter (gcov_type *counters, gcov_type all)
221 {
222   for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++)
223     if (counters[2 * i + 1] < all)
224       {
225 	counters[2 * i] = 0;
226 	counters[2 * i + 1] = 0;
227       }
228 }
229 
230 /* Prune counters so that they are ready to store or merge.  */
231 
232 static void
prune_counters(struct gcov_info * gi)233 prune_counters (struct gcov_info *gi)
234 {
235   for (unsigned i = 0; i < gi->n_functions; i++)
236     {
237       const struct gcov_fn_info *gfi = gi->functions[i];
238       const struct gcov_ctr_info *ci = gfi->ctrs;
239 
240       for (unsigned j = 0; j < GCOV_COUNTERS; j++)
241 	{
242 	  if (gi->merge[j] == NULL)
243 	    continue;
244 
245 	  if (j == GCOV_COUNTER_V_TOPN || j == GCOV_COUNTER_V_INDIR)
246 	    {
247 	      gcc_assert (!(ci->num % GCOV_TOPN_VALUES_COUNTERS));
248 	      for (unsigned k = 0; k < (ci->num / GCOV_TOPN_VALUES_COUNTERS);
249 		   k++)
250 		{
251 		  gcov_type *counters
252 		    = ci->values + (k * GCOV_TOPN_VALUES_COUNTERS);
253 		  prune_topn_counter (counters + 1, *counters);
254 		}
255 	    }
256 	  ci++;
257 	}
258     }
259 }
260 
261 /* This function merges counters in GI_PTR to an existing gcda file.
262    Return 0 on success.
263    Return -1 on error. In this case, caller will goto read_fatal.  */
264 
265 static int
merge_one_data(const char * filename,struct gcov_info * gi_ptr,struct gcov_summary * summary)266 merge_one_data (const char *filename,
267 		struct gcov_info *gi_ptr,
268 		struct gcov_summary *summary)
269 {
270   gcov_unsigned_t tag, length;
271   unsigned t_ix;
272   int f_ix = -1;
273   int error = 0;
274   struct gcov_fn_buffer **fn_tail = &fn_buffer;
275 
276   length = gcov_read_unsigned ();
277   if (!gcov_version (gi_ptr, length, filename))
278     return -1;
279 
280   length = gcov_read_unsigned ();
281   if (length != gi_ptr->stamp)
282     {
283       /* Read from a different compilation.  Overwrite the file.  */
284       gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
285 		  "with a different timestamp\n", filename);
286       return 0;
287     }
288 
289   tag = gcov_read_unsigned ();
290   if (tag != GCOV_TAG_OBJECT_SUMMARY)
291     goto read_mismatch;
292   length = gcov_read_unsigned ();
293   gcc_assert (length > 0);
294   gcov_read_summary (summary);
295 
296   tag = gcov_read_unsigned ();
297   /* Merge execution counts for each function.  */
298   for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
299        f_ix++, tag = gcov_read_unsigned ())
300     {
301       const struct gcov_ctr_info *ci_ptr;
302       const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
303 
304       if (tag != GCOV_TAG_FUNCTION)
305         goto read_mismatch;
306 
307       length = gcov_read_unsigned ();
308       if (!length)
309         /* This function did not appear in the other program.
310            We have nothing to merge.  */
311         continue;
312 
313       if (length != GCOV_TAG_FUNCTION_LENGTH)
314         goto read_mismatch;
315 
316       if (!gfi_ptr || gfi_ptr->key != gi_ptr)
317         {
318           /* This function appears in the other program.  We
319              need to buffer the information in order to write
320              it back out -- we'll be inserting data before
321              this point, so cannot simply keep the data in the
322              file.  */
323           fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
324           if (!fn_tail)
325             goto read_mismatch;
326           continue;
327         }
328 
329       length = gcov_read_unsigned ();
330       if (length != gfi_ptr->ident)
331         goto read_mismatch;
332 
333       length = gcov_read_unsigned ();
334       if (length != gfi_ptr->lineno_checksum)
335         goto read_mismatch;
336 
337       length = gcov_read_unsigned ();
338       if (length != gfi_ptr->cfg_checksum)
339         goto read_mismatch;
340 
341       ci_ptr = gfi_ptr->ctrs;
342       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
343         {
344           gcov_merge_fn merge = gi_ptr->merge[t_ix];
345 
346           if (!merge)
347             continue;
348 
349           tag = gcov_read_unsigned ();
350           length = gcov_read_unsigned ();
351           if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
352               || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
353             goto read_mismatch;
354           (*merge) (ci_ptr->values, ci_ptr->num);
355           ci_ptr++;
356         }
357       if ((error = gcov_is_error ()))
358         goto read_error;
359     }
360 
361   if (tag)
362     {
363     read_mismatch:;
364       gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
365                   filename, f_ix >= 0 ? "function" : "summary",
366                   f_ix < 0 ? -1 - f_ix : f_ix);
367       return -1;
368     }
369   return 0;
370 
371 read_error:
372   gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
373               error < 0 ? "Overflow": "Error");
374   return -1;
375 }
376 
377 /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
378    the case of appending to an existing file, SUMMARY_POS will be non-zero.
379    We will write the file starting from SUMMAY_POS.  */
380 
381 static void
write_one_data(const struct gcov_info * gi_ptr,const struct gcov_summary * prg_p)382 write_one_data (const struct gcov_info *gi_ptr,
383 		const struct gcov_summary *prg_p)
384 {
385   unsigned f_ix;
386 
387   gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
388   gcov_write_unsigned (gi_ptr->stamp);
389 
390   /* Generate whole program statistics.  */
391   gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
392 
393   /* Write execution counts for each function.  */
394   for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
395     {
396       unsigned buffered = 0;
397       const struct gcov_fn_info *gfi_ptr;
398       const struct gcov_ctr_info *ci_ptr;
399       gcov_unsigned_t length;
400       unsigned t_ix;
401 
402       if (fn_buffer && fn_buffer->fn_ix == f_ix)
403         {
404           /* Buffered data from another program.  */
405           buffered = 1;
406           gfi_ptr = &fn_buffer->info;
407           length = GCOV_TAG_FUNCTION_LENGTH;
408         }
409       else
410         {
411           gfi_ptr = gi_ptr->functions[f_ix];
412           if (gfi_ptr && gfi_ptr->key == gi_ptr)
413             length = GCOV_TAG_FUNCTION_LENGTH;
414           else
415                 length = 0;
416         }
417 
418       gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
419       if (!length)
420         continue;
421 
422       gcov_write_unsigned (gfi_ptr->ident);
423       gcov_write_unsigned (gfi_ptr->lineno_checksum);
424       gcov_write_unsigned (gfi_ptr->cfg_checksum);
425 
426       ci_ptr = gfi_ptr->ctrs;
427       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
428         {
429           gcov_unsigned_t n_counts;
430           gcov_type *c_ptr;
431 
432           if (!gi_ptr->merge[t_ix])
433             continue;
434 
435           n_counts = ci_ptr->num;
436           gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
437                                  GCOV_TAG_COUNTER_LENGTH (n_counts));
438           c_ptr = ci_ptr->values;
439           while (n_counts--)
440             gcov_write_counter (*c_ptr++);
441           ci_ptr++;
442         }
443       if (buffered)
444         fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
445     }
446 
447   gcov_write_unsigned (0);
448 }
449 
450 /* Helper function for merging summary.  */
451 
452 static void
merge_summary(int run_counted,struct gcov_summary * summary,gcov_type run_max)453 merge_summary (int run_counted, struct gcov_summary *summary,
454 	      gcov_type run_max)
455 {
456   if (!run_counted)
457     {
458       summary->runs++;
459       summary->sum_max += run_max;
460     }
461 }
462 
463 /* Dump the coverage counts for one gcov_info object. We merge with existing
464    counts when possible, to avoid growing the .da files ad infinitum. We use
465    this program's checksum to make sure we only accumulate whole program
466    statistics to the correct summary. An object file might be embedded
467    in two separate programs, and we must keep the two program
468    summaries separate.  */
469 
470 static void
dump_one_gcov(struct gcov_info * gi_ptr,struct gcov_filename * gf,unsigned run_counted,gcov_type run_max)471 dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
472 	       unsigned run_counted, gcov_type run_max)
473 {
474   struct gcov_summary summary = {};
475   int error;
476   gcov_unsigned_t tag;
477   fn_buffer = 0;
478 
479   /* Prune current counters before we merge them.  */
480   prune_counters (gi_ptr);
481 
482   error = gcov_exit_open_gcda_file (gi_ptr, gf);
483   if (error == -1)
484     return;
485 
486   tag = gcov_read_unsigned ();
487   if (tag)
488     {
489       /* Merge data from file.  */
490       if (tag != GCOV_DATA_MAGIC)
491         {
492 	  gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
493 		      gf->filename);
494           goto read_fatal;
495         }
496       error = merge_one_data (gf->filename, gi_ptr, &summary);
497       if (error == -1)
498         goto read_fatal;
499     }
500 
501   gcov_rewrite ();
502 
503   merge_summary (run_counted, &summary, run_max);
504 
505   write_one_data (gi_ptr, &summary);
506   /* fall through */
507 
508 read_fatal:;
509   while (fn_buffer)
510     fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
511 
512   if ((error = gcov_close ()))
513     gcov_error (error  < 0 ?
514 		GCOV_PROF_PREFIX "Overflow writing\n" :
515 		GCOV_PROF_PREFIX "Error writing\n",
516                 gf->filename);
517 }
518 
519 
520 /* Dump all the coverage counts for the program. It first computes program
521    summary and then traverses gcov_list list and dumps the gcov_info
522    objects one by one.  */
523 
524 #if !IN_GCOV_TOOL
525 static
526 #endif
527 void
gcov_do_dump(struct gcov_info * list,int run_counted)528 gcov_do_dump (struct gcov_info *list, int run_counted)
529 {
530   struct gcov_info *gi_ptr;
531   struct gcov_filename gf;
532 
533   /* Compute run_max of this program run.  */
534   gcov_type run_max = 0;
535   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
536     for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
537       {
538 	const struct gcov_ctr_info *cinfo
539 	  = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
540 
541 	for (unsigned i = 0; i < cinfo->num; i++)
542 	  if (run_max < cinfo->values[i])
543 	    run_max = cinfo->values[i];
544       }
545 
546   allocate_filename_struct (&gf);
547 
548   /* Now merge each file.  */
549   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
550     {
551       dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
552       free (gf.filename);
553     }
554 
555   free (gf.prefix);
556 }
557 
558 #if IN_GCOV_TOOL
559 const char *
560 __attribute__ ((unused))
gcov_get_filename(struct gcov_info * list)561 gcov_get_filename (struct gcov_info *list)
562 {
563   return list->filename;
564 }
565 #endif
566 
567 #if !IN_GCOV_TOOL
568 void
__gcov_dump_one(struct gcov_root * root)569 __gcov_dump_one (struct gcov_root *root)
570 {
571   if (root->dumped)
572     return;
573 
574   gcov_do_dump (root->list, root->run_counted);
575 
576   root->dumped = 1;
577   root->run_counted = 1;
578 }
579 
580 /* Per-dynamic-object gcov state.  */
581 struct gcov_root __gcov_root;
582 
583 /* Exactly one of these will be live in the process image.  */
584 struct gcov_master __gcov_master =
585   {GCOV_VERSION, 0};
586 
587 void
__gcov_exit(void)588 __gcov_exit (void)
589 {
590   __gcov_dump_one (&__gcov_root);
591   if (__gcov_root.next)
592     __gcov_root.next->prev = __gcov_root.prev;
593   if (__gcov_root.prev)
594     __gcov_root.prev->next = __gcov_root.next;
595   else
596     __gcov_master.root = __gcov_root.next;
597 
598   gcov_error_exit ();
599 }
600 
601 /* Add a new object file onto the bb chain.  Invoked automatically
602   when running an object file's global ctors.  */
603 
604 void
__gcov_init(struct gcov_info * info)605 __gcov_init (struct gcov_info *info)
606 {
607   if (!info->version || !info->n_functions)
608     return;
609   if (gcov_version (info, info->version, 0))
610     {
611       if (!__gcov_root.list)
612 	{
613 	  /* Add to master list and at exit function.  */
614 	  if (gcov_version (NULL, __gcov_master.version, "<master>"))
615 	    {
616 	      __gcov_root.next = __gcov_master.root;
617 	      if (__gcov_master.root)
618 		__gcov_master.root->prev = &__gcov_root;
619 	      __gcov_master.root = &__gcov_root;
620 	    }
621 	}
622 
623       info->next = __gcov_root.list;
624       __gcov_root.list = info;
625     }
626 }
627 #endif /* !IN_GCOV_TOOL */
628 #endif /* L_gcov */
629 #endif /* inhibit_libc */
630