Update gcc-50 to SVN version 221845
[dragonfly.git] / contrib / gcc-5.0 / gcc / gcov-tool.c
1 /* Gcc offline profile processing tool support. */
2 /* Copyright (C) 2014-2015 Free Software Foundation, Inc.
3    Contributed by Rong Xu <xur@google.com>.
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 "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "intl.h"
31 #include "diagnostic.h"
32 #include "version.h"
33 #include "gcov-io.h"
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #if HAVE_FTW_H
39 #include <ftw.h>
40 #endif
41 #include <getopt.h>
42
43 extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
44 extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
45 extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
46 extern int gcov_profile_scale (struct gcov_info*, float, int, int);
47 extern struct gcov_info* gcov_read_profile_dir (const char*, int);
48 extern void gcov_do_dump (struct gcov_info *, int);
49 extern void gcov_set_verbose (void);
50
51 /* Set to verbose output mode.  */
52 static bool verbose;
53
54 #if HAVE_FTW_H
55
56 /* Remove file NAME if it has a gcda suffix. */
57
58 static int
59 unlink_gcda_file (const char *name,
60                   const struct stat *status ATTRIBUTE_UNUSED,
61                   int type ATTRIBUTE_UNUSED,
62                   struct FTW *ftwbuf ATTRIBUTE_UNUSED)
63 {
64   int ret = 0;
65   int len = strlen (name);
66   int len1 = strlen (GCOV_DATA_SUFFIX);
67
68   if (len > len1 && !strncmp (len -len1 + name, GCOV_DATA_SUFFIX, len1))
69     ret = remove (name);
70
71   if (ret)
72     fatal_error (input_location, "error in removing %s\n", name);
73
74   return ret;
75 }
76 #endif
77
78 /* Remove the gcda files in PATH recursively.  */
79
80 static int
81 unlink_profile_dir (const char *path ATTRIBUTE_UNUSED)
82 {
83 #if HAVE_FTW_H
84     return nftw(path, unlink_gcda_file, 64, FTW_DEPTH | FTW_PHYS);
85 #else
86     return -1;
87 #endif
88 }
89
90 /* Output GCOV_INFO lists PROFILE to directory OUT. Note that
91    we will remove all the gcda files in OUT.  */
92
93 static void
94 gcov_output_files (const char *out, struct gcov_info *profile)
95 {
96   char *pwd;
97   int ret;
98
99   /* Try to make directory if it doesn't already exist.  */
100   if (access (out, F_OK) == -1)
101     {
102       if (mkdir (out, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST)
103         fatal_error (input_location, "Cannot make directory %s", out);
104     } else
105       unlink_profile_dir (out);
106
107   /* Output new profile.  */
108   pwd = getcwd (NULL, 0);
109
110   if (pwd == NULL)
111     fatal_error (input_location, "Cannot get current directory name");
112
113   ret = chdir (out);
114   if (ret)
115     fatal_error (input_location, "Cannot change directory to %s", out);
116
117   gcov_do_dump (profile, 0);
118
119   ret = chdir (pwd);
120   if (ret)
121     fatal_error (input_location, "Cannot change directory to %s", pwd);
122
123   free (pwd);
124 }
125
126 /* Merging profile D1 and D2 with weight as W1 and W2, respectively.
127    The result profile is written to directory OUT.
128    Return 0 on success.  */
129
130 static int
131 profile_merge (const char *d1, const char *d2, const char *out, int w1, int w2)
132 {
133   struct gcov_info *d1_profile;
134   struct gcov_info *d2_profile;
135   int ret;
136
137   d1_profile = gcov_read_profile_dir (d1, 0);
138   if (!d1_profile)
139     return 1;
140
141   if (d2)
142     {
143       d2_profile = gcov_read_profile_dir (d2, 0);
144       if (!d2_profile)
145         return 1;
146
147       /* The actual merge: we overwrite to d1_profile.  */
148       ret = gcov_profile_merge (d1_profile, d2_profile, w1, w2);
149
150       if (ret)
151         return ret;
152     }
153
154   gcov_output_files (out, d1_profile);
155
156   return 0;
157 }
158
159 /* Usage message for profile merge.  */
160
161 static void
162 print_merge_usage_message (int error_p)
163 {
164   FILE *file = error_p ? stderr : stdout;
165
166   fnotice (file, "  merge [options] <dir1> <dir2>         Merge coverage file contents\n");
167   fnotice (file, "    -v, --verbose                       Verbose mode\n");
168   fnotice (file, "    -o, --output <dir>                  Output directory\n");
169   fnotice (file, "    -w, --weight <w1,w2>                Set weights (float point values)\n");
170 }
171
172 static const struct option merge_options[] =
173 {
174   { "verbose",                no_argument,       NULL, 'v' },
175   { "output",                 required_argument, NULL, 'o' },
176   { "weight",                 required_argument, NULL, 'w' },
177   { 0, 0, 0, 0 }
178 };
179
180 /* Print merge usage and exit.  */
181
182 static void
183 merge_usage (void)
184 {
185   fnotice (stderr, "Merge subcomand usage:");
186   print_merge_usage_message (true);
187   exit (FATAL_EXIT_CODE);
188 }
189
190 /* Driver for profile merge sub-command.  */
191
192 static int
193 do_merge (int argc, char **argv)
194 {
195   int opt;
196   int ret;
197   const char *output_dir = 0;
198   int w1 = 1, w2 = 1;
199
200   optind = 0;
201   while ((opt = getopt_long (argc, argv, "vo:w:", merge_options, NULL)) != -1)
202     {
203       switch (opt)
204         {
205         case 'v':
206           verbose = true;
207           gcov_set_verbose ();
208           break;
209         case 'o':
210           output_dir = optarg;
211           break;
212         case 'w':
213           sscanf (optarg, "%d,%d", &w1, &w2);
214           if (w1 < 0 || w2 < 0)
215             fatal_error (input_location, "weights need to be non-negative\n");
216           break;
217         default:
218           merge_usage ();
219         }
220     }
221
222   if (output_dir == NULL)
223     output_dir = "merged_profile";
224
225   if (argc - optind == 2)
226     ret = profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2);
227   else
228     merge_usage ();
229
230   return ret;
231 }
232
233 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
234    counter value to N_VAL and scale others counters proportionally.
235    Otherwise, multiply the all counters by SCALE.  */
236
237 static int
238 profile_rewrite (const char *d1, const char *out, long long n_val,
239                  float scale, int n, int d)
240 {
241   struct gcov_info * d1_profile;
242
243   d1_profile = gcov_read_profile_dir (d1, 0);
244   if (!d1_profile)
245     return 1;
246
247   if (n_val)
248     gcov_profile_normalize (d1_profile, (gcov_type) n_val);
249   else
250     gcov_profile_scale (d1_profile, scale, n, d);
251
252   gcov_output_files (out, d1_profile);
253   return 0;
254 }
255
256 /* Usage function for profile rewrite.  */
257
258 static void
259 print_rewrite_usage_message (int error_p)
260 {
261   FILE *file = error_p ? stderr : stdout;
262
263   fnotice (file, "  rewrite [options] <dir>               Rewrite coverage file contents\n");
264   fnotice (file, "    -v, --verbose                       Verbose mode\n");
265   fnotice (file, "    -o, --output <dir>                  Output directory\n");
266   fnotice (file, "    -s, --scale <float or simple-frac>  Scale the profile counters\n");
267   fnotice (file, "    -n, --normalize <long long>         Normalize the profile\n");
268 }
269
270 static const struct option rewrite_options[] =
271 {
272   { "verbose",                no_argument,       NULL, 'v' },
273   { "output",                 required_argument, NULL, 'o' },
274   { "scale",                  required_argument, NULL, 's' },
275   { "normalize",              required_argument, NULL, 'n' },
276   { 0, 0, 0, 0 }
277 };
278
279 /* Print profile rewrite usage and exit.  */
280
281 static void
282 rewrite_usage (void)
283 {
284   fnotice (stderr, "Rewrite subcommand usage:");
285   print_rewrite_usage_message (true);
286   exit (FATAL_EXIT_CODE);
287 }
288
289 /* Driver for profile rewrite sub-command. */
290
291 static int
292 do_rewrite (int argc, char **argv)
293 {
294   int opt;
295   int ret;
296   const char *output_dir = 0;
297 #ifdef HAVE_LONG_LONG
298   long long normalize_val = 0;
299 #else
300   int64_t normalize_val = 0;
301 #endif
302   float scale = 0.0;
303   int numerator = 1;
304   int denominator = 1;
305   int do_scaling = 0;
306
307   optind = 0;
308   while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1)
309     {
310       switch (opt)
311         {
312         case 'v':
313           verbose = true;
314           gcov_set_verbose ();
315           break;
316         case 'o':
317           output_dir = optarg;
318           break;
319         case 'n':
320           if (!do_scaling)
321 #if defined(HAVE_LONG_LONG)
322             normalize_val = strtoll (optarg, (char **)NULL, 10);
323 #elif defined(INT64_T_IS_LONG)
324             normalize_val = strtol (optarg, (char **)NULL, 10);
325 #else
326             sscanf (optarg, "%" SCNd64, &normalize_val);
327 #endif
328           else
329             fnotice (stderr, "scaling cannot co-exist with normalization,"
330                 " skipping\n");
331           break;
332         case 's':
333           ret = 0;
334           do_scaling = 1;
335           if (strstr (optarg, "/"))
336             {
337               ret = sscanf (optarg, "%d/%d", &numerator, &denominator);
338               if (ret == 2)
339                 {
340                   if (numerator < 0 || denominator <= 0)
341                     {
342                       fnotice (stderr, "incorrect format in scaling, using 1/1\n");
343                       denominator = 1;
344                       numerator = 1;
345                     }
346                 }
347             }
348           if (ret != 2)
349             {
350               ret = sscanf (optarg, "%f", &scale);
351               if (ret != 1)
352                 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
353               else
354                 denominator = 0;
355             }
356
357           if (scale < 0.0)
358             fatal_error (input_location, "scale needs to be non-negative\n");
359
360           if (normalize_val != 0)
361             {
362               fnotice (stderr, "normalization cannot co-exist with scaling\n");
363               normalize_val = 0;
364             }
365           break;
366         default:
367           rewrite_usage ();
368         }
369     }
370
371   if (output_dir == NULL)
372     output_dir = "rewrite_profile";
373
374   if (argc - optind == 1)
375     {
376       if (denominator > 0)
377         ret = profile_rewrite (argv[optind],  output_dir, 0, 0.0, numerator, denominator);
378       else
379         ret = profile_rewrite (argv[optind],  output_dir, normalize_val, scale, 0, 0);
380     }
381   else
382     rewrite_usage ();
383
384   return ret;
385 }
386
387 /* Driver function to computer the overlap score b/w profile D1 and D2.
388    Return 1 on error and 0 if OK.  */
389
390 static int
391 profile_overlap (const char *d1, const char *d2)
392 {
393   struct gcov_info *d1_profile;
394   struct gcov_info *d2_profile;
395
396   d1_profile = gcov_read_profile_dir (d1, 0);
397   if (!d1_profile)
398     return 1;
399
400   if (d2)
401     {
402       d2_profile = gcov_read_profile_dir (d2, 0);
403       if (!d2_profile)
404         return 1;
405
406       return gcov_profile_overlap (d1_profile, d2_profile);
407     }
408
409   return 1;
410 }
411
412 /* Usage message for profile overlap.  */
413
414 static void
415 print_overlap_usage_message (int error_p)
416 {
417   FILE *file = error_p ? stderr : stdout;
418
419   fnotice (file, "  overlap [options] <dir1> <dir2>       Compute the overlap of two profiles\n");
420   fnotice (file, "    -v, --verbose                       Verbose mode\n");
421   fnotice (file, "    -h, --hotonly                       Only print info for hot objects/functions\n");
422   fnotice (file, "    -f, --function                      Print function level info\n");
423   fnotice (file, "    -F, --fullname                      Print full filename\n");
424   fnotice (file, "    -o, --object                        Print object level info\n");
425   fnotice (file, "    -t <float>, --hot_threshold <float> Set the threshold for hotness\n");
426
427 }
428
429 static const struct option overlap_options[] =
430 {
431   { "verbose",                no_argument,       NULL, 'v' },
432   { "function",               no_argument,       NULL, 'f' },
433   { "fullname",               no_argument,       NULL, 'F' },
434   { "object",                 no_argument,       NULL, 'o' },
435   { "hotonly",                no_argument,       NULL, 'h' },
436   { "hot_threshold",          required_argument, NULL, 't' },
437   { 0, 0, 0, 0 }
438 };
439
440 /* Print overlap usage and exit.  */
441
442 static void
443 overlap_usage (void)
444 {
445   fnotice (stderr, "Overlap subcomand usage:");
446   print_overlap_usage_message (true);
447   exit (FATAL_EXIT_CODE);
448 }
449
450 int overlap_func_level;
451 int overlap_obj_level;
452 int overlap_hot_only;
453 int overlap_use_fullname;
454 double overlap_hot_threshold = 0.005;
455
456 /* Driver for profile overlap sub-command.  */
457
458 static int
459 do_overlap (int argc, char **argv)
460 {
461   int opt;
462   int ret;
463
464   optind = 0;
465   while ((opt = getopt_long (argc, argv, "vfFoht:", overlap_options, NULL)) != -1)
466     {
467       switch (opt)
468         {
469         case 'v':
470           verbose = true;
471           gcov_set_verbose ();
472           break;
473         case 'f':
474           overlap_func_level = 1;
475           break;
476         case 'F':
477           overlap_use_fullname = 1;
478           break;
479         case 'o':
480           overlap_obj_level = 1;
481           break;
482         case 'h':
483           overlap_hot_only = 1;
484           break;
485         case 't':
486           overlap_hot_threshold = atof (optarg);
487           break;
488         default:
489           overlap_usage ();
490         }
491     }
492
493   if (argc - optind == 2)
494     ret = profile_overlap (argv[optind], argv[optind+1]);
495   else
496     overlap_usage ();
497
498   return ret;
499 }
500
501
502 /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
503    otherwise the output of --help.  */
504
505 static void
506 print_usage (int error_p)
507 {
508   FILE *file = error_p ? stderr : stdout;
509   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
510
511   fnotice (file, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname);
512   fnotice (file, "Offline tool to handle gcda counts\n\n");
513   fnotice (file, "  -h, --help                            Print this help, then exit\n");
514   fnotice (file, "  -v, --version                         Print version number, then exit\n");
515   print_merge_usage_message (error_p);
516   print_rewrite_usage_message (error_p);
517   print_overlap_usage_message (error_p);
518   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
519            bug_report_url);
520   exit (status);
521 }
522
523 /* Print version information and exit.  */
524
525 static void
526 print_version (void)
527 {
528   fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string);
529   fnotice (stdout, "Copyright %s 2014-2015 Free Software Foundation, Inc.\n",
530            _("(C)"));
531   fnotice (stdout,
532            _("This is free software; see the source for copying conditions.\n"
533              "There is NO warranty; not even for MERCHANTABILITY or \n"
534              "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
535   exit (SUCCESS_EXIT_CODE);
536 }
537
538 static const struct option options[] =
539 {
540   { "help",                 no_argument,       NULL, 'h' },
541   { "version",              no_argument,       NULL, 'v' },
542   { 0, 0, 0, 0 }
543 };
544
545 /* Process args, return index to first non-arg.  */
546
547 static int
548 process_args (int argc, char **argv)
549 {
550   int opt;
551
552   while ((opt = getopt_long (argc, argv, "+hv", options, NULL)) != -1)
553     {
554       switch (opt)
555         {
556         case 'h':
557           print_usage (false);
558           /* Print_usage will exit.  */
559         case 'v':
560           print_version ();
561           /* Print_version will exit.  */
562         default:
563           print_usage (true);
564           /* Print_usage will exit.  */
565         }
566     }
567
568   return optind;
569 }
570
571 /* Main function for gcov-tool.  */
572
573 int
574 main (int argc, char **argv)
575 {
576   const char *p;
577   const char *sub_command;
578
579   p = argv[0] + strlen (argv[0]);
580   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
581     --p;
582   progname = p;
583
584   xmalloc_set_program_name (progname);
585
586   /* Unlock the stdio streams.  */
587   unlock_std_streams ();
588
589   gcc_init_libintl ();
590
591   diagnostic_initialize (global_dc, 0);
592
593   /* Handle response files.  */
594   expandargv (&argc, &argv);
595
596   process_args (argc, argv);
597   if (optind >= argc)
598     print_usage (true);
599
600   sub_command = argv[optind];
601
602   if (!strcmp (sub_command, "merge"))
603     return do_merge (argc - optind, argv + optind);
604   else if (!strcmp (sub_command, "rewrite"))
605     return do_rewrite (argc - optind, argv + optind);
606   else if (!strcmp (sub_command, "overlap"))
607     return do_overlap (argc - optind, argv + optind);
608
609   print_usage (true);
610 }