/* Routines required for instrumenting a program. */
/* Compile this one with gcc. */
/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
+ 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
/* Size of the longest file name. */
static size_t gcov_max_filename = 0;
-#ifdef TARGET_POSIX_IO
/* Make sure path component 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)
{
+#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
+ (void) filename;
+ return -1;
+#else
char *s;
- for (s = filename + 1; *s != '\0'; s++)
+ s = filename;
+
+ if (HAS_DRIVE_SPEC(s))
+ s += 2;
+ if (IS_DIR_SEPARATOR(*s))
+ ++s;
+ for (; *s != '\0'; s++)
if (IS_DIR_SEPARATOR(*s))
{
char sep = *s;
/* Try to make directory if it doesn't already exist. */
if (access (filename, F_OK) == -1
+#ifdef TARGET_POSIX_IO
&& mkdir (filename, 0755) == -1
+#else
+ && mkdir (filename) == -1
+#endif
/* The directory might have been made by another process. */
&& errno != EEXIST)
{
*s = sep;
};
return 0;
-}
#endif
+}
/* Check if VERSION of the info block PTR matches libgcov one.
Return 1 on success, or zero in case of versions mismatch.
}
}
+ {
+ /* 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;
+ }
+ }
/* Get file name relocation prefix. Non-absolute values are ignored. */
gcov_prefix = getenv("GCOV_PREFIX");
- if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix))
+ if (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 unnecessary trailing '/' */
else
prefix_length = 0;
- /* Allocate and initialize the filename scratch space. */
- gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 1);
+ /* If no prefix was specified and a prefix stip, then we assume
+ relative. */
+ if (gcov_prefix_strip != 0 && prefix_length == 0)
+ {
+ gcov_prefix = ".";
+ prefix_length = 1;
+ }
+ /* Allocate and initialize the filename scratch space plus one. */
+ gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 2);
if (prefix_length)
memcpy (gi_filename, gcov_prefix, prefix_length);
gi_filename_up = gi_filename + prefix_length;
gcov_unsigned_t tag, length;
gcov_position_t summary_pos = 0;
gcov_position_t eof_pos = 0;
+ const char *fname, *s;
+
+ fname = gi_ptr->filename;
memset (&this_object, 0, sizeof (this_object));
memset (&object, 0, sizeof (object));
+ /* 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)
{
int level = 0;
- const char *fname = gi_ptr->filename;
- const char *s;
+ s = fname;
+ if (IS_DIR_SEPARATOR(*s))
+ ++s;
/* Skip selected directory levels. */
- for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
+ for (; (*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);
+ }
}
+ /* Update complete filename with stripped original. */
+ if (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
+ {
+ /* If prefix is given, add directory separator. */
+ strcpy (gi_filename_up, "/");
+ strcpy (gi_filename_up + 1, fname);
+ }
else
- strcpy (gi_filename_up, gi_ptr->filename);
+ strcpy (gi_filename_up, fname);
/* Totals for this object file. */
ci_ptr = gi_ptr->counts;
if (!gcov_open (gi_filename))
{
-#ifdef TARGET_POSIX_IO
/* 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;
}
-#endif
if (!gcov_open (gi_filename))
{
fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
/* Check function. */
if (tag != GCOV_TAG_FUNCTION
- || length != GCOV_TAG_FUNCTION_LENGTH
+ || length != GCOV_TAG_FUNCTION_LENGTH
|| gcov_read_unsigned () != fi_ptr->ident
- || gcov_read_unsigned () != fi_ptr->checksum)
+ || gcov_read_unsigned () != fi_ptr->lineno_checksum
+ || gcov_read_unsigned () != fi_ptr->cfg_checksum)
{
read_mismatch:;
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
/* Announce function. */
gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
gcov_write_unsigned (fi_ptr->ident);
- gcov_write_unsigned (fi_ptr->checksum);
+ gcov_write_unsigned (fi_ptr->lineno_checksum);
+ gcov_write_unsigned (fi_ptr->cfg_checksum);
c_ix = 0;
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
__gcov_merge_delta (gcov_type *counters, unsigned n_counters)
{
unsigned i, n_measures;
- gcov_type last, value, counter, all;
+ gcov_type value, counter, all;
gcc_assert (!(n_counters % 4));
n_measures = n_counters / 4;
for (i = 0; i < n_measures; i++, counters += 4)
{
- last = gcov_read_counter ();
+ /* last = */ gcov_read_counter ();
value = gcov_read_counter ();
counter = gcov_read_counter ();
all = gcov_read_counter ();
#endif
#ifdef L_gcov_indirect_call_profiler
+
+/* By default, the C++ compiler will use function addresses in the
+ vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
+ tells the compiler to use function descriptors instead. The value
+ of this macro says how many words wide the descriptor is (normally 2),
+ but it may be dependent on target flags. Since we do not have access
+ to the target flags here we just check to see if it is set and use
+ that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
+
+ It is assumed that the address of a function descriptor may be treated
+ as a pointer to a function. */
+
+#ifdef TARGET_VTABLE_USES_DESCRIPTORS
+#define VTABLE_USES_DESCRIPTORS 1
+#else
+#define VTABLE_USES_DESCRIPTORS 0
+#endif
+
/* Tries to determine the most common value among its inputs. */
void
__gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
function may have multiple descriptors and we need to dereference
the descriptors to see if they point to the same function. */
if (cur_func == callee_func
- || (TARGET_VTABLE_USES_DESCRIPTORS && callee_func
+ || (VTABLE_USES_DESCRIPTORS && callee_func
&& *(void **) cur_func == *(void **) callee_func))
__gcov_one_value_profiler_body (counter, value);
}