This source file includes following definitions.
- gcov_info_filename
- gcov_info_version
- gcov_info_next
- gcov_info_link
- gcov_info_unlink
- gcov_info_within_module
- counter_active
- num_counter_active
- gcov_info_reset
- gcov_info_is_compatible
- gcov_info_add
- gcov_info_dup
- gcov_info_free
- store_gcov_u32
- store_gcov_u64
- convert_to_gcda
- gcov_iter_new
- gcov_iter_free
- gcov_iter_get_info
- gcov_iter_start
- gcov_iter_next
- gcov_iter_write
1
2
3
4
5
6
7
8
9
10
11
12
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
38
39
40
41
42
43
44 struct gcov_ctr_info {
45 unsigned int num;
46 gcov_type *values;
47 };
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
76
77
78
79
80
81
82
83
84
85
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
99
100
101 const char *gcov_info_filename(struct gcov_info *info)
102 {
103 return info->filename;
104 }
105
106
107
108
109
110 unsigned int gcov_info_version(struct gcov_info *info)
111 {
112 return info->version;
113 }
114
115
116
117
118
119
120
121
122 struct gcov_info *gcov_info_next(struct gcov_info *info)
123 {
124 if (!info)
125 return gcov_info_head;
126
127 return info->next;
128 }
129
130
131
132
133
134 void gcov_info_link(struct gcov_info *info)
135 {
136 info->next = gcov_info_head;
137 gcov_info_head = info;
138 }
139
140
141
142
143
144
145 void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
146 {
147 if (prev)
148 prev->next = info->next;
149 else
150 gcov_info_head = info->next;
151 }
152
153
154
155
156
157
158
159
160 bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
161 {
162 return within_module((unsigned long)info, mod);
163 }
164
165
166 const struct gcov_link gcov_link[] = {
167 { OBJ_TREE, "gcno" },
168 { 0, NULL},
169 };
170
171
172
173
174 static int counter_active(struct gcov_info *info, unsigned int type)
175 {
176 return info->merge[type] ? 1 : 0;
177 }
178
179
180 static unsigned int num_counter_active(struct gcov_info *info)
181 {
182 unsigned int i;
183 unsigned int result = 0;
184
185 for (i = 0; i < GCOV_COUNTERS; i++) {
186 if (counter_active(info, i))
187 result++;
188 }
189 return result;
190 }
191
192
193
194
195
196 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 for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
203 ci_ptr = info->functions[fi_idx]->ctrs;
204
205 for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
206 if (!counter_active(info, ct_idx))
207 continue;
208
209 memset(ci_ptr->values, 0,
210 sizeof(gcov_type) * ci_ptr->num);
211 ci_ptr++;
212 }
213 }
214 }
215
216
217
218
219
220
221
222
223 int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
224 {
225 return (info1->stamp == info2->stamp);
226 }
227
228
229
230
231
232
233
234
235 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 for (fi_idx = 0; fi_idx < src->n_functions; fi_idx++) {
244 dci_ptr = dst->functions[fi_idx]->ctrs;
245 sci_ptr = src->functions[fi_idx]->ctrs;
246
247 for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
248 if (!counter_active(src, ct_idx))
249 continue;
250
251 for (val_idx = 0; val_idx < sci_ptr->num; val_idx++)
252 dci_ptr->values[val_idx] +=
253 sci_ptr->values[val_idx];
254
255 dci_ptr++;
256 sci_ptr++;
257 }
258 }
259 }
260
261
262
263
264
265
266
267 struct gcov_info *gcov_info_dup(struct gcov_info *info)
268 {
269 struct gcov_info *dup;
270 struct gcov_ctr_info *dci_ptr;
271 struct gcov_ctr_info *sci_ptr;
272 unsigned int active;
273 unsigned int fi_idx;
274 unsigned int ct_idx;
275 size_t fi_size;
276 size_t cv_size;
277
278 dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
279 if (!dup)
280 return NULL;
281
282 dup->next = NULL;
283 dup->filename = NULL;
284 dup->functions = NULL;
285
286 dup->filename = kstrdup(info->filename, GFP_KERNEL);
287 if (!dup->filename)
288 goto err_free;
289
290 dup->functions = kcalloc(info->n_functions,
291 sizeof(struct gcov_fn_info *), GFP_KERNEL);
292 if (!dup->functions)
293 goto err_free;
294
295 active = num_counter_active(info);
296 fi_size = sizeof(struct gcov_fn_info);
297 fi_size += sizeof(struct gcov_ctr_info) * active;
298
299 for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
300 dup->functions[fi_idx] = kzalloc(fi_size, GFP_KERNEL);
301 if (!dup->functions[fi_idx])
302 goto err_free;
303
304 *(dup->functions[fi_idx]) = *(info->functions[fi_idx]);
305
306 sci_ptr = info->functions[fi_idx]->ctrs;
307 dci_ptr = dup->functions[fi_idx]->ctrs;
308
309 for (ct_idx = 0; ct_idx < active; ct_idx++) {
310
311 cv_size = sizeof(gcov_type) * sci_ptr->num;
312
313 dci_ptr->values = vmalloc(cv_size);
314
315 if (!dci_ptr->values)
316 goto err_free;
317
318 dci_ptr->num = sci_ptr->num;
319 memcpy(dci_ptr->values, sci_ptr->values, cv_size);
320
321 sci_ptr++;
322 dci_ptr++;
323 }
324 }
325
326 return dup;
327 err_free:
328 gcov_info_free(dup);
329 return NULL;
330 }
331
332
333
334
335
336 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 if (!info->functions)
344 goto free_info;
345
346 active = num_counter_active(info);
347
348 for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
349 if (!info->functions[fi_idx])
350 continue;
351
352 ci_ptr = info->functions[fi_idx]->ctrs;
353
354 for (ct_idx = 0; ct_idx < active; ct_idx++, ci_ptr++)
355 vfree(ci_ptr->values);
356
357 kfree(info->functions[fi_idx]);
358 }
359
360 free_info:
361 kfree(info->functions);
362 kfree(info->filename);
363 kfree(info);
364 }
365
366 #define ITER_STRIDE PAGE_SIZE
367
368
369
370
371
372
373
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
384
385
386
387
388
389
390
391
392
393 static size_t store_gcov_u32(void *buffer, size_t off, u32 v)
394 {
395 u32 *data;
396
397 if (buffer) {
398 data = buffer + off;
399 *data = v;
400 }
401
402 return sizeof(*data);
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416
417 static size_t store_gcov_u64(void *buffer, size_t off, u64 v)
418 {
419 u32 *data;
420
421 if (buffer) {
422 data = buffer + off;
423
424 data[0] = (v & 0xffffffffUL);
425 data[1] = (v >> 32);
426 }
427
428 return sizeof(*data) * 2;
429 }
430
431
432
433
434
435
436
437
438 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
448 pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
449 pos += store_gcov_u32(buffer, pos, info->version);
450 pos += store_gcov_u32(buffer, pos, info->stamp);
451
452 for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
453 fi_ptr = info->functions[fi_idx];
454
455
456 pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
457 pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH);
458 pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
459 pos += store_gcov_u32(buffer, pos, fi_ptr->lineno_checksum);
460 pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
461
462 ci_ptr = fi_ptr->ctrs;
463
464 for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
465 if (!counter_active(info, ct_idx))
466 continue;
467
468
469 pos += store_gcov_u32(buffer, pos,
470 GCOV_TAG_FOR_COUNTER(ct_idx));
471 pos += store_gcov_u32(buffer, pos, ci_ptr->num * 2);
472
473 for (cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++) {
474 pos += store_gcov_u64(buffer, pos,
475 ci_ptr->values[cv_idx]);
476 }
477
478 ci_ptr++;
479 }
480 }
481
482 return pos;
483 }
484
485
486
487
488
489
490
491 struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
492 {
493 struct gcov_iterator *iter;
494
495 iter = kzalloc(sizeof(struct gcov_iterator), GFP_KERNEL);
496 if (!iter)
497 goto err_free;
498
499 iter->info = info;
500
501 iter->size = convert_to_gcda(NULL, info);
502 iter->buffer = vmalloc(iter->size);
503 if (!iter->buffer)
504 goto err_free;
505
506 convert_to_gcda(iter->buffer, info);
507
508 return iter;
509
510 err_free:
511 kfree(iter);
512 return NULL;
513 }
514
515
516
517
518
519
520 void gcov_iter_free(struct gcov_iterator *iter)
521 {
522 vfree(iter->buffer);
523 kfree(iter);
524 }
525
526
527
528
529
530 struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
531 {
532 return iter->info;
533 }
534
535
536
537
538
539 void gcov_iter_start(struct gcov_iterator *iter)
540 {
541 iter->pos = 0;
542 }
543
544
545
546
547
548
549
550 int gcov_iter_next(struct gcov_iterator *iter)
551 {
552 if (iter->pos < iter->size)
553 iter->pos += ITER_STRIDE;
554
555 if (iter->pos >= iter->size)
556 return -EINVAL;
557
558 return 0;
559 }
560
561
562
563
564
565
566
567
568 int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
569 {
570 size_t len;
571
572 if (iter->pos >= iter->size)
573 return -EINVAL;
574
575 len = ITER_STRIDE;
576 if (iter->pos + len > iter->size)
577 len = iter->size - iter->pos;
578
579 seq_write(seq, iter->buffer + iter->pos, len);
580
581 return 0;
582 }