git: 5dff273d680a - main - uexterr_gettext(3): support dynamic kernel categories

Brooks Davis <[email protected]> Mon, 03 Aug 2026 21:44:07 +0000
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a710ba7.3cbc0.79d9e807__49839.5272925094$1785793638$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by brooks:

URL: https://cgit.FreeBSD.org/src/commit/?id=5dff273d680ab848c62ca50efacb19f199217ab7

commit 5dff273d680ab848c62ca50efacb19f199217ab7
Author:     Brooks Davis <[email protected]>
AuthorDate: 2026-08-03 16:50:26 +0000
Commit:     Brooks Davis <[email protected]>
CommitDate: 2026-08-03 21:43:23 +0000

    uexterr_gettext(3): support dynamic kernel categories
    
    Add an uncached sysctl based implementation which retrieves individual
    categories.  A cache would be an obvious extension should this optional
    feature that can only be enabled by an environmental varible have a
    noticable performance impact in a case that matters.
    
    Reviewed by:    kib
    Sponsored by:   Innovate UK
    Differential Revision:  https://reviews.freebsd.org/D58238
---
 lib/libc/gen/uexterr_format.c | 68 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 64 insertions(+), 4 deletions(-)

diff --git a/lib/libc/gen/uexterr_format.c b/lib/libc/gen/uexterr_format.c
index df93ae1447cd..99ae85715f43 100644
--- a/lib/libc/gen/uexterr_format.c
+++ b/lib/libc/gen/uexterr_format.c
@@ -11,20 +11,75 @@
 #include <sys/param.h>
 #include <sys/exterr_cat.h>
 #include <sys/exterrvar.h>
+#include <sys/sysctl.h>
 #include <exterr.h>
+#include <pthread.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+#include "libc_private.h"
+
 static const char * const cat_to_filenames[] = {
 #include "exterr_cat_filenames.h"
 };
 
+_Thread_local char filename_buf[128];
+
+#define	MIB_SIZE	4
+static int mib_template[MIB_SIZE];
+pthread_once_t mib_template_once_control = PTHREAD_ONCE_INIT;
+
+static void
+mib_template_init(void)
+{
+	size_t len;
+
+	len = nitems(mib_template);
+	(void)sysctlnametomib("kern.exterr.categories", mib_template, &len);
+	/* failure handled in kern_dynamic_cat_to_filename() */
+}
+
+static const char *
+kern_dynamic_cat_to_filename(int category)
+{
+	int mib[MIB_SIZE];
+	size_t len;
+
+	if (_once(&mib_template_once_control, mib_template_init) != 0)
+		return (NULL);
+	if (__predict_false(mib_template[0] != CTL_KERN)) {
+		filename_buf[0] = '\0';
+		return (filename_buf);
+	}
+
+	memcpy(mib, mib_template, MIB_SIZE);
+	mib[MIB_SIZE - 1] = category;
+	len = sizeof(filename_buf);
+	if (sysctl(mib, nitems(mib), filename_buf, &len, NULL, 0) != 0)
+		return (NULL);
+	return (filename_buf);
+}
+
+static const char *
+cat_to_file_prefix(int category)
+{
+	switch (EXTERR_CAT_SRC(category)) {
+	case EXTERR_CAT_SRC_KERN_STATIC:
+	case EXTERR_CAT_SRC_KERN_DYNAMIC:
+		return ("sys/");
+	default:
+		return ("");
+	}
+}
+
 static const char *
 cat_to_filename(int category)
 {
+	const char *path;
+
 	switch (EXTERR_CAT_SRC(category)) {
 	case EXTERR_CAT_SRC_KERN_STATIC:
 		if (category < 0 || category >= nitems(cat_to_filenames) ||
@@ -33,7 +88,10 @@ cat_to_filename(int category)
 		return (cat_to_filenames[category]);
 
 	case EXTERR_CAT_SRC_KERN_DYNAMIC:
-		return ("unknown:kern");
+		path = kern_dynamic_cat_to_filename(EXTERR_CAT(category));
+		if (path == NULL)
+			return ("unknown:kern");
+		return (path);
 
 	case EXTERR_CAT_SRC_USER:
 		return ("unknown:user");
@@ -97,16 +155,18 @@ __uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz)
 	if (exterror_verbose > EXTERR_VERBOSE_DEFAULT || !has_msg) {
 		char lbuf[128];
 
-#define	SRC_FMT "(src sys/%s:%u)"
+#define	SRC_FMT "(src %s%s:%u)"
 		if (exterror_verbose == EXTERR_VERBOSE_ALLOW_BRIEF) {
 			snprintf(lbuf, sizeof(lbuf), SRC_FMT,
+			    cat_to_file_prefix(ue->cat),
                             cat_to_filename(ue->cat), ue->src_line);
 		} else if (!has_msg ||
 		    exterror_verbose == EXTERR_VERBOSE_ALLOW_FULL) {
 			snprintf(lbuf, sizeof(lbuf),
 			    "errno %d category %u " SRC_FMT " p1 %#jx p2 %#jx",
-			    ue->error, ue->cat, cat_to_filename(ue->cat),
-			    ue->src_line, (uintmax_t)ue->p1, (uintmax_t)ue->p2);
+			    ue->error, ue->cat, cat_to_file_prefix(ue->cat),
+			    cat_to_filename(ue->cat), ue->src_line,
+			    (uintmax_t)ue->p1, (uintmax_t)ue->p2);
 		}
 #undef SRC_FMT
 		if (has_msg)