cregit-Linux how code gets into the kernel

Release 4.7 kernel/gcov/gcc_3_4.c

Directory: kernel/gcov
/*
 *  This code provides functions to handle gcc's profiling data format
 *  introduced with gcc 3.4. Future versions of gcc may change the gcov
 *  format (as happened before), so all format-specific information needs
 *  to be kept modular and easily exchangeable.
 *
 *  This file is based on gcc-internal definitions. Functions and data
 *  structures are defined to be compatible with gcc counterparts.
 *  For a better understanding, refer to gcc source: gcc/gcov-io.h.
 *
 *    Copyright IBM Corp. 2009
 *    Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
 *
 *    Uses gcc-internal data definitions.
 */

#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
#include "gcov.h"


#define GCOV_COUNTERS		5


static struct gcov_info *gcov_info_head;

/**
 * struct gcov_fn_info - profiling meta data per function
 * @ident: object file-unique function identifier
 * @checksum: function checksum
 * @n_ctrs: number of values per counter type belonging to this function
 *
 * This data is generated by gcc during compilation and doesn't change
 * at run-time.
 */

struct gcov_fn_info {
	
unsigned int ident;
	
unsigned int checksum;
	
unsigned int n_ctrs[0];
};

/**
 * struct gcov_ctr_info - profiling data per counter type
 * @num: number of counter values for this type
 * @values: array of counter values for this type
 * @merge: merge function for counter values of this type (unused)
 *
 * This data is generated by gcc during compilation and doesn't change
 * at run-time with the exception of the values array.
 */

struct gcov_ctr_info {
	
unsigned int	num;
	
gcov_type	*values;
	
void		(*merge)(gcov_type *, unsigned int);
};

/**
 * struct gcov_info - profiling data per object file
 * @version: gcov version magic indicating the gcc version used for compilation
 * @next: list head for a singly-linked list
 * @stamp: time stamp
 * @filename: name of the associated gcov data file
 * @n_functions: number of instrumented functions
 * @functions: function data
 * @ctr_mask: mask specifying which counter types are active
 * @counts: counter data per counter type
 *
 * This data is generated by gcc during compilation and doesn't change
 * at run-time with the exception of the next pointer.
 */

struct gcov_info {
	
unsigned int			version;
	
struct gcov_info		*next;
	
unsigned int			stamp;
	
const char			*filename;
	
unsigned int			n_functions;
	
const struct gcov_fn_info	*functions;
	
unsigned int			ctr_mask;
	
struct gcov_ctr_info		counts[0];
};

/**
 * gcov_info_filename - return info filename
 * @info: profiling data set
 */

const char *gcov_info_filename(struct gcov_info *info) { return info->filename; }

Contributors

PersonTokensPropCommitsCommitProp
frantisek hrbatafrantisek hrbata17100.00%1100.00%
Total17100.00%1100.00%

/** * gcov_info_version - return info version * @info: profiling data set */
unsigned int gcov_info_version(struct gcov_info *info) { return info->version; }

Contributors

PersonTokensPropCommitsCommitProp
frantisek hrbatafrantisek hrbata16100.00%1100.00%
Total16100.00%1100.00%

/** * gcov_info_next - return next profiling data set * @info: profiling data set * * Returns next gcov_info following @info or first gcov_info in the chain if * @info is %NULL. */
struct gcov_info *gcov_info_next(struct gcov_info *info) { if (!info) return gcov_info_head; return info->next; }

Contributors

PersonTokensPropCommitsCommitProp
frantisek hrbatafrantisek hrbata25100.00%1100.00%
Total25100.00%1100.00%

/** * gcov_info_link - link/add profiling data set to the list * @info: profiling data set */
void gcov_info_link(struct gcov_info *info) { info->next = gcov_info_head; gcov_info_head = info; }

Contributors

PersonTokensPropCommitsCommitProp
frantisek hrbatafrantisek hrbata20100.00%1100.00%
Total20100.00%1100.00%

