diff options
Diffstat (limited to 'libctf/ctf-create.c')
-rw-r--r-- | libctf/ctf-create.c | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index 073006b..d674603 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -1048,7 +1048,6 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name, ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, enid); unsigned char *old_vlen; ctf_enum_t *en; - size_t i; uint32_t kind, vlen, root; @@ -1068,6 +1067,12 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name, root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info); vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info); + /* Enumeration constant names are only added, and only checked for duplicates, + if the enum they are part of is a root-visible type. */ + + if (root == CTF_ADD_ROOT && ctf_dynhash_lookup (fp->ctf_names, name)) + return (ctf_set_errno (ofp, ECTF_DUPLICATE)); + if (kind != CTF_K_ENUM) return (ctf_set_errno (ofp, ECTF_NOTENUM)); @@ -1075,24 +1080,46 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name, return (ctf_set_errno (ofp, ECTF_DTFULL)); old_vlen = dtd->dtd_vlen; + if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0) return -1; /* errno is set for us. */ + en = (ctf_enum_t *) dtd->dtd_vlen; /* Remove refs in the old vlen region and reapply them. */ ctf_str_move_refs (fp, old_vlen, sizeof (ctf_enum_t) * vlen, dtd->dtd_vlen); - for (i = 0; i < vlen; i++) - if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0) - return (ctf_set_errno (ofp, ECTF_DUPLICATE)); + /* Check for constant duplication within any given enum: only needed for + non-root-visible types, since the duplicate detection above does the job + for root-visible types just fine. */ - en[i].cte_name = ctf_str_add_movable_ref (fp, name, &en[i].cte_name); - en[i].cte_value = value; + if (root == CTF_ADD_NONROOT) + { + size_t i; - if (en[i].cte_name == 0 && name != NULL && name[0] != '\0') + for (i = 0; i < vlen; i++) + if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0) + return (ctf_set_errno (ofp, ECTF_DUPLICATE)); + } + + en[vlen].cte_name = ctf_str_add_movable_ref (fp, name, &en[vlen].cte_name); + en[vlen].cte_value = value; + + if (en[vlen].cte_name == 0 && name != NULL && name[0] != '\0') return (ctf_set_errno (ofp, ctf_errno (fp))); + /* Put the newly-added enumerator name into the name table if this type is + root-visible. */ + + if (root == CTF_ADD_ROOT) + { + if (ctf_dynhash_insert (fp->ctf_names, + (char *) ctf_strptr (fp, en[vlen].cte_name), + (void *) (uintptr_t) enid) < 0) + return ctf_set_errno (fp, ENOMEM); + } + dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1); return 0; |