/* CTF file creation.
- Copyright (C) 2019 Free Software Foundation, Inc.
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
This file is part of libctf.
if (strtab.cts_strs == NULL)
{
- ctf_free (buf);
+ free (buf);
return (ctf_set_errno (fp, EAGAIN));
}
if ((newbuf = ctf_realloc (fp, buf, buf_size + strtab.cts_len)) == NULL)
{
- ctf_free (buf);
- ctf_free (strtab.cts_strs);
+ free (buf);
+ free (strtab.cts_strs);
return (ctf_set_errno (fp, EAGAIN));
}
buf = newbuf;
hdrp = (ctf_header_t *) buf;
hdrp->cth_strlen = strtab.cts_len;
buf_size += hdrp->cth_strlen;
- ctf_free (strtab.cts_strs);
+ free (strtab.cts_strs);
/* Finally, we are ready to ctf_simple_open() the new container. If this
is successful, we then switch nfp and fp and free the old container. */
0, NULL, 0, fp->ctf_syn_ext_strtab,
1, &err)) == NULL)
{
- ctf_free (buf);
+ free (buf);
return (ctf_set_errno (fp, err));
}
nfp->ctf_dvhash = fp->ctf_dvhash;
nfp->ctf_dvdefs = fp->ctf_dvdefs;
nfp->ctf_dtoldid = fp->ctf_dtoldid;
+ nfp->ctf_add_processing = fp->ctf_add_processing;
nfp->ctf_snapshots = fp->ctf_snapshots + 1;
nfp->ctf_specific = fp->ctf_specific;
nfp->ctf_ptrtab = fp->ctf_ptrtab;
fp->ctf_str_atoms = NULL;
fp->ctf_prov_strtab = NULL;
memset (&fp->ctf_dtdefs, 0, sizeof (ctf_list_t));
+ fp->ctf_add_processing = NULL;
fp->ctf_ptrtab = NULL;
fp->ctf_link_inputs = NULL;
fp->ctf_link_outputs = NULL;
dmd != NULL; dmd = nmd)
{
if (dmd->dmd_name != NULL)
- ctf_free (dmd->dmd_name);
+ free (dmd->dmd_name);
nmd = ctf_list_next (dmd);
- ctf_free (dmd);
+ free (dmd);
}
break;
case CTF_K_FUNCTION:
- ctf_free (dtd->dtd_u.dtu_argv);
+ free (dtd->dtd_u.dtu_argv);
break;
}
}
ctf_list_delete (&fp->ctf_dtdefs, dtd);
- ctf_free (dtd);
+ free (dtd);
}
ctf_dtdef_t *
ctf_dvd_delete (ctf_file_t *fp, ctf_dvdef_t *dvd)
{
ctf_dynhash_remove (fp->ctf_dvhash, dvd->dvd_name);
- ctf_free (dvd->dvd_name);
+ free (dvd->dvd_name);
ctf_list_delete (&fp->ctf_dvdefs, dvd);
- ctf_free (dvd);
+ free (dvd);
}
ctf_dvdef_t *
if (ctf_grow_ptrtab (fp) < 0)
return CTF_ERR; /* errno is set for us. */
- if ((dtd = ctf_alloc (sizeof (ctf_dtdef_t))) == NULL)
+ if ((dtd = malloc (sizeof (ctf_dtdef_t))) == NULL)
return (ctf_set_errno (fp, EAGAIN));
type = ++fp->ctf_typemax;
if (dtd->dtd_data.ctt_name == 0 && name != NULL && name[0] != '\0')
{
- ctf_free (dtd);
+ free (dtd);
return (ctf_set_errno (fp, EAGAIN));
}
if (ctf_dtd_insert (fp, dtd, kind) < 0)
{
- ctf_free (dtd);
+ free (dtd);
return CTF_ERR; /* errno is set for us. */
}
fp->ctf_flags |= LCTF_DIRTY;
if (vlen > CTF_MAX_VLEN)
return (ctf_set_errno (fp, EOVERFLOW));
- if (vlen != 0 && (vdat = ctf_alloc (sizeof (ctf_id_t) * vlen)) == NULL)
+ if (vlen != 0 && (vdat = malloc (sizeof (ctf_id_t) * vlen)) == NULL)
return (ctf_set_errno (fp, EAGAIN));
if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_FUNCTION,
&dtd)) == CTF_ERR)
{
- ctf_free (vdat);
+ free (vdat);
return CTF_ERR; /* errno is set for us. */
}
return (ctf_set_errno (fp, ECTF_DUPLICATE));
}
- if ((dmd = ctf_alloc (sizeof (ctf_dmdef_t))) == NULL)
+ if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL)
return (ctf_set_errno (fp, EAGAIN));
- if ((s = ctf_strdup (name)) == NULL)
+ if ((s = strdup (name)) == NULL)
{
- ctf_free (dmd);
+ free (dmd);
return (ctf_set_errno (fp, EAGAIN));
}
(malign = ctf_type_align (fp, type)) < 0)
return -1; /* errno is set for us. */
- if ((dmd = ctf_alloc (sizeof (ctf_dmdef_t))) == NULL)
+ if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL)
return (ctf_set_errno (fp, EAGAIN));
- if (name != NULL && (s = ctf_strdup (name)) == NULL)
+ if (name != NULL && (s = strdup (name)) == NULL)
{
- ctf_free (dmd);
+ free (dmd);
return (ctf_set_errno (fp, EAGAIN));
}
&& (ctf_errno (fp) == ECTF_NONREPRESENTABLE))
return -1;
- if ((dvd = ctf_alloc (sizeof (ctf_dvdef_t))) == NULL)
+ if ((dvd = malloc (sizeof (ctf_dvdef_t))) == NULL)
return (ctf_set_errno (fp, EAGAIN));
- if (name != NULL && (dvd->dvd_name = ctf_strdup (name)) == NULL)
+ if (name != NULL && (dvd->dvd_name = strdup (name)) == NULL)
{
- ctf_free (dvd);
+ free (dvd);
return (ctf_set_errno (fp, EAGAIN));
}
dvd->dvd_type = ref;
if (ctf_dvd_insert (fp, dvd) < 0)
{
- ctf_free (dvd);
+ free (dvd->dvd_name);
+ free (dvd);
return -1; /* errno is set for us. */
}
if (ctf_enum_value (ctb->ctb_file, ctb->ctb_type, name, &bvalue) < 0)
{
- ctf_dprintf ("Conflict due to member %s iteration error.\n", name);
+ ctf_dprintf ("Conflict due to member %s iteration error: %s.\n", name,
+ ctf_errmsg (ctf_errno (ctb->ctb_file)));
return 1;
}
if (value != bvalue)
if (ctf_member_info (ctb->ctb_file, ctb->ctb_type, name, &ctm) < 0)
{
- ctf_dprintf ("Conflict due to member %s iteration error.\n", name);
+ ctf_dprintf ("Conflict due to member %s iteration error: %s.\n", name,
+ ctf_errmsg (ctf_errno (ctb->ctb_file)));
return 1;
}
if (ctm.ctm_offset != offset)
ctf_dmdef_t *dmd;
char *s = NULL;
- if ((dmd = ctf_alloc (sizeof (ctf_dmdef_t))) == NULL)
+ if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL)
return (ctf_set_errno (ctb->ctb_file, EAGAIN));
- if (name != NULL && (s = ctf_strdup (name)) == NULL)
+ if (name != NULL && (s = strdup (name)) == NULL)
{
- ctf_free (dmd);
+ free (dmd);
return (ctf_set_errno (ctb->ctb_file, EAGAIN));
}
following the source type's links and embedded member types. If the
destination container already contains a named type which has the same
attributes, then we succeed and return this type but no changes occur. */
-ctf_id_t
-ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
+static ctf_id_t
+ctf_add_type_internal (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type,
+ ctf_file_t *proc_tracking_fp)
{
ctf_id_t dst_type = CTF_ERR;
uint32_t dst_kind = CTF_K_UNKNOWN;
+ ctf_file_t *tmp_fp = dst_fp;
ctf_id_t tmp;
const char *name;
ctf_encoding_t src_en, dst_en;
ctf_arinfo_t src_ar, dst_ar;
- ctf_dtdef_t *dtd;
ctf_funcinfo_t ctc;
ctf_id_t orig_src_type = src_type;
flag = LCTF_INFO_ISROOT (src_fp, src_tp->ctt_info);
vlen = LCTF_INFO_VLEN (src_fp, src_tp->ctt_info);
+ /* If this is a type we are currently in the middle of adding, hand it
+ straight back. (This lets us handle self-referential structures without
+ considering forwards and empty structures the same as their completed
+ forms.) */
+
+ tmp = ctf_type_mapping (src_fp, src_type, &tmp_fp);
+
+ if (tmp != 0)
+ {
+ if (ctf_dynhash_lookup (proc_tracking_fp->ctf_add_processing,
+ (void *) (uintptr_t) src_type))
+ return tmp;
+
+ /* If this type has already been added from this container, and is the same
+ kind and (if a struct or union) has the same number of members, hand it
+ straight back. */
+
+ if ((ctf_type_kind_unsliced (tmp_fp, tmp) == (int) kind)
+ && (kind == CTF_K_STRUCT || kind == CTF_K_UNION
+ || kind == CTF_K_ENUM))
+ {
+ if ((dst_tp = ctf_lookup_by_id (&tmp_fp, dst_type)) != NULL)
+ if (vlen == LCTF_INFO_VLEN (tmp_fp, dst_tp->ctt_info))
+ return tmp;
+ }
+ }
+
forward_kind = kind;
if (kind == CTF_K_FORWARD)
forward_kind = src_tp->ctt_type;
if ((dst_tp = ctf_lookup_by_id (&fp, dst_type)) == NULL)
return CTF_ERR;
+ if (ctf_type_encoding (dst_fp, dst_type, &dst_en) != 0)
+ return CTF_ERR; /* errno set for us. */
+
if (LCTF_INFO_ISROOT (fp, dst_tp->ctt_info) & CTF_ADD_ROOT)
{
/* The type that we found in the hash is also root-visible. If
even if there is no conflict: we must check the contained type
too. */
- if (ctf_type_encoding (dst_fp, dst_type, &dst_en) != 0)
- return CTF_ERR; /* errno set for us. */
-
if (memcmp (&src_en, &dst_en, sizeof (ctf_encoding_t)) == 0)
{
if (kind != CTF_K_SLICE)
}
else
{
- /* We found a non-root-visible type in the hash. We reset
- dst_type to ensure that we continue to look for a possible
- conflict in the pending list. */
-
- dst_type = CTF_ERR;
- }
- }
- }
-
- /* If the non-empty name was not found in the appropriate hash, search
- the list of pending dynamic definitions that are not yet committed.
- If a matching name and kind are found, assume this is the type that
- we are looking for. This is necessary to permit ctf_add_type() to
- operate recursively on entities such as a struct that contains a
- pointer member that refers to the same struct type. */
-
- if (dst_type == CTF_ERR && name[0] != '\0')
- {
- for (dtd = ctf_list_prev (&dst_fp->ctf_dtdefs); dtd != NULL
- && 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_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? */
- int match; /* Do the encodings match? */
-
- if (kind != CTF_K_INTEGER && kind != CTF_K_FLOAT && kind != CTF_K_SLICE)
- {
- ctf_add_type_mapping (src_fp, src_type, dst_fp, dtd->dtd_type);
- return dtd->dtd_type;
- }
-
- sroot = (flag & CTF_ADD_ROOT);
- droot = (LCTF_INFO_ISROOT (dst_fp,
- dtd->dtd_data.
- ctt_info) & CTF_ADD_ROOT);
-
- match = (memcmp (&src_en, &dtd->dtd_u.dtu_enc,
- sizeof (ctf_encoding_t)) == 0);
-
- /* If the types share the same encoding then return the id of the
- first unless one type is root-visible and the other is not; in
- that case the new type must get a new id if a match is never
- found. Note: slices are not certain to match even if there is
- no conflict: we must check the contained type too. */
+ /* We found a non-root-visible type in the hash. If its encoding
+ is the same, we can reuse it, unless it is a slice. */
- if (match && sroot == droot)
+ if (memcmp (&src_en, &dst_en, sizeof (ctf_encoding_t)) == 0)
{
if (kind != CTF_K_SLICE)
{
- ctf_add_type_mapping (src_fp, src_type, dst_fp, dtd->dtd_type);
- return dtd->dtd_type;
+ ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
+ return dst_type;
}
}
- else if (!match && sroot && droot)
- {
- return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
- }
}
}
}
dst.ctb_type = dst_type;
dst.ctb_dtd = NULL;
- /* Now perform kind-specific processing. If dst_type is CTF_ERR, then
- we add a new type with the same properties as src_type to dst_fp.
- If dst_type is not CTF_ERR, then we verify that dst_type has the
- same attributes as src_type. We recurse for embedded references. */
+ /* Now perform kind-specific processing. If dst_type is CTF_ERR, then we add
+ a new type with the same properties as src_type to dst_fp. If dst_type is
+ not CTF_ERR, then we verify that dst_type has the same attributes as
+ src_type. We recurse for embedded references. Before we start, we note
+ that we are processing this type, to prevent infinite recursion: we do not
+ re-process any type that appears in this list. The list is emptied
+ wholesale at the end of processing everything in this recursive stack. */
+
+ if (ctf_dynhash_insert (proc_tracking_fp->ctf_add_processing,
+ (void *) (uintptr_t) src_type, (void *) 1) < 0)
+ return ctf_set_errno (dst_fp, ENOMEM);
+
switch (kind)
{
case CTF_K_INTEGER:
/* We have checked for conflicting encodings: now try to add the
contained type. */
src_type = ctf_type_reference (src_fp, src_type);
- dst_type = ctf_add_type (dst_fp, src_fp, src_type);
+ src_type = ctf_add_type_internal (dst_fp, src_fp, src_type,
+ proc_tracking_fp);
if (src_type == CTF_ERR)
return CTF_ERR; /* errno is set for us. */
case CTF_K_CONST:
case CTF_K_RESTRICT:
src_type = ctf_type_reference (src_fp, src_type);
- src_type = ctf_add_type (dst_fp, src_fp, src_type);
+ src_type = ctf_add_type_internal (dst_fp, src_fp, src_type,
+ proc_tracking_fp);
if (src_type == CTF_ERR)
return CTF_ERR; /* errno is set for us. */
return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
src_ar.ctr_contents =
- ctf_add_type (dst_fp, src_fp, src_ar.ctr_contents);
- src_ar.ctr_index = ctf_add_type (dst_fp, src_fp, src_ar.ctr_index);
+ ctf_add_type_internal (dst_fp, src_fp, src_ar.ctr_contents,
+ proc_tracking_fp);
+ src_ar.ctr_index = ctf_add_type_internal (dst_fp, src_fp,
+ src_ar.ctr_index,
+ proc_tracking_fp);
src_ar.ctr_nelems = src_ar.ctr_nelems;
if (src_ar.ctr_contents == CTF_ERR || src_ar.ctr_index == CTF_ERR)
break;
case CTF_K_FUNCTION:
- ctc.ctc_return = ctf_add_type (dst_fp, src_fp, src_tp->ctt_type);
+ ctc.ctc_return = ctf_add_type_internal (dst_fp, src_fp,
+ src_tp->ctt_type,
+ proc_tracking_fp);
ctc.ctc_argc = 0;
ctc.ctc_flags = 0;
int errs = 0;
size_t size;
ssize_t ssize;
+ ctf_dtdef_t *dtd;
/* Technically to match a struct or union we need to check both
ways (src members vs. dst, dst members vs. src) but we make
This optimization can be defeated for unions, but is so
pathological as to render it irrelevant for our purposes. */
- if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD)
+ if (dst_type != CTF_ERR && kind != CTF_K_FORWARD
+ && dst_kind != CTF_K_FORWARD)
{
if (ctf_type_size (src_fp, src_type) !=
ctf_type_size (dst_fp, dst_type))
dst.ctb_type = dst_type;
dst.ctb_dtd = dtd;
+ /* Pre-emptively add this struct to the type mapping so that
+ structures that refer to themselves work. */
+ ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
+
if (ctf_member_iter (src_fp, src_type, membadd, &dst) != 0)
errs++; /* Increment errs and fail at bottom of case. */
for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
dmd != NULL; dmd = ctf_list_next (dmd))
{
- if ((dmd->dmd_type = ctf_add_type (dst_fp, src_fp,
- dmd->dmd_type)) == CTF_ERR)
+ ctf_file_t *dst = dst_fp;
+ ctf_id_t memb_type;
+
+ memb_type = ctf_type_mapping (src_fp, dmd->dmd_type, &dst);
+ if (memb_type == 0)
{
- if (ctf_errno (dst_fp) != ECTF_NONREPRESENTABLE)
- errs++;
+ if ((dmd->dmd_type =
+ ctf_add_type_internal (dst_fp, src_fp, dmd->dmd_type,
+ proc_tracking_fp)) == CTF_ERR)
+ {
+ if (ctf_errno (dst_fp) != ECTF_NONREPRESENTABLE)
+ errs++;
+ }
}
+ else
+ dmd->dmd_type = memb_type;
}
if (errs)
}
case CTF_K_ENUM:
- if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD)
+ if (dst_type != CTF_ERR && kind != CTF_K_FORWARD
+ && dst_kind != CTF_K_FORWARD)
{
if (ctf_enum_iter (src_fp, src_type, enumcmp, &dst)
|| ctf_enum_iter (dst_fp, dst_type, enumcmp, &src))
case CTF_K_TYPEDEF:
src_type = ctf_type_reference (src_fp, src_type);
- src_type = ctf_add_type (dst_fp, src_fp, src_type);
+ src_type = ctf_add_type_internal (dst_fp, src_fp, src_type,
+ proc_tracking_fp);
if (src_type == CTF_ERR)
return CTF_ERR; /* errno is set for us. */
equivalent. */
if (dst_type == CTF_ERR)
- {
dst_type = ctf_add_typedef (dst_fp, flag, name, src_type);
- }
+
break;
default:
return dst_type;
}
+ctf_id_t
+ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
+{
+ ctf_id_t id;
+
+ if (!src_fp->ctf_add_processing)
+ src_fp->ctf_add_processing = ctf_dynhash_create (ctf_hash_integer,
+ ctf_hash_eq_integer,
+ NULL, NULL);
+
+ /* We store the hash on the source, because it contains only source type IDs:
+ but callers will invariably expect errors to appear on the dest. */
+ if (!src_fp->ctf_add_processing)
+ return (ctf_set_errno (dst_fp, ENOMEM));
+
+ id = ctf_add_type_internal (dst_fp, src_fp, src_type, src_fp);
+ ctf_dynhash_empty (src_fp->ctf_add_processing);
+
+ return id;
+}
+
/* Write the compressed CTF data stream to the specified gzFile descriptor. */
int
ctf_gzwrite (ctf_file_t *fp, gzFile fd)
hp->cth_flags |= CTF_F_COMPRESS;
compress_len = compressBound (fp->ctf_size);
- if ((buf = ctf_alloc (compress_len)) == NULL)
+ if ((buf = malloc (compress_len)) == NULL)
return (ctf_set_errno (fp, ECTF_ZALLOC));
if ((rc = compress (buf, (uLongf *) &compress_len,
}
ret:
- ctf_free (buf);
+ free (buf);
return err;
}
{
ctf_dprintf ("zlib deflate err: %s\n", zError (rc));
ctf_set_errno (fp, ECTF_COMPRESS);
- ctf_free (buf);
+ free (buf);
return NULL;
}
*size += compress_len;