/* CTF dict creation.
- Copyright (C) 2019-2021 Free Software Foundation, Inc.
+ Copyright (C) 2019-2022 Free Software Foundation, Inc.
This file is part of libctf.
return 0;
}
-/* Delete data symbols that have been assigned names from the variable section.
- Must be called from within ctf_serialize, because that is the only place
- you can safely delete variables without messing up ctf_rollback. */
+/* Delete symbols that have been assigned names from the variable section. Must
+ be called from within ctf_serialize, because that is the only place you can
+ safely delete variables without messing up ctf_rollback. */
static int
-symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp)
+symtypetab_delete_nonstatics (ctf_dict_t *fp, ctf_dict_t *symfp)
{
ctf_dvdef_t *dvd, *nvd;
ctf_id_t type;
{
nvd = ctf_list_next (dvd);
- if (((type = (ctf_id_t) (uintptr_t)
- ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
+ if ((((type = (ctf_id_t) (uintptr_t)
+ ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
+ || (type = (ctf_id_t) (uintptr_t)
+ ctf_dynhash_lookup (fp->ctf_funchash, dvd->dvd_name)) > 0)
&& ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL
&& type == dvd->dvd_type)
ctf_dvd_delete (fp, dvd);
/* If we are filtering symbols out, those symbols that the linker has not
reported have now been removed from the ctf_objthash and ctf_funchash.
- Delete entries from the variable section that duplicate newly-added data
- symbols. There's no need to migrate new ones in, because the compiler
- always emits both a variable and a data symbol simultaneously, and
- filtering only happens at final link time. */
+ Delete entries from the variable section that duplicate newly-added
+ symbols. There's no need to migrate new ones in: we do that (if necessary)
+ in ctf_link_deduplicating_variables. */
if (s->filter_syms && s->symfp->ctf_dynsyms &&
- symtypetab_delete_nonstatic_vars (fp, s->symfp) < 0)
+ symtypetab_delete_nonstatics (fp, s->symfp) < 0)
return -1;
return 0;
/* Type section. */
-static unsigned char *
-ctf_copy_smembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
-{
- ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
- ctf_member_t ctm;
-
- for (; dmd != NULL; dmd = ctf_list_next (dmd))
- {
- ctf_member_t *copied;
-
- ctm.ctm_name = 0;
- ctm.ctm_type = (uint32_t) dmd->dmd_type;
- ctm.ctm_offset = (uint32_t) dmd->dmd_offset;
-
- memcpy (t, &ctm, sizeof (ctm));
- copied = (ctf_member_t *) t;
- if (dmd->dmd_name)
- ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctm_name);
-
- t += sizeof (ctm);
- }
-
- return t;
-}
-
-static unsigned char *
-ctf_copy_lmembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
-{
- ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
- ctf_lmember_t ctlm;
-
- for (; dmd != NULL; dmd = ctf_list_next (dmd))
- {
- ctf_lmember_t *copied;
-
- ctlm.ctlm_name = 0;
- ctlm.ctlm_type = (uint32_t) dmd->dmd_type;
- ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset);
- ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset);
-
- memcpy (t, &ctlm, sizeof (ctlm));
- copied = (ctf_lmember_t *) t;
- if (dmd->dmd_name)
- ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctlm_name);
-
- t += sizeof (ctlm);
- }
-
- return t;
-}
-
-static unsigned char *
-ctf_copy_emembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
-{
- ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
- ctf_enum_t cte;
-
- for (; dmd != NULL; dmd = ctf_list_next (dmd))
- {
- ctf_enum_t *copied;
-
- cte.cte_value = dmd->dmd_value;
- memcpy (t, &cte, sizeof (cte));
- copied = (ctf_enum_t *) t;
- ctf_str_add_ref (fp, dmd->dmd_name, &copied->cte_name);
- t += sizeof (cte);
- }
-
- return t;
-}
-
/* Iterate through the dynamic type definition list and compute the
size of the CTF type section. */
{
uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+ size_t type_ctt_size = dtd->dtd_data.ctt_size;
+
+ /* Shrink ctf_type_t-using types from a ctf_type_t to a ctf_stype_t
+ if possible. */
+
+ if (kind == CTF_K_STRUCT || kind == CTF_K_UNION)
+ {
+ size_t lsize = CTF_TYPE_LSIZE (&dtd->dtd_data);
+
+ if (lsize <= CTF_MAX_SIZE)
+ type_ctt_size = lsize;
+ }
- if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+ if (type_ctt_size != CTF_LSIZE_SENT)
type_size += sizeof (ctf_stype_t);
else
type_size += sizeof (ctf_type_t);
break;
case CTF_K_STRUCT:
case CTF_K_UNION:
- if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+ if (type_ctt_size < CTF_LSTRUCT_THRESH)
type_size += sizeof (ctf_member_t) * vlen;
else
type_size += sizeof (ctf_lmember_t) * vlen;
{
uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
-
+ size_t type_ctt_size = dtd->dtd_data.ctt_size;
size_t len;
ctf_stype_t *copied;
const char *name;
+ size_t i;
+
+ /* Shrink ctf_type_t-using types from a ctf_type_t to a ctf_stype_t
+ if possible. */
- if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+ if (kind == CTF_K_STRUCT || kind == CTF_K_UNION)
+ {
+ size_t lsize = CTF_TYPE_LSIZE (&dtd->dtd_data);
+
+ if (lsize <= CTF_MAX_SIZE)
+ type_ctt_size = lsize;
+ }
+
+ if (type_ctt_size != CTF_LSIZE_SENT)
len = sizeof (ctf_stype_t);
else
len = sizeof (ctf_type_t);
ctf_str_add_ref (fp, name, &copied->ctt_name);
ctf_str_add_ref (fp, name, &dtd->dtd_data.ctt_name);
}
+ copied->ctt_size = type_ctt_size;
t += len;
switch (kind)
break;
case CTF_K_FUNCTION:
- memcpy (t, dtd->dtd_vlen, sizeof (uint32_t) * (vlen + (vlen & 1)));
+ /* Functions with no args also have no vlen. */
+ if (dtd->dtd_vlen)
+ memcpy (t, dtd->dtd_vlen, sizeof (uint32_t) * (vlen + (vlen & 1)));
t += sizeof (uint32_t) * (vlen + (vlen & 1));
break;
+ /* These need to be copied across element by element, depending on
+ their ctt_size. */
case CTF_K_STRUCT:
case CTF_K_UNION:
- if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
- t = ctf_copy_smembers (fp, dtd, t);
+ {
+ ctf_lmember_t *dtd_vlen = (ctf_lmember_t *) dtd->dtd_vlen;
+ ctf_lmember_t *t_lvlen = (ctf_lmember_t *) t;
+ ctf_member_t *t_vlen = (ctf_member_t *) t;
+
+ for (i = 0; i < vlen; i++)
+ {
+ const char *name = ctf_strraw (fp, dtd_vlen[i].ctlm_name);
+
+ ctf_str_add_ref (fp, name, &dtd_vlen[i].ctlm_name);
+
+ if (type_ctt_size < CTF_LSTRUCT_THRESH)
+ {
+ t_vlen[i].ctm_name = dtd_vlen[i].ctlm_name;
+ t_vlen[i].ctm_type = dtd_vlen[i].ctlm_type;
+ t_vlen[i].ctm_offset = CTF_LMEM_OFFSET (&dtd_vlen[i]);
+ ctf_str_add_ref (fp, name, &t_vlen[i].ctm_name);
+ }
+ else
+ {
+ t_lvlen[i] = dtd_vlen[i];
+ ctf_str_add_ref (fp, name, &t_lvlen[i].ctlm_name);
+ }
+ }
+ }
+
+ if (type_ctt_size < CTF_LSTRUCT_THRESH)
+ t += sizeof (ctf_member_t) * vlen;
else
- t = ctf_copy_lmembers (fp, dtd, t);
+ t += sizeof (ctf_lmember_t) * vlen;
break;
case CTF_K_ENUM:
- t = ctf_copy_emembers (fp, dtd, t);
- break;
+ {
+ ctf_enum_t *dtd_vlen = (struct ctf_enum *) dtd->dtd_vlen;
+ ctf_enum_t *t_vlen = (struct ctf_enum *) t;
+
+ memcpy (t, dtd->dtd_vlen, sizeof (struct ctf_enum) * vlen);
+ for (i = 0; i < vlen; i++)
+ {
+ const char *name = ctf_strraw (fp, dtd_vlen[i].cte_name);
+
+ ctf_str_add_ref (fp, name, &t_vlen[i].cte_name);
+ ctf_str_add_ref (fp, name, &dtd_vlen[i].cte_name);
+ }
+ t += sizeof (struct ctf_enum) * vlen;
+
+ break;
+ }
}
}
/* File writing. */
-/* Write the compressed CTF data stream to the specified gzFile descriptor. */
+/* Write the compressed CTF data stream to the specified gzFile descriptor. The
+ whole stream is compressed, and cannot be read by CTF opening functions in
+ this library until it is decompressed. (The functions below this one leave
+ the header uncompressed, and the CTF opening functions work on them without
+ manual decompression.)
+
+ No support for (testing-only) endian-flipping. */
int
ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
{
return 0;
}
-/* Compress the specified CTF data stream and write it to the specified file
- descriptor. */
-int
-ctf_compress_write (ctf_dict_t *fp, int fd)
-{
- unsigned char *buf;
- unsigned char *bp;
- ctf_header_t h;
- ctf_header_t *hp = &h;
- ssize_t header_len = sizeof (ctf_header_t);
- ssize_t compress_len;
- 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 = malloc (compress_len)) == NULL)
- {
- ctf_err_warn (fp, 0, 0, _("ctf_compress_write: cannot allocate %li bytes"),
- (unsigned long) compress_len);
- return (ctf_set_errno (fp, ECTF_ZALLOC));
- }
-
- if ((rc = compress (buf, (uLongf *) &compress_len,
- fp->ctf_buf, fp->ctf_size)) != Z_OK)
- {
- err = ctf_set_errno (fp, ECTF_COMPRESS);
- ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
- goto ret;
- }
-
- while (header_len > 0)
- {
- if ((len = write (fd, hp, header_len)) < 0)
- {
- err = ctf_set_errno (fp, errno);
- ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing header"));
- goto ret;
- }
- header_len -= len;
- hp += len;
- }
-
- bp = buf;
- while (compress_len > 0)
- {
- if ((len = write (fd, bp, compress_len)) < 0)
- {
- err = ctf_set_errno (fp, errno);
- ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
- goto ret;
- }
- compress_len -= len;
- bp += len;
- }
-
-ret:
- free (buf);
- return err;
-}
-
/* Optionally compress the specified CTF data stream and return it as a new
- dynamically-allocated string. */
+ dynamically-allocated string. Possibly write it with reversed
+ endianness. */
unsigned char *
ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
{
unsigned char *buf;
unsigned char *bp;
ctf_header_t *hp;
+ unsigned char *flipped, *src;
ssize_t header_len = sizeof (ctf_header_t);
ssize_t compress_len;
+ int flip_endian;
+ int uncompressed;
int rc;
+ flip_endian = getenv ("LIBCTF_WRITE_FOREIGN_ENDIAN") != NULL;
+ uncompressed = (fp->ctf_size < threshold);
+
if (ctf_serialize (fp) < 0)
return NULL; /* errno is set for us. */
bp = buf + sizeof (struct ctf_header);
*size = sizeof (struct ctf_header);
- if (fp->ctf_size < threshold)
+ if (uncompressed)
+ hp->cth_flags &= ~CTF_F_COMPRESS;
+ else
+ hp->cth_flags |= CTF_F_COMPRESS;
+
+ src = fp->ctf_buf;
+ flipped = NULL;
+
+ if (flip_endian)
{
- hp->cth_flags &= ~CTF_F_COMPRESS;
- memcpy (bp, fp->ctf_buf, fp->ctf_size);
+ if ((flipped = malloc (fp->ctf_size)) == NULL)
+ {
+ ctf_set_errno (fp, ENOMEM);
+ ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
+ (unsigned long) fp->ctf_size + sizeof (struct ctf_header));
+ return NULL;
+ }
+ ctf_flip_header (hp);
+ memcpy (flipped, fp->ctf_buf, fp->ctf_size);
+ if (ctf_flip (fp, fp->ctf_header, flipped, 1) < 0)
+ {
+ free (buf);
+ free (flipped);
+ return NULL; /* errno is set for us. */
+ }
+ src = flipped;
+ }
+
+ if (uncompressed)
+ {
+ memcpy (bp, src, fp->ctf_size);
*size += fp->ctf_size;
}
else
{
- hp->cth_flags |= CTF_F_COMPRESS;
if ((rc = compress (bp, (uLongf *) &compress_len,
- fp->ctf_buf, fp->ctf_size)) != Z_OK)
+ src, fp->ctf_size)) != Z_OK)
{
ctf_set_errno (fp, ECTF_COMPRESS);
ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
}
*size += compress_len;
}
+
+ free (flipped);
+
return buf;
}
-/* Write the uncompressed CTF data stream to the specified file descriptor. */
+/* Compress the specified CTF data stream and write it to the specified file
+ descriptor. */
int
-ctf_write (ctf_dict_t *fp, int fd)
+ctf_compress_write (ctf_dict_t *fp, int fd)
{
- const unsigned char *buf;
- ssize_t resid;
+ unsigned char *buf;
+ unsigned char *bp;
+ size_t tmp;
+ ssize_t buf_len;
ssize_t len;
+ int err = 0;
- if (ctf_serialize (fp) < 0)
+ if ((buf = ctf_write_mem (fp, &tmp, 0)) == NULL)
return -1; /* errno is set for us. */
- resid = sizeof (ctf_header_t);
- buf = (unsigned char *) fp->ctf_header;
- while (resid != 0)
+ buf_len = tmp;
+ bp = buf;
+
+ while (buf_len > 0)
{
- if ((len = write (fd, buf, resid)) <= 0)
+ if ((len = write (fd, bp, buf_len)) < 0)
{
- ctf_err_warn (fp, 0, errno, _("ctf_write: error writing header"));
- return (ctf_set_errno (fp, errno));
+ err = ctf_set_errno (fp, errno);
+ ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
+ goto ret;
}
- resid -= len;
- buf += len;
+ buf_len -= len;
+ bp += len;
}
- resid = fp->ctf_size;
- buf = fp->ctf_buf;
- while (resid != 0)
+ret:
+ free (buf);
+ return err;
+}
+
+/* Write the uncompressed CTF data stream to the specified file descriptor. */
+int
+ctf_write (ctf_dict_t *fp, int fd)
+{
+ unsigned char *buf;
+ unsigned char *bp;
+ size_t tmp;
+ ssize_t buf_len;
+ ssize_t len;
+ int err = 0;
+
+ if ((buf = ctf_write_mem (fp, &tmp, (size_t) -1)) == NULL)
+ return -1; /* errno is set for us. */
+
+ buf_len = tmp;
+ bp = buf;
+
+ while (buf_len > 0)
{
- if ((len = write (fd, buf, resid)) <= 0)
+ if ((len = write (fd, bp, buf_len)) < 0)
{
- ctf_err_warn (fp, 0, errno, _("ctf_write: error writing"));
- return (ctf_set_errno (fp, errno));
+ err = ctf_set_errno (fp, errno);
+ ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
+ goto ret;
}
- resid -= len;
- buf += len;
+ buf_len -= len;
+ bp += len;
}
- return 0;
+ret:
+ free (buf);
+ return err;
}