gcov.patch

From: Christian Prochaska <christian.prochaska@genode-labs.com>


---
 gcc/gcov.c |  145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 136 insertions(+), 9 deletions(-)

diff --git a/gcc/gcov.c b/gcc/gcov.c
index a291bac3e..813c7e19b 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -50,6 +50,8 @@ along with Gcov; see the file COPYING3.  If not see
 #include <zlib.h>
 #include <getopt.h>
 
+#include <dirent.h>
+
 #include "md5.h"
 
 using namespace std;
@@ -58,6 +60,7 @@ using namespace std;
 #include "gcov-io.h"
 #include "gcov-io.c"
 
+
 /* The gcno file is generated by -ftest-coverage option. The gcda file is
    generated by a program compiled with -fprofile-arcs. Their formats
    are documented in gcov-io.h.  */
@@ -507,6 +510,11 @@ static const char *bbg_cwd;
 
 static char *da_file_name;
 
+/* Name and file pointer of the input file for the annotation source list (gcan).  */
+
+#define GCOV_ANNOTATE_SUFFIX ".gcan"
+static char *an_file_name;
+
 /* Data file is missing.  */
 
 static int no_data_file;
@@ -579,6 +587,16 @@ static int flag_human_readable_numbers = 0;
 
 static int flag_function_summary = 0;
 
+/*
+ * Genode autopilot mode
+ *
+ * - scans for gcov data files
+ * - strips the Genode depot path from source paths
+ * - writes results to stdout
+ */
+
+static int flag_genode_autopilot = 0;
+
 /* Object directory file prefix.  This is the directory/file where the
    graph and data files are looked for, if nonzero.  */
 
@@ -826,6 +844,43 @@ get_cycles_count (line_info &linfo)
   return count;
 }
 
+void process_files(const char *dir_path)
+{
+	char new_path[strlen(dir_path) + sizeof('/') + NAME_MAX];
+
+	DIR *dir = opendir(dir_path);
+
+	if (!dir)
+		return;
+
+	struct dirent *dirent;
+
+	while((dirent = readdir(dir)) != NULL) {
+
+		snprintf(new_path, sizeof(new_path), "%s/%s", dir_path, dirent->d_name);
+
+		struct stat stat_buf;
+
+		if (stat(new_path, &stat_buf) != 0)
+			continue;
+
+		if (S_ISDIR(stat_buf.st_mode)) {
+			process_files(new_path);
+			continue;
+		}
+		
+		if (!S_ISREG(stat_buf.st_mode))
+			continue;
+		
+		if (!strstr(dirent->d_name, ".gcda"))
+			continue;
+
+		process_file(new_path);
+	}
+
+  	closedir(dir);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -851,13 +906,25 @@ main (int argc, char **argv)
   expandargv (&argc, &argv);
 
   argno = process_args (argc, argv);
-  if (optind == argc)
+  if ((optind == argc) && !flag_genode_autopilot)
     print_usage (true);
 
   if (argc - argno > 1)
     multiple_files = 1;
 
   first_arg = argno;
+  
+  if (flag_genode_autopilot) {
+
+  	/* search .gcda files and process each one */
+  	process_files("/");
+
+	process_all_functions();
+	generate_results(NULL);
+	release_structures();
+
+	return 0;
+  }
 
   for (; argno != argc; argno++)
     {
@@ -911,7 +978,8 @@ print_usage (int error_p)
   fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
   fnotice (file, "  -v, --version                   Print version number, then exit\n");
   fnotice (file, "  -w, --verbose                   Print verbose informations\n");
-  fnotice (file, "  -x, --hash-filenames            Hash long pathnames\n");
+  fnotice (file, "  -x, --hash-filenames            Hash long pathnames\n\n");
+  fnotice (file, "  -g, --genode-autopilot          Genode autopilot mode\n");
   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
 	   bug_report_url);
   exit (status);
@@ -957,6 +1025,7 @@ static const struct option options[] =
   { "hash-filenames",	    no_argument,       NULL, 'x' },
   { "use-colors",	    no_argument,       NULL, 'k' },
   { "use-hotness-colors",   no_argument,       NULL, 'q' },
+  { "genode-autopilot",     no_argument,       NULL, 'g' },
   { 0, 0, 0, 0 }
 };
 
