All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jann Horn <jannh@google.com>
To: Dmitry Vyukov <dvyukov@google.com>,
	 Andrey Konovalov <andreyknvl@gmail.com>,
	 Alexander Potapenko <glider@google.com>
Cc: Nathan Chancellor <nathan@kernel.org>,
	 Nick Desaulniers <nick.desaulniers+lkml@gmail.com>,
	 Bill Wendling <morbo@google.com>,
	Justin Stitt <justinstitt@google.com>,
	 linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com,
	 llvm@lists.linux.dev, Jann Horn <jannh@google.com>
Subject: [PATCH RFC v3 09/12] kcov: record return address on function entry
Date: Tue, 08 Sep 2026 18:54:49 +0200	[thread overview]
Message-ID: <20260908-kcov-extrecord-v3-9-dcbc11593e88@google.com> (raw)
In-Reply-To: <20260908-kcov-extrecord-v3-0-dcbc11593e88@google.com>

It is helpful to know which code location a function was called from for:

 - attributing calls to source locations in the callee
 - attributing calls to inlined functions

For this purpose, make function entry records bigger, and record the caller
instruction address in them.

Signed-off-by: Jann Horn <jannh@google.com>
---
 kernel/kcov.c     | 26 ++++++++++++++++++--------
 lib/Kconfig.debug |  2 ++
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/kernel/kcov.c b/kernel/kcov.c
index 83e05aa61728..88aedaf41a9e 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -202,7 +202,8 @@ static notrace unsigned long canonicalize_ip(unsigned long ip)
 	return ip;
 }
 
-static __always_inline void notrace kcov_add_pc_record(struct task_struct *t, unsigned long record)
+static __always_inline notrace
+void kcov_add_pc_record(struct task_struct *t, unsigned long record, bool hasext, unsigned long ext)
 {
 	unsigned long *area;
 	unsigned long pos;
@@ -213,7 +214,7 @@ static __always_inline void notrace kcov_add_pc_record(struct task_struct *t, un
 	area = t->kcov_area;
 	/* The first 64-bit word is the number of subsequent PCs. */
 	pos = READ_ONCE(area[0]) + 1;
-	if (likely(pos < t->kcov_size)) {
+	if (likely(pos + (hasext?1:0) < t->kcov_size)) {
 		/* Previously we write pc before updating pos. However, some
 		 * early interrupt code could bypass check_kcov_context() check
 		 * and invoke __sanitizer_cov_trace_pc(). If such interrupt is
@@ -221,9 +222,11 @@ static __always_inline void notrace kcov_add_pc_record(struct task_struct *t, un
 		 * overitten by the recursive __sanitizer_cov_trace_pc().
 		 * Update pos before writing pc to avoid such interleaving.
 		 */
-		WRITE_ONCE(area[0], pos);
+		WRITE_ONCE(area[0], pos + (hasext?1:0));
 		barrier();
 		area[pos] = record;
+		if (hasext)
+			area[pos+1] = ext;
 	}
 }
 
@@ -244,7 +247,7 @@ void notrace __sanitizer_cov_trace_pc(void)
 	 * This relies on userspace not caring about the rest of the top byte
 	 * for KCOV_RECORDFLAG_TYPE_NORMAL records.
 	 */
-	kcov_add_pc_record(cur, canonicalize_ip(_RET_IP_));
+	kcov_add_pc_record(cur, canonicalize_ip(_RET_IP_), false, 0);
 }
 EXPORT_SYMBOL(__sanitizer_cov_trace_pc);
 
@@ -254,6 +257,7 @@ void notrace __sanitizer_cov_trace_pc_entry(void)
 	struct task_struct *cur = current;
 	unsigned long record = canonicalize_ip(_RET_IP_);
 	unsigned int kcov_mode = READ_ONCE(cur->kcov_mode);
+	bool ext_format;
 
 	/*
 	 * This hook replaces __sanitizer_cov_trace_pc() for the function entry
@@ -265,9 +269,15 @@ void notrace __sanitizer_cov_trace_pc_entry(void)
 		cur->kcov->suppressed_stack_delta++;
 		return;
 	}
-	if ((kcov_mode & KCOV_EXT_FORMAT) != 0)
+	ext_format = (kcov_mode & KCOV_EXT_FORMAT) != 0;
+	if (ext_format)
 		record = (record & KCOV_RECORD_IP_MASK) | KCOV_RECORDFLAG_TYPE_ENTRY;
-	kcov_add_pc_record(cur, record);
+	/*
+	 * __builtin_return_address(1) is safe because this function is only
+	 * called from C functions, which are compiled with frame pointers
+	 * enabled
+	 */
+	kcov_add_pc_record(cur, record, ext_format, (unsigned long)__builtin_return_address(1));
 }
 void notrace __sanitizer_cov_trace_pc_exit(void)
 {
@@ -293,7 +303,7 @@ void notrace __sanitizer_cov_trace_pc_exit(void)
 		return;
 	}
 	record = (canonicalize_ip(_RET_IP_) & KCOV_RECORD_IP_MASK) | KCOV_RECORDFLAG_TYPE_EXIT;
