gcc_4_7.c 14 KB

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