Page MenuHomeFreeBSD

D58059.id182528.diff
No OneTemporary

D58059.id182528.diff

diff --git a/include/Makefile b/include/Makefile
--- a/include/Makefile
+++ b/include/Makefile
@@ -33,7 +33,8 @@
stddef.h stdnoreturn.h stdio.h stdlib.h string.h stringlist.h \
strings.h sysexits.h tar.h termios.h tgmath.h \
time.h timeconv.h timers.h ttyent.h \
- uchar.h ulimit.h unistd.h utime.h utmpx.h uuid.h varargs.h \
+ uchar.h uexterror.h ulimit.h unistd.h utime.h utmpx.h uuid.h \
+ varargs.h \
wchar.h wctype.h wordexp.h xlocale.h
.PATH: ${SRCTOP}/contrib/libc-vis
diff --git a/include/uexterror.h b/include/uexterror.h
new file mode 100644
--- /dev/null
+++ b/include/uexterror.h
@@ -0,0 +1,65 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ * Copyright (c) 2026 Capabilities Limited
+ * All rights reserved.
+ *
+ * This software were developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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”).
+ */
+
+#ifndef _UEXTERROR_H_
+#define _UEXTERROR_H_
+
+#include <sys/types.h>
+#include <sys/linker_set.h>
+
+struct exterr_cat {
+ unsigned int cat;
+ const char *file;
+};
+
+#ifndef UEXTERR_CATEGORY
+#error "Specify error category before including uexterror.h"
+#endif
+
+#ifndef NO_UEXTERR_STRINGS
+static struct exterr_cat __dynamic_cat = { .file = UEXTERR_CATEGORY };
+DATA_WSET(exterr_cats, __dynamic_cat);
+#define _UEXTERR_CATEGORY \
+ (__dynamic_cat.cat | EXTERR_CAT_SRC_USER)
+#else
+#define _UEXTERR_CATEGORY (EXTERR_CAT_NONE | EXTERR_CAT_SRC_USER)
+#endif
+
+
+#ifdef NO_UEXTERR_STRINGS
+#define SET_ERROR_MSG(mmsg) NULL
+#else
+#define SET_ERROR_MSG(mmsg) (mmsg)
+#endif
+
+#define _SET_ERROR2(eerror, mmsg, pp1, pp2) \
+ uexterr_set(eerror, _UEXTERR_CATEGORY, SET_ERROR_MSG(mmsg), \
+ (uint64ptr_t)(pp1), (uint64ptr_t)(pp2), __LINE__)
+#define _SET_ERROR0(eerror, mmsg) _SET_ERROR2(eerror, mmsg, 0, 0)
+#define _SET_ERROR1(eerror, mmsg, pp1) _SET_ERROR2(eerror, mmsg, pp1, 0)
+
+#define _UEXTERROR_MACRO(eerror, mmsg, _1, _2, NAME, ...) \
+ NAME
+#define UEXTERROR(...) \
+ _UEXTERROR_MACRO(__VA_ARGS__, _SET_ERROR2, _SET_ERROR1, \
+ _SET_ERROR0)(__VA_ARGS__)
+
+__BEGIN_DECLS
+void uexterr_set(int error, int category, const char *mmsg, uint64ptr_t pp1,
+ uint64ptr_t pp2, int line);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -164,6 +164,7 @@
ualarm.c \
uexterr_format.c \
uexterr_gettext.c \
+ uexterr_set.c \
ulimit.c \
uname.c \
unvis-compat.c \
@@ -324,6 +325,7 @@
ttyname.3 \
ualarm.3 \
ucontext.3 \
+ uexterr.3 \
uexterr_gettext.3 \
ulimit.3 \
uname.3 \
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -482,6 +482,7 @@
posix_spawnattr_getprocdescp_np;
posix_spawnattr_setexecfd_np;
posix_spawnattr_setprocdescp_np;
+ uexterr_set;
};
FBSDprivate_1.0 {
@@ -612,4 +613,5 @@
__getcontextx_size;
__makecontext;
__uexterr_format;
+ __uexterr_set_ue;
};
diff --git a/lib/libc/gen/libc_interposing_table.c b/lib/libc/gen/libc_interposing_table.c
--- a/lib/libc/gen/libc_interposing_table.c
+++ b/lib/libc/gen/libc_interposing_table.c
@@ -43,6 +43,7 @@
SLOT(spinunlock, __libc_spinunlock_stub),
SLOT(map_stacks_exec, __libc_map_stacks_exec),
SLOT(uexterr_gettext, __libc_uexterr_gettext),
+ SLOT(uexterr_set, __libc_uexterr_set),
};
#undef SLOT
diff --git a/lib/libc/gen/uexterr_gettext.c b/lib/libc/gen/uexterr_gettext.c
--- a/lib/libc/gen/uexterr_gettext.c
+++ b/lib/libc/gen/uexterr_gettext.c
@@ -11,11 +11,12 @@
#define _WANT_P_OSREL
#include <sys/param.h>
#include <sys/exterrvar.h>
+#include <errno.h>
#include <exterr.h>
#include <string.h>
#include "libc_private.h"
-static struct uexterror uexterr = {
+struct uexterror uexterr = {
.ver = UEXTERROR_VER,
};
diff --git a/lib/libc/gen/uexterr_set.c b/lib/libc/gen/uexterr_set.c
new file mode 100644
--- /dev/null
+++ b/lib/libc/gen/uexterr_set.c
@@ -0,0 +1,50 @@
+/*-
+ * 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”).
+ */
+
+#include <sys/exterrvar.h>
+#include <errno.h>
+#include <exterr.h>
+#include <string.h>
+#include "libc_private.h"
+
+void
+__uexterr_set_ue(struct uexterror *ue, int error, int category,
+ const char *mmsg, uint64ptr_t pp1, uint64ptr_t pp2, int line)
+{
+ memset((char *)ue + offsetof(struct uexterror, error), 0,
+ sizeof(struct uexterror) - offsetof(struct uexterror, error));
+ ue->error = error;
+ ue->cat = category | EXTERR_CAT_SRC_USER;
+ ue->src_line = line;
+ ue->p1 = pp1;
+ ue->p2 = pp2;
+ if (mmsg != NULL)
+ strlcpy(ue->msg, mmsg, sizeof(ue->msg));
+ else
+ ue->msg[0] = '\0';
+ errno = error;
+}
+
+void
+__libc_uexterr_set(int error, int category, const char *mmsg, uint64ptr_t pp1,
+ uint64ptr_t pp2, int line)
+{
+ __uexterr_set_ue(&uexterr, error, category, mmsg, pp1, pp2, line);
+}
+
+void
+uexterr_set(int error, int category, const char *mmsg, uint64ptr_t pp1,
+ uint64ptr_t pp2, int line)
+{
+ ((void (*)(int, int, const char *, uint64ptr_t, uint64ptr_t, int))
+ __libc_interposing[INTERPOS_uexterr_set])(error, category,
+ mmsg, pp1, pp2, line);
+}
diff --git a/lib/libc/gen/uexterror.3 b/lib/libc/gen/uexterror.3
new file mode 100644
--- /dev/null
+++ b/lib/libc/gen/uexterror.3
@@ -0,0 +1,135 @@
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 The FreeBSD Foundation
+.\" Copyright (c) 2026 Capabilities Limited
+.\"
+.\" This documentation was written by
+.\" Konstantin Belousov <kib@FreeBSD.org> under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" 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”).
+.\"
+.Dd July 23, 2026
+.Dt UEXTERROR 3
+.Os
+.Sh NAME
+.Nm uexterror
+.Nd provide extended error information from user-space code
+.Sh SYNOPSIS
+.Bd -literal -offset left -compact
+#define UEXTERR_CATEGORY "path/to/this/file.c"
+.Ed
+.In uexterror.h
+.Ft void
+.Fn UEXTERROR "int error" "const char *msg" ...
+.Sh DESCRIPTION
+The
+.Nm
+framework allows user-space code to report errors using the
+same
+.Xr exterror 9
+infrastructure the kernel uses to return additional information about an
+error along with the standard
+.Xr errno 3
+error code, which is terse and often lacking context.
+.Pp
+The terseness is especially visible with commonly overloaded error codes like
+.Er EINVAL
+or
+.Er EIO ,
+which occur at many places for a given syscall, or even
+outside the context of the current call.
+Identifying the specific cause for the returned error using only the
+.Va errno
+value requires searching for all instances that the error is returned
+in user-space and the kernel and trying to guess which is the most
+likely code path to have returned the error.
+.Nm
+attaches additional data to the error itself
+and records the error category and
+the source code file line number.
+The intent of
+.Nm
+is to make it easier for a user to identify the cause of the error.
+.Sh USAGE
+Before
+.Nm
+can be used in the given source .c file, the category of extended errors
+must be defined.
+This can be done by setting the
+.Va UEXTERR_CATEGORY
+macro to a string containing the name of the file relative to
+.Pa src/sys
+directory.
+.Pp
+A typical code fragment to report an error is to set errno
+.D1 errno = EINVAL;
+An extended error can augment the error code with additional information:
+.D1 UEXTERROR(EINVAL, \[dq]Invalid length\[dq]));
+The error data and metadata is saved in the current thread storage.
+The metadata includes the category and the source file line number.
+.Pp
+Arguments to the
+.Fn UEXTERROR
+macro:
+.Bl -dash
+.It
+The first argument to
+.Fn UEXTERROR
+is the errno error code.
+.It
+The second argument is a constant string with the unbound lifetime,
+which should tersely provide enough human-readable details about
+the error.
+.It
+The
+.Fn UEXTERROR
+macro can take two optional uintptr_t or 64-bit integer arguments,
+whose meaning is specific to the subsystem.
+The format string may include up to two printf-like format
+specifiers to insert the optional argument values in the
+user output, which is done in userspace.
+.Pp
+The format specifier must be for an character, integer, or pointer type.
+Note that userspace printing assumes all
+.Dt long Ns -derived
+types such as
+.Dt size_t
+are 64-bit and prints them accordingly.
+Signed integer types should thus be cast to
+.Dt int64_t
+or similar to insure proper sign extension.
+.El
+.Pp
+Note that unlike its kernel counterpart
+.Xr EXTERROR 9
+the
+.Nm
+macro does not return a value and sets
+.Xr errno 3
+directly.
+.Pp
+The name of the file and strings passed as the second argument are
+retained in the program or library text as long as the translation unit
+was not compiled with the
+.Cd NO_UEXTERR_STRINGS
+macro defined.
+.Sh SEE ALSO
+.Xr errno 3 ,
+.Xr err 3 ,
+.Xr uexterr_gettext 3 ,
+.Xr exterror 9
+.Sh HISTORY
+The
+.Nm
+facility was introduced in
+.Fx 15.0 .
+.Sh AUTHORS
+This software and this manual page were 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
+.Pq Do CheriBSD feature extraction, maturity, and testing Dc .
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -253,6 +253,7 @@
INTERPOS_pdfork,
INTERPOS_uexterr_gettext,
INTERPOS_pdwait,
+ INTERPOS_uexterr_set,
INTERPOS_MAX
};
@@ -381,7 +382,12 @@
struct _xlocale *locale);
struct uexterror;
+extern struct uexterror uexterr;
int __uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz);
+void __uexterr_set_ue(struct uexterror *ue, int error, int category,
+ const char *mmsg, uint64ptr_t pp1, uint64ptr_t pp2, int line);
int __libc_uexterr_gettext(char *buf, size_t bufsz);
+void __libc_uexterr_set(int eerror, int category, const char *mmsg,
+ uint64ptr_t pp1, uint64ptr_t pp2, int line);
#endif /* _LIBC_PRIVATE_H_ */
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
--- a/lib/libthr/thread/thr_syscalls.c
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -643,6 +643,18 @@
return (__uexterr_format(&curthread->uexterr, buf, bufsz));
}
+static void
+__thr_uexterr_set(int error, int category, const char *mmsg, uint64ptr_t pp1,
+ uint64ptr_t pp2, int line)
+{
+ struct pthread *curthread;
+
+ curthread = _get_curthread();
+
+ __uexterr_set_ue(&curthread->uexterr, error, category, mmsg,
+ pp1, pp2, line);
+}
+
void
__thr_interpose_libc(void)
{
@@ -700,6 +712,7 @@
SLOT(pdfork);
SLOT(uexterr_gettext);
SLOT(pdwait);
+ SLOT(uexterr_set);
#undef SLOT
*(__libc_interposing_slot(
INTERPOS__pthread_mutex_init_calloc_cb)) =
diff --git a/share/man/man9/exterror.9 b/share/man/man9/exterror.9
--- a/share/man/man9/exterror.9
+++ b/share/man/man9/exterror.9
@@ -244,6 +244,7 @@
.Xr errno 3 ,
.Xr err 3 ,
.Xr uexterr_gettext 3
+.Xr uexterr 3
.Sh HISTORY
The
.Nm

File Metadata

Mime Type
text/plain
Expires
Sat, Aug 1, 12:28 PM (17 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35821605
Default Alt Text
D58059.id182528.diff (11 KB)

Event Timeline