From nobody Mon Aug 3 21:44:06 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hDVYf5stPz6n575 for ; Mon, 03 Aug 2026 21:44:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hDVYf4m7kz3FHH for ; Mon, 03 Aug 2026 21:44:06 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785793446; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=rYvavaxVEPCiUY/BEc53mDrblZVkgeE8xAZL8SEQ++w=; b=HWcnAvT11o6ohl7kwyH1YnxJ8xFgFOFg/PTxxLshPpjsL0sZYuPjL07cd0dJDOnzd7V0/L nOdfktGZAn4gGHXs0XJuSsKMEDVt9wnJlBtDEO8pwAD34LMMdc3pNXd2VB9uy5OyU7Tpm+ 59aCRowg2MWFAfkG+JWdO1S4Ilo3mzfgIvtNsJmB+TBiQyyD3ojANIrNcB7xU9/LxKk9VY EWG9pwwA84LxvQ+u/JjNEYhuPo7RFdnLKeuXH2b6Oz7+oZe8xCwsGrF7tKFZBOQ4OlBqIn YczrDONhVMNO/7SNjJ6rteIDE8pYVa3mDP3IP/gZ/BLYUh8EYKkSAJ3vI0JBog== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1785793446; a=rsa-sha256; cv=none; b=UL+MO/3znpGnlKljBvYtBvg3pKUTQoXg26PRgkV8JMidPcqpXxy5v7Neluv+ssTwFPn0Mx c019NhUVZjocFot2EHjuJlNH3H8qOBle/SGEXeH3A5w+gSK981rOkBqjbwyuAjbfSKEDnf 5ATXzeR8WNnWf06I5FWjJbz3Licu1y2THijfDH8NFP9zQyDkrvWsC85G7Xw+M6aF+TKgM5 nGG71sXDrMhAf8I/34uI653oYh35CVxRc62FrK7JEyJH5fAw3M2Gzes6idBUC/9JXuyL62 S1Z035TcuojtJZstSpqieL9aykEiCrYlUb4FQ+4iHi2gVlutxSW7q7Irck1YAQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785793446; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=rYvavaxVEPCiUY/BEc53mDrblZVkgeE8xAZL8SEQ++w=; b=ndnq0PcaiLXKsTjn8KyZsBHypPa4bh8DFdUqhUJsFwYxq8oqkggmIHfI3gH+FKWAR3r6XI 1C2Bss//KHB1mYFDUAK7LUCceOXSg9GvKYyMqvUbGkwNslk1QZqnnPabUItifigpmAYt4E INsdsGcw/qawaJRUq5IVOB7A+Vy0GbcUgZX2+Sm2pdJ97YrtKt/yJv3Blc5bCiOCSgsqEZ RjIwhYVfTUH1pQm+FVtGcNvxaGq7SGh44uJTzs+qhrBs93JOLw04/7envtF2sVDhg08htX ghWNsXqoPZLIFKYZaNKtYveX73mc7sWKF7rlhJyH/4tQkLk+qmTwvKOJauU6JQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hDVYf3lMKz3CN for ; Mon, 03 Aug 2026 21:44:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3bc5b by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 03 Aug 2026 21:44:06 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Brooks Davis Subject: git: 295f10230903 - main - exterror(9): dynamic kernel categories List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: brooks X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 295f10230903d54c700518467c4ea4492f5c4faa Auto-Submitted: auto-generated Date: Mon, 03 Aug 2026 21:44:06 +0000 Message-Id: <6a710ba6.3bc5b.16ea80c3@gitrepo.freebsd.org> The branch main has been updated by brooks: URL: https://cgit.FreeBSD.org/src/commit/?id=295f10230903d54c700518467c4ea4492f5c4faa commit 295f10230903d54c700518467c4ea4492f5c4faa Author: Brooks Davis AuthorDate: 2026-08-03 16:50:01 +0000 Commit: Brooks Davis CommitDate: 2026-08-03 21:43:23 +0000 exterror(9): dynamic kernel categories Make it possible to define categories without compiling their paths into libc (important for third-party modules). The EXTERR_CATEGORY_DYNAMIC macro can be defined to a string describing the compilation unit (generally the path relative to src/sys) which takes the place of EXTERR_CATEGORY. These strings are assembled in linker sets with category numbers assigned at system startup or module load time. The strings can be retrieved from the kern.exterr.categories. sysctl. Reviewed by: kib Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D58237 --- share/man/man9/exterror.9 | 11 ++- sys/conf/files | 1 + sys/kern/kern_linker.c | 36 +++++++++ sys/kern/subr_exterr.c | 169 +++++++++++++++++++++++++++++++++++++++++++ sys/sys/exterrvar.h | 22 ++++++ tests/sys/kern/exterr_test.c | 27 +++++++ 6 files changed, 264 insertions(+), 2 deletions(-) diff --git a/share/man/man9/exterror.9 b/share/man/man9/exterror.9 index 2c9dc73f7616..a7e63abab577 100644 --- a/share/man/man9/exterror.9 +++ b/share/man/man9/exterror.9 @@ -6,7 +6,7 @@ .\" Konstantin Belousov under sponsorship .\" from the FreeBSD Foundation. .\" -.Dd July 21, 2026 +.Dd August 3, 2026 .Dt EXTERROR 9 .Os .Sh NAME @@ -14,6 +14,7 @@ .Nd provide extended error information to userspace .Sh SYNOPSIS .Bd -literal -offset left -compact +#define EXTERR_CATEGORY_DYNAMIC "path/to/this/file.c" #define EXTERR_CATEGORY EXTERR_CAT_MYCATEGORY .Ed .In sys/exterrvar.h @@ -56,7 +57,13 @@ is to make it easier for a user to identify the cause of the error. Before .Nm can be used in the given source .c file, the category of extended errors -should be allocated in the +must be defined. +This can be done by setting the +.Va EXTERR_CATEGORY_DYNAMIC +macro to a string containing the name of the file relative to +.Pa src/sys +directory. +Alternatively, an entry may be allocated in the .In sys/exterr_cat.h file. The category is the unique integer, that, together with the source diff --git a/sys/conf/files b/sys/conf/files index 1c52b432442f..165bcba4356b 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3988,6 +3988,7 @@ kern/subr_disk.c standard kern/subr_early.c standard kern/subr_epoch.c standard kern/subr_eventhandler.c standard +kern/subr_exterr.c standard kern/subr_fattime.c standard kern/subr_firmware.c optional firmware kern/subr_filter.c standard diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index b183d18eaea6..69b47fa6dd17 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -331,6 +331,40 @@ linker_file_register_sysctls(linker_file_t lf, bool enable) sx_xlock(&kld_sx); } +static void +linker_file_register_exterr(linker_file_t lf) +{ + struct exterr_cat **start, **stop; + + KLD_DPF(FILE, + (__func__ ": registering exterror categories for %s\n", + lf->filename)); + + sx_assert(&kld_sx, SA_XLOCKED); + + if (linker_file_lookup_set(lf, "exterr_cats", &start, &stop, NULL) != 0) + return; + + exterr_cat_register_module(start, stop); +} + +static void +linker_file_unregister_exterr(linker_file_t lf) +{ + struct exterr_cat **start, **stop; + + KLD_DPF(FILE, + (__func__ ": unregistering exterror categories for %s\n", + lf->filename)); + + sx_assert(&kld_sx, SA_XLOCKED); + + if (linker_file_lookup_set(lf, "exterr_cats", &start, &stop, NULL) != 0) + return; + + exterr_cat_unregister_module(start, stop); +} + /* * Invoke the LINKER_CTF_GET implementation for this file. Existing * implementations will load CTF info from the filesystem upon the first call @@ -500,6 +534,7 @@ linker_load_file(const char *filename, linker_file_t *result) #ifdef VIMAGE LINKER_PROPAGATE_VNETS(lf); #endif + linker_file_register_exterr(lf); linker_file_sysinit(lf); lf->flags |= LINKER_FILE_LINKED; @@ -775,6 +810,7 @@ linker_file_unload(linker_file_t file, int flags) if ((file->flags & LINKER_FILE_LINKED) != 0) { file->flags &= ~LINKER_FILE_LINKED; linker_file_unregister_sysctls(file); + linker_file_unregister_exterr(file); linker_file_sysuninit(file); EVENTHANDLER_INVOKE(kld_unload, file->filename, file->address, file->size); diff --git a/sys/kern/subr_exterr.c b/sys/kern/subr_exterr.c new file mode 100644 index 000000000000..b704d3ba1dae --- /dev/null +++ b/sys/kern/subr_exterr.c @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 2026 Capabilities Limited + * + * SPDX-License-Identifier: BSD-2-Clause + * + * This software was developed by Capabilities Limited with funding from + * Innovate UK and the Department for Science, Innovation and Technology + * for the adoption and diffusion of CHERI technology under project + * 10168042 (“CheriBSD feature extraction, maturity, and testing”). + * + */ + +#define EXTERR_CATEGORY_DYNAMIC "kern/subr_exterr.c" + +#include +#include +#include +#include +#include +#include +#include +#include /* Need MALLOC_DECLARE */ +#include +#include +#include + +struct exterr_cat_span { + unsigned int first; + unsigned int count; + struct exterr_cat **cat_sets; + TAILQ_ENTRY(exterr_cat_span) entries; +}; + +TAILQ_HEAD(exterr_cat_span_head, exterr_cat_span) cat_span_head; + +SET_DECLARE(exterr_cats, struct exterr_cat); + +static struct exterr_cat_span kern_cats; +unsigned int ncats; +struct rwlock cat_lock; + +static bool +exterr_cat_register_set(struct exterr_cat_span *span, struct exterr_cat **start, + struct exterr_cat **stop) +{ + struct exterr_cat **catp; + ptrdiff_t count; + + count = stop - start; + if (count < 1) + return (true); + + rw_wlock(&cat_lock); + + if (ncats + count < ncats) { + printf("too many exterror categories\n"); + rw_wunlock(&cat_lock); + return (false); + } + + span->first = ncats + 1; + for (catp = start; catp < stop; catp++) + (*catp)->cat = ++ncats; + span->count = count; + span->cat_sets = start; + TAILQ_INSERT_TAIL(&cat_span_head, span, entries); + + rw_wunlock(&cat_lock); + + return (true); +} + +void +exterr_cat_register_module(struct exterr_cat **start, struct exterr_cat **stop) +{ + struct exterr_cat_span *span; + + span = malloc(sizeof(*span), M_LINKER, M_WAITOK | M_ZERO); + if (!exterr_cat_register_set(span, start, stop)) + free(span, M_LINKER); +} + +void +exterr_cat_unregister_module(struct exterr_cat **start, + struct exterr_cat **stop) +{ + struct exterr_cat_span *span; + + if (stop - start < 1) + return; + + rw_wlock(&cat_lock); + + TAILQ_FOREACH(span, &cat_span_head, entries) { + if (span->cat_sets == start) { + MPASS(span->first > 1); + MPASS(span->count == stop - start); + TAILQ_REMOVE(&cat_span_head, span, entries); + break; + } + } + KASSERT(span != NULL, ("start not found in spans")); + + /* + * NB: we leak category numbers on module unload because we can't + * reasonably know which ones are in use in running software. + */ + + rw_wunlock(&cat_lock); + + free(span, M_LINKER); +} + +static void +exterr_cat_register_kern(void *arg) +{ + rw_init(&cat_lock, "exterr dynamic categories"); + + TAILQ_INIT(&cat_span_head); + + if (SET_COUNT(exterr_cats) == 0) + return; + + exterr_cat_register_set(&kern_cats, SET_BEGIN(exterr_cats), + SET_LIMIT(exterr_cats)); +} +SYSINIT(exterr, SI_SUB_KMEM, SI_ORDER_FIRST, exterr_cat_register_kern, NULL); + +static int +sysctl_exterr_categories(SYSCTL_HANDLER_ARGS) +{ + struct exterr_cat_span *span; + const struct exterr_cat *cat = NULL; + int idx; + + if (arg2 != 1) + return (EXTERROR(EINVAL, + "too many args to kern.exterr.categories %d", arg2)); + + idx = *(int *)arg1; + + rw_rlock(&cat_lock); + if (idx < 1 || idx > ncats) { + rw_runlock(&cat_lock); + return (EXTERROR(EINVAL, "category %d out of range (1...%d)", + idx, ncats)); + } + + TAILQ_FOREACH(span, &cat_span_head, entries) { + if (idx < span->first) + break; /* Not here any more */ + + if (idx < span->first + span->count) + cat = span->cat_sets[idx - span->first]; + } + rw_runlock(&cat_lock); + + if (cat == NULL) + return (EXTERROR(ENOENT, "category not found %d", idx)); + MPASS(cat->cat == idx); + return (SYSCTL_OUT(req, cat->file, strlen(cat->file) + 1)); +} + +SYSCTL_NODE(_kern, OID_AUTO, exterr, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, + "Extended error information"); +SYSCTL_UINT(_kern_exterr, OID_AUTO, ncategories, CTLFLAG_RD | CTLFLAG_MPSAFE, + &ncats, 0, "Number of dynamic categories"); +SYSCTL_NODE(_kern_exterr, OID_AUTO, categories, CTLFLAG_RD | CTLFLAG_MPSAFE, + sysctl_exterr_categories, "Extended error categories"); diff --git a/sys/sys/exterrvar.h b/sys/sys/exterrvar.h index a4f6d5313efc..e0822288d746 100644 --- a/sys/sys/exterrvar.h +++ b/sys/sys/exterrvar.h @@ -14,6 +14,9 @@ #include #include #include +#ifdef EXTERR_CATEGORY_DYNAMIC +#include +#endif #define UEXTERROR_MAXLEN 256 @@ -27,8 +30,23 @@ #ifdef _KERNEL +struct exterr_cat { + unsigned int cat; + const char *file; +}; + struct thread; +#ifdef EXTERR_CATEGORY_DYNAMIC +#ifdef EXTERR_STRINGS +static struct exterr_cat __dynamic_cat = { .file = EXTERR_CATEGORY_DYNAMIC }; +DATA_WSET(exterr_cats, __dynamic_cat); +#define EXTERR_CATEGORY (__dynamic_cat.cat | EXTERR_CAT_SRC_KERN_DYNAMIC) +#else +#define EXTERR_CATEGORY EXTERR_CAT_NONE +#endif +#endif + #ifndef EXTERR_CATEGORY #error "Specify error category before including sys/exterrvar.h" #endif @@ -78,6 +96,10 @@ int exterr_set(int eerror, int category, const char *mmsg, uint64ptr_t pp1, uint64ptr_t pp2, int line); int exterr_to_ue(struct thread *td, struct uexterror *ue); void ktrexterr(struct thread *td); +void exterr_cat_register_module(struct exterr_cat **start, + struct exterr_cat **stop); +void exterr_cat_unregister_module(struct exterr_cat **start, + struct exterr_cat **stop); #else /* !_KERNEL */ diff --git a/tests/sys/kern/exterr_test.c b/tests/sys/kern/exterr_test.c index bde7654fecfc..fad002767163 100644 --- a/tests/sys/kern/exterr_test.c +++ b/tests/sys/kern/exterr_test.c @@ -23,8 +23,10 @@ * SUCH DAMAGE. */ +#include #include #include +#include #include #include @@ -121,11 +123,36 @@ ATF_TC_BODY(gettext_noextended_after_extended, tc) ATF_CHECK_STREQ(exterr, ""); } +ATF_TC(exterr_dynamic_categories); +ATF_TC_HEAD(exterr_dynamic_categories, tc) +{ + atf_tc_set_md_var(tc, "descr", + "directly check there is at least one registered category"); +} +ATF_TC_BODY(exterr_dynamic_categories, tc) +{ + int mib[4]; + size_t len; + char filename_buf[128]; + + len = nitems(mib); + ATF_REQUIRE_EQ(sysctlnametomib("kern.exterr.categories", mib, &len), + 0); + mib[3] = 1; + len = sizeof(filename_buf); + ATF_REQUIRE_EQ(sysctl(mib, nitems(mib), filename_buf, &len, NULL, 0), + 0); + printf("%s\n", filename_buf); + /* We can't know what it is, but make sure it's non-empty */ + ATF_REQUIRE(strlen(filename_buf) > 1); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, gettext_extended); ATF_TP_ADD_TC(tp, gettext_noextended); ATF_TP_ADD_TC(tp, gettext_noextended_after_extended); + ATF_TP_ADD_TC(tp, exterr_dynamic_categories); return (atf_no_error()); }