diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,4 +10,5 @@ set(LFR_BP_SRC ${CMAKE_CURRENT_SOURCE_DI SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/sparc") +add_subdirectory(libgcov) add_subdirectory(src) diff --git a/libgcov/CMakeLists.txt b/libgcov/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libgcov/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.6) +project(libgcov C) +include(sparc-rtems) +include(cppcheck) + +set(LIB_GCOV_SOURCES + gcov-io.c + gcov-io.h + gcov-iov.h + libgcov.c +) + +add_library(gcov STATIC ${LIB_GCOV_SOURCES}) + +add_custom_target(gcovr + COMMAND gcovr --exclude='.*gcov.*' --gcov-executable=${rtems_dir}/bin/sparc-rtems-gcov --object-directory ${CMAKE_BINARY_DIR} -r ${CMAKE_SOURCE_DIR} --html --html-details -o ${CMAKE_CURRENT_BINARY_DIR}/gcov.html && xdg-open ${CMAKE_CURRENT_BINARY_DIR}/gcov.html + ) diff --git a/libgcov/build_gcov_files.py b/libgcov/build_gcov_files.py new file mode 100644 --- /dev/null +++ b/libgcov/build_gcov_files.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +__author__ = "Alexis Jeandet" +__copyright__ = "Copyright 2018, Laboratory of Plasma Physics" +__credits__ = [] +__license__ = "GPLv2" +__version__ = "1.0.0" +__maintainer__ = "Alexis Jeandet" +__email__ = "alexis.jeandet@member.fsf.org" +__status__ = "Development" + +import time +import sys +import os +import serial +import argparse +from datetime import datetime + +parser = argparse.ArgumentParser() +parser.add_argument("-f", "--gcov-file", help="Gcov output file generated by record_lfr_console.py") +args = parser.parse_args() + + + +def main(): + with open(args.gcov_file,'r') as gcov: + for line in gcov.readlines(): + head,dest_file,data = line.split(',') + if head == '_GCOV_': + print(f"Writing {dest_file}\n") + with open(dest_file,'wb') as gcda_file: + gcda_file.write(bytes([int(''.join(value),16) for value in zip(data[::2],data[1::2]) ])) + else: + raise + + +if __name__ == "__main__": + main() diff --git a/libgcov/gcov-io.c b/libgcov/gcov-io.c new file mode 100644 --- /dev/null +++ b/libgcov/gcov-io.c @@ -0,0 +1,820 @@ +/* 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 . + Completely remangled by Nathan Sidwell . + + 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 +#include /* for atexit() */ +#include +#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); +//static const gcov_unsigned_t *gcov_read_words (unsigned); + +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 this_object, object; +// struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all; +// int error = 0; +// gcov_unsigned_t tag, length; +// gcov_position_t summary_pos = 0; + 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; + +#if 0 + memset (&this_object, 0, sizeof (this_object)); + memset (&object, 0, sizeof (object)); + + + /* Totals for this object file. */ + 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_object.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++; + } +#endif + + 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; + } + +#if 0 + tag = gcov_read_unsigned (); + if (tag) + { + /* Merge data from file. */ + if (tag != GCOV_DATA_MAGIC) + { + fprintf (stderr, "profiling:%s:Not a gcov data file\n", + gi_ptr->filename); +read_fatal:; + gcov_close (); + continue; + } + length = gcov_read_unsigned (); + if (!gcov_version (gi_ptr, length)) + goto read_fatal; + + length = gcov_read_unsigned (); + if (length != gi_ptr->stamp) + { + /* Read from a different compilation. Overwrite the + file. */ + gcov_truncate (); + goto rewrite; + } + + /* Merge 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); + tag = gcov_read_unsigned (); + length = gcov_read_unsigned (); + + /* Check function. */ + if (tag != GCOV_TAG_FUNCTION + || length != GCOV_TAG_FUNCTION_LENGTH + || gcov_read_unsigned () != fi_ptr->ident + || gcov_read_unsigned () != fi_ptr->checksum) + { +read_mismatch:; + fprintf (stderr, "profiling:%s:Merge mismatch for %s\n", + gi_ptr->filename, + f_ix + 1 ? "function" : "summaries"); + goto read_fatal; + } + + c_ix = 0; + for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) + { + gcov_merge_fn merge; + + if (!((1 << t_ix) & gi_ptr->ctr_mask)) + continue; + + n_counts = fi_ptr->n_ctrs[c_ix]; + merge = gi_ptr->counts[c_ix].merge; + + tag = gcov_read_unsigned (); + length = gcov_read_unsigned (); + if (tag != GCOV_TAG_FOR_COUNTER (t_ix) + || length != GCOV_TAG_COUNTER_LENGTH (n_counts)) + goto read_mismatch; + (*merge) (values[c_ix], n_counts); + values[c_ix] += n_counts; + c_ix++; + } + if ((error = gcov_is_error ())) + goto read_error; + } + + f_ix = ~0u; + /* Check program & object summary */ + while (1) + { + gcov_position_t base = gcov_position (); + int is_program; + + tag = gcov_read_unsigned (); + if (!tag) + break; + length = gcov_read_unsigned (); + is_program = tag == GCOV_TAG_PROGRAM_SUMMARY; + if (length != GCOV_TAG_SUMMARY_LENGTH + || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY)) + goto read_mismatch; + gcov_read_summary (is_program ? &program : &object); + if ((error = gcov_is_error ())) + goto read_error; + if (is_program && program.checksum == gcov_crc32) + { + summary_pos = base; + goto rewrite; + } + } + } + + if (!gcov_is_eof ()) + { +read_error:; + fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n" + : "profiling:%s:Error merging\n", gi_ptr->filename); + goto read_fatal; + } +rewrite:; + gcov_rewrite (); + if (!summary_pos) + memset (&program, 0, sizeof (program)); + /* Merge the summaries. */ + f_ix = ~0u; + for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) + { + cs_obj = &object.ctrs[t_ix]; + cs_tobj = &this_object.ctrs[t_ix]; + cs_prg = &program.ctrs[t_ix]; + cs_tprg = &this_program.ctrs[t_ix]; + cs_all = &all.ctrs[t_ix]; + + if ((1 << t_ix) & gi_ptr->ctr_mask) + { + if (!cs_obj->runs++) + cs_obj->num = cs_tobj->num; + else if (cs_obj->num != cs_tobj->num) + goto read_mismatch; + cs_obj->sum_all += cs_tobj->sum_all; + if (cs_obj->run_max < cs_tobj->run_max) + cs_obj->run_max = cs_tobj->run_max; + cs_obj->sum_max += cs_tobj->run_max; + + if (!cs_prg->runs++) + cs_prg->num = cs_tprg->num; + else if (cs_prg->num != cs_tprg->num) + goto read_mismatch; + cs_prg->sum_all += cs_tprg->sum_all; + if (cs_prg->run_max < cs_tprg->run_max) + cs_prg->run_max = cs_tprg->run_max; + cs_prg->sum_max += cs_tprg->run_max; + } + else if (cs_obj->num || cs_prg->num) + goto read_mismatch; + + if (!cs_all->runs && cs_prg->runs) + memcpy (cs_all, cs_prg, sizeof (*cs_all)); + else if (!all.checksum + && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs) + && memcmp (cs_all, cs_prg, sizeof (*cs_all))) + { + fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s", + gi_ptr->filename, GCOV_LOCKED + ? "" : " or concurrent update without locking support"); + all.checksum = ~0u; + } + } + + 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++; + } + +#endif + 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++; + } + } + + /* Object file summary. */ + // gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object); + + /* Generate whole program statistics. */ + // gcov_seek (summary_pos); + // gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program); + gcov_send(); + gcov_close(); + /* if ((error = gcov_send ())) + fprintf (stderr, error < 0 ? + "profiling:%s:Overflow writing\n" : + "profiling:%s:Error writing\n", + gi_ptr->filename);*/ + } + + 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) +{ + /*printf("%s: %s\n", __func__, gcov_var.filename);*/ + 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; +} + +/* Write out the + current block, if needs be. */ +/*static void gcov_write_block (unsigned size) { + unsigned int bw = 0; + unsigned int i; + + printf("_GCOV_,%s,", gcov_var.filename); + for(i = 0; i < size << 2; i++) { + char str[5] = {0}; + + printf("%02X", ((unsigned char*)(gcov_var.buffer))[i]); + } + printf("\n"); + + gcov_var.start += size; + gcov_var.offset -= size; +}*/ + +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; + +// if (value < 0) +// gcov_var.error = -1; +} + +/* 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); + } +} + +/* Return a pointer to read BYTES bytes from the gcov file. Returns + NULL on failure (read past EOF). */ +#if 0 + GCOV_LINKAGE const gcov_unsigned_t * +gcov_read_words (unsigned words) +{ + const gcov_unsigned_t *result; + unsigned excess = gcov_var.length - gcov_var.offset; + + GCOV_CHECK_READING (); + if (excess < words) + { + gcov_var.start += gcov_var.offset; + if (excess) + { + GCOV_CHECK (excess == 1); + memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4); + } + gcov_var.offset = 0; + gcov_var.length = excess; + GCOV_CHECK (!gcov_var.length || gcov_var.length == 1); + excess = GCOV_BLOCK_SIZE; + excess = fread (gcov_var.buffer + gcov_var.length, + 1, excess << 2, gcov_var.file) >> 2; + gcov_var.length += excess; + if (gcov_var.length < words) + { + gcov_var.overread += words - gcov_var.length; + gcov_var.length = 0; + return 0; + } + } + result = &gcov_var.buffer[gcov_var.offset]; + gcov_var.offset += words; + return result; +} + + +/* Read unsigned value from a coverage file. Sets error flag on file + error, overflow flag on overflow */ + + GCOV_LINKAGE gcov_unsigned_t +gcov_read_unsigned (void) +{ + gcov_unsigned_t value; + const gcov_unsigned_t *buffer = gcov_read_words (1); + + if (!buffer) + return 0; + value = from_file (buffer[0]); + return value; +} + +/* Read counter value from a coverage file. Sets error flag on file + error, overflow flag on overflow */ +#endif + GCOV_LINKAGE gcov_type +gcov_read_counter (void) +{ +#if 0 + gcov_type value; + const gcov_unsigned_t *buffer = gcov_read_words (2); + + if (!buffer) + return 0; + value = from_file (buffer[0]); + if (sizeof (value) > sizeof (gcov_unsigned_t)) + value |= ((gcov_type) from_file (buffer[1])) << 32; + else if (buffer[1]) + gcov_var.error = -1; + + if (value < 0) + gcov_var.error = -1; + return value; +#endif + return 0; +} +#if 0 + +/* Read string from coverage file. Returns a pointer to a static + buffer, or NULL on empty string. You must copy the string before + calling another gcov function. */ + + GCOV_LINKAGE void +gcov_read_summary (struct gcov_summary *summary) +{ + unsigned ix; + struct gcov_ctr_summary *csum; + + summary->checksum = gcov_read_unsigned (); + for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) + { + csum->num = gcov_read_unsigned (); + csum->runs = gcov_read_unsigned (); + csum->sum_all = gcov_read_counter (); + csum->run_max = gcov_read_counter (); + csum->sum_max = gcov_read_counter (); + } +} + +/* Move to the a set position in a gcov file. BASE is zero to move to + the end, and nonzero to move to that position. */ + + GCOV_LINKAGE void +gcov_seek (gcov_position_t base) +{ + GCOV_CHECK_WRITING (); + if (gcov_var.offset) + gcov_write_block (gcov_var.offset); + fseek (gcov_var.file, base << 2, base ? SEEK_SET : SEEK_END); + gcov_var.start = ftell (gcov_var.file) >> 2; +} + +#endif + +/* 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__ */ diff --git a/libgcov/gcov-io.h b/libgcov/gcov-io.h new file mode 100644 --- /dev/null +++ b/libgcov/gcov-io.h @@ -0,0 +1,531 @@ +/* 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 ) ) +//#include +//#include +/* File format for coverage information + Copyright (C) 1996, 1997, 1998, 2000, 2002, + 2003, 2004 Free Software Foundation, Inc. + Contributed by Bob Manson . + Completely remangled by Nathan Sidwell . + + 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. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* Coverage information is held in two files. A notes file, which is + generated by the compiler, and a data file, which is generated + by the program under test. Both files use a similar structure. We + do not attempt to make these files backwards compatible with + previous versions, as you only need coverage information when + developing a program. We do hold version information, so that + mismatches can be detected, and we use a format that allows tools + to skip information they do not understand or are not interested + in. + + Numbers are recorded in the 32 bit unsigned binary form of the + endianness of the machine generating the file. 64 bit numbers are + stored as two 32 bit numbers, the low part first. Strings are + padded with 1 to 4 NUL bytes, to bring the length up to a multiple + of 4. The number of 4 bytes is stored, followed by the padded + string. Zero length and NULL strings are simply stored as + a length of zero (they have no trailing NUL or padding). + +int32: byte3 byte2 byte1 byte0 | byte0 byte1 byte2 byte3 +int64: int32:low int32:high +string: int32:0 | int32:length char* char:0 padding +padding: | char:0 | char:0 char:0 | char:0 char:0 char:0 +item: int32 | int64 | string + +The basic format of the files is + +file : int32:magic int32:version int32:stamp record* + +The magic ident is different for the notes and the data files. The +magic ident is used to determine the endianness of the file, when +reading. The version is the same for both files and is derived +from gcc's version number. The stamp value is used to synchronize +note and data files and to synchronize merging within a data +file. It need not be an absolute time stamp, merely a ticker that +increments fast enough and cycles slow enough to distinguish +different compile/run/compile cycles. + +Although the ident and version are formally 32 bit numbers, they +are derived from 4 character ASCII strings. The version number +consists of the single character major version number, a two +character minor version number (leading zero for versions less than +10), and a single character indicating the status of the release. +That will be 'e' experimental, 'p' prerelease and 'r' for release. +Because, by good fortune, these are in alphabetical order, string +collating can be used to compare version strings. Be aware that +the 'e' designation will (naturally) be unstable and might be +incompatible with itself. For gcc 3.4 experimental, it would be +'304e' (0x33303465). When the major version reaches 10, the +letters A-Z will be used. Assuming minor increments releases every +6 months, we have to make a major increment every 50 years. +Assuming major increments releases every 5 years, we're ok for the +next 155 years -- good enough for me. + +A record has a tag, length and variable amount of data. + +record: header data +header: int32:tag int32:length +data: item* + +Records are not nested, but there is a record hierarchy. Tag +numbers reflect this hierarchy. Tags are unique across note and +data files. Some record types have a varying amount of data. The +LENGTH is the number of 4bytes that follow and is usually used to +determine how much data. The tag value is split into 4 8-bit +fields, one for each of four possible levels. The most significant +is allocated first. Unused levels are zero. Active levels are +odd-valued, so that the LSB of the level is one. A sub-level +incorporates the values of its superlevels. This formatting allows +you to determine the tag hierarchy, without understanding the tags +themselves, and is similar to the standard section numbering used +in technical documents. Level values [1..3f] are used for common +tags, values [41..9f] for the notes file and [a1..ff] for the data +file. + +The basic block graph file contains the following records +note: unit function-graph* +unit: header int32:checksum string:source +function-graph: announce_function basic_blocks {arcs | lines}* +announce_function: header int32:ident int32:checksum +string:name string:source int32:lineno +basic_block: header int32:flags* +arcs: header int32:block_no arc* +arc: int32:dest_block int32:flags +lines: header int32:block_no line* +int32:0 string:NULL +line: int32:line_no | int32:0 string:filename + +The BASIC_BLOCK record holds per-bb flags. The number of blocks +can be inferred from its data length. There is one ARCS record per +basic block. The number of arcs from a bb is implicit from the +data length. It enumerates the destination bb and per-arc flags. +There is one LINES record per basic block, it enumerates the source +lines which belong to that basic block. Source file names are +introduced by a line number of 0, following lines are from the new +source file. The initial source file for the function is NULL, but +the current source file should be remembered from one LINES record +to the next. The end of a block is indicated by an empty filename +- this does not reset the current source file. Note there is no +ordering of the ARCS and LINES records: they may be in any order, + interleaved in any manner. The current filename follows the order + the LINES records are stored in the file, *not* the ordering of the + blocks they are for. + + The data file contains the following records. + data: {unit function-data* summary:object summary:program*}* + unit: header int32:checksum + function-data: announce_function arc_counts + announce_function: header int32:ident int32:checksum + arc_counts: header int64:count* + summary: int32:checksum {count-summary}GCOV_COUNTERS + count-summary: int32:num int32:runs int64:sum + int64:max int64:sum_max + + The ANNOUNCE_FUNCTION record is the same as that in the note file, + but without the source location. The ARC_COUNTS gives the counter + values for those arcs that are instrumented. The SUMMARY records + give information about the whole object file and about the whole + program. The checksum is used for whole program summaries, and + disambiguates different programs which include the same + instrumented object file. There may be several program summaries, + each with a unique checksum. The object summary's checksum is zero. + Note that the data file might contain information from several runs + concatenated, or the data might be merged. + + This file is included by both the compiler, gcov tools and the + runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to + distinguish which case is which. If IN_LIBGCOV is nonzero, + libgcov is being built. If IN_GCOV is nonzero, the gcov tools are + being built. Otherwise the compiler is being built. IN_GCOV may be + positive or negative. If positive, we are compiling a tool that + requires additional functions (see the code for knowledge of what + those functions are). */ + +#ifndef GCC_GCOV_IO_H +#define GCC_GCOV_IO_H + + typedef unsigned int gcov_unsigned_t; + typedef unsigned int gcov_position_t; + + typedef unsigned long long gcov_type; + + /* No tengo ni idea de que es el SETLKW, asi que de momento el target + * no tiene de eso */ + + //#if defined (TARGET_HAS_F_SETLKW) + //#define GCOV_LOCKED 1 + //#else +#define GCOV_LOCKED 0 + //#endif + //#endif + + + + /* In gcov we want function linkage to be static. In the compiler we want + it extern, so that they can be accessed from elsewhere. In libgcov we + need these functions to be extern, so prefix them with __gcov. In + libgcov they must also be hidden so that the instance in the executable + is not also used in a DSO. */ + +#define gcov_var __gcov_var +#define gcov_open __gcov_open +#define gcov_close __gcov_close +#define gcov_write_tag_length __gcov_write_tag_length +#define gcov_position __gcov_position +#define gcov_seek __gcov_seek +#define gcov_rewrite __gcov_rewrite +#define gcov_is_error __gcov_is_error +#define gcov_is_eof __gcov_is_eof +#define gcov_write_unsigned __gcov_write_unsigned +#define gcov_write_counter __gcov_write_counter +#define gcov_write_summary __gcov_write_summary +#define gcov_read_unsigned __gcov_read_unsigned +#define gcov_read_counter __gcov_read_counter +#define gcov_read_summary __gcov_read_summary + + /* Esto no tengo ni repajolera idea de para que vale */ + + /* Poison these, so they don't accidentally slip in. */ + //#pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length + //#pragma GCC poison gcov_read_string gcov_sync gcov_time gcov_magic + +#ifdef HAVE_GAS_HIDDEN +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) +#else +#define ATTRIBUTE_HIDDEN +#endif + +#ifndef GCOV_LINKAGE +#define GCOV_LINKAGE extern + //#define GCOV_LINKAGE +#endif + + /* File suffixes. */ +#define GCOV_DATA_SUFFIX ".gcda" +#define GCOV_NOTE_SUFFIX ".gcno" + + /* File magic. Must not be palindromes. */ +#define GCOV_DATA_MAGIC ((gcov_unsigned_t)0x67636461) /* "gcda" */ +#define GCOV_NOTE_MAGIC ((gcov_unsigned_t)0x67636e6f) /* "gcno" */ + + /* gcov-iov.h is automatically generated by the makefile from + version.c, it looks like +#define GCOV_VERSION ((gcov_unsigned_t)0x89abcdef) +*/ +#include "gcov-iov.h" + + /* Convert a magic or version number to a 4 character string. */ +#define GCOV_UNSIGNED2STRING(ARRAY,VALUE) \ + ((ARRAY)[0] = (char)((VALUE) >> 24), \ + (ARRAY)[1] = (char)((VALUE) >> 16), \ + (ARRAY)[2] = (char)((VALUE) >> 8), \ + (ARRAY)[3] = (char)((VALUE) >> 0)) + + /* The record tags. Values [1..3f] are for tags which may be in either + file. Values [41..9f] for those in the note file and [a1..ff] for + the data file. */ + +#define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000) +#define GCOV_TAG_FUNCTION_LENGTH (2) +#define GCOV_TAG_BLOCKS ((gcov_unsigned_t)0x01410000) +#define GCOV_TAG_BLOCKS_LENGTH(NUM) (NUM) +#define GCOV_TAG_BLOCKS_NUM(LENGTH) (LENGTH) +#define GCOV_TAG_ARCS ((gcov_unsigned_t)0x01430000) +#define GCOV_TAG_ARCS_LENGTH(NUM) (1 + (NUM) * 2) +#define GCOV_TAG_ARCS_NUM(LENGTH) (((LENGTH) - 1) / 2) +#define GCOV_TAG_LINES ((gcov_unsigned_t)0x01450000) +#define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t)0x01a10000) +#define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 2) +#define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2) +#define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000) +#define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000) +#define GCOV_TAG_SUMMARY_LENGTH \ + (1 + GCOV_COUNTERS_SUMMABLE * (2 + 3 * 2)) + + /* Counters that are collected. */ +#define GCOV_COUNTER_ARCS 0 /* Arc transitions. */ +#define GCOV_COUNTERS_SUMMABLE 1 /* Counters which can be + summaried. */ +#define GCOV_FIRST_VALUE_COUNTER 1 /* The first of counters used for value + profiling. They must form a consecutive + interval and their order must match + the order of HIST_TYPEs in + value-prof.h. */ +#define GCOV_COUNTER_V_INTERVAL 1 /* Histogram of value inside an interval. */ +#define GCOV_COUNTER_V_POW2 2 /* Histogram of exact power2 logarithm + of a value. */ +#define GCOV_COUNTER_V_SINGLE 3 /* The most common value of expression. */ +#define GCOV_COUNTER_V_DELTA 4 /* The most common difference between + consecutive values of expression. */ +#define GCOV_LAST_VALUE_COUNTER 4 /* The last of counters used for value + profiling. */ +#define GCOV_COUNTERS 5 + + /* Number of counters used for value profiling. */ +#define GCOV_N_VALUE_COUNTERS \ + (GCOV_LAST_VALUE_COUNTER - GCOV_FIRST_VALUE_COUNTER + 1) + + /* A list of human readable names of the counters */ +#define GCOV_COUNTER_NAMES {"arcs", "interval", "pow2", "single", "delta"} + + /* Names of merge functions for counters. */ +#define GCOV_MERGE_FUNCTIONS {"__gcov_merge_add", \ + "__gcov_merge_add", \ + "__gcov_merge_add", \ + "__gcov_merge_single", \ + "__gcov_merge_delta"} + + /* Convert a counter index to a tag. */ +#define GCOV_TAG_FOR_COUNTER(COUNT) \ + (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t)(COUNT) << 17)) + /* Convert a tag to a counter. */ +#define GCOV_COUNTER_FOR_TAG(TAG) \ + ((unsigned)(((TAG) - GCOV_TAG_COUNTER_BASE) >> 17)) + /* Check whether a tag is a counter tag. */ +#define GCOV_TAG_IS_COUNTER(TAG) \ + (!((TAG) & 0xFFFF) && GCOV_COUNTER_FOR_TAG (TAG) < GCOV_COUNTERS) + + /* The tag level mask has 1's in the position of the inner levels, & + the lsb of the current level, and zero on the current and outer + levels. */ +#define GCOV_TAG_MASK(TAG) (((TAG) - 1) ^ (TAG)) + + /* Return nonzero if SUB is an immediate subtag of TAG. */ +#define GCOV_TAG_IS_SUBTAG(TAG,SUB) \ + (GCOV_TAG_MASK (TAG) >> 8 == GCOV_TAG_MASK (SUB) \ + && !(((SUB) ^ (TAG)) & ~GCOV_TAG_MASK(TAG))) + + /* Return nonzero if SUB is at a sublevel to TAG. */ +#define GCOV_TAG_IS_SUBLEVEL(TAG,SUB) \ + (GCOV_TAG_MASK (TAG) > GCOV_TAG_MASK (SUB)) + + /* Basic block flags. */ +#define GCOV_BLOCK_UNEXPECTED (1 << 1) + + /* Arc flags. */ +#define GCOV_ARC_ON_TREE (1 << 0) +#define GCOV_ARC_FAKE (1 << 1) +#define GCOV_ARC_FALLTHROUGH (1 << 2) + + /* Structured records. */ + + /* Cumulative counter data. */ + struct gcov_ctr_summary +{ + gcov_unsigned_t num; /* number of counters. */ + gcov_unsigned_t runs; /* number of program runs */ + gcov_type sum_all; /* sum of all counters accumulated. */ + gcov_type run_max; /* maximum value on a single run. */ + gcov_type sum_max; /* sum of individual run max values. */ +}; + + +/* Object & program summary record. */ +struct gcov_summary +{ + gcov_unsigned_t checksum; /* checksum of program */ + struct gcov_ctr_summary ctrs[GCOV_COUNTERS_SUMMABLE]; +}; + +/* Structures embedded in coveraged program. The structures generated + by write_profile must match these. */ + +/* Information about a single function. This uses the trailing array + idiom. The number of counters is determined from the counter_mask + in gcov_info. We hold an array of function info, so have to + explicitly calculate the correct array stride. */ +struct gcov_fn_info +{ + gcov_unsigned_t ident; /* unique ident of function */ + gcov_unsigned_t checksum; /* function checksum */ + unsigned n_ctrs[0]; /* instrumented counters */ +}; + +/* Type of function used to merge counters. */ +typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t); + +/* Information about counters. */ +struct gcov_ctr_info +{ + gcov_unsigned_t num; /* number of counters. */ + gcov_type *values; /* their values. */ + gcov_merge_fn merge; /* The function used to merge them. */ +}; + +/* Information about a single object file. */ +struct gcov_info +{ + gcov_unsigned_t version; /* expected version number */ + struct gcov_info *next; /* link to next, used by libgcov */ + + gcov_unsigned_t stamp; /* uniquifying time stamp */ + const char *filename; /* output file name */ + + unsigned n_functions; /* number of functions */ + const struct gcov_fn_info *functions; /* table of functions */ + + unsigned ctr_mask; /* mask of counters instrumented. */ + struct gcov_ctr_info counts[0]; /* count data. The number of bits + set in the ctr_mask field + determines how big this array + is. */ +}; + +/* Register a new object file module. */ +extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN; + +/* Called before fork, to avoid double counting. */ +extern void __gcov_flush (void) ATTRIBUTE_HIDDEN; + +/* The merge function that just sums the counters. */ +extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; + +/* The merge function to choose the most common value. */ +extern void __gcov_merge_single (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; + +/* The merge function to choose the most common difference between + consecutive values. */ +extern void __gcov_merge_delta (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; + +/* Optimum number of gcov_unsigned_t's read from or written to disk. */ +// We limit GCOV_BLOCK_SIZE to 512 unsigned long because post processing with +// DOS batch cannot handle command lines bigger than 8191 characters, knowing +// that for each char, we print 4 characters (e.g "\x00") +#define GCOV_BLOCK_SIZE (1 << 8) +#define MAXFILENAME (1024) + +GCOV_LINKAGE struct gcov_var +{ + // FILE *file; + char filename[MAXFILENAME]; + gcov_position_t start; /* Position of first byte of block */ + unsigned offset; /* Read/write position within the block. */ + unsigned length; /* Read limit in the block. */ + unsigned overread; /* Number of words overread. */ + int error; /* < 0 overflow, > 0 disk error. */ + /* Holds one block plus 4 bytes, thus all coverage reads & writes + fit within this buffer and we always can transfer GCOV_BLOCK_SIZE + to and from the disk. libgcov never backtracks and only writes 4 + or 8 byte objects. */ + gcov_unsigned_t buffer[GCOV_BLOCK_SIZE + 1]; +} gcov_var ATTRIBUTE_HIDDEN; + +#if 1 +/* Functions for reading and writing gcov files. In libgcov you can + open the file for reading then writing. Elsewhere you can open the + file either for reading or for writing. When reading a file you may + use the gcov_read_* functions, gcov_sync, gcov_position, & + gcov_error. When writing a file you may use the gcov_write + functions, gcov_seek & gcov_error. When a file is to be rewritten + you use the functions for reading, then gcov_rewrite then the + functions for writing. Your file may become corrupted if you break + these invariants. */ +GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN; +GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDEN; + +/* Available everywhere. */ +/* static gcov_position_t gcov_position (void); + * static int gcov_is_error (void); + * static int gcov_is_eof (void); + */ + +GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void) ATTRIBUTE_HIDDEN; +GCOV_LINKAGE gcov_type gcov_read_counter (void) ATTRIBUTE_HIDDEN; +GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *) ATTRIBUTE_HIDDEN; +#endif +/* Available only in libgcov */ +GCOV_LINKAGE void gcov_write_counter (gcov_type) ATTRIBUTE_HIDDEN; +GCOV_LINKAGE void gcov_write_tag_length (gcov_unsigned_t, + gcov_unsigned_t) ATTRIBUTE_HIDDEN; +GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/, + const struct gcov_summary *) ATTRIBUTE_HIDDEN; + +/* Available outside gcov */ +GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t) ATTRIBUTE_HIDDEN; + +/* Make sure the library is used correctly. */ +#if ENABLE_CHECKING +#define GCOV_CHECK(expr) ((expr) ? (void)0 : (void)abort ()) +#else +#define GCOV_CHECK(expr) +#endif +#define GCOV_CHECK_READING() GCOV_CHECK(gcov_var.mode > 0) +#define GCOV_CHECK_WRITING() GCOV_CHECK(gcov_var.mode < 0) +#if 0 +/* Save the current position in the gcov file. */ + + static inline gcov_position_t +gcov_position (void) +{ + GCOV_CHECK_READING (); + return gcov_var.start + gcov_var.offset; +} + +/* Return nonzero if we read to end of file. */ + + static inline int +gcov_is_eof (void) +{ + return !gcov_var.overread; +} + +/* Return nonzero if the error flag is set. */ + + static inline int +gcov_is_error (void) +{ + return gcov_var.file ? gcov_var.error : 1; +} + +/* Move to beginning of file and initialize for writing. */ + + static inline void +gcov_rewrite (void) +{ + GCOV_CHECK_READING (); + gcov_var.mode = -1; + gcov_var.start = 0; + gcov_var.offset = 0; + fseek (gcov_var.file, 0L, SEEK_SET); +} + +#ifdef __MINGW32__ +#define ftruncate _chsize +#endif + static inline void +gcov_truncate (void) +{ + ftruncate (fileno (gcov_var.file), 0L); +} +#endif +#endif /* GCC_GCOV_IO_H */ +//#endif /* __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ */ diff --git a/libgcov/gcov-iov.h b/libgcov/gcov-iov.h new file mode 100644 --- /dev/null +++ b/libgcov/gcov-iov.h @@ -0,0 +1,13 @@ +/* Generated by the program `C:\home\obswteam\workspace\sparc-gcov-master\tools\version\gcov-iov.exe' + from `4.4 (4 4) and (*)'. */ +#if ( __GNUC__ == 3 && __GNUC_MINOR__ == 4 ) +#define GCOV_VERSION ((gcov_unsigned_t)0x3330342a) /* type 'gcov-iov 3.4 ""' */ +#endif /* __GNUC__ __GNUC_MINOR__ */ + +#if ( __GNUC__ == 4 && __GNUC_MINOR__ == 4 ) +#define GCOV_VERSION ((gcov_unsigned_t)0x3430342a) /* type 'gcov-iov 4.4 ""' */ +#endif /* __GNUC__ __GNUC_MINOR__ */ + +#if ( __GNUC__ > 4 ) +#define GCOV_VERSION ((gcov_unsigned_t)0x3430342a) /* type 'gcov-iov 4.4 ""' */ +#endif /* __GNUC__ __GNUC_MINOR__ */ diff --git a/libgcov/libgcov.c b/libgcov/libgcov.c new file mode 100644 --- /dev/null +++ b/libgcov/libgcov.c @@ -0,0 +1,133 @@ +/* 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 ) ) +/* 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 Free Software Foundation, Inc. + +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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +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. */ + +#define GCOV_LINKAGE /* nothing */ + +#include "gcov-io.h" + +/* Chain of per-object gcov structures. */ +struct gcov_info *gcov_list; + +/* A program checksum allows us to distinguish program data for an + object file included in multiple programs. */ +gcov_unsigned_t gcov_crc32; + +/* The profile merging function that just adds the counters. It is given + an array COUNTERS of N_COUNTERS old counters and it reads the same number + of counters from the gcov file. */ +void +__gcov_merge_add (gcov_type *counters, unsigned n_counters) +{ + for (; n_counters; counters++, n_counters--) + *counters += gcov_read_counter (); +} +/* The profile merging function for choosing the most common value. + It is given an array COUNTERS of N_COUNTERS old counters and it + reads the same number of counters from the gcov file. The counters + are split into 3-tuples where the members of the tuple have + meanings: + + -- the stored candidate on the most common value of the measured entity + -- counter + -- total number of evaluations of the value */ +void +__gcov_merge_single (gcov_type *counters, unsigned n_counters) +{ + unsigned i, n_measures; + gcov_type value, counter, all; + + GCOV_CHECK (!(n_counters % 3)); + n_measures = n_counters / 3; + for (i = 0; i < n_measures; i++, counters += 3) + { + value = gcov_read_counter (); + counter = gcov_read_counter (); + all = gcov_read_counter (); + + if (counters[0] == value) + counters[1] += counter; + else if (counter > counters[1]) + { + counters[0] = value; + counters[1] = counter - counters[1]; + } + else + counters[1] -= counter; + counters[2] += all; + } +} + +/* The profile merging function for choosing the most common + difference between two consecutive evaluations of the value. It is + given an array COUNTERS of N_COUNTERS old counters and it reads the + same number of counters from the gcov file. The counters are split + into 4-tuples where the members of the tuple have meanings: + + -- the last value of the measured entity + -- the stored candidate on the most common difference + -- counter + -- total number of evaluations of the value */ + +void +__gcov_merge_delta (gcov_type *counters, unsigned n_counters) +{ + unsigned i, n_measures; + gcov_type last, value, counter, all; + + GCOV_CHECK (!(n_counters % 4)); + n_measures = n_counters / 4; + for (i = 0; i < n_measures; i++, counters += 4) + { + last = gcov_read_counter (); + value = gcov_read_counter (); + counter = gcov_read_counter (); + all = gcov_read_counter (); + + if (counters[1] == value) + counters[2] += counter; + else if (counter > counters[2]) + { + counters[1] = value; + counters[2] = counter - counters[2]; + } + else + counters[2] -= counter; + counters[3] += all; + } +} +#endif /* __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ */ diff --git a/libgcov/record_lfr_console.py b/libgcov/record_lfr_console.py new file mode 100644 --- /dev/null +++ b/libgcov/record_lfr_console.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +__author__ = "Alexis Jeandet" +__copyright__ = "Copyright 2018, Laboratory of Plasma Physics" +__credits__ = [] +__license__ = "GPLv2" +__version__ = "1.0.0" +__maintainer__ = "Alexis Jeandet" +__email__ = "alexis.jeandet@member.fsf.org" +__status__ = "Development" + +import time +import sys +import os +import serial +import argparse +from datetime import datetime + +parser = argparse.ArgumentParser() +parser.add_argument("-p", "--port", help="Serial port") +parser.add_argument("-s", "--speed", help="Baud rate") +args = parser.parse_args() + + + +def main(): + with open('gcov_out_'+str(datetime.now())+'.txt','w') as gcov: + with open('console_'+str(datetime.now())+'.txt','w') as console: + with serial.Serial(args.port, args.speed, timeout=None) as ser: + line = ser.readline().decode() + while '_GCOVEXIT_BEGIN_' not in line: + console.write(line) + line = ser.readline().decode() + line = ser.readline().decode() + while '_GCOVEXIT_END_' not in line: + gcov.write(line) + line = ser.readline().decode() + +if __name__ == "__main__": + main() diff --git a/sparc/sparc-rtems.cmake b/sparc/sparc-rtems.cmake --- a/sparc/sparc-rtems.cmake +++ b/sparc/sparc-rtems.cmake @@ -7,12 +7,24 @@ set(CMAKE_LINKER ${rtems_dir}/bin/sparc SET(CMAKE_EXE_LINKER_FLAGS "-static") option(fix-b2bst "Activate -mfix-b2bst switch to mitigate \"LEON3FT Stale Cache Entry After Store with Data Tag Parity Error\" errata, GRLIB-TN-0009" ON) +option(Coverage "Enables code coverage" OFF) + + +set(CMAKE_C_FLAGS_RELEASE "-O3") +set(CMAKE_C_FLAGS_DEBUG "-O0") + + if(fix-b2bst) - set(CMAKE_C_FLAGS_RELEASE "-O3 -mfix-b2bst") -else() - set(CMAKE_C_FLAGS_RELEASE "-O3") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfix-b2bst") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mfix-b2bst") endif() +if(Coverage) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fprofile-arcs -ftest-coverage") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage") +endif() + + set(CMAKE_C_LINK_EXECUTABLE " -Xlinker -Map=.map -o ") include_directories("${rtems_dir}/sparc-rtems/leon3/lib/include") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -104,8 +104,12 @@ add_definitions(-DSW_VERSION_N2=${SW_VER add_definitions(-DSW_VERSION_N3=${SW_VERSION_N3}) add_definitions(-DSW_VERSION_N4=${SW_VERSION_N4}) +add_executable(fsw ${SOURCES}) -add_executable(fsw ${SOURCES}) +if(Coverage) + target_link_libraries(fsw gcov) +endif() + if(fix-b2bst) check_b2bst(fsw ${CMAKE_CURRENT_BINARY_DIR})