1 /*
2 * This code provides functions to handle gcc's profiling data format
3 * introduced with gcc 4.7.
4 *
5 * This file is based heavily on gcc_3_4.c file.
6 *
7 * For a better understanding, refer to gcc source:
8 * gcc/gcov-io.h
9 * libgcc/libgcov.c
10 *
11 * Uses gcc-internal data definitions.
12 *
13 * Imported from Linux and modified for Xen by
14 * Wei Liu <wei.liu2@citrix.com>
15 */
16
17 #include <xen/string.h>
18
19 #include "gcov.h"
20
21 /*
22 * GCOV_COUNTERS will be defined if this file is included by other
23 * source files.
24 */
25 #ifndef GCOV_COUNTERS
26 # if !(GCC_VERSION >= 40700 && GCC_VERSION < 40900)
27 # error "Wrong version of GCC used to compile gcov"
28 # endif
29 #define GCOV_COUNTERS 8
30 #endif
31
32 #define GCOV_TAG_FUNCTION_LENGTH 3
33
34 static struct gcov_info *gcov_info_head;
35
36 /**
37 * struct gcov_ctr_info - information about counters for a single function
38 * @num: number of counter values for this type
39 * @values: array of counter values for this type
40 *
41 * This data is generated by gcc during compilation and doesn't change
42 * at run-time with the exception of the values array.
43 */
44 struct gcov_ctr_info {
45 unsigned int num;
46 gcov_type *values;
47 };
48
49 /**
50 * struct gcov_fn_info - profiling meta data per function
51 * @key: comdat key
52 * @ident: unique ident of function
53 * @lineno_checksum: function lineo_checksum
54 * @cfg_checksum: function cfg checksum
55 * @ctrs: instrumented counters
56 *
57 * This data is generated by gcc during compilation and doesn't change
58 * at run-time.
59 *
60 * Information about a single function. This uses the trailing array
61 * idiom. The number of counters is determined from the merge pointer
62 * array in gcov_info. The key is used to detect which of a set of
63 * comdat functions was selected -- it points to the gcov_info object
64 * of the object file containing the selected comdat function.
65 */
66 struct gcov_fn_info {
67 const struct gcov_info *key;
68 unsigned int ident;
69 unsigned int lineno_checksum;
70 unsigned int cfg_checksum;
71 struct gcov_ctr_info ctrs[0];
72 };
73
74 /**
75 * struct gcov_info - profiling data per object file
76 * @version: gcov version magic indicating the gcc version used for compilation
77 * @next: list head for a singly-linked list
78 * @stamp: uniquifying time stamp
79 * @filename: name of the associated gcov data file
80 * @merge: merge functions (null for unused counter type)
81 * @n_functions: number of instrumented functions
82 * @functions: pointer to pointers to function information
83 *
84 * This data is generated by gcc during compilation and doesn't change
85 * at run-time with the exception of the next pointer.
86 */
87 struct gcov_info {
88 unsigned int version;
89 struct gcov_info *next;
90 unsigned int stamp;
91 const char *filename;
92 void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int);
93 unsigned int n_functions;
94 struct gcov_fn_info **functions;
95 };
96
counter_active(const struct gcov_info * info,unsigned int type)97 static int counter_active(const struct gcov_info *info, unsigned int type)
98 {
99 return info->merge[type] ? 1 : 0;
100 }
101
gcov_info_link(struct gcov_info * info)102 void gcov_info_link(struct gcov_info *info)
103 {
104 info->next = gcov_info_head;
105 gcov_info_head = info;
106 }
107
gcov_info_next(const struct gcov_info * info)108 struct gcov_info *gcov_info_next(const struct gcov_info *info)
109 {
110 if ( !info )
111 return gcov_info_head;
112 return info->next;
113 }
114
gcov_info_reset(struct gcov_info * info)115 void gcov_info_reset(struct gcov_info *info)
116 {
117 struct gcov_ctr_info *ci_ptr;
118 unsigned int fi_idx;
119 unsigned int ct_idx;
120
121 for ( fi_idx = 0; fi_idx < info->n_functions; fi_idx++ )
122 {
123 ci_ptr = info->functions[fi_idx]->ctrs;
124
125 for ( ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++ )
126 {
127 if ( !counter_active(info, ct_idx) )
128 continue;
129
130 memset(ci_ptr->values, 0, sizeof(gcov_type) * ci_ptr->num);
131 ci_ptr++;
132 }
133 }
134 }
135
gcov_info_filename(const struct gcov_info * info)136 const char *gcov_info_filename(const struct gcov_info *info)
137 {
138 return info->filename;
139 }
140
141
142 /**
143 * gcov_info_to_gcda - convert profiling data set to gcda file format
144 * @buffer: the buffer to store file data or %NULL if no data should be stored
145 * @info: profiling data set to be converted
146 *
147 * Returns the number of bytes that were/would have been stored into the buffer.
148 */
gcov_info_to_gcda(char * buffer,const struct gcov_info * info)149 size_t gcov_info_to_gcda(char *buffer, const struct gcov_info *info)
150 {
151 struct gcov_fn_info *fi_ptr;
152 struct gcov_ctr_info *ci_ptr;
153 unsigned int fi_idx;
154 unsigned int ct_idx;
155 unsigned int cv_idx;
156 size_t pos = 0;
157
158 /* File header. */
159 pos += gcov_store_uint32(buffer, pos, GCOV_DATA_MAGIC);
160 pos += gcov_store_uint32(buffer, pos, info->version);
161 pos += gcov_store_uint32(buffer, pos, info->stamp);
162
163 for ( fi_idx = 0; fi_idx < info->n_functions; fi_idx++ )
164 {
165 fi_ptr = info->functions[fi_idx];
166
167 /* Function record. */
168 pos += gcov_store_uint32(buffer, pos, GCOV_TAG_FUNCTION);
169 pos += gcov_store_uint32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH);
170 pos += gcov_store_uint32(buffer, pos, fi_ptr->ident);
171 pos += gcov_store_uint32(buffer, pos, fi_ptr->lineno_checksum);
172 pos += gcov_store_uint32(buffer, pos, fi_ptr->cfg_checksum);
173
174 ci_ptr = fi_ptr->ctrs;
175
176 for ( ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++ )
177 {
178 if (! counter_active(info, ct_idx) )
179 continue;
180
181 /* Counter record. */
182 pos += gcov_store_uint32(buffer, pos,
183 GCOV_TAG_FOR_COUNTER(ct_idx));
184 pos += gcov_store_uint32(buffer, pos, ci_ptr->num * 2);
185
186 for ( cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++ )
187 pos += gcov_store_uint64(buffer, pos, ci_ptr->values[cv_idx]);
188
189 ci_ptr++;
190 }
191 }
192
193 return pos;
194 }
195
196 /*
197 * Local variables:
198 * mode: C
199 * c-file-style: "BSD"
200 * c-basic-offset: 4
201 * tab-width: 4
202 * indent-tabs-mode: nil
203 * End:
204 */
205