]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov-driver-system.c
2013-11-12 Rong Xu <xur@google.com>
[thirdparty/gcc.git] / libgcc / libgcov-driver-system.c
CommitLineData
ded3d3f8 1/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
3/* Copyright (C) 1989-2013 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24<http://www.gnu.org/licenses/>. */
25
26/* A utility function for outputing errors. */
27
28static int __attribute__((format(printf, 1, 2)))
29gcov_error (const char *fmt, ...)
30{
31 int ret;
32 va_list argp;
33 va_start (argp, fmt);
34 ret = vfprintf (stderr, fmt, argp);
35 va_end (argp);
36 return ret;
37}
38
39/* Make sure path component of the given FILENAME exists, create
40 missing directories. FILENAME must be writable.
41 Returns zero on success, or -1 if an error occurred. */
42
43static int
44create_file_directory (char *filename)
45{
46#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
47 (void) filename;
48 return -1;
49#else
50 char *s;
51
52 s = filename;
53
54 if (HAS_DRIVE_SPEC(s))
55 s += 2;
56 if (IS_DIR_SEPARATOR(*s))
57 ++s;
58 for (; *s != '\0'; s++)
59 if (IS_DIR_SEPARATOR(*s))
60 {
61 char sep = *s;
62 *s = '\0';
63
64 /* Try to make directory if it doesn't already exist. */
65 if (access (filename, F_OK) == -1
66#ifdef TARGET_POSIX_IO
67 && mkdir (filename, 0755) == -1
68#else
69 && mkdir (filename) == -1
70#endif
71 /* The directory might have been made by another process. */
72 && errno != EEXIST)
73 {
74 gcov_error ("profiling:%s:Cannot create directory\n", filename);
75 *s = sep;
76 return -1;
77 };
78
79 *s = sep;
80 };
81 return 0;
82#endif
83}
84
85static void
86allocate_filename_struct (struct gcov_filename_aux *gf)
87{
88 const char *gcov_prefix;
89 int gcov_prefix_strip = 0;
90 size_t prefix_length;
91 char *gi_filename_up;
92
93 gcc_assert (gf);
94 {
95 /* Check if the level of dirs to strip off specified. */
96 char *tmp = getenv("GCOV_PREFIX_STRIP");
97 if (tmp)
98 {
99 gcov_prefix_strip = atoi (tmp);
100 /* Do not consider negative values. */
101 if (gcov_prefix_strip < 0)
102 gcov_prefix_strip = 0;
103 }
104 }
105
106 /* Get file name relocation prefix. Non-absolute values are ignored. */
107 gcov_prefix = getenv("GCOV_PREFIX");
108 if (gcov_prefix)
109 {
110 prefix_length = strlen(gcov_prefix);
111
112 /* Remove an unnecessary trailing '/' */
113 if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
114 prefix_length--;
115 }
116 else
117 prefix_length = 0;
118
119 /* If no prefix was specified and a prefix stip, then we assume
120 relative. */
121 if (gcov_prefix_strip != 0 && prefix_length == 0)
122 {
123 gcov_prefix = ".";
124 prefix_length = 1;
125 }
126 /* Allocate and initialize the filename scratch space plus one. */
127 gi_filename = (char *) malloc (prefix_length + gcov_max_filename + 2);
128 if (prefix_length)
129 memcpy (gi_filename, gcov_prefix, prefix_length);
130 gi_filename_up = gi_filename + prefix_length;
131
132 gf->gi_filename_up = gi_filename_up;
133 gf->prefix_length = prefix_length;
134 gf->gcov_prefix_strip = gcov_prefix_strip;
135}
136
137/* Open a gcda file specified by GI_FILENAME.
138 Return -1 on error. Return 0 on success. */
139
140static int
141gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
142{
143 int gcov_prefix_strip;
144 size_t prefix_length;
145 char *gi_filename_up;
146 const char *fname, *s;
147
148 gcov_prefix_strip = gf->gcov_prefix_strip;
149 gi_filename_up = gf->gi_filename_up;
150 prefix_length = gf->prefix_length;
151 fname = gi_ptr->filename;
152
153 /* Avoid to add multiple drive letters into combined path. */
154 if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
155 fname += 2;
156
157 /* Build relocated filename, stripping off leading
158 directories from the initial filename if requested. */
159 if (gcov_prefix_strip > 0)
160 {
161 int level = 0;
162
163 s = fname;
164 if (IS_DIR_SEPARATOR(*s))
165 ++s;
166
167 /* Skip selected directory levels. */
168 for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
169 if (IS_DIR_SEPARATOR(*s))
170 {
171 fname = s;
172 level++;
173 }
174 }
175
176 /* Update complete filename with stripped original. */
177 if (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
178 {
179 /* If prefix is given, add directory separator. */
180 strcpy (gi_filename_up, "/");
181 strcpy (gi_filename_up + 1, fname);
182 }
183 else
184 strcpy (gi_filename_up, fname);
185
186 if (!gcov_open (gi_filename))
187 {
188 /* Open failed likely due to missed directory.
189 Create directory and retry to open file. */
190 if (create_file_directory (gi_filename))
191 {
192 fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
193 return -1;
194 }
195 if (!gcov_open (gi_filename))
196 {
197 fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
198 return -1;
199 }
200 }
201
202 return 0;
203}