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