diff options
author | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-05-10 16:10:54 +0000 |
---|---|---|
committer | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-05-10 16:10:54 +0000 |
commit | 0dfbb9e09d99b4f74de3cefc3c8b210d2b6f5f7d (patch) | |
tree | 88434cdc971ae92b6f0f0bfa67f792324670c31b /gcc/libgcov.c | |
parent | c51429aedf0dd9a3736b9e12e65410c064cb50c2 (diff) | |
download | gcc-0dfbb9e09d99b4f74de3cefc3c8b210d2b6f5f7d.tar.gz |
* libgcov.c (create_file_directory): New function. Create
directory for the given file name.
(gcov_max_filename): New static var. Keeps size of the longest
file name.
(gcov_exit): Always try to create directory for output
file. Relocate each filename basing on environment vars.
(__gcov_init): Remember the longest file name.
* tsystem.h: include filenames.h to get IS_DIR_SEPARATOR
* doc/gcov.texi (Cross-profiling): New node documenting
cross-profiling management.
* doc/invoke.texi (-fprofile-arcs): Add xref to cross-profiling.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@99523 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/libgcov.c')
-rw-r--r-- | gcc/libgcov.c | 135 |
1 files changed, 122 insertions, 13 deletions
diff --git a/gcc/libgcov.c b/gcc/libgcov.c index 8061383ff7e..8b478a7707c 100644 --- a/gcc/libgcov.c +++ b/gcc/libgcov.c @@ -88,8 +88,49 @@ static struct gcov_info *gcov_list; object file included in multiple programs. */ static gcov_unsigned_t gcov_crc32; +/* Size of the longest file name. */ +static size_t gcov_max_filename = 0; + +/* Make sure path compenent of the given FILENAME exists, create + missing directories. FILENAME must be writable. + Returns zero on success, or -1 if an error occurred. */ + +static int +create_file_directory (char *filename) +{ + char *s; + + for (s = filename + 1; *s != '\0'; s++) + if (IS_DIR_SEPARATOR(*s)) + { + char sep = *s; + *s = '\0'; + + /* Try to make directory if it doesn't already exist. */ + if (access (filename, F_OK) == -1 + && mkdir (filename, 0755) == -1 + /* The directory might have been made by another process. */ + && errno != EEXIST) + { + fprintf (stderr, "profiling:%s:Cannot create directory\n", + filename); + *s = sep; + return -1; + }; + + *s = sep; + }; + return 0; +} + +/* Check if VERSION of the info block PTR matches libgcov one. + Return 1 on success, or zero in case of versions mismatch. + If FILENAME is not NULL, its value used for reporting purposes + instead of value from the info block. */ + static int -gcov_version (struct gcov_info *ptr, gcov_unsigned_t version) +gcov_version (struct gcov_info *ptr, gcov_unsigned_t version, + const char *filename) { if (version != GCOV_VERSION) { @@ -100,7 +141,7 @@ gcov_version (struct gcov_info *ptr, gcov_unsigned_t version) fprintf (stderr, "profiling:%s:Version mismatch - expected %.4s got %.4s\n", - ptr->filename, e, v); + filename? filename : ptr->filename, e, v); return 0; } return 1; @@ -123,6 +164,10 @@ gcov_exit (void) const struct gcov_ctr_info *ci_ptr; unsigned t_ix; gcov_unsigned_t c_num; + const char *gcov_prefix; + int gcov_prefix_strip = 0; + size_t prefix_length; + char *gi_filename, *gi_filename_up; memset (&all, 0, sizeof (all)); /* Find the totals for this execution. */ @@ -147,6 +192,33 @@ gcov_exit (void) } } + /* Get file name relocation prefix. Non-absolute values are ignored. */ + gcov_prefix = getenv("GCOV_PREFIX"); + if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix)) + { + /* Check if the level of dirs to strip off specified. */ + char *tmp = getenv("GCOV_PREFIX_STRIP"); + if (tmp) + { + gcov_prefix_strip = atoi (tmp); + /* Do not consider negative values. */ + if (gcov_prefix_strip < 0) + gcov_prefix_strip = 0; + } + + prefix_length = strlen(gcov_prefix); + + /* Remove an unneccesary trailing '/' */ + if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1])) + prefix_length--; + } + + /* Allocate and initialize the filename scratch space. */ + gi_filename = alloca (prefix_length + gcov_max_filename + 1); + if (prefix_length) + memcpy (gi_filename, gcov_prefix, prefix_length); + gi_filename_up = gi_filename + prefix_length; + /* Now merge each file. */ for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) { @@ -165,6 +237,28 @@ gcov_exit (void) memset (&this_object, 0, sizeof (this_object)); memset (&object, 0, sizeof (object)); + /* Build relocated filename, stripping off leading + directories from the initial filename if requested. */ + if (gcov_prefix_strip > 0) + { + int level = 0; + const char *fname = gi_ptr->filename; + const char *s; + + /* Skip selected directory levels. */ + for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++) + if (IS_DIR_SEPARATOR(*s)) + { + fname = s; + level++; + }; + + /* Update complete filename with stripped original. */ + strcpy (gi_filename_up, fname); + } + else + strcpy (gi_filename_up, gi_ptr->filename); + /* Totals for this object file. */ ci_ptr = gi_ptr->counts; for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) @@ -201,10 +295,20 @@ gcov_exit (void) fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1); } - if (!gcov_open (gi_ptr->filename)) + if (!gcov_open (gi_filename)) { - fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename); - continue; + /* Open failed likely due to missed directory. + Create directory and retry to open file. */ + if (create_file_directory (gi_filename)) + { + fprintf (stderr, "profiling:%s:Skip\n", gi_filename); + continue; + } + if (!gcov_open (gi_filename)) + { + fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename); + continue; + } } tag = gcov_read_unsigned (); @@ -214,11 +318,11 @@ gcov_exit (void) if (tag != GCOV_DATA_MAGIC) { fprintf (stderr, "profiling:%s:Not a gcov data file\n", - gi_ptr->filename); + gi_filename); goto read_fatal; } length = gcov_read_unsigned (); - if (!gcov_version (gi_ptr, length)) + if (!gcov_version (gi_ptr, length, gi_filename)) goto read_fatal; length = gcov_read_unsigned (); @@ -242,7 +346,7 @@ gcov_exit (void) { read_mismatch:; fprintf (stderr, "profiling:%s:Merge mismatch for %s\n", - gi_ptr->filename, + gi_filename, f_ix + 1 ? "function" : "summaries"); goto read_fatal; } @@ -301,7 +405,7 @@ gcov_exit (void) read_error:; fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n" - : "profiling:%s:Error merging\n", gi_ptr->filename); + : "profiling:%s:Error merging\n", gi_filename); read_fatal:; gcov_close (); @@ -352,7 +456,7 @@ gcov_exit (void) && memcmp (cs_all, cs_prg, sizeof (*cs_all))) { fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s", - gi_ptr->filename, GCOV_LOCKED + gi_filename, GCOV_LOCKED ? "" : " or concurrent update without locking support"); all.checksum = ~0u; } @@ -417,7 +521,7 @@ gcov_exit (void) fprintf (stderr, error < 0 ? "profiling:%s:Overflow writing\n" : "profiling:%s:Error writing\n", - gi_ptr->filename); + gi_filename); } } @@ -429,11 +533,16 @@ __gcov_init (struct gcov_info *info) { if (!info->version) return; - if (gcov_version (info, info->version)) + if (gcov_version (info, info->version, 0)) { const char *ptr = info->filename; gcov_unsigned_t crc32 = gcov_crc32; - + size_t filename_length = strlen(info->filename); + + /* Refresh the longest file name information */ + if (filename_length > gcov_max_filename) + gcov_max_filename = filename_length; + do { unsigned ix; |