diff options
-rw-r--r-- | libctf/ChangeLog | 141 | ||||
-rw-r--r-- | libctf/ctf-archive.c | 3 | ||||
-rw-r--r-- | libctf/ctf-create.c | 423 | ||||
-rw-r--r-- | libctf/ctf-impl.h | 54 | ||||
-rw-r--r-- | libctf/ctf-link.c | 20 | ||||
-rw-r--r-- | libctf/ctf-lookup.c | 23 | ||||
-rw-r--r-- | libctf/ctf-open.c | 206 | ||||
-rw-r--r-- | libctf/ctf-string.c | 163 | ||||
-rw-r--r-- | libctf/ctf-types.c | 277 | ||||
-rw-r--r-- | libctf/ctf-util.c | 8 |
10 files changed, 896 insertions, 422 deletions
diff --git a/libctf/ChangeLog b/libctf/ChangeLog index f3e136f..723db81 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,3 +1,144 @@ +2019-08-09 Nick Alcock <nick.alcock@oracle.com> + + * ctf-impl.h (ctf_names_t): New. + (ctf_lookup_t) <ctf_hash>: Now a ctf_names_t, not a ctf_hash_t. + (ctf_file_t) <ctf_structs>: Likewise. + <ctf_unions>: Likewise. + <ctf_enums>: Likewise. + <ctf_names>: Likewise. + <ctf_lookups>: Improve comment. + <ctf_ptrtab_len>: New. + <ctf_prov_strtab>: New. + <ctf_str_prov_offset>: New. + <ctf_dtbyname>: Remove, redundant to the names hashes. + <ctf_dtnextid>: Remove, redundant to ctf_typemax. + (ctf_dtdef_t) <dtd_name>: Remove. + <dtd_data>: Note that the ctt_name is now populated. + (ctf_str_atom_t) <csa_offset>: This is now the strtab + offset for internal strings too. + <csa_external_offset>: New, the external strtab offset. + (CTF_INDEX_TO_TYPEPTR): Handle the LCTF_RDWR case. + (ctf_name_table): New declaration. + (ctf_lookup_by_rawname): Likewise. + (ctf_lookup_by_rawhash): Likewise. + (ctf_set_ctl_hashes): Likewise. + (ctf_serialize): Likewise. + (ctf_dtd_insert): Adjust. + (ctf_simple_open_internal): Likewise. + (ctf_bufopen_internal): Likewise. + (ctf_list_empty_p): Likewise. + (ctf_str_remove_ref): Likewise. + (ctf_str_add): Returns uint32_t now. + (ctf_str_add_ref): Likewise. + (ctf_str_add_external): Now returns a boolean (int). + * ctf-string.c (ctf_strraw_explicit): Check the ctf_prov_strtab + for strings in the appropriate range. + (ctf_str_create_atoms): Create the ctf_prov_strtab. Detect OOM + when adding the null string to the new strtab. + (ctf_str_free_atoms): Destroy the ctf_prov_strtab. + (ctf_str_add_ref_internal): Add make_provisional argument. If + make_provisional, populate the offset and fill in the + ctf_prov_strtab accordingly. + (ctf_str_add): Return the offset, not the string. + (ctf_str_add_ref): Likewise. + (ctf_str_add_external): Return a success integer. + (ctf_str_remove_ref): New, remove a single ref. + (ctf_str_count_strtab): Do not count the initial null string's + length or the existence or length of any unreferenced internal + atoms. + (ctf_str_populate_sorttab): Skip atoms with no refs. + (ctf_str_write_strtab): Populate the nullstr earlier. Add one + to the cts_len for the null string, since it is no longer done + in ctf_str_count_strtab. Adjust for csa_external_offset rename. + Populate the csa_offset for both internal and external cases. + Flush the ctf_prov_strtab afterwards, and reset the + ctf_str_prov_offset. + * ctf-create.c (ctf_grow_ptrtab): New. + (ctf_create): Call it. Initialize new fields rather than old + ones. Tell ctf_bufopen_internal that this is a writable dictionary. + Set the ctl hashes and data model. + (ctf_update): Rename to... + (ctf_serialize): ... this. Leave a compatibility function behind. + Tell ctf_simple_open_internal that this is a writable dictionary. + Pass the new fields along from the old dictionary. Drop + ctf_dtnextid and ctf_dtbyname. Use ctf_strraw, not dtd_name. + Do not zero out the DTD's ctt_name. + (ctf_prefixed_name): Rename to... + (ctf_name_table): ... this. No longer return a prefixed name: return + the applicable name table instead. + (ctf_dtd_insert): Use it, and use the right name table. Pass in the + kind we're adding. Migrate away from dtd_name. + (ctf_dtd_delete): Adjust similarly. Remove the ref to the + deleted ctt_name. + (ctf_dtd_lookup_type_by_name): Remove. + (ctf_dynamic_type): Always return NULL on read-only dictionaries. + No longer check ctf_dtnextid: check ctf_typemax instead. + (ctf_snapshot): No longer use ctf_dtnextid: use ctf_typemax instead. + (ctf_rollback): Likewise. No longer fail with ECTF_OVERROLLBACK. Use + ctf_name_table and the right name table, and migrate away from + dtd_name as in ctf_dtd_delete. + (ctf_add_generic): Pass in the kind explicitly and pass it to + ctf_dtd_insert. Use ctf_typemax, not ctf_dtnextid. Migrate away + from dtd_name to using ctf_str_add_ref to populate the ctt_name. + Grow the ptrtab if needed. + (ctf_add_encoded): Pass in the kind. + (ctf_add_slice): Likewise. + (ctf_add_array): Likewise. + (ctf_add_function): Likewise. + (ctf_add_typedef): Likewise. + (ctf_add_reftype): Likewise. Initialize the ctf_ptrtab, checking + ctt_name rather than dtd_name. + (ctf_add_struct_sized): Pass in the kind. Use + ctf_lookup_by_rawname, not ctf_hash_lookup_type / + ctf_dtd_lookup_type_by_name. + (ctf_add_union_sized): Likewise. + (ctf_add_enum): Likewise. + (ctf_add_enum_encoded): Likewise. + (ctf_add_forward): Likewise. + (ctf_add_type): Likewise. + (ctf_compress_write): Call ctf_serialize: adjust for ctf_size not + being initialized until after the call. + (ctf_write_mem): Likewise. + (ctf_write): Likewise. + * ctf-archive.c (arc_write_one_ctf): Likewise. + * ctf-lookup.c (ctf_lookup_by_name): Use ctf_lookuup_by_rawhash, not + ctf_hash_lookup_type. + (ctf_lookup_by_id): No longer check the readonly types if the + dictionary is writable. + * ctf-open.c (init_types): Assert that this dictionary is not + writable. Adjust to use the new name hashes, ctf_name_table, + and ctf_ptrtab_len. GNU style fix for the final ptrtab scan. + (ctf_bufopen_internal): New 'writable' parameter. Flip on LCTF_RDWR + if set. Drop out early when dictionary is writable. Split the + ctf_lookups initialization into... + (ctf_set_cth_hashes): ... this new function. + (ctf_simple_open_internal): Adjust. New 'writable' parameter. + (ctf_simple_open): Adjust accordingly. + (ctf_bufopen): Likewise. + (ctf_file_close): Destroy the appropriate name hashes. No longer + destroy ctf_dtbyname, which is gone. + (ctf_getdatasect): Remove spurious "extern". + * ctf-types.c (ctf_lookup_by_rawname): New, look up types in the + specified name table, given a kind. + (ctf_lookup_by_rawhash): Likewise, given a ctf_names_t *. + (ctf_member_iter): Add support for iterating over the + dynamic type list. + (ctf_enum_iter): Likewise. + (ctf_variable_iter): Likewise. + (ctf_type_rvisit): Likewise. + (ctf_member_info): Add support for types in the dynamic type list. + (ctf_enum_name): Likewise. + (ctf_enum_value): Likewise. + (ctf_func_type_info): Likewise. + (ctf_func_type_args): Likewise. + * ctf-link.c (ctf_accumulate_archive_names): No longer call + ctf_update. + (ctf_link_write): Likewise. + (ctf_link_intern_extern_string): Adjust for new + ctf_str_add_external return value. + (ctf_link_add_strtab): Likewise. + * ctf-util.c (ctf_list_empty_p): New. + 2019-08-05 Nick Alcock <nick.alcock@oracle.com> * ctf-types.c (ctf_type_resolve): Return ECTF_NONREPRESENTABLE on diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c index 979641c..ed1483a 100644 --- a/libctf/ctf-archive.c +++ b/libctf/ctf-archive.c @@ -267,6 +267,9 @@ arc_write_one_ctf (ctf_file_t * f, int fd, size_t threshold) size_t ctfsz_len; int (*writefn) (ctf_file_t * fp, int fd); + if (ctf_serialize (f) < 0) + return f->ctf_errno * -1; + if ((off = lseek (fd, 0, SEEK_CUR)) < 0) return errno * -1; diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index 466777a..16e7de8 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -27,6 +27,40 @@ #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #endif +/* Make sure the ptrtab has enough space for at least one more type. + + We start with 4KiB of ptrtab, enough for a thousand types, then grow it 25% + at a time. */ + +static int +ctf_grow_ptrtab (ctf_file_t *fp) +{ + size_t new_ptrtab_len = fp->ctf_ptrtab_len; + + /* We allocate one more ptrtab entry than we need, for the initial zero, + plus one because the caller will probably allocate a new type. */ + + if (fp->ctf_ptrtab == NULL) + new_ptrtab_len = 1024; + else if ((fp->ctf_typemax + 2) > fp->ctf_ptrtab_len) + new_ptrtab_len = fp->ctf_ptrtab_len * 1.25; + + if (new_ptrtab_len != fp->ctf_ptrtab_len) + { + uint32_t *new_ptrtab; + + if ((new_ptrtab = realloc (fp->ctf_ptrtab, + new_ptrtab_len * sizeof (uint32_t))) == NULL) + return (ctf_set_errno (fp, ENOMEM)); + + fp->ctf_ptrtab = new_ptrtab; + memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0, + (new_ptrtab_len - fp->ctf_ptrtab_len) * sizeof (uint32_t)); + fp->ctf_ptrtab_len = new_ptrtab_len; + } + return 0; +} + /* To create an empty CTF container, we just declare a zeroed header and call ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new container r/w and initialize the dynamic members. We start assigning type IDs at 1 because @@ -39,7 +73,7 @@ ctf_create (int *errp) ctf_dynhash_t *dthash; ctf_dynhash_t *dvhash; - ctf_dynhash_t *dtbyname; + ctf_dynhash_t *structs = NULL, *unions = NULL, *enums = NULL, *names = NULL; ctf_sect_t cts; ctf_file_t *fp; @@ -60,9 +94,15 @@ ctf_create (int *errp) goto err_dt; } - dtbyname = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, - free, NULL); - if (dtbyname == NULL) + structs = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, + NULL, NULL); + unions = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, + NULL, NULL); + enums = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, + NULL, NULL); + names = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, + NULL, NULL); + if (!structs || !unions || !enums || !names) { ctf_set_open_errno (errp, EAGAIN); goto err_dv; @@ -73,23 +113,35 @@ ctf_create (int *errp) cts.cts_size = sizeof (hdr); cts.cts_entsize = 1; - if ((fp = ctf_bufopen (&cts, NULL, NULL, errp)) == NULL) - goto err_dtbyname; + if ((fp = ctf_bufopen_internal (&cts, NULL, NULL, NULL, 1, errp)) == NULL) + goto err_dv; - fp->ctf_flags |= LCTF_RDWR; - fp->ctf_dtbyname = dtbyname; + fp->ctf_structs.ctn_writable = structs; + fp->ctf_unions.ctn_writable = unions; + fp->ctf_enums.ctn_writable = enums; + fp->ctf_names.ctn_writable = names; fp->ctf_dthash = dthash; fp->ctf_dvhash = dvhash; - fp->ctf_dtnextid = 1; fp->ctf_dtoldid = 0; fp->ctf_snapshots = 1; fp->ctf_snapshot_lu = 0; + ctf_set_ctl_hashes (fp); + ctf_setmodel (fp, CTF_MODEL_NATIVE); + if (ctf_grow_ptrtab (fp) < 0) + { + ctf_set_open_errno (errp, ctf_errno (fp)); + ctf_file_close (fp); + return NULL; + } + return fp; - err_dtbyname: - ctf_dynhash_destroy (dtbyname); err_dv: + ctf_dynhash_destroy (structs); + ctf_dynhash_destroy (unions); + ctf_dynhash_destroy (enums); + ctf_dynhash_destroy (names); ctf_dynhash_destroy (dvhash); err_dt: ctf_dynhash_destroy (dthash); @@ -187,23 +239,30 @@ ctf_sort_var (const void *one_, const void *two_, void *arg_) ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab))); } -/* If the specified CTF container is writable and has been modified, reload this - container with the updated type definitions. In order to make this code and - the rest of libctf as simple as possible, we perform updates by taking the - dynamic type definitions and creating an in-memory CTF file containing the - definitions, and then call ctf_simple_open_internal() on it. This not only - leverages ctf_simple_open(), but also avoids having to bifurcate the rest of - the library code with different lookup paths for static and dynamic type - definitions. We are therefore optimizing greatly for lookup over update, - which we assume will be an uncommon operation. We perform one extra trick - here for the benefit of callers and to keep our code simple: - ctf_simple_open_internal() will return a new ctf_file_t, but we want to keep - the fp constant for the caller, so after ctf_simple_open_internal() returns, - we use memcpy to swap the interior of the old and new ctf_file_t's, and then - free the old. */ +/* Compatibility: just update the threshold for ctf_discard. */ int ctf_update (ctf_file_t *fp) { + if (!(fp->ctf_flags & LCTF_RDWR)) + return (ctf_set_errno (fp, ECTF_RDONLY)); + + fp->ctf_dtoldid = fp->ctf_typemax; + return 0; +} + +/* If the specified CTF container is writable and has been modified, reload this + container with the updated type definitions, ready for serialization. In + order to make this code and the rest of libctf as simple as possible, we + perform updates by taking the dynamic type definitions and creating an + in-memory CTF file containing the definitions, and then call + ctf_simple_open_internal() on it. We perform one extra trick here for the + benefit of callers and to keep our code simple: ctf_simple_open_internal() + will return a new ctf_file_t, but we want to keep the fp constant for the + caller, so after ctf_simple_open_internal() returns, we use memcpy to swap + the interior of the old and new ctf_file_t's, and then free the old. */ +int +ctf_serialize (ctf_file_t *fp) +{ ctf_file_t ofp, *nfp; ctf_header_t hdr, *hdrp; ctf_dtdef_t *dtd; @@ -335,8 +394,7 @@ ctf_update (ctf_file_t *fp) uint32_t encoding; size_t len; ctf_stype_t *copied; - - dtd->dtd_data.ctt_name = 0; + const char *name; if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) len = sizeof (ctf_stype_t); @@ -345,8 +403,9 @@ ctf_update (ctf_file_t *fp) memcpy (t, &dtd->dtd_data, len); copied = (ctf_stype_t *) t; /* name is at the start: constant offset. */ - if (dtd->dtd_name) - ctf_str_add_ref (fp, dtd->dtd_name, &copied->ctt_name); + if (copied->ctt_name + && (name = ctf_strraw (fp, copied->ctt_name)) != NULL) + ctf_str_add_ref (fp, name, &copied->ctt_name); t += len; switch (kind) @@ -448,7 +507,7 @@ ctf_update (ctf_file_t *fp) if ((nfp = ctf_simple_open_internal ((char *) buf, buf_size, NULL, 0, 0, NULL, 0, fp->ctf_syn_ext_strtab, - &err)) == NULL) + 1, &err)) == NULL) { ctf_free (buf); return (ctf_set_errno (fp, err)); @@ -463,15 +522,16 @@ ctf_update (ctf_file_t *fp) nfp->ctf_dynbase = buf; /* Make sure buf is freed on close. */ nfp->ctf_dthash = fp->ctf_dthash; nfp->ctf_dtdefs = fp->ctf_dtdefs; - nfp->ctf_dtbyname = fp->ctf_dtbyname; nfp->ctf_dvhash = fp->ctf_dvhash; nfp->ctf_dvdefs = fp->ctf_dvdefs; - nfp->ctf_dtnextid = fp->ctf_dtnextid; - nfp->ctf_dtoldid = fp->ctf_dtnextid - 1; + nfp->ctf_dtoldid = fp->ctf_dtoldid; nfp->ctf_snapshots = fp->ctf_snapshots + 1; nfp->ctf_specific = fp->ctf_specific; + nfp->ctf_ptrtab = fp->ctf_ptrtab; + nfp->ctf_ptrtab_len = fp->ctf_ptrtab_len; nfp->ctf_link_inputs = fp->ctf_link_inputs; nfp->ctf_link_outputs = fp->ctf_link_outputs; + nfp->ctf_str_prov_offset = fp->ctf_str_prov_offset; nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab; nfp->ctf_link_cu_mapping = fp->ctf_link_cu_mapping; nfp->ctf_link_type_mapping = fp->ctf_link_type_mapping; @@ -480,12 +540,20 @@ ctf_update (ctf_file_t *fp) nfp->ctf_snapshot_lu = fp->ctf_snapshots; - fp->ctf_dtbyname = NULL; + memcpy (&nfp->ctf_lookups, fp->ctf_lookups, sizeof (fp->ctf_lookups)); + nfp->ctf_structs = fp->ctf_structs; + nfp->ctf_unions = fp->ctf_unions; + nfp->ctf_enums = fp->ctf_enums; + nfp->ctf_names = fp->ctf_names; + fp->ctf_dthash = NULL; ctf_str_free_atoms (nfp); nfp->ctf_str_atoms = fp->ctf_str_atoms; + nfp->ctf_prov_strtab = fp->ctf_prov_strtab; fp->ctf_str_atoms = NULL; + fp->ctf_prov_strtab = NULL; memset (&fp->ctf_dtdefs, 0, sizeof (ctf_list_t)); + fp->ctf_ptrtab = NULL; fp->ctf_link_inputs = NULL; fp->ctf_link_outputs = NULL; fp->ctf_syn_ext_strtab = NULL; @@ -494,63 +562,54 @@ ctf_update (ctf_file_t *fp) fp->ctf_dvhash = NULL; memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t)); + memset (fp->ctf_lookups, 0, sizeof (fp->ctf_lookups)); + fp->ctf_structs.ctn_writable = NULL; + fp->ctf_unions.ctn_writable = NULL; + fp->ctf_enums.ctn_writable = NULL; + fp->ctf_names.ctn_writable = NULL; memcpy (&ofp, fp, sizeof (ctf_file_t)); memcpy (fp, nfp, sizeof (ctf_file_t)); memcpy (nfp, &ofp, sizeof (ctf_file_t)); - /* Initialize the ctf_lookup_by_name top-level dictionary. We keep an - array of type name prefixes and the corresponding ctf_dynhash to use. - NOTE: This code must be kept in sync with the code in ctf_bufopen(). */ - - fp->ctf_lookups[0].ctl_hash = fp->ctf_structs; - fp->ctf_lookups[1].ctl_hash = fp->ctf_unions; - fp->ctf_lookups[2].ctl_hash = fp->ctf_enums; - fp->ctf_lookups[3].ctl_hash = fp->ctf_names; - nfp->ctf_refcnt = 1; /* Force nfp to be freed. */ ctf_file_close (nfp); return 0; } -static char * -ctf_prefixed_name (int kind, const char *name) +ctf_names_t * +ctf_name_table (ctf_file_t *fp, int kind) { - char *prefixed; - switch (kind) { case CTF_K_STRUCT: - prefixed = ctf_strdup ("struct "); - break; + return &fp->ctf_structs; case CTF_K_UNION: - prefixed = ctf_strdup ("union "); - break; + return &fp->ctf_unions; case CTF_K_ENUM: - prefixed = ctf_strdup ("enum "); - break; + return &fp->ctf_enums; default: - prefixed = ctf_strdup (""); + return &fp->ctf_names; } - - prefixed = ctf_str_append (prefixed, name); - return prefixed; } int -ctf_dtd_insert (ctf_file_t *fp, ctf_dtdef_t *dtd) +ctf_dtd_insert (ctf_file_t *fp, ctf_dtdef_t *dtd, int kind) { + const char *name; if (ctf_dynhash_insert (fp->ctf_dthash, (void *) dtd->dtd_type, dtd) < 0) return -1; - if (dtd->dtd_name) + if (dtd->dtd_data.ctt_name + && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL) { - int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); - if (ctf_dynhash_insert (fp->ctf_dtbyname, - ctf_prefixed_name (kind, dtd->dtd_name), - dtd) < 0) - return -1; + if (ctf_dynhash_insert (ctf_name_table (fp, kind)->ctn_writable, + (char *) name, (void *) dtd->dtd_type) < 0) + { + ctf_dynhash_remove (fp->ctf_dthash, (void *) dtd->dtd_type); + return -1; + } } ctf_list_append (&fp->ctf_dtdefs, dtd); return 0; @@ -561,6 +620,7 @@ ctf_dtd_delete (ctf_file_t *fp, ctf_dtdef_t *dtd) { ctf_dmdef_t *dmd, *nmd; int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); + const char *name; ctf_dynhash_remove (fp->ctf_dthash, (void *) dtd->dtd_type); @@ -583,14 +643,12 @@ ctf_dtd_delete (ctf_file_t *fp, ctf_dtdef_t *dtd) break; } - if (dtd->dtd_name) + if (dtd->dtd_data.ctt_name + && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL) { - char *name; - - name = ctf_prefixed_name (kind, dtd->dtd_name); - ctf_dynhash_remove (fp->ctf_dtbyname, name); - free (name); - ctf_free (dtd->dtd_name); + ctf_dynhash_remove (ctf_name_table (fp, kind)->ctn_writable, + name); + ctf_str_remove_ref (fp, name, &dtd->dtd_data.ctt_name); } ctf_list_delete (&fp->ctf_dtdefs, dtd); @@ -603,33 +661,20 @@ ctf_dtd_lookup (const ctf_file_t *fp, ctf_id_t type) return (ctf_dtdef_t *) ctf_dynhash_lookup (fp->ctf_dthash, (void *) type); } -static ctf_id_t -ctf_dtd_lookup_type_by_name (ctf_file_t *fp, int kind, const char *name) -{ - ctf_dtdef_t *dtd; - char *decorated = ctf_prefixed_name (kind, name); - - dtd = (ctf_dtdef_t *) ctf_dynhash_lookup (fp->ctf_dtbyname, decorated); - free (decorated); - - if (dtd) - return dtd->dtd_type; - - return 0; -} - ctf_dtdef_t * ctf_dynamic_type (const ctf_file_t *fp, ctf_id_t id) { ctf_id_t idx; + if (!(fp->ctf_flags & LCTF_RDWR)) + return NULL; + if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, id)) fp = fp->ctf_parent; idx = LCTF_TYPE_TO_INDEX(fp, id); - if (((unsigned long) idx > fp->ctf_typemax) && - ((unsigned long) idx < fp->ctf_dtnextid)) + if ((unsigned long) idx <= fp->ctf_typemax) return ctf_dtd_lookup (fp, id); return NULL; } @@ -684,7 +729,7 @@ ctf_snapshot_id_t ctf_snapshot (ctf_file_t *fp) { ctf_snapshot_id_t snapid; - snapid.dtd_id = fp->ctf_dtnextid - 1; + snapid.dtd_id = fp->ctf_typemax; snapid.snapshot_id = fp->ctf_snapshots++; return snapid; } @@ -699,19 +744,30 @@ ctf_rollback (ctf_file_t *fp, ctf_snapshot_id_t id) if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno (fp, ECTF_RDONLY)); - if (fp->ctf_dtoldid > id.dtd_id) - return (ctf_set_errno (fp, ECTF_OVERROLLBACK)); - if (fp->ctf_snapshot_lu >= id.snapshot_id) return (ctf_set_errno (fp, ECTF_OVERROLLBACK)); for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { + int kind; + const char *name; + ntd = ctf_list_next (dtd); if (LCTF_TYPE_TO_INDEX (fp, dtd->dtd_type) <= id.dtd_id) continue; + kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); + + if (dtd->dtd_data.ctt_name + && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL) + { + ctf_dynhash_remove (ctf_name_table (fp, kind)->ctn_writable, + name); + ctf_str_remove_ref (fp, name, &dtd->dtd_data.ctt_name); + } + + ctf_dynhash_remove (fp->ctf_dthash, (void *) dtd->dtd_type); ctf_dtd_delete (fp, dtd); } @@ -725,7 +781,7 @@ ctf_rollback (ctf_file_t *fp, ctf_snapshot_id_t id) ctf_dvd_delete (fp, dvd); } - fp->ctf_dtnextid = id.dtd_id + 1; + fp->ctf_typemax = id.dtd_id; fp->ctf_snapshots = id.snapshot_id; if (fp->ctf_snapshots == fp->ctf_snapshot_lu) @@ -735,12 +791,11 @@ ctf_rollback (ctf_file_t *fp, ctf_snapshot_id_t id) } static ctf_id_t -ctf_add_generic (ctf_file_t *fp, uint32_t flag, const char *name, +ctf_add_generic (ctf_file_t *fp, uint32_t flag, const char *name, int kind, ctf_dtdef_t **rp) { ctf_dtdef_t *dtd; ctf_id_t type; - char *s = NULL; if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT) return (ctf_set_errno (fp, EINVAL)); @@ -748,29 +803,33 @@ ctf_add_generic (ctf_file_t *fp, uint32_t flag, const char *name, if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno (fp, ECTF_RDONLY)); - if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_dtnextid, 1) > CTF_MAX_TYPE) + if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE) return (ctf_set_errno (fp, ECTF_FULL)); - if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_dtnextid, 1) == CTF_MAX_PTYPE) + if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1)) return (ctf_set_errno (fp, ECTF_FULL)); + /* Make sure ptrtab always grows to be big enough for all types. */ + if (ctf_grow_ptrtab (fp) < 0) + return CTF_ERR; /* errno is set for us. */ + if ((dtd = ctf_alloc (sizeof (ctf_dtdef_t))) == NULL) return (ctf_set_errno (fp, EAGAIN)); - if (name != NULL && (s = ctf_strdup (name)) == NULL) - { - ctf_free (dtd); - return (ctf_set_errno (fp, EAGAIN)); - } - - type = fp->ctf_dtnextid++; + type = ++fp->ctf_typemax; type = LCTF_INDEX_TO_TYPE (fp, type, (fp->ctf_flags & LCTF_CHILD)); memset (dtd, 0, sizeof (ctf_dtdef_t)); - dtd->dtd_name = s; + dtd->dtd_data.ctt_name = ctf_str_add_ref (fp, name, &dtd->dtd_data.ctt_name); dtd->dtd_type = type; - if (ctf_dtd_insert (fp, dtd) < 0) + if (dtd->dtd_data.ctt_name == 0 && name != NULL && name[0] != '\0') + { + ctf_free (dtd); + return (ctf_set_errno (fp, EAGAIN)); + } + + if (ctf_dtd_insert (fp, dtd, kind) < 0) { ctf_free (dtd); return CTF_ERR; /* errno is set for us. */ @@ -808,7 +867,7 @@ ctf_add_encoded (ctf_file_t *fp, uint32_t flag, if (ep == NULL) return (ctf_set_errno (fp, EINVAL)); - if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR) + if ((type = ctf_add_generic (fp, flag, name, kind, &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, 0); @@ -825,6 +884,7 @@ ctf_add_reftype (ctf_file_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind) ctf_dtdef_t *dtd; ctf_id_t type; ctf_file_t *tmp = fp; + int child = fp->ctf_flags & LCTF_CHILD; if (ref == CTF_ERR || ref > CTF_MAX_TYPE) return (ctf_set_errno (fp, EINVAL)); @@ -832,12 +892,38 @@ ctf_add_reftype (ctf_file_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind) if (ctf_lookup_by_id (&tmp, ref) == NULL) return CTF_ERR; /* errno is set for us. */ - if ((type = ctf_add_generic (fp, flag, NULL, &dtd)) == CTF_ERR) + if ((type = ctf_add_generic (fp, flag, NULL, kind, &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, 0); dtd->dtd_data.ctt_type = (uint32_t) ref; + if (kind != CTF_K_POINTER) + return type; + + /* If we are adding a pointer, update the ptrtab, both the directly pointed-to + type and (if an anonymous typedef node is being pointed at) the type that + points at too. Note that ctf_typemax is at this point one higher than we + want to check against, because it's just been incremented for the addition + of this type. */ + + uint32_t type_idx = LCTF_TYPE_TO_INDEX (fp, type); + uint32_t ref_idx = LCTF_TYPE_TO_INDEX (fp, ref); + + if (LCTF_TYPE_ISCHILD (fp, ref) == child + && ref_idx < fp->ctf_typemax) + { + fp->ctf_ptrtab[ref_idx] = type_idx; + + ctf_id_t refref_idx = LCTF_TYPE_TO_INDEX (fp, dtd->dtd_data.ctt_type); + + if (tmp == fp + && (LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) == CTF_K_TYPEDEF) + && strcmp (ctf_strptr (fp, dtd->dtd_data.ctt_name), "") == 0 + && refref_idx < fp->ctf_typemax) + fp->ctf_ptrtab[refref_idx] = type_idx; + } + return type; } @@ -868,7 +954,7 @@ ctf_add_slice (ctf_file_t *fp, uint32_t flag, ctf_id_t ref, (kind != CTF_K_ENUM)) return (ctf_set_errno (fp, ECTF_NOTINTFP)); - if ((type = ctf_add_generic (fp, flag, NULL, &dtd)) == CTF_ERR) + if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE, &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0); @@ -918,7 +1004,7 @@ ctf_add_array (ctf_file_t *fp, uint32_t flag, const ctf_arinfo_t *arp) if (ctf_lookup_by_id (&tmp, arp->ctr_index) == NULL) return CTF_ERR; /* errno is set for us. */ - if ((type = ctf_add_generic (fp, flag, NULL, &dtd)) == CTF_ERR) + if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY, &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0); @@ -981,7 +1067,8 @@ ctf_add_function (ctf_file_t *fp, uint32_t flag, if (vlen != 0 && (vdat = ctf_alloc (sizeof (ctf_id_t) * vlen)) == NULL) return (ctf_set_errno (fp, EAGAIN)); - if ((type = ctf_add_generic (fp, flag, NULL, &dtd)) == CTF_ERR) + if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_FUNCTION, + &dtd)) == CTF_ERR) { ctf_free (vdat); return CTF_ERR; /* errno is set for us. */ @@ -1002,22 +1089,18 @@ ctf_id_t ctf_add_struct_sized (ctf_file_t *fp, uint32_t flag, const char *name, size_t size) { - ctf_hash_t *hp = fp->ctf_structs; ctf_dtdef_t *dtd; ctf_id_t type = 0; /* Promote forwards to structs. */ if (name != NULL) - { - type = ctf_hash_lookup_type (hp, fp, name); - if (type == 0) - type = ctf_dtd_lookup_type_by_name (fp, CTF_K_STRUCT, name); - } + type = ctf_lookup_by_rawname (fp, CTF_K_STRUCT, name); if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD) dtd = ctf_dtd_lookup (fp, type); - else if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR) + else if ((type = ctf_add_generic (fp, flag, name, CTF_K_STRUCT, + &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0); @@ -1044,21 +1127,17 @@ ctf_id_t ctf_add_union_sized (ctf_file_t *fp, uint32_t flag, const char *name, size_t size) { - ctf_hash_t *hp = fp->ctf_unions; ctf_dtdef_t *dtd; ctf_id_t type = 0; /* Promote forwards to unions. */ if (name != NULL) - { - type = ctf_hash_lookup_type (hp, fp, name); - if (type == 0) - type = ctf_dtd_lookup_type_by_name (fp, CTF_K_UNION, name); - } + type = ctf_lookup_by_rawname (fp, CTF_K_UNION, name); if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD) dtd = ctf_dtd_lookup (fp, type); - else if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR) + else if ((type = ctf_add_generic (fp, flag, name, CTF_K_UNION, + &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0); @@ -1084,21 +1163,17 @@ ctf_add_union (ctf_file_t *fp, uint32_t flag, const char *name) ctf_id_t ctf_add_enum (ctf_file_t *fp, uint32_t flag, const char *name) { - ctf_hash_t *hp = fp->ctf_enums; ctf_dtdef_t *dtd; ctf_id_t type = 0; /* Promote forwards to enums. */ if (name != NULL) - { - type = ctf_hash_lookup_type (hp, fp, name); - if (type == 0) - type = ctf_dtd_lookup_type_by_name (fp, CTF_K_ENUM, name); - } + type = ctf_lookup_by_rawname (fp, CTF_K_ENUM, name); if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD) dtd = ctf_dtd_lookup (fp, type); - else if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR) + else if ((type = ctf_add_generic (fp, flag, name, CTF_K_ENUM, + &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0); @@ -1111,7 +1186,6 @@ ctf_id_t ctf_add_enum_encoded (ctf_file_t *fp, uint32_t flag, const char *name, const ctf_encoding_t *ep) { - ctf_hash_t *hp = fp->ctf_enums; ctf_id_t type = 0; /* First, create the enum if need be, using most of the same machinery as @@ -1120,11 +1194,7 @@ ctf_add_enum_encoded (ctf_file_t *fp, uint32_t flag, const char *name, slice, which would be a useless thing to do anyway.) */ if (name != NULL) - { - type = ctf_hash_lookup_type (hp, fp, name); - if (type == 0) - type = ctf_dtd_lookup_type_by_name (fp, CTF_K_ENUM, name); - } + type = ctf_lookup_by_rawname (fp, CTF_K_ENUM, name); if (type != 0) { @@ -1144,36 +1214,19 @@ ctf_id_t ctf_add_forward (ctf_file_t *fp, uint32_t flag, const char *name, uint32_t kind) { - ctf_hash_t *hp; ctf_dtdef_t *dtd; ctf_id_t type = 0; - switch (kind) - { - case CTF_K_STRUCT: - hp = fp->ctf_structs; - break; - case CTF_K_UNION: - hp = fp->ctf_unions; - break; - case CTF_K_ENUM: - hp = fp->ctf_enums; - break; - default: - return (ctf_set_errno (fp, ECTF_NOTSUE)); - } + if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM) + return (ctf_set_errno (fp, ECTF_NOTSUE)); /* If the type is already defined or exists as a forward tag, just return the ctf_id_t of the existing definition. */ if (name != NULL) - { - if (((type = ctf_hash_lookup_type (hp, fp, name)) != 0) - || (type = ctf_dtd_lookup_type_by_name (fp, kind, name)) != 0) - return type; - } + type = ctf_lookup_by_rawname (fp, kind, name); - if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR) + if ((type = ctf_add_generic (fp, flag, name, CTF_K_FORWARD,&dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0); @@ -1196,7 +1249,8 @@ ctf_add_typedef (ctf_file_t *fp, uint32_t flag, const char *name, if (ctf_lookup_by_id (&tmp, ref) == NULL) return CTF_ERR; /* errno is set for us. */ - if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR) + if ((type = ctf_add_generic (fp, flag, name, CTF_K_TYPEDEF, + &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_TYPEDEF, flag, 0); @@ -1567,7 +1621,6 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) ctf_dtdef_t *dtd; ctf_funcinfo_t ctc; - ctf_hash_t *hp; ctf_id_t orig_src_type = src_type; if (!(dst_fp->ctf_flags & LCTF_RDWR)) @@ -1589,28 +1642,12 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) if (kind == CTF_K_FORWARD) forward_kind = src_tp->ctt_type; - switch (forward_kind) - { - case CTF_K_STRUCT: - hp = dst_fp->ctf_structs; - break; - case CTF_K_UNION: - hp = dst_fp->ctf_unions; - break; - case CTF_K_ENUM: - hp = dst_fp->ctf_enums; - break; - default: - hp = dst_fp->ctf_names; - break; - } - /* If the source type has a name and is a root type (visible at the top-level scope), lookup the name in the destination container and verify that it is of the same kind before we do anything else. */ if ((flag & CTF_ADD_ROOT) && name[0] != '\0' - && (tmp = ctf_hash_lookup_type (hp, dst_fp, name)) != 0) + && (tmp = ctf_lookup_by_rawname (dst_fp, forward_kind, name)) != 0) { dst_type = tmp; dst_kind = ctf_type_kind_unsliced (dst_fp, dst_type); @@ -1708,8 +1745,12 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) && LCTF_TYPE_TO_INDEX (src_fp, dtd->dtd_type) > dst_fp->ctf_dtoldid; dtd = ctf_list_prev (dtd)) { + const char *ctt_name; + if (LCTF_INFO_KIND (src_fp, dtd->dtd_data.ctt_info) == kind - && dtd->dtd_name != NULL && strcmp (dtd->dtd_name, name) == 0) + && dtd->dtd_data.ctt_name + && ((ctt_name = ctf_strraw (src_fp, dtd->dtd_data.ctt_name)) != NULL) + && strcmp (ctt_name, name) == 0) { int sroot; /* Is the src root-visible? */ int droot; /* Is the dst root-visible? */ @@ -1888,7 +1929,7 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) manually so as to avoid repeated lookups in ctf_add_member and to ensure the exact same member offsets as in src_type. */ - dst_type = ctf_add_generic (dst_fp, flag, name, &dtd); + dst_type = ctf_add_generic (dst_fp, flag, name, kind, &dtd); if (dst_type == CTF_ERR) return CTF_ERR; /* errno is set for us. */ @@ -2032,18 +2073,20 @@ ctf_compress_write (ctf_file_t *fp, int fd) ctf_header_t *hp = &h; ssize_t header_len = sizeof (ctf_header_t); ssize_t compress_len; - size_t max_compress_len = compressBound (fp->ctf_size); ssize_t len; int rc; int err = 0; + if (ctf_serialize (fp) < 0) + return -1; /* errno is set for us. */ + memcpy (hp, fp->ctf_header, header_len); hp->cth_flags |= CTF_F_COMPRESS; + compress_len = compressBound (fp->ctf_size); - if ((buf = ctf_alloc (max_compress_len)) == NULL) + if ((buf = ctf_alloc (compress_len)) == NULL) return (ctf_set_errno (fp, ECTF_ZALLOC)); - compress_len = max_compress_len; if ((rc = compress (buf, (uLongf *) &compress_len, fp->ctf_buf, fp->ctf_size)) != Z_OK) { @@ -2090,12 +2133,15 @@ ctf_write_mem (ctf_file_t *fp, size_t *size, size_t threshold) ctf_header_t *hp; ssize_t header_len = sizeof (ctf_header_t); ssize_t compress_len; - size_t max_compress_len = compressBound (fp->ctf_size); int rc; + if (ctf_serialize (fp) < 0) + return NULL; /* errno is set for us. */ + + compress_len = compressBound (fp->ctf_size); if (fp->ctf_size < threshold) - max_compress_len = fp->ctf_size; - if ((buf = malloc (max_compress_len + compress_len = fp->ctf_size; + if ((buf = malloc (compress_len + sizeof (struct ctf_header))) == NULL) { ctf_set_errno (fp, ENOMEM); @@ -2107,8 +2153,6 @@ ctf_write_mem (ctf_file_t *fp, size_t *size, size_t threshold) bp = buf + sizeof (struct ctf_header); *size = sizeof (struct ctf_header); - compress_len = max_compress_len; - if (fp->ctf_size < threshold) { hp->cth_flags &= ~CTF_F_COMPRESS; @@ -2139,6 +2183,9 @@ ctf_write (ctf_file_t *fp, int fd) ssize_t resid; ssize_t len; + if (ctf_serialize (fp) < 0) + return -1; /* errno is set for us. */ + resid = sizeof (ctf_header_t); buf = (unsigned char *) fp->ctf_header; while (resid != 0) diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 211099e..d284717 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -89,11 +89,17 @@ typedef struct ctf_dmodel size_t ctd_long; /* Size of long in bytes. */ } ctf_dmodel_t; +typedef struct ctf_names +{ + ctf_hash_t *ctn_readonly; /* Hash table when readonly. */ + ctf_dynhash_t *ctn_writable; /* Hash table when writable. */ +} ctf_names_t; + typedef struct ctf_lookup { const char *ctl_prefix; /* String prefix for this lookup. */ size_t ctl_len; /* Length of prefix string in bytes. */ - ctf_hash_t *ctl_hash; /* Pointer to hash table for lookup. */ + ctf_names_t *ctl_hash; /* Pointer to hash table for lookup. */ } ctf_lookup_t; typedef struct ctf_fileops @@ -152,9 +158,8 @@ typedef struct ctf_dmdef typedef struct ctf_dtdef { ctf_list_t dtd_list; /* List forward/back pointers. */ - char *dtd_name; /* Name associated with definition (if any). */ ctf_id_t dtd_type; /* Type identifier for this definition. */ - ctf_type_t dtd_data; /* Type node: name left unpopulated. */ + ctf_type_t dtd_data; /* Type node, including name. */ union { ctf_list_t dtu_members; /* struct, union, or enum */ @@ -193,7 +198,8 @@ typedef struct ctf_str_atom { const char *csa_str; /* Backpointer to string (hash key). */ ctf_list_t csa_refs; /* This string's refs. */ - uint32_t csa_offset; /* External strtab offset, if any. */ + uint32_t csa_offset; /* Strtab offset, if any. */ + uint32_t csa_external_offset; /* External strtab offset, if any. */ unsigned long csa_snapshot_id; /* Snapshot ID at time of creation. */ } ctf_str_atom_t; @@ -235,17 +241,20 @@ struct ctf_file ctf_sect_t ctf_data; /* CTF data from object file. */ ctf_sect_t ctf_symtab; /* Symbol table from object file. */ ctf_sect_t ctf_strtab; /* String table from object file. */ + ctf_dynhash_t *ctf_prov_strtab; /* Maps provisional-strtab offsets + to names. */ ctf_dynhash_t *ctf_syn_ext_strtab; /* Maps ext-strtab offsets to names. */ void *ctf_data_mmapped; /* CTF data we mmapped, to free later. */ size_t ctf_data_mmapped_len; /* Length of CTF data we mmapped. */ - ctf_hash_t *ctf_structs; /* Hash table of struct types. */ - ctf_hash_t *ctf_unions; /* Hash table of union types. */ - ctf_hash_t *ctf_enums; /* Hash table of enum types. */ - ctf_hash_t *ctf_names; /* Hash table of remaining type names. */ - ctf_lookup_t ctf_lookups[5]; /* Pointers to hashes for name lookup. */ + ctf_names_t ctf_structs; /* Hash table of struct types. */ + ctf_names_t ctf_unions; /* Hash table of union types. */ + ctf_names_t ctf_enums; /* Hash table of enum types. */ + ctf_names_t ctf_names; /* Hash table of remaining type names. */ + ctf_lookup_t ctf_lookups[5]; /* Pointers to nametabs for name lookup. */ ctf_strs_t ctf_str[2]; /* Array of string table base and bounds. */ ctf_dynhash_t *ctf_str_atoms; /* Hash table of ctf_str_atoms_t. */ uint64_t ctf_str_num_refs; /* Number of refs to cts_str_atoms. */ + uint32_t ctf_str_prov_offset; /* Latest provisional offset assigned so far. */ unsigned char *ctf_base; /* CTF file pointer. */ unsigned char *ctf_dynbase; /* Freeable CTF file pointer. */ unsigned char *ctf_buf; /* Uncompressed CTF data buffer. */ @@ -254,6 +263,7 @@ struct ctf_file unsigned long ctf_nsyms; /* Number of entries in symtab xlate table. */ uint32_t *ctf_txlate; /* Translation table for type IDs. */ uint32_t *ctf_ptrtab; /* Translation table for pointer-to lookups. */ + size_t ctf_ptrtab_len; /* Num types storable in ptrtab currently. */ struct ctf_varent *ctf_vars; /* Sorted variable->type mapping. */ unsigned long ctf_nvars; /* Number of variables in ctf_vars. */ unsigned long ctf_typemax; /* Maximum valid type ID number. */ @@ -270,11 +280,9 @@ struct ctf_file int ctf_errno; /* Error code for most recent error. */ int ctf_version; /* CTF data version. */ ctf_dynhash_t *ctf_dthash; /* Hash of dynamic type definitions. */ - ctf_dynhash_t *ctf_dtbyname; /* DTDs, indexed by name. */ ctf_list_t ctf_dtdefs; /* List of dynamic type definitions. */ ctf_dynhash_t *ctf_dvhash; /* Hash of dynamic variable mappings. */ ctf_list_t ctf_dvdefs; /* List of dynamic variable definitions. */ - unsigned long ctf_dtnextid; /* Next dynamic type id to assign. */ unsigned long ctf_dtoldid; /* Oldest id that has been committed. */ unsigned long ctf_snapshots; /* ctf_snapshot() plus ctf_update() count. */ unsigned long ctf_snapshot_lu; /* ctf_snapshot() call count at last update. */ @@ -320,7 +328,10 @@ struct ctf_archive_internal (id)) #define LCTF_INDEX_TO_TYPEPTR(fp, i) \ - ((ctf_type_t *)((uintptr_t)(fp)->ctf_buf + (fp)->ctf_txlate[(i)])) + ((fp->ctf_flags & LCTF_RDWR) ? \ + &(ctf_dtd_lookup (fp, LCTF_INDEX_TO_TYPE \ + (fp, i, fp->ctf_flags & LCTF_CHILD))->dtd_data) : \ + (ctf_type_t *)((uintptr_t)(fp)->ctf_buf + (fp)->ctf_txlate[(i)])) #define LCTF_INFO_KIND(fp, info) ((fp)->ctf_fileops->ctfo_get_kind(info)) #define LCTF_INFO_ISROOT(fp, info) ((fp)->ctf_fileops->ctfo_get_root(info)) @@ -340,7 +351,11 @@ static inline ssize_t ctf_get_ctt_size (const ctf_file_t *fp, #define LCTF_RDWR 0x0002 /* CTF container is writable */ #define LCTF_DIRTY 0x0004 /* CTF container has been modified */ +extern ctf_names_t *ctf_name_table (ctf_file_t *, int); extern const ctf_type_t *ctf_lookup_by_id (ctf_file_t **, ctf_id_t); +extern ctf_id_t ctf_lookup_by_rawname (ctf_file_t *, int, const char *); +extern ctf_id_t ctf_lookup_by_rawhash (ctf_file_t *, ctf_names_t *, const char *); +extern void ctf_set_ctl_hashes (ctf_file_t *); typedef unsigned int (*ctf_hash_fun) (const void *ptr); extern unsigned int ctf_hash_integer (const void *ptr); @@ -381,8 +396,9 @@ extern void ctf_dynhash_iter_remove (ctf_dynhash_t *, ctf_hash_iter_remove_f, extern void ctf_list_append (ctf_list_t *, void *); extern void ctf_list_prepend (ctf_list_t *, void *); extern void ctf_list_delete (ctf_list_t *, void *); +extern int ctf_list_empty_p (ctf_list_t *lp); -extern int ctf_dtd_insert (ctf_file_t *, ctf_dtdef_t *); +extern int ctf_dtd_insert (ctf_file_t *, ctf_dtdef_t *, int); extern void ctf_dtd_delete (ctf_file_t *, ctf_dtdef_t *); extern ctf_dtdef_t *ctf_dtd_lookup (const ctf_file_t *, ctf_id_t); extern ctf_dtdef_t *ctf_dynamic_type (const ctf_file_t *, ctf_id_t); @@ -410,9 +426,10 @@ extern const char *ctf_strraw_explicit (ctf_file_t *, uint32_t, ctf_strs_t *); extern int ctf_str_create_atoms (ctf_file_t *); extern void ctf_str_free_atoms (ctf_file_t *); -extern const char *ctf_str_add (ctf_file_t *, const char *); -extern const char *ctf_str_add_ref (ctf_file_t *, const char *, uint32_t *ref); -extern const char *ctf_str_add_external (ctf_file_t *, const char *, uint32_t offset); +extern uint32_t ctf_str_add (ctf_file_t *, const char *); +extern uint32_t ctf_str_add_ref (ctf_file_t *, const char *, uint32_t *ref); +extern int ctf_str_add_external (ctf_file_t *, const char *, uint32_t offset); +extern void ctf_str_remove_ref (ctf_file_t *, const char *, uint32_t *ref); extern void ctf_str_rollback (ctf_file_t *, ctf_snapshot_id_t); extern void ctf_str_purge_refs (ctf_file_t *); extern ctf_strs_writable_t ctf_str_write_strtab (ctf_file_t *); @@ -426,10 +443,11 @@ extern unsigned long ctf_set_errno (ctf_file_t *, int); extern ctf_file_t *ctf_simple_open_internal (const char *, size_t, const char *, size_t, size_t, const char *, size_t, - ctf_dynhash_t *, int *); + ctf_dynhash_t *, int, int *); extern ctf_file_t *ctf_bufopen_internal (const ctf_sect_t *, const ctf_sect_t *, const ctf_sect_t *, ctf_dynhash_t *, - int *); + int, int *); +extern int ctf_serialize (ctf_file_t *); _libctf_malloc_ extern void *ctf_mmap (size_t length, size_t offset, int fd); diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c index e2a0348..2f05522 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -639,7 +639,7 @@ ctf_link_intern_extern_string (void *key _libctf_unused_, void *value, ctf_link_out_string_cb_arg_t *arg = (ctf_link_out_string_cb_arg_t *) arg_; fp->ctf_flags |= LCTF_DIRTY; - if (ctf_str_add_external (fp, arg->str, arg->offset) == NULL) + if (!ctf_str_add_external (fp, arg->str, arg->offset)) arg->err = ENOMEM; } @@ -662,7 +662,7 @@ ctf_link_add_strtab (ctf_file_t *fp, ctf_link_strtab_string_f *add_string, ctf_link_out_string_cb_arg_t iter_arg = { str, offset, 0 }; fp->ctf_flags |= LCTF_DIRTY; - if (ctf_str_add_external (fp, str, offset) == NULL) + if (!ctf_str_add_external (fp, str, offset)) err = ENOMEM; ctf_dynhash_iter (fp->ctf_link_outputs, ctf_link_intern_extern_string, @@ -693,8 +693,7 @@ typedef struct ctf_name_list_accum_cb_arg size_t ndynames; } ctf_name_list_accum_cb_arg_t; -/* Accumulate the names and a count of the names in the link output hash, - and run ctf_update() on them to generate them. */ +/* Accumulate the names and a count of the names in the link output hash. */ static void ctf_accumulate_archive_names (void *key, void *value, void *arg_) { @@ -703,13 +702,6 @@ ctf_accumulate_archive_names (void *key, void *value, void *arg_) char **names; ctf_file_t **files; ctf_name_list_accum_cb_arg_t *arg = (ctf_name_list_accum_cb_arg_t *) arg_; - int err; - - if ((err = ctf_update (fp)) < 0) - { - ctf_set_errno (arg->fp, ctf_errno (fp)); - return; - } if ((names = realloc (arg->names, sizeof (char *) * ++(arg->i))) == NULL) { @@ -788,12 +780,6 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold) memset (&arg, 0, sizeof (ctf_name_list_accum_cb_arg_t)); arg.fp = fp; - if (ctf_update (fp) < 0) - { - errloc = "CTF file construction"; - goto err; - } - if (fp->ctf_link_outputs) { ctf_dynhash_iter (fp->ctf_link_outputs, ctf_accumulate_archive_names, &arg); diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c index 40eaf9c..6f180d6 100644 --- a/libctf/ctf-lookup.c +++ b/libctf/ctf-lookup.c @@ -161,8 +161,8 @@ ctf_lookup_by_name (ctf_file_t *fp, const char *name) } } - if ((type = ctf_hash_lookup_type (lp->ctl_hash, fp, - fp->ctf_tmp_typeslice)) == 0) + if ((type = ctf_lookup_by_rawhash (fp, lp->ctl_hash, + fp->ctf_tmp_typeslice)) == 0) { (void) ctf_set_errno (fp, ECTF_NOTYPE); goto err; @@ -322,13 +322,6 @@ ctf_lookup_by_id (ctf_file_t **fpp, ctf_id_t type) return NULL; } - idx = LCTF_TYPE_TO_INDEX (fp, type); - if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax) - { - *fpp = fp; /* Function returns ending CTF container. */ - return (LCTF_INDEX_TO_TYPEPTR (fp, idx)); - } - /* If this container is writable, check for a dynamic type. */ if (fp->ctf_flags & LCTF_RDWR) @@ -340,7 +333,19 @@ ctf_lookup_by_id (ctf_file_t **fpp, ctf_id_t type) *fpp = fp; return &dtd->dtd_data; } + (void) ctf_set_errno (*fpp, ECTF_BADID); + return NULL; } + + /* Check for a type in the static portion. */ + + idx = LCTF_TYPE_TO_INDEX (fp, type); + if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax) + { + *fpp = fp; /* Function returns ending CTF container. */ + return (LCTF_INDEX_TO_TYPEPTR (fp, idx)); + } + (void) ctf_set_errno (*fpp, ECTF_BADID); return NULL; } diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index 9dcd274..c4fca24 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -655,7 +655,6 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) unsigned long pop[CTF_K_MAX + 1] = { 0 }; const ctf_type_t *tp; - ctf_hash_t *hp; uint32_t id, dst; uint32_t *xp; @@ -666,6 +665,8 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) int nlstructs = 0, nlunions = 0; int err; + assert (!(fp->ctf_flags & LCTF_RDWR)); + if (_libctf_unlikely_ (fp->ctf_version == CTF_VERSION_1)) { int err; @@ -717,32 +718,37 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) /* Now that we've counted up the number of each type, we can allocate the hash tables, type translation table, and pointer table. */ - if ((fp->ctf_structs = ctf_hash_create (pop[CTF_K_STRUCT], ctf_hash_string, - ctf_hash_eq_string)) == NULL) + if ((fp->ctf_structs.ctn_readonly + = ctf_hash_create (pop[CTF_K_STRUCT], ctf_hash_string, + ctf_hash_eq_string)) == NULL) return ENOMEM; - if ((fp->ctf_unions = ctf_hash_create (pop[CTF_K_UNION], ctf_hash_string, - ctf_hash_eq_string)) == NULL) + if ((fp->ctf_unions.ctn_readonly + = ctf_hash_create (pop[CTF_K_UNION], ctf_hash_string, + ctf_hash_eq_string)) == NULL) return ENOMEM; - if ((fp->ctf_enums = ctf_hash_create (pop[CTF_K_ENUM], ctf_hash_string, - ctf_hash_eq_string)) == NULL) + if ((fp->ctf_enums.ctn_readonly + = ctf_hash_create (pop[CTF_K_ENUM], ctf_hash_string, + ctf_hash_eq_string)) == NULL) return ENOMEM; - if ((fp->ctf_names = ctf_hash_create (pop[CTF_K_INTEGER] + - pop[CTF_K_FLOAT] + - pop[CTF_K_FUNCTION] + - pop[CTF_K_TYPEDEF] + - pop[CTF_K_POINTER] + - pop[CTF_K_VOLATILE] + - pop[CTF_K_CONST] + - pop[CTF_K_RESTRICT], - ctf_hash_string, - ctf_hash_eq_string)) == NULL) + if ((fp->ctf_names.ctn_readonly + = ctf_hash_create (pop[CTF_K_INTEGER] + + pop[CTF_K_FLOAT] + + pop[CTF_K_FUNCTION] + + pop[CTF_K_TYPEDEF] + + pop[CTF_K_POINTER] + + pop[CTF_K_VOLATILE] + + pop[CTF_K_CONST] + + pop[CTF_K_RESTRICT], + ctf_hash_string, + ctf_hash_eq_string)) == NULL) return ENOMEM; fp->ctf_txlate = ctf_alloc (sizeof (uint32_t) * (fp->ctf_typemax + 1)); - fp->ctf_ptrtab = ctf_alloc (sizeof (uint32_t) * (fp->ctf_typemax + 1)); + fp->ctf_ptrtab_len = fp->ctf_typemax + 1; + fp->ctf_ptrtab = ctf_alloc (sizeof (uint32_t) * fp->ctf_ptrtab_len); if (fp->ctf_txlate == NULL || fp->ctf_ptrtab == NULL) return ENOMEM; /* Memory allocation failed. */ @@ -779,10 +785,11 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) root-visible version so that we can be sure to find it when checking for conflicting definitions in ctf_add_type(). */ - if (((ctf_hash_lookup_type (fp->ctf_names, fp, name)) == 0) + if (((ctf_hash_lookup_type (fp->ctf_names.ctn_readonly, + fp, name)) == 0) || (flag & CTF_ADD_ROOT)) { - err = ctf_hash_define_type (fp->ctf_names, fp, + err = ctf_hash_define_type (fp->ctf_names.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) @@ -797,7 +804,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_FUNCTION: - err = ctf_hash_insert_type (fp->ctf_names, fp, + err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) @@ -805,7 +812,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_STRUCT: - err = ctf_hash_define_type (fp->ctf_structs, fp, + err = ctf_hash_define_type (fp->ctf_structs.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); @@ -817,7 +824,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_UNION: - err = ctf_hash_define_type (fp->ctf_unions, fp, + err = ctf_hash_define_type (fp->ctf_unions.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); @@ -829,7 +836,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_ENUM: - err = ctf_hash_define_type (fp->ctf_enums, fp, + err = ctf_hash_define_type (fp->ctf_enums.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); @@ -838,7 +845,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_TYPEDEF: - err = ctf_hash_insert_type (fp->ctf_names, fp, + err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) @@ -846,32 +853,20 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_FORWARD: - /* Only insert forward tags into the given hash if the type or tag - name is not already present. */ - switch (tp->ctt_type) - { - case CTF_K_STRUCT: - hp = fp->ctf_structs; - break; - case CTF_K_UNION: - hp = fp->ctf_unions; - break; - case CTF_K_ENUM: - hp = fp->ctf_enums; - break; - default: - hp = fp->ctf_structs; - } - - if (ctf_hash_lookup_type (hp, fp, name) == 0) - { - err = ctf_hash_insert_type (hp, fp, - LCTF_INDEX_TO_TYPE (fp, id, child), - tp->ctt_name); - if (err != 0) - return err; - } - break; + { + ctf_names_t *np = ctf_name_table (fp, tp->ctt_type); + /* Only insert forward tags into the given hash if the type or tag + name is not already present. */ + if (ctf_hash_lookup_type (np->ctn_readonly, fp, name) == 0) + { + err = ctf_hash_insert_type (np->ctn_readonly, fp, + LCTF_INDEX_TO_TYPE (fp, id, child), + tp->ctt_name); + if (err != 0) + return err; + } + break; + } case CTF_K_POINTER: /* If the type referenced by the pointer is in this CTF container, @@ -886,7 +881,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: - err = ctf_hash_insert_type (fp->ctf_names, fp, + err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) @@ -903,12 +898,14 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) } ctf_dprintf ("%lu total types processed\n", fp->ctf_typemax); - ctf_dprintf ("%u enum names hashed\n", ctf_hash_size (fp->ctf_enums)); + ctf_dprintf ("%u enum names hashed\n", + ctf_hash_size (fp->ctf_enums.ctn_readonly)); ctf_dprintf ("%u struct names hashed (%d long)\n", - ctf_hash_size (fp->ctf_structs), nlstructs); + ctf_hash_size (fp->ctf_structs.ctn_readonly), nlstructs); ctf_dprintf ("%u union names hashed (%d long)\n", - ctf_hash_size (fp->ctf_unions), nlunions); - ctf_dprintf ("%u base type names hashed\n", ctf_hash_size (fp->ctf_names)); + ctf_hash_size (fp->ctf_unions.ctn_readonly), nlunions); + ctf_dprintf ("%u base type names hashed\n", + ctf_hash_size (fp->ctf_names.ctn_readonly)); /* Make an additional pass through the pointer table to find pointers that point to anonymous typedef nodes. If we find one, modify the pointer table @@ -921,11 +918,11 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) { tp = LCTF_INDEX_TO_TYPEPTR (fp, id); - if (LCTF_INFO_KIND (fp, tp->ctt_info) == CTF_K_TYPEDEF && - strcmp (ctf_strptr (fp, tp->ctt_name), "") == 0 && - LCTF_TYPE_ISCHILD (fp, tp->ctt_type) == child && - LCTF_TYPE_TO_INDEX (fp, tp->ctt_type) <= fp->ctf_typemax) - fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, tp->ctt_type)] = dst; + if (LCTF_INFO_KIND (fp, tp->ctt_info) == CTF_K_TYPEDEF + && strcmp (ctf_strptr (fp, tp->ctt_name), "") == 0 + && LCTF_TYPE_ISCHILD (fp, tp->ctt_type) == child + && LCTF_TYPE_TO_INDEX (fp, tp->ctt_type) <= fp->ctf_typemax) + fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, tp->ctt_type)] = dst; } } @@ -1197,6 +1194,29 @@ flip_ctf (ctf_header_t *cth, unsigned char *buf) return flip_types (buf + cth->cth_typeoff, cth->cth_stroff - cth->cth_typeoff); } +/* Set up the ctl hashes in a ctf_file_t. Called by both writable and + non-writable dictionary initialization. */ +void ctf_set_ctl_hashes (ctf_file_t *fp) +{ + /* Initialize the ctf_lookup_by_name top-level dictionary. We keep an + array of type name prefixes and the corresponding ctf_hash to use. */ + fp->ctf_lookups[0].ctl_prefix = "struct"; + fp->ctf_lookups[0].ctl_len = strlen (fp->ctf_lookups[0].ctl_prefix); + fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs; + fp->ctf_lookups[1].ctl_prefix = "union"; + fp->ctf_lookups[1].ctl_len = strlen (fp->ctf_lookups[1].ctl_prefix); + fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions; + fp->ctf_lookups[2].ctl_prefix = "enum"; + fp->ctf_lookups[2].ctl_len = strlen (fp->ctf_lookups[2].ctl_prefix); + fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums; + fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR; + fp->ctf_lookups[3].ctl_len = strlen (fp->ctf_lookups[3].ctl_prefix); + fp->ctf_lookups[3].ctl_hash = &fp->ctf_names; + fp->ctf_lookups[4].ctl_prefix = NULL; + fp->ctf_lookups[4].ctl_len = 0; + fp->ctf_lookups[4].ctl_hash = NULL; +} + /* Open a CTF file, mocking up a suitable ctf_sect. */ ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size, @@ -1207,7 +1227,7 @@ ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size, { return ctf_simple_open_internal (ctfsect, ctfsect_size, symsect, symsect_size, symsect_entsize, strsect, strsect_size, NULL, - errp); + 0, errp); } /* Open a CTF file, mocking up a suitable ctf_sect and overriding the external @@ -1217,7 +1237,8 @@ ctf_file_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size, const char *symsect, size_t symsect_size, size_t symsect_entsize, const char *strsect, size_t strsect_size, - ctf_dynhash_t *syn_strtab, int *errp) + ctf_dynhash_t *syn_strtab, int writable, + int *errp) { ctf_sect_t skeleton; @@ -1254,7 +1275,8 @@ ctf_file_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size, strsectp = &str_sect; } - return ctf_bufopen_internal (ctfsectp, symsectp, strsectp, syn_strtab, errp); + return ctf_bufopen_internal (ctfsectp, symsectp, strsectp, syn_strtab, + writable, errp); } /* Decode the specified CTF buffer and optional symbol table, and create a new @@ -1266,7 +1288,7 @@ ctf_file_t * ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, const ctf_sect_t *strsect, int *errp) { - return ctf_bufopen_internal (ctfsect, symsect, strsect, NULL, errp); + return ctf_bufopen_internal (ctfsect, symsect, strsect, NULL, 0, errp); } /* Like ctf_bufopen, but overriding the external strtab with a synthetic one. */ @@ -1274,7 +1296,7 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, ctf_file_t * ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, const ctf_sect_t *strsect, ctf_dynhash_t *syn_strtab, - int *errp) + int writable, int *errp) { const ctf_preamble_t *pp; size_t hdrsz = sizeof (ctf_header_t); @@ -1353,6 +1375,9 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, memset (fp, 0, sizeof (ctf_file_t)); + if (writable) + fp->ctf_flags |= LCTF_RDWR; + if ((fp->ctf_header = ctf_alloc (sizeof (struct ctf_header))) == NULL) { ctf_free (fp); @@ -1514,6 +1539,14 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, ctf_set_base (fp, hp, fp->ctf_base); + /* No need to do anything else for dynamic containers: they do not support + symbol lookups, and the type table is maintained in the dthashes. */ + if (fp->ctf_flags & LCTF_RDWR) + { + fp->ctf_refcnt = 1; + return fp; + } + if ((err = init_types (fp, hp)) != 0) goto bad; @@ -1537,24 +1570,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, goto bad; } - /* Initialize the ctf_lookup_by_name top-level dictionary. We keep an - array of type name prefixes and the corresponding ctf_hash to use. - NOTE: This code must be kept in sync with the code in ctf_update(). */ - fp->ctf_lookups[0].ctl_prefix = "struct"; - fp->ctf_lookups[0].ctl_len = strlen (fp->ctf_lookups[0].ctl_prefix); - fp->ctf_lookups[0].ctl_hash = fp->ctf_structs; - fp->ctf_lookups[1].ctl_prefix = "union"; - fp->ctf_lookups[1].ctl_len = strlen (fp->ctf_lookups[1].ctl_prefix); - fp->ctf_lookups[1].ctl_hash = fp->ctf_unions; - fp->ctf_lookups[2].ctl_prefix = "enum"; - fp->ctf_lookups[2].ctl_len = strlen (fp->ctf_lookups[2].ctl_prefix); - fp->ctf_lookups[2].ctl_hash = fp->ctf_enums; - fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR; - fp->ctf_lookups[3].ctl_len = strlen (fp->ctf_lookups[3].ctl_prefix); - fp->ctf_lookups[3].ctl_hash = fp->ctf_names; - fp->ctf_lookups[4].ctl_prefix = NULL; - fp->ctf_lookups[4].ctl_len = 0; - fp->ctf_lookups[4].ctl_hash = NULL; + ctf_set_ctl_hashes (fp); if (symsect != NULL) { @@ -1607,7 +1623,20 @@ ctf_file_close (ctf_file_t *fp) ctf_dtd_delete (fp, dtd); } ctf_dynhash_destroy (fp->ctf_dthash); - ctf_dynhash_destroy (fp->ctf_dtbyname); + if (fp->ctf_flags & LCTF_RDWR) + { + ctf_dynhash_destroy (fp->ctf_structs.ctn_writable); + ctf_dynhash_destroy (fp->ctf_unions.ctn_writable); + ctf_dynhash_destroy (fp->ctf_enums.ctn_writable); + ctf_dynhash_destroy (fp->ctf_names.ctn_writable); + } + else + { + ctf_hash_destroy (fp->ctf_structs.ctn_readonly); + ctf_hash_destroy (fp->ctf_unions.ctn_readonly); + ctf_hash_destroy (fp->ctf_enums.ctn_readonly); + ctf_hash_destroy (fp->ctf_names.ctn_readonly); + } for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd) { @@ -1641,11 +1670,6 @@ ctf_file_close (ctf_file_t *fp) ctf_free (fp->ctf_txlate); ctf_free (fp->ctf_ptrtab); - ctf_hash_destroy (fp->ctf_structs); - ctf_hash_destroy (fp->ctf_unions); - ctf_hash_destroy (fp->ctf_enums); - ctf_hash_destroy (fp->ctf_names); - ctf_free (fp->ctf_header); ctf_free (fp); } @@ -1670,7 +1694,7 @@ ctf_get_arc (const ctf_file_t *fp) structure, not a pointer to it, since that is likely to become a pointer to freed data before the return value is used under the expected use case of ctf_getsect()/ ctf_file_close()/free(). */ -extern ctf_sect_t +ctf_sect_t ctf_getdatasect (const ctf_file_t *fp) { return fp->ctf_data; diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c index 44cd447..243e1ac 100644 --- a/libctf/ctf-string.c +++ b/libctf/ctf-string.c @@ -38,6 +38,16 @@ ctf_strraw_explicit (ctf_file_t *fp, uint32_t name, ctf_strs_t *strtab) return ctf_dynhash_lookup (fp->ctf_syn_ext_strtab, (void *) (uintptr_t) name); + /* If the name is in the internal strtab, and the offset is beyond the end of + the ctsp->cts_len but below the ctf_str_prov_offset, this is a provisional + string added by ctf_str_add*() but not yet built into a real strtab: get + the value out of the ctf_prov_strtab. */ + + if (CTF_NAME_STID (name) == CTF_STRTAB_0 + && name >= ctsp->cts_len && name < fp->ctf_str_prov_offset) + return ctf_dynhash_lookup (fp->ctf_prov_strtab, + (void *) (uintptr_t) name); + if (ctsp->cts_strs != NULL && CTF_NAME_OFFSET (name) < ctsp->cts_len) return (ctsp->cts_strs + CTF_NAME_OFFSET (name)); @@ -96,24 +106,45 @@ ctf_str_create_atoms (ctf_file_t *fp) if (fp->ctf_str_atoms == NULL) return -ENOMEM; + if (!fp->ctf_prov_strtab) + fp->ctf_prov_strtab = ctf_dynhash_create (ctf_hash_integer, + ctf_hash_eq_integer, + NULL, NULL); + if (!fp->ctf_prov_strtab) + goto oom_prov_strtab; + + errno = 0; ctf_str_add (fp, ""); + if (errno == ENOMEM) + goto oom_str_add; + return 0; + + oom_str_add: + ctf_dynhash_destroy (fp->ctf_prov_strtab); + fp->ctf_prov_strtab = NULL; + oom_prov_strtab: + ctf_dynhash_destroy (fp->ctf_str_atoms); + fp->ctf_str_atoms = NULL; + return -ENOMEM; } /* Destroy the atoms table. */ void ctf_str_free_atoms (ctf_file_t *fp) { + ctf_dynhash_destroy (fp->ctf_prov_strtab); ctf_dynhash_destroy (fp->ctf_str_atoms); } /* Add a string to the atoms table, copying the passed-in string. Return the atom added. Return NULL only when out of memory (and do not touch the passed-in string in that case). Possibly augment the ref list with the - passed-in ref. */ + passed-in ref. Possibly add a provisional entry for this string to the + provisional strtab. */ static ctf_str_atom_t * ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, - int add_ref, uint32_t *ref) + int add_ref, int make_provisional, uint32_t *ref) { char *newstr = NULL; ctf_str_atom_t *atom = NULL; @@ -150,6 +181,18 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, atom->csa_str = newstr; atom->csa_snapshot_id = fp->ctf_snapshots; + + if (make_provisional) + { + atom->csa_offset = fp->ctf_str_prov_offset; + + if (ctf_dynhash_insert (fp->ctf_prov_strtab, (void *) (uintptr_t) + atom->csa_offset, (void *) atom->csa_str) < 0) + goto oom; + + fp->ctf_str_prov_offset += strlen (atom->csa_str) + 1; + } + if (add_ref) { ctf_list_append (&atom->csa_refs, aref); @@ -158,59 +201,87 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, return atom; oom: + if (newstr) + ctf_dynhash_remove (fp->ctf_str_atoms, newstr); ctf_free (atom); ctf_free (aref); ctf_free (newstr); return NULL; } -/* Add a string to the atoms table and return it, without augmenting the ref - list for this string. */ -const char * +/* Add a string to the atoms table, without augmenting the ref list for this + string: return a 'provisional offset' which can be used to return this string + until ctf_str_write_strtab is called, or 0 on failure. (Everywhere the + provisional offset is assigned to should be added as a ref using + ctf_str_add_ref() as well.) */ +uint32_t ctf_str_add (ctf_file_t *fp, const char *str) { ctf_str_atom_t *atom; if (!str) - return NULL; + return 0; - atom = ctf_str_add_ref_internal (fp, str, FALSE, 0); + atom = ctf_str_add_ref_internal (fp, str, FALSE, TRUE, 0); if (!atom) - return NULL; + return 0; - return atom->csa_str; + return atom->csa_offset; } /* Like ctf_str_add(), but additionally augment the atom's refs list with the passed-in ref, whether or not the string is already present. There is no attempt to deduplicate the refs list (but duplicates are harmless). */ -const char * +uint32_t ctf_str_add_ref (ctf_file_t *fp, const char *str, uint32_t *ref) { ctf_str_atom_t *atom; if (!str) - return NULL; + return 0; - atom = ctf_str_add_ref_internal (fp, str, TRUE, ref); + atom = ctf_str_add_ref_internal (fp, str, TRUE, TRUE, ref); if (!atom) - return NULL; + return 0; - return atom->csa_str; + return atom->csa_offset; } -/* Add an external strtab reference at OFFSET. */ -const char * +/* Add an external strtab reference at OFFSET. Returns zero if the addition + failed, nonzero otherwise. */ +int ctf_str_add_external (ctf_file_t *fp, const char *str, uint32_t offset) { ctf_str_atom_t *atom; if (!str) - return NULL; + return 0; + + atom = ctf_str_add_ref_internal (fp, str, FALSE, FALSE, 0); + if (!atom) + return 0; + + atom->csa_external_offset = CTF_SET_STID (offset, CTF_STRTAB_1); + return 1; +} - atom = ctf_str_add_ref_internal (fp, str, FALSE, 0); +/* Remove a single ref. */ +void +ctf_str_remove_ref (ctf_file_t *fp, const char *str, uint32_t *ref) +{ + ctf_str_atom_ref_t *aref, *anext; + ctf_str_atom_t *atom = NULL; + + atom = ctf_dynhash_lookup (fp->ctf_str_atoms, str); if (!atom) - return NULL; + return; - atom->csa_offset = CTF_SET_STID (offset, CTF_STRTAB_1); - return atom->csa_str; + for (aref = ctf_list_next (&atom->csa_refs); aref != NULL; aref = anext) + { + anext = ctf_list_next (aref); + if (aref->caf_ref == ref) + { + ctf_list_delete (&atom->csa_refs, aref); + ctf_free (aref); + } + } } /* A ctf_dynhash_iter_remove() callback that removes atoms later than a given @@ -285,12 +356,25 @@ ctf_str_count_strtab (void *key _libctf_unused_, void *value, ctf_str_atom_t *atom = (ctf_str_atom_t *) value; ctf_strtab_write_state_t *s = (ctf_strtab_write_state_t *) arg; - /* We only factor in the length of items that have no offset: - other items are in the external strtab. They still contribute to the - total count, though, because we still have to sort them. */ - if (!atom->csa_offset) - s->strtab->cts_len += strlen (atom->csa_str) + 1; - s->strtab_count++; + /* We only factor in the length of items that have no offset and have refs: + other items are in the external strtab, or will simply not be written out + at all. They still contribute to the total count, though, because we still + have to sort them. We add in the null string's length explicitly, outside + this function, since it is explicitly written out even if it has no refs at + all. */ + + if (s->nullstr == atom) + { + s->strtab_count++; + return; + } + + if (!ctf_list_empty_p (&atom->csa_refs)) + { + if (!atom->csa_external_offset) + s->strtab->cts_len += strlen (atom->csa_str) + 1; + s->strtab_count++; + } } /* Populate the sorttab with pointers to the strtab atoms. */ @@ -305,7 +389,9 @@ ctf_str_populate_sorttab (void *key _libctf_unused_, void *value, if (s->nullstr == atom) return; - s->sorttab[s->i++] = atom; + /* Skip atoms with no refs. */ + if (!ctf_list_empty_p (&atom->csa_refs)) + s->sorttab[s->i++] = atom; } /* Sort the strtab. */ @@ -346,7 +432,9 @@ ctf_str_write_strtab (ctf_file_t *fp) return strtab; } + s.nullstr = nullstr; ctf_dynhash_iter (fp->ctf_str_atoms, ctf_str_count_strtab, &s); + strtab.cts_len++; /* For the null string. */ ctf_dprintf ("%lu bytes of strings in strtab.\n", (unsigned long) strtab.cts_len); @@ -359,7 +447,6 @@ ctf_str_write_strtab (ctf_file_t *fp) sorttab[0] = nullstr; s.i = 1; s.sorttab = sorttab; - s.nullstr = nullstr; ctf_dynhash_iter (fp->ctf_str_atoms, ctf_str_populate_sorttab, &s); qsort (&sorttab[1], s.strtab_count - 1, sizeof (ctf_str_atom_t *), @@ -378,7 +465,7 @@ ctf_str_write_strtab (ctf_file_t *fp) /* Update all refs: also update the strtab appropriately. */ for (i = 0; i < s.strtab_count; i++) { - if (sorttab[i]->csa_offset) + if (sorttab[i]->csa_external_offset) { /* External strtab entry: populate the synthetic external strtab. @@ -388,17 +475,21 @@ ctf_str_write_strtab (ctf_file_t *fp) until ctf_file_close. */ any_external = 1; - ctf_str_update_refs (sorttab[i], sorttab[i]->csa_offset); + ctf_str_update_refs (sorttab[i], sorttab[i]->csa_external_offset); if (ctf_dynhash_insert (fp->ctf_syn_ext_strtab, - (void *) (uintptr_t) sorttab[i]->csa_offset, + (void *) (uintptr_t) + sorttab[i]->csa_external_offset, (void *) sorttab[i]->csa_str) < 0) goto oom_strtab; + sorttab[i]->csa_offset = sorttab[i]->csa_external_offset; } else { - /* Internal strtab entry: actually add to the string table. */ + /* Internal strtab entry with refs: actually add to the string + table. */ ctf_str_update_refs (sorttab[i], cur_stroff); + sorttab[i]->csa_offset = cur_stroff; strcpy (&strtab.cts_strs[cur_stroff], sorttab[i]->csa_str); cur_stroff += strlen (sorttab[i]->csa_str) + 1; } @@ -411,6 +502,12 @@ ctf_str_write_strtab (ctf_file_t *fp) fp->ctf_syn_ext_strtab = NULL; } + /* All the provisional strtab entries are now real strtab entries, and + ctf_strptr() will find them there. The provisional offset now starts right + beyond the new end of the strtab. */ + + ctf_dynhash_empty (fp->ctf_prov_strtab); + fp->ctf_str_prov_offset = strtab.cts_len + 1; return strtab; oom_strtab: diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c index 9fe4d5a..6e67762 100644 --- a/libctf/ctf-types.c +++ b/libctf/ctf-types.c @@ -42,6 +42,7 @@ ctf_member_iter (ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) { ctf_file_t *ofp = fp; const ctf_type_t *tp; + ctf_dtdef_t *dtd; ssize_t size, increment; uint32_t kind, n; int rc; @@ -58,29 +59,43 @@ ctf_member_iter (ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno (ofp, ECTF_NOTSOU)); - if (size < CTF_LSTRUCT_THRESH) + if ((dtd = ctf_dynamic_type (fp, type)) == NULL) { - const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + - increment); - - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) + if (size < CTF_LSTRUCT_THRESH) { - const char *name = ctf_strptr (fp, mp->ctm_name); - if ((rc = func (name, mp->ctm_type, mp->ctm_offset, arg)) != 0) + const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + + increment); + + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) + { + const char *name = ctf_strptr (fp, mp->ctm_name); + if ((rc = func (name, mp->ctm_type, mp->ctm_offset, arg)) != 0) return rc; + } } + else + { + const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + + increment); + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) + { + const char *name = ctf_strptr (fp, lmp->ctlm_name); + if ((rc = func (name, lmp->ctlm_type, + (unsigned long) CTF_LMEM_OFFSET (lmp), arg)) != 0) + return rc; + } + } } else { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + - increment); + ctf_dmdef_t *dmd; - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) + for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + dmd != NULL; dmd = ctf_list_next (dmd)) { - const char *name = ctf_strptr (fp, lmp->ctlm_name); - if ((rc = func (name, lmp->ctlm_type, - (unsigned long) CTF_LMEM_OFFSET (lmp), arg)) != 0) + if ((rc = func (dmd->dmd_name, dmd->dmd_type, + dmd->dmd_offset, arg)) != 0) return rc; } } @@ -97,6 +112,7 @@ ctf_enum_iter (ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg) ctf_file_t *ofp = fp; const ctf_type_t *tp; const ctf_enum_t *ep; + ctf_dtdef_t *dtd; ssize_t increment; uint32_t n; int rc; @@ -112,13 +128,27 @@ ctf_enum_iter (ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg) (void) ctf_get_ctt_size (fp, tp, NULL, &increment); - ep = (const ctf_enum_t *) ((uintptr_t) tp + increment); + if ((dtd = ctf_dynamic_type (ofp, type)) == NULL) + { + ep = (const ctf_enum_t *) ((uintptr_t) tp + increment); - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++) + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++) + { + const char *name = ctf_strptr (fp, ep->cte_name); + if ((rc = func (name, ep->cte_value, arg)) != 0) + return rc; + } + } + else { - const char *name = ctf_strptr (fp, ep->cte_name); - if ((rc = func (name, ep->cte_value, arg)) != 0) - return rc; + ctf_dmdef_t *dmd; + + for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + dmd != NULL; dmd = ctf_list_next (dmd)) + { + if ((rc = func (dmd->dmd_name, dmd->dmd_value, arg)) != 0) + return rc; + } } return 0; @@ -171,16 +201,30 @@ ctf_type_iter_all (ctf_file_t *fp, ctf_type_all_f *func, void *arg) int ctf_variable_iter (ctf_file_t *fp, ctf_variable_f *func, void *arg) { - unsigned long i; int rc; if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL)) return ECTF_NOPARENT; - for (i = 0; i < fp->ctf_nvars; i++) - if ((rc = func (ctf_strptr (fp, fp->ctf_vars[i].ctv_name), - fp->ctf_vars[i].ctv_type, arg)) != 0) - return rc; + if (!(fp->ctf_flags & LCTF_RDWR)) + { + unsigned long i; + for (i = 0; i < fp->ctf_nvars; i++) + if ((rc = func (ctf_strptr (fp, fp->ctf_vars[i].ctv_name), + fp->ctf_vars[i].ctv_type, arg)) != 0) + return rc; + } + else + { + ctf_dvdef_t *dvd; + + for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; + dvd = ctf_list_next (dvd)) + { + if ((rc = func (dvd->dvd_name, dvd->dvd_type, arg)) != 0) + return rc; + } + } return 0; } @@ -249,6 +293,29 @@ ctf_type_resolve_unsliced (ctf_file_t *fp, ctf_id_t type) return type; } +/* Look up a name in the given name table, in the appropriate hash given the + kind of the identifier. The name is a raw, undecorated identifier. */ + +ctf_id_t ctf_lookup_by_rawname (ctf_file_t *fp, int kind, const char *name) +{ + return ctf_lookup_by_rawhash (fp, ctf_name_table (fp, kind), name); +} + +/* Look up a name in the given name table, in the appropriate hash given the + readability state of the dictionary. The name is a raw, undecorated + identifier. */ + +ctf_id_t ctf_lookup_by_rawhash (ctf_file_t *fp, ctf_names_t *np, const char *name) +{ + ctf_id_t id; + + if (fp->ctf_flags & LCTF_RDWR) + id = (ctf_id_t) ctf_dynhash_lookup (np->ctn_writable, name); + else + id = ctf_hash_lookup_type (np->ctn_readonly, fp, name); + return id; +} + /* Lookup the given type ID and return its name as a new dynamcally-allocated string. */ @@ -829,6 +896,7 @@ ctf_member_info (ctf_file_t *fp, ctf_id_t type, const char *name, { ctf_file_t *ofp = fp; const ctf_type_t *tp; + ctf_dtdef_t *dtd; ssize_t size, increment; uint32_t kind, n; @@ -844,32 +912,50 @@ ctf_member_info (ctf_file_t *fp, ctf_id_t type, const char *name, if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno (ofp, ECTF_NOTSOU)); - if (size < CTF_LSTRUCT_THRESH) + if ((dtd = ctf_dynamic_type (fp, type)) == NULL) { - const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + - increment); + if (size < CTF_LSTRUCT_THRESH) + { + const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + + increment); - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) + { + if (strcmp (ctf_strptr (fp, mp->ctm_name), name) == 0) + { + mip->ctm_type = mp->ctm_type; + mip->ctm_offset = mp->ctm_offset; + return 0; + } + } + } + else { - if (strcmp (ctf_strptr (fp, mp->ctm_name), name) == 0) + const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + + increment); + + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) { - mip->ctm_type = mp->ctm_type; - mip->ctm_offset = mp->ctm_offset; - return 0; + if (strcmp (ctf_strptr (fp, lmp->ctlm_name), name) == 0) + { + mip->ctm_type = lmp->ctlm_type; + mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp); + return 0; + } } } } else { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + - increment); + ctf_dmdef_t *dmd; - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) + for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + dmd != NULL; dmd = ctf_list_next (dmd)) { - if (strcmp (ctf_strptr (fp, lmp->ctlm_name), name) == 0) + if (strcmp (dmd->dmd_name, name) == 0) { - mip->ctm_type = lmp->ctlm_type; - mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp); + mip->ctm_type = dmd->dmd_type; + mip->ctm_offset = dmd->dmd_offset; return 0; } } @@ -920,6 +1006,7 @@ ctf_enum_name (ctf_file_t *fp, ctf_id_t type, int value) ctf_file_t *ofp = fp; const ctf_type_t *tp; const ctf_enum_t *ep; + const ctf_dtdef_t *dtd; ssize_t increment; uint32_t n; @@ -937,12 +1024,26 @@ ctf_enum_name (ctf_file_t *fp, ctf_id_t type, int value) (void) ctf_get_ctt_size (fp, tp, NULL, &increment); - ep = (const ctf_enum_t *) ((uintptr_t) tp + increment); + if ((dtd = ctf_dynamic_type (ofp, type)) == NULL) + { + ep = (const ctf_enum_t *) ((uintptr_t) tp + increment); - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++) + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++) + { + if (ep->cte_value == value) + return (ctf_strptr (fp, ep->cte_name)); + } + } + else { - if (ep->cte_value == value) - return (ctf_strptr (fp, ep->cte_name)); + ctf_dmdef_t *dmd; + + for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + dmd != NULL; dmd = ctf_list_next (dmd)) + { + if (dmd->dmd_value == value) + return dmd->dmd_name; + } } (void) ctf_set_errno (ofp, ECTF_NOENUMNAM); @@ -958,6 +1059,7 @@ ctf_enum_value (ctf_file_t * fp, ctf_id_t type, const char *name, int *valp) ctf_file_t *ofp = fp; const ctf_type_t *tp; const ctf_enum_t *ep; + const ctf_dtdef_t *dtd; ssize_t increment; uint32_t n; @@ -977,13 +1079,31 @@ ctf_enum_value (ctf_file_t * fp, ctf_id_t type, const char *name, int *valp) ep = (const ctf_enum_t *) ((uintptr_t) tp + increment); - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++) + if ((dtd = ctf_dynamic_type (ofp, type)) == NULL) { - if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0) + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++) { - if (valp != NULL) - *valp = ep->cte_value; - return 0; + if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0) + { + if (valp != NULL) + *valp = ep->cte_value; + return 0; + } + } + } + else + { + ctf_dmdef_t *dmd; + + for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + dmd != NULL; dmd = ctf_list_next (dmd)) + { + if (strcmp (dmd->dmd_name, name) == 0) + { + if (valp != NULL) + *valp = dmd->dmd_value; + return 0; + } } } @@ -1000,6 +1120,7 @@ ctf_func_type_info (ctf_file_t *fp, ctf_id_t type, ctf_funcinfo_t *fip) const ctf_type_t *tp; uint32_t kind; const uint32_t *args; + const ctf_dtdef_t *dtd; ssize_t size, increment; if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) @@ -1015,10 +1136,13 @@ ctf_func_type_info (ctf_file_t *fp, ctf_id_t type, ctf_funcinfo_t *fip) return (ctf_set_errno (fp, ECTF_NOTFUNC)); fip->ctc_return = tp->ctt_type; - fip->ctc_argc = LCTF_INFO_VLEN (fp, tp->ctt_info); fip->ctc_flags = 0; + fip->ctc_argc = LCTF_INFO_VLEN (fp, tp->ctt_info); - args = (uint32_t *) ((uintptr_t) tp + increment); + if ((dtd = ctf_dynamic_type (fp, type)) == NULL) + args = (uint32_t *) ((uintptr_t) tp + increment); + else + args = (uint32_t *) dtd->dtd_u.dtu_argv; if (fip->ctc_argc != 0 && args[fip->ctc_argc - 1] == 0) { @@ -1037,6 +1161,7 @@ ctf_func_type_args (ctf_file_t *fp, ctf_id_t type, uint32_t argc, ctf_id_t *argv { const ctf_type_t *tp; const uint32_t *args; + const ctf_dtdef_t *dtd; ssize_t size, increment; ctf_funcinfo_t f; @@ -1051,7 +1176,10 @@ ctf_func_type_args (ctf_file_t *fp, ctf_id_t type, uint32_t argc, ctf_id_t *argv (void) ctf_get_ctt_size (fp, tp, &size, &increment); - args = (uint32_t *) ((uintptr_t) tp + increment); + if ((dtd = ctf_dynamic_type (fp, type)) == NULL) + args = (uint32_t *) ((uintptr_t) tp + increment); + else + args = (uint32_t *) dtd->dtd_u.dtu_argv; for (argc = MIN (argc, f.ctc_argc); argc != 0; argc--) *argv++ = *args++; @@ -1071,6 +1199,7 @@ ctf_type_rvisit (ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, { ctf_id_t otype = type; const ctf_type_t *tp; + const ctf_dtdef_t *dtd; ssize_t size, increment; uint32_t kind, n; int rc; @@ -1091,32 +1220,48 @@ ctf_type_rvisit (ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, (void) ctf_get_ctt_size (fp, tp, &size, &increment); - if (size < CTF_LSTRUCT_THRESH) + if ((dtd = ctf_dynamic_type (fp, type)) == NULL) { - const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + - increment); - - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) + if (size < CTF_LSTRUCT_THRESH) { - if ((rc = ctf_type_rvisit (fp, mp->ctm_type, - func, arg, ctf_strptr (fp, mp->ctm_name), - offset + mp->ctm_offset, - depth + 1)) != 0) - return rc; + const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + + increment); + + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) + { + if ((rc = ctf_type_rvisit (fp, mp->ctm_type, + func, arg, ctf_strptr (fp, + mp->ctm_name), + offset + mp->ctm_offset, + depth + 1)) != 0) + return rc; + } } + else + { + const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + + increment); + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) + { + if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type, + func, arg, ctf_strptr (fp, + lmp->ctlm_name), + offset + (unsigned long) CTF_LMEM_OFFSET (lmp), + depth + 1)) != 0) + return rc; + } + } } else { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + - increment); + ctf_dmdef_t *dmd; - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) + for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + dmd != NULL; dmd = ctf_list_next (dmd)) { - if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type, - func, arg, ctf_strptr (fp, - lmp->ctlm_name), - offset + (unsigned long) CTF_LMEM_OFFSET (lmp), + if ((rc = ctf_type_rvisit (fp, dmd->dmd_type, func, arg, + dmd->dmd_name, dmd->dmd_offset, depth + 1)) != 0) return rc; } diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c index b813c0d..f27c768 100644 --- a/libctf/ctf-util.c +++ b/libctf/ctf-util.c @@ -80,6 +80,14 @@ ctf_list_delete (ctf_list_t *lp, void *existing) lp->l_prev = p->l_prev; } +/* Return 1 if the list is empty. */ + +int +ctf_list_empty_p (ctf_list_t *lp) +{ + return (lp->l_next == NULL && lp->l_prev == NULL); +} + /* Convert a 32-bit ELF symbol into Elf64 and return a pointer to it. */ Elf64_Sym * |