linux/kernel/gcov/gcc_3_4.c
<<
>>
Prefs
   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 <oberpar@linux.vnet.ibm.com>
  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#define GCOV_COUNTERS           5
  25
  26static struct gcov_info *gcov_info_head;
  27
  28/**
  29 * struct gcov_fn_info - profiling meta data per function
  30 * @ident: object file-unique function identifier
  31 * @checksum: function checksum
  32 * @n_ctrs: number of values per counter type belonging to this function
  33 *
  34 * This data is generated by gcc during compilation and doesn't change
  35 * at run-time.
  36 */
  37struct gcov_fn_info {
  38        unsigned int ident;
  39        unsigned int checksum;
  40        unsigned int n_ctrs[0];
  41};
  42
  43/**
  44 * struct gcov_ctr_info - profiling data per counter type
  45 * @num: number of counter values for this type
  46 * @values: array of counter values for this type
  47 * @merge: merge function for counter values of this type (unused)
  48 *
  49 * This data is generated by gcc during compilation and doesn't change
  50 * at run-time with the exception of the values array.
  51 */
  52struct gcov_ctr_info {
  53        unsigned int    num;
  54        gcov_type       *values;
  55        void            (*merge)(gcov_type *, unsigned int);
  56};
  57
  58/**
  59 * struct gcov_info - profiling data per object file
  60 * @version: gcov version magic indicating the gcc version used for compilation
  61 * @next: list head for a singly-linked list
  62 * @stamp: time stamp
  63 * @filename: name of the associated gcov data file
  64 * @n_functions: number of instrumented functions
  65 * @functions: function data
  66 * @ctr_mask: mask specifying which counter types are active
  67 * @counts: counter data per counter type
  68 *
  69 * This data is generated by gcc during compilation and doesn't change
  70 * at run-time with the exception of the next pointer.
  71 */
  72struct gcov_info {
  73        unsigned int                    version;
  74        struct gcov_info                *next;
  75        unsigned int                    stamp;
  76        const char                      *filename;
  77        unsigned int                    n_functions;
  78        const struct gcov_fn_info       *functions;
  79        unsigned int                    ctr_mask;
  80        struct gcov_ctr_info            counts[0];
  81};
  82
  83/**
  84 * gcov_info_filename - return info filename
  85 * @info: profiling data set
  86 */
  87const char *gcov_info_filename(struct gcov_info *info)
  88{
  89        return info->filename;
  90}
  91
  92/**
  93 * gcov_info_version - return info version
  94 * @info: profiling data set
  95 */
  96unsigned int gcov_info_version(struct gcov_info *info)
  97{
  98        return info->version;
  99}
 100
 101/**
 102 * gcov_info_next - return next profiling data set
 103 * @info: profiling data set
 104 *
 105 * Returns next gcov_info following @info or first gcov_info in the chain if
 106 * @info is %NULL.
 107 */
 108struct gcov_info *gcov_info_next(struct gcov_info *info)
 109{
 110        if (!info)
 111                return gcov_info_head;
 112
 113        return info->next;
 114}
 115
 116/**
 117 * gcov_info_link - link/add profiling data set to the list
 118 * @info: profiling data set
 119 */
 120void gcov_info_link(struct gcov_info *info)
 121{
 122        info->next = gcov_info_head;
 123        gcov_info_head = info;
 124}
 125
 126/**
 127 * gcov_info_unlink - unlink/remove profiling data set from the list
 128 * @prev: previous profiling data set
 129 * @info: profiling data set
 130 */
 131void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
 132{
 133        if (prev)
 134                prev->next = info->next;
 135        else
 136                gcov_info_head = info->next;
 137}
 138
 139/* Symbolic links to be created for each profiling data file. */
 140const struct gcov_link gcov_link[] = {
 141        { OBJ_TREE, "gcno" },   /* Link to .gcno file in $(objtree). */
 142        { 0, NULL},
 143};
 144
 145/*
 146 * Determine whether a counter is active. Based on gcc magic. Doesn't change
 147 * at run-time.
 148 */
 149static int counter_active(struct gcov_info *info, unsigned int type)
 150{
 151        return (1 << type) & info->ctr_mask;
 152}
 153
 154/* Determine number of active counters. Based on gcc magic. */
 155static unsigned int num_counter_active(struct gcov_info *info)
 156{
 157        unsigned int i;
 158        unsigned int result = 0;
 159
 160        for (i = 0; i < GCOV_COUNTERS; i++) {
 161                if (counter_active(info, i))
 162                        result++;
 163        }
 164        return result;
 165}
 166
 167/**
 168 * gcov_info_reset - reset profiling data to zero
 169 * @info: profiling data set
 170 */
 171void gcov_info_reset(struct gcov_info *info)
 172{
 173        unsigned int active = num_counter_active(info);
 174        unsigned int i;
 175
 176        for (i = 0; i < active; i++) {
 177                memset(info->counts[i].values, 0,
 178                       info->counts[i].num * sizeof(gcov_type));
 179        }
 180}
 181
 182/**
 183 * gcov_info_is_compatible - check if profiling data can be added
 184 * @info1: first profiling data set
 185 * @info2: second profiling data set
 186 *
 187 * Returns non-zero if profiling data can be added, zero otherwise.
 188 */
 189int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
 190{
 191        return (info1->stamp == info2->stamp);
 192}
 193
 194/**
 195 * gcov_info_add - add up profiling data
 196 * @dest: profiling data set to which data is added
 197 * @source: profiling data set which is added
 198 *
 199 * Adds profiling counts of @source to @dest.
 200 */
 201void gcov_info_add(struct gcov_info *dest, struct gcov_info *source)
 202{
 203        unsigned int i;
 204        unsigned int j;
 205
 206        for (i = 0; i < num_counter_active(dest); i++) {
 207                for (j = 0; j < dest->counts[i].num; j++) {
 208                        dest->counts[i].values[j] +=
 209                                source->counts[i].values[j];
 210                }
 211        }
 212}
 213
 214/* Get size of function info entry. Based on gcc magic. */
 215static size_t get_fn_size(struct gcov_info *info)
 216{
 217        size_t size;
 218
 219        size = sizeof(struct gcov_fn_info) + num_counter_active(info) *
 220               sizeof(unsigned int);
 221        if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int))
 222                size = ALIGN(size, __alignof__(struct gcov_fn_info));
 223        return size;
 224}
 225
 226/* Get address of function info entry. Based on gcc magic. */
 227static struct gcov_fn_info *get_fn_info(struct gcov_info *info, unsigned int fn)
 228{
 229        return (struct gcov_fn_info *)
 230                ((char *) info->functions + fn * get_fn_size(info));
 231}
 232
 233/**
 234 * gcov_info_dup - duplicate profiling data set
 235 * @info: profiling data set to duplicate
 236 *
 237 * Return newly allocated duplicate on success, %NULL on error.
 238 */
 239struct gcov_info *gcov_info_dup(struct gcov_info *info)
 240{
 241        struct gcov_info *dup;
 242        unsigned int i;
 243        unsigned int active;
 244
 245        /* Duplicate gcov_info. */
 246        active = num_counter_active(info);
 247        dup = kzalloc(sizeof(struct gcov_info) +
 248                      sizeof(struct gcov_ctr_info) * active, GFP_KERNEL);
 249        if (!dup)
 250                return NULL;
 251        dup->version            = info->version;
 252        dup->stamp              = info->stamp;
 253        dup->n_functions        = info->n_functions;
 254        dup->ctr_mask           = info->ctr_mask;
 255        /* Duplicate filename. */
 256        dup->filename           = kstrdup(info->filename, GFP_KERNEL);
 257        if (!dup->filename)
 258                goto err_free;
 259        /* Duplicate table of functions. */
 260        dup->functions = kmemdup(info->functions, info->n_functions *
 261                                 get_fn_size(info), GFP_KERNEL);
 262        if (!dup->functions)
 263                goto err_free;
 264        /* Duplicate counter arrays. */
 265        for (i = 0; i < active ; i++) {
 266                struct gcov_ctr_info *ctr = &info->counts[i];
 267                size_t size = ctr->num * sizeof(gcov_type);
 268
 269                dup->counts[i].num = ctr->num;
 270                dup->counts[i].merge = ctr->merge;
 271                dup->counts[i].values = vmalloc(size);
 272                if (!dup->counts[i].values)
 273                        goto err_free;
 274                memcpy(dup->counts[i].values, ctr->values, size);
 275        }
 276        return dup;
 277
 278err_free:
 279        gcov_info_free(dup);
 280        return NULL;
 281}
 282
 283/**
 284 * gcov_info_free - release memory for profiling data set duplicate
 285 * @info: profiling data set duplicate to free
 286 */
 287void gcov_info_free(struct gcov_info *info)
 288{
 289        unsigned int active = num_counter_active(info);
 290        unsigned int i;
 291
 292        for (i = 0; i < active ; i++)
 293                vfree(info->counts[i].values);
 294        kfree(info->functions);
 295        kfree(info->filename);
 296        kfree(info);
 297}
 298
 299/**
 300 * struct type_info - iterator helper array
 301 * @ctr_type: counter type
 302 * @offset: index of the first value of the current function for this type
 303 *
 304 * This array is needed to convert the in-memory data format into the in-file
 305 * data format:
 306 *
 307 * In-memory:
 308 *   for each counter type
 309 *     for each function
 310 *       values
 311 *
 312 * In-file:
 313 *   for each function
 314 *     for each counter type
 315 *       values
 316 *
 317 * See gcc source gcc/gcov-io.h for more information on data organization.
 318 */
 319struct type_info {
 320        int ctr_type;
 321        unsigned int offset;
 322};
 323
 324/**
 325 * struct gcov_iterator - specifies current file position in logical records
 326 * @info: associated profiling data
 327 * @record: record type
 328 * @function: function number
 329 * @type: counter type
 330 * @count: index into values array
 331 * @num_types: number of counter types
 332 * @type_info: helper array to get values-array offset for current function
 333 */
 334struct gcov_iterator {
 335        struct gcov_info *info;
 336
 337        int record;
 338        unsigned int function;
 339        unsigned int type;
 340        unsigned int count;
 341
 342        int num_types;
 343        struct type_info type_info[0];
 344};
 345
 346static struct gcov_fn_info *get_func(struct gcov_iterator *iter)
 347{
 348        return get_fn_info(iter->info, iter->function);
 349}
 350
 351static struct type_info *get_type(struct gcov_iterator *iter)
 352{
 353        return &iter->type_info[iter->type];
 354}
 355
 356/**
 357 * gcov_iter_new - allocate and initialize profiling data iterator
 358 * @info: profiling data set to be iterated
 359 *
 360 * Return file iterator on success, %NULL otherwise.
 361 */
 362struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
 363{
 364        struct gcov_iterator *iter;
 365
 366        iter = kzalloc(sizeof(struct gcov_iterator) +
 367                       num_counter_active(info) * sizeof(struct type_info),
 368                       GFP_KERNEL);
 369        if (iter)
 370                iter->info = info;
 371
 372        return iter;
 373}
 374
 375/**
 376 * gcov_iter_free - release memory for iterator
 377 * @iter: file iterator to free
 378 */
 379void gcov_iter_free(struct gcov_iterator *iter)
 380{
 381        kfree(iter);
 382}
 383
 384/**
 385 * gcov_iter_get_info - return profiling data set for given file iterator
 386 * @iter: file iterator
 387 */
 388struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
 389{
 390        return iter->info;
 391}
 392
 393/**
 394 * gcov_iter_start - reset file iterator to starting position
 395 * @iter: file iterator
 396 */
 397void gcov_iter_start(struct gcov_iterator *iter)
 398{
 399        int i;
 400
 401        iter->record = 0;
 402        iter->function = 0;
 403        iter->type = 0;
 404        iter->count = 0;
 405        iter->num_types = 0;
 406        for (i = 0; i < GCOV_COUNTERS; i++) {
 407                if (counter_active(iter->info, i)) {
 408                        iter->type_info[iter->num_types].ctr_type = i;
 409                        iter->type_info[iter->num_types++].offset = 0;
 410                }
 411        }
 412}
 413
 414/* Mapping of logical record number to actual file content. */
 415#define RECORD_FILE_MAGIC       0
 416#define RECORD_GCOV_VERSION     1
 417#define RECORD_TIME_STAMP       2
 418#define RECORD_FUNCTION_TAG     3
 419#define RECORD_FUNCTON_TAG_LEN  4
 420#define RECORD_FUNCTION_IDENT   5
 421#define RECORD_FUNCTION_CHECK   6
 422#define RECORD_COUNT_TAG        7
 423#define RECORD_COUNT_LEN        8
 424#define RECORD_COUNT            9
 425
 426/**
 427 * gcov_iter_next - advance file iterator to next logical record
 428 * @iter: file iterator
 429 *
 430 * Return zero if new position is valid, non-zero if iterator has reached end.
 431 */
 432int gcov_iter_next(struct gcov_iterator *iter)
 433{
 434        switch (iter->record) {
 435        case RECORD_FILE_MAGIC:
 436        case RECORD_GCOV_VERSION:
 437        case RECORD_FUNCTION_TAG:
 438        case RECORD_FUNCTON_TAG_LEN:
 439        case RECORD_FUNCTION_IDENT:
 440        case RECORD_COUNT_TAG:
 441                /* Advance to next record */
 442                iter->record++;
 443                break;
 444        case RECORD_COUNT:
 445                /* Advance to next count */
 446                iter->count++;
 447                /* fall through */
 448        case RECORD_COUNT_LEN:
 449                if (iter->count < get_func(iter)->n_ctrs[iter->type]) {
 450                        iter->record = 9;
 451                        break;
 452                }
 453                /* Advance to next counter type */
 454                get_type(iter)->offset += iter->count;
 455                iter->count = 0;
 456                iter->type++;
 457                /* fall through */
 458        case RECORD_FUNCTION_CHECK:
 459                if (iter->type < iter->num_types) {
 460                        iter->record = 7;
 461                        break;
 462                }
 463                /* Advance to next function */
 464                iter->type = 0;
 465                iter->function++;
 466                /* fall through */
 467        case RECORD_TIME_STAMP:
 468                if (iter->function < iter->info->n_functions)
 469                        iter->record = 3;
 470                else
 471                        iter->record = -1;
 472                break;
 473        }
 474        /* Check for EOF. */
 475        if (iter->record == -1)
 476                return -EINVAL;
 477        else
 478                return 0;
 479}
 480
 481/**
 482 * seq_write_gcov_u32 - write 32 bit number in gcov format to seq_file
 483 * @seq: seq_file handle
 484 * @v: value to be stored
 485 *
 486 * Number format defined by gcc: numbers are recorded in the 32 bit
 487 * unsigned binary form of the endianness of the machine generating the
 488 * file.
 489 */
 490static int seq_write_gcov_u32(struct seq_file *seq, u32 v)
 491{
 492        return seq_write(seq, &v, sizeof(v));
 493}
 494
 495/**
 496 * seq_write_gcov_u64 - write 64 bit number in gcov format to seq_file
 497 * @seq: seq_file handle
 498 * @v: value to be stored
 499 *
 500 * Number format defined by gcc: numbers are recorded in the 32 bit
 501 * unsigned binary form of the endianness of the machine generating the
 502 * file. 64 bit numbers are stored as two 32 bit numbers, the low part
 503 * first.
 504 */
 505static int seq_write_gcov_u64(struct seq_file *seq, u64 v)
 506{
 507        u32 data[2];
 508
 509        data[0] = (v & 0xffffffffUL);
 510        data[1] = (v >> 32);
 511        return seq_write(seq, data, sizeof(data));
 512}
 513
 514/**
 515 * gcov_iter_write - write data for current pos to seq_file
 516 * @iter: file iterator
 517 * @seq: seq_file handle
 518 *
 519 * Return zero on success, non-zero otherwise.
 520 */
 521int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
 522{
 523        int rc = -EINVAL;
 524
 525        switch (iter->record) {
 526        case RECORD_FILE_MAGIC:
 527                rc = seq_write_gcov_u32(seq, GCOV_DATA_MAGIC);
 528                break;
 529        case RECORD_GCOV_VERSION:
 530                rc = seq_write_gcov_u32(seq, iter->info->version);
 531                break;
 532        case RECORD_TIME_STAMP:
 533                rc = seq_write_gcov_u32(seq, iter->info->stamp);
 534                break;
 535        case RECORD_FUNCTION_TAG:
 536                rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION);
 537                break;
 538        case RECORD_FUNCTON_TAG_LEN:
 539                rc = seq_write_gcov_u32(seq, 2);
 540                break;
 541        case RECORD_FUNCTION_IDENT:
 542                rc = seq_write_gcov_u32(seq, get_func(iter)->ident);
 543                break;
 544        case RECORD_FUNCTION_CHECK:
 545                rc = seq_write_gcov_u32(seq, get_func(iter)->checksum);
 546                break;
 547        case RECORD_COUNT_TAG:
 548                rc = seq_write_gcov_u32(seq,
 549                        GCOV_TAG_FOR_COUNTER(get_type(iter)->ctr_type));
 550                break;
 551        case RECORD_COUNT_LEN:
 552                rc = seq_write_gcov_u32(seq,
 553                                get_func(iter)->n_ctrs[iter->type] * 2);
 554                break;
 555        case RECORD_COUNT:
 556                rc = seq_write_gcov_u64(seq,
 557                        iter->info->counts[iter->type].
 558                                values[iter->count + get_type(iter)->offset]);
 559                break;
 560        }
 561        return rc;
 562}
 563