9os

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 44a2f95676a50d4f9503f994064f3b52cb072a5f
parent 39cb4f0d11e97be5acc091d1ab54f82d2716b550
Author: Dimitris Papastamos <dimitris.papastamos@arm.com>
Date:   Tue, 19 Feb 2019 10:50:55 +0000

Remove libgcov

Change-Id: I2a7ff5495d7e69e378d75f735d1961a4002bf5ac

Diffstat:
Dsrc/libgcov/gcov-glue.c | 156-------------------------------------------------------------------------------
Dsrc/libgcov/gcov-io.c | 532-------------------------------------------------------------------------------
Dsrc/libgcov/gcov-io.h | 633-------------------------------------------------------------------------------
Dsrc/libgcov/gcov-iov.h | 4----
Dsrc/libgcov/libgcov.c | 1157-------------------------------------------------------------------------------
5 files changed, 0 insertions(+), 2482 deletions(-)

diff --git a/src/libgcov/gcov-glue.c b/src/libgcov/gcov-glue.c @@ -1,156 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2012 Google, Inc. All rights reserved. - * - * This program 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; version 2 of the License. - * - * This program 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. - */ - -#include <stdint.h> -#include <bootstate.h> -#include <cbmem.h> - -typedef struct file { - uint32_t magic; - struct file *next; - char *filename; - char *data; - int offset; - int len; -} FILE; - -#define SEEK_SET 0 /* Seek from beginning of file. */ - -#define DIR_SEPARATOR '/' -#define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) -#define HAS_DRIVE_SPEC(f) (0) - -#define COVERAGE_SIZE (32*1024) - -#define COVERAGE_MAGIC 0x584d4153 - -static FILE *current_file = NULL; -static FILE *previous_file = NULL; - -static FILE *fopen(const char *path, const char *mode) -{ -#if IS_ENABLED(CONFIG_DEBUG_COVERAGE) - printk(BIOS_DEBUG, "fopen %s with mode %s\n", - path, mode); -#endif - if (!current_file) { - current_file = cbmem_add(CBMEM_ID_COVERAGE, 32*1024); - } else { - previous_file = current_file; - current_file = - (FILE *)(ALIGN(((unsigned long)previous_file->data - + previous_file->len), 16)); - } - - // TODO check if we're at the end of the CBMEM region (ENOMEM) - if (current_file) { - current_file->magic = COVERAGE_MAGIC; - current_file->next = NULL; - if (previous_file) - previous_file->next = current_file; - current_file->filename = (char *)&current_file[1]; - strcpy(current_file->filename, path); - current_file->data = - (char *)ALIGN(((unsigned long)current_file->filename - + strlen(path) + 1), 16); - current_file->offset = 0; - current_file->len = 0; - } - - return current_file; -} - -static int fclose(FILE *stream) -{ -#if IS_ENABLED(CONFIG_DEBUG_COVERAGE) - printk(BIOS_DEBUG, "fclose %s\n", stream->filename); -#endif - return 0; -} - -static int fseek(FILE *stream, long offset, int whence) -{ - /* fseek should only be called with offset==0 and whence==SEEK_SET - * to a freshly opened file. */ - gcc_assert(offset == 0 && whence == SEEK_SET); -#if IS_ENABLED(CONFIG_DEBUG_COVERAGE) - printk(BIOS_DEBUG, "fseek %s offset=%ld whence=%d\n", - stream->filename, offset, whence); -#endif - return 0; -} - -static long ftell(FILE *stream) -{ - /* ftell should currently not be called */ - gcc_assert(0); -#if IS_ENABLED(CONFIG_DEBUG_COVERAGE) - printk(BIOS_DEBUG, "ftell %s\n", stream->filename); -#endif - return 0; -} - -static size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) -{ -#if IS_ENABLED(CONFIG_DEBUG_COVERAGE) - printk(BIOS_DEBUG, "fread: ptr=%p size=%zd nmemb=%zd FILE*=%p\n", - ptr, size, nmemb, stream); -#endif - return 0; -} - -static size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) -{ -#if IS_ENABLED(CONFIG_DEBUG_COVERAGE) - printk(BIOS_DEBUG, "fwrite: %zd * %zd bytes to file %s\n", - nmemb, size, stream->filename); -#endif - // TODO check if file is last opened file and fail otherwise. - - memcpy(stream->data + stream->offset, ptr, size * nmemb); - stream->len += (nmemb * size) - (stream->len - stream->offset); - stream->offset += nmemb * size; - return nmemb; -} - -static void setbuf(FILE *stream, char *buf) -{ - gcc_assert(buf == 0); -} - -static void coverage_init(void *unused) -{ - extern long __CTOR_LIST__; - typedef void (*func_ptr)(void); - func_ptr *ctor = (func_ptr *) &__CTOR_LIST__; - if (ctor == NULL) - return; - - for (; *ctor != (func_ptr) 0; ctor++) - (*ctor)(); -} - -void __gcov_flush(void); -static void coverage_exit(void *unused) -{ -#if IS_ENABLED(CONFIG_DEBUG_COVERAGE) - printk(BIOS_DEBUG, "Syncing coverage data.\n"); -#endif - __gcov_flush(); -} - -BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, coverage_init, NULL); -BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, coverage_exit, NULL); -BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, coverage_exit, NULL); diff --git a/src/libgcov/gcov-io.c b/src/libgcov/gcov-io.c @@ -1,532 +0,0 @@ -/* File format for coverage information - Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007, - 2008 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 3, 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. -*/ - -/* Routines declared in gcov-io.h. This file should be #included by - another source file, after having #included gcov-io.h. */ - -#if !IN_GCOV -static void gcov_write_block(unsigned int); -static gcov_unsigned_t *gcov_write_words(unsigned int); -#endif -static const gcov_unsigned_t *gcov_read_words(unsigned int); -#if !IN_LIBGCOV -static void gcov_allocate(unsigned int); -#endif - -static inline gcov_unsigned_t from_file(gcov_unsigned_t value) -{ -#if !IN_LIBGCOV - if (gcov_var.endian) { - value = (value >> 16) | (value << 16); - value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff); - } -#endif - return value; -} - -/* 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. 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. If MODE < 0, the file will be opened in - read-only mode. Otherwise it will be opened for modification. - Return zero on failure, >0 on opening an existing file and <0 on - creating a new one. */ - -GCOV_LINKAGE int -#if IN_LIBGCOV -gcov_open(const char *name) -#else -gcov_open(const char *name, int mode) -#endif -{ -#if IN_LIBGCOV - const int mode = 0; -#endif -#if GCOV_LOCKED - struct flock s_flock; - int fd; - - s_flock.l_whence = SEEK_SET; - s_flock.l_start = 0; - s_flock.l_len = 0; /* Until EOF. */ - s_flock.l_pid = getpid(); -#endif - - gcc_assert(!gcov_var.file); - gcov_var.start = 0; - gcov_var.offset = gcov_var.length = 0; - gcov_var.overread = -1u; - gcov_var.error = 0; -#if !IN_LIBGCOV - gcov_var.endian = 0; -#endif -#if GCOV_LOCKED - if (mode > 0) { - /* Read-only mode - acquire a read-lock. */ - s_flock.l_type = F_RDLCK; - fd = open(name, O_RDONLY); - } else { - /* Write mode - acquire a write-lock. */ - s_flock.l_type = F_WRLCK; - fd = open(name, O_RDWR | O_CREAT, 0666); - } - if (fd < 0) - return 0; - - while (fcntl(fd, F_SETLKW, &s_flock) && errno == EINTR) - continue; - - gcov_var.file = fdopen(fd, (mode > 0) ? "rb" : "r+b"); - - if (!gcov_var.file) { - close(fd); - return 0; - } - - if (mode > 0) - gcov_var.mode = 1; - else if (mode == 0) { - struct stat st; - - if (fstat(fd, &st) < 0) { - fclose(gcov_var.file); - gcov_var.file = 0; - return 0; - } - if (st.st_size != 0) - gcov_var.mode = 1; - else - gcov_var.mode = mode * 2 + 1; - } else - gcov_var.mode = mode * 2 + 1; -#else - if (mode >= 0) - gcov_var.file = fopen(name, (mode > 0) ? "rb" : "r+b"); - - if (gcov_var.file) - gcov_var.mode = 1; - else if (mode <= 0) { - gcov_var.file = fopen(name, "w+b"); - if (gcov_var.file) - gcov_var.mode = mode * 2 + 1; - } - if (!gcov_var.file) - return 0; -#endif - - setbuf(gcov_var.file, (char *)0); - - return 1; -} - -/* Close the current gcov file. Flushes data to disk. Returns nonzero - on failure or error flag set. */ - -GCOV_LINKAGE int -gcov_close(void) -{ - if (gcov_var.file) { -#if !IN_GCOV - if (gcov_var.offset && gcov_var.mode < 0) - gcov_write_block(gcov_var.offset); -#endif - fclose(gcov_var.file); - gcov_var.file = 0; - gcov_var.length = 0; - } -#if !IN_LIBGCOV - free(gcov_var.buffer); - gcov_var.alloc = 0; - gcov_var.buffer = 0; -#endif - gcov_var.mode = 0; - return gcov_var.error; -} - -#if !IN_LIBGCOV -/* Check if MAGIC is EXPECTED. Use it to determine endianness of the - file. Returns +1 for same endian, -1 for other endian and zero for - not EXPECTED. */ - -GCOV_LINKAGE int -gcov_magic(gcov_unsigned_t magic, gcov_unsigned_t expected) -{ - if (magic == expected) - return 1; - magic = (magic >> 16) | (magic << 16); - magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff); - if (magic == expected) { - gcov_var.endian = 1; - return -1; - } - return 0; -} -#endif - -#if !IN_LIBGCOV -static void -gcov_allocate(unsigned int length) -{ - size_t new_size = gcov_var.alloc; - - if (!new_size) - new_size = GCOV_BLOCK_SIZE; - new_size += length; - new_size *= 2; - - gcov_var.alloc = new_size; - gcov_var.buffer = XRESIZEVAR(gcov_unsigned_t, gcov_var.buffer, - new_size << 2); -} -#endif - -#if !IN_GCOV -/* Write out the current block, if needs be. */ - -static void -gcov_write_block(unsigned int size) -{ - if (fwrite(gcov_var.buffer, size << 2, 1, gcov_var.file) != 1) - gcov_var.error = 1; - 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 int words) -{ - gcov_unsigned_t *result; - - gcc_assert(gcov_var.mode < 0); -#if IN_LIBGCOV - if (gcov_var.offset >= GCOV_BLOCK_SIZE) { - gcov_write_block(GCOV_BLOCK_SIZE); - if (gcov_var.offset) { - gcc_assert(gcov_var.offset == 1); - memcpy(gcov_var.buffer, gcov_var.buffer - + GCOV_BLOCK_SIZE, 4); - } - } -#else - if (gcov_var.offset + words > gcov_var.alloc) - gcov_allocate(gcov_var.offset + words); -#endif - 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. */ - -#if IN_LIBGCOV -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; -} -#endif /* IN_LIBGCOV */ - -#if !IN_LIBGCOV -/* Write STRING to coverage file. Sets error flag on file - error, overflow flag on overflow */ - -GCOV_LINKAGE void -gcov_write_string(const char *string) -{ - unsigned int length = 0; - unsigned int alloc = 0; - gcov_unsigned_t *buffer; - - if (string) { - length = strlen(string); - alloc = (length + 4) >> 2; - } - - buffer = gcov_write_words(1 + alloc); - - buffer[0] = alloc; - buffer[alloc] = 0; - memcpy(&buffer[1], string, length); -} -#endif - -#if !IN_LIBGCOV -/* Write a tag TAG and reserve space for the record length. Return a - value to be used for gcov_write_length. */ - -GCOV_LINKAGE gcov_position_t -gcov_write_tag(gcov_unsigned_t tag) -{ - gcov_position_t result = gcov_var.start + gcov_var.offset; - gcov_unsigned_t *buffer = gcov_write_words(2); - - buffer[0] = tag; - buffer[1] = 0; - - return result; -} - -/* Write a record length using POSITION, which was returned by - gcov_write_tag. The current file position is the end of the - record, and is restored before returning. Returns nonzero on - overflow. */ - -GCOV_LINKAGE void -gcov_write_length(gcov_position_t position) -{ - unsigned int offset; - gcov_unsigned_t length; - gcov_unsigned_t *buffer; - - gcc_assert(gcov_var.mode < 0); - gcc_assert(position + 2 <= gcov_var.start + gcov_var.offset); - gcc_assert(position >= gcov_var.start); - offset = position - gcov_var.start; - length = gcov_var.offset - offset - 2; - buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset]; - buffer[1] = length; - if (gcov_var.offset >= GCOV_BLOCK_SIZE) - gcov_write_block(gcov_var.offset); -} - -#else /* IN_LIBGCOV */ - -/* 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 int 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); - } -} -#endif /* IN_LIBGCOV */ - -#endif /*!IN_GCOV */ - -/* Return a pointer to read BYTES bytes from the gcov file. Returns - NULL on failure (read past EOF). */ - -static const gcov_unsigned_t * -gcov_read_words(unsigned int words) -{ - const gcov_unsigned_t *result; - unsigned int excess = gcov_var.length - gcov_var.offset; - - gcc_assert(gcov_var.mode > 0); - if (excess < words) { - gcov_var.start += gcov_var.offset; -#if IN_LIBGCOV - if (excess) { - gcc_assert(excess == 1); - memcpy(gcov_var.buffer, gcov_var.buffer - + gcov_var.offset, 4); - } -#else - memmove(gcov_var.buffer, gcov_var.buffer - + gcov_var.offset, excess * 4); -#endif - gcov_var.offset = 0; - gcov_var.length = excess; -#if IN_LIBGCOV - gcc_assert(!gcov_var.length || gcov_var.length == 1); - excess = GCOV_BLOCK_SIZE; -#else - if (gcov_var.length + words > gcov_var.alloc) - gcov_allocate(gcov_var.length + words); - excess = gcov_var.alloc - gcov_var.length; -#endif - 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 */ - -GCOV_LINKAGE gcov_type -gcov_read_counter(void) -{ - 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; - - return value; -} - -/* 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. */ - -#if !IN_LIBGCOV -GCOV_LINKAGE const char * -gcov_read_string(void) -{ - unsigned int length = gcov_read_unsigned(); - - if (!length) - return 0; - - return (const char *) gcov_read_words(length); -} -#endif - -GCOV_LINKAGE void -gcov_read_summary(struct gcov_summary *summary) -{ - unsigned int 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(); - } -} - -#if !IN_LIBGCOV -/* Reset to a known position. BASE should have been obtained from - gcov_position, LENGTH should be a record length. */ - -GCOV_LINKAGE void -gcov_sync(gcov_position_t base, gcov_unsigned_t length) -{ - gcc_assert(gcov_var.mode > 0); - base += length; - if (base - gcov_var.start <= gcov_var.length) - gcov_var.offset = base - gcov_var.start; - else { - gcov_var.offset = gcov_var.length = 0; - fseek(gcov_var.file, base << 2, SEEK_SET); - gcov_var.start = ftell(gcov_var.file) >> 2; - } -} -#endif - -#if IN_LIBGCOV -/* Move to a given position in a gcov file. */ - -GCOV_LINKAGE void -gcov_seek(gcov_position_t base) -{ - gcc_assert(gcov_var.mode < 0); - if (gcov_var.offset) - gcov_write_block(gcov_var.offset); - fseek(gcov_var.file, base << 2, SEEK_SET); - gcov_var.start = ftell(gcov_var.file) >> 2; -} -#endif - -#if IN_GCOV > 0 -/* Return the modification time of the current gcov file. */ - -GCOV_LINKAGE time_t -gcov_time(void) -{ - struct stat status; - - if (fstat(fileno(gcov_var.file), &status)) - return 0; - else - return status.st_mtime; -} -#endif /* IN_GCOV */ diff --git a/src/libgcov/gcov-io.h b/src/libgcov/gcov-io.h @@ -1,633 +0,0 @@ -/* File format for coverage information - Copyright (C) 1996, 1997, 1998, 2000, 2002, - 2003, 2004, 2005, 2008, 2009 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 3, 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. -*/ - - -/* 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:lineno_checksum int32:cfg_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 summary:object summary:program* function-data*}* - unit: header int32:checksum - function-data: announce_function present counts - announce_function: header int32:ident - int32:lineno_checksum int32:cfg_checksum - present: header int32:present - counts: header int64:count* - summary: int32:checksum {count-summary}GCOV_COUNTERS_SUMMABLE - 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 COUNTS gives the - counter values for instrumented features. The 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 - -#ifdef __COREBOOT__ -#define GCOV_LINKAGE /* nothing */ -/* We need the definitions for - BITS_PER_UNIT and - LONG_LONG_TYPE_SIZE - They are defined in gcc/defaults.h and gcc/config/<arch_depend_files> - (like, gcc/config/i386/i386.h). And it can be overridden by setting - in build scripts. Here I hardcoded the value for x86. */ -#define BITS_PER_UNIT 8 -#define LONG_LONG_TYPE_SIZE 64 - -/* There are many gcc_assertions. Set the value to 1 if we want a warning - message if the assertion fails. */ -#ifndef ENABLE_ASSERT_CHECKING -#define ENABLE_ASSERT_CHECKING 1 -#endif -#endif /* __COREBOOT__ */ - -#if IN_LIBGCOV -/* About the target */ - -#if BITS_PER_UNIT == 8 -typedef unsigned int gcov_unsigned_t __attribute__((mode(SI))); -typedef unsigned int gcov_position_t __attribute__((mode(SI))); -#if LONG_LONG_TYPE_SIZE > 32 -typedef signed gcov_type __attribute__((mode(DI))); -#else -typedef signed gcov_type __attribute__((mode(SI))); -#endif -#else -#if BITS_PER_UNIT == 16 -typedef unsigned int gcov_unsigned_t __attribute__((mode(HI))); -typedef unsigned int gcov_position_t __attribute__((mode(HI))); -#if LONG_LONG_TYPE_SIZE > 32 -typedef signed gcov_type __attribute__((mode(SI))); -#else -typedef signed gcov_type __attribute__((mode(HI))); -#endif -#else -typedef unsigned int gcov_unsigned_t __attribute__((mode(QI))); -typedef unsigned int gcov_position_t __attribute__((mode(QI))); -#if LONG_LONG_TYPE_SIZE > 32 -typedef signed gcov_type __attribute__((mode(HI))); -#else -typedef signed gcov_type __attribute__((mode(QI))); -#endif -#endif -#endif - - -#if defined(TARGET_POSIX_IO) -#define GCOV_LOCKED 1 -#else -#define GCOV_LOCKED 0 -#endif - -#else /* !IN_LIBGCOV */ -/* About the host */ - -typedef unsigned int gcov_unsigned_t; -typedef unsigned int gcov_position_t; -/* gcov_type is typedef'd elsewhere for the compiler */ -#if IN_GCOV -#define GCOV_LINKAGE static -typedef HOST_WIDEST_INT gcov_type; -#if IN_GCOV > 0 -#include <sys/types.h> -#endif -#else /*!IN_GCOV */ -#define GCOV_TYPE_SIZE (LONG_LONG_TYPE_SIZE > 32 ? 64 : 32) -#endif - -#if defined(HOST_HAS_F_SETLKW) -#define GCOV_LOCKED 1 -#else -#define GCOV_LOCKED 0 -#endif - -#endif /* !IN_LIBGCOV */ - -/* 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. */ -#if IN_LIBGCOV - -#ifndef __COREBOOT__ -#include "tconfig.h" -#endif /* __COREBOOT__ */ - -#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_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 - -/* 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 - -#else - -#define ATTRIBUTE_HIDDEN - -#endif - -#ifndef GCOV_LINKAGE -#define GCOV_LINKAGE extern -#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. The tag value zero is used as an explicit end of - file marker -- it is not required to be present. */ - -#define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000) -#define GCOV_TAG_FUNCTION_LENGTH (3) -#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) /* Obsolete */ -#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 - summed. */ -#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_COUNTER_V_INDIR 5 /* The most common indirect address */ -#define GCOV_COUNTER_AVERAGE 6 /* Compute average value passed to the - counter. */ -#define GCOV_COUNTER_IOR 7 /* IOR of the all values passed to - counter. */ -#define GCOV_LAST_VALUE_COUNTER 7 /* The last of counters used for value - profiling. */ -#define GCOV_COUNTERS 8 - -/* 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", "indirect_call", "average", "ior"} - - /* 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", \ - "__gcov_merge_single", \ - "__gcov_merge_add", \ - "__gcov_merge_ior"} - -/* 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 int)(((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 coverage program. The structures generated - by write_profile must match these. */ - -#if IN_LIBGCOV -/* Information about counters for a single function. */ -struct gcov_ctr_info { - gcov_unsigned_t num; /* number of counters. */ - gcov_type *values; /* their values. */ -}; - -/* Information about a single function. This uses the trailing array - idiom. The number of counters is determined from the merge pointer - array in gcov_info. The key is used to detect which of a set of - comdat functions was selected -- it points to the gcov_info object - of the object file containing the selected comdat function. */ - -struct gcov_fn_info { - const struct gcov_info *key; /* comdat key */ - gcov_unsigned_t ident; /* unique ident of function */ - gcov_unsigned_t lineno_checksum; /* function lineo_checksum */ - gcov_unsigned_t cfg_checksum; /* function cfg checksum */ - struct gcov_ctr_info ctrs[0]; /* instrumented counters */ -}; - -/* Type of function used to merge counters. */ -typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t); - -/* 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 */ - - gcov_merge_fn merge[GCOV_COUNTERS]; /* merge functions (null for - unused) */ - - unsigned int n_functions; /* number of functions */ - const struct gcov_fn_info *const *functions; /* pointer to pointers to - function information */ -}; - -/* Register a new object file module. */ -extern void __gcov_init(struct gcov_info *) ATTRIBUTE_HIDDEN; - -#ifndef __COREBOOT__ -/* Called before fork, to avoid double counting. */ -extern void __gcov_flush(void) ATTRIBUTE_HIDDEN; -#endif - -/* The merge function that just sums the counters. */ -extern void __gcov_merge_add(gcov_type *, unsigned int) ATTRIBUTE_HIDDEN; - -/* The merge function to choose the most common value. */ -extern void __gcov_merge_single(gcov_type *, unsigned int) ATTRIBUTE_HIDDEN; - -/* The merge function to choose the most common difference between - consecutive values. */ -extern void __gcov_merge_delta(gcov_type *, unsigned int) ATTRIBUTE_HIDDEN; - -/* The merge function that just ors the counters together. */ -extern void __gcov_merge_ior(gcov_type *, unsigned int) ATTRIBUTE_HIDDEN; - -/* The profiler functions. */ -extern void __gcov_interval_profiler(gcov_type *, gcov_type, int, unsigned int); -extern void __gcov_pow2_profiler(gcov_type *, gcov_type); -extern void __gcov_one_value_profiler(gcov_type *, gcov_type); -extern void __gcov_indirect_call_profiler(gcov_type *, gcov_type, void *, - void *); -extern void __gcov_average_profiler(gcov_type *, gcov_type); -extern void __gcov_ior_profiler(gcov_type *, gcov_type); - -#ifndef inhibit_libc -/* The wrappers around some library functions.. */ -extern pid_t __gcov_fork(void) ATTRIBUTE_HIDDEN; -extern int __gcov_execl(const char *, char *, ...) ATTRIBUTE_HIDDEN; -extern int __gcov_execlp(const char *, char *, ...) ATTRIBUTE_HIDDEN; -extern int __gcov_execle(const char *, char *, ...) ATTRIBUTE_HIDDEN; -extern int __gcov_execv(const char *, char *const []) ATTRIBUTE_HIDDEN; -extern int __gcov_execvp(const char *, char *const []) ATTRIBUTE_HIDDEN; -extern int __gcov_execve(const char *, char *const [], char *const []) - ATTRIBUTE_HIDDEN; -#endif - -#endif /* IN_LIBGCOV */ - -#if IN_LIBGCOV >= 0 - -/* Optimum number of gcov_unsigned_t's read from or written to disk. */ -#define GCOV_BLOCK_SIZE (1 << 10) - -GCOV_LINKAGE struct gcov_var -{ - FILE *file; - gcov_position_t start; /* Position of first byte of block */ - unsigned int offset; /* Read/write position within the block. */ - unsigned int length; /* Read limit in the block. */ - unsigned int overread; /* Number of words overread. */ - int error; /* < 0 overflow, > 0 disk error. */ - int mode; /* < 0 writing, > 0 reading */ -#if IN_LIBGCOV - /* 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]; -#else - int endian; /* Swap endianness. */ - /* Holds a variable length block, as the compiler can write - * strings and needs to backtrack. - */ - size_t alloc; - gcov_unsigned_t *buffer; -#endif -} gcov_var ATTRIBUTE_HIDDEN; - -/* 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. */ -#if IN_LIBGCOV -GCOV_LINKAGE int gcov_open(const char */*name*/) ATTRIBUTE_HIDDEN; -#else -GCOV_LINKAGE int gcov_open(const char */*name*/, int /*direction*/); -GCOV_LINKAGE int gcov_magic(gcov_unsigned_t, gcov_unsigned_t); -#endif -GCOV_LINKAGE int gcov_close(void) ATTRIBUTE_HIDDEN; - -/* Available everywhere. */ -static gcov_position_t gcov_position(void); -static int gcov_is_error(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; - -#if IN_LIBGCOV -/* 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; -static void gcov_rewrite(void); -GCOV_LINKAGE void gcov_seek(gcov_position_t /*position*/) ATTRIBUTE_HIDDEN; -#else -/* Available outside libgcov */ -GCOV_LINKAGE const char *gcov_read_string(void); -GCOV_LINKAGE void gcov_sync(gcov_position_t /*base*/, - gcov_unsigned_t /*length */); -#endif - -#if !IN_GCOV -/* Available outside gcov */ -GCOV_LINKAGE void gcov_write_unsigned(gcov_unsigned_t) ATTRIBUTE_HIDDEN; -#endif - -#if !IN_GCOV && !IN_LIBGCOV -/* Available only in compiler */ -GCOV_LINKAGE void gcov_write_string(const char *); -GCOV_LINKAGE gcov_position_t gcov_write_tag(gcov_unsigned_t); -GCOV_LINKAGE void gcov_write_length(gcov_position_t /*position*/); -#endif - -#if IN_GCOV > 0 -/* Available in gcov */ -GCOV_LINKAGE time_t gcov_time(void); -#endif - -/* Save the current position in the gcov file. */ - -static inline gcov_position_t -gcov_position(void) -{ - gcc_assert(gcov_var.mode > 0); - return gcov_var.start + gcov_var.offset; -} - -/* Return nonzero if the error flag is set. */ - -static inline int -gcov_is_error(void) -{ - return gcov_var.file ? gcov_var.error : 1; -} - -#if IN_LIBGCOV -/* Move to beginning of file and initialize for writing. */ - -static inline void -gcov_rewrite(void) -{ - gcc_assert(gcov_var.mode > 0); - gcov_var.mode = -1; - gcov_var.start = 0; - gcov_var.offset = 0; - fseek(gcov_var.file, 0L, SEEK_SET); -} -#endif - -#endif /* IN_LIBGCOV >= 0 */ - -#endif /* GCC_GCOV_IO_H */ diff --git a/src/libgcov/gcov-iov.h b/src/libgcov/gcov-iov.h @@ -1,4 +0,0 @@ -/* Generated automatically by the program `build/gcov-iov' - from `4.7.2 (4 7) and (*)'. */ - -#define GCOV_VERSION ((gcov_unsigned_t)0x3430372a) /* 407* */ diff --git a/src/libgcov/libgcov.c b/src/libgcov/libgcov.c @@ -1,1157 +0,0 @@ -/* 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, 2004, 2005, 2008, 2009, 2010, 2011 - 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 3, 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. -*/ - -#define __COREBOOT__ -#ifdef __COREBOOT__ -#include <stdlib.h> -#include <string.h> -#include <console/console.h> -#include <assert.h> -typedef s32 pid_t; -#define gcc_assert(x) ASSERT(x) -#define fprintf(file, x...) printk(BIOS_ERR, x) -#define alloca(size) __builtin_alloca(size) -#include "gcov-glue.c" - -/* Define MACROs to be used by coreboot compilation. */ -# define L_gcov -# define L_gcov_interval_profiler -# define L_gcov_pow2_profiler -# define L_gcov_one_value_profiler -# define L_gcov_indirect_call_profiler -# define L_gcov_average_profiler -# define L_gcov_ior_profiler - -# define HAVE_CC_TLS 0 -# define __GCOV_KERNEL__ - -# define IN_LIBGCOV 1 -# define IN_GCOV 0 -#else /* __COREBOOT__ */ -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include "libgcc_tm.h" -#endif /* __COREBOOT__ */ - -#ifndef __COREBOOT__ -#if defined(inhibit_libc) -#define IN_LIBGCOV (-1) -#else -#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ -#include <stdio.h> -#define IN_LIBGCOV 1 -#if defined(L_gcov) -#define GCOV_LINKAGE /* nothing */ -#endif -#endif -#endif /* __COREBOOT__ */ -#include "gcov-io.h" - -#if defined(inhibit_libc) -/* If libc and its header files are not available, provide dummy functions. */ - -#ifdef L_gcov -void __gcov_init(struct gcov_info *p __attribute__((unused))) {} -void __gcov_flush(void) {} -#endif - -#ifdef L_gcov_merge_add -void __gcov_merge_add(gcov_type *counters __attribute__((unused)), - unsigned int n_counters __attribute__((unused))) {} -#endif - -#ifdef L_gcov_merge_single -void __gcov_merge_single(gcov_type *counters __attribute__((unused)), - unsigned int n_counters __attribute__((unused))) {} -#endif - -#ifdef L_gcov_merge_delta -void __gcov_merge_delta(gcov_type *counters __attribute__((unused)), - unsigned int n_counters __attribute__((unused))) {} -#endif - -#else - -#ifndef __COREBOOT__ -#include <string.h> -#if GCOV_LOCKED -#include <fcntl.h> -#include <errno.h> -#include <sys/stat.h> -#endif -#else -void __gcov_merge_add(gcov_type *counters __attribute__((unused)), - unsigned int n_counters __attribute__((unused))) {} -#endif /* __COREBOOT__ */ - -#ifdef L_gcov -#include "gcov-io.c" - -struct gcov_fn_buffer { - struct gcov_fn_buffer *next; - unsigned int fn_ix; - struct gcov_fn_info info; - /* note gcov_fn_info ends in a trailing array. */ -}; - -/* Chain of per-object gcov structures. */ -static struct gcov_info *gcov_list; - -/* Size of the longest file name. */ -static size_t gcov_max_filename = 0; - -/* Make sure path component of the given FILENAME exists, create - missing directories. FILENAME must be writable. - Returns zero on success, or -1 if an error occurred. */ - -static int -create_file_directory(char *filename) -{ -#ifdef __COREBOOT__ - (void) filename; - return 0; -#else -#if !defined(TARGET_POSIX_IO) && !defined(_WIN32) - (void) filename; - return -1; -#else - char *s; - - s = filename; - - if (HAS_DRIVE_SPEC(s)) - s += 2; - if (IS_DIR_SEPARATOR(*s)) - ++s; - for (; *s != '\0'; s++) - if (IS_DIR_SEPARATOR(*s)) { - char sep = *s; - *s = '\0'; - - /* Try to make directory if it doesn't already exist. */ - if (access(filename, F_OK) == -1 -#ifdef TARGET_POSIX_IO - && mkdir(filename, 0755) == -1 -#else - && mkdir(filename) == -1 -#endif - /* The directory might have been made by another - * process. - */ - && errno != EEXIST) { - fprintf(stderr, - "profiling:%s:Cannot create directory\n", - filename); - *s = sep; - return -1; - }; - - *s = sep; - }; - return 0; -#endif -#endif -} - -static struct gcov_fn_buffer * -free_fn_data(const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer, - unsigned int limit) -{ - struct gcov_fn_buffer *next; - unsigned int ix, n_ctr = 0; - - if (!buffer) - return 0; - next = buffer->next; - - for (ix = 0; ix != limit; ix++) - if (gi_ptr->merge[ix]) - free(buffer->info.ctrs[n_ctr++].values); - free(buffer); - return next; -} - -static struct gcov_fn_buffer ** -buffer_fn_data(const char *filename, const struct gcov_info *gi_ptr, - struct gcov_fn_buffer **end_ptr, unsigned int fn_ix) -{ - unsigned int n_ctrs = 0, ix = 0; - struct gcov_fn_buffer *fn_buffer; - unsigned int len; - - for (ix = GCOV_COUNTERS; ix--;) - if (gi_ptr->merge[ix]) - n_ctrs++; - - len = sizeof(*fn_buffer) + sizeof(fn_buffer->info.ctrs[0]) * n_ctrs; - fn_buffer = (struct gcov_fn_buffer *)malloc(len); - - if (!fn_buffer) - goto fail; - - fn_buffer->next = 0; - fn_buffer->fn_ix = fn_ix; - fn_buffer->info.ident = gcov_read_unsigned(); - fn_buffer->info.lineno_checksum = gcov_read_unsigned(); - fn_buffer->info.cfg_checksum = gcov_read_unsigned(); - - for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++) { - gcov_unsigned_t length; - gcov_type *values; - - if (!gi_ptr->merge[ix]) - continue; - - if (gcov_read_unsigned() != GCOV_TAG_FOR_COUNTER(ix)) { - len = 0; - goto fail; - } - - length = GCOV_TAG_COUNTER_NUM(gcov_read_unsigned()); - len = length * sizeof(gcov_type); - values = (gcov_type *)malloc(len); - if (!values) - goto fail; - - fn_buffer->info.ctrs[n_ctrs].num = length; - fn_buffer->info.ctrs[n_ctrs].values = values; - - while (length--) - *values++ = gcov_read_counter(); - n_ctrs++; - } - - *end_ptr = fn_buffer; - return &fn_buffer->next; - -fail: - fprintf(stderr, "profiling:%s:Function %u %s %u\n", filename, fn_ix, - len ? "cannot allocate" : "counter mismatch", len ? len : ix); - - return (struct gcov_fn_buffer **)free_fn_data(gi_ptr, fn_buffer, ix); -} - -/* Add an unsigned value to the current crc */ - -static gcov_unsigned_t -crc32_unsigned(gcov_unsigned_t crc32, gcov_unsigned_t value) -{ - unsigned int ix; - - for (ix = 32; ix--; value <<= 1) { - unsigned int feedback; - - feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; - crc32 <<= 1; - crc32 ^= feedback; - } - - return crc32; -} - -/* Check if VERSION of the info block PTR matches libgcov one. - Return 1 on success, or zero in case of versions mismatch. - If FILENAME is not NULL, its value used for reporting purposes - instead of value from the info block. */ - -static int -gcov_version(struct gcov_info *ptr, gcov_unsigned_t version, - const char *filename) -{ - if (version != GCOV_VERSION) { - char v[4], e[4]; - - GCOV_UNSIGNED2STRING(v, version); - GCOV_UNSIGNED2STRING(e, GCOV_VERSION); - - fprintf(stderr, - "profiling:%s:Version mismatch - expected %.4s got %.4s\n", - filename ? filename : ptr->filename, e, v); - return 0; - } - return 1; -} - -/* 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. */ - -static void -gcov_exit(void) -{ - struct gcov_info *gi_ptr; - const struct gcov_fn_info *gfi_ptr; - struct gcov_summary this_prg; /* summary for program. */ - struct gcov_summary all_prg; /* summary for all instances of program. */ - struct gcov_ctr_summary *cs_ptr; - const struct gcov_ctr_info *ci_ptr; - unsigned int t_ix; - int f_ix = 0; - gcov_unsigned_t c_num; - const char *gcov_prefix; - int gcov_prefix_strip = 0; - size_t prefix_length; - char *gi_filename, *gi_filename_up; - gcov_unsigned_t crc32 = 0; - - memset(&all_prg, 0, sizeof(all_prg)); - /* Find the totals for this execution. */ - memset(&this_prg, 0, sizeof(this_prg)); - for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) { - crc32 = crc32_unsigned(crc32, gi_ptr->stamp); - crc32 = crc32_unsigned(crc32, gi_ptr->n_functions); - - for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions; - f_ix++) { - gfi_ptr = gi_ptr->functions[f_ix]; - - if (gfi_ptr && gfi_ptr->key != gi_ptr) - gfi_ptr = 0; - - crc32 = crc32_unsigned(crc32, gfi_ptr - ? gfi_ptr->cfg_checksum : 0); - crc32 = crc32_unsigned(crc32, - gfi_ptr ? gfi_ptr->lineno_checksum : 0); - if (!gfi_ptr) - continue; - - ci_ptr = gfi_ptr->ctrs; - for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) { - if (!gi_ptr->merge[t_ix]) - continue; - - cs_ptr = &this_prg.ctrs[t_ix]; - cs_ptr->num += ci_ptr->num; - crc32 = crc32_unsigned(crc32, 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++; - } - } - } - -#ifndef __COREBOOT__ - { - /* Check if the level of dirs to strip off specified. */ - char *tmp = getenv("GCOV_PREFIX_STRIP"); - if (tmp) { - gcov_prefix_strip = atoi(tmp); - /* Do not consider negative values. */ - if (gcov_prefix_strip < 0) - gcov_prefix_strip = 0; - } - } - - /* Get file name relocation prefix. Non-absolute values are ignored. */ - gcov_prefix = getenv("GCOV_PREFIX"); - if (gcov_prefix) { - prefix_length = strlen(gcov_prefix); - - /* Remove an unnecessary trailing '/' */ - if (IS_DIR_SEPARATOR(gcov_prefix[prefix_length - 1])) - prefix_length--; - } else -#endif - prefix_length = 0; - - /* If no prefix was specified and a prefix strip, then we assume - relative. */ - if (gcov_prefix_strip != 0 && prefix_length == 0) { - gcov_prefix = "."; - prefix_length = 1; - } - /* Allocate and initialize the filename scratch space plus one. */ - gi_filename = (char *) alloca(prefix_length + gcov_max_filename + 2); - if (prefix_length) - memcpy(gi_filename, gcov_prefix, prefix_length); - gi_filename_up = gi_filename + prefix_length; - - /* Now merge each file. */ - for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) { - unsigned int n_counts; - struct gcov_summary prg; /* summary for this object over all - program. */ - struct gcov_ctr_summary *cs_prg, *cs_tprg, *cs_all; - int error = 0; - gcov_unsigned_t tag, length; - gcov_position_t summary_pos = 0; - gcov_position_t eof_pos = 0; - const char *fname, *s; - struct gcov_fn_buffer *fn_buffer = NULL; - struct gcov_fn_buffer **fn_tail = &fn_buffer; - - fname = gi_ptr->filename; - - /* Avoid to add multiple drive letters into combined path. */ - if (prefix_length != 0 && HAS_DRIVE_SPEC(fname)) - fname += 2; - - /* Build relocated filename, stripping off leading - * directories from the initial filename if requested. - */ - if (gcov_prefix_strip > 0) { - int level = 0; - - s = fname; - if (IS_DIR_SEPARATOR(*s)) - ++s; - - /* Skip selected directory levels. */ - for (; (*s != '\0') && (level < gcov_prefix_strip); s++) - if (IS_DIR_SEPARATOR(*s)) { - fname = s; - level++; - } - } - - /* Update complete filename with stripped original. */ - if (prefix_length != 0 && !IS_DIR_SEPARATOR(*fname)) { - /* If prefix is given, add directory separator. - */ - strcpy(gi_filename_up, "/"); - strcpy(gi_filename_up + 1, fname); - } else - strcpy(gi_filename_up, fname); - - if (!gcov_open(gi_filename)) { - /* Open failed likely due to missed directory. - * Create directory and retry to open file. - */ - if (create_file_directory(gi_filename)) { - fprintf(stderr, "profiling:%s:Skip\n", - gi_filename); - continue; - } - if (!gcov_open(gi_filename)) { - fprintf(stderr, - "profiling:%s:Cannot open\n", - gi_filename); - continue; - } - } - - 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_filename); - goto read_fatal; - } - length = gcov_read_unsigned(); - if (!gcov_version(gi_ptr, length, gi_filename)) - goto read_fatal; - - length = gcov_read_unsigned(); - if (length != gi_ptr->stamp) - /* Read from a different compilation. - * Overwrite the file. - */ - goto rewrite; - - /* Look for program summary. */ - for (f_ix = 0;;) { - struct gcov_summary tmp; - - eof_pos = gcov_position(); - tag = gcov_read_unsigned(); - if (tag != GCOV_TAG_PROGRAM_SUMMARY) - break; - - f_ix--; - length = gcov_read_unsigned(); - if (length != GCOV_TAG_SUMMARY_LENGTH) - goto read_mismatch; - gcov_read_summary(&tmp); - error = gcov_is_error(); - if (error) - goto read_error; - if (summary_pos - || tmp.checksum != crc32) - goto next_summary; - - for (t_ix = 0; t_ix != - GCOV_COUNTERS_SUMMABLE; t_ix++) - if (tmp.ctrs[t_ix].num != - this_prg.ctrs[t_ix].num) - goto next_summary; - prg = tmp; - summary_pos = eof_pos; - - next_summary:; - } - - /* Merge execution counts for each function. */ - for (f_ix = 0; (unsigned int)f_ix != - gi_ptr->n_functions; - f_ix++, tag = gcov_read_unsigned()) { - gfi_ptr = gi_ptr->functions[f_ix]; - - if (tag != GCOV_TAG_FUNCTION) - goto read_mismatch; - - length = gcov_read_unsigned(); - if (!length) - /* This function did not appear - * in the other program. We - * have nothing to merge. - */ - continue; - - if (length != GCOV_TAG_FUNCTION_LENGTH) - goto read_mismatch; - - if (!gfi_ptr || gfi_ptr->key != - gi_ptr) { - /* This function appears in the - * other program. We need to - * buffer the information in - * order to write it back out -- - * we'll be inserting data - * before this point, so cannot - * simply keep the data in the - * file. - */ - fn_tail = buffer_fn_data( - gi_filename, gi_ptr, - fn_tail, f_ix); - if (!fn_tail) - goto read_mismatch; - continue; - } - - length = gcov_read_unsigned(); - if (length != gfi_ptr->ident) - goto read_mismatch; - - length = gcov_read_unsigned(); - if (length != gfi_ptr->lineno_checksum) - goto read_mismatch; - - length = gcov_read_unsigned(); - if (length != gfi_ptr->cfg_checksum) - goto read_mismatch; - - ci_ptr = gfi_ptr->ctrs; - for (t_ix = 0; t_ix < GCOV_COUNTERS; - t_ix++) { - gcov_merge_fn merge = - gi_ptr->merge[t_ix]; - - if (!merge) - continue; - - tag = gcov_read_unsigned(); - length = gcov_read_unsigned(); - if (tag != GCOV_TAG_FOR_COUNTER( - t_ix) || length != - GCOV_TAG_COUNTER_LENGTH( - ci_ptr->num)) - goto read_mismatch; - (*merge)(ci_ptr->values, - ci_ptr->num); - ci_ptr++; - } - error = gcov_is_error(); - if (error) - goto read_error; - } - - if (tag) { - read_mismatch:; - fprintf(stderr, - "profiling:%s:Merge mismatch for %s %u\n", - gi_filename, f_ix >= 0 ? - "function" : "summary", - f_ix < 0 ? -1 - f_ix : f_ix); - goto read_fatal; - } - } - goto rewrite; - -read_error:; - fprintf(stderr, "profiling:%s:%s merging\n", gi_filename, - error < 0 ? "Overflow" : "Error"); - - goto read_fatal; - -rewrite:; - gcov_rewrite(); - if (!summary_pos) { - memset(&prg, 0, sizeof(prg)); - summary_pos = eof_pos; - } - - /* Merge the summaries. */ - for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) { - cs_prg = &prg.ctrs[t_ix]; - cs_tprg = &this_prg.ctrs[t_ix]; - cs_all = &all_prg.ctrs[t_ix]; - - if (gi_ptr->merge[t_ix]) { - if (!cs_prg->runs++) - cs_prg->num = cs_tprg->num; - 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_prg->runs) - goto read_mismatch; - - if (!cs_all->runs && cs_prg->runs) - memcpy(cs_all, cs_prg, sizeof(*cs_all)); - else if (!all_prg.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\n", - gi_filename, GCOV_LOCKED ? "" : - " or concurrently updated without locking support"); - all_prg.checksum = ~0u; - } - } - - prg.checksum = crc32; - - /* Write out the data. */ - if (!eof_pos) { - gcov_write_tag_length(GCOV_DATA_MAGIC, GCOV_VERSION); - gcov_write_unsigned(gi_ptr->stamp); - } - - if (summary_pos) - gcov_seek(summary_pos); - - /* Generate whole program statistics. */ - gcov_write_summary(GCOV_TAG_PROGRAM_SUMMARY, &prg); - - if (summary_pos < eof_pos) - gcov_seek(eof_pos); - - /* Write execution counts for each function. */ - for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions; - f_ix++) { - unsigned int buffered = 0; - - if (fn_buffer && fn_buffer->fn_ix - == (unsigned int)f_ix) { - /* Buffered data from another program. */ - buffered = 1; - gfi_ptr = &fn_buffer->info; - length = GCOV_TAG_FUNCTION_LENGTH; - } else { - gfi_ptr = gi_ptr->functions[f_ix]; - if (gfi_ptr && gfi_ptr->key == gi_ptr) - length = GCOV_TAG_FUNCTION_LENGTH; - else - length = 0; - } - - gcov_write_tag_length(GCOV_TAG_FUNCTION, length); - if (!length) - continue; - - gcov_write_unsigned(gfi_ptr->ident); - gcov_write_unsigned(gfi_ptr->lineno_checksum); - gcov_write_unsigned(gfi_ptr->cfg_checksum); - - ci_ptr = gfi_ptr->ctrs; - for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) { - if (!gi_ptr->merge[t_ix]) - continue; - - n_counts = ci_ptr->num; - gcov_write_tag_length( - GCOV_TAG_FOR_COUNTER(t_ix), - GCOV_TAG_COUNTER_LENGTH(n_counts)); - gcov_type *c_ptr = ci_ptr->values; - while (n_counts--) - gcov_write_counter(*c_ptr++); - ci_ptr++; - } - if (buffered) - fn_buffer = free_fn_data(gi_ptr, fn_buffer, - GCOV_COUNTERS); - } - - gcov_write_unsigned(0); - -read_fatal:; - while (fn_buffer) - fn_buffer = free_fn_data(gi_ptr, fn_buffer, - GCOV_COUNTERS); - - error = gcov_close(); - if (error) - fprintf(stderr, error < 0 ? - "profiling:%s:Overflow writing\n" : - "profiling:%s:Error writing\n", - gi_filename); - } -} - -/* 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 || !info->n_functions) - return; - if (gcov_version(info, info->version, 0)) { - size_t filename_length = strlen(info->filename); - - /* Refresh the longest file name information */ - if (filename_length > gcov_max_filename) - gcov_max_filename = filename_length; - -#ifndef __COREBOOT__ - if (!gcov_list) - atexit(gcov_exit); -#endif - - info->next = gcov_list; - gcov_list = info; - } - info->version = 0; -} - -/* 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 int f_ix; - - for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { - unsigned int t_ix; - const struct gcov_fn_info *gfi_ptr = - gi_ptr->functions[f_ix]; - - if (!gfi_ptr || gfi_ptr->key != gi_ptr) - continue; - const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs; - for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) { - if (!gi_ptr->merge[t_ix]) - continue; - - memset(ci_ptr->values, 0, - sizeof(gcov_type) * ci_ptr->num); - ci_ptr++; - } - } - } -} - -#endif /* L_gcov */ - -#ifdef L_gcov_merge_add -/* 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 int n_counters) -{ - for (; n_counters; counters++, n_counters--) - *counters += gcov_read_counter(); -} -#endif /* L_gcov_merge_add */ - -#ifdef L_gcov_merge_ior -/* 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_ior(gcov_type *counters, unsigned int n_counters) -{ - for (; n_counters; counters++, n_counters--) - *counters |= gcov_read_counter(); -} -#endif - -#ifdef L_gcov_merge_single -/* 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 int n_counters) -{ - unsigned int i, n_measures; - gcov_type value, counter, all; - - gcc_assert(!(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; - } -} -#endif /* L_gcov_merge_single */ - -#ifdef L_gcov_merge_delta -/* 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 int n_counters) -{ - unsigned int i, n_measures; - gcov_type value, counter, all; - - gcc_assert(!(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 /* L_gcov_merge_delta */ - -#ifdef L_gcov_interval_profiler -/* If VALUE is in interval <START, START + STEPS - 1>, then increases the - corresponding counter in COUNTERS. If the VALUE is above or below - the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased - instead. */ - -void -__gcov_interval_profiler(gcov_type *counters, gcov_type value, - int start, unsigned int steps) -{ - gcov_type delta = value - start; - if (delta < 0) - counters[steps + 1]++; - else if (delta >= steps) - counters[steps]++; - else - counters[delta]++; -} -#endif - -#ifdef L_gcov_pow2_profiler -/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise - COUNTERS[0] is incremented. */ - -void -__gcov_pow2_profiler(gcov_type *counters, gcov_type value) -{ - if (value & (value - 1)) - counters[0]++; - else - counters[1]++; -} -#endif - -/* Tries to determine the most common value among its inputs. Checks if the - value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1] - is incremented. If this is not the case and COUNTERS[1] is not zero, - COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and - VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this - function is called more than 50% of the time with one value, this value - will be in COUNTERS[0] in the end. - - In any case, COUNTERS[2] is incremented. */ - -static inline void -__gcov_one_value_profiler_body(gcov_type *counters, gcov_type value) -{ - if (value == counters[0]) - counters[1]++; - else if (counters[1] == 0) { - counters[1] = 1; - counters[0] = value; - } else - counters[1]--; - counters[2]++; -} - -#ifdef L_gcov_one_value_profiler -void -__gcov_one_value_profiler(gcov_type *counters, gcov_type value) -{ - __gcov_one_value_profiler_body(counters, value); -} -#endif - -#ifdef L_gcov_indirect_call_profiler - -/* By default, the C++ compiler will use function addresses in the - vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero - tells the compiler to use function descriptors instead. The value - of this macro says how many words wide the descriptor is (normally 2), - but it may be dependent on target flags. Since we do not have access - to the target flags here we just check to see if it is set and use - that to set VTABLE_USES_DESCRIPTORS to 0 or 1. - - It is assumed that the address of a function descriptor may be treated - as a pointer to a function. */ - -#ifdef TARGET_VTABLE_USES_DESCRIPTORS -#define VTABLE_USES_DESCRIPTORS 1 -#else -#define VTABLE_USES_DESCRIPTORS 0 -#endif - -/* Tries to determine the most common value among its inputs. */ -void -__gcov_indirect_call_profiler(gcov_type *counter, gcov_type value, - void *cur_func, void *callee_func) -{ - /* If the C++ virtual tables contain function descriptors then one - * function may have multiple descriptors and we need to dereference - * the descriptors to see if they point to the same function. - */ - if (cur_func == callee_func - || (VTABLE_USES_DESCRIPTORS && callee_func - && *(void **) cur_func == *(void **) callee_func)) - __gcov_one_value_profiler_body(counter, value); -} -#endif - - -#ifdef L_gcov_average_profiler -/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want - to saturate up. */ - -void -__gcov_average_profiler(gcov_type *counters, gcov_type value) -{ - counters[0] += value; - counters[1]++; -} -#endif - -#ifdef L_gcov_ior_profiler -/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want - to saturate up. */ - -void -__gcov_ior_profiler(gcov_type *counters, gcov_type value) -{ - *counters |= value; -} -#endif - -#ifdef L_gcov_fork -/* A wrapper for the fork function. Flushes the accumulated profiling data, so - that they are not counted twice. */ - -pid_t -__gcov_fork(void) -{ - __gcov_flush(); - return fork(); -} -#endif - -#ifdef L_gcov_execl -/* A wrapper for the execl function. Flushes the accumulated profiling data, so - that they are not lost. */ - -int -__gcov_execl(const char *path, char *arg, ...) -{ - va_list ap, aq; - unsigned int i, length; - char **args; - - __gcov_flush(); - - va_start(ap, arg); - va_copy(aq, ap); - - length = 2; - while (va_arg(ap, char *)) - length++; - va_end(ap); - - args = (char **) alloca(length * sizeof(void *)); - args[0] = arg; - for (i = 1; i < length; i++) - args[i] = va_arg(aq, char *); - va_end(aq); - - return execv(path, args); -} -#endif - -#ifdef L_gcov_execlp -/* A wrapper for the execlp function. Flushes the accumulated profiling data, - * so that they are not lost. - */ - -int -__gcov_execlp(const char *path, char *arg, ...) -{ - va_list ap, aq; - unsigned int i, length; - char **args; - - __gcov_flush(); - - va_start(ap, arg); - va_copy(aq, ap); - - length = 2; - while (va_arg(ap, char *)) - length++; - va_end(ap); - - args = (char **) alloca(length * sizeof(void *)); - args[0] = arg; - for (i = 1; i < length; i++) - args[i] = va_arg(aq, char *); - va_end(aq); - - return execvp(path, args); -} -#endif - -#ifdef L_gcov_execle -/* A wrapper for the execle function. Flushes the accumulated profiling data, - * so that they are not lost. - */ - -int -__gcov_execle(const char *path, char *arg, ...) -{ - va_list ap, aq; - unsigned int i, length; - char **args; - char **envp; - - __gcov_flush(); - - va_start(ap, arg); - va_copy(aq, ap); - - length = 2; - while (va_arg(ap, char *)) - length++; - va_end(ap); - - args = (char **) alloca(length * sizeof(void *)); - args[0] = arg; - for (i = 1; i < length; i++) - args[i] = va_arg(aq, char *); - envp = va_arg(aq, char **); - va_end(aq); - - return execve(path, args, envp); -} -#endif - -#ifdef L_gcov_execv -/* A wrapper for the execv function. Flushes the accumulated profiling data, so - that they are not lost. */ - -int -__gcov_execv(const char *path, char *const argv[]) -{ - __gcov_flush(); - return execv(path, argv); -} -#endif - -#ifdef L_gcov_execvp -/* A wrapper for the execvp function. Flushes the accumulated profiling data, - * so that they are not lost. - */ - -int -__gcov_execvp(const char *path, char *const argv[]) -{ - __gcov_flush(); - return execvp(path, argv); -} -#endif - -#ifdef L_gcov_execve -/* A wrapper for the execve function. Flushes the accumulated profiling data, - * so that they are not lost. - */ - -int -__gcov_execve(const char *path, char *const argv[], char *const envp[]) -{ - __gcov_flush(); - return execve(path, argv, envp); -} -#endif -#endif /* inhibit_libc */