@@ -967,7 +1036,7 @@ process_args (int argc, char **argv)
 {
   int opt;
 
-  const char *opts = "abcdfhijklmno:pqrs:tuvwx";
+  const char *opts = "abcdfghijklmno:pqrs:tuvwx";
   while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
     {
       switch (opt)
@@ -984,6 +1053,9 @@ process_args (int argc, char **argv)
 	case 'f':
 	  flag_function_summary = 1;
 	  break;
+	case 'g':
+	  flag_genode_autopilot = 1;
+	  break;
 	case 'h':
 	  print_usage (false);
 	  /* print_usage will exit.  */
@@ -1363,11 +1435,43 @@ process_all_functions (void)
 static void
 output_gcov_file (const char *file_name, source_info *src)
 {
+  if (flag_genode_autopilot) {
+
+	/* output only if the file name appears in the .gcan file */
+
+    FILE *annotate_file = fopen(an_file_name, "r");
+
+    if (!annotate_file)
+      return;
+
+    char *source_file = NULL;
+    size_t len = 0;
+    bool annotate = false;
+
+    while (getline(&source_file, &len, annotate_file) != -1) {
+
+      /* remove '\n' */
+      source_file[strlen(source_file) - 1] = 0;
+
+      if (strstr(src->coverage.name, source_file) != NULL) {
+        annotate = true;
+        break;
+      }
+    }
+
+    fclose(annotate_file);
+
+    if (!annotate)
+      return;
+  }
+
   char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name);
 
   if (src->coverage.lines)
     {
-      FILE *gcov_file = fopen (gcov_file_name, "w");
+      FILE *gcov_file = flag_genode_autopilot ?
+                        stdout :
+                        fopen (gcov_file_name, "w");
       if (gcov_file)
 	{
 	  fnotice (stdout, "Creating '%s'\n", gcov_file_name);
@@ -1375,7 +1479,8 @@ output_gcov_file (const char *file_name, source_info *src)
 	  if (ferror (gcov_file))
 	    fnotice (stderr, "Error writing output file '%s'\n",
 		     gcov_file_name);
-	  fclose (gcov_file);
+	  if (!flag_genode_autopilot)
+	    fclose (gcov_file);
 	}
       else
 	fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
@@ -1422,7 +1527,8 @@ generate_results (const char *file_name)
 	file_name = canonicalize_name (file_name);
     }
 
-  gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
+  if (file_name)
+    gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
 
   json::object *root = new json::object ();
   root->set ("format_version", new json::string ("1"));
@@ -1430,7 +1536,8 @@ generate_results (const char *file_name)
 
   if (bbg_cwd != NULL)
     root->set ("current_working_directory", new json::string (bbg_cwd));
-  root->set ("data_file", new json::string (file_name));
+  if (file_name)
+    root->set ("data_file", new json::string (file_name));
 
   json::array *json_files = new json::array ();
   root->set ("files", json_files);
@@ -1459,7 +1566,10 @@ generate_results (const char *file_name)
 	file_summary (&src->coverage);
       total_lines += src->coverage.lines;
       total_executed += src->coverage.lines_executed;
-      if (flag_gcov_file)
+
+      if (flag_gcov_file &&
+          !(flag_genode_autopilot &&
+            (src->coverage.lines_executed == src->coverage.lines)))
 	{
 	  if (flag_json_format)
 	    output_json_intermediate_file (json_files, src);
@@ -1547,7 +1657,8 @@ create_file_names (const char *file_name)
   /* Free previous file names.  */
   free (bbg_file_name);
   free (da_file_name);
-  da_file_name = bbg_file_name = NULL;
+  free (an_file_name);
+  da_file_name = bbg_file_name = an_file_name = NULL;
   bbg_file_time = 0;
   bbg_stamp = 0;
 
@@ -1593,6 +1704,10 @@ create_file_names (const char *file_name)
   strcpy (da_file_name, name);
   strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
 
+  an_file_name = XNEWVEC (char, length + strlen (GCOV_ANNOTATE_SUFFIX) + 1);
+  strcpy (an_file_name, name);
+  strcpy (an_file_name + length, GCOV_ANNOTATE_SUFFIX);
+
   free (name);
   return;
 }
@@ -1649,6 +1764,18 @@ find_source (const char *file_name)
 #endif
 	  && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
 	src->coverage.name += source_length + 1;
+
+      if (flag_genode_autopilot) {
+
+        /* strip path of the Genode depot */
+
+        char *depot_relative_path = strstr(src->name, "/depot/");
+        if (depot_relative_path) {
+          src->name = depot_relative_path + strlen("/depot");
+          src->coverage.name = src->name;
+        }
+      }
+
       if (!stat (src->name, &status))
 	src->file_time = status.st_mtime;
     }
