@@ -353,6 +353,7 @@ union
#define CTF_NAME_STID(name) ((name) >> 31)
#define CTF_NAME_OFFSET(name) ((name) & CTF_MAX_NAME)
+#define CTF_SET_STID(name, stid) ((name) | (stid) << 31)
/* V2 only. */
#define CTF_TYPE_INFO(kind, isroot, vlen) \
@@ -192,6 +192,7 @@ typedef struct ctf_str_atom
{
const char *csa_str; /* Backpointer to string (hash key). */
ctf_list_t csa_refs; /* This string's refs. */
+ uint32_t csa_offset; /* External strtab offset, if any. */
unsigned long csa_snapshot_id; /* Snapshot ID at time of creation. */
} ctf_str_atom_t;
@@ -380,7 +381,8 @@ extern const char *ctf_strptr (ctf_file_t *, uint32_t);
extern int ctf_str_create_atoms (ctf_file_t *);
extern void ctf_str_free_atoms (ctf_file_t *);
extern const char *ctf_str_add (ctf_file_t *, const char *);
-extern const char *ctf_str_add_ref (ctf_file_t *, const char *, uint32_t *);
+extern const char *ctf_str_add_ref (ctf_file_t *, const char *, uint32_t *ref);
+extern const char *ctf_str_add_external (ctf_file_t *, const char *, uint32_t offset);
extern void ctf_str_rollback (ctf_file_t *, ctf_snapshot_id_t);
extern void ctf_str_purge_refs (ctf_file_t *);
extern ctf_strs_writable_t ctf_str_write_strtab (ctf_file_t *);
@@ -88,11 +88,11 @@ ctf_str_free_atoms (ctf_file_t *fp)
ctf_dynhash_destroy (fp->ctf_str_atoms);
}
-/* Add a string to the atoms table and return it, or return an existing string
- if present, copying the passed-in string. Returns NULL only when out of
- memory (and do not touch the passed-in string in that case). Possibly
- augment the ref list with the passed-in ref. */
-static const char *
+/* Add a string to the atoms table, copying the passed-in string. Return the
+ atom added. Return NULL only when out of memory (and do not touch the
+ passed-in string in that case). Possibly augment the ref list with the
+ passed-in ref. */
+static ctf_str_atom_t *
ctf_str_add_ref_internal (ctf_file_t *fp, const char *str,
int add_ref, uint32_t *ref)
{
@@ -116,7 +116,7 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str,
ctf_list_append (&atom->csa_refs, aref);
fp->ctf_str_num_refs++;
}
- return atom->csa_str;
+ return atom;
}
if ((atom = ctf_alloc (sizeof (struct ctf_str_atom))) == NULL)
@@ -136,7 +136,7 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str,
ctf_list_append (&atom->csa_refs, aref);
fp->ctf_str_num_refs++;
}
- return newstr;
+ return atom;
oom:
ctf_free (atom);
@@ -150,9 +150,48 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str,
const char *
ctf_str_add (ctf_file_t *fp, const char *str)
{
- if (str)
- return ctf_str_add_ref_internal (fp, str, FALSE, 0);
- return NULL;
+ ctf_str_atom_t *atom;
+ if (!str)
+ return NULL;
+
+ atom = ctf_str_add_ref_internal (fp, str, FALSE, 0);
+ if (!atom)
+ return NULL;
+
+ return atom->csa_str;
+}
+
+/* Like ctf_str_add(), but additionally augment the atom's refs list with the
+ passed-in ref, whether or not the string is already present. There is no
+ attempt to deduplicate the refs list (but duplicates are harmless). */
+const char *
+ctf_str_add_ref (ctf_file_t *fp, const char *str, uint32_t *ref)
+{
+ ctf_str_atom_t *atom;
+ if (!str)
+ return NULL;
+
+ atom = ctf_str_add_ref_internal (fp, str, TRUE, ref);
+ if (!atom)
+ return NULL;
+
+ return atom->csa_str;
+}
+
+/* Add an external strtab reference at OFFSET. */
+const char *
+ctf_str_add_external (ctf_file_t *fp, const char *str, uint32_t offset)
+{
+ ctf_str_atom_t *atom;
+ if (!str)
+ return NULL;
+
+ atom = ctf_str_add_ref_internal (fp, str, FALSE, 0);
+ if (!atom)
+ return NULL;
+
+ atom->csa_offset = CTF_SET_STID (offset, CTF_STRTAB_1);
+ return atom->csa_str;
}
/* A ctf_dynhash_iter_remove() callback that removes atoms later than a given
@@ -173,17 +212,6 @@ ctf_str_rollback (ctf_file_t *fp, ctf_snapshot_id_t id)
ctf_dynhash_iter_remove (fp->ctf_str_atoms, ctf_str_rollback_atom, &id);
}
-/* Like ctf_str_add(), but additionally augment the atom's refs list with the
- passed-in ref, whether or not the string is already present. There is no
- attempt to deduplicate the refs list (but duplicates are harmless). */
-const char *
-ctf_str_add_ref (ctf_file_t *fp, const char *str, uint32_t *ref)
-{
- if (str)
- return ctf_str_add_ref_internal (fp, str, TRUE, ref);
- return NULL;
-}
-
/* An adaptor around ctf_purge_atom_refs. */
static void
ctf_str_purge_one_atom_refs (void *key _libctf_unused_, void *value,
@@ -238,7 +266,11 @@ ctf_str_count_strtab (void *key _libctf_unused_, void *value,
ctf_str_atom_t *atom = (ctf_str_atom_t *) value;
ctf_strtab_write_state_t *s = (ctf_strtab_write_state_t *) arg;
- s->strtab->cts_len += strlen (atom->csa_str) + 1;
+ /* We only factor in the length of items that have no offset:
+ other items are in the external strtab. They still contribute to the
+ total count, though, because we still have to sort them. */
+ if (!atom->csa_offset)
+ s->strtab->cts_len += strlen (atom->csa_str) + 1;
s->strtab_count++;
}
@@ -317,12 +349,18 @@ ctf_str_write_strtab (ctf_file_t *fp)
return strtab;
}
- /* Update the strtab, and all refs. */
+ /* Update all refs: also update the strtab if this is not an external strtab
+ pointer. */
for (i = 0; i < s.strtab_count; i++)
{
- strcpy (&strtab.cts_strs[cur_stroff], sorttab[i]->csa_str);
- ctf_str_update_refs (sorttab[i], cur_stroff);
- cur_stroff += strlen (sorttab[i]->csa_str) + 1;
+ if (sorttab[i]->csa_offset)
+ ctf_str_update_refs (sorttab[i], sorttab[i]->csa_offset);
+ else
+ {
+ ctf_str_update_refs (sorttab[i], cur_stroff);
+ strcpy (&strtab.cts_strs[cur_stroff], sorttab[i]->csa_str);
+ cur_stroff += strlen (sorttab[i]->csa_str) + 1;
+ }
}
free (sorttab);