1/*	$OpenBSD: subr_kubsan.c,v 1.12 2019/11/06 19:16:48 anton Exp $	*/
2
3/*
4 * Copyright (c) 2019 Anton Lindqvist <anton@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/param.h>
21#include <sys/atomic.h>
22#include <sys/syslimits.h>
23#include <sys/systm.h>
24#include <sys/timeout.h>
25
26#include <uvm/uvm_extern.h>
27
28#define KUBSAN_INTERVAL	100	/* report interval in msec */
29#define KUBSAN_NSLOTS	32
30
31#define NUMBER_BUFSIZ		32
32#define LOCATION_BUFSIZ		(PATH_MAX + 32)	/* filename:line:column */
33#define LOCATION_REPORTED	(1U << 31)
34
35#define NBITS(typ)	(1 << ((typ)->t_info >> 1))
36#define SIGNED(typ)	((typ)->t_info & 1)
37
38struct kubsan_report {
39	enum {
40		KUBSAN_FLOAT_CAST_OVERFLOW,
41		KUBSAN_INVALID_VALUE,
42		KUBSAN_NEGATE_OVERFLOW,
43		KUBSAN_NONNULL_ARG,
44		KUBSAN_OUT_OF_BOUNDS,
45		KUBSAN_OVERFLOW,
46		KUBSAN_POINTER_OVERFLOW,
47		KUBSAN_SHIFT_OUT_OF_BOUNDS,
48		KUBSAN_TYPE_MISMATCH,
49		KUBSAN_UNREACHABLE,
50	} kr_type;
51
52	struct source_location *kr_src;
53
54	union {
55		struct {
56			const struct float_cast_overflow_data *v_data;
57			unsigned long v_val;
58		} v_float_cast_overflow;
59
60		struct {
61			const struct invalid_value_data *v_data;
62			unsigned long v_val;
63		} v_invalid_value;
64
65		struct {
66			const struct overflow_data *v_data;
67			unsigned int v_val;
68		} v_negate_overflow;
69
70		struct {
71			const struct nonnull_arg_data *v_data;
72		} v_nonnull_arg;
73
74		struct {
75			const struct out_of_bounds_data *v_data;
76			unsigned int v_idx;
77		} v_out_of_bounds;
78
79		struct {
80			const struct overflow_data *v_data;
81			unsigned long v_lhs;
82			unsigned long v_rhs;
83			char v_op;
84		} v_overflow;
85
86		struct {
87			const struct pointer_overflow_data *v_data;
88			unsigned long v_base;
89			unsigned long v_res;
90		} v_pointer_overflow;
91
92		struct {
93			const struct shift_out_of_bounds_data *v_data;
94			unsigned long v_lhs;
95			unsigned long v_rhs;
96		} v_shift_out_of_bounds;
97
98		struct {
99			const struct type_mismatch_data *v_data;
100			unsigned long v_ptr;
101		} v_type_mismatch;
102	} kr_u;
103};
104#define kr_float_cast_overflow		kr_u.v_float_cast_overflow
105#define kr_invalid_value		kr_u.v_invalid_value
106#define kr_negate_overflow		kr_u.v_negate_overflow
107#define kr_nonnull_arg			kr_u.v_nonnull_arg
108#define kr_out_of_bounds		kr_u.v_out_of_bounds
109#define kr_overflow			kr_u.v_overflow
110#define kr_pointer_overflow		kr_u.v_pointer_overflow
111#define kr_shift_out_of_bounds		kr_u.v_shift_out_of_bounds
112#define kr_type_mismatch		kr_u.v_type_mismatch
113
114struct type_descriptor {
115	uint16_t t_kind;
116	uint16_t t_info;
117	char t_name[1];	/* type name as variable length array */
118};
119
120struct source_location {
121	const char *sl_filename;
122	uint32_t sl_line;
123	uint32_t sl_column;
124};
125
126struct float_cast_overflow_data {
127	struct source_location d_src;
128	struct type_descriptor *d_ftype;	/* from type */
129	struct type_descriptor *d_ttype;	/* to type */
130};
131
132struct invalid_value_data {
133	struct source_location d_src;
134	struct type_descriptor *d_type;
135};
136
137struct nonnull_arg_data {
138	struct source_location d_src;
139	struct source_location d_attr_src;	/* __attribute__ location */
140	int d_idx;
141};
142
143struct out_of_bounds_data {
144	struct source_location d_src;
145	struct type_descriptor *d_atype;	/* array type */
146	struct type_descriptor *d_itype;	/* index type */
147};
148
149struct overflow_data {
150	struct source_location d_src;
151	struct type_descriptor *d_type;
152};
153
154struct pointer_overflow_data {
155	struct source_location d_src;
156};
157
158struct shift_out_of_bounds_data {
159	struct source_location d_src;
160	struct type_descriptor *d_ltype;
161	struct type_descriptor *d_rtype;
162};
163
164struct type_mismatch_data {
165	struct source_location d_src;
166	struct type_descriptor *d_type;
167	uint8_t d_align;	/* log2 alignment */
168	uint8_t d_kind;
169};
170
171struct unreachable_data {
172	struct source_location d_src;
173};
174
175int64_t		 kubsan_deserialize_int(struct type_descriptor *,
176		    unsigned long);
177uint64_t	 kubsan_deserialize_uint(struct type_descriptor *,
178		    unsigned long);
179void		 kubsan_defer_report(struct kubsan_report *);
180void		 kubsan_format_int(struct type_descriptor *, unsigned long,
181		    char *, size_t);
182int		 kubsan_format_location(const struct source_location *, char *,
183		    size_t);
184int		 kubsan_is_reported(struct source_location *);
185const char	*kubsan_kind(uint8_t);
186void		 kubsan_report(void *);
187void		 kubsan_unreport(struct source_location *);
188
189static int	is_negative(struct type_descriptor *, unsigned long);
190static int	is_shift_exponent_too_large(struct type_descriptor *,
191		    unsigned long);
192
193static const char	*pathstrip(const char *);
194
195#ifdef KUBSAN_WATCH
196int kubsan_watch = 2;
197#else
198int kubsan_watch = 1;
199#endif
200
201struct kubsan_report	*kubsan_reports = NULL;
202struct timeout		 kubsan_timo = TIMEOUT_INITIALIZER(kubsan_report, NULL);
203unsigned int		 kubsan_slot = 0;
204int			 kubsan_cold = 1;
205
206/*
207 * Compiling the kernel with `-fsanitize=undefined' will cause the following
208 * functions to be called when a sanitizer detects undefined behavior.
209 * Some sanitizers are omitted since they are only applicable to C++.
210 *
211 * Every __ubsan_*() sanitizer function also has a corresponding
212 * __ubsan_*_abort() function as part of the ABI provided by Clang.
213 * But, since the kernel never is compiled with `fno-sanitize-recover' for
214 * obvious reasons, they are also omitted.
215 */
216
217void
218__ubsan_handle_add_overflow(struct overflow_data *data,
219    unsigned long lhs, unsigned long rhs)
220{
221	struct kubsan_report kr = {
222		.kr_type		= KUBSAN_OVERFLOW,
223		.kr_src			= &data->d_src,
224		.kr_overflow		= { data, lhs, rhs, '+' },
225	};
226
227	kubsan_defer_report(&kr);
228}
229
230void
231__ubsan_handle_builtin_unreachable(struct unreachable_data *data)
232{
233	struct kubsan_report kr = {
234		.kr_type		= KUBSAN_UNREACHABLE,
235		.kr_src			= &data->d_src,
236	};
237
238	kubsan_defer_report(&kr);
239}
240
241void
242__ubsan_handle_divrem_overflow(struct overflow_data *data,
243    unsigned long lhs, unsigned long rhs)
244{
245	struct kubsan_report kr = {
246		.kr_type		= KUBSAN_OVERFLOW,
247		.kr_src			= &data->d_src,
248		.kr_overflow		= { data, lhs, rhs, '/' },
249	};
250
251	kubsan_defer_report(&kr);
252}
253
254void
255__ubsan_handle_float_cast_overflow(struct float_cast_overflow_data *data,
256    unsigned long val)
257{
258	struct kubsan_report kr = {
259		.kr_type		= KUBSAN_FLOAT_CAST_OVERFLOW,
260		.kr_src			= &data->d_src,
261		.kr_float_cast_overflow	= { data, val },
262	};
263
264	kubsan_defer_report(&kr);
265}
266
267void
268__ubsan_handle_load_invalid_value(struct invalid_value_data *data,
269    unsigned long val)
270{
271	struct kubsan_report kr = {
272		.kr_type		= KUBSAN_INVALID_VALUE,
273		.kr_src			= &data->d_src,
274		.kr_invalid_value	= { data, val },
275	};
276
277	kubsan_defer_report(&kr);
278}
279
280void
281__ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
282{
283	struct kubsan_report kr = {
284		.kr_type		= KUBSAN_NONNULL_ARG,
285		.kr_src			= &data->d_src,
286		.kr_nonnull_arg		= { data },
287	};
288
289	kubsan_defer_report(&kr);
290}
291
292void
293__ubsan_handle_mul_overflow(struct overflow_data *data,
294    unsigned long lhs, unsigned long rhs)
295{
296	struct kubsan_report kr = {
297		.kr_type		= KUBSAN_OVERFLOW,
298		.kr_src			= &data->d_src,
299		.kr_overflow		= { data, lhs, rhs, '*' },
300	};
301
302	kubsan_defer_report(&kr);
303}
304
305void
306__ubsan_handle_negate_overflow(struct overflow_data *data, unsigned long val)
307{
308	struct kubsan_report kr = {
309		.kr_type		= KUBSAN_NEGATE_OVERFLOW,
310		.kr_src			= &data->d_src,
311		.kr_negate_overflow	= { data, val },
312	};
313
314	kubsan_defer_report(&kr);
315}
316
317void
318__ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
319    unsigned long idx)
320{
321	struct kubsan_report kr = {
322		.kr_type		= KUBSAN_OUT_OF_BOUNDS,
323		.kr_src			= &data->d_src,
324		.kr_out_of_bounds	= { data, idx },
325	};
326
327	kubsan_defer_report(&kr);
328}
329
330void
331__ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
332    unsigned long base, unsigned long res)
333{
334	struct kubsan_report kr = {
335		.kr_type		= KUBSAN_POINTER_OVERFLOW,
336		.kr_src			= &data->d_src,
337		.kr_pointer_overflow	= { data, base, res },
338	};
339
340	kubsan_defer_report(&kr);
341}
342
343void
344__ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
345    unsigned long lhs, unsigned long rhs)
346{
347	struct kubsan_report kr = {
348		.kr_type		= KUBSAN_SHIFT_OUT_OF_BOUNDS,
349		.kr_src			= &data->d_src,
350		.kr_shift_out_of_bounds	= { data, lhs, rhs },
351	};
352
353	kubsan_defer_report(&kr);
354}
355
356void
357__ubsan_handle_sub_overflow(struct overflow_data *data,
358    unsigned long lhs, unsigned long rhs)
359{
360	struct kubsan_report kr = {
361		.kr_type		= KUBSAN_OVERFLOW,
362		.kr_src			= &data->d_src,
363		.kr_overflow		= { data, lhs, rhs, '-' },
364	};
365
366	kubsan_defer_report(&kr);
367}
368
369void
370__ubsan_handle_type_mismatch_v1(struct type_mismatch_data *data,
371    unsigned long ptr)
372{
373	struct kubsan_report kr = {
374		.kr_type		= KUBSAN_TYPE_MISMATCH,
375		.kr_src			= &data->d_src,
376		.kr_type_mismatch	= { data, ptr },
377	};
378
379	kubsan_defer_report(&kr);
380}
381
382/*
383 * Allocate storage for reports and schedule the reporter.
384 * Must be called as early on as possible in order to catch undefined behavior
385 * during boot.
386 */
387void
388kubsan_init(void)
389{
390	kubsan_reports = (void *)uvm_pageboot_alloc(
391	    sizeof(struct kubsan_report) * KUBSAN_NSLOTS);
392	kubsan_cold = 0;
393
394	timeout_add_msec(&kubsan_timo, KUBSAN_INTERVAL);
395}
396
397int64_t
398kubsan_deserialize_int(struct type_descriptor *typ, unsigned long val)
399{
400	switch (NBITS(typ)) {
401	case 8:
402		return ((int8_t)val);
403	case 16:
404		return ((int16_t)val);
405	case 32:
406		return ((int32_t)val);
407	case 64:
408	default:
409		return ((int64_t)val);
410	}
411}
412
413uint64_t
414kubsan_deserialize_uint(struct type_descriptor *typ, unsigned long val)
415{
416	switch (NBITS(typ)) {
417	case 8:
418		return ((uint8_t)val);
419	case 16:
420		return ((uint16_t)val);
421	case 32:
422		return ((uint32_t)val);
423	case 64:
424	default:
425		return ((uint64_t)val);
426	}
427}
428
429void
430kubsan_defer_report(struct kubsan_report *kr)
431{
432	unsigned int slot;
433
434	if (__predict_false(kubsan_cold == 1) ||
435	    kubsan_is_reported(kr->kr_src))
436		return;
437
438	slot = atomic_inc_int_nv(&kubsan_slot) - 1;
439	if (slot >= KUBSAN_NSLOTS) {
440		/*
441		 * No slots left, flag source location as not reported and
442		 * hope a slot will be available next time.
443		 */
444		kubsan_unreport(kr->kr_src);
445		return;
446	}
447
448	memcpy(&kubsan_reports[slot], kr, sizeof(*kr));
449}
450
451void
452kubsan_format_int(struct type_descriptor *typ, unsigned long val,
453    char *buf, size_t bufsiz)
454{
455	switch (typ->t_kind) {
456	case 0:	/* integer */
457		if (SIGNED(typ)) {
458			int64_t i = kubsan_deserialize_int(typ, val);
459			snprintf(buf, bufsiz, "%lld", i);
460		} else {
461			uint64_t u = kubsan_deserialize_uint(typ, val);
462			snprintf(buf, bufsiz, "%llu", u);
463		}
464		break;
465	default:
466		snprintf(buf, bufsiz, "%#x<NaN>", typ->t_kind);
467	}
468}
469
470int
471kubsan_format_location(const struct source_location *src, char *buf,
472    size_t bufsiz)
473{
474	const char *path;
475
476	path = pathstrip(src->sl_filename);
477
478	return snprintf(buf, bufsiz, "%s:%u:%u",
479	    path, src->sl_line & ~LOCATION_REPORTED, src->sl_column);
480}
481
482int
483kubsan_is_reported(struct source_location *src)
484{
485	uint32_t *line = &src->sl_line;
486	uint32_t prev;
487
488	/*
489	 * Treat everything as reported when disabled.
490	 * Otherwise, new violations would go by unnoticed.
491	 */
492	if (__predict_false(kubsan_watch == 0))
493		return (1);
494
495	do {
496		prev = *line;
497		/* If already reported, avoid redundant atomic operation. */
498		if (prev & LOCATION_REPORTED)
499			break;
500	} while (atomic_cas_uint(line, prev, prev | LOCATION_REPORTED) != prev);
501
502	return (prev & LOCATION_REPORTED);
503}
504
505const char *
506kubsan_kind(uint8_t kind)
507{
508	static const char *kinds[] = {
509		"load of",
510		"store to",
511		"reference binding to",
512		"member access within",
513		"member call on",
514		"constructor call on",
515		"downcast of",
516		"downcast of",
517		"upcast of",
518		"cast to virtual base of",
519		"_Nonnull binding to",
520		"dynamic operation on"
521	};
522
523	if (kind >= nitems(kinds))
524		return ("?");
525
526	return (kinds[kind]);
527}
528
529void
530kubsan_report(void *arg)
531{
532	char bloc[LOCATION_BUFSIZ];
533	char blhs[NUMBER_BUFSIZ];
534	char brhs[NUMBER_BUFSIZ];
535	struct kubsan_report *kr;
536	unsigned int nslots;
537	unsigned int i = 0;
538
539again:
540	nslots = kubsan_slot;
541	if (nslots == 0)
542		goto done;
543	if (nslots > KUBSAN_NSLOTS)
544		nslots = KUBSAN_NSLOTS;
545
546	for (; i < nslots; i++) {
547		kr = &kubsan_reports[i];
548
549		kubsan_format_location(kr->kr_src, bloc, sizeof(bloc));
550		switch (kr->kr_type) {
551		case KUBSAN_FLOAT_CAST_OVERFLOW: {
552			const struct float_cast_overflow_data *data =
553			    kr->kr_float_cast_overflow.v_data;
554
555			kubsan_format_int(data->d_ftype,
556			    kr->kr_float_cast_overflow.v_val,
557			    blhs, sizeof(blhs));
558			printf("kubsan: %s: %s of type %s is outside the range "
559			    "of representable values of type %s\n",
560			    bloc, blhs, data->d_ftype->t_name,
561			    data->d_ttype->t_name);
562			break;
563		}
564
565		case KUBSAN_INVALID_VALUE: {
566			const struct invalid_value_data *data =
567			    kr->kr_invalid_value.v_data;
568
569			kubsan_format_int(data->d_type,
570			    kr->kr_invalid_value.v_val, blhs, sizeof(blhs));
571			printf("kubsan: %s: load invalid value: load of value "
572			    "%s is not a valid value for type %s\n",
573			    bloc, blhs, data->d_type->t_name);
574			break;
575		}
576
577		case KUBSAN_NEGATE_OVERFLOW: {
578			const struct overflow_data *data =
579			    kr->kr_negate_overflow.v_data;
580
581			kubsan_format_int(data->d_type,
582			    kr->kr_negate_overflow.v_val, blhs, sizeof(blhs));
583			printf("kubsan: %s: negate overflow: negation of %s "
584			    "cannot be represented in type %s\n",
585			    bloc, blhs, data->d_type->t_name);
586			break;
587		}
588
589		case KUBSAN_NONNULL_ARG: {
590			const struct nonnull_arg_data *data =
591			    kr->kr_nonnull_arg.v_data;
592
593			if (data->d_attr_src.sl_filename)
594				kubsan_format_location(&data->d_attr_src,
595				    blhs, sizeof(blhs));
596			else
597				blhs[0] = '\0';
598
599			printf("kubsan: %s: null pointer passed as argument "
600			    "%d, which is declared to never be null%s%s\n",
601			    bloc, data->d_idx,
602			    blhs[0] ? "nonnull specified in " : "", blhs);
603			break;
604		}
605
606		case KUBSAN_OUT_OF_BOUNDS: {
607			const struct out_of_bounds_data *data =
608			    kr->kr_out_of_bounds.v_data;
609
610			kubsan_format_int(data->d_itype,
611			    kr->kr_out_of_bounds.v_idx, blhs, sizeof(blhs));
612			printf("kubsan: %s: out of bounds: index %s is out of "
613			    "range for type %s\n",
614			    bloc, blhs, data->d_atype->t_name);
615			break;
616		}
617
618		case KUBSAN_OVERFLOW: {
619			const struct overflow_data *data =
620			    kr->kr_overflow.v_data;
621
622			kubsan_format_int(data->d_type,
623			    kr->kr_overflow.v_lhs, blhs, sizeof(blhs));
624			kubsan_format_int(data->d_type,
625			    kr->kr_overflow.v_rhs, brhs, sizeof(brhs));
626                        printf("kubsan: %s: %s integer overflow: %s %c %s "
627                            "cannot be represented in type %s\n",
628			    bloc, SIGNED(data->d_type) ? "signed" : "unsigned",
629			    blhs, kr->kr_overflow.v_op, brhs,
630			    data->d_type->t_name);
631			break;
632		}
633
634		case KUBSAN_POINTER_OVERFLOW:
635			printf("kubsan: %s: pointer overflow: pointer "
636			    "expression with base %#lx overflowed to %#lx\n",
637			    bloc, kr->kr_pointer_overflow.v_base,
638			    kr->kr_pointer_overflow.v_res);
639			break;
640
641		case KUBSAN_SHIFT_OUT_OF_BOUNDS: {
642			const struct shift_out_of_bounds_data *data =
643				kr->kr_shift_out_of_bounds.v_data;
644			unsigned long lhs = kr->kr_shift_out_of_bounds.v_lhs;
645			unsigned long rhs = kr->kr_shift_out_of_bounds.v_rhs;
646
647			kubsan_format_int(data->d_ltype, lhs, blhs,
648			    sizeof(blhs));
649			kubsan_format_int(data->d_rtype, rhs, brhs,
650			    sizeof(brhs));
651			if (is_negative(data->d_rtype, rhs))
652				printf("kubsan: %s: shift: shift exponent %s "
653				    "is negative\n",
654				    bloc, brhs);
655			else if (is_shift_exponent_too_large(data->d_rtype, rhs))
656				printf("kubsan: %s: shift: shift exponent %s "
657				    "is too large for %u-bit type\n",
658				    bloc, brhs, NBITS(data->d_rtype));
659			else if (is_negative(data->d_ltype, lhs))
660				printf("kubsan: %s: shift: left shift of "
661				    "negative value %s\n",
662				    bloc, blhs);
663			else
664				printf("kubsan: %s: shift: left shift of %s by "
665				    "%s places cannot be represented in type "
666				    "%s\n",
667				    bloc, blhs, brhs, data->d_ltype->t_name);
668			break;
669		}
670
671		case KUBSAN_TYPE_MISMATCH: {
672			const struct type_mismatch_data *data =
673				kr->kr_type_mismatch.v_data;
674			unsigned long ptr = kr->kr_type_mismatch.v_ptr;
675			unsigned long align = 1UL << data->d_align;
676
677			if (ptr == 0UL)
678				printf("kubsan: %s: type mismatch: %s null "
679				    "pointer of type %s\n",
680				    bloc, kubsan_kind(data->d_kind),
681				    data->d_type->t_name);
682			else if (ptr & (align - 1))
683				printf("kubsan: %s: type mismatch: %s "
684				    "misaligned address %p for type %s which "
685				    "requires %lu byte alignment\n",
686				    bloc, kubsan_kind(data->d_kind),
687				    (void *)ptr, data->d_type->t_name, align);
688			else
689				printf("kubsan: %s: type mismatch: %s address "
690				    "%p with insufficient space for an object "
691				    "of type %s\n",
692				    bloc, kubsan_kind(data->d_kind),
693				    (void *)ptr, data->d_type->t_name);
694			break;
695		}
696
697		case KUBSAN_UNREACHABLE:
698			printf("kubsan: %s: unreachable: calling "
699			    "__builtin_unreachable()\n",
700			    bloc);
701			break;
702		}
703
704#ifdef DDB
705		if (kubsan_watch == 2)
706			db_enter();
707#endif
708	}
709
710	/* New reports can arrive at any time. */
711	if (atomic_cas_uint(&kubsan_slot, nslots, 0) != nslots) {
712		if (nslots < KUBSAN_NSLOTS)
713			goto again;
714		atomic_swap_uint(&kubsan_slot, 0);
715	}
716
717done:
718	timeout_add_msec(&kubsan_timo, KUBSAN_INTERVAL);
719}
720
721void
722kubsan_unreport(struct source_location *src)
723{
724	uint32_t *line = &src->sl_line;
725
726	atomic_clearbits_int(line, LOCATION_REPORTED);
727}
728
729static int
730is_negative(struct type_descriptor *typ, unsigned long val)
731{
732	return (SIGNED(typ) && kubsan_deserialize_int(typ, val) < 0);
733}
734
735static int
736is_shift_exponent_too_large(struct type_descriptor *typ, unsigned long val)
737{
738	return (kubsan_deserialize_int(typ, val) >= NBITS(typ));
739}
740
741/*
742 * A source location is an absolute path making reports quite long.
743 * Instead, use everything after the first /sys/ segment as the path.
744 */
745static const char *
746pathstrip(const char *path)
747{
748	const char *needle = "/sys/";
749	size_t i, j;
750
751	for (i = j = 0; path[i] != '\0'; i++) {
752		if (path[i] != needle[j]) {
753			j = 0;
754			continue;
755		}
756
757		if (needle[++j] == '\0')
758			return path + i + 1;
759	}
760
761	return path;
762}
763