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