x86, quirk: Fix SB600 revision check
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / kernel / gcov / gcc_3_4.c
blobae5bb42600335d23ca4336cbead99a79be9bbf60
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.
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.
11 * Copyright IBM Corp. 2009
12 * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
14 * Uses gcc-internal data definitions.
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"
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},
31 * Determine whether a counter is active. Based on gcc magic. Doesn't change
32 * at run-time.
34 static int counter_active(struct gcov_info *info, unsigned int type)
36 return (1 << type) & info->ctr_mask;
39 /* Determine number of active counters. Based on gcc magic. */
40 static unsigned int num_counter_active(struct gcov_info *info)
42 unsigned int i;
43 unsigned int result = 0;
45 for (i = 0; i < GCOV_COUNTERS; i++) {
46 if (counter_active(info, i))
47 result++;
49 return result;
52 /**
53 * gcov_info_reset - reset profiling data to zero
54 * @info: profiling data set
56 void gcov_info_reset(struct gcov_info *info)
58 unsigned int active = num_counter_active(info);
59 unsigned int i;
61 for (i = 0; i < active; i++) {
62 memset(info->counts[i].values, 0,
63 info->counts[i].num * sizeof(gcov_type));
67 /**
68 * gcov_info_is_compatible - check if profiling data can be added
69 * @info1: first profiling data set
70 * @info2: second profiling data set
72 * Returns non-zero if profiling data can be added, zero otherwise.
74 int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
76 return (info1->stamp == info2->stamp);
79 /**
80 * gcov_info_add - add up profiling data
81 * @dest: profiling data set to which data is added
82 * @source: profiling data set which is added
84 * Adds profiling counts of @source to @dest.
86 void gcov_info_add(struct gcov_info *dest, struct gcov_info *source)
88 unsigned int i;
89 unsigned int j;
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];
99 /* Get size of function info entry. Based on gcc magic. */
100 static size_t get_fn_size(struct gcov_info *info)
102 size_t size;
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;
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)
114 return (struct gcov_fn_info *)
115 ((char *) info->functions + fn * get_fn_size(info));
119 * gcov_info_dup - duplicate profiling data set
120 * @info: profiling data set to duplicate
122 * Return newly allocated duplicate on success, %NULL on error.
124 struct gcov_info *gcov_info_dup(struct gcov_info *info)
126 struct gcov_info *dup;
127 unsigned int i;
128 unsigned int active;
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);
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);
161 return dup;
163 err_free:
164 gcov_info_free(dup);
165 return NULL;
169 * gcov_info_free - release memory for profiling data set duplicate
170 * @info: profiling data set duplicate to free
172 void gcov_info_free(struct gcov_info *info)
174 unsigned int active = num_counter_active(info);
175 unsigned int i;
177 for (i = 0; i < active ; i++)
178 vfree(info->counts[i].values);
179 kfree(info->functions);
180 kfree(info->filename);
181 kfree(info);
185 * struct type_info - iterator helper array
186 * @ctr_type: counter type
187 * @offset: index of the first value of the current function for this type
189 * This array is needed to convert the in-memory data format into the in-file
190 * data format:
192 * In-memory:
193 * for each counter type
194 * for each function
195 * values
197 * In-file:
198 * for each function
199 * for each counter type
200 * values
202 * See gcc source gcc/gcov-io.h for more information on data organization.
204 struct type_info {
205 int ctr_type;
206 unsigned int offset;
210 * struct gcov_iterator - specifies current file position in logical records
211 * @info: associated profiling data
212 * @record: record type
213 * @function: function number
214 * @type: counter type
215 * @count: index into values array
216 * @num_types: number of counter types
217 * @type_info: helper array to get values-array offset for current function
219 struct gcov_iterator {
220 struct gcov_info *info;
222 int record;
223 unsigned int function;
224 unsigned int type;
225 unsigned int count;
227 int num_types;
228 struct type_info type_info[0];
231 static struct gcov_fn_info *get_func(struct gcov_iterator *iter)
233 return get_fn_info(iter->info, iter->function);
236 static struct type_info *get_type(struct gcov_iterator *iter)
238 return &iter->type_info[iter->type];
242 * gcov_iter_new - allocate and initialize profiling data iterator
243 * @info: profiling data set to be iterated
245 * Return file iterator on success, %NULL otherwise.
247 struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
249 struct gcov_iterator *iter;
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;
257 return iter;
261 * gcov_iter_free - release memory for iterator
262 * @iter: file iterator to free
264 void gcov_iter_free(struct gcov_iterator *iter)
266 kfree(iter);
270 * gcov_iter_get_info - return profiling data set for given file iterator
271 * @iter: file iterator
273 struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
275 return iter->info;
279 * gcov_iter_start - reset file iterator to starting position
280 * @iter: file iterator
282 void gcov_iter_start(struct gcov_iterator *iter)
284 int i;
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;
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
312 * gcov_iter_next - advance file iterator to next logical record
313 * @iter: file iterator
315 * Return zero if new position is valid, non-zero if iterator has reached end.
317 int gcov_iter_next(struct gcov_iterator *iter)
319 switch (iter->record) {
320 case RECORD_FILE_MAGIC:
321 case RECORD_GCOV_VERSION:
322 case RECORD_FUNCTION_TAG:
323 case RECORD_FUNCTON_TAG_LEN:
324 case RECORD_FUNCTION_IDENT:
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;
338 /* Advance to next counter type */
339 get_type(iter)->offset += iter->count;
340 iter->count = 0;
341 iter->type++;
342 /* fall through */
343 case RECORD_FUNCTION_CHECK:
344 if (iter->type < iter->num_types) {
345 iter->record = 7;
346 break;
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;
359 /* Check for EOF. */
360 if (iter->record == -1)
361 return -EINVAL;
362 else
363 return 0;
367 * seq_write_gcov_u32 - write 32 bit number in gcov format to seq_file
368 * @seq: seq_file handle
369 * @v: value to be stored
371 * Number format defined by gcc: numbers are recorded in the 32 bit
372 * unsigned binary form of the endianness of the machine generating the
373 * file.
375 static int seq_write_gcov_u32(struct seq_file *seq, u32 v)
377 return seq_write(seq, &v, sizeof(v));
381 * seq_write_gcov_u64 - write 64 bit number in gcov format to seq_file
382 * @seq: seq_file handle
383 * @v: value to be stored
385 * Number format defined by gcc: numbers are recorded in the 32 bit
386 * unsigned binary form of the endianness of the machine generating the
387 * file. 64 bit numbers are stored as two 32 bit numbers, the low part
388 * first.
390 static int seq_write_gcov_u64(struct seq_file *seq, u64 v)
392 u32 data[2];
394 data[0] = (v & 0xffffffffUL);
395 data[1] = (v >> 32);
396 return seq_write(seq, data, sizeof(data));
400 * gcov_iter_write - write data for current pos to seq_file
401 * @iter: file iterator
402 * @seq: seq_file handle
404 * Return zero on success, non-zero otherwise.
406 int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
408 int rc = -EINVAL;
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;
423 case RECORD_FUNCTON_TAG_LEN:
424 rc = seq_write_gcov_u32(seq, 2);
425 break;
426 case RECORD_FUNCTION_IDENT:
427 rc = seq_write_gcov_u32(seq, get_func(iter)->ident);
428 break;
429 case RECORD_FUNCTION_CHECK:
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;
446 return rc;