1 // SPDX-License-Identifier: GPL-2.0
3 * This code exports profiling data as debugfs files to userspace.
5 * Copyright IBM Corp. 2009
6 * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
8 * Uses gcc-internal data definitions.
9 * Based on the gcov-kernel patch by:
10 * Hubertus Franke <frankeh@us.ibm.com>
11 * Nigel Hinds <nhinds@us.ibm.com>
12 * Rajan Ravindran <rajancr@us.ibm.com>
13 * Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
18 #define pr_fmt(fmt) "gcov: " fmt
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/debugfs.h>
24 #include <linux/list.h>
25 #include <linux/string.h>
26 #include <linux/slab.h>
27 #include <linux/mutex.h>
28 #include <linux/seq_file.h>
33 * struct gcov_node - represents a debugfs entry
34 * @list: list head for child node list
35 * @children: child nodes
36 * @all: list head for list of all nodes
37 * @parent: parent node
38 * @loaded_info: array of pointers to profiling data sets for loaded object
40 * @num_loaded: number of profiling data sets for loaded object files.
41 * @unloaded_info: accumulated copy of profiling data sets for unloaded
42 * object files. Used only when gcov_persist=1.
43 * @dentry: main debugfs entry, either a directory or data file
44 * @links: associated symbolic links
45 * @name: data file basename
47 * struct gcov_node represents an entity within the gcov/ subdirectory
48 * of debugfs. There are directory and data file nodes. The latter represent
49 * the actual synthesized data file plus any associated symbolic links which
50 * are needed by the gcov tool to work correctly.
53 struct list_head list
;
54 struct list_head children
;
56 struct gcov_node
*parent
;
57 struct gcov_info
**loaded_info
;
58 struct gcov_info
*unloaded_info
;
59 struct dentry
*dentry
;
60 struct dentry
**links
;
65 static const char objtree
[] = OBJTREE
;
66 static const char srctree
[] = SRCTREE
;
67 static struct gcov_node root_node
;
68 static LIST_HEAD(all_head
);
69 static DEFINE_MUTEX(node_lock
);
71 /* If non-zero, keep copies of profiling data for unloaded modules. */
72 static int gcov_persist
= 1;
74 static int __init
gcov_persist_setup(char *str
)
78 if (kstrtoul(str
, 0, &val
)) {
79 pr_warn("invalid gcov_persist parameter '%s'\n", str
);
83 pr_info("setting gcov_persist to %d\n", gcov_persist
);
87 __setup("gcov_persist=", gcov_persist_setup
);
89 #define ITER_STRIDE PAGE_SIZE
92 * struct gcov_iterator - specifies current file position in logical records
93 * @info: associated profiling data
94 * @buffer: buffer containing file data
95 * @size: size of buffer
96 * @pos: current position in file
98 struct gcov_iterator
{
99 struct gcov_info
*info
;
102 char buffer
[] __counted_by(size
);
106 * gcov_iter_new - allocate and initialize profiling data iterator
107 * @info: profiling data set to be iterated
109 * Return file iterator on success, %NULL otherwise.
111 static struct gcov_iterator
*gcov_iter_new(struct gcov_info
*info
)
113 struct gcov_iterator
*iter
;
116 /* Dry-run to get the actual buffer size. */
117 size
= convert_to_gcda(NULL
, info
);
119 iter
= kvmalloc(struct_size(iter
, buffer
, size
), GFP_KERNEL
);
125 convert_to_gcda(iter
->buffer
, info
);
132 * gcov_iter_free - free iterator data
133 * @iter: file iterator
135 static void gcov_iter_free(struct gcov_iterator
*iter
)
141 * gcov_iter_get_info - return profiling data set for given file iterator
142 * @iter: file iterator
144 static struct gcov_info
*gcov_iter_get_info(struct gcov_iterator
*iter
)
150 * gcov_iter_start - reset file iterator to starting position
151 * @iter: file iterator
153 static void gcov_iter_start(struct gcov_iterator
*iter
)
159 * gcov_iter_next - advance file iterator to next logical record
160 * @iter: file iterator
162 * Return zero if new position is valid, non-zero if iterator has reached end.
164 static int gcov_iter_next(struct gcov_iterator
*iter
)
166 if (iter
->pos
< iter
->size
)
167 iter
->pos
+= ITER_STRIDE
;
169 if (iter
->pos
>= iter
->size
)
176 * gcov_iter_write - write data for current pos to seq_file
177 * @iter: file iterator
178 * @seq: seq_file handle
180 * Return zero on success, non-zero otherwise.
182 static int gcov_iter_write(struct gcov_iterator
*iter
, struct seq_file
*seq
)
186 if (iter
->pos
>= iter
->size
)
190 if (iter
->pos
+ len
> iter
->size
)
191 len
= iter
->size
- iter
->pos
;
193 seq_write(seq
, iter
->buffer
+ iter
->pos
, len
);
199 * seq_file.start() implementation for gcov data files. Note that the
200 * gcov_iterator interface is designed to be more restrictive than seq_file
201 * (no start from arbitrary position, etc.), to simplify the iterator
204 static void *gcov_seq_start(struct seq_file
*seq
, loff_t
*pos
)
208 gcov_iter_start(seq
->private);
209 for (i
= 0; i
< *pos
; i
++) {
210 if (gcov_iter_next(seq
->private))
216 /* seq_file.next() implementation for gcov data files. */
217 static void *gcov_seq_next(struct seq_file
*seq
, void *data
, loff_t
*pos
)
219 struct gcov_iterator
*iter
= data
;
222 if (gcov_iter_next(iter
))
228 /* seq_file.show() implementation for gcov data files. */
229 static int gcov_seq_show(struct seq_file
*seq
, void *data
)
231 struct gcov_iterator
*iter
= data
;
233 if (gcov_iter_write(iter
, seq
))
238 static void gcov_seq_stop(struct seq_file
*seq
, void *data
)
243 static const struct seq_operations gcov_seq_ops
= {
244 .start
= gcov_seq_start
,
245 .next
= gcov_seq_next
,
246 .show
= gcov_seq_show
,
247 .stop
= gcov_seq_stop
,
251 * Return a profiling data set associated with the given node. This is
252 * either a data set for a loaded object file or a data set copy in case
253 * all associated object files have been unloaded.
255 static struct gcov_info
*get_node_info(struct gcov_node
*node
)
257 if (node
->num_loaded
> 0)
258 return node
->loaded_info
[0];
260 return node
->unloaded_info
;
264 * Return a newly allocated profiling data set which contains the sum of
265 * all profiling data associated with the given node.
267 static struct gcov_info
*get_accumulated_info(struct gcov_node
*node
)
269 struct gcov_info
*info
;
272 if (node
->unloaded_info
)
273 info
= gcov_info_dup(node
->unloaded_info
);
275 info
= gcov_info_dup(node
->loaded_info
[i
++]);
278 for (; i
< node
->num_loaded
; i
++)
279 gcov_info_add(info
, node
->loaded_info
[i
]);
285 * open() implementation for gcov data files. Create a copy of the profiling
286 * data set and initialize the iterator and seq_file interface.
288 static int gcov_seq_open(struct inode
*inode
, struct file
*file
)
290 struct gcov_node
*node
= inode
->i_private
;
291 struct gcov_iterator
*iter
;
292 struct seq_file
*seq
;
293 struct gcov_info
*info
;
296 mutex_lock(&node_lock
);
298 * Read from a profiling data copy to minimize reference tracking
299 * complexity and concurrent access and to keep accumulating multiple
300 * profiling data sets associated with one node simple.
302 info
= get_accumulated_info(node
);
305 iter
= gcov_iter_new(info
);
308 rc
= seq_open(file
, &gcov_seq_ops
);
310 goto err_free_iter_info
;
311 seq
= file
->private_data
;
314 mutex_unlock(&node_lock
);
318 gcov_iter_free(iter
);
320 gcov_info_free(info
);
325 * release() implementation for gcov data files. Release resources allocated
328 static int gcov_seq_release(struct inode
*inode
, struct file
*file
)
330 struct gcov_iterator
*iter
;
331 struct gcov_info
*info
;
332 struct seq_file
*seq
;
334 seq
= file
->private_data
;
336 info
= gcov_iter_get_info(iter
);
337 gcov_iter_free(iter
);
338 gcov_info_free(info
);
339 seq_release(inode
, file
);
345 * Find a node by the associated data file name. Needs to be called with
348 static struct gcov_node
*get_node_by_name(const char *name
)
350 struct gcov_node
*node
;
351 struct gcov_info
*info
;
353 list_for_each_entry(node
, &all_head
, all
) {
354 info
= get_node_info(node
);
355 if (info
&& (strcmp(gcov_info_filename(info
), name
) == 0))
363 * Reset all profiling data associated with the specified node.
365 static void reset_node(struct gcov_node
*node
)
369 if (node
->unloaded_info
)
370 gcov_info_reset(node
->unloaded_info
);
371 for (i
= 0; i
< node
->num_loaded
; i
++)
372 gcov_info_reset(node
->loaded_info
[i
]);
375 static void remove_node(struct gcov_node
*node
);
378 * write() implementation for gcov data files. Reset profiling data for the
379 * corresponding file. If all associated object files have been unloaded,
380 * remove the debug fs node as well.
382 static ssize_t
gcov_seq_write(struct file
*file
, const char __user
*addr
,
383 size_t len
, loff_t
*pos
)
385 struct seq_file
*seq
;
386 struct gcov_info
*info
;
387 struct gcov_node
*node
;
389 seq
= file
->private_data
;
390 info
= gcov_iter_get_info(seq
->private);
391 mutex_lock(&node_lock
);
392 node
= get_node_by_name(gcov_info_filename(info
));
394 /* Reset counts or remove node for unloaded modules. */
395 if (node
->num_loaded
== 0)
400 /* Reset counts for open file. */
401 gcov_info_reset(info
);
402 mutex_unlock(&node_lock
);
408 * Given a string <path> representing a file path of format:
410 * construct and return a new string:
411 * <dir/>path/to/file.<ext>
413 static char *link_target(const char *dir
, const char *path
, const char *ext
)
419 copy
= kstrdup(path
, GFP_KERNEL
);
422 old_ext
= strrchr(copy
, '.');
426 target
= kasprintf(GFP_KERNEL
, "%s/%s.%s", dir
, copy
, ext
);
428 target
= kasprintf(GFP_KERNEL
, "%s.%s", copy
, ext
);
435 * Construct a string representing the symbolic link target for the given
436 * gcov data file name and link type. Depending on the link type and the
437 * location of the data file, the link target can either point to a
438 * subdirectory of srctree, objtree or in an external location.
440 static char *get_link_target(const char *filename
, const struct gcov_link
*ext
)
445 if (strncmp(filename
, objtree
, strlen(objtree
)) == 0) {
446 rel
= filename
+ strlen(objtree
) + 1;
447 if (ext
->dir
== SRC_TREE
)
448 result
= link_target(srctree
, rel
, ext
->ext
);
450 result
= link_target(objtree
, rel
, ext
->ext
);
452 /* External compilation. */
453 result
= link_target(NULL
, filename
, ext
->ext
);
459 #define SKEW_PREFIX ".tmp_"
462 * For a filename .tmp_filename.ext return filename.ext. Needed to compensate
463 * for filename skewing caused by the mod-versioning mechanism.
465 static const char *deskew(const char *basename
)
467 if (strncmp(basename
, SKEW_PREFIX
, sizeof(SKEW_PREFIX
) - 1) == 0)
468 return basename
+ sizeof(SKEW_PREFIX
) - 1;
473 * Create links to additional files (usually .c and .gcno files) which the
474 * gcov tool expects to find in the same directory as the gcov data file.
476 static void add_links(struct gcov_node
*node
, struct dentry
*parent
)
478 const char *basename
;
483 for (num
= 0; gcov_link
[num
].ext
; num
++)
485 node
->links
= kcalloc(num
, sizeof(struct dentry
*), GFP_KERNEL
);
488 for (i
= 0; i
< num
; i
++) {
489 target
= get_link_target(
490 gcov_info_filename(get_node_info(node
)),
494 basename
= kbasename(target
);
495 if (basename
== target
)
497 node
->links
[i
] = debugfs_create_symlink(deskew(basename
),
506 debugfs_remove(node
->links
[i
]);
511 static const struct file_operations gcov_data_fops
= {
512 .open
= gcov_seq_open
,
513 .release
= gcov_seq_release
,
516 .write
= gcov_seq_write
,
519 /* Basic initialization of a new node. */
520 static void init_node(struct gcov_node
*node
, struct gcov_info
*info
,
521 const char *name
, struct gcov_node
*parent
)
523 INIT_LIST_HEAD(&node
->list
);
524 INIT_LIST_HEAD(&node
->children
);
525 INIT_LIST_HEAD(&node
->all
);
526 if (node
->loaded_info
) {
527 node
->loaded_info
[0] = info
;
528 node
->num_loaded
= 1;
530 node
->parent
= parent
;
532 strcpy(node
->name
, name
);
536 * Create a new node and associated debugfs entry. Needs to be called with
539 static struct gcov_node
*new_node(struct gcov_node
*parent
,
540 struct gcov_info
*info
, const char *name
)
542 struct gcov_node
*node
;
544 node
= kzalloc(sizeof(struct gcov_node
) + strlen(name
) + 1, GFP_KERNEL
);
548 node
->loaded_info
= kcalloc(1, sizeof(struct gcov_info
*),
550 if (!node
->loaded_info
)
553 init_node(node
, info
, name
, parent
);
554 /* Differentiate between gcov data file nodes and directory nodes. */
556 node
->dentry
= debugfs_create_file(deskew(node
->name
), 0600,
557 parent
->dentry
, node
, &gcov_data_fops
);
559 node
->dentry
= debugfs_create_dir(node
->name
, parent
->dentry
);
561 add_links(node
, parent
->dentry
);
562 list_add(&node
->list
, &parent
->children
);
563 list_add(&node
->all
, &all_head
);
569 pr_warn("out of memory\n");
573 /* Remove symbolic links associated with node. */
574 static void remove_links(struct gcov_node
*node
)
580 for (i
= 0; gcov_link
[i
].ext
; i
++)
581 debugfs_remove(node
->links
[i
]);
587 * Remove node from all lists and debugfs and release associated resources.
588 * Needs to be called with node_lock held.
590 static void release_node(struct gcov_node
*node
)
592 list_del(&node
->list
);
593 list_del(&node
->all
);
594 debugfs_remove(node
->dentry
);
596 kfree(node
->loaded_info
);
597 if (node
->unloaded_info
)
598 gcov_info_free(node
->unloaded_info
);
602 /* Release node and empty parents. Needs to be called with node_lock held. */
603 static void remove_node(struct gcov_node
*node
)
605 struct gcov_node
*parent
;
607 while ((node
!= &root_node
) && list_empty(&node
->children
)) {
608 parent
= node
->parent
;
615 * Find child node with given basename. Needs to be called with node_lock
618 static struct gcov_node
*get_child_by_name(struct gcov_node
*parent
,
621 struct gcov_node
*node
;
623 list_for_each_entry(node
, &parent
->children
, list
) {
624 if (strcmp(node
->name
, name
) == 0)
632 * write() implementation for reset file. Reset all profiling data to zero
633 * and remove nodes for which all associated object files are unloaded.
635 static ssize_t
reset_write(struct file
*file
, const char __user
*addr
,
636 size_t len
, loff_t
*pos
)
638 struct gcov_node
*node
;
640 mutex_lock(&node_lock
);
642 list_for_each_entry(node
, &all_head
, all
) {
643 if (node
->num_loaded
> 0)
645 else if (list_empty(&node
->children
)) {
647 /* Several nodes may have gone - restart loop. */
651 mutex_unlock(&node_lock
);
656 /* read() implementation for reset file. Unused. */
657 static ssize_t
reset_read(struct file
*file
, char __user
*addr
, size_t len
,
660 /* Allow read operation so that a recursive copy won't fail. */
664 static const struct file_operations gcov_reset_fops
= {
665 .write
= reset_write
,
667 .llseek
= noop_llseek
,
671 * Create a node for a given profiling data set and add it to all lists and
672 * debugfs. Needs to be called with node_lock held.
674 static void add_node(struct gcov_info
*info
)
679 struct gcov_node
*parent
;
680 struct gcov_node
*node
;
682 filename
= kstrdup(gcov_info_filename(info
), GFP_KERNEL
);
686 /* Create directory nodes along the path. */
687 for (curr
= filename
; (next
= strchr(curr
, '/')); curr
= next
+ 1) {
691 if (strcmp(curr
, ".") == 0)
693 if (strcmp(curr
, "..") == 0) {
696 parent
= parent
->parent
;
699 node
= get_child_by_name(parent
, curr
);
701 node
= new_node(parent
, NULL
, curr
);
707 /* Create file node. */
708 node
= new_node(parent
, info
, curr
);
721 * Associate a profiling data set with an existing node. Needs to be called
722 * with node_lock held.
724 static void add_info(struct gcov_node
*node
, struct gcov_info
*info
)
726 struct gcov_info
**loaded_info
;
727 int num
= node
->num_loaded
;
730 * Prepare new array. This is done first to simplify cleanup in
731 * case the new data set is incompatible, the node only contains
732 * unloaded data sets and there's not enough memory for the array.
734 loaded_info
= kcalloc(num
+ 1, sizeof(struct gcov_info
*), GFP_KERNEL
);
736 pr_warn("could not add '%s' (out of memory)\n",
737 gcov_info_filename(info
));
740 memcpy(loaded_info
, node
->loaded_info
,
741 num
* sizeof(struct gcov_info
*));
742 loaded_info
[num
] = info
;
743 /* Check if the new data set is compatible. */
746 * A module was unloaded, modified and reloaded. The new
747 * data set replaces the copy of the last one.
749 if (!gcov_info_is_compatible(node
->unloaded_info
, info
)) {
750 pr_warn("discarding saved data for %s "
751 "(incompatible version)\n",
752 gcov_info_filename(info
));
753 gcov_info_free(node
->unloaded_info
);
754 node
->unloaded_info
= NULL
;
758 * Two different versions of the same object file are loaded.
759 * The initial one takes precedence.
761 if (!gcov_info_is_compatible(node
->loaded_info
[0], info
)) {
762 pr_warn("could not add '%s' (incompatible "
763 "version)\n", gcov_info_filename(info
));
768 /* Overwrite previous array. */
769 kfree(node
->loaded_info
);
770 node
->loaded_info
= loaded_info
;
771 node
->num_loaded
= num
+ 1;
775 * Return the index of a profiling data set associated with a node.
777 static int get_info_index(struct gcov_node
*node
, struct gcov_info
*info
)
781 for (i
= 0; i
< node
->num_loaded
; i
++) {
782 if (node
->loaded_info
[i
] == info
)
789 * Save the data of a profiling data set which is being unloaded.
791 static void save_info(struct gcov_node
*node
, struct gcov_info
*info
)
793 if (node
->unloaded_info
)
794 gcov_info_add(node
->unloaded_info
, info
);
796 node
->unloaded_info
= gcov_info_dup(info
);
797 if (!node
->unloaded_info
) {
798 pr_warn("could not save data for '%s' "
800 gcov_info_filename(info
));
806 * Disassociate a profiling data set from a node. Needs to be called with
809 static void remove_info(struct gcov_node
*node
, struct gcov_info
*info
)
813 i
= get_info_index(node
, info
);
815 pr_warn("could not remove '%s' (not found)\n",
816 gcov_info_filename(info
));
820 save_info(node
, info
);
822 node
->loaded_info
[i
] = node
->loaded_info
[node
->num_loaded
- 1];
824 if (node
->num_loaded
> 0)
826 /* Last loaded data set was removed. */
827 kfree(node
->loaded_info
);
828 node
->loaded_info
= NULL
;
829 node
->num_loaded
= 0;
830 if (!node
->unloaded_info
)
835 * Callback to create/remove profiling files when code compiled with
836 * -fprofile-arcs is loaded/unloaded.
838 void gcov_event(enum gcov_action action
, struct gcov_info
*info
)
840 struct gcov_node
*node
;
842 mutex_lock(&node_lock
);
843 node
= get_node_by_name(gcov_info_filename(info
));
847 add_info(node
, info
);
853 remove_info(node
, info
);
855 pr_warn("could not remove '%s' (not found)\n",
856 gcov_info_filename(info
));
860 mutex_unlock(&node_lock
);
863 /* Create debugfs entries. */
864 static __init
int gcov_fs_init(void)
866 init_node(&root_node
, NULL
, NULL
, NULL
);
868 * /sys/kernel/debug/gcov will be parent for the reset control file
869 * and all profiling files.
871 root_node
.dentry
= debugfs_create_dir("gcov", NULL
);
873 * Create reset file which resets all profiling counts when written
876 debugfs_create_file("reset", 0600, root_node
.dentry
, NULL
,
878 /* Replay previous events to get our fs hierarchy up-to-date. */
879 gcov_enable_events();
882 device_initcall(gcov_fs_init
);