Line data Source code
1 : /* Test for GCC >= 3.4.4 && <= 4.4.6 */
2 : //#if ( ( __GNUC__ > 3 ) || \
3 : // ( __GNUC__ == 3 && __GNUC_MINOR__ > 4 )|| \
4 : // ( __GNUC__ == 3 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ >= 4 ) ) && \
5 : // ( ( __GNUC__ < 4 ) || \
6 : // ( __GNUC__ == 4 && __GNUC_MINOR__ < 4 )|| \
7 : // ( __GNUC__ == 4 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ <= 6 ) )
8 : /*
9 : * =====================================================================================
10 : *
11 : * Filename: gcov-io.c
12 : *
13 : * Description: This is the I/O file for embedded systems
14 : *
15 : * Version: 1.0
16 : * Created: 03/04/08 09:51:59
17 : * Revision: none
18 : * Compiler: gcc
19 : *
20 : * Author: Aitor Viana Sanchez (avs), aitor.viana.sanchez@esa.int
21 : * Company: European Space Agency (ESA-ESTEC)
22 : *
23 : * =====================================================================================
24 : */
25 :
26 : /* File format for coverage information
27 : Copyright (C) 1996, 1997, 1998, 2000, 2002,
28 : 2003 Free Software Foundation, Inc.
29 : Contributed by Bob Manson <manson@cygnus.com>.
30 : Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
31 :
32 : This file is part of GCC.
33 :
34 : GCC is free software; you can redistribute it and/or modify it under
35 : the terms of the GNU General Public License as published by the Free
36 : Software Foundation; either version 2, or (at your option) any later
37 : version.
38 :
39 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
40 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
41 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
42 : for more details.
43 :
44 : You should have received a copy of the GNU General Public License
45 : along with GCC; see the file COPYING. If not, write to the Free
46 : Software Foundation, 59 Temple Place - Suite 330, Boston, MA
47 : 02111-1307, USA. */
48 :
49 : #include "gcov-io.h"
50 : #include <stdio.h>
51 : #include <stdlib.h> /* for atexit() */
52 : #include <string.h>
53 :
54 : /* Routines declared in gcov-io.h. This file should be #included by
55 : another source file, after having #included gcov-io.h. */
56 :
57 :
58 : /* This function shall be defined somewhere else */
59 : // int send_data(unsigned char * buffer, unsigned int size);
60 :
61 : /*-----------------------------------------------------------------------------
62 : * PRIVATE INTERFACE
63 : *-----------------------------------------------------------------------------*/
64 :
65 : static void gcov_write_block(unsigned);
66 : static gcov_unsigned_t* gcov_write_words(unsigned);
67 : GCOV_LINKAGE int gcov_send(void);
68 : GCOV_LINKAGE int gcov_close(void);
69 :
70 : extern struct gcov_info* gcov_list;
71 : extern gcov_unsigned_t gcov_crc32;
72 :
73 : int dev_id = 0;
74 :
75 : /*
76 : * === FUNCTION ======================================================================
77 : * Name: from_file
78 : * Description: This function just return the given parameter
79 : * =====================================================================================
80 : */
81 : static inline gcov_unsigned_t from_file(gcov_unsigned_t value)
82 : {
83 : return value;
84 : }
85 :
86 : /*
87 : * === FUNCTION ======================================================================
88 : * Name: gcov_version
89 : * Description: This function returns TRUE (1) if the gcov version is the
90 : * version expected. The function returns FALSE (0) in any other case.
91 : * =====================================================================================
92 : */
93 : static int gcov_version(struct gcov_info* ptr, gcov_unsigned_t version)
94 : {
95 23 : if (version != GCOV_VERSION)
96 : {
97 : char v[4], e[4];
98 :
99 0 : GCOV_UNSIGNED2STRING(v, version);
100 0 : GCOV_UNSIGNED2STRING(e, GCOV_VERSION);
101 :
102 0 : printf("profiling:%s:Version mismatch - expected %.4s got %.4s\n", ptr->filename, e, v);
103 :
104 0 : return 0;
105 : }
106 23 : return 1;
107 : }
108 :
109 :
110 : /*-----------------------------------------------------------------------------
111 : * PUBLIC INTERFACE
112 : *-----------------------------------------------------------------------------*/
113 :
114 : /* Dump the coverage counts. We merge with existing counts when
115 : possible, to avoid growing the .da files ad infinitum. We use this
116 : program's checksum to make sure we only accumulate whole program
117 : statistics to the correct summary. An object file might be embedded
118 : in two separate programs, and we must keep the two program
119 : summaries separate. */
120 :
121 : /*
122 : * === FUNCTION ======================================================================
123 : * Name: gcov_exit
124 : * Description: This function dumps the coverage couns. The merging with
125 : * existing counts is not done in embedded systems.
126 : * =====================================================================================
127 : */
128 1 : void gcov_exit(void)
129 : {
130 : struct gcov_info* gi_ptr;
131 : struct gcov_summary this_program;
132 : struct gcov_summary all;
133 : struct gcov_ctr_summary* cs_ptr;
134 : const struct gcov_ctr_info* ci_ptr;
135 : unsigned t_ix;
136 : gcov_unsigned_t c_num;
137 1 : unsigned long coreId = 0;
138 :
139 : /* retrieve the id of the CPU the program is running on */
140 : #ifdef LEON3
141 : __asm__ __volatile__(
142 : "rd %%asr17,%0\n\t"
143 : "srl %0,28,%0"
144 : : "=&r"(coreId)
145 : :);
146 : #endif
147 :
148 1 : printf("_GCOVEXIT_BEGIN_,core%d\n", coreId); /* see also _GCOVEXIT_END_ */
149 :
150 1 : if (gcov_list == (void*)0x0)
151 0 : printf("%s: gcov_list == NULL\n", __func__);
152 :
153 1 : memset(&all, 0, sizeof(all));
154 : /* Find the totals for this execution. */
155 1 : memset(&this_program, 0, sizeof(this_program));
156 24 : for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
157 : {
158 :
159 23 : ci_ptr = gi_ptr->counts;
160 46 : for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
161 : {
162 23 : if (!((1 << t_ix) & gi_ptr->ctr_mask))
163 0 : continue;
164 :
165 23 : cs_ptr = &this_program.ctrs[t_ix];
166 23 : cs_ptr->num += ci_ptr->num;
167 2091 : for (c_num = 0; c_num < ci_ptr->num; c_num++)
168 : {
169 2068 : cs_ptr->sum_all += ci_ptr->values[c_num];
170 2068 : if (cs_ptr->run_max < ci_ptr->values[c_num])
171 13 : cs_ptr->run_max = ci_ptr->values[c_num];
172 : }
173 23 : ci_ptr++;
174 : }
175 : }
176 : /* Now merge each file. */
177 22 : for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
178 : {
179 :
180 : struct gcov_summary program;
181 : gcov_type* values[GCOV_COUNTERS];
182 : const struct gcov_fn_info* fi_ptr;
183 : unsigned fi_stride;
184 : unsigned c_ix, f_ix, n_counts;
185 :
186 22 : c_ix = 0;
187 132 : for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
188 110 : if ((1 << t_ix) & gi_ptr->ctr_mask)
189 : {
190 22 : values[c_ix] = gi_ptr->counts[c_ix].values;
191 22 : c_ix++;
192 : }
193 :
194 : /* Calculate the function_info stride. This depends on the
195 : number of counter types being measured. */
196 22 : fi_stride = sizeof(struct gcov_fn_info) + c_ix * sizeof(unsigned);
197 : if (__alignof__(struct gcov_fn_info) > sizeof(unsigned))
198 : {
199 : fi_stride += __alignof__(struct gcov_fn_info) - 1;
200 : fi_stride &= ~(__alignof__(struct gcov_fn_info) - 1);
201 : }
202 :
203 22 : if (!gcov_open(gi_ptr->filename))
204 : {
205 0 : printf("profiling:%s:Cannot open\n", gi_ptr->filename);
206 0 : continue;
207 : }
208 :
209 22 : program.checksum = gcov_crc32;
210 :
211 : /* Write out the data. */
212 22 : gcov_write_tag_length(GCOV_DATA_MAGIC, GCOV_VERSION);
213 22 : gcov_write_unsigned(gi_ptr->stamp);
214 :
215 : /* Write execution counts for each function. */
216 310 : for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
217 : {
218 289 : fi_ptr
219 289 : = (const struct gcov_fn_info*)((const char*)gi_ptr->functions + f_ix * fi_stride);
220 :
221 : /* Announce function. */
222 289 : gcov_write_tag_length(GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
223 289 : gcov_write_unsigned(fi_ptr->ident);
224 289 : gcov_write_unsigned(fi_ptr->checksum);
225 :
226 289 : c_ix = 0;
227 1729 : for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
228 : {
229 : gcov_type* c_ptr;
230 :
231 1441 : if (!((1 << t_ix) & gi_ptr->ctr_mask))
232 1152 : continue;
233 :
234 289 : n_counts = fi_ptr->n_ctrs[c_ix];
235 :
236 289 : gcov_write_tag_length(
237 289 : GCOV_TAG_FOR_COUNTER(t_ix), GCOV_TAG_COUNTER_LENGTH(n_counts));
238 289 : c_ptr = values[c_ix];
239 2611 : while (n_counts--)
240 2034 : gcov_write_counter(*c_ptr++);
241 :
242 288 : values[c_ix] = c_ptr;
243 288 : c_ix++;
244 : }
245 : }
246 :
247 21 : gcov_send();
248 21 : gcov_close();
249 : }
250 :
251 0 : printf("_GCOVEXIT_END_,core%d\n", coreId);
252 0 : }
253 :
254 :
255 : /* Called before fork or exec - write out profile information gathered so
256 : far and reset it to zero. This avoids duplication or loss of the
257 : profile information gathered so far. */
258 :
259 0 : void __gcov_flush(void)
260 : {
261 : const struct gcov_info* gi_ptr;
262 :
263 0 : gcov_exit();
264 0 : for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
265 : {
266 : unsigned t_ix;
267 : const struct gcov_ctr_info* ci_ptr;
268 :
269 0 : for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
270 0 : if ((1 << t_ix) & gi_ptr->ctr_mask)
271 : {
272 0 : memset(ci_ptr->values, 0, sizeof(gcov_type) * ci_ptr->num);
273 0 : ci_ptr++;
274 : }
275 : }
276 0 : }
277 :
278 :
279 : /* Open a gcov file. NAME is the name of the file to open and MODE
280 : indicates whether a new file should be created, or an existing file
281 : opened for modification. If MODE is >= 0 an existing file will be
282 : opened, if possible, and if MODE is <= 0, a new file will be
283 : created. Use MODE=0 to attempt to reopen an existing file and then
284 : fall back on creating a new one. Return zero on failure, >0 on
285 : opening an existing file and <0 on creating a new one. */
286 22 : GCOV_LINKAGE int gcov_open(const char* name)
287 : {
288 : // gcov_var.start is cleared in the gcov_close function.
289 : // If this variable is not cleared...ERROR
290 22 : if (gcov_var.start != 0)
291 0 : return 0;
292 :
293 : // Clear everything
294 22 : gcov_var.start = 0;
295 22 : gcov_var.offset = gcov_var.length = 0;
296 22 : gcov_var.overread = -1u;
297 22 : gcov_var.error = 0;
298 :
299 :
300 : // copy the filename in the gcov_var structure
301 22 : strcpy(gcov_var.filename, name);
302 :
303 :
304 : // return 1 means everything is OK
305 22 : return 1;
306 : }
307 :
308 : /* Close the current gcov file. Flushes data to disk. Returns nonzero
309 : on failure or error flag set. */
310 :
311 21 : GCOV_LINKAGE int gcov_send(void)
312 : {
313 : /*printf("%s: file %s\n", __func__, gcov_var.filename);*/
314 21 : if (gcov_var.offset)
315 21 : gcov_write_block(gcov_var.offset);
316 :
317 21 : gcov_var.length = 0;
318 21 : return gcov_var.error;
319 : }
320 :
321 21 : GCOV_LINKAGE int gcov_close(void)
322 : {
323 21 : memset(gcov_var.filename, 0, strlen(gcov_var.filename));
324 :
325 : // Clear the start variable because will be tested in the gcov_open
326 : // function
327 21 : gcov_var.start = 0;
328 :
329 : // Return the error, not sure whether the error is modifed.
330 21 : return gcov_var.error;
331 : }
332 :
333 :
334 21 : static void gcov_write_block(unsigned size)
335 : {
336 21 : unsigned char* buffer = (unsigned char*)gcov_var.buffer;
337 : unsigned int i;
338 :
339 21 : printf("_GCOV_,%s,", gcov_var.filename);
340 : /* to speed up the printing process, we display bytes 4 by 4 */
341 5692 : for (i = 0; i < size; i++)
342 : {
343 17013 : printf("%02X%02X%02X%02X", (unsigned int)(buffer[0]), (unsigned int)(buffer[1]),
344 11342 : (unsigned int)(buffer[2]), (unsigned int)(buffer[3]));
345 :
346 5671 : buffer += sizeof(gcov_unsigned_t);
347 : }
348 21 : printf("\n");
349 :
350 21 : gcov_var.start += size;
351 21 : gcov_var.offset -= size;
352 21 : }
353 :
354 : /* Allocate space to write BYTES bytes to the gcov file. Return a
355 : pointer to those bytes, or NULL on failure. */
356 :
357 3159 : static gcov_unsigned_t* gcov_write_words(unsigned words)
358 : {
359 : gcov_unsigned_t* result;
360 :
361 : GCOV_CHECK_WRITING();
362 3159 : if (gcov_var.offset >= GCOV_BLOCK_SIZE)
363 : {
364 0 : gcov_write_block(GCOV_BLOCK_SIZE);
365 0 : if (gcov_var.offset)
366 : {
367 : GCOV_CHECK(gcov_var.offset == 1);
368 0 : memcpy(gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4);
369 : }
370 : }
371 3159 : result = &gcov_var.buffer[gcov_var.offset];
372 3159 : gcov_var.offset += words;
373 :
374 3159 : return result;
375 : }
376 :
377 : /* Write unsigned VALUE to coverage file. Sets error flag
378 : appropriately. */
379 :
380 590 : GCOV_LINKAGE void gcov_write_unsigned(gcov_unsigned_t value)
381 : {
382 590 : gcov_unsigned_t* buffer = gcov_write_words(1);
383 :
384 590 : buffer[0] = value;
385 590 : }
386 :
387 : /* Write counter VALUE to coverage file. Sets error flag
388 : appropriately. */
389 :
390 1997 : GCOV_LINKAGE void gcov_write_counter(gcov_type value)
391 : {
392 1997 : gcov_unsigned_t* buffer = gcov_write_words(2);
393 :
394 1998 : buffer[0] = (gcov_unsigned_t)value;
395 : if (sizeof(value) > sizeof(gcov_unsigned_t))
396 1998 : buffer[1] = (gcov_unsigned_t)(value >> 32);
397 : else
398 : buffer[1] = 0;
399 1998 : }
400 :
401 : /* Write a tag TAG and length LENGTH. */
402 :
403 586 : GCOV_LINKAGE void gcov_write_tag_length(gcov_unsigned_t tag, gcov_unsigned_t length)
404 : {
405 586 : gcov_unsigned_t* buffer = gcov_write_words(2);
406 :
407 586 : buffer[0] = tag;
408 586 : buffer[1] = length;
409 586 : }
410 :
411 : /* Write a summary structure to the gcov file. Return nonzero on
412 : overflow. */
413 :
414 0 : GCOV_LINKAGE void gcov_write_summary(gcov_unsigned_t tag, const struct gcov_summary* summary)
415 : {
416 : unsigned ix;
417 : const struct gcov_ctr_summary* csum;
418 :
419 0 : gcov_write_tag_length(tag, GCOV_TAG_SUMMARY_LENGTH);
420 0 : gcov_write_unsigned(summary->checksum);
421 0 : for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
422 : {
423 0 : gcov_write_unsigned(csum->num);
424 0 : gcov_write_unsigned(csum->runs);
425 0 : gcov_write_counter(csum->sum_all);
426 0 : gcov_write_counter(csum->run_max);
427 0 : gcov_write_counter(csum->sum_max);
428 : }
429 0 : }
430 :
431 0 : GCOV_LINKAGE gcov_type gcov_read_counter(void)
432 : {
433 0 : return 0;
434 : }
435 :
436 : /* Add a new object file onto the bb chain. Invoked automatically
437 : when running an object file's global ctors. */
438 :
439 23 : void __gcov_init(struct gcov_info* info)
440 : {
441 23 : if (!info->version)
442 : return;
443 46 : if (gcov_version(info, info->version))
444 : {
445 23 : const char* ptr = info->filename;
446 23 : gcov_unsigned_t crc32 = gcov_crc32;
447 :
448 : /* Added by LESIA*/
449 23 : printf("Covered file: %s\n", info->filename);
450 : /* End of Added by LESIA*/
451 :
452 : do
453 : {
454 : unsigned ix;
455 1867 : gcov_unsigned_t value = *ptr << 24;
456 :
457 16803 : for (ix = 8; ix--; value <<= 1)
458 : {
459 : gcov_unsigned_t feedback;
460 :
461 14936 : feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
462 14936 : crc32 <<= 1;
463 14936 : crc32 ^= feedback;
464 : }
465 1867 : } while (*ptr++);
466 :
467 23 : gcov_crc32 = crc32;
468 :
469 : #ifdef GCOV_USE_EXIT
470 23 : if (!gcov_list)
471 1 : atexit(gcov_exit);
472 : #endif
473 :
474 23 : info->next = gcov_list;
475 23 : gcov_list = info;
476 : }
477 : else
478 0 : printf("%s: Version mismatch\n", "WARNING");
479 23 : info->version = 0;
480 : }
481 : //#endif /* __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ */
|