libctf: make ctf_serialize() actually serialize

ctf_serialize() evolved from the old ctf_update(), which mutated the
in-memory CTF dict to make all the dynamic in-memory types into static,
unchanging written-to-the-dict types (by deserializing and reserializing
it): back in the days when you could only do type lookups on static types,
this meant you could see all the types you added recently, at the small,
small cost of making it impossible to change those older types ever again
and inducing an amortized O(n^2) cost if you actually wanted to add
references to types you added at arbitrary times to later types.

It also reset things so that ctf_discard() would throw away only types you
added after the most recent ctf_update() call.

Some time ago this was all changed so that you could look up dynamic types
just as easily as static types: ctf_update() changed so that only its
visible side-effect of affecting ctf_discard() remained: the old
ctf_update() was renamed to ctf_serialize(), made internal to libctf, and
called from the various functions that wrote files out.

... but it was still working by serializing and deserializing the entire
dict, swapping out its guts with the newly-serialized copy in an invasive
and horrible fashion that coupled ctf_serialize() to almost every field in
the ctf_dict_t.  This is totally useless, and fixing it is easy: just rip
all that code out and have ctf_serialize return a serialized representation,
and let everything use that directly.  This simplifies most of its callers
significantly.

(It also points up another bug: ctf_gzwrite() failed to call ctf_serialize()
at all, so it would only ever work for a dict you just ctf_write_mem()ed
yourself, just for its invisible side-effect of serializing the dict!)

This lets us simplify away a bunch of internal-only open-side functionality
for overriding the syn_ext_strtab and some just-added functionality for
forcing in an existing atoms table, without loss of functionality, and lets
us lift the restriction on reserializing a dict that was ctf_open()ed rather
than being ctf_create()d: it's now perfectly OK to open a dict, modify it
(except for adding members to existing structs, unions, or enums, which
fails with -ECTF_RDONLY), and write it out again, just as one would expect.

libctf/

	* ctf-serialize.c (ctf_symtypetab_sect_sizes): Fix typos.
	(ctf_type_sect_size): Add static type sizes too.
	(ctf_serialize): Return the new dict rather than updating the
	existing dict.  No longer fail for dicts with static types;
	copy them onto the start of the new types table.
	(ctf_gzwrite): Actually serialize before gzwriting.
	(ctf_write_mem): Improve forced (test-mode) endian-flipping:
	flip dicts even if they are too small to be compressed.
	Improve confusing variable naming.
	* ctf-archive.c (arc_write_one_ctf): Don't bother to call
	ctf_serialize: both the functions we call do so.
	* ctf-string.c (ctf_str_create_atoms): Drop serializing case
	(atoms arg).
	* ctf-open.c (ctf_simple_open): Call ctf_bufopen directly.
	(ctf_simple_open_internal): Delete.
	(ctf_bufopen_internal): Delete/rename to ctf_bufopen: no
	longer bother with syn_ext_strtab or forced atoms table,
	serialization no longer needs them.
	* ctf-create.c (ctf_create): Call ctf_bufopen directly.
	* ctf-impl.h (ctf_str_create_atoms): Drop atoms arg.
	(ctf_simple_open_internal): Delete.
	(ctf_bufopen_internal): Likewise.
	(ctf_serialize): Adjust.
	* testsuite/libctf-lookup/add-to-opened.c: Adjust now that
	this is supposed to work.
This commit is contained in:
Nick Alcock 2024-03-26 13:04:20 +00:00
parent cf9da3b0b6
commit 483546ce4f
7 changed files with 137 additions and 348 deletions

View File

@ -253,12 +253,12 @@ ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
return err;
}
/* Write one CTF file out. Return the file position of the written file (or
/* Write one CTF dict out. Return the file position of the written file (or
rather, of the file-size uint64_t that precedes it): negative return is a
negative errno or ctf_errno value. On error, the file position may no longer
be at the end of the file. */
static off_t
arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold)
arc_write_one_ctf (ctf_dict_t *f, int fd, size_t threshold)
{
off_t off, end_off;
uint64_t ctfsz = 0;
@ -266,9 +266,6 @@ arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold)
size_t ctfsz_len;
int (*writefn) (ctf_dict_t * fp, int fd);
if (ctf_serialize (f) < 0)
return f->ctf_errno * -1;
if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
return errno * -1;

