}
static void
-allocate_filename_struct (struct gcov_filename_aux *gf)
+allocate_filename_struct (struct gcov_filename *gf)
{
const char *gcov_prefix;
- int gcov_prefix_strip = 0;
size_t prefix_length;
- char *gi_filename_up;
+ int strip = 0;
- gcc_assert (gf);
{
/* Check if the level of dirs to strip off specified. */
char *tmp = getenv("GCOV_PREFIX_STRIP");
if (tmp)
{
- gcov_prefix_strip = atoi (tmp);
+ strip = atoi (tmp);
/* Do not consider negative values. */
- if (gcov_prefix_strip < 0)
- gcov_prefix_strip = 0;
+ if (strip < 0)
+ strip = 0;
}
}
+ gf->strip = strip;
/* Get file name relocation prefix. Non-absolute values are ignored. */
gcov_prefix = getenv("GCOV_PREFIX");
- if (gcov_prefix)
- {
- prefix_length = strlen(gcov_prefix);
-
- /* Remove an unnecessary trailing '/' */
- if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
- prefix_length--;
- }
- else
- prefix_length = 0;
+ prefix_length = gcov_prefix ? strlen (gcov_prefix) : 0;
+
+ /* Remove an unnecessary trailing '/' */
+ if (prefix_length && IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
+ prefix_length--;
/* If no prefix was specified and a prefix stip, then we assume
relative. */
- if (gcov_prefix_strip != 0 && prefix_length == 0)
+ if (!prefix_length && gf->strip)
{
gcov_prefix = ".";
prefix_length = 1;
}
- /* Allocate and initialize the filename scratch space plus one. */
- gi_filename = (char *) xmalloc (prefix_length + gcov_max_filename + 2);
- if (prefix_length)
- memcpy (gi_filename, gcov_prefix, prefix_length);
- gi_filename_up = gi_filename + prefix_length;
+ gf->prefix = prefix_length;
- gf->gi_filename_up = gi_filename_up;
- gf->prefix_length = prefix_length;
- gf->gcov_prefix_strip = gcov_prefix_strip;
+ /* Allocate and initialize the filename scratch space. */
+ gf->filename = (char *) xmalloc (gf->max_length + prefix_length + 2);
+ if (prefix_length)
+ memcpy (gf->filename, gcov_prefix, prefix_length);
}
/* Open a gcda file specified by GI_FILENAME.
Return -1 on error. Return 0 on success. */
static int
-gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
+gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
+ struct gcov_filename *gf)
{
- int gcov_prefix_strip;
- size_t prefix_length;
- char *gi_filename_up;
- const char *fname, *s;
+ const char *fname = gi_ptr->filename;
+ char *dst = gf->filename + gf->prefix;
- gcov_prefix_strip = gf->gcov_prefix_strip;
- gi_filename_up = gf->gi_filename_up;
- prefix_length = gf->prefix_length;
fname = gi_ptr->filename;
- /* Avoid to add multiple drive letters into combined path. */
- if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
- fname += 2;
-
/* Build relocated filename, stripping off leading
directories from the initial filename if requested. */
- if (gcov_prefix_strip > 0)
+ if (gf->strip > 0)
{
- int level = 0;
+ const char *probe = fname;
+ int level;
- s = fname;
- if (IS_DIR_SEPARATOR(*s))
- ++s;
+ /* Remove a leading separator, without counting it. */
+ if (IS_DIR_SEPARATOR (*probe))
+ probe++;
- /* Skip selected directory levels. */
- for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
- if (IS_DIR_SEPARATOR(*s))
+ /* Skip selected directory levels. If we fall off the end, we
+ keep the final part. */
+ for (level = gf->strip; *probe && level; probe++)
+ if (IS_DIR_SEPARATOR (*probe))
{
- fname = s;
- level++;
+ fname = probe;
+ level--;
}
}
/* Update complete filename with stripped original. */
- if (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
+ if (gf->prefix)
{
- /* If prefix is given, add directory separator. */
- strcpy (gi_filename_up, "/");
- strcpy (gi_filename_up + 1, fname);
+ /* Avoid to add multiple drive letters into combined path. */
+ if (HAS_DRIVE_SPEC(fname))
+ fname += 2;
+
+ if (!IS_DIR_SEPARATOR (*fname))
+ *dst++ = '/';
}
- else
- strcpy (gi_filename_up, fname);
+ strcpy (dst, fname);
- if (!gcov_open (gi_filename))
+ if (!gcov_open (gf->filename))
{
/* Open failed likely due to missed directory.
Create directory and retry to open file. */
- if (create_file_directory (gi_filename))
+ if (create_file_directory (gf->filename))
{
- fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
+ fprintf (stderr, "profiling:%s:Skip\n", gf->filename);
return -1;
}
- if (!gcov_open (gi_filename))
+ if (!gcov_open (gf->filename))
{
- fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
+ fprintf (stderr, "profiling:%s:Cannot open\n", gf->filename);
return -1;
}
}
struct gcov_summary summary;
};
+/* A struct that bundles all the related information about the
+ gcda filename. */
+
+struct gcov_filename
+{
+ char *filename; /* filename buffer */
+ size_t max_length; /* maximum filename length */
+ int strip; /* leading chars to strip from filename */
+ size_t prefix; /* chars to prepend to filename */
+};
+
/* Chain of per-object gcov structures. */
#ifndef IN_GCOV_TOOL
/* We need to expose this static variable when compiling for gcov-tool. */
#endif
struct gcov_info *gcov_list;
-/* Size of the longest file name. */
-/* We need to expose this static variable when compiling for gcov-tool. */
-#ifndef IN_GCOV_TOOL
-static
-#endif
-size_t gcov_max_filename = 0;
-
/* Flag when the profile has already been dumped via __gcov_dump(). */
static int gcov_dump_complete;
}
}
-/* gcda filename. */
-static char *gi_filename;
/* buffer for the fn_data from another program. */
static struct gcov_fn_buffer *fn_buffer;
/* buffer for summary from other programs to be written out. */
functions executed once may mistakely become cold. */
static int run_accounted = 0;
-/* This funtions computes the program level summary and the histo-gram.
- It computes and returns CRC32 and stored summary in THIS_PRG. */
+/* This function computes the program level summary and the histo-gram.
+ It computes and returns CRC32 and stored summary in THIS_PRG.
+ Also determines the longest filename length of the info files. */
static gcov_unsigned_t
-gcov_exit_compute_summary (struct gcov_summary *this_prg)
+gcov_exit_compute_summary (struct gcov_summary *this_prg,
+ size_t *max_length)
{
struct gcov_info *gi_ptr;
const struct gcov_fn_info *gfi_ptr;
/* Find the totals for this execution. */
memset (this_prg, 0, sizeof (*this_prg));
+ *max_length = 0;
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
+ size_t len = strlen (gi_ptr->filename);
+ if (len > *max_length)
+ *max_length = len;
+
crc32 = crc32_unsigned (crc32, gi_ptr->stamp);
crc32 = crc32_unsigned (crc32, gi_ptr->n_functions);
return crc32;
}
-/* A struct that bundles all the related information about the
- gcda filename. */
-struct gcov_filename_aux{
- char *gi_filename_up;
- int gcov_prefix_strip;
- size_t prefix_length;
-};
-
/* Including system dependent components. */
#include "libgcov-driver-system.c"
Return -1 on error. In this case, caller will goto read_fatal. */
static int
-gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
+gcov_exit_merge_gcda (const char *filename,
+ struct gcov_info *gi_ptr,
struct gcov_summary *prg_p,
struct gcov_summary *this_prg,
gcov_position_t *summary_pos_p,
struct gcov_summary_buffer **sum_tail = &sum_buffer;
length = gcov_read_unsigned ();
- if (!gcov_version (gi_ptr, length, gi_filename))
+ if (!gcov_version (gi_ptr, length, filename))
return -1;
length = gcov_read_unsigned ();
it back out -- we'll be inserting data before
this point, so cannot simply keep the data in the
file. */
- fn_tail = buffer_fn_data (gi_filename,
- gi_ptr, fn_tail, f_ix);
+ fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
if (!fn_tail)
goto read_mismatch;
continue;
{
read_mismatch:;
gcov_error ("profiling:%s:Merge mismatch for %s %u\n",
- gi_filename, f_ix >= 0 ? "function" : "summary",
+ filename, f_ix >= 0 ? "function" : "summary",
f_ix < 0 ? -1 - f_ix : f_ix);
return -1;
}
return 0;
read_error:
- gcov_error ("profiling:%s:%s merging\n", gi_filename,
+ gcov_error ("profiling:%s:%s merging\n", filename,
error < 0 ? "Overflow": "Error");
return -1;
}
Return -1 on error. Return 0 on success. */
static int
-gcov_exit_merge_summary (const struct gcov_info *gi_ptr, struct gcov_summary *prg,
+gcov_exit_merge_summary (const char *filename,
+ const struct gcov_info *gi_ptr, struct gcov_summary *prg,
struct gcov_summary *this_prg, gcov_unsigned_t crc32,
struct gcov_summary *all_prg __attribute__ ((unused)))
{
else if (cs_prg->runs)
{
gcov_error ("profiling:%s:Merge mismatch for summary.\n",
- gi_filename);
+ filename);
return -1;
}
#if !GCOV_LOCKED
{
gcov_error ("profiling:%s:Data file mismatch - some "
"data files may have been concurrently "
- "updated without locking support\n", gi_filename);
+ "updated without locking support\n", filename);
all_prg->checksum = ~0u;
}
#endif
summaries separate. */
static void
-gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf,
+gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
gcov_unsigned_t crc32, struct gcov_summary *all_prg,
struct gcov_summary *this_prg)
{
/* Merge data from file. */
if (tag != GCOV_DATA_MAGIC)
{
- gcov_error ("profiling:%s:Not a gcov data file\n", gi_filename);
+ gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename);
goto read_fatal;
}
- error = gcov_exit_merge_gcda (gi_ptr, &prg, this_prg, &summary_pos, &eof_pos,
- crc32);
+ error = gcov_exit_merge_gcda (gf->filename, gi_ptr, &prg, this_prg,
+ &summary_pos, &eof_pos, crc32);
if (error == -1)
goto read_fatal;
}
summary_pos = eof_pos;
}
- error = gcov_exit_merge_summary (gi_ptr, &prg, this_prg, crc32, all_prg);
+ error = gcov_exit_merge_summary (gf->filename, gi_ptr, &prg, this_prg,
+ crc32, all_prg);
if (error == -1)
goto read_fatal;
gcov_error (error < 0 ?
"profiling:%s:Overflow writing\n" :
"profiling:%s:Error writing\n",
- gi_filename);
+ gf->filename);
}
gcov_exit (void)
{
struct gcov_info *gi_ptr;
- struct gcov_filename_aux gf;
+ struct gcov_filename gf;
gcov_unsigned_t crc32;
struct gcov_summary all_prg;
struct gcov_summary this_prg;
return;
gcov_dump_complete = 1;
-
- crc32 = gcov_exit_compute_summary (&this_prg);
+
+ crc32 = gcov_exit_compute_summary (&this_prg, &gf.max_length);
allocate_filename_struct (&gf);
#if !GCOV_LOCKED
gcov_exit_dump_gcov (gi_ptr, &gf, crc32, &all_prg, &this_prg);
run_accounted = 1;
- if (gi_filename)
- free (gi_filename);
+ free (gf.filename);
}
/* Reset all counters to zero. */
return;
if (gcov_version (info, info->version, 0))
{
- size_t filename_length = strlen(info->filename);
-
- /* Refresh the longest file name information */
- if (filename_length > gcov_max_filename)
- gcov_max_filename = filename_length;
-
if (!gcov_list)
atexit (gcov_exit);
extern gcov_position_t gcov_position();
extern int gcov_is_error();
-extern size_t gcov_max_filename;
/* Verbose mode for debug. */
static int verbose;
static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
/* Number of kind of counters that have been seen. */
static int k_ctrs_types;
-/* The longest length of all the filenames. */
-static int max_filename_len;
/* Merge functions for counters. */
#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
num_fn_info = 0;
curr_fn_info = 0;
{
- char *str_dup = (char*) xmalloc (strlen (filename) + 1);
- int len;
+ size_t len = strlen (filename) + 1;
+ char *str_dup = (char*) xmalloc (len);
- strcpy (str_dup, filename);
+ memcpy (str_dup, filename, len);
obj_info->filename = str_dup;
- if ((len = strlen (filename)) > max_filename_len)
- max_filename_len = len;
}
/* Read stamp. */
/* Driver for read a profile directory and convert into gcov_info list in memory.
Return NULL on error,
- Return the head of gcov_info list on success.
- Note the file static variable GCOV_MAX_FILENAME is also set. */
+ Return the head of gcov_info list on success. */
struct gcov_info *
gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
free (pwd);
- /* gcov_max_filename is defined in libgcov.c that records the
- max filename len. We need to set it here to allocate the
- array for dumping. */
- gcov_max_filename = max_filename_len;
-
return gcov_info_head;;
}