Index: cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c =================================================================== --- cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c +++ cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c @@ -68,9 +68,11 @@ #define BSWAP_8(x) ((x) & 0xff) #define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8)) #define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16)) +#define BSWAP_64(x) ((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32)) #define SWAP_16(x) (x) = BSWAP_16(x) #define SWAP_32(x) (x) = BSWAP_32(x) +#define SWAP_64(x) (x) = BSWAP_64(x) static int target_requires_swap; @@ -523,6 +525,37 @@ write_unsized_type_rec(b, &ctt); break; + case CONSTVAL: + if (tp->t_extra == 0) + i = 0; + else if (tp->t_extra >= INT32_MIN && tp->t_extra <= INT32_MAX) + i = 4; + else + i = 8; + + ctt.ctt_info = CTF_TYPE_INFO(CTF_K_CONSTVAL, isroot, i); + ctt.ctt_type = tp->t_tdesc->t_id; + write_unsized_type_rec(b, &ctt); + + if (i == 4) { + uint32_t u32 = (int32_t)tp->t_extra; + + if (target_requires_swap) { + SWAP_32(u32); + } + + ctf_buf_write(b, &u32, sizeof (u32)); + } else if (i == 8) { + uint64_t u64 = tp->t_extra; + + if (target_requires_swap) { + SWAP_64(u64); + } + + ctf_buf_write(b, &u64, sizeof (u64)); + } + break; + default: warning("Can't write unknown type %d\n", tp->t_type); } @@ -814,6 +847,9 @@ case CTF_K_ENUM: dptr += sizeof (ctf_enum_t) * vlen; break; + case CTF_K_CONSTVAL: + dptr += vlen; + break; case CTF_K_UNKNOWN: break; default: @@ -1231,6 +1267,33 @@ tdp->t_tdesc = tdarr[ctt->ctt_type]; break; + case CTF_K_CONSTVAL: + tdp->t_type = CONSTVAL; + tdp->t_tdesc = tdarr[ctt->ctt_type]; + + switch (vlen) { + case 0: + tdp->t_extra = 0; + break; + case 4: { + int32_t i32; + + memcpy(&i32, dptr, sizeof(i32)); + tdp->t_extra = i32; + } + break; + case 8: + memcpy(&tdp->t_extra, dptr, + sizeof(tdp->t_extra)); + break; + default: + terminate("%s: Unrecognized CONSTVAL encoding " + "%d\n", __func__, vlen); + } + + dptr += vlen; + break; + case CTF_K_UNKNOWN: break; Index: cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h =================================================================== --- cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h +++ cddl/contrib/opensolaris/tools/ctf/cvt/ctftools.h @@ -144,6 +144,7 @@ VOLATILE, CONST, RESTRICT, + CONSTVAL, STABTYPE_LAST /* do not use */ } stabtype_t; @@ -239,6 +240,7 @@ int t_flags; int t_vgen; /* Visitation generation (see traverse.c) */ int t_emark; /* Equality mark (see equiv_cb() in merge.c) */ + int64_t t_extra; }; #define t_intr t_data.intr @@ -416,6 +418,8 @@ void tdata_free(tdata_t *); void tdata_build_hashes(tdata_t *td); const char *tdesc_name(tdesc_t *); +int tdesc_cvhash(int, void *); +int tdesc_cvcmp(void *, void *); int tdesc_idhash(int, void *); int tdesc_idcmp(void *, void *); int tdesc_namehash(int, void *); Index: cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c =================================================================== --- cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c +++ cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c @@ -80,6 +80,7 @@ * traversals. */ +#include #include #include #include @@ -128,6 +129,7 @@ tdata_t *dw_td; /* root of the tdesc/iidesc tree */ hash_t *dw_tidhash; /* hash of tdescs by t_id */ hash_t *dw_fwdhash; /* hash of fwd decls by name */ + hash_t *dw_constvhash; /* hash of constval tdescs by value */ hash_t *dw_enumhash; /* hash of memberless enums by name */ tdesc_t *dw_void; /* manufactured void type */ tdesc_t *dw_long; /* manufactured long type for arrays */ @@ -166,6 +168,43 @@ return (NULL); } +#define TDLOOKUP_CREATE_IF_MISSING 0x1 +#define TDLOOKUP_VALIDFLAGS TDLOOKUP_CREATE_IF_MISSING +static tdesc_t * +tdesc_lookup_for_typed_constval(dwarf_t *dw, tdesc_t *ttdp, int64_t val, + int flags) +{ + tdesc_t tmpl, *valp; + int tid; + void *v; + + if ((flags & ~TDLOOKUP_VALIDFLAGS) != 0) + terminate("%s: bad flags %x\n", __func__, (unsigned)flags); +#undef TDLOOKUP_VALIDFLAGS + + tmpl = (tdesc_t) { + .t_type = CONSTVAL, + .t_tdesc = ttdp, + .t_extra = val, + }; + if (hash_find(dw->dw_constvhash, &tmpl, &v)) + return (v); + + if ((flags & TDLOOKUP_CREATE_IF_MISSING) == 0) + return (NULL); + + valp = xcalloc(sizeof (*valp)); + *valp = tmpl; + tid = valp->t_id = mfgtid_next(dw); + + debug(3, "Creating new constval type %d <%x>\n", tid, tid); + + hash_add(dw->dw_constvhash, valp); + tdesc_add(dw, valp); + + return (valp); +} + /* * Resolve a tdesc down to a node which should have a size. Returns the size, * zero if the size hasn't yet been determined. @@ -482,6 +521,93 @@ return (die_add(dw, ref)); } +/* + * Given a DW_TAG_formal_parameter, look up or create the relevant type object. + */ +static tdesc_t * +die_lookup_funarg_pass1(dwarf_t *dw, Dwarf_Die die) +{ + tdesc_t *tdp; + Dwarf_Bool hasloc, hasconst; + Dwarf_Error err; + + tdp = die_lookup_pass1(dw, die, DW_AT_type); + + if (dwarf_hasattr(die, DW_AT_location, &hasloc, &err) != DW_DLV_OK) + terminate("dwarf_hasattr: %d\n", err); + if (dwarf_hasattr(die, DW_AT_const_value, &hasconst, &err) != DW_DLV_OK) + terminate("dwarf_hasattr: %d\n", err); + + if (hasloc && hasconst) + terminate("die '%s': func arg has both location and constval\n", + die_name(dw, die)); + else if (hasloc) + return (tdp); + else if (hasconst) { + Dwarf_Attribute dat; + Dwarf_Half form; + Dwarf_Off off; + char *name; + union { + Dwarf_Unsigned uns_val; + Dwarf_Signed s_val; + } _u; + bool sign; + + if (dwarf_attr(die, DW_AT_const_value, &dat, &err) != + DW_DLV_OK) + terminate("dwarf_attr: %d\n", err); + + if (dwarf_whatform(dat, &form, &err) != DW_DLV_OK) + terminate("dwarf_whatform: %d\n", err); + + switch (form) { + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_sdata: + if (dwarf_attrval_signed(die, DW_AT_const_value, + &_u.s_val, &err) != DW_DLV_OK) + terminate("dwarf_attrval_signed: %d\n", err); + sign = true; + break; + case DW_FORM_addr: + case DW_FORM_udata: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + if (dwarf_attrval_unsigned(die, DW_AT_const_value, + &_u.uns_val, &err) != DW_DLV_OK) + terminate("dwarf_attrval_unsigned: %d\n", err); + sign = false; + break; + default: + terminate("dwarf_whatform: unrecognized form %d for " + "die '%s':DW_AT_const_value\n", form, die_name(dw, + die)); + } + + off = die_off(dw, die); + name = die_name(dw, die); + debug(3, "die %llu <%llx>: creating constval function argument" + " %s (%jd)\n", off, off, name, + sign ? (intmax_t)_u.s_val : (intmax_t)_u.uns_val); + free(name); + + tdp = tdesc_lookup_for_typed_constval(dw, tdp, + sign ? (int64_t)_u.s_val : (int64_t)_u.uns_val, + TDLOOKUP_CREATE_IF_MISSING); + return (tdp); + } else { + debug(3, "die '%s': func arg has no location nor constval\n", + die_name(dw, die)); + return (tdp); + } +} + static int die_mem_offset(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Unsigned *valp, int req __unused) @@ -1632,8 +1758,7 @@ if (die_tag(dw, arg) != DW_TAG_formal_parameter) continue; - ii->ii_args[i++] = die_lookup_pass1(dw, arg, - DW_AT_type); + ii->ii_args[i++] = die_lookup_funarg_pass1(dw, arg); } } @@ -1779,38 +1904,18 @@ } while ((die = die_sibling(dw, die)) != NULL); } -static tdtrav_cb_f die_resolvers[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - die_array_resolve, /* array */ - NULL, /* function */ - die_sou_resolve, /* struct */ - die_sou_resolve, /* union */ - die_enum_resolve, /* enum */ - die_fwd_resolve, /* forward */ - NULL, /* typedef */ - NULL, /* typedef unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL, /* restrict */ +static tdtrav_cb_f die_resolvers[STABTYPE_LAST] = { + [ARRAY] = die_array_resolve, + [STRUCT] = die_sou_resolve, + [UNION] = die_sou_resolve, + [ENUM] = die_enum_resolve, + [FORWARD] = die_fwd_resolve, }; -static tdtrav_cb_f die_fail_reporters[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - die_array_failed, /* array */ - NULL, /* function */ - die_sou_failed, /* struct */ - die_sou_failed, /* union */ - NULL, /* enum */ - NULL, /* forward */ - NULL, /* typedef */ - NULL, /* typedef unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL, /* restrict */ +static tdtrav_cb_f die_fail_reporters[STABTYPE_LAST] = { + [ARRAY] = die_array_failed, + [STRUCT] = die_sou_failed, + [UNION] = die_sou_failed, }; static void @@ -1918,6 +2023,8 @@ tdesc_namecmp); dw.dw_enumhash = hash_new(TDESC_HASH_BUCKETS, tdesc_namehash, tdesc_namecmp); + dw.dw_constvhash = hash_new(TDESC_HASH_BUCKETS, tdesc_cvhash, + tdesc_cvcmp); if ((rc = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dw.dw_dw, &dw.dw_err)) == DW_DLV_NO_ENTRY) { Index: cddl/contrib/opensolaris/tools/ctf/cvt/merge.c =================================================================== --- cddl/contrib/opensolaris/tools/ctf/cvt/merge.c +++ cddl/contrib/opensolaris/tools/ctf/cvt/merge.c @@ -526,7 +526,7 @@ return (1); } -static tdtrav_cb_f map_pre[] = { +static tdtrav_cb_f map_pre[STABTYPE_LAST] = { NULL, map_td_tree_pre, /* intrinsic */ map_td_tree_pre, /* pointer */ @@ -540,10 +540,11 @@ tdtrav_assert, /* typedef_unres */ map_td_tree_pre, /* volatile */ map_td_tree_pre, /* const */ - map_td_tree_pre /* restrict */ + map_td_tree_pre, /* restrict */ + map_td_tree_pre, /* constval */ }; -static tdtrav_cb_f map_post[] = { +static tdtrav_cb_f map_post[STABTYPE_LAST] = { NULL, map_td_tree_post, /* intrinsic */ map_td_tree_post, /* pointer */ @@ -557,10 +558,11 @@ tdtrav_assert, /* typedef_unres */ map_td_tree_post, /* volatile */ map_td_tree_post, /* const */ - map_td_tree_post /* restrict */ + map_td_tree_post, /* restrict */ + map_td_tree_post, /* constval */ }; -static tdtrav_cb_f map_self_post[] = { +static tdtrav_cb_f map_self_post[STABTYPE_LAST] = { NULL, map_td_tree_self_post, /* intrinsic */ map_td_tree_self_post, /* pointer */ @@ -574,7 +576,8 @@ tdtrav_assert, /* typedef_unres */ map_td_tree_self_post, /* volatile */ map_td_tree_self_post, /* const */ - map_td_tree_self_post /* restrict */ + map_td_tree_self_post, /* restrict */ + map_td_tree_self_post, /* constval */ }; /* @@ -716,6 +719,7 @@ new->t_size = old->t_size; new->t_id = newselfid; new->t_flags = old->t_flags; + new->t_extra = old->t_extra; return (new); } @@ -875,21 +879,9 @@ return (1); } -static tdtrav_cb_f fwd_redir_cbs[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - NULL, /* array */ - NULL, /* function */ - NULL, /* struct */ - NULL, /* union */ - NULL, /* enum */ - fwd_redir, /* forward */ - NULL, /* typedef */ - tdtrav_assert, /* typedef_unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL /* restrict */ +static tdtrav_cb_f fwd_redir_cbs[STABTYPE_LAST] = { + [FORWARD] = fwd_redir, + [TYPEDEF_UNRES] = tdtrav_assert, }; typedef struct redir_mstr_data { @@ -1116,7 +1108,7 @@ tgt->td_ref--; } -tdesc_ops_t tdesc_ops[] = { +tdesc_ops_t tdesc_ops[STABTYPE_LAST] = { { "ERROR! BAD tdesc TYPE", NULL, NULL }, { "intrinsic", equiv_intrinsic, conjure_intrinsic }, { "pointer", equiv_plain, conjure_plain }, @@ -1130,5 +1122,6 @@ { "typedef_unres", equiv_assert, conjure_assert }, { "volatile", equiv_plain, conjure_plain }, { "const", equiv_plain, conjure_plain }, - { "restrict", equiv_plain, conjure_plain } + { "restrict", equiv_plain, conjure_plain }, + { "constval", equiv_plain, conjure_plain }, }; Index: cddl/contrib/opensolaris/tools/ctf/cvt/output.c =================================================================== --- cddl/contrib/opensolaris/tools/ctf/cvt/output.c +++ cddl/contrib/opensolaris/tools/ctf/cvt/output.c @@ -94,7 +94,7 @@ return (1); } -static tdtrav_cb_f burst_types_cbs[] = { +static tdtrav_cb_f burst_types_cbs[STABTYPE_LAST] = { NULL, save_type_by_id, /* intrinsic */ save_type_by_id, /* pointer */ @@ -108,7 +108,8 @@ tdtrav_assert, /* typedef_unres */ save_type_by_id, /* volatile */ save_type_by_id, /* const */ - save_type_by_id /* restrict */ + save_type_by_id, /* restrict */ + save_type_by_id, /* constval */ }; Index: cddl/contrib/opensolaris/tools/ctf/cvt/stabs.c =================================================================== --- cddl/contrib/opensolaris/tools/ctf/cvt/stabs.c +++ cddl/contrib/opensolaris/tools/ctf/cvt/stabs.c @@ -95,21 +95,9 @@ return (1); } -static tdtrav_cb_f resolve_cbs[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - NULL, /* array */ - NULL, /* function */ - NULL, /* struct */ - NULL, /* union */ - NULL, /* enum */ - resolve_fwd_node, /* forward */ - NULL, /* typedef */ - resolve_tou_node, /* typedef unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL, /* restrict */ +static tdtrav_cb_f resolve_cbs[STABTYPE_LAST] = { + [FORWARD] = resolve_fwd_node, /* forward */ + [TYPEDEF_UNRES] = resolve_tou_node, /* typedef unres */ }; static void Index: cddl/contrib/opensolaris/tools/ctf/cvt/tdata.c =================================================================== --- cddl/contrib/opensolaris/tools/ctf/cvt/tdata.c +++ cddl/contrib/opensolaris/tools/ctf/cvt/tdata.c @@ -66,6 +66,7 @@ case TYPEDEF: case VOLATILE: case CONST: + case CONSTVAL: case RESTRICT: name = tdp->t_tdesc->t_name; break; @@ -173,6 +174,50 @@ return (!streq(tdp1->t_name, tdp2->t_name)); } +#define FNV1A_INITIAL_VALUE 0xcbf29ce484222325ull +static uint64_t +fnv1a_update(uint64_t hash, const void *v, size_t len) +{ + const uint8_t *data = v; + + for (; len--; data++) { + hash ^= (uint64_t)*data; + hash *= 0x100000001b3ull; + } + return (hash); +} + +int +tdesc_cvhash(int nbuckets, void *data) +{ + tdesc_t *cv = data; + uint64_t h; + + h = FNV1A_INITIAL_VALUE; + h = fnv1a_update(h, &cv->t_tdesc, sizeof(cv->t_tdesc)); + h = fnv1a_update(h, &cv->t_extra, sizeof(cv->t_extra)); + return (h % nbuckets); +} + +int +tdesc_cvcmp(void *v1, void *v2) +{ + const tdesc_t *cv1, *cv2; + int rc; + + cv1 = v1; + cv2 = v2; + + rc = tdesc_idcmp(cv1->t_tdesc, cv2->t_tdesc); + if (rc != 0) + return (rc); + + if (cv1->t_extra == cv2->t_extra) + return (0); + else + return (cv1->t_extra > cv2->t_extra ? 1 : -1); +} + #ifdef illumos /*ARGSUSED1*/ static int @@ -230,21 +275,12 @@ } } -static void (*free_cbs[])(tdesc_t *) = { - NULL, - free_intr, - NULL, - free_ardef, - NULL, - free_mlist, - free_mlist, - free_elist, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL +static void (*free_cbs[STABTYPE_LAST])(tdesc_t *) = { + [INTRINSIC] = free_intr, + [ARRAY] = free_ardef, + [STRUCT] = free_mlist, + [UNION] = free_mlist, + [ENUM] = free_elist, }; /*ARGSUSED1*/ @@ -425,7 +461,7 @@ return (1); } -static tdtrav_cb_f build_hashes_cbs[] = { +static tdtrav_cb_f build_hashes_cbs[STABTYPE_LAST] = { NULL, build_hashes, /* intrinsic */ build_hashes, /* pointer */ @@ -439,7 +475,8 @@ tdtrav_assert, /* typedef_unres */ build_hashes, /* volatile */ build_hashes, /* const */ - build_hashes /* restrict */ + build_hashes, /* restrict */ + build_hashes, /* constval */ }; static void Index: cddl/contrib/opensolaris/tools/ctf/cvt/traverse.c =================================================================== --- cddl/contrib/opensolaris/tools/ctf/cvt/traverse.c +++ cddl/contrib/opensolaris/tools/ctf/cvt/traverse.c @@ -38,7 +38,7 @@ #include "memory.h" static int (*tddescenders[])(tdesc_t *, tdtrav_data_t *); -static tdtrav_cb_f tdnops[]; +static tdtrav_cb_f tdnops[STABTYPE_LAST]; void tdtrav_init(tdtrav_data_t *tdtd, int *vgenp, tdtrav_cb_f *firstops, @@ -111,38 +111,17 @@ return (-1); } -static tdtrav_cb_f tdnops[] = { - NULL, - NULL, /* intrinsic */ - NULL, /* pointer */ - NULL, /* array */ - NULL, /* function */ - NULL, /* struct */ - NULL, /* union */ - NULL, /* enum */ - NULL, /* forward */ - NULL, /* typedef */ - NULL, /* typedef_unres */ - NULL, /* volatile */ - NULL, /* const */ - NULL /* restrict */ -}; - -static int (*tddescenders[])(tdesc_t *, tdtrav_data_t *) = { - NULL, - NULL, /* intrinsic */ - tdtrav_plain, /* pointer */ - tdtrav_array, /* array */ - tdtrav_func, /* function */ - tdtrav_su, /* struct */ - tdtrav_su, /* union */ - NULL, /* enum */ - NULL, /* forward */ - tdtrav_plain, /* typedef */ - NULL, /* typedef_unres */ - tdtrav_plain, /* volatile */ - tdtrav_plain, /* const */ - tdtrav_plain /* restrict */ +static int (*tddescenders[STABTYPE_LAST])(tdesc_t *, tdtrav_data_t *) = { + [POINTER] = tdtrav_plain, + [ARRAY] = tdtrav_array, + [FUNCTION] = tdtrav_func, + [STRUCT] = tdtrav_su, + [UNION] = tdtrav_su, + [TYPEDEF] = tdtrav_plain, + [VOLATILE] = tdtrav_plain, + [CONST] = tdtrav_plain, + [RESTRICT] = tdtrav_plain, + [CONSTVAL] = tdtrav_plain, }; int Index: cddl/contrib/opensolaris/tools/ctf/dump/dump.c =================================================================== --- cddl/contrib/opensolaris/tools/ctf/dump/dump.c +++ cddl/contrib/opensolaris/tools/ctf/dump/dump.c @@ -77,7 +77,7 @@ ulong_t s_nargs; /* total number of function arguments */ ulong_t s_argmax; /* longest argument list */ ulong_t s_ntypes; /* total number of types */ - ulong_t s_types[16]; /* number of types by kind */ + ulong_t s_types[CTF_K_MAX+1]; /* number of types by kind */ ulong_t s_nsmem; /* total number of struct members */ ulong_t s_nsbytes; /* total size of all structs */ ulong_t s_smmax; /* largest struct in terms of members */ @@ -610,6 +610,37 @@ } break; + case CTF_K_CONSTVAL: + if (flags != F_STATS) { + int64_t decoded; + + switch (n) { + case 0: + decoded = 0; + break; + case 4: { + int32_t dec32; + + memcpy(&dec32, u.ptr, sizeof(dec32)); + decoded = dec32; + } + break; + case 8: + memcpy(&decoded, u.ptr, sizeof(decoded)); + break; + default: + printf("invalid constval size %lu\n", + n); + return (E_ERROR); + } + + (void) printf("CONSTVAL %jd refers to: %u", + (intmax_t)decoded, tp->ctt_type); + } + + vlen = roundup2(n, 4); + break; + case CTF_K_UNKNOWN: break; /* hole in type id space */ @@ -708,6 +739,8 @@ long_stat("total number of const types", stats.s_types[CTF_K_CONST]); long_stat("total number of restrict types", stats.s_types[CTF_K_RESTRICT]); + long_stat("total number of constval types", + stats.s_types[CTF_K_CONSTVAL]); long_stat("total number of unknowns (holes)", stats.s_types[CTF_K_UNKNOWN]); Index: sys/cddl/contrib/opensolaris/uts/common/sys/ctf.h =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/sys/ctf.h +++ sys/cddl/contrib/opensolaris/uts/common/sys/ctf.h @@ -268,6 +268,8 @@ #define CTF_K_VOLATILE 11 /* ctt_type is base type */ #define CTF_K_CONST 12 /* ctt_type is base type */ #define CTF_K_RESTRICT 13 /* ctt_type is base type */ +#define CTF_K_CONSTVAL 14 /* ctt_type is type; value is vlen-encoded + signed integer */ #define CTF_K_MAX 31 /* Maximum possible CTF_K_* value */