return 0;
}
-/* Flip the endianness of BUF, given the offsets in the (already endian-
- converted) CTH. If TO_FOREIGN is set, flip to foreign-endianness; if not,
- flip away.
+/* Flip the endianness of BUF, given the offsets in the (native-endianness) CTH.
+ If TO_FOREIGN is set, flip to foreign-endianness; if not, flip away.
All of this stuff happens before the header is fully initialized, so the
LCTF_*() macros cannot be used yet. Since we do not try to endian-convert v1
size_t symsect_entsize,
const char *strsect, size_t strsect_size,
int *errp)
-{
- return ctf_simple_open_internal (ctfsect, ctfsect_size, symsect, symsect_size,
- symsect_entsize, strsect, strsect_size, NULL,
- NULL, errp);
-}
-
-/* Open a CTF file, mocking up a suitable ctf_sect and overriding the external
- strtab with a synthetic one. */
-
-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,
- ctf_dynhash_t *atoms, int *errp)
{
ctf_sect_t skeleton;
strsectp = &str_sect;
}
- return ctf_bufopen_internal (ctfsectp, symsectp, strsectp, syn_strtab,
- atoms, errp);
+ return ctf_bufopen (ctfsectp, symsectp, strsectp, errp);
}
/* Decode the specified CTF buffer and optional symbol table, and create a new
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, NULL, errp);
-}
-
-/* Like ctf_bufopen, but overriding the external strtab with a synthetic one. */
-
-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,
- ctf_dynhash_t *atoms, int *errp)
{
const ctf_preamble_t *pp;
size_t hdrsz = sizeof (ctf_header_t);
libctf_init_debug();
- if ((ctfsect == NULL) || ((symsect != NULL) &&
- ((strsect == NULL) && syn_strtab == NULL)))
+ if ((ctfsect == NULL) || ((symsect != NULL) && (strsect == NULL)))
return (ctf_set_open_errno (errp, EINVAL));
if (symsect != NULL && symsect->cts_entsize != sizeof (Elf32_Sym) &&
fp->ctf_str[CTF_STRTAB_0].cts_strs = (const char *) fp->ctf_buf
+ hp->cth_stroff;
fp->ctf_str[CTF_STRTAB_0].cts_len = hp->cth_strlen;
- if (ctf_str_create_atoms (fp, atoms) < 0)
+ if (ctf_str_create_atoms (fp) < 0)
{
err = ENOMEM;
goto bad;
fp->ctf_str[CTF_STRTAB_1].cts_strs = strsect->cts_data;
fp->ctf_str[CTF_STRTAB_1].cts_len = strsect->cts_size;
}
- fp->ctf_syn_ext_strtab = syn_strtab;
/* Dynamic state, for dynamic addition to this dict after loading. */
filter out reported symbols from the variable section, and filter out all
other symbols from the symtypetab sections. (If we are not linking, the
symbols are sorted; if we are linking, don't bother sorting if we are not
- filtering out reported symbols: this is almost certaily an ld -r and only
+ filtering out reported symbols: this is almost certainly an ld -r and only
the linker is likely to consume these symtypetabs again. The linker
- doesn't care what order the symtypetab entries is in, since it only
+ doesn't care what order the symtypetab entries are in, since it only
iterates over symbols and does not use the ctf_lookup_by_symbol* API.) */
s->sort_syms = 1;
/* Type section. */
-/* Iterate through the dynamic type definition list and compute the
- size of the CTF type section. */
+/* Iterate through the static types and the dynamic type definition list and
+ compute the size of the CTF type section. */
static size_t
ctf_type_sect_size (ctf_dict_t *fp)
}
}
- return type_size;
+ return type_size + fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff;
}
/* Take a final lap through the dynamic type definition list and copy the
/* Overall serialization. */
-/* If the specified CTF dict is writable and has been modified, reload this dict
- 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 dict
- 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_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.
-
- 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. */
+/* Emit a new CTF dict which is a serialized copy of this one: also reify
+ the string table and update all offsets in the current dict suitably.
+ (This simplifies ctf-string.c a little, at the cost of storing a second
+ copy of the strtab if this dict was originally read in via ctf_open.)
-int
-ctf_serialize (ctf_dict_t *fp)
+ Other aspects of the existing dict are unchanged, although some
+ static entries may be duplicated in the dynamic state (which should
+ have no effect on visible operation). */
+
+static unsigned char *
+ctf_serialize (ctf_dict_t *fp, size_t *bufsiz)
{
- ctf_dict_t ofp, *nfp;
ctf_header_t hdr, *hdrp;
ctf_dvdef_t *dvd;
ctf_varent_t *dvarents;
const ctf_strs_writable_t *strtab;
- int err;
int sym_functions = 0;
unsigned char *t;
emit_symtypetab_state_t symstate;
memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
- /* 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));
-
/* Fill in an initial CTF header. We will leave the label, object,
and function sections empty and only output a header, type section,
and string table. The type section begins at a 4-byte aligned
/* 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. */
+ state, likely due to repeated serialization, are left unchanged. */
do
{
ctf_next_t *it = NULL;
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. */
+ return NULL; /* errno is set for us. */
if (ctf_errno (fp) != ECTF_NEXT_END)
- return -1; /* errno is set for us. */
+ return NULL; /* 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. */
+ return NULL; /* 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
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. */
+ return NULL; /* errno is set for us. */
}
for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs);
buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
if ((buf = malloc (buf_size)) == NULL)
- return (ctf_set_errno (fp, EAGAIN));
+ {
+ ctf_set_errno (fp, EAGAIN);
+ return NULL;
+ }
memcpy (buf, &hdr, sizeof (ctf_header_t));
t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
+ /* Copy in existing static types, then emit new dynamic types. */
+
+ memcpy (t, fp->ctf_buf + fp->ctf_header->cth_typeoff,
+ fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff);
+ t += fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff;
ctf_emit_type_sect (fp, &t);
assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff);
hdrp = (ctf_header_t *) buf;
hdrp->cth_strlen = strtab->cts_len;
buf_size += hdrp->cth_strlen;
+ *bufsiz = buf_size;
- /* Finally, we are ready to ctf_simple_open() the new dict. If this is
- successful, we then switch nfp and fp and free the old dict. */
-
- if ((nfp = ctf_simple_open_internal ((char *) buf, buf_size, NULL, 0,
- 0, NULL, 0, fp->ctf_syn_ext_strtab,
- fp->ctf_str_atoms, &err)) == NULL)
- {
- free (buf);
- return (ctf_set_errno (fp, err));
- }
-
- (void) ctf_setmodel (nfp, ctf_getmodel (fp));
-
- nfp->ctf_parent = fp->ctf_parent;
- nfp->ctf_parent_unreffed = fp->ctf_parent_unreffed;
- nfp->ctf_refcnt = fp->ctf_refcnt;
- if (nfp->ctf_dynbase == NULL)
- 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_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_nfuncidx = fp->ctf_nfuncidx;
- nfp->ctf_nobjtidx = fp->ctf_nobjtidx;
- nfp->ctf_objthash = fp->ctf_objthash;
- nfp->ctf_funchash = fp->ctf_funchash;
- nfp->ctf_dynsyms = fp->ctf_dynsyms;
- 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;
- nfp->ctf_pptrtab_len = fp->ctf_pptrtab_len;
- nfp->ctf_link_inputs = fp->ctf_link_inputs;
- nfp->ctf_link_outputs = fp->ctf_link_outputs;
- nfp->ctf_errs_warnings = fp->ctf_errs_warnings;
- nfp->ctf_funcidx_names = fp->ctf_funcidx_names;
- nfp->ctf_objtidx_names = fp->ctf_objtidx_names;
- nfp->ctf_funcidx_sxlate = fp->ctf_funcidx_sxlate;
- nfp->ctf_objtidx_sxlate = fp->ctf_objtidx_sxlate;
- nfp->ctf_str_prov_offset = fp->ctf_str_prov_offset;
- nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab;
- nfp->ctf_pptrtab_typemax = fp->ctf_pptrtab_typemax;
- nfp->ctf_in_flight_dynsyms = fp->ctf_in_flight_dynsyms;
- nfp->ctf_link_in_cu_mapping = fp->ctf_link_in_cu_mapping;
- nfp->ctf_link_out_cu_mapping = fp->ctf_link_out_cu_mapping;
- nfp->ctf_link_type_mapping = fp->ctf_link_type_mapping;
- nfp->ctf_link_memb_name_changer = fp->ctf_link_memb_name_changer;
- nfp->ctf_link_memb_name_changer_arg = fp->ctf_link_memb_name_changer_arg;
- nfp->ctf_link_variable_filter = fp->ctf_link_variable_filter;
- nfp->ctf_link_variable_filter_arg = fp->ctf_link_variable_filter_arg;
- nfp->ctf_symsect_little_endian = fp->ctf_symsect_little_endian;
- nfp->ctf_link_flags = fp->ctf_link_flags;
- nfp->ctf_dedup_atoms = fp->ctf_dedup_atoms;
- nfp->ctf_dedup_atoms_alloc = fp->ctf_dedup_atoms_alloc;
- memcpy (&nfp->ctf_dedup, &fp->ctf_dedup, sizeof (fp->ctf_dedup));
-
- nfp->ctf_snapshot_lu = fp->ctf_snapshots;
-
- 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;
- nfp->ctf_dynstrtab = fp->ctf_dynstrtab;
- nfp->ctf_str_movable_refs = fp->ctf_str_movable_refs;
- fp->ctf_str_atoms = NULL;
- fp->ctf_prov_strtab = NULL;
- fp->ctf_dynstrtab = NULL;
- fp->ctf_str_movable_refs = NULL;
- memset (&fp->ctf_dtdefs, 0, sizeof (ctf_list_t));
- memset (&fp->ctf_errs_warnings, 0, sizeof (ctf_list_t));
- fp->ctf_add_processing = NULL;
- fp->ctf_ptrtab = NULL;
- fp->ctf_pptrtab = NULL;
- fp->ctf_funcidx_names = NULL;
- fp->ctf_objtidx_names = NULL;
- fp->ctf_funcidx_sxlate = NULL;
- fp->ctf_objtidx_sxlate = NULL;
- fp->ctf_objthash = NULL;
- fp->ctf_funchash = NULL;
- fp->ctf_dynsyms = NULL;
- fp->ctf_dynsymidx = NULL;
- fp->ctf_link_inputs = NULL;
- fp->ctf_link_outputs = NULL;
- fp->ctf_syn_ext_strtab = NULL;
- fp->ctf_link_in_cu_mapping = NULL;
- fp->ctf_link_out_cu_mapping = NULL;
- fp->ctf_link_type_mapping = NULL;
- fp->ctf_dedup_atoms = NULL;
- fp->ctf_dedup_atoms_alloc = NULL;
- fp->ctf_parent_unreffed = 1;
-
- fp->ctf_dvhash = NULL;
- memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t));
- memset (fp->ctf_lookups, 0, sizeof (fp->ctf_lookups));
- memset (&fp->ctf_in_flight_dynsyms, 0, sizeof (fp->ctf_in_flight_dynsyms));
- memset (&fp->ctf_dedup, 0, sizeof (fp->ctf_dedup));
- fp->ctf_structs = NULL;
- fp->ctf_unions = NULL;
- fp->ctf_enums = NULL;
- fp->ctf_names = NULL;
-
- memcpy (&ofp, fp, sizeof (ctf_dict_t));
- memcpy (fp, nfp, sizeof (ctf_dict_t));
- memcpy (nfp, &ofp, sizeof (ctf_dict_t));
-
- nfp->ctf_refcnt = 1; /* Force nfp to be freed. */
- ctf_dict_close (nfp);
-
- return 0;
+ return buf;
oom:
- free (buf);
- return (ctf_set_errno (fp, EAGAIN));
+ ctf_set_errno (fp, EAGAIN);
err:
free (buf);
- return -1; /* errno is set for us. */
+ return NULL; /* errno is set for us. */
}
/* File writing. */
int
ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
{
- const unsigned char *buf;
- ssize_t resid;
- ssize_t len;
+ unsigned char *buf;
+ unsigned char *p;
+ size_t bufsiz;
+ size_t len, written = 0;
- resid = sizeof (ctf_header_t);
- buf = (unsigned char *) fp->ctf_header;
- while (resid != 0)
- {
- if ((len = gzwrite (fd, buf, resid)) <= 0)
- return (ctf_set_errno (fp, errno));
- resid -= len;
- buf += len;
- }
+ if ((buf = ctf_serialize (fp, &bufsiz)) == NULL)
+ return -1; /* errno is set for us. */
- resid = fp->ctf_size;
- buf = fp->ctf_buf;
- while (resid != 0)
+ p = buf;
+ while (written < bufsiz)
{
- if ((len = gzwrite (fd, buf, resid)) <= 0)
- return (ctf_set_errno (fp, errno));
- resid -= len;
- buf += len;
+ if ((len = gzwrite (fd, p, bufsiz - written)) <= 0)
+ {
+ free (buf);
+ return (ctf_set_errno (fp, errno));
+ }
+ written += len;
+ p += len;
}
+ free (buf);
return 0;
}
unsigned char *
ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
{
- unsigned char *buf;
+ unsigned char *rawbuf;
+ unsigned char *buf = NULL;
unsigned char *bp;
- ctf_header_t *hp;
- unsigned char *flipped, *src;
- ssize_t header_len = sizeof (ctf_header_t);
- ssize_t compress_len;
+ ctf_header_t *rawhp, *hp;
+ unsigned char *src;
+ size_t rawbufsiz;
+ size_t alloc_len = 0;
+ int uncompressed = 0;
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)
+ if ((rawbuf = ctf_serialize (fp, &rawbufsiz)) == NULL)
return NULL; /* errno is set for us. */
- compress_len = compressBound (fp->ctf_size);
- if (fp->ctf_size < threshold)
- compress_len = fp->ctf_size;
- if ((buf = malloc (compress_len
- + sizeof (struct ctf_header))) == NULL)
+ if (!ctf_assert (fp, rawbufsiz >= sizeof (ctf_header_t)))
+ goto err;
+
+ if (rawbufsiz >= threshold)
+ alloc_len = compressBound (rawbufsiz - sizeof (ctf_header_t))
+ + sizeof (ctf_header_t);
+
+ /* Trivial operation if the buffer is incompressible or too small to bother
+ compressing, and we're not doing a forced write-time flip. */
+
+ if (rawbufsiz < threshold || rawbufsiz < alloc_len)
+ {
+ alloc_len = rawbufsiz;
+ uncompressed = 1;
+ }
+
+ if (!flip_endian && uncompressed)
+ {
+ *size = rawbufsiz;
+ return rawbuf;
+ }
+
+ if ((buf = malloc (alloc_len)) == NULL)
{
ctf_set_errno (fp, ENOMEM);
ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
- (unsigned long) (compress_len + sizeof (struct ctf_header)));
- return NULL;
+ (unsigned long) (alloc_len));
+ goto err;
}
+ rawhp = (ctf_header_t *) rawbuf;
hp = (ctf_header_t *) buf;
- memcpy (hp, fp->ctf_header, header_len);
- bp = buf + sizeof (struct ctf_header);
- *size = sizeof (struct ctf_header);
+ memcpy (hp, rawbuf, sizeof (ctf_header_t));
+ bp = buf + sizeof (ctf_header_t);
+ *size = sizeof (ctf_header_t);
- if (uncompressed)
- hp->cth_flags &= ~CTF_F_COMPRESS;
- else
+ if (!uncompressed)
hp->cth_flags |= CTF_F_COMPRESS;
- src = fp->ctf_buf;
- flipped = NULL;
+ src = rawbuf + sizeof (ctf_header_t);
if (flip_endian)
{
- 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 (ctf_flip (fp, rawhp, src, 1) < 0)
+ goto err; /* errno is set for us. */
}
- if (uncompressed)
- {
- memcpy (bp, src, fp->ctf_size);
- *size += fp->ctf_size;
- }
- else
+ if (!uncompressed)
{
+ size_t compress_len = alloc_len - sizeof (ctf_header_t);
+
if ((rc = compress (bp, (uLongf *) &compress_len,
- src, fp->ctf_size)) != Z_OK)
+ src, rawbufsiz - sizeof (ctf_header_t))) != Z_OK)
{
ctf_set_errno (fp, ECTF_COMPRESS);
ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
- free (buf);
- return NULL;
+ goto err;
}
*size += compress_len;
}
+ else
+ {
+ memcpy (bp, src, rawbufsiz - sizeof (ctf_header_t));
+ *size += rawbufsiz - sizeof (ctf_header_t);
+ }
- free (flipped);
-
+ free (rawbuf);
return buf;
+err:
+ free (buf);
+ free (rawbuf);
+ return NULL;
}
/* Compress the specified CTF data stream and write it to the specified file