Branch data Line data Source code
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/seq_file.h>
19 : : #include <linux/vmalloc.h>
20 : : #include "gcov.h"
21 : :
22 : : #if (__GNUC__ >= 7)
23 : : #define GCOV_COUNTERS 9
24 : : #elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
25 : : #define GCOV_COUNTERS 10
26 : : #elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9
27 : : #define GCOV_COUNTERS 9
28 : : #else
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 : :
97 : : /**
98 : : * gcov_info_filename - return info filename
99 : : * @info: profiling data set
100 : : */
101 : 341515431 : const char *gcov_info_filename(struct gcov_info *info)
102 : : {
103 : 341515431 : return info->filename;
104 : : }
105 : :
106 : : /**
107 : : * gcov_info_version - return info version
108 : : * @info: profiling data set
109 : : */
110 : 207 : unsigned int gcov_info_version(struct gcov_info *info)
111 : : {
112 : 207 : return info->version;
113 : : }
114 : :
115 : : /**
116 : : * gcov_info_next - return next profiling data set
117 : : * @info: profiling data set
118 : : *
119 : : * Returns next gcov_info following @info or first gcov_info in the chain if
120 : : * @info is %NULL.
121 : : */
122 : 345897 : struct gcov_info *gcov_info_next(struct gcov_info *info)
123 : : {
124 [ + + ]: 345897 : if (!info)
125 : 207 : return gcov_info_head;
126 : :
127 : 345690 : return info->next;
128 : : }
129 : :
130 : : /**
131 : : * gcov_info_link - link/add profiling data set to the list
132 : : * @info: profiling data set
133 : : */
134 : 375498 : void gcov_info_link(struct gcov_info *info)
135 : : {
136 : 375498 : info->next = gcov_info_head;
137 : 375498 : gcov_info_head = info;
138 : 375498 : }
139 : :
140 : : /**
141 : : * gcov_info_unlink - unlink/remove profiling data set from the list
142 : : * @prev: previous profiling data set
143 : : * @info: profiling data set
144 : : */
145 : 0 : void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
146 : : {
147 [ # # ]: 0 : if (prev)
148 : 0 : prev->next = info->next;
149 : : else
150 : 0 : gcov_info_head = info->next;
151 : 0 : }
152 : :
153 : : /**
154 : : * gcov_info_within_module - check if a profiling data set belongs to a module
155 : : * @info: profiling data set
156 : : * @mod: module
157 : : *
158 : : * Returns true if profiling data belongs module, false otherwise.
159 : : */
160 : 0 : bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
161 : : {
162 : 0 : return within_module((unsigned long)info, mod);
163 : : }
164 : :
165 : : /* Symbolic links to be created for each profiling data file. */
166 : : const struct gcov_link gcov_link[] = {
167 : : { OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */
168 : : { 0, NULL},
169 : : };
170 : :
171 : : /*
172 : : * Determine whether a counter is active. Doesn't change at run-time.
173 : : */
174 : : static int counter_active(struct gcov_info *info, unsigned int type)
175 : : {
176 : 22641039 : return info->merge[type] ? 1 : 0;
177 : : }
178 : :
179 : : /* Determine number of active counters. Based on gcc magic. */
180 : : static unsigned int num_counter_active(struct gcov_info *info)
181 : : {
182 : : unsigned int i;
183 : : unsigned int result = 0;
184 : :
185 [ + + + + ]: 579393 : for (i = 0; i < GCOV_COUNTERS; i++) {
186 [ + + + + ]: 579393 : if (counter_active(info, i))
187 : 64377 : result++;
188 : : }
189 : 64377 : return result;
190 : : }
191 : :
192 : : /**
193 : : * gcov_info_reset - reset profiling data to zero
194 : : * @info: profiling data set
195 : : */
196 : 0 : void gcov_info_reset(struct gcov_info *info)
197 : : {
198 : : struct gcov_ctr_info *ci_ptr;
199 : : unsigned int fi_idx;
200 : : unsigned int ct_idx;
201 : :
202 [ # # ]: 0 : for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
203 : 0 : ci_ptr = info->functions[fi_idx]->ctrs;
204 : :
205 [ # # ]: 0 : for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
206 [ # # ]: 0 : if (!counter_active(info, ct_idx))
207 : 0 : continue;
208 : :
209 : 0 : memset(ci_ptr->values, 0,
210 : 0 : sizeof(gcov_type) * ci_ptr->num);
211 : 0 : ci_ptr++;
212 : : }
213 : : }
214 : 0 : }
215 : :
216 : : /**
217 : : * gcov_info_is_compatible - check if profiling data can be added
218 : : * @info1: first profiling data set
219 : : * @info2: second profiling data set
220 : : *
221 : : * Returns non-zero if profiling data can be added, zero otherwise.
222 : : */
223 : 0 : int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
224 : : {
225 : 0 : return (info1->stamp == info2->stamp);
226 : : }
227 : :
228 : : /**
229 : : * gcov_info_add - add up profiling data
230 : : * @dest: profiling data set to which data is added
231 : : * @source: profiling data set which is added
232 : : *
233 : : * Adds profiling counts of @source to @dest.
234 : : */
235 : 0 : void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
236 : : {
237 : : struct gcov_ctr_info *dci_ptr;
238 : : struct gcov_ctr_info *sci_ptr;
239 : : unsigned int fi_idx;
240 : : unsigned int ct_idx;
241 : : unsigned int val_idx;
242 : :
243 [ # # ]: 0 : for (fi_idx = 0; fi_idx < src->n_functions; fi_idx++) {
244 : 0 : dci_ptr = dst->functions[fi_idx]->ctrs;
245 : 0 : sci_ptr = src->functions[fi_idx]->ctrs;
246 : :
247 [ # # ]: 0 : for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
248 [ # # ]: 0 : if (!counter_active(src, ct_idx))
249 : 0 : continue;
250 : :
251 [ # # ]: 0 : for (val_idx = 0; val_idx < sci_ptr->num; val_idx++)
252 : 0 : dci_ptr->values[val_idx] +=
253 : 0 : sci_ptr->values[val_idx];
254 : :
255 : 0 : dci_ptr++;
256 : 0 : sci_ptr++;
257 : : }
258 : : }
259 : 0 : }
260 : :
261 : : /**
262 : : * gcov_info_dup - duplicate profiling data set
263 : : * @info: profiling data set to duplicate
264 : : *
265 : : * Return newly allocated duplicate on success, %NULL on error.
266 : : */
267 : 32292 : struct gcov_info *gcov_info_dup(struct gcov_info *info)
268 : : {
269 : : struct gcov_info *dup;
270 : : struct gcov_ctr_info *dci_ptr; /* dst counter info */
271 : : struct gcov_ctr_info *sci_ptr; /* src counter info */
272 : : unsigned int active;
273 : : unsigned int fi_idx; /* function info idx */
274 : : unsigned int ct_idx; /* counter type idx */
275 : : size_t fi_size; /* function info size */
276 : : size_t cv_size; /* counter values size */
277 : :
278 : 32292 : dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
279 [ + - ]: 32292 : if (!dup)
280 : : return NULL;
281 : :
282 : 32292 : dup->next = NULL;
283 : 32292 : dup->filename = NULL;
284 : 32292 : dup->functions = NULL;
285 : :
286 : 32292 : dup->filename = kstrdup(info->filename, GFP_KERNEL);
287 [ + - ]: 32292 : if (!dup->filename)
288 : : goto err_free;
289 : :
290 : 64584 : dup->functions = kcalloc(info->n_functions,
291 : : sizeof(struct gcov_fn_info *), GFP_KERNEL);
292 [ + - ]: 32292 : if (!dup->functions)
293 : : goto err_free;
294 : :
295 : : active = num_counter_active(info);
296 : : fi_size = sizeof(struct gcov_fn_info);
297 : 32292 : fi_size += sizeof(struct gcov_ctr_info) * active;
298 : :
299 [ + + ]: 1259595 : for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
300 : 1227510 : dup->functions[fi_idx] = kzalloc(fi_size, GFP_KERNEL);
301 [ + - ]: 1227510 : if (!dup->functions[fi_idx])
302 : : goto err_free;
303 : :
304 : 1227510 : *(dup->functions[fi_idx]) = *(info->functions[fi_idx]);
305 : :
306 : 1227510 : sci_ptr = info->functions[fi_idx]->ctrs;
307 : 1227510 : dci_ptr = dup->functions[fi_idx]->ctrs;
308 : :
309 [ + + ]: 2454813 : for (ct_idx = 0; ct_idx < active; ct_idx++) {
310 : :
311 : 1227510 : cv_size = sizeof(gcov_type) * sci_ptr->num;
312 : :
313 : 1227510 : dci_ptr->values = vmalloc(cv_size);
314 : :
315 [ + + ]: 1227510 : if (!dci_ptr->values)
316 : : goto err_free;
317 : :
318 : 1227303 : dci_ptr->num = sci_ptr->num;
319 : 1227303 : memcpy(dci_ptr->values, sci_ptr->values, cv_size);
320 : :
321 : 1227303 : sci_ptr++;
322 : 1227303 : dci_ptr++;
323 : : }
324 : : }
325 : :
326 : : return dup;
327 : : err_free:
328 : 207 : gcov_info_free(dup);
329 : 0 : return NULL;
330 : : }
331 : :
332 : : /**
333 : : * gcov_info_free - release memory for profiling data set duplicate
334 : : * @info: profiling data set duplicate to free
335 : : */
336 : 32085 : void gcov_info_free(struct gcov_info *info)
337 : : {
338 : : unsigned int active;
339 : : unsigned int fi_idx;
340 : : unsigned int ct_idx;
341 : : struct gcov_ctr_info *ci_ptr;
342 : :
343 [ + - ]: 32085 : if (!info->functions)
344 : : goto free_info;
345 : :
346 : : active = num_counter_active(info);
347 : :
348 [ + + ]: 1257732 : for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
349 [ - + ]: 1225647 : if (!info->functions[fi_idx])
350 : 0 : continue;
351 : :
352 : 1225647 : ci_ptr = info->functions[fi_idx]->ctrs;
353 : :
354 [ + + ]: 2451294 : for (ct_idx = 0; ct_idx < active; ct_idx++, ci_ptr++)
355 : 1225647 : vfree(ci_ptr->values);
356 : :
357 : 1225647 : kfree(info->functions[fi_idx]);
358 : : }
359 : :
360 : : free_info:
361 : 32085 : kfree(info->functions);
362 : 32085 : kfree(info->filename);
363 : 32085 : kfree(info);
364 : 32085 : }
365 : :
366 : : #define ITER_STRIDE PAGE_SIZE
367 : :
368 : : /**
369 : : * struct gcov_iterator - specifies current file position in logical records
370 : : * @info: associated profiling data
371 : : * @buffer: buffer containing file data
372 : : * @size: size of buffer
373 : : * @pos: current position in file
374 : : */
375 : : struct gcov_iterator {
376 : : struct gcov_info *info;
377 : : void *buffer;
378 : : size_t size;
379 : : loff_t pos;
380 : : };
381 : :
382 : : /**
383 : : * store_gcov_u32 - store 32 bit number in gcov format to buffer
384 : : * @buffer: target buffer or NULL
385 : : * @off: offset into the buffer
386 : : * @v: value to be stored
387 : : *
388 : : * Number format defined by gcc: numbers are recorded in the 32 bit
389 : : * unsigned binary form of the endianness of the machine generating the
390 : : * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't
391 : : * store anything.
392 : : */
393 : : static size_t store_gcov_u32(void *buffer, size_t off, u32 v)
394 : : {
395 : : u32 *data;
396 : :
397 [ + + + + : 17351568 : if (buffer) {
+ + + + +
+ + + + +
+ + + + +
+ ]
398 : 8579529 : data = buffer + off;
399 : 8675784 : *data = v;
400 : : }
401 : :
402 : : return sizeof(*data);
403 : : }
404 : :
405 : : /**
406 : : * store_gcov_u64 - store 64 bit number in gcov format to buffer
407 : : * @buffer: target buffer or NULL
408 : : * @off: offset into the buffer
409 : : * @v: value to be stored
410 : : *
411 : : * Number format defined by gcc: numbers are recorded in the 32 bit
412 : : * unsigned binary form of the endianness of the machine generating the
413 : : * file. 64 bit numbers are stored as two 32 bit numbers, the low part
414 : : * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store
415 : : * anything.
416 : : */
417 : : static size_t store_gcov_u64(void *buffer, size_t off, u64 v)
418 : : {
419 : : u32 *data;
420 : :
421 [ + + ]: 23351670 : if (buffer) {
422 : 11675835 : data = buffer + off;
423 : :
424 : 11675835 : data[0] = (v & 0xffffffffUL);
425 : 11675835 : data[1] = (v >> 32);
426 : : }
427 : :
428 : : return sizeof(*data) * 2;
429 : : }
430 : :
431 : : /**
432 : : * convert_to_gcda - convert profiling data set to gcda file format
433 : : * @buffer: the buffer to store file data or %NULL if no data should be stored
434 : : * @info: profiling data set to be converted
435 : : *
436 : : * Returns the number of bytes that were/would have been stored into the buffer.
437 : : */
438 : 64170 : static size_t convert_to_gcda(char *buffer, struct gcov_info *info)
439 : : {
440 : : struct gcov_fn_info *fi_ptr;
441 : : struct gcov_ctr_info *ci_ptr;
442 : : unsigned int fi_idx;
443 : : unsigned int ct_idx;
444 : : unsigned int cv_idx;
445 : : size_t pos = 0;
446 : :
447 : : /* File header. */
448 : : pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
449 : 64170 : pos += store_gcov_u32(buffer, pos, info->version);
450 : 64170 : pos += store_gcov_u32(buffer, pos, info->stamp);
451 : :
452 [ + + ]: 2451294 : for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
453 : 2451294 : fi_ptr = info->functions[fi_idx];
454 : :
455 : : /* Function record. */
456 : 2451294 : pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
457 : 2451294 : pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH);
458 : 4902588 : pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
459 : 4902588 : pos += store_gcov_u32(buffer, pos, fi_ptr->lineno_checksum);
460 : 4902588 : pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
461 : :
462 : 2451294 : ci_ptr = fi_ptr->ctrs;
463 : :
464 [ + + ]: 24512940 : for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
465 [ + + ]: 22061646 : if (!counter_active(info, ct_idx))
466 : 19610352 : continue;
467 : :
468 : : /* Counter record. */
469 : 4902588 : pos += store_gcov_u32(buffer, pos,
470 : 2451294 : GCOV_TAG_FOR_COUNTER(ct_idx));
471 : 4902588 : pos += store_gcov_u32(buffer, pos, ci_ptr->num * 2);
472 : :
473 [ + + ]: 25802964 : for (cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++) {
474 : 46703340 : pos += store_gcov_u64(buffer, pos,
475 : 23351670 : ci_ptr->values[cv_idx]);
476 : : }
477 : :
478 : 2451294 : ci_ptr++;
479 : : }
480 : : }
481 : :
482 : 64170 : return pos;
483 : : }
484 : :
485 : : /**
486 : : * gcov_iter_new - allocate and initialize profiling data iterator
487 : : * @info: profiling data set to be iterated
488 : : *
489 : : * Return file iterator on success, %NULL otherwise.
490 : : */
491 : 32085 : struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
492 : : {
493 : : struct gcov_iterator *iter;
494 : :
495 : 32085 : iter = kzalloc(sizeof(struct gcov_iterator), GFP_KERNEL);
496 [ + - ]: 32085 : if (!iter)
497 : : goto err_free;
498 : :
499 : 32085 : iter->info = info;
500 : : /* Dry-run to get the actual buffer size. */
501 : 32085 : iter->size = convert_to_gcda(NULL, info);
502 : 32085 : iter->buffer = vmalloc(iter->size);
503 [ + - ]: 32085 : if (!iter->buffer)
504 : : goto err_free;
505 : :
506 : 32085 : convert_to_gcda(iter->buffer, info);
507 : :
508 : 32085 : return iter;
509 : :
510 : : err_free:
511 : 0 : kfree(iter);
512 : 0 : return NULL;
513 : : }
514 : :
515 : :
516 : : /**
517 : : * gcov_iter_get_info - return profiling data set for given file iterator
518 : : * @iter: file iterator
519 : : */
520 : 32085 : void gcov_iter_free(struct gcov_iterator *iter)
521 : : {
522 : 32085 : vfree(iter->buffer);
523 : 32085 : kfree(iter);
524 : 32085 : }
525 : :
526 : : /**
527 : : * gcov_iter_get_info - return profiling data set for given file iterator
528 : : * @iter: file iterator
529 : : */
530 : 32085 : struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
531 : : {
532 : 32085 : return iter->info;
533 : : }
534 : :
535 : : /**
536 : : * gcov_iter_start - reset file iterator to starting position
537 : : * @iter: file iterator
538 : : */
539 : 83214 : void gcov_iter_start(struct gcov_iterator *iter)
540 : : {
541 : 83214 : iter->pos = 0;
542 : 83214 : }
543 : :
544 : : /**
545 : : * gcov_iter_next - advance file iterator to next logical record
546 : : * @iter: file iterator
547 : : *
548 : : * Return zero if new position is valid, non-zero if iterator has reached end.
549 : : */
550 : 120888 : int gcov_iter_next(struct gcov_iterator *iter)
551 : : {
552 [ + - ]: 120888 : if (iter->pos < iter->size)
553 : 120888 : iter->pos += ITER_STRIDE;
554 : :
555 [ + + ]: 120888 : if (iter->pos >= iter->size)
556 : : return -EINVAL;
557 : :
558 : 56718 : return 0;
559 : : }
560 : :
561 : : /**
562 : : * gcov_iter_write - write data for current pos to seq_file
563 : : * @iter: file iterator
564 : : * @seq: seq_file handle
565 : : *
566 : : * Return zero on success, non-zero otherwise.
567 : : */
568 : 70173 : int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
569 : : {
570 : : size_t len;
571 : :
572 [ + - ]: 70173 : if (iter->pos >= iter->size)
573 : : return -EINVAL;
574 : :
575 : : len = ITER_STRIDE;
576 [ + + ]: 70173 : if (iter->pos + len > iter->size)
577 : 32085 : len = iter->size - iter->pos;
578 : :
579 : 70173 : seq_write(seq, iter->buffer + iter->pos, len);
580 : :
581 : 70173 : return 0;
582 : : }
|