##// END OF EJS Templates
Close branch No PWD scrub with FPU
Close branch No PWD scrub with FPU

File last commit:

r388:01d5c5b53213 No PWD scrub with...
r391:8059ee986796 No PWD scrub with...
Show More
gcov-io.c
488 lines | 14.4 KiB | text/x-c | CLexer
/* 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)
{
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();
}
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*/
printf("Covered file: %s\n", info->filename);
/* 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__ */