@@ -47,9 +47,13 @@ ctf_grow_ptrtab (ctf_dict_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. */
+ plus one because the caller will probably allocate a new type.
- if (fp->ctf_ptrtab == NULL)
+ Equally, if the ptrtab is small -- perhaps due to ctf_open of a small
+ dict -- boost it by quite a lot at first, so we don't need to keep
+ realloc()ing. */
+
+ if (fp->ctf_ptrtab == NULL || fp->ctf_ptrtab_len < 1024)
new_ptrtab_len = 1024;
else if ((fp->ctf_typemax + 2) > fp->ctf_ptrtab_len)
new_ptrtab_len = fp->ctf_ptrtab_len * 1.25;
@@ -104,29 +108,11 @@ ctf_create (int *errp)
{
static const ctf_header_t hdr = { .cth_preamble = { CTF_MAGIC, CTF_VERSION, 0 } };
- ctf_dynhash_t *dthash;
- ctf_dynhash_t *dvhash;
ctf_dynhash_t *structs = NULL, *unions = NULL, *enums = NULL, *names = NULL;
- ctf_dynhash_t *objthash = NULL, *funchash = NULL;
ctf_sect_t cts;
ctf_dict_t *fp;
libctf_init_debug();
- dthash = ctf_dynhash_create (ctf_hash_integer, ctf_hash_eq_integer,
- NULL, NULL);
- if (dthash == NULL)
- {
- ctf_set_open_errno (errp, EAGAIN);
- goto err;
- }
-
- dvhash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
- NULL, NULL);
- if (dvhash == NULL)
- {
- ctf_set_open_errno (errp, EAGAIN);
- goto err_dt;
- }
structs = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
NULL, NULL);
@@ -136,14 +122,10 @@ ctf_create (int *errp)
NULL, NULL);
names = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
NULL, NULL);
- objthash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
- free, NULL);
- funchash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
- free, NULL);
if (!structs || !unions || !enums || !names)
{
ctf_set_open_errno (errp, EAGAIN);
- goto err_dv;
+ goto err;
}
cts.cts_name = _CTF_SECTION;
@@ -151,24 +133,26 @@ ctf_create (int *errp)
cts.cts_size = sizeof (hdr);
cts.cts_entsize = 1;
- if ((fp = ctf_bufopen_internal (&cts, NULL, NULL, NULL, 1, errp)) == NULL)
- goto err_dv;
+ if ((fp = ctf_bufopen_internal (&cts, NULL, NULL, NULL, errp)) == NULL)
+ goto err;
+ /* These hashes will have been initialized with a starting size of zero,
+ which is surely wrong. Use ones with slightly larger sizes. */
+ ctf_dynhash_destroy (fp->ctf_structs);
+ ctf_dynhash_destroy (fp->ctf_unions);
+ ctf_dynhash_destroy (fp->ctf_enums);
+ ctf_dynhash_destroy (fp->ctf_names);
fp->ctf_structs = structs;
fp->ctf_unions = unions;
fp->ctf_enums = enums;
fp->ctf_names = names;
- fp->ctf_objthash = objthash;
- fp->ctf_funchash = funchash;
- fp->ctf_dthash = dthash;
- fp->ctf_dvhash = dvhash;
fp->ctf_dtoldid = 0;
- fp->ctf_snapshots = 1;
fp->ctf_snapshot_lu = 0;
fp->ctf_flags |= LCTF_DIRTY;
+ /* Make sure the ptrtab starts out at a reasonable size. */
+
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));
@@ -178,17 +162,11 @@ ctf_create (int *errp)
return fp;
- err_dv:
+ err:
ctf_dynhash_destroy (structs);
ctf_dynhash_destroy (unions);
ctf_dynhash_destroy (enums);
ctf_dynhash_destroy (names);
- ctf_dynhash_destroy (objthash);
- ctf_dynhash_destroy (funchash);
- ctf_dynhash_destroy (dvhash);
- err_dt:
- ctf_dynhash_destroy (dthash);
- err:
return NULL;
}
@@ -196,9 +174,6 @@ ctf_create (int *errp)
int
ctf_update (ctf_dict_t *fp)
{
- if (!(fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (fp, ECTF_RDONLY));
-
fp->ctf_dtoldid = fp->ctf_typemax;
return 0;
}
@@ -310,9 +285,6 @@ ctf_dynamic_type (const ctf_dict_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;
@@ -323,6 +295,19 @@ ctf_dynamic_type (const ctf_dict_t *fp, ctf_id_t id)
return NULL;
}
+static int
+ctf_static_type (const ctf_dict_t *fp, ctf_id_t id)
+{
+ ctf_id_t idx;
+
+ if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, id))
+ fp = fp->ctf_parent;
+
+ idx = LCTF_TYPE_TO_INDEX(fp, id);
+
+ return ((unsigned long) idx <= fp->ctf_stypes);
+}
+
int
ctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd)
{
@@ -385,7 +370,7 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
ctf_dtdef_t *dtd, *ntd;
ctf_dvdef_t *dvd, *nvd;
- if (!(fp->ctf_flags & LCTF_RDWR))
+ if (id.snapshot_id < fp->ctf_stypes)
return (ctf_set_errno (fp, ECTF_RDONLY));
if (fp->ctf_snapshot_lu >= id.snapshot_id)
@@ -449,15 +434,25 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
return (ctf_set_typed_errno (fp, EINVAL));
- if (!(fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_typed_errno (fp, ECTF_RDONLY));
-
if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE)
return (ctf_set_typed_errno (fp, ECTF_FULL));
if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))
return (ctf_set_typed_errno (fp, ECTF_FULL));
+ /* Prohibit addition of a root-visible type that is already present
+ in the non-dynamic portion. */
+
+ if (flag == CTF_ADD_ROOT && name != NULL && name[0] != '\0')
+ {
+ ctf_id_t existing;
+
+ if (((existing = ctf_dynhash_lookup_type (ctf_name_table (fp, kind),
+ name)) > 0)
+ && ctf_static_type (fp, existing))
+ return (ctf_set_typed_errno (fp, ECTF_RDONLY));
+ }
+
/* 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. */
@@ -724,10 +719,9 @@ ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, type))
fp = fp->ctf_parent;
- if (!(ofp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (ofp, ECTF_RDONLY));
-
- if (!(fp->ctf_flags & LCTF_RDWR))
+ /* You can only call ctf_set_array on a type you have added, not a
+ type that was read in via ctf_open(). */
+ if (type < fp->ctf_stypes)
return (ctf_set_errno (ofp, ECTF_RDONLY));
if (dtd == NULL
@@ -755,9 +749,6 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
size_t initial_vlen;
size_t i;
- if (!(fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_typed_errno (fp, ECTF_RDONLY));
-
if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
|| (ctc->ctc_argc != 0 && argv == NULL))
return (ctf_set_typed_errno (fp, EINVAL));
@@ -813,6 +804,10 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
if (name != NULL)
type = ctf_lookup_by_rawname (fp, CTF_K_STRUCT, name);
+ /* Prohibit promotion if this type was ctf_open()ed. */
+ if (type > 0 && type < fp->ctf_stypes)
+ return (ctf_set_errno (fp, ECTF_RDONLY));
+
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, CTF_K_STRUCT,
@@ -853,11 +848,15 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
if (name != NULL)
type = ctf_lookup_by_rawname (fp, CTF_K_UNION, name);
+ /* Prohibit promotion if this type was ctf_open()ed. */
+ if (type > 0 && type < fp->ctf_stypes)
+ return (ctf_set_errno (fp, ECTF_RDONLY));
+
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, CTF_K_UNION,
initial_vlen, &dtd)) == CTF_ERR)
- return CTF_ERR; /* errno is set for us */
+ return CTF_ERR; /* errno is set for us. */
/* Forwards won't have any vlen yet. */
if (dtd->dtd_vlen_alloc == 0)
@@ -892,6 +891,10 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
if (name != NULL)
type = ctf_lookup_by_rawname (fp, CTF_K_ENUM, name);
+ /* Prohibit promotion if this type was ctf_open()ed. */
+ if (type > 0 && type < fp->ctf_stypes)
+ return (ctf_set_errno (fp, ECTF_RDONLY));
+
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, CTF_K_ENUM,
@@ -953,8 +956,9 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
if (name == NULL || name[0] == '\0')
return (ctf_set_typed_errno (fp, ECTF_NONAME));
- /* If the type is already defined or exists as a forward tag, just
- return the ctf_id_t of the existing definition. */
+ /* If the type is already defined or exists as a forward tag, just return
+ the ctf_id_t of the existing definition. Since this changes nothing,
+ it's safe to do even on the read-only portion of the dict. */
type = ctf_lookup_by_rawname (fp, kind, name);
@@ -1066,10 +1070,7 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, enid))
fp = fp->ctf_parent;
- if (!(ofp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (ofp, ECTF_RDONLY));
-
- if (!(fp->ctf_flags & LCTF_RDWR))
+ if (enid < fp->ctf_stypes)
return (ctf_set_errno (ofp, ECTF_RDONLY));
if (dtd == NULL)
@@ -1142,10 +1143,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
fp = fp->ctf_parent;
}
- if (!(ofp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (ofp, ECTF_RDONLY));
-
- if (!(fp->ctf_flags & LCTF_RDWR))
+ if (souid < fp->ctf_stypes)
return (ctf_set_errno (ofp, ECTF_RDONLY));
if (dtd == NULL)
@@ -1332,18 +1330,15 @@ ctf_add_member (ctf_dict_t *fp, ctf_id_t souid, const char *name,
return ctf_add_member_offset (fp, souid, name, type, (unsigned long) - 1);
}
+/* Add a variable regardless of whether or not it is already present.
+
+ Internal use only. */
int
-ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
+ctf_add_variable_forced (ctf_dict_t *fp, const char *name, ctf_id_t ref)
{
ctf_dvdef_t *dvd;
ctf_dict_t *tmp = fp;
- if (!(fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (fp, ECTF_RDONLY));
-
- if (ctf_dvd_lookup (fp, name) != NULL)
- return (ctf_set_errno (fp, ECTF_DUPLICATE));
-
if (ctf_lookup_by_id (&tmp, ref) == NULL)
return -1; /* errno is set for us. */
@@ -1375,21 +1370,30 @@ ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
}
int
-ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_t id)
+ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
+{
+ if (ctf_lookup_variable_here (fp, name) != CTF_ERR)
+ return (ctf_set_errno (fp, ECTF_DUPLICATE));
+
+ if (ctf_errno (fp) != ECTF_NOTYPEDAT)
+ return -1; /* errno is set for us. */
+
+ return ctf_add_variable_forced (fp, name, ref);
+}
+
+/* Add a function or object symbol regardless of whether or not it is already
+ present (already existing symbols are silently overwritten).
+
+ Internal use only. */
+int
+ctf_add_funcobjt_sym_forced (ctf_dict_t *fp, int is_function, const char *name, ctf_id_t id)
{
ctf_dict_t *tmp = fp;
char *dupname;
ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
- if (!(fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (fp, ECTF_RDONLY));
-
- if (ctf_dynhash_lookup (fp->ctf_objthash, name) != NULL ||
- ctf_dynhash_lookup (fp->ctf_funchash, name) != NULL)
- return (ctf_set_errno (fp, ECTF_DUPLICATE));
-
if (ctf_lookup_by_id (&tmp, id) == NULL)
- return -1; /* errno is set for us. */
+ return -1; /* errno is set for us. */
if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
return (ctf_set_errno (fp, ECTF_NOTFUNC));
@@ -1405,6 +1409,15 @@ ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_
return 0;
}
+int
+ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_t id)
+{
+ if (ctf_lookup_by_sym_or_name (fp, 0, name, 0, is_function) != CTF_ERR)
+ return (ctf_set_errno (fp, ECTF_DUPLICATE));
+
+ return ctf_add_funcobjt_sym_forced (fp, is_function, name, id);
+}
+
int
ctf_add_objt_sym (ctf_dict_t *fp, const char *name, ctf_id_t id)
{
@@ -1606,9 +1619,6 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
ctf_id_t orig_src_type = src_type;
- if (!(dst_fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_typed_errno (dst_fp, ECTF_RDONLY));
-
if ((src_tp = ctf_lookup_by_id (&src_fp, src_type)) == NULL)
return (ctf_set_typed_errno (dst_fp, ctf_errno (src_fp)));
@@ -369,7 +369,8 @@ struct ctf_dict
ctf_sect_t ctf_symtab; /* Symbol table from object file. */
ctf_sect_t ctf_strtab; /* String table from object file. */
int ctf_symsect_little_endian; /* Endianness of the ctf_symtab. */
- ctf_dynhash_t *ctf_symhash; /* (partial) hash, symsect name -> idx. */
+ ctf_dynhash_t *ctf_symhash_func; /* (partial) hash, symsect name -> idx. */
+ ctf_dynhash_t *ctf_symhash_objt; /* ditto, for object symbols. */
size_t ctf_symhash_latest; /* Amount of symsect scanned so far. */
ctf_dynhash_t *ctf_prov_strtab; /* Maps provisional-strtab offsets
to names. */
@@ -406,8 +407,8 @@ struct ctf_dict
uint32_t *ctf_funcidx_sxlate; /* Offsets into funcinfo for a given funcidx. */
uint32_t *ctf_objtidx_sxlate; /* Likewise, for ctf_objtidx. */
size_t ctf_nobjtidx; /* Number of objtidx entries. */
- ctf_dynhash_t *ctf_objthash; /* name -> type ID. */
- ctf_dynhash_t *ctf_funchash; /* name -> CTF_K_FUNCTION type ID. */
+ ctf_dynhash_t *ctf_objthash; /* Dynamic: name -> type ID. */
+ ctf_dynhash_t *ctf_funchash; /* Dynamic: name -> CTF_K_FUNCTION type ID. */
/* The next three are linker-derived state found in ctf_link targets only. */
@@ -418,6 +419,7 @@ struct ctf_dict
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. */
+ unsigned long ctf_stypes; /* Number of static (non-dynamic) types. */
const ctf_dmodel_t *ctf_dmodel; /* Data model pointer (see above). */
const char *ctf_cuname; /* Compilation unit name (if any). */
char *ctf_dyncuname; /* Dynamically allocated name of CU. */
@@ -575,7 +577,7 @@ struct ctf_next
(id))
#define LCTF_INDEX_TO_TYPEPTR(fp, i) \
- ((fp->ctf_flags & LCTF_RDWR) ? \
+ ((i > fp->ctf_stypes) ? \
&(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)]))
@@ -587,14 +589,19 @@ struct ctf_next
((fp)->ctf_dictops->ctfo_get_vbytes(fp, kind, size, vlen))
#define LCTF_CHILD 0x0001 /* CTF dict is a child. */
-#define LCTF_RDWR 0x0002 /* CTF dict is writable. */
-#define LCTF_DIRTY 0x0004 /* CTF dict has been modified. */
-#define LCTF_LINKING 0x0008 /* CTF link is underway: respect ctf_link_flags. */
+#define LCTF_DIRTY 0x0002 /* CTF dict has been modified. */
+#define LCTF_LINKING 0x0004 /* CTF link is underway: respect ctf_link_flags. */
extern ctf_dynhash_t *ctf_name_table (ctf_dict_t *, int);
extern const ctf_type_t *ctf_lookup_by_id (ctf_dict_t **, ctf_id_t);
+extern ctf_id_t ctf_lookup_variable_here (ctf_dict_t *fp, const char *name);
+extern ctf_id_t ctf_lookup_by_sym_or_name (ctf_dict_t *, unsigned long symidx,
+ const char *symname, int try_parent,
+ int is_function);
extern ctf_id_t ctf_lookup_by_rawname (ctf_dict_t *, int, const char *);
extern void ctf_set_ctl_hashes (ctf_dict_t *);
+extern ctf_id_t ctf_symbol_next_static (ctf_dict_t *, ctf_next_t **,
+ const char **, int);
extern int ctf_symtab_skippable (ctf_link_sym_t *sym);
extern int ctf_add_funcobjt_sym (ctf_dict_t *, int is_function,
@@ -690,6 +697,9 @@ extern ctf_id_t ctf_add_encoded (ctf_dict_t *, uint32_t, const char *,
const ctf_encoding_t *, uint32_t kind);
extern ctf_id_t ctf_add_reftype (ctf_dict_t *, uint32_t, ctf_id_t,
uint32_t kind);
+extern int ctf_add_variable_forced (ctf_dict_t *, const char *, ctf_id_t);
+extern int ctf_add_funcobjt_sym_forced (ctf_dict_t *, int is_function,
+ const char *, ctf_id_t);
extern int ctf_dedup_atoms_init (ctf_dict_t *);
extern int ctf_dedup (ctf_dict_t *, ctf_dict_t **, uint32_t ninputs,
@@ -741,10 +751,10 @@ extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
extern ctf_dict_t *ctf_simple_open_internal (const char *, size_t, const char *,
size_t, size_t,
const char *, size_t,
- ctf_dynhash_t *, int, int *);
+ ctf_dynhash_t *, int *);
extern ctf_dict_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_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp);
extern int ctf_serialize (ctf_dict_t *);
@@ -1576,6 +1576,8 @@ ctf_link_intern_extern_string (void *key _libctf_unused_, void *value,
/* Repeatedly call ADD_STRING to acquire strings from the external string table,
adding them to the atoms table for this CU and all subsidiary CUs.
+ Must be called on a dict that has not yet been serialized.
+
If ctf_link is also called, it must be called first if you want the new CTF
files ctf_link can create to get their strings dedupped against the ELF
strtab properly. */
@@ -1587,6 +1589,9 @@ ctf_link_add_strtab (ctf_dict_t *fp, ctf_link_strtab_string_f *add_string,
uint32_t offset;
int err = 0;
+ if (fp->ctf_stypes > 0)
+ return ctf_set_errno (fp, ECTF_RDONLY);
+
while ((str = add_string (&offset, arg)) != NULL)
{
ctf_link_out_string_cb_arg_t iter_arg = { str, offset, 0 };
@@ -1610,7 +1615,8 @@ ctf_link_add_strtab (ctf_dict_t *fp, ctf_link_strtab_string_f *add_string,
/* Inform the ctf-link machinery of a new symbol in the target symbol table
(which must be some symtab that is not usually stripped, and which
is in agreement with ctf_bfdopen_ctfsect). May be called either before or
- after ctf_link_add_strtab. */
+ after ctf_link_add_strtab. As with that function, must be called on a dict which
+ has not yet been serialized. */
int
ctf_link_add_linker_symbol (ctf_dict_t *fp, ctf_link_sym_t *sym)
{
@@ -1625,6 +1631,9 @@ ctf_link_add_linker_symbol (ctf_dict_t *fp, ctf_link_sym_t *sym)
if (ctf_errno (fp) == ENOMEM)
return -ENOMEM; /* errno is set for us. */
+ if (fp->ctf_stypes > 0)
+ return ctf_set_errno (fp, ECTF_RDONLY);
+
if (ctf_symtab_skippable (sym))
return 0;
@@ -1660,6 +1669,9 @@ ctf_link_shuffle_syms (ctf_dict_t *fp)
int err = ENOMEM;
void *name_, *sym_;
+ if (fp->ctf_stypes > 0)
+ return ctf_set_errno (fp, ECTF_RDONLY);
+
if (!fp->ctf_dynsyms)
{
fp->ctf_dynsyms = ctf_dynhash_create (ctf_hash_string,
@@ -329,7 +329,7 @@ ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
const ctf_type_t *
ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
{
- ctf_dict_t *fp = *fpp; /* Caller passes in starting CTF dict. */
+ ctf_dict_t *fp = *fpp;
ctf_id_t idx;
if ((fp = ctf_get_dict (fp, type)) == NULL)
@@ -338,27 +338,10 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
return NULL;
}
- /* If this dict is writable, check for a dynamic type. */
-
- if (fp->ctf_flags & LCTF_RDWR)
- {
- ctf_dtdef_t *dtd;
-
- if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
- {
- *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 dict. */
+ *fpp = fp; /* Possibly the parent CTF dict. */
return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
}
@@ -384,36 +367,52 @@ ctf_lookup_var (const void *key_, const void *lookup_)
return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, lookup->ctv_name)));
}
-/* Given a variable name, return the type of the variable with that name. */
+/* Given a variable name, return the type of the variable with that name.
+ Look only in this dict, not in the parent. */
ctf_id_t
-ctf_lookup_variable (ctf_dict_t *fp, const char *name)
+ctf_lookup_variable_here (ctf_dict_t *fp, const char *name)
{
+ ctf_dvdef_t *dvd = ctf_dvd_lookup (fp, name);
ctf_varent_t *ent;
ctf_lookup_idx_key_t key = { fp, name, NULL };
+ if (dvd != NULL)
+ return dvd->dvd_type;
+
/* This array is sorted, so we can bsearch for it. */
ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t),
ctf_lookup_var);
if (ent == NULL)
- {
- if (fp->ctf_parent != NULL)
- {
- ctf_id_t ptype;
-
- if ((ptype = ctf_lookup_variable (fp->ctf_parent, name)) != CTF_ERR)
- return ptype;
- return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
- }
-
return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT));
- }
return ent->ctv_type;
}
+/* As above, but look in the parent too. */
+
+ctf_id_t
+ctf_lookup_variable (ctf_dict_t *fp, const char *name)
+{
+ ctf_id_t type;
+
+ if ((type = ctf_lookup_variable_here (fp, name)) == CTF_ERR)
+ {
+ if (ctf_errno (fp) == ECTF_NOTYPEDAT && fp->ctf_parent != NULL)
+ {
+ if ((type = ctf_lookup_variable_here (fp->ctf_parent, name)) != CTF_ERR)
+ return type;
+ return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
+ }
+
+ return -1; /* errno is set for us. */
+ }
+
+ return type;
+}
+
typedef struct ctf_symidx_sort_arg_cb
{
ctf_dict_t *fp;
@@ -535,9 +534,11 @@ ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
}
/* Given a symbol name, return the index of that symbol, or -1 on error or if
- not found. */
+ not found. If is_function is >= 0, return only function or data object
+ symbols, respectively. */
static unsigned long
-ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
+ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname, int try_parent,
+ int is_function)
{
const ctf_sect_t *sp = &fp->ctf_symtab;
ctf_link_sym_t sym;
@@ -551,7 +552,9 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
ctf_link_sym_t *symp;
- if ((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL)
+ if (((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL)
+ || (symp->st_type != STT_OBJECT && is_function == 0)
+ || (symp->st_type != STT_FUNC && is_function == 1))
goto try_parent;
return symp->st_symidx;
@@ -562,22 +565,33 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
goto try_parent;
/* First, try a hash lookup to see if we have already spotted this symbol
- during a past iteration: create the hash first if need be. The lifespan
- of the strings is equal to the lifespan of the cts_data, so we don't
- need to strdup them. If this dict was opened as part of an archive,
- and this archive has designed a crossdict_cache to cache results that
+ during a past iteration: create the hash first if need be. The
+ lifespan of the strings is equal to the lifespan of the cts_data, so we
+ don't need to strdup them. If this dict was opened as part of an
+ archive, and this archive has a crossdict_cache to cache results that
are the same across all dicts in an archive, use it. */
if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache)
cache = fp->ctf_archive->ctfi_crossdict_cache;
- if (!cache->ctf_symhash)
- if ((cache->ctf_symhash = ctf_dynhash_create (ctf_hash_string,
- ctf_hash_eq_string,
- NULL, NULL)) == NULL)
+ if (!cache->ctf_symhash_func)
+ if ((cache->ctf_symhash_func = ctf_dynhash_create (ctf_hash_string,
+ ctf_hash_eq_string,
+ NULL, NULL)) == NULL)
goto oom;
- if (ctf_dynhash_lookup_kv (cache->ctf_symhash, symname, NULL, &known_idx))
+ if (!cache->ctf_symhash_objt)
+ if ((cache->ctf_symhash_objt = ctf_dynhash_create (ctf_hash_string,
+ ctf_hash_eq_string,
+ NULL, NULL)) == NULL)
+ goto oom;
+
+ if (is_function != 0 &&
+ ctf_dynhash_lookup_kv (cache->ctf_symhash_func, symname, NULL, &known_idx))
+ return (unsigned long) (uintptr_t) known_idx;
+
+ if (is_function != 1 &&
+ ctf_dynhash_lookup_kv (cache->ctf_symhash_objt, symname, NULL, &known_idx))
return (unsigned long) (uintptr_t) known_idx;
/* Hash lookup unsuccessful: linear search, populating the hashtab for later
@@ -586,21 +600,16 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize;
cache->ctf_symhash_latest++)
{
+ ctf_dynhash_t *h;
+
switch (sp->cts_entsize)
{
case sizeof (Elf64_Sym):
{
Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data;
+
ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest],
cache->ctf_symhash_latest);
- if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name,
- NULL, NULL))
- if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name,
- (const void *) (uintptr_t)
- cache->ctf_symhash_latest) < 0)
- goto oom;
- if (strcmp (sym.st_name, symname) == 0)
- return cache->ctf_symhash_latest++;
}
break;
case sizeof (Elf32_Sym):
@@ -608,20 +617,28 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data;
ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest],
cache->ctf_symhash_latest);
- if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name,
- NULL, NULL))
- if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name,
- (const void *) (uintptr_t)
- cache->ctf_symhash_latest) < 0)
- goto oom;
- if (strcmp (sym.st_name, symname) == 0)
- return cache->ctf_symhash_latest++;
+ break;
}
- break;
default:
ctf_set_errno (fp, ECTF_SYMTAB);
return (unsigned long) -1;
}
+
+ if (sym.st_type == STT_FUNC)
+ h = cache->ctf_symhash_func;
+ else if (sym.st_type == STT_OBJECT)
+ h = cache->ctf_symhash_objt;
+ else
+ continue; /* Not of interest. */
+
+ if (!ctf_dynhash_lookup_kv (h, sym.st_name,
+ NULL, NULL))
+ if (ctf_dynhash_cinsert (h, sym.st_name,
+ (const void *) (uintptr_t)
+ cache->ctf_symhash_latest) < 0)
+ goto oom;
+ if (strcmp (sym.st_name, symname) == 0)
+ return cache->ctf_symhash_latest++;
}
/* Searched everything, still not found. */
@@ -629,11 +646,12 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
return (unsigned long) -1;
try_parent:
- if (fp->ctf_parent)
+ if (fp->ctf_parent && try_parent)
{
unsigned long psym;
- if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname))
+ if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname, try_parent,
+ is_function))
!= (unsigned long) -1)
return psym;
@@ -653,12 +671,17 @@ oom:
}
-/* Iterate over all symbols with types: if FUNC, function symbols, otherwise,
- data symbols. The name argument is not optional. The return order is
- arbitrary, though is likely to be in symbol index or name order. You can
- change the value of 'functions' in the middle of iteration over non-dynamic
- dicts, but doing so on dynamic dicts will fail. (This is probably not very
- useful, but there is no reason to prohibit it.) */
+ctf_id_t
+ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name,
+ int functions);
+
+/* Iterate over all symbols with types: if FUNC, function symbols,
+ otherwise, data symbols. The name argument is not optional. The return
+ order is arbitrary, though is likely to be in symbol index or name order.
+ Changing the value of 'functions' in the middle of iteration has
+ unpredictable effects (probably skipping symbols, etc) and is not
+ recommended. Adding symbols while iteration is underway may also lead
+ to other symbols being skipped. */
ctf_id_t
ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
@@ -685,24 +708,24 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
if (fp != i->cu.ctn_fp)
return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
- /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
+ /* Check the dynamic set of names first, to allow previously-written names
+ to be replaced with dynamic ones (there is still no way to remove them,
+ though).
+
+ We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
incurring additional sorting cost for unsorted symtypetabs coming from the
compiler, to allow ctf_symbol_next to work in the absence of a symtab, and
finally because it's easier to work out what the name of each symbol is if
we do that. */
- if (fp->ctf_flags & LCTF_RDWR)
+ ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash;
+ void *dyn_name = NULL, *dyn_value = NULL;
+ size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0;
+
+ if (i->ctn_n < dyn_els)
{
- ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash;
- void *dyn_name = NULL, *dyn_value = NULL;
-
- if (!dynh)
- {
- ctf_next_destroy (i);
- return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
- }
-
err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
+
/* This covers errors and also end-of-iteration. */
if (err != 0)
{
@@ -713,9 +736,50 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
*name = dyn_name;
sym = (ctf_id_t) (uintptr_t) dyn_value;
+ i->ctn_n++;
+
+ return sym;
}
- else if ((!functions && fp->ctf_objtidx_names) ||
- (functions && fp->ctf_funcidx_names))
+
+ return ctf_symbol_next_static (fp, it, name, functions);
+}
+
+/* ctf_symbol_next, but only for static symbols. Mostly an internal
+ implementation detail of ctf_symbol_next, but also used to simplify
+ serialization. */
+ctf_id_t
+ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name,
+ int functions)
+{
+ ctf_id_t sym = CTF_ERR;
+ ctf_next_t *i = *it;
+ ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash;
+ size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0;
+
+ /* Only relevant for direct internal-to-library calls, not via
+ ctf_symbol_next (but important then). */
+
+ if (!i)
+ {
+ if ((i = ctf_next_create ()) == NULL)
+ return ctf_set_typed_errno (fp, ENOMEM);
+
+ i->cu.ctn_fp = fp;
+ i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
+ i->ctn_n = dyn_els;
+ *it = i;
+ }
+
+ if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
+ return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
+
+ if (fp != i->cu.ctn_fp)
+ return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
+
+ /* TODO-v4: Indexed after non-indexed portions? */
+
+ if ((!functions && fp->ctf_objtidx_names) ||
+ (functions && fp->ctf_funcidx_names))
{
ctf_header_t *hp = fp->ctf_header;
uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names;
@@ -735,48 +799,51 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
do
{
- if (i->ctn_n >= len)
+ if (i->ctn_n - dyn_els >= len)
goto end;
- *name = ctf_strptr (fp, idx[i->ctn_n]);
- sym = tab[i->ctn_n++];
+ *name = ctf_strptr (fp, idx[i->ctn_n - dyn_els]);
+ sym = tab[i->ctn_n - dyn_els];
+ i->ctn_n++;
}
while (sym == -1u || sym == 0);
}
else
{
- /* Skip over pads in ctf_xslate, padding for typeless symbols in the
+ /* Skip over pads in ctf_sxlate, padding for typeless symbols in the
symtypetab itself, and symbols in the wrong table. */
- for (; i->ctn_n < fp->ctf_nsyms; i->ctn_n++)
+ for (; i->ctn_n - dyn_els < fp->ctf_nsyms; i->ctn_n++)
{
ctf_header_t *hp = fp->ctf_header;
+ size_t n = i->ctn_n - dyn_els;
- if (fp->ctf_sxlate[i->ctn_n] == -1u)
+ if (fp->ctf_sxlate[n] == -1u)
continue;
- sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[i->ctn_n]);
+ sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[n]);
if (sym == 0)
continue;
if (functions)
{
- if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_funcoff
- && fp->ctf_sxlate[i->ctn_n] < hp->cth_objtidxoff)
+ if (fp->ctf_sxlate[n] >= hp->cth_funcoff
+ && fp->ctf_sxlate[n] < hp->cth_objtidxoff)
break;
}
else
{
- if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_objtoff
- && fp->ctf_sxlate[i->ctn_n] < hp->cth_funcoff)
+ if (fp->ctf_sxlate[n] >= hp->cth_objtoff
+ && fp->ctf_sxlate[n] < hp->cth_funcoff)
break;
}
}
- if (i->ctn_n >= fp->ctf_nsyms)
+ if (i->ctn_n - dyn_els >= fp->ctf_nsyms)
goto end;
- *name = ctf_lookup_symbol_name (fp, i->ctn_n++);
+ *name = ctf_lookup_symbol_name (fp, i->ctn_n - dyn_els);
+ i->ctn_n++;
}
return sym;
@@ -815,6 +882,13 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
if (symname == NULL)
symname = ctf_lookup_symbol_name (fp, symidx);
+ /* Dynamic dict with no static portion: just return. */
+ if (!hp)
+ {
+ ctf_dprintf ("%s not found in idx: dict is dynamic\n", symname);
+ return 0;
+ }
+
ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in "
"indexed symtypetab\n", symidx, symname);
@@ -887,17 +961,27 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
function or data object described by the corresponding entry in the symbol
table. We can only return symbols in read-only dicts and in dicts for which
ctf_link_shuffle_syms has been called to assign symbol indexes to symbol
- names. */
+ names.
-static ctf_id_t
+ If try_parent is false, do not check the parent dict too.
+
+ If is_function is > -1, only look for data objects or functions in
+ particular. */
+
+ctf_id_t
ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
- const char *symname)
+ const char *symname, int try_parent,
+ int is_function)
{
const ctf_sect_t *sp = &fp->ctf_symtab;
ctf_id_t type = 0;
int err = 0;
- /* Shuffled dynsymidx present? Use that. */
+ /* Shuffled dynsymidx present? Use that. For now, the dynsymidx and
+ shuffled-symbol lookup only support dynamically-added symbols, because
+ this interface is meant for use by linkers, and linkers are only going
+ to report symbols against newly-created, freshly-ctf_link'ed dicts: so
+ there will be no static component in any case. */
if (fp->ctf_dynsymidx)
{
const ctf_link_sym_t *sym;
@@ -909,10 +993,6 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
ctf_dprintf ("Looking up type of object with symtab idx %lx in "
"writable dict symtypetab\n", symidx);
- /* The dict must be dynamic. */
- if (!ctf_assert (fp, fp->ctf_flags & LCTF_RDWR))
- return CTF_ERR;
-
/* No name? Need to look it up. */
if (!symname)
{
@@ -922,7 +1002,9 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
sym = fp->ctf_dynsymidx[symidx];
err = ECTF_NOTYPEDAT;
- if (!sym || (sym->st_shndx != STT_OBJECT && sym->st_shndx != STT_FUNC))
+ if (!sym || (sym->st_type != STT_OBJECT && sym->st_type != STT_FUNC)
+ || (sym->st_type != STT_OBJECT && is_function == 0)
+ || (sym->st_type != STT_FUNC && is_function == 1))
goto try_parent;
if (!ctf_assert (fp, !sym->st_nameidx_set))
@@ -931,49 +1013,55 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
}
if (fp->ctf_objthash == NULL
- || ((type = (ctf_id_t) (uintptr_t)
- ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
+ || is_function == 1
+ || (type = (ctf_id_t) (uintptr_t)
+ ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0)
{
if (fp->ctf_funchash == NULL
- || ((type = (ctf_id_t) (uintptr_t)
- ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0))
+ || is_function == 0
+ || (type = (ctf_id_t) (uintptr_t)
+ ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0)
goto try_parent;
}
return type;
}
- /* Lookup by name in a dynamic dict: just do it directly. */
- if (symname && fp->ctf_flags & LCTF_RDWR)
+ /* Dict not shuffled: look for a dynamic sym first, and look it up
+ directly. */
+ if (symname)
{
- if (fp->ctf_objthash == NULL
- || ((type = (ctf_id_t) (uintptr_t)
- ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
- {
- if (fp->ctf_funchash == NULL
- || ((type = (ctf_id_t) (uintptr_t)
- ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0))
- goto try_parent;
- }
- return type;
+ if (fp->ctf_objthash != NULL
+ && is_function != 1
+ && ((type = (ctf_id_t) (uintptr_t)
+ ctf_dynhash_lookup (fp->ctf_objthash, symname)) != 0))
+ return type;
+
+ if (fp->ctf_funchash != NULL
+ && is_function != 0
+ && ((type = (ctf_id_t) (uintptr_t)
+ ctf_dynhash_lookup (fp->ctf_funchash, symname)) != 0))
+ return type;
}
err = ECTF_NOSYMTAB;
if (sp->cts_data == NULL)
goto try_parent;
- /* This covers both out-of-range lookups and a dynamic dict which hasn't been
- shuffled yet. */
+ /* This covers both out-of-range lookups by index and a dynamic dict which
+ hasn't been shuffled yet. */
err = EINVAL;
if (symname == NULL && symidx >= fp->ctf_nsyms)
goto try_parent;
- if (fp->ctf_objtidx_names)
+ /* Try an indexed lookup. */
+
+ if (fp->ctf_objtidx_names && is_function != 1)
{
if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR)
return CTF_ERR; /* errno is set for us. */
}
- if (type == 0 && fp->ctf_funcidx_names)
+ if (type == 0 && fp->ctf_funcidx_names && is_function != 0)
{
if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR)
return CTF_ERR; /* errno is set for us. */
@@ -981,6 +1069,7 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
if (type != 0)
return type;
+ /* Indexed but no symbol found -> not present, try the parent. */
err = ECTF_NOTYPEDAT;
if (fp->ctf_objtidx_names && fp->ctf_funcidx_names)
goto try_parent;
@@ -990,7 +1079,8 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx);
if (symname != NULL)
- if ((symidx = ctf_lookup_symbol_idx (fp, symname)) == (unsigned long) -1)
+ if ((symidx = ctf_lookup_symbol_idx (fp, symname, try_parent, is_function))
+ == (unsigned long) -1)
goto try_parent;
if (fp->ctf_sxlate[symidx] == -1u)
@@ -1002,11 +1092,16 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
goto try_parent;
return type;
+
try_parent:
+ if (!try_parent)
+ return ctf_set_errno (fp, err);
+
if (fp->ctf_parent)
{
ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx,
- symname);
+ symname, try_parent,
+ is_function);
if (ret == CTF_ERR)
ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
return ret;
@@ -1020,7 +1115,7 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
ctf_id_t
ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
{
- return ctf_lookup_by_sym_or_name (fp, symidx, NULL);
+ return ctf_lookup_by_sym_or_name (fp, symidx, NULL, 1, -1);
}
/* Given a symbol name, return the type of the function or data object described
@@ -1028,7 +1123,7 @@ ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
ctf_id_t
ctf_lookup_by_symbol_name (ctf_dict_t *fp, const char *symname)
{
- return ctf_lookup_by_sym_or_name (fp, 0, symname);
+ return ctf_lookup_by_sym_or_name (fp, 0, symname, 1, -1);
}
/* Given a symbol table index, return the info for the function described
@@ -670,13 +670,15 @@ upgrade_types (ctf_dict_t *fp, ctf_header_t *cth)
return 0;
}
-/* Initialize the type ID translation table with the byte offset of each type,
+/* Populate statically-defined types (those loaded from a saved buffer).
+
+ Initialize the type ID translation table with the byte offset of each type,
and initialize the hash tables of each named type. Upgrade the type table to
the latest supported representation in the process, if needed, and if this
recension of libctf supports upgrading. */
static int
-init_types (ctf_dict_t *fp, ctf_header_t *cth)
+init_static_types (ctf_dict_t *fp, ctf_header_t *cth)
{
const ctf_type_t *tbuf;
const ctf_type_t *tend;
@@ -694,8 +696,6 @@ init_types (ctf_dict_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;
@@ -770,9 +770,16 @@ init_types (ctf_dict_t *fp, ctf_header_t *cth)
ctf_hash_eq_string, NULL, NULL)) == NULL)
return ENOMEM;
+ /* The ptrtab and txlate can be appropriately sized for precisely this set
+ of types: the txlate because it is only used to look up static types,
+ so dynamic types added later will never go through it, and the ptrtab
+ because later-added types will call grow_ptrtab() automatically, as
+ needed. */
+
fp->ctf_txlate = malloc (sizeof (uint32_t) * (typemax + 1));
fp->ctf_ptrtab_len = typemax + 1;
fp->ctf_ptrtab = malloc (sizeof (uint32_t) * fp->ctf_ptrtab_len);
+ fp->ctf_stypes = typemax;
if (fp->ctf_txlate == NULL || fp->ctf_ptrtab == NULL)
return ENOMEM; /* Memory allocation failed. */
@@ -1283,7 +1290,7 @@ ctf_dict_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,
- 0, errp);
+ errp);
}
/* Open a CTF file, mocking up a suitable ctf_sect and overriding the external
@@ -1293,8 +1300,7 @@ ctf_dict_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 writable,
- int *errp)
+ ctf_dynhash_t *syn_strtab, int *errp)
{
ctf_sect_t skeleton;
@@ -1332,7 +1338,7 @@ ctf_dict_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size,
}
return ctf_bufopen_internal (ctfsectp, symsectp, strsectp, syn_strtab,
- writable, errp);
+ errp);
}
/* Decode the specified CTF buffer and optional symbol table, and create a new
@@ -1344,7 +1350,7 @@ ctf_dict_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, 0, errp);
+ return ctf_bufopen_internal (ctfsect, symsect, strsect, NULL, errp);
}
/* Like ctf_bufopen, but overriding the external strtab with a synthetic one. */
@@ -1352,7 +1358,7 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
ctf_dict_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 writable, int *errp)
+ int *errp)
{
const ctf_preamble_t *pp;
size_t hdrsz = sizeof (ctf_header_t);
@@ -1441,9 +1447,6 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
memset (fp, 0, sizeof (ctf_dict_t));
- if (writable)
- fp->ctf_flags |= LCTF_RDWR;
-
if ((fp->ctf_header = malloc (sizeof (struct ctf_header))) == NULL)
{
free (fp);
@@ -1526,7 +1529,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
section's buffer pointer into ctf_buf, below. */
/* Note: if this is a v1 buffer, it will be reallocated and expanded by
- init_types(). */
+ init_static_types(). */
if (hp->cth_flags & CTF_F_COMPRESS)
{
@@ -1607,7 +1610,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
proceed with initializing the ctf_dict_t we allocated above.
Nothing that depends on buf or base should be set directly in this function
- before the init_types() call, because it may be reallocated during
+ before the init_static_types() call, because it may be reallocated during
transparent upgrade if this recension of libctf is so configured: see
ctf_set_base(). */
@@ -1660,6 +1663,26 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
}
fp->ctf_syn_ext_strtab = syn_strtab;
+ /* Dynamic state, for dynamic addition to this dict after loading. */
+
+ fp->ctf_dthash = ctf_dynhash_create (ctf_hash_integer, ctf_hash_eq_integer,
+ NULL, NULL);
+ fp->ctf_dvhash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
+ NULL, NULL);
+ fp->ctf_snapshots = 1;
+
+ fp->ctf_objthash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
+ free, NULL);
+ fp->ctf_funchash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
+ free, NULL);
+
+ if (!fp->ctf_dthash || !fp->ctf_dvhash || !fp->ctf_snapshots ||
+ !fp->ctf_objthash || !fp->ctf_funchash)
+ {
+ err = ENOMEM;
+ goto bad;
+ }
+
if (foreign_endian &&
(err = ctf_flip (fp, hp, fp->ctf_buf, 0)) != 0)
{
@@ -1673,15 +1696,7 @@ 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 dicts: 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)
+ if ((err = init_static_types (fp, hp)) != 0)
goto bad;
/* Allocate and initialize the symtab translation table, pointed to by
@@ -1800,7 +1815,8 @@ ctf_dict_close (ctf_dict_t *fp)
}
ctf_dynhash_destroy (fp->ctf_dvhash);
- ctf_dynhash_destroy (fp->ctf_symhash);
+ ctf_dynhash_destroy (fp->ctf_symhash_func);
+ ctf_dynhash_destroy (fp->ctf_symhash_objt);
free (fp->ctf_funcidx_sxlate);
free (fp->ctf_objtidx_sxlate);
ctf_dynhash_destroy (fp->ctf_objthash);
@@ -945,7 +945,12 @@ ctf_sort_var (const void *one_, const void *two_, void *arg_)
code simple: ctf_simple_open_internal() will return a new ctf_dict_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_dict_t's, and then free the old. */
+ old and new ctf_dict_t's, and then free the old.
+
+ We do not currently support serializing a dict that has already been
+ serialized in the past: but all the tables support it except for the types
+ table. */
+
int
ctf_serialize (ctf_dict_t *fp)
{
@@ -956,6 +961,7 @@ ctf_serialize (ctf_dict_t *fp)
ctf_strs_writable_t strtab;
int err;
int num_missed_str_refs;
+ int sym_functions = 0;
unsigned char *t;
unsigned long i;
@@ -967,7 +973,11 @@ ctf_serialize (ctf_dict_t *fp)
emit_symtypetab_state_t symstate;
memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
- if (!(fp->ctf_flags & LCTF_RDWR))
+ /* This isn't a very nice error code, but it's close enough: it's what you
+ get if you try to modify a type loaded out of a serialized dict, so
+ it makes at least a little sense that it's what you get if you try to
+ reserialize the dict again. */
+ if (fp->ctf_stypes > 0)
return (ctf_set_errno (fp, ECTF_RDONLY));
/* Update required? */
@@ -999,10 +1009,44 @@ ctf_serialize (ctf_dict_t *fp)
of the dynsym and dynstr these days. */
hdr.cth_flags = (CTF_F_NEWFUNCINFO | CTF_F_DYNSTR);
+ /* Propagate all symbols in the symtypetabs into the dynamic state, so that
+ we can put them back in the right order. Symbols already in the dynamic
+ state are left as they are. */
+ do
+ {
+ ctf_next_t *it = NULL;
+ const char *sym_name;
+ ctf_id_t sym;
+
+ while ((sym = ctf_symbol_next_static (fp, &it, &sym_name,
+ sym_functions)) != CTF_ERR)
+ if ((ctf_add_funcobjt_sym_forced (fp, sym_functions, sym_name, sym)) < 0)
+ if (ctf_errno (fp) != ECTF_DUPLICATE)
+ return -1; /* errno is set for us. */
+
+ if (ctf_errno (fp) != ECTF_NEXT_END)
+ return -1; /* errno is set for us. */
+ } while (sym_functions++ < 1);
+
+ /* Figure out how big the symtypetabs are now. */
+
if (ctf_symtypetab_sect_sizes (fp, &symstate, &hdr, &objt_size, &func_size,
&objtidx_size, &funcidx_size) < 0)
return -1; /* errno is set for us. */
+ /* Propagate all vars into the dynamic state, so we can put them back later.
+ Variables already in the dynamic state, likely due to repeated
+ serialization, are left unchanged. */
+
+ for (i = 0; i < fp->ctf_nvars; i++)
+ {
+ const char *name = ctf_strptr (fp, fp->ctf_vars[i].ctv_name);
+
+ if (name != NULL && !ctf_dvd_lookup (fp, name))
+ if (ctf_add_variable_forced (fp, name, fp->ctf_vars[i].ctv_type) < 0)
+ return -1; /* errno is set for us. */
+ }
+
for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs);
dvd != NULL; dvd = ctf_list_next (dvd), nvars++);
@@ -1101,7 +1145,7 @@ ctf_serialize (ctf_dict_t *fp)
if ((nfp = ctf_simple_open_internal ((char *) buf, buf_size, NULL, 0,
0, NULL, 0, fp->ctf_syn_ext_strtab,
- 1, &err)) == NULL)
+ &err)) == NULL)
{
free (buf);
return (ctf_set_errno (fp, err));
@@ -1131,6 +1175,7 @@ ctf_serialize (ctf_dict_t *fp)
nfp->ctf_ptrtab = fp->ctf_ptrtab;
nfp->ctf_pptrtab = fp->ctf_pptrtab;
nfp->ctf_typemax = fp->ctf_typemax;
+ nfp->ctf_stypes = fp->ctf_stypes;
nfp->ctf_dynsymidx = fp->ctf_dynsymidx;
nfp->ctf_dynsymmax = fp->ctf_dynsymmax;
nfp->ctf_ptrtab_len = fp->ctf_ptrtab_len;
@@ -492,6 +492,7 @@ ctf_id_t
ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
{
ctf_next_t *i = *it;
+ ctf_id_t id;
if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL))
return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
@@ -503,8 +504,7 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
i->cu.ctn_fp = fp;
i->ctn_iter_fun = (void (*) (void)) ctf_variable_next;
- if (fp->ctf_flags & LCTF_RDWR)
- i->u.ctn_dvd = ctf_list_next (&fp->ctf_dvdefs);
+ i->u.ctn_dvd = ctf_list_next (&fp->ctf_dvdefs);
*it = i;
}
@@ -514,27 +514,21 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
if (fp != i->cu.ctn_fp)
return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
- if (!(fp->ctf_flags & LCTF_RDWR))
+ if (i->ctn_n < fp->ctf_nvars)
{
- if (i->ctn_n >= fp->ctf_nvars)
- goto end_iter;
-
*name = ctf_strptr (fp, fp->ctf_vars[i->ctn_n].ctv_name);
return fp->ctf_vars[i->ctn_n++].ctv_type;
- }
- else
- {
- ctf_id_t id;
- if (i->u.ctn_dvd == NULL)
- goto end_iter;
-
- *name = i->u.ctn_dvd->dvd_name;
- id = i->u.ctn_dvd->dvd_type;
- i->u.ctn_dvd = ctf_list_next (i->u.ctn_dvd);
- return id;
}
+ if (i->u.ctn_dvd == NULL)
+ goto end_iter;
+
+ *name = i->u.ctn_dvd->dvd_name;
+ id = i->u.ctn_dvd->dvd_type;
+ i->u.ctn_dvd = ctf_list_next (i->u.ctn_dvd);
+ return id;
+
end_iter:
ctf_next_destroy (i);
*it = NULL;
new file mode 100644
@@ -0,0 +1,19 @@
+int an_int;
+char *a_char_ptr;
+typedef int (*a_typedef) (int main);
+struct struct_forward;
+enum enum_forward;
+union union_forward;
+typedef int an_array[50];
+struct a_struct { int foo; };
+union a_union { int bar; };
+enum an_enum { FOO };
+
+a_typedef a;
+struct struct_forward *x;
+union union_forward *y;
+enum enum_forward *z;
+struct a_struct *xx;
+union a_union *yy;
+enum an_enum *zz;
+an_array ar;
new file mode 100644
@@ -0,0 +1,147 @@
+/* Make sure you can add to ctf_open()ed CTF dicts, and that you
+ cannot make changes to existing types. */
+
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+ ctf_dict_t *fp;
+ ctf_archive_t *ctf;
+ ctf_id_t type, ptrtype;
+ ctf_arinfo_t ar = {0, 0, 0};
+ ctf_encoding_t en = { CTF_INT_SIGNED, 0, sizeof (int) };
+ unsigned char *ctf_written;
+ size_t size;
+ int err;
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
+ exit(1);
+ }
+
+ if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+ goto open_err;
+ if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
+ goto open_err;
+
+ /* Check that various modifications to already-written types
+ are prohibited. */
+
+ if (ctf_add_integer (fp, CTF_ADD_ROOT, "int", &en) == 0)
+ fprintf (stderr, "allowed to add integer existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to add integer in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_typedef (fp, CTF_ADD_ROOT, "a_typedef", 0) == 0)
+ fprintf (stderr, "allowed to add typedef existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to add typedef in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_struct (fp, CTF_ADD_ROOT, "a_struct") == 0)
+ fprintf (stderr, "allowed to add struct existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to add struct in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_union (fp, CTF_ADD_ROOT, "a_union") == 0)
+ fprintf (stderr, "allowed to add union existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to add union in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_enum (fp, CTF_ADD_ROOT, "an_enum") == 0)
+ fprintf (stderr, "allowed to add enum existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to add enum in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_struct (fp, CTF_ADD_ROOT, "struct_forward") == 0)
+ fprintf (stderr, "allowed to promote struct forward existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to promote struct forward in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_union (fp, CTF_ADD_ROOT, "union_forward") == 0)
+ fprintf (stderr, "allowed to promote union forward existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to promote union forward in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_enum (fp, CTF_ADD_ROOT, "enum_forward") == 0)
+ fprintf (stderr, "allowed to promote enum forward existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to promote enum forward in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if ((type = ctf_lookup_by_name (fp, "struct a_struct")) == CTF_ERR)
+ fprintf (stderr, "Lookup of struct a_struct failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_member (fp, type, "wombat", 0) == 0)
+ fprintf (stderr, "allowed to add member to struct existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to add member to struct in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if ((type = ctf_lookup_by_name (fp, "union a_union")) == CTF_ERR)
+ fprintf (stderr, "Lookup of union a_union failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_member (fp, type, "wombat", 0) == 0)
+ fprintf (stderr, "allowed to add member to union existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to add member to union in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if ((type = ctf_lookup_by_name (fp, "enum an_enum")) == CTF_ERR)
+ fprintf (stderr, "Lookup of enum an_enum failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_add_enumerator (fp, type, "wombat", 0) == 0)
+ fprintf (stderr, "allowed to add enumerator to enum existing in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to add enumerator to enum in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if ((type = ctf_lookup_by_name (fp, "an_array")) == CTF_ERR)
+ fprintf (stderr, "Lookup of an_array failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if ((type = ctf_type_reference (fp, type)) == CTF_ERR)
+ fprintf (stderr, "Lookup of type reffed by an_array failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_set_array (fp, type, &ar) == 0)
+ fprintf (stderr, "allowed to set array in readonly portion\n");
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s attempting to set array in readonly portion\n", ctf_errmsg (ctf_errno (fp)));
+
+ if ((ctf_written = ctf_write_mem (fp, &size, 4096)) != NULL)
+ fprintf (stderr, "Writeout unexpectedly succeeded: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_errno (fp) != ECTF_RDONLY)
+ fprintf (stderr, "unexpected error %s trying to write out previously serialized dict\n", ctf_errmsg (ctf_errno (fp)));
+
+ /* Finally, make sure we can add new types, and look them up again. */
+
+ if ((type = ctf_lookup_by_name (fp, "struct a_struct")) == CTF_ERR)
+ fprintf (stderr, "Lookup of struct a_struct failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if ((ptrtype = ctf_add_pointer (fp, CTF_ADD_ROOT, type)) == CTF_ERR)
+ fprintf (stderr, "Cannot add pointer to ctf_opened dict: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_type_reference (fp, ptrtype) == CTF_ERR)
+ fprintf (stderr, "Lookup of pointer preserved across writeout failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+
+ if (ctf_type_reference (fp, ptrtype) != type)
+ fprintf (stderr, "Look up of newly-added type in serialized dict yields ID %lx, expected %lx\n", ctf_type_reference (fp, ptrtype), type);
+
+ printf ("All done.\n");
+ return 0;
+
+ open_err:
+ fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err));
+ return 1;
+}
new file mode 100644
@@ -0,0 +1,3 @@
+# source: add-to-opened-ctf.c
+# lookup: add-to-opened.c
+All done.