/* Routines required for instrumenting a program. */
/* Compile this one with gcc. */
/* Copyright (C) 1989-2014 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.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgcov.h"
#if defined(inhibit_libc)
/* If libc and its header files are not available, provide dummy functions. */
#if defined(L_gcov)
void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
#endif
#else /* inhibit_libc */
#if !defined(__KERNEL__)
#include <string.h>
#if GCOV_LOCKED
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#endif
#endif /* __KERNEL__ */
#ifdef L_gcov
#include "gcov-io.c"
/* Unique identifier assigned to each module (object file). */
static gcov_unsigned_t gcov_cur_module_id = 0;
/* Dynamic call graph build and form module groups. */
int __gcov_compute_module_groups (char **zero_counts) ATTRIBUTE_HIDDEN;
void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
/* The following functions can be called from outside of this file. */
extern void gcov_clear (void) ATTRIBUTE_HIDDEN;
extern void gcov_exit (void) ATTRIBUTE_HIDDEN;
extern void set_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
extern void reset_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
extern int get_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
extern void set_gcov_list (struct gcov_info *) ATTRIBUTE_HIDDEN;
__attribute__((weak)) void __coverage_callback (gcov_type, int);
#if !defined(IN_GCOV_TOOL) && !defined(__KERNEL__)
extern gcov_unsigned_t __gcov_sampling_period;
extern gcov_unsigned_t __gcov_has_sampling;
static int gcov_sampling_period_initialized = 0;
/* Create a strong reference to these symbols so that they are
unconditionally pulled into the instrumented binary, even when
the only reference is a weak reference. This is necessary because
we are using weak references to enable references from code that
may not be linked with libgcov. These are the only symbols that
should be accessed via link references from application code!
A subtlety of the linker is that it will only resolve weak references
defined within archive libraries when there is a strong reference to
something else defined within the same object file. Since these functions
are defined within their own object files, they would not automatically
get resolved. Since there are symbols within the main L_gcov
section that are strongly referenced during -fprofile-generate and
-ftest-coverage builds, these dummy symbols will always need to be
resolved. */
void (*__gcov_dummy_ref1)(void) = &__gcov_reset;
void (*__gcov_dummy_ref2)(void) = &__gcov_dump;
extern char *__gcov_get_profile_prefix (void);
char *(*__gcov_dummy_ref3)(void) = &__gcov_get_profile_prefix;
extern void __gcov_set_sampling_period (unsigned int period);
char *(*__gcov_dummy_ref4)(void) = &__gcov_set_sampling_period;
extern unsigned int __gcov_sampling_enabled (void);
char *(*__gcov_dummy_ref5)(void) = &__gcov_sampling_enabled;
extern void __gcov_flush (void);
char *(*__gcov_dummy_ref6)(void) = &__gcov_flush;
extern unsigned int __gcov_profiling_for_test_coverage (void);
char *(*__gcov_dummy_ref7)(void) = &__gcov_profiling_for_test_coverage;
#endif
/* Default callback function for profile instrumentation callback. */
__attribute__((weak)) void
__coverage_callback (gcov_type funcdef_no __attribute__ ((unused)),
int edge_no __attribute__ ((unused)))
{
/* nothing */
}
struct gcov_fn_buffer
{
struct gcov_fn_buffer *next;
unsigned fn_ix;
struct gcov_fn_info info;
/* note gcov_fn_info ends in a trailing array. */
};
struct gcov_summary_buffer
{
struct gcov_summary_buffer *next;
struct gcov_summary summary;
};
/* Chain of per-object gcov structures. */
extern struct gcov_info *__gcov_list;
/* Set the head of gcov_list. */
void
set_gcov_list (struct gcov_info *head)
{
__gcov_list = head;
}
/* Flag if the current function being read was marked as having fixed-up
zero counters. */
static int __gcov_curr_fn_fixed_up;
/* Set function fixed up flag. */
void
set_gcov_fn_fixed_up (int fixed_up)
{
__gcov_curr_fn_fixed_up = fixed_up;
}
/* Return function fixed up flag. */
int
get_gcov_fn_fixed_up (void)
{
return __gcov_curr_fn_fixed_up;
}
/* Size of the longest file name. */
/* We need to expose this static variable when compiling for gcov-tool. */
#ifndef IN_GCOV_TOOL
static
#endif
size_t gcov_max_filename = 0;
/* Flag when the profile has already been dumped via __gcov_dump(). */
static int gcov_dump_complete;
/* A global function that get the vaule of gcov_dump_complete. */
int
get_gcov_dump_complete (void)
{
return gcov_dump_complete;
}
/* A global functino that set the vaule of gcov_dump_complete. Will
be used in __gcov_dump() in libgcov-interface.c. */
void
set_gcov_dump_complete (void)
{
gcov_dump_complete = 1;
}
/* A global functino that set the vaule of gcov_dump_complete. Will
be used in __gcov_reset() in libgcov-interface.c. */
void
reset_gcov_dump_complete (void)
{
gcov_dump_complete = 0;
}
/* A utility function for outputing errors. */
static int gcov_error (const char *, ...);
static struct gcov_fn_buffer *
free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
unsigned limit)
{
struct gcov_fn_buffer *next;
unsigned ix, n_ctr = 0;
if (!buffer)
return 0;
next = buffer->next;
for (ix = 0; ix != limit; ix++)
if (gi_ptr->merge[ix])
xfree (buffer->info.ctrs[n_ctr++].values);
xfree (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 fn_ix)
{
unsigned n_ctrs = 0, ix = 0;
struct gcov_fn_buffer *fn_buffer;
unsigned 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 *) xmalloc (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 *) xmalloc (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:
gcov_error ("profiling:%s:Function %u %s %u \n", filename, fn_ix,
len ? "cannot allocate" : "counter mismatch", len ? len : ix);
return (struct gcov_fn_buffer **)
评论0