gcc_4_7.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  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. /* Symbolic links to be created for each profiling data file. */
  142. const struct gcov_link gcov_link[] = {
  143. { OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */
  144. { 0, NULL},
  145. };
  146. /*
  147. * Determine whether a counter is active. Doesn't change at run-time.
  148. */
  149. static int counter_active(struct gcov_info *info, unsigned int type)
  150. {
  151. return info->merge[type] ? 1 : 0;
  152. }
  153. /* Determine number of active counters. Based on gcc magic. */
  154. static unsigned int num_counter_active(struct gcov_info *info)
  155. {
  156. unsigned int i;
  157. unsigned int result = 0;
  158. for (i = 0; i < GCOV_COUNTERS; i++) {
  159. if (counter_active(info, i))
  160. result++;
  161. }
  162. return result;
  163. }
  164. /**
  165. * gcov_info_reset - reset profiling data to zero
  166. * @info: profiling data set
  167. */
  168. void gcov_info_reset(struct gcov_info *info)
  169. {
  170. struct gcov_ctr_info *ci_ptr;
  171. unsigned int fi_idx;
  172. unsigned int ct_idx;
  173. for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
  174. ci_ptr = info->functions[fi_idx]->ctrs;
  175. for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
  176. if (!counter_active(info, ct_idx))
  177. continue;
  178. memset(ci_ptr->values, 0,
  179. sizeof(gcov_type) * ci_ptr->num);
  180. ci_ptr++;
  181. }
  182. }
  183. }
  184. /**
  185. * gcov_info_is_compatible - check if profiling data can be added
  186. * @info1: first profiling data set
  187. * @info2: second profiling data set
  188. *
  189. * Returns non-zero if profiling data can be added, zero otherwise.
  190. */
  191. int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
  192. {
  193. return (info1->stamp == info2->stamp);
  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. */
  202. void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
  203. {
  204. struct gcov_ctr_info *dci_ptr;
  205. struct gcov_ctr_info *sci_ptr;
  206. unsigned int fi_idx;
  207. unsigned int ct_idx;
  208. unsigned int val_idx;
  209. for (fi_idx = 0; fi_idx < src->n_functions; fi_idx++) {
  210. dci_ptr = dst->functions[fi_idx]->ctrs;
  211. sci_ptr = src->functions[fi_idx]->ctrs;
  212. for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
  213. if (!counter_active(src, ct_idx))
  214. continue;
  215. for (val_idx = 0; val_idx < sci_ptr->num; val_idx++)
  216. dci_ptr->values[val_idx] +=
  217. sci_ptr->values[val_idx];
  218. dci_ptr++;
  219. sci_ptr++;
  220. }
  221. }
  222. }
  223. /**
  224. * gcov_info_dup - duplicate profiling data set
  225. * @info: profiling data set to duplicate
  226. *
  227. * Return newly allocated duplicate on success, %NULL on error.
  228. */
  229. struct gcov_info *gcov_info_dup(struct gcov_info *info)
  230. {
  231. struct gcov_info *dup;
  232. struct gcov_ctr_info *dci_ptr; /* dst counter info */
  233. struct gcov_ctr_info *sci_ptr; /* src counter info */
  234. unsigned int active;
  235. unsigned int fi_idx; /* function info idx */
  236. unsigned int ct_idx; /* counter type idx */
  237. size_t fi_size; /* function info size */
  238. size_t cv_size; /* counter values size */
  239. dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
  240. if (!dup)
  241. return NULL;
  242. dup->next = NULL;
  243. dup->filename = NULL;
  244. dup->functions = NULL;
  245. dup->filename = kstrdup(info->filename, GFP_KERNEL);
  246. if (!dup->filename)
  247. goto err_free;
  248. dup->functions = kcalloc(info->n_functions,
  249. sizeof(struct gcov_fn_info *), GFP_KERNEL);
  250. if (!dup->functions)
  251. goto err_free;
  252. active = num_counter_active(info);
  253. fi_size = sizeof(struct gcov_fn_info);
  254. fi_size += sizeof(struct gcov_ctr_info) * active;
  255. for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
  256. dup->functions[fi_idx] = kzalloc(fi_size, GFP_KERNEL);
  257. if (!dup->functions[fi_idx])
  258. goto err_free;
  259. *(dup->functions[fi_idx]) = *(info->functions[fi_idx]);
  260. sci_ptr = info->functions[fi_idx]->ctrs;
  261. dci_ptr = dup->functions[fi_idx]->ctrs;
  262. for (ct_idx = 0; ct_idx < active; ct_idx++) {
  263. cv_size = sizeof(gcov_type) * sci_ptr->num;
  264. dci_ptr->values = vmalloc(cv_size);
  265. if (!dci_ptr->values)
  266. goto err_free;
  267. dci_ptr->num = sci_ptr->num;
  268. memcpy(dci_ptr->values, sci_ptr->values, cv_size);
  269. sci_ptr++;
  270. dci_ptr++;
  271. }
  272. }
  273. return dup;
  274. err_free:
  275. gcov_info_free(dup);
  276. return NULL;
  277. }
  278. /**
  279. * gcov_info_free - release memory for profiling data set duplicate
  280. * @info: profiling data set duplicate to free
  281. */
  282. void gcov_info_free(struct gcov_info *info)
  283. {
  284. unsigned int active;
  285. unsigned int fi_idx;
  286. unsigned int ct_idx;
  287. struct gcov_ctr_info *ci_ptr;
  288. if (!info->functions)
  289. goto free_info;
  290. active = num_counter_active(info);
  291. for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
  292. if (!info->functions[fi_idx])
  293. continue;
  294. ci_ptr = info->functions[fi_idx]->ctrs;
  295. for (ct_idx = 0; ct_idx < active; ct_idx++, ci_ptr++)
  296. vfree(ci_ptr->values);
  297. kfree(info->functions[fi_idx]);
  298. }
  299. free_info:
  300. kfree(info->functions);
  301. kfree(info->filename);
  302. kfree(info);
  303. }
  304. #define ITER_STRIDE PAGE_SIZE
  305. /**
  306. * struct gcov_iterator - specifies current file position in logical records
  307. * @info: associated profiling data
  308. * @buffer: buffer containing file data
  309. * @size: size of buffer
  310. * @pos: current position in file
  311. */
  312. struct gcov_iterator {
  313. struct gcov_info *info;
  314. void *buffer;
  315. size_t size;
  316. loff_t pos;
  317. };
  318. /**
  319. * store_gcov_u32 - store 32 bit number in gcov format to buffer
  320. * @buffer: target buffer or NULL
  321. * @off: offset into the buffer
  322. * @v: value to be stored
  323. *
  324. * Number format defined by gcc: numbers are recorded in the 32 bit
  325. * unsigned binary form of the endianness of the machine generating the
  326. * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't
  327. * store anything.
  328. */
  329. static size_t store_gcov_u32(void *buffer, size_t off, u32 v)
  330. {
  331. u32 *data;
  332. if (buffer) {
  333. data = buffer + off;
  334. *data = v;
  335. }
  336. return sizeof(*data);
  337. }
  338. /**
  339. * store_gcov_u64 - store 64 bit number in gcov format to buffer
  340. * @buffer: target buffer or NULL
  341. * @off: offset into the buffer
  342. * @v: value to be stored
  343. *
  344. * Number format defined by gcc: numbers are recorded in the 32 bit
  345. * unsigned binary form of the endianness of the machine generating the
  346. * file. 64 bit numbers are stored as two 32 bit numbers, the low part
  347. * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store
  348. * anything.
  349. */
  350. static size_t store_gcov_u64(void *buffer, size_t off, u64 v)
  351. {
  352. u32 *data;
  353. if (buffer) {
  354. data = buffer + off;
  355. data[0] = (v & 0xffffffffUL);
  356. data[1] = (v >> 32);
  357. }
  358. return sizeof(*data) * 2;
  359. }
  360. /**
  361. * convert_to_gcda - convert profiling data set to gcda file format
  362. * @buffer: the buffer to store file data or %NULL if no data should be stored
  363. * @info: profiling data set to be converted
  364. *
  365. * Returns the number of bytes that were/would have been stored into the buffer.
  366. */
  367. static size_t convert_to_gcda(char *buffer, struct gcov_info *info)
  368. {
  369. struct gcov_fn_info *fi_ptr;
  370. struct gcov_ctr_info *ci_ptr;
  371. unsigned int fi_idx;
  372. unsigned int ct_idx;
  373. unsigned int cv_idx;
  374. size_t pos = 0;
  375. /* File header. */
  376. pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
  377. pos += store_gcov_u32(buffer, pos, info->version);
  378. pos += store_gcov_u32(buffer, pos, info->stamp);
  379. for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
  380. fi_ptr = info->functions[fi_idx];
  381. /* Function record. */
  382. pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
  383. pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH);
  384. pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
  385. pos += store_gcov_u32(buffer, pos, fi_ptr->lineno_checksum);
  386. pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
  387. ci_ptr = fi_ptr->ctrs;
  388. for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
  389. if (!counter_active(info, ct_idx))
  390. continue;
  391. /* Counter record. */
  392. pos += store_gcov_u32(buffer, pos,
  393. GCOV_TAG_FOR_COUNTER(ct_idx));
  394. pos += store_gcov_u32(buffer, pos, ci_ptr->num * 2);
  395. for (cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++) {
  396. pos += store_gcov_u64(buffer, pos,
  397. ci_ptr->values[cv_idx]);
  398. }
  399. ci_ptr++;
  400. }
  401. }
  402. return pos;
  403. }
  404. /**
  405. * gcov_iter_new - allocate and initialize profiling data iterator
  406. * @info: profiling data set to be iterated
  407. *
  408. * Return file iterator on success, %NULL otherwise.
  409. */
  410. struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
  411. {
  412. struct gcov_iterator *iter;
  413. iter = kzalloc(sizeof(struct gcov_iterator), GFP_KERNEL);
  414. if (!iter)
  415. goto err_free;
  416. iter->info = info;
  417. /* Dry-run to get the actual buffer size. */
  418. iter->size = convert_to_gcda(NULL, info);
  419. iter->buffer = vmalloc(iter->size);
  420. if (!iter->buffer)
  421. goto err_free;
  422. convert_to_gcda(iter->buffer, info);
  423. return iter;
  424. err_free:
  425. kfree(iter);
  426. return NULL;
  427. }
  428. /**
  429. * gcov_iter_get_info - return profiling data set for given file iterator
  430. * @iter: file iterator
  431. */
  432. void gcov_iter_free(struct gcov_iterator *iter)
  433. {
  434. vfree(iter->buffer);
  435. kfree(iter);
  436. }
  437. /**
  438. * gcov_iter_get_info - return profiling data set for given file iterator
  439. * @iter: file iterator
  440. */
  441. struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
  442. {
  443. return iter->info;
  444. }
  445. /**
  446. * gcov_iter_start - reset file iterator to starting position
  447. * @iter: file iterator
  448. */
  449. void gcov_iter_start(struct gcov_iterator *iter)
  450. {
  451. iter->pos = 0;
  452. }
  453. /**
  454. * gcov_iter_next - advance file iterator to next logical record
  455. * @iter: file iterator
  456. *
  457. * Return zero if new position is valid, non-zero if iterator has reached end.
  458. */
  459. int gcov_iter_next(struct gcov_iterator *iter)
  460. {
  461. if (iter->pos < iter->size)
  462. iter->pos += ITER_STRIDE;
  463. if (iter->pos >= iter->size)
  464. return -EINVAL;
  465. return 0;
  466. }
  467. /**
  468. * gcov_iter_write - write data for current pos to seq_file
  469. * @iter: file iterator
  470. * @seq: seq_file handle
  471. *
  472. * Return zero on success, non-zero otherwise.
  473. */
  474. int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
  475. {
  476. size_t len;
  477. if (iter->pos >= iter->size)
  478. return -EINVAL;
  479. len = ITER_STRIDE;
  480. if (iter->pos + len > iter->size)
  481. len = iter->size - iter->pos;
  482. seq_write(seq, iter->buffer + iter->pos, len);
  483. return 0;
  484. }