xref: /linux-6.15/lib/codetag.c (revision 916cc516)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/codetag.h>
3 #include <linux/idr.h>
4 #include <linux/kallsyms.h>
5 #include <linux/module.h>
6 #include <linux/seq_buf.h>
7 #include <linux/slab.h>
8 
9 struct codetag_type {
10 	struct list_head link;
11 	unsigned int count;
12 	struct idr mod_idr;
13 	struct rw_semaphore mod_lock; /* protects mod_idr */
14 	struct codetag_type_desc desc;
15 };
16 
17 struct codetag_range {
18 	struct codetag *start;
19 	struct codetag *stop;
20 };
21 
22 struct codetag_module {
23 	struct module *mod;
24 	struct codetag_range range;
25 };
26 
27 static DEFINE_MUTEX(codetag_lock);
28 static LIST_HEAD(codetag_types);
29 
30 void codetag_lock_module_list(struct codetag_type *cttype, bool lock)
31 {
32 	if (lock)
33 		down_read(&cttype->mod_lock);
34 	else
35 		up_read(&cttype->mod_lock);
36 }
37 
38 struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
39 {
40 	struct codetag_iterator iter = {
41 		.cttype = cttype,
42 		.cmod = NULL,
43 		.mod_id = 0,
44 		.ct = NULL,
45 	};
46 
47 	return iter;
48 }
49 
50 static inline struct codetag *get_first_module_ct(struct codetag_module *cmod)
51 {
52 	return cmod->range.start < cmod->range.stop ? cmod->range.start : NULL;
53 }
54 
55 static inline
56 struct codetag *get_next_module_ct(struct codetag_iterator *iter)
57 {
58 	struct codetag *res = (struct codetag *)
59 			((char *)iter->ct + iter->cttype->desc.tag_size);
60 
61 	return res < iter->cmod->range.stop ? res : NULL;
62 }
63 
64 struct codetag *codetag_next_ct(struct codetag_iterator *iter)
65 {
66 	struct codetag_type *cttype = iter->cttype;
67 	struct codetag_module *cmod;
68 	struct codetag *ct;
69 
70 	lockdep_assert_held(&cttype->mod_lock);
71 
72 	if (unlikely(idr_is_empty(&cttype->mod_idr)))
73 		return NULL;
74 
75 	ct = NULL;
76 	while (true) {
77 		cmod = idr_find(&cttype->mod_idr, iter->mod_id);
78 
79 		/* If module was removed move to the next one */
80 		if (!cmod)
81 			cmod = idr_get_next_ul(&cttype->mod_idr,
82 					       &iter->mod_id);
83 
84 		/* Exit if no more modules */
85 		if (!cmod)
86 			break;
87 
88 		if (cmod != iter->cmod) {
89 			iter->cmod = cmod;
90 			ct = get_first_module_ct(cmod);
91 		} else
92 			ct = get_next_module_ct(iter);
93 
94 		if (ct)
95 			break;
96 
97 		iter->mod_id++;
98 	}
99 
100 	iter->ct = ct;
101 	return ct;
102 }
103 
104 void codetag_to_text(struct seq_buf *out, struct codetag *ct)
105 {
106 	if (ct->modname)
107 		seq_buf_printf(out, "%s:%u [%s] func:%s",
108 			       ct->filename, ct->lineno,
109 			       ct->modname, ct->function);
110 	else
111 		seq_buf_printf(out, "%s:%u func:%s",
112 			       ct->filename, ct->lineno, ct->function);
113 }
114 
115 static inline size_t range_size(const struct codetag_type *cttype,
116 				const struct codetag_range *range)
117 {
118 	return ((char *)range->stop - (char *)range->start) /
119 			cttype->desc.tag_size;
120 }
121 
122 #ifdef CONFIG_MODULES
123 static void *get_symbol(struct module *mod, const char *prefix, const char *name)
124 {
125 	DECLARE_SEQ_BUF(sb, KSYM_NAME_LEN);
126 	const char *buf;
127 
128 	seq_buf_printf(&sb, "%s%s", prefix, name);
129 	if (seq_buf_has_overflowed(&sb))
130 		return NULL;
131 
132 	buf = seq_buf_str(&sb);
133 	return mod ?
134 		(void *)find_kallsyms_symbol_value(mod, buf) :
135 		(void *)kallsyms_lookup_name(buf);
136 }
137 
138 static struct codetag_range get_section_range(struct module *mod,
139 					      const char *section)
140 {
141 	return (struct codetag_range) {
142 		get_symbol(mod, "__start_", section),
143 		get_symbol(mod, "__stop_", section),
144 	};
145 }
146 
147 static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
148 {
149 	struct codetag_range range;
150 	struct codetag_module *cmod;
151 	int err;
152 
153 	range = get_section_range(mod, cttype->desc.section);
154 	if (!range.start || !range.stop) {
155 		pr_warn("Failed to load code tags of type %s from the module %s\n",
156 			cttype->desc.section,
157 			mod ? mod->name : "(built-in)");
158 		return -EINVAL;
159 	}
160 
161 	/* Ignore empty ranges */
162 	if (range.start == range.stop)
163 		return 0;
164 
165 	BUG_ON(range.start > range.stop);
166 
167 	cmod = kmalloc(sizeof(*cmod), GFP_KERNEL);
168 	if (unlikely(!cmod))
169 		return -ENOMEM;
170 
171 	cmod->mod = mod;
172 	cmod->range = range;
173 
174 	down_write(&cttype->mod_lock);
175 	err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
176 	if (err >= 0)
177 		cttype->count += range_size(cttype, &range);
178 	up_write(&cttype->mod_lock);
179 
180 	if (err < 0) {
181 		kfree(cmod);
182 		return err;
183 	}
184 
185 	return 0;
186 }
187 
188 #else /* CONFIG_MODULES */
189 static int codetag_module_init(struct codetag_type *cttype, struct module *mod) { return 0; }
190 #endif /* CONFIG_MODULES */
191 
192 struct codetag_type *
193 codetag_register_type(const struct codetag_type_desc *desc)
194 {
195 	struct codetag_type *cttype;
196 	int err;
197 
198 	BUG_ON(desc->tag_size <= 0);
199 
200 	cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
201 	if (unlikely(!cttype))
202 		return ERR_PTR(-ENOMEM);
203 
204 	cttype->desc = *desc;
205 	idr_init(&cttype->mod_idr);
206 	init_rwsem(&cttype->mod_lock);
207 
208 	err = codetag_module_init(cttype, NULL);
209 	if (unlikely(err)) {
210 		kfree(cttype);
211 		return ERR_PTR(err);
212 	}
213 
214 	mutex_lock(&codetag_lock);
215 	list_add_tail(&cttype->link, &codetag_types);
216 	mutex_unlock(&codetag_lock);
217 
218 	return cttype;
219 }
220