gcc_4_7.c 13 KB

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