View File

@ -133,7 +133,7 @@ ctf_create (int *errp)
cts.cts_size = sizeof (hdr);
cts.cts_entsize = 1;
if ((fp = ctf_bufopen_internal (&cts, NULL, NULL, NULL, NULL, errp)) == NULL)
if ((fp = ctf_bufopen (&cts, NULL, NULL, errp)) == NULL)
goto err;
/* These hashes will have been initialized with a starting size of zero,

View File

@ -364,14 +364,7 @@ typedef struct ctf_dedup
clients, who see it only as an opaque pointer. Modifications can therefore
be made freely to this structure without regard to client versioning. The
ctf_dict_t typedef appears in <ctf-api.h> and declares a forward tag.
(A ctf_file_t typedef also appears there, for historical reasons.)
NOTE: ctf_serialize requires that everything inside of ctf_dict either be an
immediate value, a pointer to dynamically allocated data *outside* of the
ctf_dict itself, a pointer to statically allocated data, or specially handled
in ctf_serialize. If you add a pointer to ctf_dict that points to something
within the ctf_dict itself, you must make corresponding changes to
ctf_serialize. */
(A ctf_file_t typedef also appears there, for historical reasons.) */
struct ctf_dict
{
@ -735,7 +728,7 @@ extern const char *ctf_strraw (ctf_dict_t *, uint32_t);
extern const char *ctf_strraw_explicit (ctf_dict_t *, uint32_t,
ctf_strs_t *);
extern const char *ctf_strptr_validate (ctf_dict_t *, uint32_t);
extern int ctf_str_create_atoms (ctf_dict_t *, ctf_dynhash_t *atoms);
extern int ctf_str_create_atoms (ctf_dict_t *);
extern void ctf_str_free_atoms (ctf_dict_t *);
extern uint32_t ctf_str_add (ctf_dict_t *, const char *);
extern uint32_t ctf_str_add_ref (ctf_dict_t *, const char *, uint32_t *ref);
@ -760,15 +753,7 @@ extern void *ctf_set_open_errno (int *, int);
extern void ctf_flip_header (ctf_header_t *);
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 *, 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 *,
ctf_dynhash_t *, int *);
extern int ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp);
extern int ctf_serialize (ctf_dict_t *);
_libctf_malloc_
extern void *ctf_mmap (size_t length, size_t offset, int fd);

View File

@ -1233,9 +1233,8 @@ flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign)
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
@ -1287,21 +1286,6 @@ ctf_dict_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size,
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;
@ -1338,8 +1322,7 @@ ctf_dict_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size,
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
@ -1350,16 +1333,6 @@ ctf_dict_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size,
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);
@ -1370,8 +1343,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
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) &&
@ -1623,7 +1595,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
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;
@ -1669,7 +1641,6 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
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. */

View File

@ -470,9 +470,9 @@ ctf_symtypetab_sect_sizes (ctf_dict_t *fp, emit_symtypetab_state_t *s,
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;
@ -718,8 +718,8 @@ symerr:
/* 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)
@ -778,7 +778,7 @@ 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
@ -933,30 +933,22 @@ ctf_sort_var (const void *one_, const void *two_, void *arg_)
/* 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.
/* 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.)
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. */
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). */
int
ctf_serialize (ctf_dict_t *fp)
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;
@ -969,13 +961,6 @@ ctf_serialize (ctf_dict_t *fp)
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
@ -993,7 +978,7 @@ ctf_serialize (ctf_dict_t *fp)
/* 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;
@ -1004,17 +989,17 @@ ctf_serialize (ctf_dict_t *fp)
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
@ -1026,7 +1011,7 @@ ctf_serialize (ctf_dict_t *fp)
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);
@ -1050,7 +1035,10 @@ ctf_serialize (ctf_dict_t *fp)
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;
@ -1085,6 +1073,11 @@ ctf_serialize (ctf_dict_t *fp)
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);
@ -1111,136 +1104,15 @@ ctf_serialize (ctf_dict_t *fp)
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. */
@ -1255,30 +1127,27 @@ err:
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 ((buf = ctf_serialize (fp, &bufsiz)) == NULL)
return -1; /* errno is set for us. */
p = buf;
while (written < bufsiz)
{
if ((len = gzwrite (fd, buf, resid)) <= 0)
return (ctf_set_errno (fp, errno));
resid -= len;
buf += len;
}
resid = fp->ctf_size;
buf = fp->ctf_buf;
while (resid != 0)
{
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;
}
@ -1288,88 +1157,95 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
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

