Hi, The attached patch adds some new features to gcov-tool. It aims to rewrite LIPO profile for reuse, debug or performance tuning purpose.
-l, --modu_list <file> Only use the modules in this file -r, --string Replace string in path -u, --use_imports_file Use the grouping in import files. -l uses only the modules in specified file to compute module grouping (and subsequent dumping). -r replaces the pattern specified in the argument. The format is: old_str1:new_str1[,old_str2:new_str2]*, only the first occurrence is replaced. -u skips the run-time module grouping computation and reuses the one comes with the profiles (which is user editable). Tested with profiles from google internal benchmarks. -Rong
2014-01-29 Rong Xu <x...@google.com> * gcc/gcov-tool.c (mod_name_id): New type of the hashtable entry. (mod_name_id_htab_hash): Hash function for module-name and module-id hashtab. (mod_name_id_hash_eq): Comparison function for the hashtab. (module_name_hash_lookup): Lookup function of the hashtab. (is_lipo_source_type): Find if a file is of LIPO target source. (lipo_process_name_string): Support of -l. (lipo_process_modu_list): Ditto. (is_module_available): Support of -u. (get_module_id_from_name): Ditto. (print_rewrite_usage_message): Add -u -l and -r support. (do_rewrite): Ditto. (print_version): Ditto. (process_args): Ditto. * libgcc/dyn-ipa.c (flag_use_existing_grouping): New flag for -u. (init_dyn_call_graph): Support of -l. (__gcov_finalize_dyn_callgraph): Ditto. (gcov_build_callgraph): Ditto. (gcov_compute_cutoff_count): Ditto. (gcov_process_cgraph_node): Ditto. (build_modu_graph): Ditto. (gcov_compute_module_groups_eager_propagation): Ditto. (gcov_compute_random_module_groups): Ditto. (gcov_write_module_infos): Ditto. (gcov_dump_callgraph): Ditto. (set_use_existing_grouping): Support of -u. (open_imports_file): Ditto. (read_modu_groups_from_imports_files): Ditto. (__gcov_compute_module_groups): Ditto. * libgcc/libgcov-util.c (substitute_string): Support -r. (lipo_set_substitute_string): Ditto. (lipo_process_substitute_string_1): Ditto. (lipo_process_substitute_string): Ditto. (read_gcda_file): Ditto. (flag_use_modu_list): Support of -l (set_use_modu_list): Ditto. (ftw_read_file): Ditto. (source_profile_dir): Support of -u. (get_source_profile_dir): Ditto. (gcov_read_profile_dir): Ditto. Index: gcc/gcov-tool.c =================================================================== --- gcc/gcov-tool.c (revision 207055) +++ gcc/gcov-tool.c (working copy) @@ -29,6 +29,7 @@ see the files COPYING3 and COPYING.RUNTIME respect #include "coretypes.h" #include "tm.h" #include "intl.h" +#include "hashtab.h" #include "diagnostic.h" #include "version.h" #include "gcov-io.h" @@ -38,6 +39,7 @@ see the files COPYING3 and COPYING.RUNTIME respect #include <ftw.h> #include <getopt.h> #include "params.h" +#include <string.h> extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int); extern int gcov_profile_normalize (struct gcov_info*, gcov_type); @@ -47,9 +49,11 @@ extern struct gcov_info* gcov_read_profile_dir (co extern void gcov_exit (void); extern void set_gcov_list (struct gcov_info *); extern void gcov_set_verbose (void); +extern void set_use_existing_grouping (void); +extern void set_use_modu_list (void); +extern void lipo_set_substitute_string (const char *); -static int verbose; - +/* The following defines are needed by dyn-ipa.c. */ gcov_unsigned_t __gcov_lipo_grouping_algorithm; gcov_unsigned_t __gcov_lipo_merge_modu_edges; gcov_unsigned_t __gcov_lipo_weak_inclusion; @@ -60,6 +64,8 @@ gcov_unsigned_t __gcov_lipo_random_seed; gcov_unsigned_t __gcov_lipo_dump_cgraph; gcov_unsigned_t __gcov_lipo_propagate_scale; +static int verbose; + /* Remove file NAME if it has a gcda suffix. */ static int @@ -285,6 +291,189 @@ profile_rewrite (const char *d1, const char *out, return 0; } +/* This is the hashtab entry to store a name and mod_id pair. */ +typedef struct { + const char *name; + unsigned id; +} mod_name_id; + +/* Hash and comparison functions for strings. */ + +static unsigned +mod_name_id_htab_hash (const void *s_p) +{ + const char *s = ((const mod_name_id *) s_p)->name; + return (*htab_hash_string) (s); +} + +static int +mod_name_id_hash_eq (const void *s1_p, const void *s2_p) +{ + return strcmp (((const mod_name_id *) s1_p)->name, + ((const mod_name_id *) s2_p)->name) == 0; +} + +static htab_t mod_name_id_hash_table; + +/* Look up an entry in the hash table. STRING is the module name. + CREATE controls to insert to htab or not. + If (*ID_P != 0), we write (*ID_P) to htab. + If (*ID_P == 0), we write module_id to (*ID_P). + return 1 if an entry is found and otherwise 0. */ + +static int +module_name_hash_lookup (const char *string, unsigned *id_p, int create) +{ + void **e; + mod_name_id t; + + t.name = string; + e = htab_find_slot (mod_name_id_hash_table, &t, + create ? INSERT : NO_INSERT); + if (e == NULL) + return 0; + if (*e == NULL) + { + *e = XNEW (mod_name_id *); + (*(mod_name_id **)e)->name = xstrdup (string); + } + if (id_p) + { + if (*id_p != 0) + (*(mod_name_id **)e)->id = *id_p; + else + *id_p = (*(mod_name_id **)e)->id; + } + return 1; +} + +/* Return 1 if NAME is of a source type that LIPO targets. + Return 0 otherwise. */ + +static int +is_lipo_source_type (char *name) +{ + char *p; + + if (strstr (name, ".c") || + strstr (name, ".cc") || + strstr (name, ".cpp") || + strstr (name, ".c++") || + strstr (name, ".CPP") || + strstr (name, ".C")) + return 1; + + if ((p = strstr (name, ".proto")) != NULL) + { + strcpy (p, ".pb.cc"); + return 1; + } + + return 0; +} + +/* Convert/process the names from dependence query to a + stardard format. Return NULL if this is not a lipo + target source. */ + +static char * +lipo_process_name_string (char *name) +{ + char *p; + + if (name == NULL) + return NULL; + if (strlen (name) == 0) + return NULL; + + if (!is_lipo_source_type (name)) + return NULL; + + /* Overwrite ':' with '/'. */ + if ((p = strchr (name, ':')) != NULL) + *p = '/'; + + /* Remove "//". */ + if (name[0] == '/' && name[1] =='/') + name += 2; + + return name; +} + +/* Store the list of source modules in INPUT_FILE to internal hashtab. */ + +static int +lipo_process_modu_list (const char *input_file) +{ + FILE *fd; + char *line = NULL; + size_t linecap = 0; + char *name; + + set_use_modu_list (); + + if ((fd = fopen (input_file, "r")) == NULL) + { + fnotice (stderr, "Cannot open %s\n", input_file); + return -1; + } + + /* Read all the modules */ + while (getline (&line, &linecap, fd) != -1) + { + name = strtok (line, " \t\n"); + name = lipo_process_name_string (name); + if (name) + module_name_hash_lookup (name, 0, INSERT); + + free (line); + line = NULL; + } + + return 0; +} + +#define GENFILE_PREFIX "/genfiles/" + +/* Return 1 if module NAME is availale to be used in the target + profile. CREATE controls to insert to htab or not. + If (*ID_P != 0), we write (*ID_P) to htab. + If (*ID_P == 0), we write module_id to (*ID_P). + return 1 if an entry is found and otherwise 0. */ + +int +is_module_available (const char *name, unsigned *id_p, int create) +{ + char *buf, *p; + int ret; + + if (mod_name_id_hash_table == NULL) + return 1; + + buf = xstrdup (name); + /* Remove genfile string. */ + if ((p = strstr (buf, GENFILE_PREFIX)) != NULL) + p += strlen (GENFILE_PREFIX); + else + p = buf; + + ret = module_name_hash_lookup (p, id_p, create); + free (buf); + return ret; +} + +/* Return module_ident for module NAME. + return 0 if the module NAME is not available. */ + +int +get_module_id_from_name (const char *name) +{ + unsigned mod_id = 0; + if (is_module_available (name, &mod_id, 0) == 1) + return mod_id; + return 0; +} + /* Usage function for profile rewrite. */ static void @@ -295,7 +484,10 @@ print_rewrite_usage_message (int error_p) fnotice (file, " rewrite [options] <dir> Rewrite coverage file contents\n"); fnotice (file, " -v, --verbose Verbose mode\n"); fnotice (file, " -o, --output <dir> Output directory\n"); + fnotice (file, " -l, --modu_list <file> Only use the modules in this file\n"); + fnotice (file, " -r, --string Replace string in path\n"); fnotice (file, " -s, --scale <float or simple-frac> Scale the profile counters\n"); + fnotice (file, " -u, --use_imports_file Use the grouping in import files.\n"); fnotice (file, " -n, --normalize <long long> Normalize the profile\n"); } @@ -303,7 +495,10 @@ static const struct option rewrite_options[] = { { "verbose", no_argument, NULL, 'v' }, { "output", required_argument, NULL, 'o' }, + { "modu_list", required_argument, NULL, 'l' }, + { "string", required_argument, NULL, 'r' }, { "scale", required_argument, NULL, 's' }, + { "use_imports_file", no_argument, NULL, 'u' }, { "normalize", required_argument, NULL, 'n' }, { 0, 0, 0, 0 } }; @@ -331,8 +526,11 @@ do_rewrite (int argc, char **argv) int numerator = -1; int denominator = -1; + mod_name_id_hash_table = htab_create (500, mod_name_id_htab_hash, + mod_name_id_hash_eq, NULL); + optind = 0; - while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1) + while ((opt = getopt_long (argc, argv, "vo:l:r:s:un:", rewrite_options, NULL)) != -1) { switch (opt) { @@ -343,6 +541,15 @@ do_rewrite (int argc, char **argv) case 'o': output_dir = optarg; break; + case 'l': + lipo_process_modu_list (optarg); + break; + case 'r': + lipo_set_substitute_string (optarg); + break; + case 'u': + set_use_existing_grouping (); + break; case 'n': if (scale != 1.0) { @@ -437,7 +644,7 @@ static void print_version (void) { fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string); - fprintf (stdout, "Copyright %s 2014 Free Software Foundation, Inc.\n", + fnotice (stdout, "Copyright %s 2014 Free Software Foundation, Inc.\n", _("(C)")); fnotice (stdout, _("This is free software; see the source for copying conditions.\n" @@ -496,7 +703,7 @@ process_args (int argc, char **argv) sscanf (optarg, "%d", &ret); if (ret != 0 && ret != 1) { - fprintf (stderr, "LIPO grouping algorithm can only be 0 or 1. \n"); + fnotice (stderr, "LIPO grouping algorithm can only be 0 or 1\n"); exit (-1); } __gcov_lipo_grouping_algorithm = ret; @@ -505,7 +712,7 @@ process_args (int argc, char **argv) sscanf (optarg, "%d", &ret); if (ret < 1) { - fprintf (stderr, "LIPO random group size needs to be positive.\n"); + fnotice (stderr, "LIPO random group size needs to be positive\n"); exit (-1); } __gcov_lipo_random_group_size = ret; @@ -518,7 +725,7 @@ process_args (int argc, char **argv) sscanf (optarg, "%d", &ret); if (ret < 0) { - fprintf (stderr, "LIPO max-memory size needs to be positive. \n"); + fnotice (stderr, "LIPO max-memory size needs to be positive\n"); exit (-1); } __gcov_lipo_max_mem = ret; @@ -527,7 +734,7 @@ process_args (int argc, char **argv) sscanf (optarg, "%d", &ret); if (ret < 0 || ret > 100) { - fprintf (stderr, "LIPO cutoff value range is [0, 100]. \n"); + fnotice (stderr, "LIPO cutoff value range is [0, 100]\n"); exit (-1); } __gcov_lipo_cutoff = ret;; Index: libgcc/dyn-ipa.c =================================================================== --- libgcc/dyn-ipa.c (revision 207055) +++ libgcc/dyn-ipa.c (working copy) @@ -182,6 +182,7 @@ enum GROUPING_ALGORITHM static int flag_alg_mode; static int flag_modu_merge_edges; static int flag_weak_inclusion; +static int flag_use_existing_grouping; static gcov_unsigned_t mem_threshold; /* Returns 0 if no dump is enabled. Returns 1 if text form graph @@ -364,6 +365,7 @@ static void init_dyn_call_graph (void) { unsigned num_modules = 0; + unsigned max_module_id = 0; struct gcov_info *gi_ptr; const char *env_str; int do_dump = (do_cgraph_dump () != 0); @@ -381,12 +383,22 @@ init_dyn_call_graph (void) gi_ptr = gcov_list; for (; gi_ptr; gi_ptr = gi_ptr->next) - num_modules++; + { + unsigned mod_id = get_module_ident (gi_ptr); + num_modules++; + if (max_module_id < mod_id) + max_module_id = mod_id; + } + if (num_modules < max_module_id) + num_modules = max_module_id; + the_dyn_call_graph.num_modules = num_modules; the_dyn_call_graph.modules = XNEWVEC (struct gcov_info *, num_modules); + memset (the_dyn_call_graph.modules, 0, + num_modules * sizeof (struct gcov_info*)); the_dyn_call_graph.sup_modules = XNEWVEC (struct dyn_module_info, num_modules); @@ -476,13 +488,16 @@ void __gcov_finalize_dyn_callgraph (void) { unsigned i; - struct gcov_info *gi_ptr; for (i = 0; i < the_dyn_call_graph.num_modules; i++) { - gi_ptr = the_dyn_call_graph.modules[i]; + struct gcov_info *gi_ptr = the_dyn_call_graph.modules[i]; const struct gcov_fn_info *fi_ptr; unsigned f_ix; + + if (gi_ptr == NULL) + continue; + for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { struct dyn_cgraph_node *node; @@ -651,6 +666,8 @@ gcov_build_callgraph (void) unsigned f_ix, i; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { @@ -901,6 +918,8 @@ gcov_compute_cutoff_count (void) unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { @@ -1239,7 +1258,8 @@ gcov_process_cgraph_node (struct dyn_cgraph_node * { struct gcov_info *callee_mod_info = get_module_info (callee_mod_id); - imp_mod_set_insert (imp_modules, callee_mod_info, callee_mod_wt); + if (callee_mod_info) + imp_mod_set_insert (imp_modules, callee_mod_info, callee_mod_wt); } } @@ -1629,6 +1649,8 @@ build_modu_graph (gcov_type cutoff_count) unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; modu_nodes[m_ix].module = gi_ptr; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) @@ -1950,6 +1972,8 @@ gcov_compute_module_groups_eager_propagation (gcov unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { @@ -1972,6 +1996,8 @@ gcov_compute_module_groups_eager_propagation (gcov unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { @@ -2036,7 +2062,8 @@ gcov_compute_random_module_groups (unsigned max_gr if (mod_idx == m_ix) continue; imp_mod_info = get_module_info (mod_idx + 1); - if (!imp_mod_set_insert (imp_modules, imp_mod_info, 1.0)) + if (imp_mod_info && + !imp_mod_set_insert (imp_modules, imp_mod_info, 1.0)) i++; } } @@ -2155,6 +2182,108 @@ gcov_write_module_infos (struct gcov_info *mod_inf } } +/* Set to use module grouping from existing imports files in + the profile directory. */ + +void +set_use_existing_grouping (void) +{ + flag_use_existing_grouping = 1; +} + +#ifdef IN_GCOV_TOOL +extern const char *get_source_profile_dir (void); +#endif + +/* find and open the imports files based on da_filename + in GI_PTR. */ + +static FILE * +open_imports_file (struct gcov_info *gi_ptr) +{ + const char *gcda_name; + char *imports_name; + const char *source_dir = ""; + + if (gi_ptr == NULL || gi_ptr->mod_info == NULL) + return NULL; + + gcda_name = gi_ptr->mod_info->da_filename; + gcc_assert (gcda_name); + +#ifdef IN_GCOV_TOOL + source_dir = get_source_profile_dir (); + gcc_assert (source_dir); +#endif + imports_name = (char *) alloca (strlen (gcda_name) + strlen (source_dir) + + strlen (".gcda.imports") + 2); + strcpy (imports_name, source_dir); + strcat (imports_name, "/"); + strcat (imports_name, gcda_name); + strcat (imports_name, ".gcda.imports"); + return fopen (imports_name, "r"); +} + +extern int get_module_id_from_name (const char *); + +/* Use the module grouping from existing imports files in + the profile directory. */ + +static void +read_modu_groups_from_imports_files (void) +{ + unsigned m_ix; + + init_dyn_call_graph (); + + for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) + { + struct gcov_info *gi_ptr = the_dyn_call_graph.modules[m_ix]; + FILE *fd; + struct dyn_pointer_set *imp_modules; + + if (gi_ptr == NULL) + continue; + + imp_modules = gcov_get_module_imp_module_set + (&the_dyn_call_graph.sup_modules[m_ix]); + + if ((fd = open_imports_file (gi_ptr)) != NULL) + { + char *line = NULL; + size_t linecap = 0; + while (getline (&line, &linecap, fd) != -1) + { + unsigned mod_id = 0; + char *name = strtok (line, " \t\n"); + + if (name && (mod_id = get_module_id_from_name (name))) + { + struct gcov_info *imp_mod_info; + unsigned mod_idx = mod_id - 1; + if (mod_idx == m_ix) + continue; + imp_mod_info = get_module_info (mod_idx + 1); + imp_mod_set_insert (imp_modules, imp_mod_info, 1.0); + } + free (line); + line = NULL; + } + fclose (fd); + } + } + + /* Now compute the export attribute */ + for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) + { + struct dyn_module_info *mi + = &the_dyn_call_graph.sup_modules[m_ix]; + if (mi->imported_modules) + pointer_set_traverse (mi->imported_modules, + gcov_mark_export_modules, 0, 0, 0); + } +} + /* Compute module groups needed for L-IPO compilation. */ void @@ -2192,6 +2321,12 @@ __gcov_compute_module_groups (void) return; } + if (flag_use_existing_grouping) + { + read_modu_groups_from_imports_files (); + return; + } + /* First compute dynamic call graph. */ gcov_build_callgraph (); @@ -2333,6 +2468,8 @@ gcov_dump_callgraph (gcov_type cutoff_count) unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { Index: libgcc/libgcov-util.c =================================================================== --- libgcc/libgcov-util.c (revision 207055) +++ libgcc/libgcov-util.c (working copy) @@ -267,6 +267,111 @@ read_gcda_finalize (struct gcov_info *obj_info) extern void gcov_read_module_info (struct gcov_module_info *mod_info, gcov_unsigned_t len); +/* Substitute string is of this format: + old_sub1:new_sub1[,old_sub2:new_sub2] + Note that we only apply the substutution ONE time, for the first match. */ + +static const char *substitute_string; + +/* A global function to set the substitute string. */ + +void +lipo_set_substitute_string (const char *str) +{ + char *sub_dup = xstrdup (str); + char *cur_sub = sub_dup; + + /* First check if the str is in the right form. */ + do + { + char *new_str; + char *next = strchr (cur_sub, ','); + if (next) + *next++ = '\0'; + new_str = strchr (cur_sub, ':'); + if (!new_str) + { + fprintf (stderr, "Warning: Skip invalid substibution string:%s\n", + str); + free (sub_dup); + return; + } + *new_str++ = '\0'; + cur_sub = next; + } while (cur_sub); + + free (sub_dup); + substitute_string = str; +} + +/* Replace the first occurance of CUT_STR to NEW_STR in INPUT_STR. */ + +static char * +lipo_process_substitute_string_1 (char *input_str, + const char *cur_str, + const char *new_str) +{ + char *p; + + if (!input_str || !cur_str || !new_str) + return input_str; + + if (cur_str != NULL + && (p = strstr (input_str, cur_str)) != NULL) + { + char *t; + + if (verbose) + printf ("Substitute: %s \n", input_str); + t = (char*) xmalloc (strlen (input_str) + 1 + + strlen (new_str) - strlen (cur_str)); + *p = 0; + + strcpy (t, input_str); + strcat (t, new_str); + strcat (t, p + strlen (cur_str)); + if (verbose) + printf (" --> %s\n", t); + return t; + } + + return input_str; +} + +/* Parse the substitute string and apply to the INPUT_STR. */ + +static char * +lipo_process_substitute_string (char *input_str) +{ + char *sub_dup, *cur_sub, *ret; + + if (substitute_string == NULL) + return input_str; + + sub_dup = xstrdup (substitute_string); + cur_sub = sub_dup; + ret = input_str; + + do + { + char *new_str, *new_input; + char *next = strchr (cur_sub, ','); + if (next) + *next++ = '\0'; + new_str = strchr (cur_sub, ':'); + gcc_assert (new_str); + *new_str++ = '\0'; + new_input = ret; + ret = lipo_process_substitute_string_1 (new_input, cur_sub, new_str); + if (ret != new_input) + free (new_input); + cur_sub = next; + } while (cur_sub); + + free (sub_dup); + return ret; +} + /* This function reads module_info from a gcda file. */ static void @@ -280,7 +385,11 @@ tag_module_info (unsigned tag ATTRIBUTE_UNUSED, un gcov_read_module_info (mod_info, length); if (mod_info->is_primary) - curr_module_info = mod_info; + { + mod_info->da_filename = + lipo_process_substitute_string (mod_info->da_filename); + curr_module_info = mod_info; + } else free (mod_info); } @@ -295,7 +404,8 @@ read_gcda_file (const char *filename) unsigned depth = 0; unsigned magic, version; struct gcov_info *obj_info; - int i; + int i, len; + char *str_dup; for (i=0; i< GCOV_COUNTERS; i++) k_ctrs_mask[i] = 0; @@ -335,15 +445,12 @@ read_gcda_file (const char *filename) curr_fn_info = 0; curr_module_info = 0; - { - char *str_dup = (char*) xmalloc (strlen (filename) + 1); - int len; + str_dup = xstrdup (filename); + str_dup = lipo_process_substitute_string (xstrdup (filename)); + obj_info->filename = str_dup; - strcpy (str_dup, filename); - obj_info->filename = str_dup; - if ((len = strlen (filename)) > max_filename_len) - max_filename_len = len; - } + if ((len = strlen (str_dup)) > max_filename_len) + max_filename_len = len; /* Read stamp. */ obj_info->stamp = gcov_read_unsigned (); @@ -420,6 +527,21 @@ read_gcda_file (const char *filename) return obj_info; } +extern int is_module_available (const char *, unsigned *, int); + +/* If only use the modules in the modu_list. */ + +static int flag_use_modu_list; + +/* Set to use only the modules in the modu_list file. */ + +void +set_use_modu_list (void) +{ + flag_use_modu_list = 1; +} + + /* This will be called by ftw(). It opens and read a gcda file FILENAME. Return a non-zero value to stop the tree walk. */ @@ -450,12 +572,38 @@ ftw_read_file (const char *filename, obj_info = read_gcda_file (filename); + if (obj_info->mod_info) + { + unsigned mod_id = obj_info->mod_info->ident; + int create = (flag_use_modu_list ? 0 : 1); + + if (!is_module_available (obj_info->mod_info->source_filename, + &mod_id, create)) + { + fprintf (stderr, "warning: module %s (%d) is not avail\n", + obj_info->mod_info->source_filename, mod_id); + return 0; + } + } + obj_info->next = gcov_info_head; gcov_info_head = obj_info; return 0; } +/* Source profile directory name. */ + +static const char *source_profile_dir; + +/* Return Source profile directory name. */ + +const char * +get_source_profile_dir (void) +{ + return source_profile_dir; +} + /* Initializer for reading a profile dir. */ static inline void @@ -490,6 +638,8 @@ gcov_read_profile_dir (const char* dir_name, int r fprintf (stderr, "%s is not a directory\n", dir_name); return NULL; } + source_profile_dir = getcwd (NULL, 0); + ftw (".", ftw_read_file, 50); ret = chdir (pwd); free (pwd);