-	kcov_add_pc_record(cur, record);
+	kcov_add_pc_record(cur, record, false, 0);
 }
 #endif
 
@@ -441,7 +451,7 @@ void kcov_finish_switch(struct task_struct *cur)
 	record = KCOV_RECORDFLAG_TYPE_EESUM |
 		(((u16)(s16)kcov->suppressed_stack_mindelta)<<16) |
 		(((u16)(s16)kcov->suppressed_stack_delta)<<16);
-	kcov_add_pc_record(cur, record);
+	kcov_add_pc_record(cur, record, false, 0);
 }
 
 static void kcov_start(struct task_struct *t, struct kcov *kcov,
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index f763f0504f62..55c786a373b5 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2200,6 +2200,8 @@ config KCOV_EXT_RECORDS
 	depends on KCOV
 	depends on 64BIT
 	depends on $(cc-option,-fsanitize-coverage=trace-pc-entry-exit)
+	select ARCH_WANT_FRAME_POINTERS
+	select FRAME_POINTER
 	help
 	  Extended KCOV records allow distinguishing between multiple types of
 	  records: Normal edge coverage, function entry, and function exit.

-- 
2.55.0.979.g7e5102b832-goog


  parent reply	other threads:[~2026-09-08 16:55 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-08 16:54 [PATCH RFC v3 00/12] KCOV: entry/exit records, memory access records, and delay injection Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 01/12] kcov: wire up compiler instrumentation for CONFIG_KCOV_EXT_RECORDS Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 02/12] kcov: refactor mode check out of check_kcov_mode() Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 03/12] kcov: introduce extended PC coverage collection mode Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 04/12] kcov: summarize entry/exit while disabled Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 05/12] kasan: refactor write/is_write arguments to flags Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 06/12] kcov: introduce memory access tracing Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 07/12] kasan: provide memory access information to KCOV Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 08/12] kcov: log freeing of SLUB objects and pages Jann Horn
2026-09-08 17:04   ` Jann Horn
2026-09-08 16:54 ` Jann Horn [this message]
2026-09-08 16:54 ` [PATCH RFC v3 10/12] kcov: log old value Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 11/12] kcov: introduce delay injection Jann Horn
2026-09-08 16:54 ` [PATCH RFC v3 12/12] Documentation/kcov: add documentation for EXT_RECORDS and KCOV_MEMORY Jann Horn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260908-kcov-extrecord-v3-9-dcbc11593e88@google.com \
    --to=jannh@google.com \
    --cc=andreyknvl@gmail.com \
    --cc=dvyukov@google.com \
    --cc=glider@google.com \
    --cc=justinstitt@google.com \
    --cc=kasan-dev@googlegroups.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=morbo@google.com \
    --cc=nathan@kernel.org \
    --cc=nick.desaulniers+lkml@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.