Similar to KCOV_TRACE_CMP mode, KCOV_TRACE_UNIQ_CMP stores unique CMP data
into area.
Signed-off-by: Jiao, Joey <quic_jiangenj@quicinc.com>
---
include/linux/kcov.h | 2 +
include/uapi/linux/kcov.h | 2 +
kernel/kcov.c | 112 ++++++++++++++++++++++++++++++++--------------
3 files changed, 83 insertions(+), 33 deletions(-)
diff --git a/include/linux/kcov.h b/include/linux/kcov.h
index 56b858205ba16c47fc72bda9938c98f034503c8c..a78d78164bf75368c71a958a5438fc3ee68c95ca 100644
--- a/include/linux/kcov.h
+++ b/include/linux/kcov.h
@@ -27,6 +27,8 @@ enum kcov_mode {
KCOV_MODE_TRACE_UNIQ_PC = 16,
/* Collecting uniq edge mode. */
KCOV_MODE_TRACE_UNIQ_EDGE = 32,
+ /* Collecting uniq cmp mode. */
+ KCOV_MODE_TRACE_UNIQ_CMP = 64,
};
#define KCOV_IN_CTXSW (1 << 30)
diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h
index 9b2019f0ab8b8cb5426d2d6b74472fa1a7293817..08abfca273c9624dc54a2c70b12a4a9302700f26 100644
--- a/include/uapi/linux/kcov.h
+++ b/include/uapi/linux/kcov.h
@@ -39,6 +39,8 @@ enum {
KCOV_TRACE_UNIQ_PC = 2,
/* Collecting uniq edge mode. */
KCOV_TRACE_UNIQ_EDGE = 4,
+ /* Collecting uniq CMP mode. */
+ KCOV_TRACE_UNIQ_CMP = 8,
};
/*
diff --git a/kernel/kcov.c b/kernel/kcov.c
index c04bbec9ac3186a5145240de8ac609ad8a7ca733..af73c40114d23adedab8318e8657d24bf36ae865 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -36,6 +36,11 @@
struct kcov_entry {
unsigned long ent;
+#ifdef CONFIG_KCOV_ENABLE_COMPARISONS
+ unsigned long type;
+ unsigned long arg1;
+ unsigned long arg2;
+#endif
struct hlist_node node;
};
@@ -44,7 +49,7 @@ struct kcov_entry {
#define MIN_POOL_ALLOC_ORDER ilog2(roundup_pow_of_two(sizeof(struct kcov_entry)))
/*
- * kcov hashmap to store uniq pc, prealloced mem for kcov_entry
+ * kcov hashmap to store uniq pc|edge|cmp, prealloced mem for kcov_entry
* and area shared between kernel and userspace.
*/
struct kcov_map {
@@ -87,7 +92,7 @@ struct kcov {
unsigned long prev_pc;
/* Coverage buffer shared with user space. */
void *area;
- /* Coverage hashmap for unique pc. */
+ /* Coverage hashmap for unique pc|cmp. */
struct kcov_map *map;
/* Edge hashmap for unique edge. */
struct kcov_map *map_edge;
@@ -289,14 +294,23 @@ static notrace inline void kcov_map_add(struct kcov_map *map, struct kcov_entry
struct kcov *kcov;
struct kcov_entry *entry;
unsigned int key = hash_key(ent);
- unsigned long pos, *area;
+ unsigned long pos, start_index, end_pos, max_pos, *area;
kcov = t->kcov;
- hash_for_each_possible_rcu(map->buckets, entry, node, key) {
- if (entry->ent == ent->ent)
- return;
- }
+ if ((mode == KCOV_MODE_TRACE_UNIQ_PC ||
+ mode == KCOV_MODE_TRACE_UNIQ_EDGE))
+ hash_for_each_possible_rcu(map->buckets, entry, node, key) {
+ if (entry->ent == ent->ent)
+ return;
+ }
+ else
+ hash_for_each_possible_rcu(map->buckets, entry, node, key) {
+ if (entry->ent == ent->ent && entry->type == ent->type &&
+ entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
+ return;
+ }
+ }
entry = (struct kcov_entry *)gen_pool_alloc(map->pool, 1 << MIN_POOL_ALLOC_ORDER);
if (unlikely(!entry))
@@ -306,16 +320,31 @@ static notrace inline void kcov_map_add(struct kcov_map *map, struct kcov_entry
memcpy(entry, ent, sizeof(*entry));
hash_add_rcu(map->buckets, &entry->node, key);
- if (mode == KCOV_MODE_TRACE_UNIQ_PC)
+ if (mode == KCOV_MODE_TRACE_UNIQ_PC || mode == KCOV_MODE_TRACE_UNIQ_CMP)
area = t->kcov_area;
else
area = kcov->map_edge->area;
pos = READ_ONCE(area[0]) + 1;
- if (likely(pos < t->kcov_size)) {
- WRITE_ONCE(area[0], pos);
- barrier();
- area[pos] = ent->ent;
+ if (mode == KCOV_MODE_TRACE_UNIQ_PC || mode == KCOV_MODE_TRACE_UNIQ_EDGE) {
+ if (likely(pos < t->kcov_size)) {
+ WRITE_ONCE(area[0], pos);
+ barrier();
+ area[pos] = ent->ent;
+ }
+ } else {
+ start_index = 1 + (pos - 1) * KCOV_WORDS_PER_CMP;
+ max_pos = t->kcov_size * sizeof(unsigned long);
+ end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
+ if (likely(end_pos <= max_pos)) {
+ /* See comment in __sanitizer_cov_trace_pc(). */
+ WRITE_ONCE(area[0], pos);
+ barrier();
+ area[start_index] = ent->type;
+ area[start_index + 1] = ent->arg1;
+ area[start_index + 2] = ent->arg2;
+ area[start_index + 3] = ent->ent;
+ }
}
}
@@ -384,33 +413,44 @@ static void notrace write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip)
struct task_struct *t;
u64 *area;
u64 count, start_index, end_pos, max_pos;
+ struct kcov_entry entry = {0};
+ unsigned int mode;
t = current;
- if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t))
+ if (!check_kcov_mode(KCOV_MODE_TRACE_CMP | KCOV_MODE_TRACE_UNIQ_CMP, t))
return;
+ mode = t->kcov_mode;
ip = canonicalize_ip(ip);
- /*
- * We write all comparison arguments and types as u64.
- * The buffer was allocated for t->kcov_size unsigned longs.
- */
- area = (u64 *)t->kcov_area;
- max_pos = t->kcov_size * sizeof(unsigned long);
-
- count = READ_ONCE(area[0]);
-
- /* Every record is KCOV_WORDS_PER_CMP 64-bit words. */
- start_index = 1 + count * KCOV_WORDS_PER_CMP;
- end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
- if (likely(end_pos <= max_pos)) {
- /* See comment in __sanitizer_cov_trace_pc(). */
- WRITE_ONCE(area[0], count + 1);
- barrier();
- area[start_index] = type;
- area[start_index + 1] = arg1;
- area[start_index + 2] = arg2;
- area[start_index + 3] = ip;
+ if (mode == KCOV_MODE_TRACE_CMP) {
+ /*
+ * We write all comparison arguments and types as u64.
+ * The buffer was allocated for t->kcov_size unsigned longs.
+ */
+ area = (u64 *)t->kcov_area;
+ max_pos = t->kcov_size * sizeof(unsigned long);
+
+ count = READ_ONCE(area[0]);
+
+ /* Every record is KCOV_WORDS_PER_CMP 64-bit words. */
+ start_index = 1 + count * KCOV_WORDS_PER_CMP;
+ end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
+ if (likely(end_pos <= max_pos)) {
+ /* See comment in __sanitizer_cov_trace_pc(). */
+ WRITE_ONCE(area[0], count + 1);
+ barrier();
+ area[start_index] = type;
+ area[start_index + 1] = arg1;
+ area[start_index + 2] = arg2;
+ area[start_index + 3] = ip;
+ }
+ } else {
+ entry.type = type;
+ entry.arg1 = arg1;
+ entry.arg2 = arg2;
+ entry.ent = ip;
+ kcov_map_add(t->kcov->map, &entry, t, KCOV_MODE_TRACE_UNIQ_CMP);
}
}
@@ -730,6 +770,12 @@ static int kcov_get_mode(unsigned long arg)
mode |= KCOV_MODE_TRACE_UNIQ_PC;
if (arg & KCOV_TRACE_UNIQ_EDGE)
mode |= KCOV_MODE_TRACE_UNIQ_EDGE;
+ if (arg == KCOV_TRACE_UNIQ_CMP)
+#ifdef CONFIG_KCOV_ENABLE_COMPARISONS
+ mode = KCOV_MODE_TRACE_UNIQ_CMP;
+#else
+ return -EOPNOTSUPP;
+#endif
if (!mode)
return -EINVAL;
--
2.47.1
Hi Joey,
kernel test robot noticed the following build errors:
[auto build test ERROR on 9b2ffa6148b1e4468d08f7e0e7e371c43cac9ffe]
url: https://github.com/intel-lab-lkp/linux/commits/Jiao-Joey/kcov-introduce-new-kcov-KCOV_TRACE_UNIQ_PC-mode/20250114-133713
base: 9b2ffa6148b1e4468d08f7e0e7e371c43cac9ffe
patch link: https://lore.kernel.org/r/20250114-kcov-v1-4-004294b931a2%40quicinc.com
patch subject: [PATCH 4/7] kcov: introduce new kcov KCOV_TRACE_UNIQ_CMP mode
config: x86_64-randconfig-001-20250124 (https://download.01.org/0day-ci/archive/20250124/202501242043.KmrFufhL-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250124/202501242043.KmrFufhL-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501242043.KmrFufhL-lkp@intel.com/
All errors (new ones prefixed by >>):
>> kernel/kcov.c:309:41: error: no member named 'type' in 'struct kcov_entry'
309 | if (entry->ent == ent->ent && entry->type == ent->type &&
| ~~~~~ ^
kernel/kcov.c:309:54: error: no member named 'type' in 'struct kcov_entry'
309 | if (entry->ent == ent->ent && entry->type == ent->type &&
| ~~~ ^
>> kernel/kcov.c:310:15: error: no member named 'arg1' in 'struct kcov_entry'
310 | entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
| ~~~~~ ^
kernel/kcov.c:310:28: error: no member named 'arg1' in 'struct kcov_entry'
310 | entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
| ~~~ ^
>> kernel/kcov.c:310:43: error: no member named 'arg2' in 'struct kcov_entry'
310 | entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
| ~~~~~ ^
kernel/kcov.c:310:56: error: no member named 'arg2' in 'struct kcov_entry'
310 | entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
| ~~~ ^
kernel/kcov.c:343:29: error: no member named 'type' in 'struct kcov_entry'
343 | area[start_index] = ent->type;
| ~~~ ^
kernel/kcov.c:344:33: error: no member named 'arg1' in 'struct kcov_entry'
344 | area[start_index + 1] = ent->arg1;
| ~~~ ^
kernel/kcov.c:345:33: error: no member named 'arg2' in 'struct kcov_entry'
345 | area[start_index + 2] = ent->arg2;
| ~~~ ^
9 errors generated.
vim +309 kernel/kcov.c
290
291 static notrace inline void kcov_map_add(struct kcov_map *map, struct kcov_entry *ent,
292 struct task_struct *t, unsigned int mode)
293 {
294 struct kcov *kcov;
295 struct kcov_entry *entry;
296 unsigned int key = hash_key(ent);
297 unsigned long pos, start_index, end_pos, max_pos, *area;
298
299 kcov = t->kcov;
300
301 if ((mode == KCOV_MODE_TRACE_UNIQ_PC ||
302 mode == KCOV_MODE_TRACE_UNIQ_EDGE))
303 hash_for_each_possible_rcu(map->buckets, entry, node, key) {
304 if (entry->ent == ent->ent)
305 return;
306 }
307 else
308 hash_for_each_possible_rcu(map->buckets, entry, node, key) {
> 309 if (entry->ent == ent->ent && entry->type == ent->type &&
> 310 entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
311 return;
312 }
313 }
314
315 entry = (struct kcov_entry *)gen_pool_alloc(map->pool, 1 << MIN_POOL_ALLOC_ORDER);
316 if (unlikely(!entry))
317 return;
318
319 barrier();
320 memcpy(entry, ent, sizeof(*entry));
321 hash_add_rcu(map->buckets, &entry->node, key);
322
323 if (mode == KCOV_MODE_TRACE_UNIQ_PC || mode == KCOV_MODE_TRACE_UNIQ_CMP)
324 area = t->kcov_area;
325 else
326 area = kcov->map_edge->area;
327
328 pos = READ_ONCE(area[0]) + 1;
329 if (mode == KCOV_MODE_TRACE_UNIQ_PC || mode == KCOV_MODE_TRACE_UNIQ_EDGE) {
330 if (likely(pos < t->kcov_size)) {
331 WRITE_ONCE(area[0], pos);
332 barrier();
333 area[pos] = ent->ent;
334 }
335 } else {
336 start_index = 1 + (pos - 1) * KCOV_WORDS_PER_CMP;
337 max_pos = t->kcov_size * sizeof(unsigned long);
338 end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
339 if (likely(end_pos <= max_pos)) {
340 /* See comment in __sanitizer_cov_trace_pc(). */
341 WRITE_ONCE(area[0], pos);
342 barrier();
343 area[start_index] = ent->type;
344 area[start_index + 1] = ent->arg1;
345 area[start_index + 2] = ent->arg2;
346 area[start_index + 3] = ent->ent;
347 }
348 }
349 }
350
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Joey,
kernel test robot noticed the following build errors:
[auto build test ERROR on 9b2ffa6148b1e4468d08f7e0e7e371c43cac9ffe]
url: https://github.com/intel-lab-lkp/linux/commits/Jiao-Joey/kcov-introduce-new-kcov-KCOV_TRACE_UNIQ_PC-mode/20250114-133713
base: 9b2ffa6148b1e4468d08f7e0e7e371c43cac9ffe
patch link: https://lore.kernel.org/r/20250114-kcov-v1-4-004294b931a2%40quicinc.com
patch subject: [PATCH 4/7] kcov: introduce new kcov KCOV_TRACE_UNIQ_CMP mode
config: mips-randconfig-r073-20250124 (https://download.01.org/0day-ci/archive/20250124/202501240959.61XLxBYF-lkp@intel.com/config)
compiler: mips-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250124/202501240959.61XLxBYF-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501240959.61XLxBYF-lkp@intel.com/
All errors (new ones prefixed by >>):
kernel/kcov.c: In function 'kcov_map_add':
>> kernel/kcov.c:309:60: error: 'struct kcov_entry' has no member named 'type'
309 | if (entry->ent == ent->ent && entry->type == ent->type &&
| ^~
kernel/kcov.c:309:73: error: 'struct kcov_entry' has no member named 'type'
309 | if (entry->ent == ent->ent && entry->type == ent->type &&
| ^~
>> kernel/kcov.c:310:34: error: 'struct kcov_entry' has no member named 'arg1'
310 | entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
| ^~
kernel/kcov.c:310:47: error: 'struct kcov_entry' has no member named 'arg1'
310 | entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
| ^~
>> kernel/kcov.c:310:62: error: 'struct kcov_entry' has no member named 'arg2'
310 | entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
| ^~
kernel/kcov.c:310:75: error: 'struct kcov_entry' has no member named 'arg2'
310 | entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
| ^~
kernel/kcov.c:343:48: error: 'struct kcov_entry' has no member named 'type'
343 | area[start_index] = ent->type;
| ^~
kernel/kcov.c:344:52: error: 'struct kcov_entry' has no member named 'arg1'
344 | area[start_index + 1] = ent->arg1;
| ^~
kernel/kcov.c:345:52: error: 'struct kcov_entry' has no member named 'arg2'
345 | area[start_index + 2] = ent->arg2;
| ^~
vim +309 kernel/kcov.c
290
291 static notrace inline void kcov_map_add(struct kcov_map *map, struct kcov_entry *ent,
292 struct task_struct *t, unsigned int mode)
293 {
294 struct kcov *kcov;
295 struct kcov_entry *entry;
296 unsigned int key = hash_key(ent);
297 unsigned long pos, start_index, end_pos, max_pos, *area;
298
299 kcov = t->kcov;
300
301 if ((mode == KCOV_MODE_TRACE_UNIQ_PC ||
302 mode == KCOV_MODE_TRACE_UNIQ_EDGE))
303 hash_for_each_possible_rcu(map->buckets, entry, node, key) {
304 if (entry->ent == ent->ent)
305 return;
306 }
307 else
308 hash_for_each_possible_rcu(map->buckets, entry, node, key) {
> 309 if (entry->ent == ent->ent && entry->type == ent->type &&
> 310 entry->arg1 == ent->arg1 && entry->arg2 == ent->arg2) {
311 return;
312 }
313 }
314
315 entry = (struct kcov_entry *)gen_pool_alloc(map->pool, 1 << MIN_POOL_ALLOC_ORDER);
316 if (unlikely(!entry))
317 return;
318
319 barrier();
320 memcpy(entry, ent, sizeof(*entry));
321 hash_add_rcu(map->buckets, &entry->node, key);
322
323 if (mode == KCOV_MODE_TRACE_UNIQ_PC || mode == KCOV_MODE_TRACE_UNIQ_CMP)
324 area = t->kcov_area;
325 else
326 area = kcov->map_edge->area;
327
328 pos = READ_ONCE(area[0]) + 1;
329 if (mode == KCOV_MODE_TRACE_UNIQ_PC || mode == KCOV_MODE_TRACE_UNIQ_EDGE) {
330 if (likely(pos < t->kcov_size)) {
331 WRITE_ONCE(area[0], pos);
332 barrier();
333 area[pos] = ent->ent;
334 }
335 } else {
336 start_index = 1 + (pos - 1) * KCOV_WORDS_PER_CMP;
337 max_pos = t->kcov_size * sizeof(unsigned long);
338 end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
339 if (likely(end_pos <= max_pos)) {
340 /* See comment in __sanitizer_cov_trace_pc(). */
341 WRITE_ONCE(area[0], pos);
342 barrier();
343 area[start_index] = ent->type;
344 area[start_index + 1] = ent->arg1;
345 area[start_index + 2] = ent->arg2;
346 area[start_index + 3] = ent->ent;
347 }
348 }
349 }
350
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.