gcov-io.c
488 lines
| 14.4 KiB
| text/x-c
|
CLexer
/ libgcov / gcov-io.c
r387 | /* Test for GCC >= 3.4.4 && <= 4.4.6 */ | |||
//#if ( ( __GNUC__ > 3 ) || \ | ||||
// ( __GNUC__ == 3 && __GNUC_MINOR__ > 4 )|| \ | ||||
// ( __GNUC__ == 3 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ >= 4 ) ) && \ | ||||
// ( ( __GNUC__ < 4 ) || \ | ||||
// ( __GNUC__ == 4 && __GNUC_MINOR__ < 4 )|| \ | ||||
// ( __GNUC__ == 4 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ <= 6 ) ) | ||||
/* | ||||
* ===================================================================================== | ||||
* | ||||
* Filename: gcov-io.c | ||||
* | ||||
* Description: This is the I/O file for embedded systems | ||||
* | ||||
* Version: 1.0 | ||||
* Created: 03/04/08 09:51:59 | ||||
* Revision: none | ||||
* Compiler: gcc | ||||
* | ||||
* Author: Aitor Viana Sanchez (avs), aitor.viana.sanchez@esa.int | ||||
* Company: European Space Agency (ESA-ESTEC) | ||||
* | ||||
* ===================================================================================== | ||||
*/ | ||||
/* File format for coverage information | ||||
Copyright (C) 1996, 1997, 1998, 2000, 2002, | ||||
2003 Free Software Foundation, Inc. | ||||
Contributed by Bob Manson <manson@cygnus.com>. | ||||
Completely remangled by Nathan Sidwell <nathan@codesourcery.com>. | ||||
This file is part of GCC. | ||||
GCC is free software; you can redistribute it and/or modify it under | ||||
the terms of the GNU General Public License as published by the Free | ||||
Software Foundation; either version 2, or (at your option) any later | ||||
version. | ||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY | ||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||||
for more details. | ||||
You should have received a copy of the GNU General Public License | ||||
along with GCC; see the file COPYING. If not, write to the Free | ||||
Software Foundation, 59 Temple Place - Suite 330, Boston, MA | ||||
02111-1307, USA. */ | ||||
#include <stdio.h> | ||||
#include <stdlib.h> /* for atexit() */ | ||||
#include <string.h> | ||||
#include "gcov-io.h" | ||||
/* Routines declared in gcov-io.h. This file should be #included by | ||||
another source file, after having #included gcov-io.h. */ | ||||
/* This function shall be defined somewhere else */ | ||||
//int send_data(unsigned char * buffer, unsigned int size); | ||||
/*----------------------------------------------------------------------------- | ||||
* PRIVATE INTERFACE | ||||
*-----------------------------------------------------------------------------*/ | ||||
static void gcov_write_block (unsigned); | ||||
static gcov_unsigned_t *gcov_write_words (unsigned); | ||||
GCOV_LINKAGE int gcov_send (void); | ||||
GCOV_LINKAGE int gcov_close(void); | ||||
extern struct gcov_info * gcov_list; | ||||
extern gcov_unsigned_t gcov_crc32; | ||||
int dev_id = 0; | ||||
/* | ||||
* === FUNCTION ====================================================================== | ||||
* Name: from_file | ||||
* Description: This function just return the given parameter | ||||
* ===================================================================================== | ||||
*/ | ||||
static inline gcov_unsigned_t from_file (gcov_unsigned_t value) | ||||
{ | ||||
return value; | ||||
} | ||||
/* | ||||
* === FUNCTION ====================================================================== | ||||
* Name: gcov_version | ||||
* Description: This function returns TRUE (1) if the gcov version is the | ||||
* version expected. The function returns FALSE (0) in any other case. | ||||
* ===================================================================================== | ||||
*/ | ||||
static int gcov_version (struct gcov_info *ptr, gcov_unsigned_t version) | ||||
{ | ||||
if (version != GCOV_VERSION) | ||||
{ | ||||
char v[4], e[4]; | ||||
GCOV_UNSIGNED2STRING (v, version); | ||||
GCOV_UNSIGNED2STRING (e, GCOV_VERSION); | ||||
printf ("profiling:%s:Version mismatch - expected %.4s got %.4s\n", | ||||
ptr->filename, e, v); | ||||
return 0; | ||||
} | ||||
return 1; | ||||
} | ||||
/*----------------------------------------------------------------------------- | ||||
* PUBLIC INTERFACE | ||||
*-----------------------------------------------------------------------------*/ | ||||
/* Dump the coverage counts. We merge with existing counts when | ||||
possible, to avoid growing the .da files ad infinitum. We use this | ||||
program's checksum to make sure we only accumulate whole program | ||||
statistics to the correct summary. An object file might be embedded | ||||
in two separate programs, and we must keep the two program | ||||
summaries separate. */ | ||||
/* | ||||
* === FUNCTION ====================================================================== | ||||
* Name: gcov_exit | ||||
* Description: This function dumps the coverage couns. The merging with | ||||
* existing counts is not done in embedded systems. | ||||
* ===================================================================================== | ||||
*/ | ||||
void gcov_exit (void) | ||||
{ | ||||
struct gcov_info *gi_ptr; | ||||
struct gcov_summary this_program; | ||||
struct gcov_summary all; | ||||
struct gcov_ctr_summary *cs_ptr; | ||||
const struct gcov_ctr_info *ci_ptr; | ||||
unsigned t_ix; | ||||
gcov_unsigned_t c_num; | ||||
unsigned long coreId = 0; | ||||
/* retrieve the id of the CPU the program is running on */ | ||||
#ifdef LEON3 | ||||
__asm__ __volatile__("rd %%asr17,%0\n\t" | ||||
"srl %0,28,%0" : | ||||
"=&r" (coreId) : ); | ||||
#endif | ||||
printf("_GCOVEXIT_BEGIN_,core%d\n", coreId); /* see also _GCOVEXIT_END_ */ | ||||
if(gcov_list == (void*)0x0) | ||||
printf("%s: gcov_list == NULL\n", __func__); | ||||
memset (&all, 0, sizeof (all)); | ||||
/* Find the totals for this execution. */ | ||||
memset (&this_program, 0, sizeof (this_program)); | ||||
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) | ||||
{ | ||||
ci_ptr = gi_ptr->counts; | ||||
for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) | ||||
{ | ||||
if (!((1 << t_ix) & gi_ptr->ctr_mask)) | ||||
continue; | ||||
cs_ptr = &this_program.ctrs[t_ix]; | ||||
cs_ptr->num += ci_ptr->num; | ||||
for (c_num = 0; c_num < ci_ptr->num; c_num++) | ||||
{ | ||||
cs_ptr->sum_all += ci_ptr->values[c_num]; | ||||
if (cs_ptr->run_max < ci_ptr->values[c_num]) | ||||
cs_ptr->run_max = ci_ptr->values[c_num]; | ||||
} | ||||
ci_ptr++; | ||||
} | ||||
} | ||||
/* Now merge each file. */ | ||||
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) | ||||
{ | ||||
r388 | ||||
r387 | struct gcov_summary program; | |||
gcov_type *values[GCOV_COUNTERS]; | ||||
const struct gcov_fn_info *fi_ptr; | ||||
unsigned fi_stride; | ||||
unsigned c_ix, f_ix, n_counts; | ||||
c_ix = 0; | ||||
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) | ||||
if ((1 << t_ix) & gi_ptr->ctr_mask) | ||||
{ | ||||
values[c_ix] = gi_ptr->counts[c_ix].values; | ||||
c_ix++; | ||||
} | ||||
/* Calculate the function_info stride. This depends on the | ||||
number of counter types being measured. */ | ||||
fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned); | ||||
if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned)) | ||||
{ | ||||
fi_stride += __alignof__ (struct gcov_fn_info) - 1; | ||||
fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1); | ||||
} | ||||
if (!gcov_open (gi_ptr->filename)) | ||||
{ | ||||
printf ("profiling:%s:Cannot open\n", gi_ptr->filename); | ||||
continue; | ||||
} | ||||
program.checksum = gcov_crc32; | ||||
/* Write out the data. */ | ||||
gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION); | ||||
gcov_write_unsigned (gi_ptr->stamp); | ||||
/* Write execution counts for each function. */ | ||||
for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) | ||||
{ | ||||
fi_ptr = (const struct gcov_fn_info *) | ||||
((const char *) gi_ptr->functions + f_ix * fi_stride); | ||||
/* 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); | ||||
c_ix = 0; | ||||
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) | ||||
{ | ||||
gcov_type *c_ptr; | ||||
if (!((1 << t_ix) & gi_ptr->ctr_mask)) | ||||
continue; | ||||
n_counts = fi_ptr->n_ctrs[c_ix]; | ||||
gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), | ||||
GCOV_TAG_COUNTER_LENGTH (n_counts)); | ||||
c_ptr = values[c_ix]; | ||||
while (n_counts--) | ||||
gcov_write_counter (*c_ptr++); | ||||
values[c_ix] = c_ptr; | ||||
c_ix++; | ||||
} | ||||
} | ||||
gcov_send(); | ||||
gcov_close(); | ||||
r388 | ||||
r387 | } | |||
printf("_GCOVEXIT_END_,core%d\n", coreId); | ||||
} | ||||
/* Called before fork or exec - write out profile information gathered so | ||||
far and reset it to zero. This avoids duplication or loss of the | ||||
profile information gathered so far. */ | ||||
void | ||||
__gcov_flush (void) | ||||
{ | ||||
const struct gcov_info *gi_ptr; | ||||
gcov_exit (); | ||||
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) | ||||
{ | ||||
unsigned t_ix; | ||||
const struct gcov_ctr_info *ci_ptr; | ||||
for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++) | ||||
if ((1 << t_ix) & gi_ptr->ctr_mask) | ||||
{ | ||||
memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); | ||||
ci_ptr++; | ||||
} | ||||
} | ||||
} | ||||
/* Open a gcov file. NAME is the name of the file to open and MODE | ||||
indicates whether a new file should be created, or an existing file | ||||
opened for modification. If MODE is >= 0 an existing file will be | ||||
opened, if possible, and if MODE is <= 0, a new file will be | ||||
created. Use MODE=0 to attempt to reopen an existing file and then | ||||
fall back on creating a new one. Return zero on failure, >0 on | ||||
opening an existing file and <0 on creating a new one. */ | ||||
GCOV_LINKAGE int gcov_open(const char *name) | ||||
{ | ||||
// gcov_var.start is cleared in the gcov_close function. | ||||
// If this variable is not cleared...ERROR | ||||
if( gcov_var.start != 0 ) | ||||
return 0; | ||||
// Clear everything | ||||
gcov_var.start = 0; | ||||
gcov_var.offset = gcov_var.length = 0; | ||||
gcov_var.overread = -1u; | ||||
gcov_var.error = 0; | ||||
// copy the filename in the gcov_var structure | ||||
strcpy(gcov_var.filename, name); | ||||
// return 1 means everything is OK | ||||
return 1; | ||||
} | ||||
/* Close the current gcov file. Flushes data to disk. Returns nonzero | ||||
on failure or error flag set. */ | ||||
GCOV_LINKAGE int gcov_send (void) | ||||
{ | ||||
/*printf("%s: file %s\n", __func__, gcov_var.filename);*/ | ||||
if (gcov_var.offset) | ||||
gcov_write_block (gcov_var.offset); | ||||
gcov_var.length = 0; | ||||
return gcov_var.error; | ||||
} | ||||
GCOV_LINKAGE int gcov_close(void) | ||||
{ | ||||
memset(gcov_var.filename, 0, strlen(gcov_var.filename)); | ||||
// Clear the start variable because will be tested in the gcov_open | ||||
// function | ||||
gcov_var.start = 0; | ||||
// Return the error, not sure whether the error is modifed. | ||||
return gcov_var.error; | ||||
} | ||||
static void gcov_write_block (unsigned size) { | ||||
unsigned char *buffer = (unsigned char*) gcov_var.buffer; | ||||
unsigned int i; | ||||
printf("_GCOV_,%s,", gcov_var.filename); | ||||
/* to speed up the printing process, we display bytes 4 by 4 */ | ||||
for(i = 0; i < size; i++) { | ||||
printf("%02X%02X%02X%02X", (unsigned int)(buffer[0]), | ||||
(unsigned int)(buffer[1]), | ||||
(unsigned int)(buffer[2]), | ||||
(unsigned int)(buffer[3])); | ||||
buffer += sizeof(gcov_unsigned_t); | ||||
} | ||||
printf("\n"); | ||||
gcov_var.start += size; | ||||
gcov_var.offset -= size; | ||||
} | ||||
/* Allocate space to write BYTES bytes to the gcov file. Return a | ||||
pointer to those bytes, or NULL on failure. */ | ||||
static gcov_unsigned_t *gcov_write_words (unsigned words) { | ||||
gcov_unsigned_t *result; | ||||
GCOV_CHECK_WRITING (); | ||||
if (gcov_var.offset >= GCOV_BLOCK_SIZE) | ||||
{ | ||||
gcov_write_block (GCOV_BLOCK_SIZE); | ||||
if (gcov_var.offset) | ||||
{ | ||||
GCOV_CHECK (gcov_var.offset == 1); | ||||
memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4); | ||||
} | ||||
} | ||||
result = &gcov_var.buffer[gcov_var.offset]; | ||||
gcov_var.offset += words; | ||||
return result; | ||||
} | ||||
/* Write unsigned VALUE to coverage file. Sets error flag | ||||
appropriately. */ | ||||
GCOV_LINKAGE void | ||||
gcov_write_unsigned (gcov_unsigned_t value) | ||||
{ | ||||
gcov_unsigned_t *buffer = gcov_write_words (1); | ||||
buffer[0] = value; | ||||
} | ||||
/* Write counter VALUE to coverage file. Sets error flag | ||||
appropriately. */ | ||||
GCOV_LINKAGE void | ||||
gcov_write_counter (gcov_type value) | ||||
{ | ||||
gcov_unsigned_t *buffer = gcov_write_words (2); | ||||
buffer[0] = (gcov_unsigned_t) value; | ||||
if (sizeof (value) > sizeof (gcov_unsigned_t)) | ||||
buffer[1] = (gcov_unsigned_t) (value >> 32); | ||||
else | ||||
buffer[1] = 0; | ||||
} | ||||
/* Write a tag TAG and length LENGTH. */ | ||||
GCOV_LINKAGE void | ||||
gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) | ||||
{ | ||||
gcov_unsigned_t *buffer = gcov_write_words (2); | ||||
buffer[0] = tag; | ||||
buffer[1] = length; | ||||
} | ||||
/* Write a summary structure to the gcov file. Return nonzero on | ||||
overflow. */ | ||||
GCOV_LINKAGE void | ||||
gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) | ||||
{ | ||||
unsigned ix; | ||||
const struct gcov_ctr_summary *csum; | ||||
gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH); | ||||
gcov_write_unsigned (summary->checksum); | ||||
for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) | ||||
{ | ||||
gcov_write_unsigned (csum->num); | ||||
gcov_write_unsigned (csum->runs); | ||||
gcov_write_counter (csum->sum_all); | ||||
gcov_write_counter (csum->run_max); | ||||
gcov_write_counter (csum->sum_max); | ||||
} | ||||
} | ||||
GCOV_LINKAGE gcov_type | ||||
gcov_read_counter (void) | ||||
{ | ||||
return 0; | ||||
} | ||||
/* Add a new object file onto the bb chain. Invoked automatically | ||||
when running an object file's global ctors. */ | ||||
void | ||||
__gcov_init (struct gcov_info *info) | ||||
{ | ||||
if (!info->version) | ||||
return; | ||||
if (gcov_version (info, info->version)) | ||||
{ | ||||
const char *ptr = info->filename; | ||||
gcov_unsigned_t crc32 = gcov_crc32; | ||||
/* Added by LESIA*/ | ||||
r388 | printf("Covered file: %s\n", info->filename); | |||
r387 | /* End of Added by LESIA*/ | |||
do | ||||
{ | ||||
unsigned ix; | ||||
gcov_unsigned_t value = *ptr << 24; | ||||
for (ix = 8; ix--; value <<= 1) | ||||
{ | ||||
gcov_unsigned_t feedback; | ||||
feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; | ||||
crc32 <<= 1; | ||||
crc32 ^= feedback; | ||||
} | ||||
} | ||||
while (*ptr++); | ||||
gcov_crc32 = crc32; | ||||
if (!gcov_list) | ||||
atexit (gcov_exit); | ||||
info->next = gcov_list; | ||||
gcov_list = info; | ||||
} | ||||
else | ||||
printf("%s: Version mismatch\n", "WARNING"); | ||||
info->version = 0; | ||||
} | ||||
//#endif /* __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ */ | ||||