4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * After having been declared, events, FMRIs and authorities must be defined
29 * (instantiated) before they can be used as the subjects of commands.
32 #include <sys/sysmacros.h>
33 #include <libnvpair.h>
37 #include <inj_event.h>
40 #include <inj_string.h>
43 static inj_hash_t inj_defns
[3];
44 static int inj_defns_initialized
;
46 /* Intrinsics (signed and unsigned integer integer constants) */
53 item2hash(inj_itemtype_t item
)
57 assert(item
>= 0 && item
< sizeof (inj_defns
) / sizeof (inj_hash_t
));
59 if (!inj_defns_initialized
) {
60 for (i
= 0; i
< sizeof (inj_defns
) / sizeof (inj_hash_t
); i
++)
61 inj_strhash_create(&inj_defns
[i
]);
62 inj_defns_initialized
= 1;
65 return (&inj_defns
[item
]);
69 inj_defn_lookup(const char *name
, inj_memtype_t type
)
71 inj_hash_t
*hash
= item2hash(inj_mem2item(type
));
74 if ((v
= inj_strhash_lookup(hash
, name
)) == NULL
)
77 return (inj_hash_get_cookie(v
));
81 inj_defn_destroy_memlist(inj_defnmem_t
*m
)
85 for (/* */; m
!= NULL
; m
= n
) {
88 switch (m
->dfm_type
) {
91 inj_defn_destroy_memlist(inj_list_next(&m
->dfm_list
));
94 inj_strfree(m
->dfm_str
);
100 inj_defn_destroy(inj_defn_t
*defn
)
102 if (defn
->defn_name
!= NULL
)
103 inj_strfree(defn
->defn_name
);
105 nvlist_free(defn
->defn_nvl
);
107 inj_defn_destroy_memlist(inj_list_next(&defn
->defn_members
));
110 static inj_defnmem_t
*
111 inj_defn_mem_create_common(inj_defnmemtype_t type
)
113 inj_defnmem_t
*dfm
= inj_zalloc(sizeof (inj_defnmem_t
));
115 dfm
->dfm_type
= type
;
116 dfm
->dfm_lineno
= yylineno
;
122 inj_defn_mem_create(const char *str
, inj_defnmemtype_t type
)
124 inj_defnmem_t
*dfm
= inj_defn_mem_create_common(type
);
132 inj_defn_mem_create_list(inj_defn_t
*list
, inj_defnmemtype_t type
)
134 inj_defnmem_t
*dfm
= inj_defn_mem_create_common(type
);
136 dfm
->dfm_list
= list
->defn_members
;
138 inj_free(list
, sizeof (inj_defn_t
));
144 inj_defn_create(inj_defnmem_t
*dfm
)
146 inj_defn_t
*defn
= inj_zalloc(sizeof (inj_defn_t
));
148 defn
->defn_lineno
= yylineno
;
150 inj_list_append(&defn
->defn_members
, dfm
);
156 inj_defn_addmem(inj_defn_t
*defn
, inj_defnmem_t
*dfm
)
158 inj_list_append(&defn
->defn_members
, dfm
);
162 * Validate the dimensions of an array. If the declared array size was zero,
163 * accept (and return) whatever the definition used. If fewer cells were
164 * defined than were declared, return the declared size - the calling code will
165 * fill the remaining cells with zeros. The definition of more than the
166 * declared number of cells triggers an error. We print and error message in
167 * this case and return the declared number. This will allow processing to
168 * continue. The act of emitting the error will guarantee that we never
169 * pass from parsing to program execution.
172 array_dim_check(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
)
177 for (dfnelems
= 0, l
= inj_list_next(&dfm
->dfm_list
); l
!= NULL
;
178 l
= inj_list_next(l
), dfnelems
++);
180 if (dlm
->dlm_arrdim
!= 0 && dlm
->dlm_arrdim
!= dfnelems
) {
181 yyerror(" %d: defined array has %d elements, expected %d\n",
182 dfm
->dfm_lineno
, dfnelems
, dlm
->dlm_arrdim
);
183 dfnelems
= dlm
->dlm_arrdim
;
186 return (MAX(dfnelems
, dlm
->dlm_arrdim
));
190 * The inj_defn_memcmp_* routines serve two purposes. First, they compare a
191 * given defined member with the corresponding declared member, signalling an
192 * error if the two are incompatible.
194 * Assuming that validation succeeds, an entry is added to the passed nvlist
195 * for the defined member.
198 /* Used to ease signed and unsigned integer validation */
199 static const intr_t inj_intrinsics
[] = {
200 { 0, 0 }, /* MEMTYPE_UNKNOWN */
201 { 1, 8 }, { 1, 16 }, { 1, 32 }, { 1, 64 },
202 { 0, 8 }, { 0, 16 }, { 0, 32 }, { 0, 64 }
206 inj_defn_memcmp_signed(const intr_t
*intr
, inj_declmem_t
*dlm
,
207 inj_defnmem_t
*dfm
, nvlist_t
*nvl
)
211 if (dfm
->dfm_type
!= DEFNMEM_IMM
&& dfm
->dfm_type
!= DEFNMEM_IDENT
)
212 return (inj_set_errno(EINVAL
));
214 if (inj_strtoll(dfm
->dfm_str
, intr
->ei_width
, &val
) < 0)
215 return (-1); /* errno is set for us */
217 switch (dlm
->dlm_type
) {
219 errno
= nvlist_add_int8(nvl
, (char *)dlm
->dlm_name
,
223 errno
= nvlist_add_int16(nvl
, (char *)dlm
->dlm_name
,
227 errno
= nvlist_add_int32(nvl
, (char *)dlm
->dlm_name
,
231 errno
= nvlist_add_int64(nvl
, (char *)dlm
->dlm_name
,
236 die("failed to add member %s\n", dlm
->dlm_name
);
242 inj_defn_memcmp_unsigned(const intr_t
*intr
, inj_declmem_t
*dlm
,
243 inj_defnmem_t
*dfm
, nvlist_t
*nvl
)
247 if (dfm
->dfm_type
!= DEFNMEM_IMM
&& dfm
->dfm_type
!= DEFNMEM_IDENT
)
248 return (inj_set_errno(EINVAL
));
250 if (inj_strtoull(dfm
->dfm_str
, intr
->ei_width
, &val
) < 0)
251 return (-1); /* errno is set for us */
253 switch (dlm
->dlm_type
) {
255 errno
= nvlist_add_uint8(nvl
, (char *)dlm
->dlm_name
,
259 errno
= nvlist_add_uint16(nvl
, (char *)dlm
->dlm_name
,
263 errno
= nvlist_add_uint32(nvl
, (char *)dlm
->dlm_name
,
267 errno
= nvlist_add_uint64(nvl
, (char *)dlm
->dlm_name
,
272 die("failed to add member %s\n", dlm
->dlm_name
);
277 /* Validate an array of (un)signed integers. */
279 inj_defn_memcmp_intr_array(const intr_t
*cont
, inj_declmem_t
*dlm
,
280 inj_defnmem_t
*dfm
, nvlist_t
*nvl
)
282 typedef int (*adder_t
)();
283 static const adder_t signed_adders
[] = {
284 NULL
, nvlist_add_int8_array
, nvlist_add_int16_array
,
285 NULL
, nvlist_add_int32_array
, NULL
, NULL
, NULL
,
286 nvlist_add_int64_array
288 static const adder_t unsigned_adders
[] = {
290 nvlist_add_uint8_array
, nvlist_add_uint16_array
,
291 NULL
, nvlist_add_uint32_array
, NULL
, NULL
, NULL
,
292 nvlist_add_uint64_array
297 int8_t *a8
; uint8_t *au8
;
298 int16_t *a16
; uint16_t *au16
;
299 int32_t *a32
; uint32_t *au32
;
300 int64_t *a64
; uint64_t *au64
;
303 int (*adder
)(nvlist_t
*, const char *, char *, uint_t
);
311 if (dfm
->dfm_type
!= DEFNMEM_ARRAY
)
312 return (inj_set_errno(EINVAL
));
315 * Each nvlist array adder wants an array of its own type as input,
316 * which is reasonable, but it complicates our general implementation.
317 * We fight back with casting magic.
320 nelems
= array_dim_check(dlm
, dfm
);
321 arrsz
= (nelems
+ 1) * (cont
->ei_width
/ NBBY
);
322 arrbase
= inj_zalloc(arrsz
);
323 a
.a
= arr
= (char *)P2ROUNDUP((uintptr_t)arrbase
,
324 cont
->ei_width
/ NBBY
);
326 adder
= (cont
->ei_signed
? signed_adders
:
327 unsigned_adders
)[cont
->ei_width
/ NBBY
];
328 assert(adder
!= NULL
);
330 for (i
= 1, elem
= inj_list_next(&dfm
->dfm_list
); elem
!= NULL
;
331 elem
= inj_list_next(elem
), i
++) {
332 if (elem
->dfm_type
!= DEFNMEM_IMM
&&
333 elem
->dfm_type
!= DEFNMEM_IDENT
) {
334 yyerror(" %d: array cell %d is invalid\n",
340 if (cont
->ei_signed
) {
343 if (inj_strtoll(elem
->dfm_str
, cont
->ei_width
,
345 yyerror(" %d: array cell %d %s\n",
346 dfm
->dfm_lineno
, i
, (errno
== ERANGE
?
347 "out of range for type" : "invalid"));
352 switch (cont
->ei_width
) {
354 *a
.a8
++ = (int8_t)val
;
357 *a
.a16
++ = (int16_t)val
;
360 *a
.a32
++ = (int32_t)val
;
363 *a
.a64
++ = (int64_t)val
;
369 if (inj_strtoull(elem
->dfm_str
, cont
->ei_width
,
371 yyerror(" %d: array cell %d %s\n",
372 dfm
->dfm_lineno
, i
, (errno
== ERANGE
?
373 "out of range for type" : "invalid"));
378 switch (cont
->ei_width
) {
380 *a
.au8
++ = (uint8_t)val
;
383 *a
.au16
++ = (uint16_t)val
;
386 *a
.au32
++ = (uint32_t)val
;
389 *a
.au64
++ = (uint64_t)val
;
394 if (err
== 0 && (errno
= adder(nvl
, dlm
->dlm_name
, arr
, nelems
)) != 0)
395 die("failed to add array member %s", dlm
->dlm_name
);
397 inj_free(arrbase
, arrsz
);
400 return (inj_set_errno(EINVAL
));
406 bool2val(const char *str
, boolean_t
*valp
)
408 if (strcasecmp(str
, "true") == 0)
410 else if (strcasecmp(str
, "false") == 0)
419 inj_defn_memcmp_bool(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
, nvlist_t
*nvl
)
423 if (dfm
->dfm_type
!= DEFNMEM_IDENT
)
424 return (inj_set_errno(EINVAL
));
426 if (bool2val(dfm
->dfm_str
, &val
) < 0)
427 return (inj_set_errno(EINVAL
));
429 if ((errno
= nvlist_add_boolean_value(nvl
, (char *)dlm
->dlm_name
,
431 die("failed to add boolean member %s", dlm
->dlm_name
);
437 inj_defn_memcmp_bool_array(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
,
442 size_t nelems
, arrsz
;
446 if (dfm
->dfm_type
!= DEFNMEM_ARRAY
)
447 return (inj_set_errno(EINVAL
));
449 nelems
= array_dim_check(dlm
, dfm
);
450 arrsz
= nelems
* sizeof (boolean_t
);
451 arr
= inj_zalloc(arrsz
);
453 for (i
= 0, elem
= inj_list_next(&dfm
->dfm_list
); elem
!= NULL
;
454 elem
= inj_list_next(elem
), i
++) {
455 if (elem
->dfm_type
!= DEFNMEM_IDENT
) {
456 yyerror(" %d: array cell %d is invalid\n",
457 dfm
->dfm_lineno
, i
+ 1);
462 if (bool2val(elem
->dfm_str
, &arr
[i
]) < 0)
463 return (inj_set_errno(EINVAL
));
466 if (err
== 0 && (errno
= nvlist_add_boolean_array(nvl
,
467 (char *)dlm
->dlm_name
, arr
, nelems
)) != 0)
468 die("failed to add boolean array member %s", dlm
->dlm_name
);
470 inj_free(arr
, arrsz
);
475 /* Used for both strings and enums */
477 inj_defn_memcmp_strenum(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
, nvlist_t
*nvl
)
479 inj_defnmemtype_t defnmemtype
= (dlm
->dlm_type
== MEMTYPE_ENUM
?
480 DEFNMEM_IDENT
: DEFNMEM_QSTRING
);
481 const char *strenum
= (dlm
->dlm_type
== MEMTYPE_ENUM
? "enum" :
484 if (dfm
->dfm_type
!= defnmemtype
)
485 return (inj_set_errno(EINVAL
));
487 if ((errno
= nvlist_add_string(nvl
, (char *)dlm
->dlm_name
,
488 (char *)dfm
->dfm_str
)) != 0)
489 die("failed to add %s member %s", strenum
, dlm
->dlm_name
);
495 inj_defn_memcmp_strenum_array(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
,
498 inj_defnmemtype_t defnmemtype
= (dlm
->dlm_type
== MEMTYPE_ENUM
?
499 DEFNMEM_IDENT
: DEFNMEM_QSTRING
);
500 const char *strenum
= (dlm
->dlm_type
== MEMTYPE_ENUM
? "enum" :
504 size_t nelems
, arrsz
;
509 if (dfm
->dfm_type
!= DEFNMEM_ARRAY
)
510 return (inj_set_errno(EINVAL
));
512 nelems
= array_dim_check(dlm
, dfm
);
513 arrsz
= nelems
* sizeof (char *);
514 arr
= inj_zalloc(arrsz
);
516 for (i
= 0, elem
= inj_list_next(&dfm
->dfm_list
); elem
!= NULL
;
517 elem
= inj_list_next(elem
), i
++) {
518 if (elem
->dfm_type
!= defnmemtype
) {
519 yyerror(" %d: array cell %d is invalid\n",
520 dfm
->dfm_lineno
, i
+ 1);
525 if (dlm
->dlm_type
== MEMTYPE_ENUM
&&
526 inj_strhash_lookup(dlm
->dlm_enumvals
, elem
->dfm_str
) ==
528 yyerror(" %d: invalid enum value %s\n",
529 dfm
->dfm_lineno
, elem
->dfm_str
);
534 arr
[i
] = elem
->dfm_str
;
537 if (err
== 0 && (errno
= nvlist_add_string_array(nvl
,
538 dlm
->dlm_name
, (char **)arr
, nelems
)) != 0)
539 die("failed to add %s array member %s", strenum
, dlm
->dlm_name
);
541 inj_free(arr
, arrsz
);
546 * Validator for embedded lists (events, fmris, authorities, lists, etc.).
547 * There are two cases to deal with here. The user could either have provided
548 * the name of a previously-defined list, in which case we just make a copy of
549 * said list for insertion into ours. Alternatively, the user could simply
550 * define a new list here. In that case, we recursively invoke the member
551 * comparator, but against the list type for the member being defined.
553 static nvlist_t
*inj_defn_validate_memlist(inj_declmem_t
*, inj_defnmem_t
*);
555 /* Embedded definition */
557 inj_defn_memcmp_sub_list(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
)
559 inj_declmem_t
*subdlm
= inj_list_next(&dlm
->dlm_decl
->decl_members
);
560 inj_defnmem_t
*subdfm
= inj_list_next(&dfm
->dfm_list
);
562 return (inj_defn_validate_memlist(subdlm
, subdfm
));
565 /* Reference to previously-defined thing */
567 inj_defn_memcmp_sub_defined(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
)
572 if ((subdefn
= inj_defn_lookup(dfm
->dfm_str
, dlm
->dlm_type
)) == NULL
) {
573 yyerror(" %d: reference to undefined %s %s\n", dfm
->dfm_lineno
,
574 inj_mem2str(dlm
->dlm_type
), dfm
->dfm_str
);
575 (void) inj_set_errno(EINVAL
);
579 if (subdefn
->defn_decl
!= dlm
->dlm_decl
) {
580 yyerror(" %d: %s %s is not a(n) %s\n", dfm
->dfm_lineno
,
581 inj_mem2str(dlm
->dlm_type
), dfm
->dfm_str
,
582 subdefn
->defn_decl
->decl_name
);
583 (void) inj_set_errno(EINVAL
);
587 assert(subdefn
->defn_nvl
!= NULL
);
589 if ((errno
= nvlist_dup(subdefn
->defn_nvl
, &new, 0)) != 0) {
590 die("failed to duplicate %s list %s",
591 inj_item2str(subdefn
->defn_decl
->decl_type
), dfm
->dfm_str
);
598 inj_defn_memcmp_sub_makenvl(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
)
600 inj_defnmemtype_t dftype
= dfm
->dfm_type
;
601 inj_memtype_t dltype
= dlm
->dlm_type
;
602 nvlist_t
*new = NULL
;
604 if (dftype
== DEFNMEM_LIST
)
605 new = inj_defn_memcmp_sub_list(dlm
, dfm
);
606 else if (dftype
== DEFNMEM_IDENT
&& (dltype
== MEMTYPE_EVENT
||
607 dltype
== MEMTYPE_FMRI
|| dltype
== MEMTYPE_AUTH
))
608 new = inj_defn_memcmp_sub_defined(dlm
, dfm
);
610 (void) inj_set_errno(EINVAL
);
615 /* A single sub-list */
617 inj_defn_memcmp_sub(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
, nvlist_t
*nvl
)
621 if ((new = inj_defn_memcmp_sub_makenvl(dlm
, dfm
)) == NULL
)
622 return (-1); /* errno is set for us */
624 if ((errno
= nvlist_add_nvlist(nvl
, (char *)dlm
->dlm_name
,
626 die("failed to add list member %s", dlm
->dlm_name
);
631 /* An array of sub-lists (for example, an array of events of a given type) */
633 inj_defn_memcmp_sub_array(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
, nvlist_t
*nvl
)
635 size_t nelems
, arrsz
;
641 if (dfm
->dfm_type
!= DEFNMEM_ARRAY
)
642 return (inj_set_errno(EINVAL
));
644 nelems
= array_dim_check(dlm
, dfm
);
645 arrsz
= nelems
* sizeof (char *);
646 arr
= inj_zalloc(arrsz
);
648 for (i
= 0, elem
= inj_list_next(&dfm
->dfm_list
); elem
!= NULL
;
649 elem
= inj_list_next(elem
), i
++) {
650 if ((arr
[i
] = inj_defn_memcmp_sub_makenvl(dlm
, elem
)) == NULL
) {
651 yyerror(" %d: array cell %d is invalid\n",
652 elem
->dfm_lineno
, i
+ 1);
658 if (err
== 0 && (errno
= nvlist_add_nvlist_array(nvl
,
659 (char *)dlm
->dlm_name
, arr
, nelems
)) != 0)
660 die("failed to add nvlist list member %s", dlm
->dlm_name
);
662 inj_free(arr
, arrsz
);
668 * The declaration-definition member comparator. Designed to recursive
669 * invocation to allow for the validation of embedded/referenced lists.
672 inj_defn_validate_memlist(inj_declmem_t
*dlm
, inj_defnmem_t
*dfm
)
676 int rc
, nmem
, dlnmem
, dfnmem
;
679 if ((errno
= nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0)) != 0)
680 die("failed to allocate nvl for event");
682 for (nmem
= 1; dlm
!= NULL
&& dfm
!= NULL
;
683 dlm
= inj_list_next(dlm
), dfm
= inj_list_next(dfm
), nmem
++) {
685 switch (dlm
->dlm_type
) {
690 intr
= &inj_intrinsics
[dlm
->dlm_type
];
692 if (dlm
->dlm_flags
& DECLMEM_F_ARRAY
) {
693 rc
= inj_defn_memcmp_intr_array(intr
, dlm
, dfm
,
696 rc
= inj_defn_memcmp_signed(intr
, dlm
, dfm
,
705 intr
= &inj_intrinsics
[dlm
->dlm_type
];
707 if (dlm
->dlm_flags
& DECLMEM_F_ARRAY
) {
708 rc
= inj_defn_memcmp_intr_array(intr
, dlm
, dfm
,
711 rc
= inj_defn_memcmp_unsigned(intr
, dlm
, dfm
,
717 if (dlm
->dlm_flags
& DECLMEM_F_ARRAY
)
718 rc
= inj_defn_memcmp_bool_array(dlm
, dfm
, nvl
);
720 rc
= inj_defn_memcmp_bool(dlm
, dfm
, nvl
);
724 if (dlm
->dlm_flags
& DECLMEM_F_ARRAY
) {
725 rc
= inj_defn_memcmp_strenum_array(dlm
, dfm
,
728 rc
= inj_defn_memcmp_strenum(dlm
, dfm
, nvl
);
732 if (dlm
->dlm_flags
& DECLMEM_F_ARRAY
) {
733 rc
= inj_defn_memcmp_strenum_array(dlm
, dfm
,
736 rc
= inj_defn_memcmp_strenum(dlm
, dfm
, nvl
);
743 if (dlm
->dlm_flags
& DECLMEM_F_ARRAY
)
744 rc
= inj_defn_memcmp_sub_array(dlm
, dfm
, nvl
);
746 rc
= inj_defn_memcmp_sub(dlm
, dfm
, nvl
);
750 die("unknown decl member type %d on member %s\n",
751 dlm
->dlm_type
, dlm
->dlm_name
);
755 yyerror(" %d: %s for member %s\n", dfm
->dfm_lineno
,
756 (errno
== ERANGE
? "value out of range" :
757 "invalid value"), dlm
->dlm_name
);
762 dlnmem
= dfnmem
= nmem
;
764 while (dlm
!= NULL
) {
765 dlm
= inj_list_next(dlm
);
769 while (dfm
!= NULL
) {
770 dfm
= inj_list_next(dfm
);
774 if (dlnmem
!= dfnmem
) {
775 yyerror("%d members found, expected %d", dfnmem
, dlnmem
);
788 * The members have all been defined. Validate the members against the
789 * declaration, and add it to the appropriate "defined" list.
792 inj_defn_finish(inj_defn_t
*defn
, const char *declnm
, const char *name
,
795 inj_decl_t
*decl
= inj_decl_lookup(declnm
, type
);
796 inj_hash_t
*hash
= item2hash(type
);
801 defn
->defn_name
= name
;
802 defn
->defn_decl
= decl
;
805 yyerror("unknown %s type %s\n", inj_item2str(type
), declnm
);
806 inj_defn_destroy(defn
);
810 dlm
= inj_list_next(&decl
->decl_members
);
811 dfm
= inj_list_next(&defn
->defn_members
);
813 if ((defn
->defn_nvl
= inj_defn_validate_memlist(dlm
, dfm
)) == NULL
) {
814 inj_defn_destroy(defn
);
818 if (type
== ITEMTYPE_EVENT
) {
819 if ((errno
= nvlist_add_string(defn
->defn_nvl
, "class",
820 (char *)defn
->defn_decl
->decl_name
)) != 0)
821 die("failed to add class to %s", name
);
824 if ((v
= inj_strhash_lookup(hash
, name
)) != NULL
) {
825 inj_defn_t
*other
= inj_hash_get_cookie(v
);
827 yyerror("duplicate %s name %s (other on line %d)\n",
828 inj_item2str(type
), name
, other
->defn_lineno
);
829 inj_defn_destroy(defn
);
833 (void) inj_strhash_insert(hash
, name
, (uintptr_t)defn
);