View File

@ -144,15 +144,9 @@ ctf_str_free_atom (void *a)
calls to ctf_str_add_external to populate external strtab entries, since
these are often not quite the same as what appears in any external
strtab, and the external strtab is often huge and best not aggressively
pulled in.)
Alternatively, if passed, populate atoms from the passed-in table, but do
not propagate their flags or refs: they are all non-freeable and
non-movable. (This is used when serializing a dict: this entire atoms
table will be thrown away shortly, so it is important that we not create
any new strings.) */
pulled in.) */
int
ctf_str_create_atoms (ctf_dict_t *fp, ctf_dynhash_t *atoms)
ctf_str_create_atoms (ctf_dict_t *fp)
{
size_t i;
@ -179,61 +173,26 @@ ctf_str_create_atoms (ctf_dict_t *fp, ctf_dynhash_t *atoms)
if (errno == ENOMEM)
goto oom_str_add;
/* Serializing. We have existing strings in an existing atoms table with
possibly-live pointers to them which must be used unchanged. Import
them into this atoms table. */
/* Pull in all the strings in the strtab as new atoms. The provisional
strtab must be empty at this point, so there is no need to populate
atoms from it as well. Types in this subset are frozen and readonly,
so the refs list and movable refs list need not be populated. */
if (atoms)
for (i = 0; i < fp->ctf_str[CTF_STRTAB_0].cts_len;
i += strlen (&fp->ctf_str[CTF_STRTAB_0].cts_strs[i]) + 1)
{
ctf_next_t *it = NULL;
void *k, *v;
int err;
ctf_str_atom_t *atom;
while ((err = ctf_dynhash_next (atoms, &it, &k, &v)) == 0)
{
ctf_str_atom_t *existing = v;
ctf_str_atom_t *atom;
if (fp->ctf_str[CTF_STRTAB_0].cts_strs[i] == 0)
continue;
if (existing->csa_str[0] == 0)
continue;
atom = ctf_str_add_ref_internal (fp, &fp->ctf_str[CTF_STRTAB_0].cts_strs[i],
0, 0);
if ((atom = malloc (sizeof (struct ctf_str_atom))) == NULL)
goto oom_str_add;
memcpy (atom, existing, sizeof (struct ctf_str_atom));
memset (&atom->csa_refs, 0, sizeof(ctf_list_t));
atom->csa_flags = 0;
if (!atom)
goto oom_str_add;
if (ctf_dynhash_insert (fp->ctf_str_atoms, atom->csa_str, atom) < 0)
{
free (atom);
goto oom_str_add;
}
}
}
else
{
/* Not serializing. Pull in all the strings in the strtab as new
atoms. The provisional strtab must be empty at this point, so
there is no need to populate atoms from it as well. Types in this
subset are frozen and readonly, so the refs list and movable refs
list need not be populated. */
for (i = 0; i < fp->ctf_str[CTF_STRTAB_0].cts_len;
i += strlen (&fp->ctf_str[CTF_STRTAB_0].cts_strs[i]) + 1)
{
ctf_str_atom_t *atom;
if (fp->ctf_str[CTF_STRTAB_0].cts_strs[i] == 0)
continue;
atom = ctf_str_add_ref_internal (fp, &fp->ctf_str[CTF_STRTAB_0].cts_strs[i],
0, 0);
if (!atom)
goto oom_str_add;
atom->csa_offset = i;
}
atom->csa_offset = i;
}
return 0;

View File

@ -118,11 +118,9 @@ main (int argc, char *argv[])
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)));
if ((ctf_written = ctf_write_mem (fp, &size, 4096)) == NULL)
fprintf (stderr, "Re-writeout unexpectedly failed: %s\n", ctf_errmsg (ctf_errno (fp)));
free (ctf_written);
/* Finally, make sure we can add new types, and look them up again. */
@ -138,6 +136,9 @@ main (int argc, char *argv[])
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);
ctf_dict_close (fp);
ctf_close (ctf);
printf ("All done.\n");
return 0;