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