===================================================================
@@ -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 (strcasestr (name, ".c") ||
+ strcasestr (name, ".cc") ||
+ strcasestr (name, ".cpp") ||
+ strcasestr (name, ".c++"))
+ return 1;
+
+ /* Replace ".proto" with ".pb.cc". Since the two strings have the same
+ length, we simplfy do a strcpy. */
+ if ((p = strcasestr (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, 1);
+
+ free (line);
+ line = NULL;
+ }
+
+ return 0;
+}
+
+#define GENFILE_PREFIX "/genfiles/"
+
+/* Return 1 if module NAME is available 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, --path_substr_replace <str> Replace string in path\n");
fnotice (file, " -s, --scale <float or simple-frac> Scale the profile counters\n");
+ fnotice (file, " -u, --use_imports_file <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;;
===================================================================
@@ -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,112 @@ 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);
+
+void
+set_use_existing_grouping (void)
+{
+ flag_use_existing_grouping = 1;
+}
+
+#ifdef IN_GCOV_TOOL
+extern const char *get_source_profile_dir (void);
+
+/* 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);
+
+ source_dir = get_source_profile_dir ();
+ gcc_assert (source_dir);
+ 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 *);
+
+#endif /* IN_GCOV_TOOL */
+
+/* Use the module grouping from existing imports files in
+ the profile directory. */
+
+static void
+read_modu_groups_from_imports_files (void)
+{
+#ifdef IN_GCOV_TOOL
+ 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);
+ }
+#else /* !IN_GCOV_TOOL */
+ gcc_assert (0);
+#endif /* IN_GCOV_TOOL */
+}
+
/* Compute module groups needed for L-IPO compilation. */
void
@@ -2192,6 +2325,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 +2472,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++)
{
===================================================================
@@ -267,6 +267,114 @@ 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.
+ Dup the string and split it into tokens with
+ ',' and ':' as the delimiters. */
+ 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 ((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;
+
+ /* Dup the string and split it into tokens with
+ ',' and ':' as the delimiters. */
+ 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 +388,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 +407,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 +448,11 @@ 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 = 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 +529,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 +574,39 @@ 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))
+ {
+ if (verbose)
+ 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 +641,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);