From nobody Tue Apr 7 21:31:23 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1F73635DA46 for ; Wed, 11 Mar 2026 21:06:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773263215; cv=none; b=tHVItHM2w0Ge1ddOlkO6HBNLGNHa+Qb9e3kQp18CP4gnHs/bx2ZeMxNgk5Qwwd9k8y8mR8MeIRJIAyat/wISYEZbiZ7pp4vke+JgPb4S1rfBN9Mi9wThOqP6qaAuvuV9/S9Eq2LkIvLTVvIzFRDCyUX0aX/ROa1QAMUAFBmSR0E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773263215; c=relaxed/simple; bh=gl1kEdDECICBLTyyKuOyRBl/9O6Rh/+H5tSpq5Vi8UM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=t++0ioEQ35+Ll0b1Ki57HB8wfoQ5EvaqLNfR+CpMJcCKz0dFFZl0qpktFeyp11KRiJcEkhVqITbjhDSoNTV0GzAtGJNxo6vaW+C2ay/8RTeGkxKHdzwqEJkOXBPTZGMdRP9Y7pPrUeAenmL7EvQCEL71ej+FsTNg0BkZCx8cowE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=liWzBpPe; arc=none smtp.client-ip=209.85.128.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="liWzBpPe" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-485344bbf1fso21285e9.0 for ; Wed, 11 Mar 2026 14:06:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1773263212; x=1773868012; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=jjaMhHW49Qnvje+/av4ZyUIAC9q72eON3wvAJYxVTt0=; b=liWzBpPeAqat4nH5ZzkYTAneIa5ruq9QpkSiuCteCHLM3Oq/Z2wkMDUJ9ytYfIwqN8 76nAWGs3cfe001rw8HSDsbIIMTFE08oQkgNB0/axF7EJMoMUqyTUfhFBCRjQKKmBg2JI BHPoUP+T3mT7524Q4XUCJbbUAMw7qNROZRZyoKOr+/qMw8+BiJ66DGUC2Ad1VQPYEMQJ 7TIMuNoxmTJIpGClREemKMwvh/f/vzb3uioWmNkDPEJ7U76a63cMMPuSIlgYAdsfYzcc x9x+4dxN/QYc6uKhiNJxf3MOuYZtLwCCXtGxbgFnR5ZKHP9KJJBKShTxqPRJr1Y/EmpY bYQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773263212; x=1773868012; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=jjaMhHW49Qnvje+/av4ZyUIAC9q72eON3wvAJYxVTt0=; b=q9uhYCpu2CQqBRFfYsHI9gk8W/sZBS8AO9uGo4SBvVn6jkDKxk/5BPS5CdRvY4SheO Ns44XLbTn2KAj4XFnfkKf13lczqUrAXAUbEC4AvTYAXfwRlTIF5pI0fNqIF1pOHsMFLv JuatMkadovnOL9oqYPJ8nStqZ7rcG93GEuiQzVBUq2FP5F49/ki6HUEu0R7D8wXSoMtP eERQkLIiaxqC94jsLz7mgkgLycTnGL3VuPpGVUZfkomXHEFOX4kOOJOtrJNqL8KCToFy WirHJAU8fxHlbo/ynW9o4zsvU7jnCbd2TikpzGt12eRvY6LHCYKUBlp5cGHTKzRwl2R1 WuvQ== X-Forwarded-Encrypted: i=1; AJvYcCWJ3x6hJxqrOM8F+DwyxUbVWsVcgMs4GP/P+ZBstg1PXyMGe8eBJqt0jSi0vjWvYMhQ91Jw+TPAwZBio5M=@vger.kernel.org X-Gm-Message-State: AOJu0YxHh8hB4CuQ2RF9naPnuQnbaTMiSmrkRCqeya9Z/TRVWfO0y6IY BGVputoWmVLkDvxsN0mUcQ8G5RRg/M3AuU+C/HeM9cPIGNo81WDLqXTxnkTV1Bzb9w== X-Gm-Gg: ATEYQzyzHPToMWBz3HeE5istCicntSmgq0oDuJeQ0p926/1IVQ0ZlnK9w4UbE0hGpQP ysCFDYqdDGKpRRcohaan7x+w8xDAeOzIXqs8mnC8b8rIRjF04q5USukAjRkzCyLvMFZrQju+0XS oydPhoTLac4AsPXg9VmkGeToGi5Su+1Za3v9jaaznlZDVF3JIK4f9s349Or9kd87C3Iu2w8pxv+ oS38TUsNao0YG+yrtsMt9Dh8GY8zb1HgCSjGQbY84uYm5xeEObKDVINZij6Mn3GoNMbbYYmba72 dhj8QVioGrMFI+t2BbxZGl5qwMUiFze6k8L3ik9PcUBc/0JtlAJxapt6GCapWIsQSIQENFHd5Z1 85BEPVpWbhYwu/K+DPafzkW1/xoekpMgbMiFl5RKJ37J0r5+AU6EdvC7Rp+0n/AE8xAAfz+t4Sw /vJR4/oURwn1YkXShD9fQnJC2T5rsewNqCNGg0/tH6B5cou+GoO1uXCT0Sa6l0RA== X-Received: by 2002:a05:600c:c285:b0:477:86fd:fb47 with SMTP id 5b1f17b1804b1-4854fa1a473mr146295e9.8.1773263211980; Wed, 11 Mar 2026 14:06:51 -0700 (PDT) Received: from localhost ([2a00:79e0:288a:8:c9d4:528c:7414:ba3a]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-4854b0b906esm39112635e9.4.2026.03.11.14.06.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Mar 2026 14:06:51 -0700 (PDT) From: Jann Horn Date: Wed, 11 Mar 2026 22:06:16 +0100 Subject: [PATCH 3/3] kcov: introduce extended PC coverage collection mode Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260311-kcov-extrecord-v1-3-68f03c4a05ad@google.com> References: <20260311-kcov-extrecord-v1-0-68f03c4a05ad@google.com> In-Reply-To: <20260311-kcov-extrecord-v1-0-68f03c4a05ad@google.com> To: Dmitry Vyukov , Andrey Konovalov Cc: Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, llvm@lists.linux.dev, Jann Horn X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=ed25519-sha256; t=1773263202; l=7510; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=gl1kEdDECICBLTyyKuOyRBl/9O6Rh/+H5tSpq5Vi8UM=; b=e/rnv3+0v+r78iIlsq75/4nso6BkrQk3V2nDG/iHUsVN7+gvM3C9zbVYQ5KwhdojDxQjkjCZ7 dQQGF6fxaiPBk56ppaUuFfJ3FRVFPNtBItKr6lDOZo9uaR561Iq3UG/ X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= This is the second half of CONFIG_KCOV_EXT_RECORDS. Introduce a new KCOV mode KCOV_TRACE_PC_EXT which replaces the upper 8 bits of recorded instruction pointers with metadata. For now, userspace can use this metadata to distinguish three types of records: - function entry - function exit - normal basic block inside the function Signed-off-by: Jann Horn --- include/linux/sched.h | 6 ++++-- include/uapi/linux/kcov.h | 12 ++++++++++++ kernel/kcov.c | 46 +++++++++++++++++++++++++++++++++++++++++--= --- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index a7b4a980eb2f..9a297d2d2abc 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1519,8 +1519,10 @@ struct task_struct { int kcov_sequence; =20 /* Collect coverage from softirq context: */ - unsigned int kcov_softirq; -#endif + unsigned int kcov_softirq : 1; + /* Emit KCOV records in extended format: */ + unsigned int kcov_ext_format : 1; +#endif /* CONFIG_KCOV */ =20 #ifdef CONFIG_MEMCG_V1 struct mem_cgroup *memcg_in_oom; diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index ed95dba9fa37..8d8a233bd61f 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -35,8 +35,20 @@ enum { KCOV_TRACE_PC =3D 0, /* Collecting comparison operands mode. */ KCOV_TRACE_CMP =3D 1, + /* + * Extended PC coverage collection mode. + * In this mode, the top byte of the PC is replaced with flag bits + * (KCOV_RECORDFLAG_*). + */ + KCOV_TRACE_PC_EXT =3D 2, }; =20 +#define KCOV_RECORD_IP_MASK 0x00ffffffffffffff +#define KCOV_RECORDFLAG_TYPEMASK 0xf000000000000000 +#define KCOV_RECORDFLAG_TYPE_NORMAL 0xf000000000000000 +#define KCOV_RECORDFLAG_TYPE_ENTRY 0x0000000000000000 +#define KCOV_RECORDFLAG_TYPE_EXIT 0x1000000000000000 + /* * The format for the types of collected comparisons. * diff --git a/kernel/kcov.c b/kernel/kcov.c index 2cc48b65384b..3482044a7bd5 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -71,6 +71,8 @@ struct kcov { * kcov_remote_stop(), see the comment there. */ int sequence; + /* Whether emitted records should have type bits. */ + unsigned int kcov_ext_format : 1 __guarded_by(&lock); }; =20 struct kcov_remote_area { @@ -97,6 +99,7 @@ struct kcov_percpu_data { void *saved_area; struct kcov *saved_kcov; int saved_sequence; + unsigned int saved_kcov_ext_format : 1; }; =20 static DEFINE_PER_CPU(struct kcov_percpu_data, kcov_percpu_data) =3D { @@ -235,6 +238,12 @@ static void notrace kcov_add_pc_record(unsigned long r= ecord) */ void notrace __sanitizer_cov_trace_pc(void) { + /* + * No bitops are needed here for setting the record type because + * KCOV_RECORDFLAG_TYPE_NORMAL has the high bits set. + * This relies on userspace not caring about the rest of the top byte + * for KCOV_RECORDFLAG_TYPE_NORMAL records. + */ kcov_add_pc_record(canonicalize_ip(_RET_IP_)); } EXPORT_SYMBOL(__sanitizer_cov_trace_pc); @@ -244,10 +253,26 @@ void notrace __sanitizer_cov_trace_pc_entry(void) { unsigned long record =3D canonicalize_ip(_RET_IP_); =20 + /* + * This hook replaces __sanitizer_cov_trace_pc() for the function entry + * basic block; it should still emit a record even in classic kcov mode. + */ + if (current->kcov_ext_format) + record =3D (record & KCOV_RECORD_IP_MASK) | KCOV_RECORDFLAG_TYPE_ENTRY; kcov_add_pc_record(record); } void notrace __sanitizer_cov_trace_pc_exit(void) { + unsigned long record; + + /* + * Unlike __sanitizer_cov_trace_pc_entry(), this PC should only be + * reported in extended mode. + */ + if (!current->kcov_ext_format) + return; + record =3D (canonicalize_ip(_RET_IP_) & KCOV_RECORD_IP_MASK) | KCOV_RECOR= DFLAG_TYPE_EXIT; + kcov_add_pc_record(record); } #endif =20 @@ -371,7 +396,7 @@ EXPORT_SYMBOL(__sanitizer_cov_trace_switch); =20 static void kcov_start(struct task_struct *t, struct kcov *kcov, unsigned int size, void *area, enum kcov_mode mode, - int sequence) + int sequence, unsigned int kcov_ext_format) { kcov_debug("t =3D %px, size =3D %u, area =3D %px\n", t, size, area); t->kcov =3D kcov; @@ -379,6 +404,7 @@ static void kcov_start(struct task_struct *t, struct kc= ov *kcov, t->kcov_size =3D size; t->kcov_area =3D area; t->kcov_sequence =3D sequence; + t->kcov_ext_format =3D kcov_ext_format; /* See comment in check_kcov_mode(). */ barrier(); WRITE_ONCE(t->kcov_mode, mode); @@ -398,6 +424,7 @@ static void kcov_task_reset(struct task_struct *t) kcov_stop(t); t->kcov_sequence =3D 0; t->kcov_handle =3D 0; + t->kcov_ext_format =3D 0; } =20 void kcov_task_init(struct task_struct *t) @@ -570,6 +597,8 @@ static int kcov_get_mode(unsigned long arg) #else return -ENOTSUPP; #endif + else if (arg =3D=3D KCOV_TRACE_PC_EXT) + return IS_ENABLED(CONFIG_KCOV_EXT_RECORDS) ? KCOV_MODE_TRACE_PC : -ENOTS= UPP; else return -EINVAL; } @@ -636,8 +665,9 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigne= d int cmd, return mode; kcov_fault_in_area(kcov); kcov->mode =3D mode; + kcov->kcov_ext_format =3D (arg =3D=3D KCOV_TRACE_PC_EXT); kcov_start(t, kcov, kcov->size, kcov->area, kcov->mode, - kcov->sequence); + kcov->sequence, kcov->kcov_ext_format); kcov->t =3D t; /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ kcov_get(kcov); @@ -668,7 +698,8 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigne= d int cmd, return -EINVAL; kcov->mode =3D mode; t->kcov =3D kcov; - t->kcov_mode =3D KCOV_MODE_REMOTE; + t->kcov_mode =3D KCOV_MODE_REMOTE; + kcov->kcov_ext_format =3D (remote_arg->trace_mode =3D=3D KCOV_TRACE_PC_E= XT); kcov->t =3D t; kcov->remote =3D true; kcov->remote_size =3D remote_arg->area_size; @@ -853,6 +884,7 @@ static void kcov_remote_softirq_start(struct task_struc= t *t) data->saved_area =3D t->kcov_area; data->saved_sequence =3D t->kcov_sequence; data->saved_kcov =3D t->kcov; + data->saved_kcov_ext_format =3D t->kcov_ext_format; kcov_stop(t); } } @@ -865,12 +897,14 @@ static void kcov_remote_softirq_stop(struct task_stru= ct *t) if (data->saved_kcov) { kcov_start(t, data->saved_kcov, data->saved_size, data->saved_area, data->saved_mode, - data->saved_sequence); + data->saved_sequence, + data->saved_kcov_ext_format); data->saved_mode =3D 0; data->saved_size =3D 0; data->saved_area =3D NULL; data->saved_sequence =3D 0; data->saved_kcov =3D NULL; + data->saved_kcov_ext_format =3D 0; } } =20 @@ -884,6 +918,7 @@ void kcov_remote_start(u64 handle) unsigned int size; int sequence; unsigned long flags; + unsigned int kcov_ext_format; =20 if (WARN_ON(!kcov_check_handle(handle, true, true, true))) return; @@ -930,6 +965,7 @@ void kcov_remote_start(u64 handle) * acquired _after_ kcov->lock elsewhere. */ mode =3D context_unsafe(kcov->mode); + kcov_ext_format =3D context_unsafe(kcov->kcov_ext_format); sequence =3D kcov->sequence; if (in_task()) { size =3D kcov->remote_size; @@ -958,7 +994,7 @@ void kcov_remote_start(u64 handle) kcov_remote_softirq_start(t); t->kcov_softirq =3D 1; } - kcov_start(t, kcov, size, area, mode, sequence); + kcov_start(t, kcov, size, area, mode, sequence, kcov_ext_format); =20 local_unlock_irqrestore(&kcov_percpu_data.lock, flags); =20 --=20 2.53.0.473.g4a7958ca14-goog