summaryrefslogtreecommitdiffstats
path: root/src/include/usr/gcov.h
blob: ede5e547b112e3c5bcbc4ea14e12797042722b0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/usr/gcov.h $                                      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2012,2014              */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef __USR_GCOV_H
#define __USR_GCOV_H

/** @file gcov.h
 *  @brief Header file to generate gcov_info chain for each module.
 *
 *  Each gcov-instrumented module needs to have its own gcov_info chain
 *  and associated linking function.  Each .o file will have its own
 *  gcov_info object which is added to the chain when the module is loaded
 *  (static initializers) by calling the __gcov_init function.
 *
 *  We make the gcov_info chain unique per-module, instead of a single
 *  global chain, so that we don't have bad pointers if a module was
 *  loaded and then unloaded.
 */

#include <stddef.h>
#include <stdint.h>
#include <string.h>

/** @struct gcov_info
 *  @brief Structure generated by gcc.  Do not use.
 *
 *  This structure is automatically generated and instances of it created by
 *  gcc when the --coverage compile option is used.  We don't need to
 *  manipulate this structure from code except:
 *      1) To fix up the chains as objects are added to the chain.
 *      2) To copy the gcov_info and counters into the base-chain when we
 *         unload a module.
 *
 *  The rest of this structure is parsed by the Gcov.pm debug tool.
 *
 *  Most of the items in here are used as uint32_t's by gcov but are still
 *  aligned on a 64-bit boundary.  The unusedN fields are to ensure proper
 *  alignment.
 */
struct gcov_info
{
    uint32_t version;
    uint32_t unused0;
    gcov_info* next;
    uint32_t timestamp;
    uint32_t unused1;
    char* filename;
    uint32_t n_functions;
    uint32_t unused2;
    void* functions;
    uint32_t counter_mask;
    uint32_t unused3;
    uint32_t n_counters;
    uint32_t unused4;
    uint64_t* counters;
} PACKED;

// Preprocessor magic to create a variable name based off the module name.
// GCOV_INFO_OBJ() will create a post-processed name like
// 'foobar_gcov_info_head' or 'core_gcov_info_head'.
#ifdef __HOSTBOOT_MODULE
    #define __GCOV_PREFIX __HOSTBOOT_MODULE
    #define ___GCOV_STRINGIFY(X) #X
    #define __GCOV_STRINGIFY(X) ___GCOV_STRINGIFY(X)
    #define __GCOV_PREFIX_NAME __GCOV_STRINGIFY(__HOSTBOOT_MODULE)
#else
    #define __GCOV_PREFIX core
    #define __GCOV_PREFIX_NAME "core"
#endif

#define __GCOV_INFO_OBJ(X,Y) X ## Y
#define _GCOV_INFO_OBJ(X,Y) __GCOV_INFO_OBJ(X,Y)
#define GCOV_INFO_OBJ() _GCOV_INFO_OBJ(__GCOV_PREFIX, _gcov_info_head)

/** Pointer to the beginning of the gcov_info chain for this module. */
gcov_info* GCOV_INFO_OBJ() = NULL;

/** Function called by module loading to add the object gcov_info instance
 *  to the chain.
 */
extern "C"
void __gcov_init(gcov_info* i_info)
{
    // Atomically push i_info onto the gcov_info_head stack.
    do
    {
        i_info->next = GCOV_INFO_OBJ();
    } while (!__sync_bool_compare_and_swap(&GCOV_INFO_OBJ(),
                                           i_info->next, i_info));
}

// This ifdef has two pieces of code which are used in module unloading.
//
// In the modules themselves we have a function that is registered via atexit
// to call to copy the contents of their own gcov_info chain into the base
// gcov_info chain.  This is required because the module's memory is going
// away as it is unloaded.
//
// In the base code (non-modules) we have a single implementation of the
// code for actually doing a copy of the gcov_info chain into the base code's
// own chain.  This is kept in just the base code for space savings.
//
#ifdef __HOSTBOOT_MODULE
// Forward declaration of __gcov_module_copychain for modules.
extern "C" void __gcov_module_copychain(gcov_info* chain);

/** Function called by module unloading to move the module's gcov_info
 *  instances to the global chain.
 */
extern "C"
void __gcov_module_unload(void* unused)
{
    __gcov_module_copychain(GCOV_INFO_OBJ());
}
    // Register __gcov_module_unload with __cxa_atexit.
extern void* __dso_handle;
extern "C" int __cxa_atexit(void(*)(void*),void*,void*);
int __unused_gcov_cxa_register =
                    __cxa_atexit(&__gcov_module_unload, NULL, __dso_handle);
#else
/** Function called by a module being unloaded (via __gcov_module_unload) to
 *  copy the module's gcov_info chain into the base gcov_info chain.
 */
extern "C"
void __gcov_module_copychain(gcov_info* chain)
{
    while(chain != NULL)
    {
        // Copy old info.
        gcov_info* new_info = new gcov_info();
        memcpy(new_info, chain, sizeof(gcov_info));

        // Copy old counters.
        uint64_t* new_counters = new uint64_t[chain->n_counters]();
        memcpy(new_counters, chain->counters,
               chain->n_counters*sizeof(uint64_t));
        new_info->counters = new_counters;

        // Atomically push new_info onto the core_gcov_info_head stack.
        do
        {
            new_info->next = GCOV_INFO_OBJ();
        } while (!__sync_bool_compare_and_swap(&GCOV_INFO_OBJ(),
                                               new_info->next, new_info));

        // Advance to next info in this modules chain.
        chain = chain->next;
    }
}
#endif

/** Unneeded function but must be defined to compile.
 *
 *  This function appears to be typically used by libgcov.so when instrumented
 *  on a real linux-based system.  It can be used to merge counters across
 *  multiple runs or when a 'fork' occurs.  It doesn't appear that this
 *  function ever gets called for us but the unresolved symbol is added to
 *  the module (by gcc) so we've created a stub here to pass compile.
 */
extern "C"
void __gcov_merge_add()
{
    while(1);
}

#endif
OpenPOWER on IntegriCloud