fs.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * This code exports profiling data as debugfs files to userspace.
  4. *
  5. * Copyright IBM Corp. 2009
  6. * Author(s): Peter Oberparleiter <[email protected]>
  7. *
  8. * Uses gcc-internal data definitions.
  9. * Based on the gcov-kernel patch by:
  10. * Hubertus Franke <[email protected]>
  11. * Nigel Hinds <[email protected]>
  12. * Rajan Ravindran <[email protected]>
  13. * Peter Oberparleiter <[email protected]>
  14. * Paul Larson
  15. * Yi CDL Yang
  16. */
  17. #define pr_fmt(fmt) "gcov: " fmt
  18. #include <linux/init.h>
  19. #include <linux/module.h>
  20. #include <linux/debugfs.h>
  21. #include <linux/fs.h>
  22. #include <linux/list.h>
  23. #include <linux/string.h>
  24. #include <linux/slab.h>
  25. #include <linux/mutex.h>
  26. #include <linux/seq_file.h>
  27. #include <linux/mm.h>
  28. #include "gcov.h"
  29. /**
  30. * struct gcov_node - represents a debugfs entry
  31. * @list: list head for child node list
  32. * @children: child nodes
  33. * @all: list head for list of all nodes
  34. * @parent: parent node
  35. * @loaded_info: array of pointers to profiling data sets for loaded object
  36. * files.
  37. * @num_loaded: number of profiling data sets for loaded object files.
  38. * @unloaded_info: accumulated copy of profiling data sets for unloaded
  39. * object files. Used only when gcov_persist=1.
  40. * @dentry: main debugfs entry, either a directory or data file
  41. * @links: associated symbolic links
  42. * @name: data file basename
  43. *
  44. * struct gcov_node represents an entity within the gcov/ subdirectory
  45. * of debugfs. There are directory and data file nodes. The latter represent
  46. * the actual synthesized data file plus any associated symbolic links which
  47. * are needed by the gcov tool to work correctly.
  48. */
  49. struct gcov_node {
  50. struct list_head list;
  51. struct list_head children;
  52. struct list_head all;
  53. struct gcov_node *parent;
  54. struct gcov_info **loaded_info;
  55. struct gcov_info *unloaded_info;
  56. struct dentry *dentry;
  57. struct dentry **links;
  58. int num_loaded;
  59. char name[];
  60. };
  61. static const char objtree[] = OBJTREE;
  62. static const char srctree[] = SRCTREE;
  63. static struct gcov_node root_node;
  64. static LIST_HEAD(all_head);
  65. static DEFINE_MUTEX(node_lock);
  66. /* If non-zero, keep copies of profiling data for unloaded modules. */
  67. static int gcov_persist = 1;
  68. static int __init gcov_persist_setup(char *str)
  69. {
  70. unsigned long val;
  71. if (kstrtoul(str, 0, &val)) {
  72. pr_warn("invalid gcov_persist parameter '%s'\n", str);
  73. return 0;
  74. }
  75. gcov_persist = val;
  76. pr_info("setting gcov_persist to %d\n", gcov_persist);
  77. return 1;
  78. }
  79. __setup("gcov_persist=", gcov_persist_setup);
  80. #define ITER_STRIDE PAGE_SIZE
  81. /**
  82. * struct gcov_iterator - specifies current file position in logical records
  83. * @info: associated profiling data
  84. * @buffer: buffer containing file data
  85. * @size: size of buffer
  86. * @pos: current position in file
  87. */
  88. struct gcov_iterator {
  89. struct gcov_info *info;
  90. size_t size;
  91. loff_t pos;
  92. char buffer[];
  93. };
  94. /**
  95. * gcov_iter_new - allocate and initialize profiling data iterator
  96. * @info: profiling data set to be iterated
  97. *
  98. * Return file iterator on success, %NULL otherwise.
  99. */
  100. static struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
  101. {
  102. struct gcov_iterator *iter;
  103. size_t size;
  104. /* Dry-run to get the actual buffer size. */
  105. size = convert_to_gcda(NULL, info);
  106. iter = kvmalloc(struct_size(iter, buffer, size), GFP_KERNEL);
  107. if (!iter)
  108. return NULL;
  109. iter->info = info;
  110. iter->size = size;
  111. convert_to_gcda(iter->buffer, info);
  112. return iter;
  113. }
  114. /**
  115. * gcov_iter_free - free iterator data
  116. * @iter: file iterator
  117. */
  118. static void gcov_iter_free(struct gcov_iterator *iter)
  119. {
  120. kvfree(iter);
  121. }
  122. /**
  123. * gcov_iter_get_info - return profiling data set for given file iterator
  124. * @iter: file iterator
  125. */
  126. static struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
  127. {
  128. return iter->info;
  129. }
  130. /**
  131. * gcov_iter_start - reset file iterator to starting position
  132. * @iter: file iterator
  133. */
  134. static void gcov_iter_start(struct gcov_iterator *iter)
  135. {
  136. iter->pos = 0;
  137. }
  138. /**
  139. * gcov_iter_next - advance file iterator to next logical record
  140. * @iter: file iterator
  141. *
  142. * Return zero if new position is valid, non-zero if iterator has reached end.
  143. */
  144. static int gcov_iter_next(struct gcov_iterator *iter)
  145. {
  146. if (iter->pos < iter->size)
  147. iter->pos += ITER_STRIDE;
  148. if (iter->pos >= iter->size)
  149. return -EINVAL;
  150. return 0;
  151. }
  152. /**
  153. * gcov_iter_write - write data for current pos to seq_file
  154. * @iter: file iterator
  155. * @seq: seq_file handle
  156. *
  157. * Return zero on success, non-zero otherwise.
  158. */
  159. static int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
  160. {
  161. size_t len;
  162. if (iter->pos >= iter->size)
  163. return -EINVAL;
  164. len = ITER_STRIDE;
  165. if (iter->pos + len > iter->size)
  166. len = iter->size - iter->pos;
  167. seq_write(seq, iter->buffer + iter->pos, len);
  168. return 0;
  169. }
  170. /*
  171. * seq_file.start() implementation for gcov data files. Note that the
  172. * gcov_iterator interface is designed to be more restrictive than seq_file
  173. * (no start from arbitrary position, etc.), to simplify the iterator
  174. * implementation.
  175. */
  176. static void *gcov_seq_start(struct seq_file *seq, loff_t *pos)
  177. {
  178. loff_t i;
  179. gcov_iter_start(seq->private);
  180. for (i = 0; i < *pos; i++) {
  181. if (gcov_iter_next(seq->private))
  182. return NULL;
  183. }
  184. return seq->private;
  185. }
  186. /* seq_file.next() implementation for gcov data files. */
  187. static void *gcov_seq_next(struct seq_file *seq, void *data, loff_t *pos)
  188. {
  189. struct gcov_iterator *iter = data;
  190. (*pos)++;
  191. if (gcov_iter_next(iter))
  192. return NULL;
  193. return iter;
  194. }
  195. /* seq_file.show() implementation for gcov data files. */
  196. static int gcov_seq_show(struct seq_file *seq, void *data)
  197. {
  198. struct gcov_iterator *iter = data;
  199. if (gcov_iter_write(iter, seq))
  200. return -EINVAL;
  201. return 0;
  202. }
  203. static void gcov_seq_stop(struct seq_file *seq, void *data)
  204. {
  205. /* Unused. */
  206. }
  207. static const struct seq_operations gcov_seq_ops = {
  208. .start = gcov_seq_start,
  209. .next = gcov_seq_next,
  210. .show = gcov_seq_show,
  211. .stop = gcov_seq_stop,
  212. };
  213. /*
  214. * Return a profiling data set associated with the given node. This is
  215. * either a data set for a loaded object file or a data set copy in case
  216. * all associated object files have been unloaded.
  217. */
  218. static struct gcov_info *get_node_info(struct gcov_node *node)
  219. {
  220. if (node->num_loaded > 0)
  221. return node->loaded_info[0];
  222. return node->unloaded_info;
  223. }
  224. /*
  225. * Return a newly allocated profiling data set which contains the sum of
  226. * all profiling data associated with the given node.
  227. */
  228. static struct gcov_info *get_accumulated_info(struct gcov_node *node)
  229. {
  230. struct gcov_info *info;
  231. int i = 0;
  232. if (node->unloaded_info)
  233. info = gcov_info_dup(node->unloaded_info);
  234. else
  235. info = gcov_info_dup(node->loaded_info[i++]);
  236. if (!info)
  237. return NULL;
  238. for (; i < node->num_loaded; i++)
  239. gcov_info_add(info, node->loaded_info[i]);
  240. return info;
  241. }
  242. /*
  243. * open() implementation for gcov data files. Create a copy of the profiling
  244. * data set and initialize the iterator and seq_file interface.
  245. */
  246. static int gcov_seq_open(struct inode *inode, struct file *file)
  247. {
  248. struct gcov_node *node = inode->i_private;
  249. struct gcov_iterator *iter;
  250. struct seq_file *seq;
  251. struct gcov_info *info;
  252. int rc = -ENOMEM;
  253. mutex_lock(&node_lock);
  254. /*
  255. * Read from a profiling data copy to minimize reference tracking
  256. * complexity and concurrent access and to keep accumulating multiple
  257. * profiling data sets associated with one node simple.
  258. */
  259. info = get_accumulated_info(node);
  260. if (!info)
  261. goto out_unlock;
  262. iter = gcov_iter_new(info);
  263. if (!iter)
  264. goto err_free_info;
  265. rc = seq_open(file, &gcov_seq_ops);
  266. if (rc)
  267. goto err_free_iter_info;
  268. seq = file->private_data;
  269. seq->private = iter;
  270. out_unlock:
  271. mutex_unlock(&node_lock);
  272. return rc;
  273. err_free_iter_info:
  274. gcov_iter_free(iter);
  275. err_free_info:
  276. gcov_info_free(info);
  277. goto out_unlock;
  278. }
  279. /*
  280. * release() implementation for gcov data files. Release resources allocated
  281. * by open().
  282. */
  283. static int gcov_seq_release(struct inode *inode, struct file *file)
  284. {
  285. struct gcov_iterator *iter;
  286. struct gcov_info *info;
  287. struct seq_file *seq;
  288. seq = file->private_data;
  289. iter = seq->private;
  290. info = gcov_iter_get_info(iter);
  291. gcov_iter_free(iter);
  292. gcov_info_free(info);
  293. seq_release(inode, file);
  294. return 0;
  295. }
  296. /*
  297. * Find a node by the associated data file name. Needs to be called with
  298. * node_lock held.
  299. */
  300. static struct gcov_node *get_node_by_name(const char *name)
  301. {
  302. struct gcov_node *node;
  303. struct gcov_info *info;
  304. list_for_each_entry(node, &all_head, all) {
  305. info = get_node_info(node);
  306. if (info && (strcmp(gcov_info_filename(info), name) == 0))
  307. return node;
  308. }
  309. return NULL;
  310. }
  311. /*
  312. * Reset all profiling data associated with the specified node.
  313. */
  314. static void reset_node(struct gcov_node *node)
  315. {
  316. int i;
  317. if (node->unloaded_info)
  318. gcov_info_reset(node->unloaded_info);
  319. for (i = 0; i < node->num_loaded; i++)
  320. gcov_info_reset(node->loaded_info[i]);
  321. }
  322. static void remove_node(struct gcov_node *node);
  323. /*
  324. * write() implementation for gcov data files. Reset profiling data for the
  325. * corresponding file. If all associated object files have been unloaded,
  326. * remove the debug fs node as well.
  327. */
  328. static ssize_t gcov_seq_write(struct file *file, const char __user *addr,
  329. size_t len, loff_t *pos)
  330. {
  331. struct seq_file *seq;
  332. struct gcov_info *info;
  333. struct gcov_node *node;
  334. seq = file->private_data;
  335. info = gcov_iter_get_info(seq->private);
  336. mutex_lock(&node_lock);
  337. node = get_node_by_name(gcov_info_filename(info));
  338. if (node) {
  339. /* Reset counts or remove node for unloaded modules. */
  340. if (node->num_loaded == 0)
  341. remove_node(node);
  342. else
  343. reset_node(node);
  344. }
  345. /* Reset counts for open file. */
  346. gcov_info_reset(info);
  347. mutex_unlock(&node_lock);
  348. return len;
  349. }
  350. /*
  351. * Given a string <path> representing a file path of format:
  352. * path/to/file.gcda
  353. * construct and return a new string:
  354. * <dir/>path/to/file.<ext>
  355. */
  356. static char *link_target(const char *dir, const char *path, const char *ext)
  357. {
  358. char *target;
  359. char *old_ext;
  360. char *copy;
  361. copy = kstrdup(path, GFP_KERNEL);
  362. if (!copy)
  363. return NULL;
  364. old_ext = strrchr(copy, '.');
  365. if (old_ext)
  366. *old_ext = '\0';
  367. if (dir)
  368. target = kasprintf(GFP_KERNEL, "%s/%s.%s", dir, copy, ext);
  369. else
  370. target = kasprintf(GFP_KERNEL, "%s.%s", copy, ext);
  371. kfree(copy);
  372. return target;
  373. }
  374. /*
  375. * Construct a string representing the symbolic link target for the given
  376. * gcov data file name and link type. Depending on the link type and the
  377. * location of the data file, the link target can either point to a
  378. * subdirectory of srctree, objtree or in an external location.
  379. */
  380. static char *get_link_target(const char *filename, const struct gcov_link *ext)
  381. {
  382. const char *rel;
  383. char *result;
  384. if (strncmp(filename, objtree, strlen(objtree)) == 0) {
  385. rel = filename + strlen(objtree) + 1;
  386. if (ext->dir == SRC_TREE)
  387. result = link_target(srctree, rel, ext->ext);
  388. else
  389. result = link_target(objtree, rel, ext->ext);
  390. } else {
  391. /* External compilation. */
  392. result = link_target(NULL, filename, ext->ext);
  393. }
  394. return result;
  395. }
  396. #define SKEW_PREFIX ".tmp_"
  397. /*
  398. * For a filename .tmp_filename.ext return filename.ext. Needed to compensate
  399. * for filename skewing caused by the mod-versioning mechanism.
  400. */
  401. static const char *deskew(const char *basename)
  402. {
  403. if (strncmp(basename, SKEW_PREFIX, sizeof(SKEW_PREFIX) - 1) == 0)
  404. return basename + sizeof(SKEW_PREFIX) - 1;
  405. return basename;
  406. }
  407. /*
  408. * Create links to additional files (usually .c and .gcno files) which the
  409. * gcov tool expects to find in the same directory as the gcov data file.
  410. */
  411. static void add_links(struct gcov_node *node, struct dentry *parent)
  412. {
  413. const char *basename;
  414. char *target;
  415. int num;
  416. int i;
  417. for (num = 0; gcov_link[num].ext; num++)
  418. /* Nothing. */;
  419. node->links = kcalloc(num, sizeof(struct dentry *), GFP_KERNEL);
  420. if (!node->links)
  421. return;
  422. for (i = 0; i < num; i++) {
  423. target = get_link_target(
  424. gcov_info_filename(get_node_info(node)),
  425. &gcov_link[i]);
  426. if (!target)
  427. goto out_err;
  428. basename = kbasename(target);
  429. if (basename == target)
  430. goto out_err;
  431. node->links[i] = debugfs_create_symlink(deskew(basename),
  432. parent, target);
  433. kfree(target);
  434. }
  435. return;
  436. out_err:
  437. kfree(target);
  438. while (i-- > 0)
  439. debugfs_remove(node->links[i]);
  440. kfree(node->links);
  441. node->links = NULL;
  442. }
  443. static const struct file_operations gcov_data_fops = {
  444. .open = gcov_seq_open,
  445. .release = gcov_seq_release,
  446. .read = seq_read,
  447. .llseek = seq_lseek,
  448. .write = gcov_seq_write,
  449. };
  450. /* Basic initialization of a new node. */
  451. static void init_node(struct gcov_node *node, struct gcov_info *info,
  452. const char *name, struct gcov_node *parent)
  453. {
  454. INIT_LIST_HEAD(&node->list);
  455. INIT_LIST_HEAD(&node->children);
  456. INIT_LIST_HEAD(&node->all);
  457. if (node->loaded_info) {
  458. node->loaded_info[0] = info;
  459. node->num_loaded = 1;
  460. }
  461. node->parent = parent;
  462. if (name)
  463. strcpy(node->name, name);
  464. }
  465. /*
  466. * Create a new node and associated debugfs entry. Needs to be called with
  467. * node_lock held.
  468. */
  469. static struct gcov_node *new_node(struct gcov_node *parent,
  470. struct gcov_info *info, const char *name)
  471. {
  472. struct gcov_node *node;
  473. node = kzalloc(sizeof(struct gcov_node) + strlen(name) + 1, GFP_KERNEL);
  474. if (!node)
  475. goto err_nomem;
  476. if (info) {
  477. node->loaded_info = kcalloc(1, sizeof(struct gcov_info *),
  478. GFP_KERNEL);
  479. if (!node->loaded_info)
  480. goto err_nomem;
  481. }
  482. init_node(node, info, name, parent);
  483. /* Differentiate between gcov data file nodes and directory nodes. */
  484. if (info) {
  485. node->dentry = debugfs_create_file(deskew(node->name), 0600,
  486. parent->dentry, node, &gcov_data_fops);
  487. } else
  488. node->dentry = debugfs_create_dir(node->name, parent->dentry);
  489. if (info)
  490. add_links(node, parent->dentry);
  491. list_add(&node->list, &parent->children);
  492. list_add(&node->all, &all_head);
  493. return node;
  494. err_nomem:
  495. kfree(node);
  496. pr_warn("out of memory\n");
  497. return NULL;
  498. }
  499. /* Remove symbolic links associated with node. */
  500. static void remove_links(struct gcov_node *node)
  501. {
  502. int i;
  503. if (!node->links)
  504. return;
  505. for (i = 0; gcov_link[i].ext; i++)
  506. debugfs_remove(node->links[i]);
  507. kfree(node->links);
  508. node->links = NULL;
  509. }
  510. /*
  511. * Remove node from all lists and debugfs and release associated resources.
  512. * Needs to be called with node_lock held.
  513. */
  514. static void release_node(struct gcov_node *node)
  515. {
  516. list_del(&node->list);
  517. list_del(&node->all);
  518. debugfs_remove(node->dentry);
  519. remove_links(node);
  520. kfree(node->loaded_info);
  521. if (node->unloaded_info)
  522. gcov_info_free(node->unloaded_info);
  523. kfree(node);
  524. }
  525. /* Release node and empty parents. Needs to be called with node_lock held. */
  526. static void remove_node(struct gcov_node *node)
  527. {
  528. struct gcov_node *parent;
  529. while ((node != &root_node) && list_empty(&node->children)) {
  530. parent = node->parent;
  531. release_node(node);
  532. node = parent;
  533. }
  534. }
  535. /*
  536. * Find child node with given basename. Needs to be called with node_lock
  537. * held.
  538. */
  539. static struct gcov_node *get_child_by_name(struct gcov_node *parent,
  540. const char *name)
  541. {
  542. struct gcov_node *node;
  543. list_for_each_entry(node, &parent->children, list) {
  544. if (strcmp(node->name, name) == 0)
  545. return node;
  546. }
  547. return NULL;
  548. }
  549. /*
  550. * write() implementation for reset file. Reset all profiling data to zero
  551. * and remove nodes for which all associated object files are unloaded.
  552. */
  553. static ssize_t reset_write(struct file *file, const char __user *addr,
  554. size_t len, loff_t *pos)
  555. {
  556. struct gcov_node *node;
  557. mutex_lock(&node_lock);
  558. restart:
  559. list_for_each_entry(node, &all_head, all) {
  560. if (node->num_loaded > 0)
  561. reset_node(node);
  562. else if (list_empty(&node->children)) {
  563. remove_node(node);
  564. /* Several nodes may have gone - restart loop. */
  565. goto restart;
  566. }
  567. }
  568. mutex_unlock(&node_lock);
  569. return len;
  570. }
  571. /* read() implementation for reset file. Unused. */
  572. static ssize_t reset_read(struct file *file, char __user *addr, size_t len,
  573. loff_t *pos)
  574. {
  575. /* Allow read operation so that a recursive copy won't fail. */
  576. return 0;
  577. }
  578. static const struct file_operations gcov_reset_fops = {
  579. .write = reset_write,
  580. .read = reset_read,
  581. .llseek = noop_llseek,
  582. };
  583. /*
  584. * Create a node for a given profiling data set and add it to all lists and
  585. * debugfs. Needs to be called with node_lock held.
  586. */
  587. static void add_node(struct gcov_info *info)
  588. {
  589. char *filename;
  590. char *curr;
  591. char *next;
  592. struct gcov_node *parent;
  593. struct gcov_node *node;
  594. filename = kstrdup(gcov_info_filename(info), GFP_KERNEL);
  595. if (!filename)
  596. return;
  597. parent = &root_node;
  598. /* Create directory nodes along the path. */
  599. for (curr = filename; (next = strchr(curr, '/')); curr = next + 1) {
  600. if (curr == next)
  601. continue;
  602. *next = 0;
  603. if (strcmp(curr, ".") == 0)
  604. continue;
  605. if (strcmp(curr, "..") == 0) {
  606. if (!parent->parent)
  607. goto err_remove;
  608. parent = parent->parent;
  609. continue;
  610. }
  611. node = get_child_by_name(parent, curr);
  612. if (!node) {
  613. node = new_node(parent, NULL, curr);
  614. if (!node)
  615. goto err_remove;
  616. }
  617. parent = node;
  618. }
  619. /* Create file node. */
  620. node = new_node(parent, info, curr);
  621. if (!node)
  622. goto err_remove;
  623. out:
  624. kfree(filename);
  625. return;
  626. err_remove:
  627. remove_node(parent);
  628. goto out;
  629. }
  630. /*
  631. * Associate a profiling data set with an existing node. Needs to be called
  632. * with node_lock held.
  633. */
  634. static void add_info(struct gcov_node *node, struct gcov_info *info)
  635. {
  636. struct gcov_info **loaded_info;
  637. int num = node->num_loaded;
  638. /*
  639. * Prepare new array. This is done first to simplify cleanup in
  640. * case the new data set is incompatible, the node only contains
  641. * unloaded data sets and there's not enough memory for the array.
  642. */
  643. loaded_info = kcalloc(num + 1, sizeof(struct gcov_info *), GFP_KERNEL);
  644. if (!loaded_info) {
  645. pr_warn("could not add '%s' (out of memory)\n",
  646. gcov_info_filename(info));
  647. return;
  648. }
  649. memcpy(loaded_info, node->loaded_info,
  650. num * sizeof(struct gcov_info *));
  651. loaded_info[num] = info;
  652. /* Check if the new data set is compatible. */
  653. if (num == 0) {
  654. /*
  655. * A module was unloaded, modified and reloaded. The new
  656. * data set replaces the copy of the last one.
  657. */
  658. if (!gcov_info_is_compatible(node->unloaded_info, info)) {
  659. pr_warn("discarding saved data for %s "
  660. "(incompatible version)\n",
  661. gcov_info_filename(info));
  662. gcov_info_free(node->unloaded_info);
  663. node->unloaded_info = NULL;
  664. }
  665. } else {
  666. /*
  667. * Two different versions of the same object file are loaded.
  668. * The initial one takes precedence.
  669. */
  670. if (!gcov_info_is_compatible(node->loaded_info[0], info)) {
  671. pr_warn("could not add '%s' (incompatible "
  672. "version)\n", gcov_info_filename(info));
  673. kfree(loaded_info);
  674. return;
  675. }
  676. }
  677. /* Overwrite previous array. */
  678. kfree(node->loaded_info);
  679. node->loaded_info = loaded_info;
  680. node->num_loaded = num + 1;
  681. }
  682. /*
  683. * Return the index of a profiling data set associated with a node.
  684. */
  685. static int get_info_index(struct gcov_node *node, struct gcov_info *info)
  686. {
  687. int i;
  688. for (i = 0; i < node->num_loaded; i++) {
  689. if (node->loaded_info[i] == info)
  690. return i;
  691. }
  692. return -ENOENT;
  693. }
  694. /*
  695. * Save the data of a profiling data set which is being unloaded.
  696. */
  697. static void save_info(struct gcov_node *node, struct gcov_info *info)
  698. {
  699. if (node->unloaded_info)
  700. gcov_info_add(node->unloaded_info, info);
  701. else {
  702. node->unloaded_info = gcov_info_dup(info);
  703. if (!node->unloaded_info) {
  704. pr_warn("could not save data for '%s' "
  705. "(out of memory)\n",
  706. gcov_info_filename(info));
  707. }
  708. }
  709. }
  710. /*
  711. * Disassociate a profiling data set from a node. Needs to be called with
  712. * node_lock held.
  713. */
  714. static void remove_info(struct gcov_node *node, struct gcov_info *info)
  715. {
  716. int i;
  717. i = get_info_index(node, info);
  718. if (i < 0) {
  719. pr_warn("could not remove '%s' (not found)\n",
  720. gcov_info_filename(info));
  721. return;
  722. }
  723. if (gcov_persist)
  724. save_info(node, info);
  725. /* Shrink array. */
  726. node->loaded_info[i] = node->loaded_info[node->num_loaded - 1];
  727. node->num_loaded--;
  728. if (node->num_loaded > 0)
  729. return;
  730. /* Last loaded data set was removed. */
  731. kfree(node->loaded_info);
  732. node->loaded_info = NULL;
  733. node->num_loaded = 0;
  734. if (!node->unloaded_info)
  735. remove_node(node);
  736. }
  737. /*
  738. * Callback to create/remove profiling files when code compiled with
  739. * -fprofile-arcs is loaded/unloaded.
  740. */
  741. void gcov_event(enum gcov_action action, struct gcov_info *info)
  742. {
  743. struct gcov_node *node;
  744. mutex_lock(&node_lock);
  745. node = get_node_by_name(gcov_info_filename(info));
  746. switch (action) {
  747. case GCOV_ADD:
  748. if (node)
  749. add_info(node, info);
  750. else
  751. add_node(info);
  752. break;
  753. case GCOV_REMOVE:
  754. if (node)
  755. remove_info(node, info);
  756. else {
  757. pr_warn("could not remove '%s' (not found)\n",
  758. gcov_info_filename(info));
  759. }
  760. break;
  761. }
  762. mutex_unlock(&node_lock);
  763. }
  764. /* Create debugfs entries. */
  765. static __init int gcov_fs_init(void)
  766. {
  767. init_node(&root_node, NULL, NULL, NULL);
  768. /*
  769. * /sys/kernel/debug/gcov will be parent for the reset control file
  770. * and all profiling files.
  771. */
  772. root_node.dentry = debugfs_create_dir("gcov", NULL);
  773. /*
  774. * Create reset file which resets all profiling counts when written
  775. * to.
  776. */
  777. debugfs_create_file("reset", 0600, root_node.dentry, NULL,
  778. &gcov_reset_fops);
  779. /* Replay previous events to get our fs hierarchy up-to-date. */
  780. gcov_enable_events();
  781. return 0;
  782. }
  783. device_initcall(gcov_fs_init);