Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *  This code provides functions to handle gcc's profiling data format
  4 *  introduced with gcc 4.7.
  5 *
  6 *  This file is based heavily on gcc_3_4.c file.
  7 *
  8 *  For a better understanding, refer to gcc source:
  9 *  gcc/gcov-io.h
 10 *  libgcc/libgcov.c
 11 *
 12 *  Uses gcc-internal data definitions.
 13 */
 14
 15#include <linux/errno.h>
 16#include <linux/slab.h>
 17#include <linux/string.h>
 18#include <linux/mm.h>
 19#include "gcov.h"
 20
 21#if (__GNUC__ >= 14)
 22#define GCOV_COUNTERS			9
 23#elif (__GNUC__ >= 10)
 24#define GCOV_COUNTERS			8
 25#elif (__GNUC__ >= 7)
 26#define GCOV_COUNTERS			9
 27#elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
 28#define GCOV_COUNTERS			10
 29#else
 30#define GCOV_COUNTERS			9
 31#endif
 32
 33#define GCOV_TAG_FUNCTION_LENGTH	3
 34
 35/* Since GCC 12.1 sizes are in BYTES and not in WORDS (4B). */
 36#if (__GNUC__ >= 12)
 37#define GCOV_UNIT_SIZE				4
 38#else
 39#define GCOV_UNIT_SIZE				1
 40#endif
 41
 42static struct gcov_info *gcov_info_head;
 43
 44/**
 45 * struct gcov_ctr_info - information about counters for a single function
 46 * @num: number of counter values for this type
 47 * @values: array of counter values for this type
 48 *
 49 * This data is generated by gcc during compilation and doesn't change
 50 * at run-time with the exception of the values array.
 51 */
 52struct gcov_ctr_info {
 53	unsigned int num;
 54	gcov_type *values;
 55};
 56
 57/**
 58 * struct gcov_fn_info - profiling meta data per function
 59 * @key: comdat key
 60 * @ident: unique ident of function
 61 * @lineno_checksum: function lineo_checksum
 62 * @cfg_checksum: function cfg checksum
 63 * @ctrs: instrumented counters
 64 *
 65 * This data is generated by gcc during compilation and doesn't change
 66 * at run-time.
 67 *
 68 * Information about a single function.  This uses the trailing array
 69 * idiom. The number of counters is determined from the merge pointer
 70 * array in gcov_info.  The key is used to detect which of a set of
 71 * comdat functions was selected -- it points to the gcov_info object
 72 * of the object file containing the selected comdat function.
 73 */
 74struct gcov_fn_info {
 75	const struct gcov_info *key;
 76	unsigned int ident;
 77	unsigned int lineno_checksum;
 78	unsigned int cfg_checksum;
 79	struct gcov_ctr_info ctrs[];
 80};
 81
 82/**
 83 * struct gcov_info - profiling data per object file
 84 * @version: gcov version magic indicating the gcc version used for compilation
 85 * @next: list head for a singly-linked list
 86 * @stamp: uniquifying time stamp
 87 * @checksum: unique object checksum
 88 * @filename: name of the associated gcov data file
 89 * @merge: merge functions (null for unused counter type)
 90 * @n_functions: number of instrumented functions
 91 * @functions: pointer to pointers to function information
 92 *
 93 * This data is generated by gcc during compilation and doesn't change
 94 * at run-time with the exception of the next pointer.
 95 */
 96struct gcov_info {
 97	unsigned int version;
 98	struct gcov_info *next;
 99	unsigned int stamp;
100 /* Since GCC 12.1 a checksum field is added. */
101#if (__GNUC__ >= 12)
102	unsigned int checksum;
103#endif
104	const char *filename;
105	void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int);
106	unsigned int n_functions;
107	struct gcov_fn_info **functions;
108};
109
110/**
111 * gcov_info_filename - return info filename
112 * @info: profiling data set
113 */
114const char *gcov_info_filename(struct gcov_info *info)
115{
116	return info->filename;
117}
118
119/**
120 * gcov_info_version - return info version
121 * @info: profiling data set
122 */
123unsigned int gcov_info_version(struct gcov_info *info)
124{
125	return info->version;
126}
127
128/**
129 * gcov_info_next - return next profiling data set
130 * @info: profiling data set
131 *
132 * Returns next gcov_info following @info or first gcov_info in the chain if
133 * @info is %NULL.
134 */
135struct gcov_info *gcov_info_next(struct gcov_info *info)
136{
137	if (!info)
138		return gcov_info_head;
139
140	return info->next;
141}
142
143/**
144 * gcov_info_link - link/add profiling data set to the list
145 * @info: profiling data set
146 */
147void gcov_info_link(struct gcov_info *info)
148{
149	info->next = gcov_info_head;
150	gcov_info_head = info;
151}
152
153/**
154 * gcov_info_unlink - unlink/remove profiling data set from the list
155 * @prev: previous profiling data set
156 * @info: profiling data set
157 */
158void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
159{
160	if (prev)
161		prev->next = info->next;
162	else
163		gcov_info_head = info->next;
164}
165
166/**
167 * gcov_info_within_module - check if a profiling data set belongs to a module
168 * @info: profiling data set
169 * @mod: module
170 *
171 * Returns true if profiling data belongs module, false otherwise.
172 */
173bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
174{
175	return within_module((unsigned long)info, mod);
176}
177
178/* Symbolic links to be created for each profiling data file. */
179const struct gcov_link gcov_link[] = {
180	{ OBJ_TREE, "gcno" },	/* Link to .gcno file in $(objtree). */
181	{ 0, NULL},
182};
183
184/*
185 * Determine whether a counter is active. Doesn't change at run-time.
186 */
187static int counter_active(struct gcov_info *info, unsigned int type)
188{
189	return info->merge[type] ? 1 : 0;
190}
191
192/* Determine number of active counters. Based on gcc magic. */
193static unsigned int num_counter_active(struct gcov_info *info)
194{
195	unsigned int i;
196	unsigned int result = 0;
197
198	for (i = 0; i < GCOV_COUNTERS; i++) {
199		if (counter_active(info, i))
200			result++;
201	}
202	return result;
203}
204
205/**
206 * gcov_info_reset - reset profiling data to zero
207 * @info: profiling data set
208 */
209void gcov_info_reset(struct gcov_info *info)
210{
211	struct gcov_ctr_info *ci_ptr;
212	unsigned int fi_idx;
213	unsigned int ct_idx;
214
215	for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
216		ci_ptr = info->functions[fi_idx]->ctrs;
217
218		for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
219			if (!counter_active(info, ct_idx))
220				continue;
221
222			memset(ci_ptr->values, 0,
223					sizeof(gcov_type) * ci_ptr->num);
224			ci_ptr++;
225		}
226	}
227}
228
229/**
230 * gcov_info_is_compatible - check if profiling data can be added
231 * @info1: first profiling data set
232 * @info2: second profiling data set
233 *
234 * Returns non-zero if profiling data can be added, zero otherwise.
235 */
236int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
237{
238	return (info1->stamp == info2->stamp);
239}
240
241/**
242 * gcov_info_add - add up profiling data
243 * @dst: profiling data set to which data is added
244 * @src: profiling data set which is added
245 *
246 * Adds profiling counts of @src to @dst.
247 */
248void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
249{
250	struct gcov_ctr_info *dci_ptr;
251	struct gcov_ctr_info *sci_ptr;
252	unsigned int fi_idx;
253	unsigned int ct_idx;
254	unsigned int val_idx;
255
256	for (fi_idx = 0; fi_idx < src->n_functions; fi_idx++) {
257		dci_ptr = dst->functions[fi_idx]->ctrs;
258		sci_ptr = src->functions[fi_idx]->ctrs;
259
260		for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
261			if (!counter_active(src, ct_idx))
262				continue;
263
264			for (val_idx = 0; val_idx < sci_ptr->num; val_idx++)
265				dci_ptr->values[val_idx] +=
266					sci_ptr->values[val_idx];
267
268			dci_ptr++;
269			sci_ptr++;
270		}
271	}
272}
273
274/**
275 * gcov_info_dup - duplicate profiling data set
276 * @info: profiling data set to duplicate
277 *
278 * Return newly allocated duplicate on success, %NULL on error.
279 */
280struct gcov_info *gcov_info_dup(struct gcov_info *info)
281{
282	struct gcov_info *dup;
283	struct gcov_ctr_info *dci_ptr; /* dst counter info */
284	struct gcov_ctr_info *sci_ptr; /* src counter info */
285	unsigned int active;
286	unsigned int fi_idx; /* function info idx */
287	unsigned int ct_idx; /* counter type idx */
288	size_t fi_size; /* function info size */
289	size_t cv_size; /* counter values size */
290
291	dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
292	if (!dup)
293		return NULL;
294
295	dup->next = NULL;
296	dup->filename = NULL;
297	dup->functions = NULL;
298
299	dup->filename = kstrdup(info->filename, GFP_KERNEL);
300	if (!dup->filename)
301		goto err_free;
302
303	dup->functions = kcalloc(info->n_functions,
304				 sizeof(struct gcov_fn_info *), GFP_KERNEL);
305	if (!dup->functions)
306		goto err_free;
307
308	active = num_counter_active(info);
309	fi_size = sizeof(struct gcov_fn_info);
310	fi_size += sizeof(struct gcov_ctr_info) * active;
311
312	for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
313		dup->functions[fi_idx] = kzalloc(fi_size, GFP_KERNEL);
314		if (!dup->functions[fi_idx])
315			goto err_free;
316
317		*(dup->functions[fi_idx]) = *(info->functions[fi_idx]);
318
319		sci_ptr = info->functions[fi_idx]->ctrs;
320		dci_ptr = dup->functions[fi_idx]->ctrs;
321
322		for (ct_idx = 0; ct_idx < active; ct_idx++) {
323
324			cv_size = sizeof(gcov_type) * sci_ptr->num;
325
326			dci_ptr->values = kvmalloc(cv_size, GFP_KERNEL);
327
328			if (!dci_ptr->values)
329				goto err_free;
330
331			dci_ptr->num = sci_ptr->num;
332			memcpy(dci_ptr->values, sci_ptr->values, cv_size);
333
334			sci_ptr++;
335			dci_ptr++;
336		}
337	}
338
339	return dup;
340err_free:
341	gcov_info_free(dup);
342	return NULL;
343}
344
345/**
346 * gcov_info_free - release memory for profiling data set duplicate
347 * @info: profiling data set duplicate to free
348 */
349void gcov_info_free(struct gcov_info *info)
350{
351	unsigned int active;
352	unsigned int fi_idx;
353	unsigned int ct_idx;
354	struct gcov_ctr_info *ci_ptr;
355
356	if (!info->functions)
357		goto free_info;
358
359	active = num_counter_active(info);
360
361	for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
362		if (!info->functions[fi_idx])
363			continue;
364
365		ci_ptr = info->functions[fi_idx]->ctrs;
366
367		for (ct_idx = 0; ct_idx < active; ct_idx++, ci_ptr++)
368			kvfree(ci_ptr->values);
369
370		kfree(info->functions[fi_idx]);
371	}
372
373free_info:
374	kfree(info->functions);
375	kfree(info->filename);
376	kfree(info);
377}
378
379/**
380 * convert_to_gcda - convert profiling data set to gcda file format
381 * @buffer: the buffer to store file data or %NULL if no data should be stored
382 * @info: profiling data set to be converted
383 *
384 * Returns the number of bytes that were/would have been stored into the buffer.
385 */
386size_t convert_to_gcda(char *buffer, struct gcov_info *info)
387{
388	struct gcov_fn_info *fi_ptr;
389	struct gcov_ctr_info *ci_ptr;
390	unsigned int fi_idx;
391	unsigned int ct_idx;
392	unsigned int cv_idx;
393	size_t pos = 0;
394
395	/* File header. */
396	pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
397	pos += store_gcov_u32(buffer, pos, info->version);
398	pos += store_gcov_u32(buffer, pos, info->stamp);
399
400#if (__GNUC__ >= 12)
401	/* Use zero as checksum of the compilation unit. */
402	pos += store_gcov_u32(buffer, pos, 0);
403#endif
404
405	for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
406		fi_ptr = info->functions[fi_idx];
407
408		/* Function record. */
409		pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
410		pos += store_gcov_u32(buffer, pos,
411			GCOV_TAG_FUNCTION_LENGTH * GCOV_UNIT_SIZE);
412		pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
413		pos += store_gcov_u32(buffer, pos, fi_ptr->lineno_checksum);
414		pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
415
416		ci_ptr = fi_ptr->ctrs;
417
418		for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
419			if (!counter_active(info, ct_idx))
420				continue;
421
422			/* Counter record. */
423			pos += store_gcov_u32(buffer, pos,
424					      GCOV_TAG_FOR_COUNTER(ct_idx));
425			pos += store_gcov_u32(buffer, pos,
426				ci_ptr->num * 2 * GCOV_UNIT_SIZE);
427
428			for (cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++) {
429				pos += store_gcov_u64(buffer, pos,
430						      ci_ptr->values[cv_idx]);
431			}
432
433			ci_ptr++;
434		}
435	}
436
437	return pos;
438}
v5.14.15
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *  This code provides functions to handle gcc's profiling data format
  4 *  introduced with gcc 4.7.
  5 *
  6 *  This file is based heavily on gcc_3_4.c file.
  7 *
  8 *  For a better understanding, refer to gcc source:
  9 *  gcc/gcov-io.h
 10 *  libgcc/libgcov.c
 11 *
 12 *  Uses gcc-internal data definitions.
 13 */
 14
 15#include <linux/errno.h>
 16#include <linux/slab.h>
 17#include <linux/string.h>
 18#include <linux/mm.h>
 19#include "gcov.h"
 20
 21#if (__GNUC__ >= 10)
 
 
 22#define GCOV_COUNTERS			8
 23#elif (__GNUC__ >= 7)
 24#define GCOV_COUNTERS			9
 25#elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
 26#define GCOV_COUNTERS			10
 27#else
 28#define GCOV_COUNTERS			9
 29#endif
 30
 31#define GCOV_TAG_FUNCTION_LENGTH	3
 32
 
 
 
 
 
 
 
 33static struct gcov_info *gcov_info_head;
 34
 35/**
 36 * struct gcov_ctr_info - information about counters for a single function
 37 * @num: number of counter values for this type
 38 * @values: array of counter values for this type
 39 *
 40 * This data is generated by gcc during compilation and doesn't change
 41 * at run-time with the exception of the values array.
 42 */
 43struct gcov_ctr_info {
 44	unsigned int num;
 45	gcov_type *values;
 46};
 47
 48/**
 49 * struct gcov_fn_info - profiling meta data per function
 50 * @key: comdat key
 51 * @ident: unique ident of function
 52 * @lineno_checksum: function lineo_checksum
 53 * @cfg_checksum: function cfg checksum
 54 * @ctrs: instrumented counters
 55 *
 56 * This data is generated by gcc during compilation and doesn't change
 57 * at run-time.
 58 *
 59 * Information about a single function.  This uses the trailing array
 60 * idiom. The number of counters is determined from the merge pointer
 61 * array in gcov_info.  The key is used to detect which of a set of
 62 * comdat functions was selected -- it points to the gcov_info object
 63 * of the object file containing the selected comdat function.
 64 */
 65struct gcov_fn_info {
 66	const struct gcov_info *key;
 67	unsigned int ident;
 68	unsigned int lineno_checksum;
 69	unsigned int cfg_checksum;
 70	struct gcov_ctr_info ctrs[];
 71};
 72
 73/**
 74 * struct gcov_info - profiling data per object file
 75 * @version: gcov version magic indicating the gcc version used for compilation
 76 * @next: list head for a singly-linked list
 77 * @stamp: uniquifying time stamp
 
 78 * @filename: name of the associated gcov data file
 79 * @merge: merge functions (null for unused counter type)
 80 * @n_functions: number of instrumented functions
 81 * @functions: pointer to pointers to function information
 82 *
 83 * This data is generated by gcc during compilation and doesn't change
 84 * at run-time with the exception of the next pointer.
 85 */
 86struct gcov_info {
 87	unsigned int version;
 88	struct gcov_info *next;
 89	unsigned int stamp;
 
 
 
 
 90	const char *filename;
 91	void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int);
 92	unsigned int n_functions;
 93	struct gcov_fn_info **functions;
 94};
 95
 96/**
 97 * gcov_info_filename - return info filename
 98 * @info: profiling data set
 99 */