/** * gcov_info_unlink - unlink/remove profiling data set from the list * @prev: previous profiling data set * @info: profiling data set */
void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info) { if (prev) prev->next = info->next; else gcov_info_head = info->next; }

Contributors

PersonTokensPropCommitsCommitProp
frantisek hrbatafrantisek hrbata34100.00%1100.00%
Total34100.00%1100.00%

/* Symbolic links to be created for each profiling data file. */ const struct gcov_link gcov_link[] = { { OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */ { 0, NULL}, }; /* * Determine whether a counter is active. Based on gcc magic. Doesn't change * at run-time. */
static int counter_active(struct gcov_info *info, unsigned int type) { return (1 << type) & info->ctr_mask; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter26100.00%1100.00%
Total26100.00%1100.00%

/* Determine number of active counters. Based on gcc magic. */
static unsigned int num_counter_active(struct gcov_info *info) { unsigned int i; unsigned int result = 0; for (i = 0; i < GCOV_COUNTERS; i++) { if (counter_active(info, i)) result++; } return result; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter52100.00%1100.00%
Total52100.00%1100.00%

/** * gcov_info_reset - reset profiling data to zero * @info: profiling data set */
void gcov_info_reset(struct gcov_info *info) { unsigned int active = num_counter_active(info); unsigned int i; for (i = 0; i < active; i++) { memset(info->counts[i].values, 0, info->counts[i].num * sizeof(gcov_type)); } }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter66100.00%1100.00%
Total66100.00%1100.00%

/** * gcov_info_is_compatible - check if profiling data can be added * @info1: first profiling data set * @info2: second profiling data set * * Returns non-zero if profiling data can be added, zero otherwise. */
int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2) { return (info1->stamp == info2->stamp); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter26100.00%1100.00%
Total26100.00%1100.00%

/** * gcov_info_add - add up profiling data * @dest: profiling data set to which data is added * @source: profiling data set which is added * * Adds profiling counts of @source to @dest. */
void gcov_info_add(struct gcov_info *dest, struct gcov_info *source) { unsigned int i; unsigned int j; for (i = 0; i < num_counter_active(dest); i++) { for (j = 0; j < dest->counts[i].num; j++) { dest->counts[i].values[j] += source->counts[i].values[j]; } } }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter87100.00%1100.00%
Total87100.00%1100.00%

/* Get size of function info entry. Based on gcc magic. */
static size_t get_fn_size(struct gcov_info *info) { size_t size; size = sizeof(struct gcov_fn_info) + num_counter_active(info) * sizeof(unsigned int); if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int)) size = ALIGN(size, __alignof__(struct gcov_fn_info)); return size; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter63100.00%1100.00%
Total63100.00%1100.00%

/* Get address of function info entry. Based on gcc magic. */
static struct gcov_fn_info *get_fn_info(struct gcov_info *info, unsigned int fn) { return (struct gcov_fn_info *) ((char *) info->functions + fn * get_fn_size(info)); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter40100.00%1100.00%
Total40100.00%1100.00%

/** * gcov_info_dup - duplicate profiling data set * @info: profiling data set to duplicate * * Return newly allocated duplicate on success, %NULL on error. */
struct gcov_info *gcov_info_dup(struct gcov_info *info) { struct gcov_info *dup; unsigned int i; unsigned int active; /* Duplicate gcov_info. */ active = num_counter_active(info); dup = kzalloc(sizeof(struct gcov_info) + sizeof(struct gcov_ctr_info) * active, GFP_KERNEL); if (!dup) return NULL; dup->version = info->version; dup->stamp = info->stamp; dup->n_functions = info->n_functions; dup->ctr_mask = info->ctr_mask; /* Duplicate filename. */ dup->filename = kstrdup(info->filename, GFP_KERNEL); if (!dup->filename) goto err_free; /* Duplicate table of functions. */ dup->functions = kmemdup(info->functions, info->n_functions * get_fn_size(info), GFP_KERNEL); if (!dup->functions) goto err_free; /* Duplicate counter arrays. */ for (i = 0; i < active ; i++) { struct gcov_ctr_info *ctr = &info->counts[i]; size_t size = ctr->num * sizeof(gcov_type); dup->counts[i].num = ctr->num; dup->counts[i].merge = ctr->merge; dup->counts[i].values = vmalloc(size); if (!dup->counts[i].values) goto err_free; memcpy(dup->counts[i].values, ctr->values, size); } return dup; err_free: gcov_info_free(dup); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter278100.00%1100.00%
Total278100.00%1100.00%

/** * gcov_info_free - release memory for profiling data set duplicate * @info: profiling data set duplicate to free */
void gcov_info_free(struct gcov_info *info) { unsigned int active = num_counter_active(info); unsigned int i; for (i = 0; i < active ; i++) vfree(info->counts[i].values); kfree(info->functions); kfree(info->filename); kfree(info); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter67100.00%1100.00%
Total67100.00%1100.00%

/** * struct type_info - iterator helper array * @ctr_type: counter type * @offset: index of the first value of the current function for this type * * This array is needed to convert the in-memory data format into the in-file * data format: * * In-memory: * for each counter type * for each function * values * * In-file: * for each function * for each counter type * values * * See gcc source gcc/gcov-io.h for more information on data organization. */ struct type_info { int ctr_type; unsigned int offset; }; /** * struct gcov_iterator - specifies current file position in logical records * @info: associated profiling data * @record: record type * @function: function number * @type: counter type * @count: index into values array * @num_types: number of counter types * @type_info: helper array to get values-array offset for current function */ struct gcov_iterator { struct gcov_info *info; int record; unsigned int function; unsigned int type; unsigned int count; int num_types; struct type_info type_info[0]; };
static struct gcov_fn_info *get_func(struct gcov_iterator *iter) { return get_fn_info(iter->info, iter->function); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter25100.00%1100.00%
Total25100.00%1100.00%


static struct type_info *get_type(struct gcov_iterator *iter) { return &iter->type_info[iter->type]; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter24100.00%1100.00%
Total24100.00%1100.00%

/** * gcov_iter_new - allocate and initialize profiling data iterator * @info: profiling data set to be iterated * * Return file iterator on success, %NULL otherwise. */
struct gcov_iterator *gcov_iter_new(struct gcov_info *info) { struct gcov_iterator *iter; iter = kzalloc(sizeof(struct gcov_iterator) + num_counter_active(info) * sizeof(struct type_info), GFP_KERNEL); if (iter) iter->info = info; return iter; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter54100.00%1100.00%
Total54100.00%1100.00%

/** * gcov_iter_free - release memory for iterator * @iter: file iterator to free */
void gcov_iter_free(struct gcov_iterator *iter) { kfree(iter); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter15100.00%1100.00%
Total15100.00%1100.00%

/** * gcov_iter_get_info - return profiling data set for given file iterator * @iter: file iterator */
struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter) { return iter->info; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter17100.00%1100.00%
Total17100.00%1100.00%

/** * gcov_iter_start - reset file iterator to starting position * @iter: file iterator */
void gcov_iter_start(struct gcov_iterator *iter) { int i; iter->record = 0; iter->function = 0; iter->type = 0; iter->count = 0; iter->num_types = 0; for (i = 0; i < GCOV_COUNTERS; i++) { if (counter_active(iter->info, i)) { iter->type_info[iter->num_types].ctr_type = i; iter->type_info[iter->num_types++].offset = 0; } } }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter98100.00%1100.00%
Total98100.00%1100.00%

/* Mapping of logical record number to actual file content. */ #define RECORD_FILE_MAGIC 0 #define RECORD_GCOV_VERSION 1 #define RECORD_TIME_STAMP 2 #define RECORD_FUNCTION_TAG 3 #define RECORD_FUNCTON_TAG_LEN 4 #define RECORD_FUNCTION_IDENT 5 #define RECORD_FUNCTION_CHECK 6 #define RECORD_COUNT_TAG 7 #define RECORD_COUNT_LEN 8 #define RECORD_COUNT 9 /** * gcov_iter_next - advance file iterator to next logical record * @iter: file iterator * * Return zero if new position is valid, non-zero if iterator has reached end. */
int gcov_iter_next(struct gcov_iterator *iter) { switch (iter->record) { case RECORD_FILE_MAGIC: case RECORD_GCOV_VERSION: case RECORD_FUNCTION_TAG: case RECORD_FUNCTON_TAG_LEN: case RECORD_FUNCTION_IDENT: case RECORD_COUNT_TAG: /* Advance to next record */ iter->record++; break; case RECORD_COUNT: /* Advance to next count */ iter->count++; /* fall through */ case RECORD_COUNT_LEN: if (iter->count < get_func(iter)->n_ctrs[iter->type]) { iter->record = 9; break; } /* Advance to next counter type */ get_type(iter)->offset += iter->count; iter->count = 0; iter->type++; /* fall through */ case RECORD_FUNCTION_CHECK: if (iter->type < iter->num_types) { iter->record = 7; break; } /* Advance to next function */ iter->type = 0; iter->function++; /* fall through */ case RECORD_TIME_STAMP: if (iter->function < iter->info->n_functions) iter->record = 3; else iter->record = -1; break; } /* Check for EOF. */ if (iter->record == -1) return -EINVAL; else return 0; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter190100.00%1100.00%
Total190100.00%1100.00%

/** * seq_write_gcov_u32 - write 32 bit number in gcov format to seq_file * @seq: seq_file handle * @v: value to be stored * * Number format defined by gcc: numbers are recorded in the 32 bit * unsigned binary form of the endianness of the machine generating the * file. */
static int seq_write_gcov_u32(struct seq_file *seq, u32 v) { return seq_write(seq, &v, sizeof(v)); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter28100.00%1100.00%
Total28100.00%1100.00%

/** * seq_write_gcov_u64 - write 64 bit number in gcov format to seq_file * @seq: seq_file handle * @v: value to be stored * * Number format defined by gcc: numbers are recorded in the 32 bit * unsigned binary form of the endianness of the machine generating the * file. 64 bit numbers are stored as two 32 bit numbers, the low part * first. */
static int seq_write_gcov_u64(struct seq_file *seq, u64 v) { u32 data[2]; data[0] = (v & 0xffffffffUL); data[1] = (v >> 32); return seq_write(seq, data, sizeof(data)); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter55100.00%1100.00%
Total55100.00%1100.00%

/** * gcov_iter_write - write data for current pos to seq_file * @iter: file iterator * @seq: seq_file handle * * Return zero on success, non-zero otherwise. */
int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq) { int rc = -EINVAL; switch (iter->record) { case RECORD_FILE_MAGIC: rc = seq_write_gcov_u32(seq, GCOV_DATA_MAGIC); break; case RECORD_GCOV_VERSION: rc = seq_write_gcov_u32(seq, iter->info->version); break; case RECORD_TIME_STAMP: rc = seq_write_gcov_u32(seq, iter->info->stamp); break; case RECORD_FUNCTION_TAG: rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION); break; case RECORD_FUNCTON_TAG_LEN: rc = seq_write_gcov_u32(seq, 2); break; case RECORD_FUNCTION_IDENT: rc = seq_write_gcov_u32(seq, get_func(iter)->ident); break; case RECORD_FUNCTION_CHECK: rc = seq_write_gcov_u32(seq, get_func(iter)->checksum); break; case RECORD_COUNT_TAG: rc = seq_write_gcov_u32(seq, GCOV_TAG_FOR_COUNTER(get_type(iter)->ctr_type)); break; case RECORD_COUNT_LEN: rc = seq_write_gcov_u32(seq, get_func(iter)->n_ctrs[iter->type] * 2); break; case RECORD_COUNT: rc = seq_write_gcov_u64(seq, iter->info->counts[iter->type]. values[iter->count + get_type(iter)->offset]); break; } return rc; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter223100.00%1100.00%
Total223100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter158287.79%150.00%
frantisek hrbatafrantisek hrbata22012.21%150.00%
Total1802100.00%2100.00%
Directory: kernel/gcov
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}