Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gcc_3_4.c
Go to the documentation of this file.
1 /*
2  * This code provides functions to handle gcc's profiling data format
3  * introduced with gcc 3.4. Future versions of gcc may change the gcov
4  * format (as happened before), so all format-specific information needs
5  * to be kept modular and easily exchangeable.
6  *
7  * This file is based on gcc-internal definitions. Functions and data
8  * structures are defined to be compatible with gcc counterparts.
9  * For a better understanding, refer to gcc source: gcc/gcov-io.h.
10  *
11  * Copyright IBM Corp. 2009
12  * Author(s): Peter Oberparleiter <[email protected]>
13  *
14  * Uses gcc-internal data definitions.
15  */
16 
17 #include <linux/errno.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
20 #include <linux/seq_file.h>
21 #include <linux/vmalloc.h>
22 #include "gcov.h"
23 
24 /* Symbolic links to be created for each profiling data file. */
25 const struct gcov_link gcov_link[] = {
26  { OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */
27  { 0, NULL},
28 };
29 
30 /*
31  * Determine whether a counter is active. Based on gcc magic. Doesn't change
32  * at run-time.
33  */
34 static int counter_active(struct gcov_info *info, unsigned int type)
35 {
36  return (1 << type) & info->ctr_mask;
37 }
38 
39 /* Determine number of active counters. Based on gcc magic. */
40 static unsigned int num_counter_active(struct gcov_info *info)
41 {
42  unsigned int i;
43  unsigned int result = 0;
44 
45  for (i = 0; i < GCOV_COUNTERS; i++) {
46  if (counter_active(info, i))
47  result++;
48  }
49  return result;
50 }
51 
56 void gcov_info_reset(struct gcov_info *info)
57 {
58  unsigned int active = num_counter_active(info);
59  unsigned int i;
60 
61  for (i = 0; i < active; i++) {
62  memset(info->counts[i].values, 0,
63  info->counts[i].num * sizeof(gcov_type));
64  }
65 }
66 
75 {
76  return (info1->stamp == info2->stamp);
77 }
78 
87 {
88  unsigned int i;
89  unsigned int j;
90 
91  for (i = 0; i < num_counter_active(dest); i++) {
92  for (j = 0; j < dest->counts[i].num; j++) {
93  dest->counts[i].values[j] +=
94  source->counts[i].values[j];
95  }
96  }
97 }
98 
99 /* Get size of function info entry. Based on gcc magic. */
100 static size_t get_fn_size(struct gcov_info *info)
101 {
102  size_t size;
103 
104  size = sizeof(struct gcov_fn_info) + num_counter_active(info) *
105  sizeof(unsigned int);
106  if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int))
107  size = ALIGN(size, __alignof__(struct gcov_fn_info));
108  return size;
109 }
110 
111 /* Get address of function info entry. Based on gcc magic. */
112 static struct gcov_fn_info *get_fn_info(struct gcov_info *info, unsigned int fn)
113 {
114  return (struct gcov_fn_info *)
115  ((char *) info->functions + fn * get_fn_size(info));
116 }
117 
124 struct gcov_info *gcov_info_dup(struct gcov_info *info)
125 {
126  struct gcov_info *dup;
127  unsigned int i;
128  unsigned int active;
129 
130  /* Duplicate gcov_info. */
131  active = num_counter_active(info);
132  dup = kzalloc(sizeof(struct gcov_info) +
133  sizeof(struct gcov_ctr_info) * active, GFP_KERNEL);
134  if (!dup)
135  return NULL;
136  dup->version = info->version;
137  dup->stamp = info->stamp;
138  dup->n_functions = info->n_functions;
139  dup->ctr_mask = info->ctr_mask;
140  /* Duplicate filename. */
141  dup->filename = kstrdup(info->filename, GFP_KERNEL);
142  if (!dup->filename)
143  goto err_free;
144  /* Duplicate table of functions. */
145  dup->functions = kmemdup(info->functions, info->n_functions *
146  get_fn_size(info), GFP_KERNEL);
147  if (!dup->functions)
148  goto err_free;
149  /* Duplicate counter arrays. */
150  for (i = 0; i < active ; i++) {
151  struct gcov_ctr_info *ctr = &info->counts[i];
152  size_t size = ctr->num * sizeof(gcov_type);
153 
154  dup->counts[i].num = ctr->num;
155  dup->counts[i].merge = ctr->merge;
156  dup->counts[i].values = vmalloc(size);
157  if (!dup->counts[i].values)
158  goto err_free;
159  memcpy(dup->counts[i].values, ctr->values, size);
160  }
161  return dup;
162 
163 err_free:
164  gcov_info_free(dup);
165  return NULL;
166 }
167 
172 void gcov_info_free(struct gcov_info *info)
173 {
174  unsigned int active = num_counter_active(info);
175  unsigned int i;
176 
177  for (i = 0; i < active ; i++)
178  vfree(info->counts[i].values);
179  kfree(info->functions);
180  kfree(info->filename);
181  kfree(info);
182 }
183 
204 struct type_info {
205  int ctr_type;
206  unsigned int offset;
207 };
208 
220  struct gcov_info *info;
221 
222  int record;
223  unsigned int function;
224  unsigned int type;
225  unsigned int count;
226 
228  struct type_info type_info[0];
229 };
230 
231 static struct gcov_fn_info *get_func(struct gcov_iterator *iter)
232 {
233  return get_fn_info(iter->info, iter->function);
234 }
235 
236 static struct type_info *get_type(struct gcov_iterator *iter)
237 {
238  return &iter->type_info[iter->type];
239 }
240 
247 struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
248 {
249  struct gcov_iterator *iter;
250 
251  iter = kzalloc(sizeof(struct gcov_iterator) +
252  num_counter_active(info) * sizeof(struct type_info),
253  GFP_KERNEL);
254  if (iter)
255  iter->info = info;
256 
257  return iter;
258 }
259 
264 void gcov_iter_free(struct gcov_iterator *iter)
265 {
266  kfree(iter);
267 }
268 
274 {
275  return iter->info;
276 }
277 
282 void gcov_iter_start(struct gcov_iterator *iter)
283 {
284  int i;
285 
286  iter->record = 0;
287  iter->function = 0;
288  iter->type = 0;
289  iter->count = 0;
290  iter->num_types = 0;
291  for (i = 0; i < GCOV_COUNTERS; i++) {
292  if (counter_active(iter->info, i)) {
293  iter->type_info[iter->num_types].ctr_type = i;
294  iter->type_info[iter->num_types++].offset = 0;
295  }
296  }
297 }
298 
299 /* Mapping of logical record number to actual file content. */
300 #define RECORD_FILE_MAGIC 0
301 #define RECORD_GCOV_VERSION 1
302 #define RECORD_TIME_STAMP 2
303 #define RECORD_FUNCTION_TAG 3
304 #define RECORD_FUNCTON_TAG_LEN 4
305 #define RECORD_FUNCTION_IDENT 5
306 #define RECORD_FUNCTION_CHECK 6
307 #define RECORD_COUNT_TAG 7
308 #define RECORD_COUNT_LEN 8
309 #define RECORD_COUNT 9
310 
317 int gcov_iter_next(struct gcov_iterator *iter)
318 {
319  switch (iter->record) {
320  case RECORD_FILE_MAGIC:
321  case RECORD_GCOV_VERSION:
322  case RECORD_FUNCTION_TAG:
325  case RECORD_COUNT_TAG:
326  /* Advance to next record */
327  iter->record++;
328  break;
329  case RECORD_COUNT:
330  /* Advance to next count */
331  iter->count++;
332  /* fall through */
333  case RECORD_COUNT_LEN:
334  if (iter->count < get_func(iter)->n_ctrs[iter->type]) {
335  iter->record = 9;
336  break;
337  }
338  /* Advance to next counter type */
339  get_type(iter)->offset += iter->count;
340  iter->count = 0;
341  iter->type++;
342  /* fall through */
344  if (iter->type < iter->num_types) {
345  iter->record = 7;
346  break;
347  }
348  /* Advance to next function */
349  iter->type = 0;
350  iter->function++;
351  /* fall through */
352  case RECORD_TIME_STAMP:
353  if (iter->function < iter->info->n_functions)
354  iter->record = 3;
355  else
356  iter->record = -1;
357  break;
358  }
359  /* Check for EOF. */
360  if (iter->record == -1)
361  return -EINVAL;
362  else
363  return 0;
364 }
365 
375 static int seq_write_gcov_u32(struct seq_file *seq, u32 v)
376 {
377  return seq_write(seq, &v, sizeof(v));
378 }
379 
390 static int seq_write_gcov_u64(struct seq_file *seq, u64 v)
391 {
392  u32 data[2];
393 
394  data[0] = (v & 0xffffffffUL);
395  data[1] = (v >> 32);
396  return seq_write(seq, data, sizeof(data));
397 }
398 
406 int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
407 {
408  int rc = -EINVAL;
409 
410  switch (iter->record) {
411  case RECORD_FILE_MAGIC:
412  rc = seq_write_gcov_u32(seq, GCOV_DATA_MAGIC);
413  break;
414  case RECORD_GCOV_VERSION:
415  rc = seq_write_gcov_u32(seq, iter->info->version);
416  break;
417  case RECORD_TIME_STAMP:
418  rc = seq_write_gcov_u32(seq, iter->info->stamp);
419  break;
420  case RECORD_FUNCTION_TAG:
421  rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION);
422  break;
424  rc = seq_write_gcov_u32(seq, 2);
425  break;
427  rc = seq_write_gcov_u32(seq, get_func(iter)->ident);
428  break;
430  rc = seq_write_gcov_u32(seq, get_func(iter)->checksum);
431  break;
432  case RECORD_COUNT_TAG:
433  rc = seq_write_gcov_u32(seq,
434  GCOV_TAG_FOR_COUNTER(get_type(iter)->ctr_type));
435  break;
436  case RECORD_COUNT_LEN:
437  rc = seq_write_gcov_u32(seq,
438  get_func(iter)->n_ctrs[iter->type] * 2);
439  break;
440  case RECORD_COUNT:
441  rc = seq_write_gcov_u64(seq,
442  iter->info->counts[iter->type].
443  values[iter->count + get_type(iter)->offset]);
444  break;
445  }
446  return rc;
447 }