100const char *gcov_info_filename(struct gcov_info *info)
101{
102	return info->filename;
103}
104
105/**
106 * gcov_info_version - return info version
107 * @info: profiling data set
108 */
109unsigned int gcov_info_version(struct gcov_info *info)
110{
111	return info->version;
112}
113
114/**
115 * gcov_info_next - return next profiling data set
116 * @info: profiling data set
117 *
118 * Returns next gcov_info following @info or first gcov_info in the chain if
119 * @info is %NULL.
120 */
121struct gcov_info *gcov_info_next(struct gcov_info *info)
122{
123	if (!info)
124		return gcov_info_head;
125
126	return info->next;
127}
128
129/**
130 * gcov_info_link - link/add profiling data set to the list
131 * @info: profiling data set
132 */
133void gcov_info_link(struct gcov_info *info)
134{
135	info->next = gcov_info_head;
136	gcov_info_head = info;
137}
138
139/**
140 * gcov_info_unlink - unlink/remove profiling data set from the list
141 * @prev: previous profiling data set
142 * @info: profiling data set
143 */
144void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
145{
146	if (prev)
147		prev->next = info->next;
148	else
149		gcov_info_head = info->next;
150}
151
152/**
153 * gcov_info_within_module - check if a profiling data set belongs to a module
154 * @info: profiling data set
155 * @mod: module
156 *
157 * Returns true if profiling data belongs module, false otherwise.
158 */
159bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
160{
161	return within_module((unsigned long)info, mod);
162}
163
164/* Symbolic links to be created for each profiling data file. */
165const struct gcov_link gcov_link[] = {
166	{ OBJ_TREE, "gcno" },	/* Link to .gcno file in $(objtree). */
167	{ 0, NULL},
168};
169
170/*
171 * Determine whether a counter is active. Doesn't change at run-time.
172 */
173static int counter_active(struct gcov_info *info, unsigned int type)
174{
175	return info->merge[type] ? 1 : 0;
176}
177
178/* Determine number of active counters. Based on gcc magic. */
179static unsigned int num_counter_active(struct gcov_info *info)
180{
181	unsigned int i;
182	unsigned int result = 0;
183
184	for (i = 0; i < GCOV_COUNTERS; i++) {
185		if (counter_active(info, i))
186			result++;
187	}
188	return result;
189}
190
191/**
192 * gcov_info_reset - reset profiling data to zero
193 * @info: profiling data set
194 */
195void gcov_info_reset(struct gcov_info *info)
196{
197	struct gcov_ctr_info *ci_ptr;
198	unsigned int fi_idx;
199	unsigned int ct_idx;
200
201	for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
202		ci_ptr = info->functions[fi_idx]->ctrs;
203
204		for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
205			if (!counter_active(info, ct_idx))
206				continue;
207
208			memset(ci_ptr->values, 0,
209					sizeof(gcov_type) * ci_ptr->num);
210			ci_ptr++;
211		}
212	}
213}
214
215/**
216 * gcov_info_is_compatible - check if profiling data can be added
217 * @info1: first profiling data set
218 * @info2: second profiling data set
219 *
220 * Returns non-zero if profiling data can be added, zero otherwise.
221 */
222int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
223{
224	return (info1->stamp == info2->stamp);
225}
226
227/**
228 * gcov_info_add - add up profiling data
229 * @dst: profiling data set to which data is added
230 * @src: profiling data set which is added
231 *
232 * Adds profiling counts of @src to @dst.
233 */
234void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
235{
236	struct gcov_ctr_info *dci_ptr;
237	struct gcov_ctr_info *sci_ptr;
238	unsigned int fi_idx;
239	unsigned int ct_idx;
240	unsigned int val_idx;
241
242	for (fi_idx = 0; fi_idx < src->n_functions; fi_idx++) {
243		dci_ptr = dst->functions[fi_idx]->ctrs;
244		sci_ptr = src->functions[fi_idx]->ctrs;
245
246		for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
247			if (!counter_active(src, ct_idx))
248				continue;
249
250			for (val_idx = 0; val_idx < sci_ptr->num; val_idx++)
251				dci_ptr->values[val_idx] +=
252					sci_ptr->values[val_idx];
253
254			dci_ptr++;
255			sci_ptr++;
256		}
257	}
258}
259
260/**
261 * gcov_info_dup - duplicate profiling data set
262 * @info: profiling data set to duplicate
263 *
264 * Return newly allocated duplicate on success, %NULL on error.
265 */
266struct gcov_info *gcov_info_dup(struct gcov_info *info)
267{
268	struct gcov_info *dup;
269	struct gcov_ctr_info *dci_ptr; /* dst counter info */
270	struct gcov_ctr_info *sci_ptr; /* src counter info */
271	unsigned int active;
272	unsigned int fi_idx; /* function info idx */
273	unsigned int ct_idx; /* counter type idx */
274	size_t fi_size; /* function info size */
275	size_t cv_size; /* counter values size */
276
277	dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
278	if (!dup)
279		return NULL;
280
281	dup->next = NULL;
282	dup->filename = NULL;
283	dup->functions = NULL;
284
285	dup->filename = kstrdup(info->filename, GFP_KERNEL);
286	if (!dup->filename)
287		goto err_free;
288
289	dup->functions = kcalloc(info->n_functions,
290				 sizeof(struct gcov_fn_info *), GFP_KERNEL);
291	if (!dup->functions)
292		goto err_free;
293
294	active = num_counter_active(info);
295	fi_size = sizeof(struct gcov_fn_info);
296	fi_size += sizeof(struct gcov_ctr_info) * active;
297
298	for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
299		dup->functions[fi_idx] = kzalloc(fi_size, GFP_KERNEL);
300		if (!dup->functions[fi_idx])
301			goto err_free;
302
303		*(dup->functions[fi_idx]) = *(info->functions[fi_idx]);
304
305		sci_ptr = info->functions[fi_idx]->ctrs;
306		dci_ptr = dup->functions[fi_idx]->ctrs;
307
308		for (ct_idx = 0; ct_idx < active; ct_idx++) {
309
310			cv_size = sizeof(gcov_type) * sci_ptr->num;
311
312			dci_ptr->values = kvmalloc(cv_size, GFP_KERNEL);
313
314			if (!dci_ptr->values)
315				goto err_free;
316
317			dci_ptr->num = sci_ptr->num;
318			memcpy(dci_ptr->values, sci_ptr->values, cv_size);
319
320			sci_ptr++;
321			dci_ptr++;
322		}
323	}
324
325	return dup;
326err_free:
327	gcov_info_free(dup);
328	return NULL;
329}
330
331/**
332 * gcov_info_free - release memory for profiling data set duplicate
333 * @info: profiling data set duplicate to free
334 */
335void gcov_info_free(struct gcov_info *info)
336{
337	unsigned int active;
338	unsigned int fi_idx;
339	unsigned int ct_idx;
340	struct gcov_ctr_info *ci_ptr;
341
342	if (!info->functions)
343		goto free_info;
344
345	active = num_counter_active(info);
346
347	for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
348		if (!info->functions[fi_idx])
349			continue;
350
351		ci_ptr = info->functions[fi_idx]->ctrs;
352
353		for (ct_idx = 0; ct_idx < active; ct_idx++, ci_ptr++)
354			kvfree(ci_ptr->values);
355
356		kfree(info->functions[fi_idx]);
357	}
358
359free_info:
360	kfree(info->functions);
361	kfree(info->filename);
362	kfree(info);
363}
364
365/**
366 * convert_to_gcda - convert profiling data set to gcda file format
367 * @buffer: the buffer to store file data or %NULL if no data should be stored
368 * @info: profiling data set to be converted
369 *
370 * Returns the number of bytes that were/would have been stored into the buffer.
371 */
372size_t convert_to_gcda(char *buffer, struct gcov_info *info)
373{
374	struct gcov_fn_info *fi_ptr;
375	struct gcov_ctr_info *ci_ptr;
376	unsigned int fi_idx;
377	unsigned int ct_idx;
378	unsigned int cv_idx;
379	size_t pos = 0;
380
381	/* File header. */
382	pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
383	pos += store_gcov_u32(buffer, pos, info->version);
384	pos += store_gcov_u32(buffer, pos, info->stamp);
385
 
 
 
 
 
386	for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
387		fi_ptr = info->functions[fi_idx];
388
389		/* Function record. */
390		pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
391		pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH);
 
392		pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
393		pos += store_gcov_u32(buffer, pos, fi_ptr->lineno_checksum);
394		pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
395
396		ci_ptr = fi_ptr->ctrs;
397
398		for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
399			if (!counter_active(info, ct_idx))
400				continue;
401
402			/* Counter record. */
403			pos += store_gcov_u32(buffer, pos,
404					      GCOV_TAG_FOR_COUNTER(ct_idx));
405			pos += store_gcov_u32(buffer, pos, ci_ptr->num * 2);
 
406
407			for (cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++) {
408				pos += store_gcov_u64(buffer, pos,
409						      ci_ptr->values[cv_idx]);
410			}
411
412			ci_ptr++;
413		}
414	}
415
416	return pos;
417}