aboutsummaryrefslogtreecommitdiff
path: root/libctf/ctf-serialize.c
diff options
context:
space:
mode:
authorNick Alcock <nick.alcock@oracle.com>2024-03-26 13:04:20 +0000
committerNick Alcock <nick.alcock@oracle.com>2024-04-19 16:14:47 +0100
commit483546ce4f36a93d3fb711f2261b15b75871f3f9 (patch)
tree7022abc55beff5b441d1c959ae52cbc18bafaf82 /libctf/ctf-serialize.c
parentcf9da3b0b6a6ae9d71ba36898a5e39710150f85e (diff)
downloadbinutils-483546ce4f36a93d3fb711f2261b15b75871f3f9.zip
binutils-483546ce4f36a93d3fb711f2261b15b75871f3f9.tar.gz
binutils-483546ce4f36a93d3fb711f2261b15b75871f3f9.tar.bz2
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.
Diffstat (limited to 'libctf/ctf-serialize.c')
-rw-r--r--libctf/ctf-serialize.c334
1 files changed, 105 insertions, 229 deletions
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index 82e5b7d..2d1f014 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -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.
-
- 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;
@@ -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 ((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;
}
@@ -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