open errors list if NULL): if ERR is nonzero it is the errno to report to the
debug stream instead of that recorded on fp. */
_libctf_printflike_ (4, 5)
-extern void
+void
ctf_err_warn (ctf_dict_t *fp, int is_warning, int err,
const char *format, ...)
{
ctf_list_splice (&open_errors, &fp->ctf_errs_warnings);
}
+/* Copy all the errors/warnings from one fp to another one, and the error code
+ as well. */
+void
+ctf_err_copy (ctf_dict_t *dest, ctf_dict_t *src)
+{
+ ctf_err_warning_t *cew;
+ for (cew = ctf_list_next (&src->ctf_errs_warnings); cew != NULL;
+ cew = ctf_list_next (cew))
+ ctf_err_warn (dest, cew->cew_is_warning, 0, cew->cew_text);
+ ctf_set_errno (dest, ctf_errno (src));
+}
+
/* Error-warning reporting: an 'iterator' that returns errors and warnings from
the error/warning list, in order of emission. Errors and warnings are popped
after return: the caller must free the returned error-text pointer.
and ctfi_symnamedicts. Never initialized. */
static ctf_dict_t enosym;
+/* Prepare to serialize everything. Members of archives have dependencies on
+ each other, because the strtabs and type IDs of children depend on the
+ parent: so we have to work over the archive as a whole to prepare for final
+ serialization.
+
+ Returns zero on success, or an errno, or an ECTF_* value.
+
+ Updates the first dict in the archive with the errno value. */
+
+static int
+ctf_arc_preserialize (ctf_dict_t **ctf_dicts, ssize_t ctf_dict_cnt)
+{
+ uint64_t old_parent_strlen, all_strlens = 0;
+ ssize_t i;
+ int err;
+
+ ctf_dprintf ("Preserializing dicts.\n");
+
+ /* Preserialize everything, doing everything but strtab generation and things
+ that depend on that. */
+ for (i = 0; i < ctf_dict_cnt; i++)
+ if (ctf_preserialize (ctf_dicts[i]) < 0)
+ goto err;
+
+ ctf_dprintf ("Deduplicating strings.\n");
+
+ for (i = 0; i < ctf_dict_cnt; i++)
+ all_strlens += ctf_dicts[i]->ctf_str[0].cts_len
+ + ctf_dicts[i]->ctf_str_prov_len;
+
+ /* If linking, deduplicate strings against the children in every dict that has
+ any. (String deduplication is not yet implemented for non-linked dicts.) */
+ for (i = 0; i < ctf_dict_cnt; i++)
+ if (ctf_dicts[i]->ctf_flags & LCTF_LINKING && ctf_dicts[i]->ctf_link_outputs)
+ {
+ old_parent_strlen = ctf_dicts[i]->ctf_str[0].cts_len
+ + ctf_dicts[i]->ctf_str_prov_len;
+
+ if (ctf_dedup_strings (ctf_dicts[i]) < 0)
+ goto err;
+
+ ctf_dprintf ("Deduplicated strings in archive member %zi: "
+ "original parent strlen: %zu; original lengths: %zu; "
+ "final length: %zu.\n", i, (size_t) old_parent_strlen,
+ (size_t) all_strlens,
+ (size_t) ctf_dicts[i]->ctf_str_prov_len);
+ }
+
+ return 0;
+
+ err:
+ err = ctf_errno (ctf_dicts[i]);
+ ctf_err_copy (ctf_dicts[0], ctf_dicts[i]);
+ for (i--; i >= 0; i--)
+ ctf_depreserialize (ctf_dicts[i]);
+ return err;
+}
+
/* Write out a CTF archive to the start of the file referenced by the passed-in
fd. The entries in CTF_DICTS are referenced by name: the names are passed in
the names array, which must have CTF_DICTS entries.
char *nametbl = NULL; /* The name table. */
char *np;
off_t nameoffs;
+ int err;
struct ctf_archive_modent *modent;
+ /* Prepare by serializing everything. Done first because it allocates a lot
+ of space and thus is more likely to fail. */
+ if (ctf_dict_cnt > 0 &&
+ (err = ctf_arc_preserialize (ctf_dicts, ctf_dict_cnt)) < 0)
+ return err;
+
ctf_dprintf ("Writing CTF archive with %lu files\n",
(unsigned long) ctf_dict_cnt);
extern void ctf_err_warn (ctf_dict_t *, int is_warning, int err,
const char *, ...);
extern void ctf_err_warn_to_open (ctf_dict_t *);
+extern void ctf_err_copy (ctf_dict_t *dest, ctf_dict_t *src);
extern void ctf_assert_fail_internal (ctf_dict_t *, const char *,
size_t, const char *);
extern const char *ctf_link_input_name (ctf_dict_t *);
long fsize;
const char *errloc;
unsigned char *buf = NULL;
- uint64_t old_parent_strlen, all_strlens = 0;
memset (&arg, 0, sizeof (ctf_name_list_accum_cb_arg_t));
arg.fp = fp;
memmove (&(arg.files[1]), arg.files, sizeof (ctf_dict_t *) * (arg.i));
arg.files[0] = fp;
- /* Preserialize everything, doing everything but strtab generation and things that
- depend on that. */
- for (i = 0; i < arg.i + 1; i++)
- {
- if (ctf_preserialize (arg.files[i]) < 0)
- {
- errno = ctf_errno (arg.files[i]);
- for (i--; i >= 0; i--)
- ctf_depreserialize (arg.files[i]);
- errloc = "preserialization";
- goto err_no;
- }
- }
-
- ctf_dprintf ("Deduplicating strings.\n");
-
- for (i = 0; i < arg.i; i++)
- all_strlens += arg.files[i]->ctf_str[0].cts_len
- + arg.files[i]->ctf_str_prov_len;
- old_parent_strlen = arg.files[0]->ctf_str[0].cts_len
- + arg.files[0]->ctf_str_prov_len;
-
- if (ctf_dedup_strings (fp) < 0)
- {
- for (i = 0; i < arg.i + 1; i++)
- ctf_depreserialize (arg.files[i]);
- errloc = "string deduplication";
- goto err_str_dedup;
- }
-
- ctf_dprintf ("Deduplicated strings: original parent strlen: %zu; "
- "original lengths: %zu; final length: %zu.\n",
- (size_t) old_parent_strlen, (size_t) all_strlens,
- (size_t) arg.files[0]->ctf_str_prov_len);
-
if ((f = tmpfile ()) == NULL)
{
errloc = "tempfile creation";
(const char **) arg.names,
threshold)) < 0)
{
- errloc = "archive writing";
- errno = err;
- goto err_no;
+ errloc = NULL; /* errno is set for us. */
+ goto err_set;
}
if (fseek (f, 0, SEEK_END) < 0)
err_no:
ctf_set_errno (fp, errno);
- err_str_dedup:
+ err_set:
/* Turn off the is-linking flag on all the dicts in this link, as above. */
for (i = 0; i < arg.i; i++)
{
free (arg.dynames[i]);
free (arg.dynames);
}
- ctf_err_warn (fp, 0, 0, _("cannot write archive in link: %s failure"),
- errloc);
+ if (errloc)
+ ctf_err_warn (fp, 0, 0, _("cannot write archive in link: %s failure"),
+ errloc);
return NULL;
}