1*869ffda3Schristos /* CTF string table management.
2*869ffda3Schristos Copyright (C) 2019-2020 Free Software Foundation, Inc.
3*869ffda3Schristos
4*869ffda3Schristos This file is part of libctf.
5*869ffda3Schristos
6*869ffda3Schristos libctf is free software; you can redistribute it and/or modify it under
7*869ffda3Schristos the terms of the GNU General Public License as published by the Free
8*869ffda3Schristos Software Foundation; either version 3, or (at your option) any later
9*869ffda3Schristos version.
10*869ffda3Schristos
11*869ffda3Schristos This program is distributed in the hope that it will be useful, but
12*869ffda3Schristos WITHOUT ANY WARRANTY; without even the implied warranty of
13*869ffda3Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14*869ffda3Schristos See the GNU General Public License for more details.
15*869ffda3Schristos
16*869ffda3Schristos You should have received a copy of the GNU General Public License
17*869ffda3Schristos along with this program; see the file COPYING. If not see
18*869ffda3Schristos <http://www.gnu.org/licenses/>. */
19*869ffda3Schristos
20*869ffda3Schristos #include <ctf-impl.h>
21*869ffda3Schristos #include <string.h>
22*869ffda3Schristos
23*869ffda3Schristos /* Convert an encoded CTF string name into a pointer to a C string, using an
24*869ffda3Schristos explicit internal strtab rather than the fp-based one. */
25*869ffda3Schristos const char *
ctf_strraw_explicit(ctf_file_t * fp,uint32_t name,ctf_strs_t * strtab)26*869ffda3Schristos ctf_strraw_explicit (ctf_file_t *fp, uint32_t name, ctf_strs_t *strtab)
27*869ffda3Schristos {
28*869ffda3Schristos ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID (name)];
29*869ffda3Schristos
30*869ffda3Schristos if ((CTF_NAME_STID (name) == CTF_STRTAB_0) && (strtab != NULL))
31*869ffda3Schristos ctsp = strtab;
32*869ffda3Schristos
33*869ffda3Schristos /* If this name is in the external strtab, and there is a synthetic strtab,
34*869ffda3Schristos use it in preference. */
35*869ffda3Schristos
36*869ffda3Schristos if (CTF_NAME_STID (name) == CTF_STRTAB_1
37*869ffda3Schristos && fp->ctf_syn_ext_strtab != NULL)
38*869ffda3Schristos return ctf_dynhash_lookup (fp->ctf_syn_ext_strtab,
39*869ffda3Schristos (void *) (uintptr_t) name);
40*869ffda3Schristos
41*869ffda3Schristos /* If the name is in the internal strtab, and the offset is beyond the end of
42*869ffda3Schristos the ctsp->cts_len but below the ctf_str_prov_offset, this is a provisional
43*869ffda3Schristos string added by ctf_str_add*() but not yet built into a real strtab: get
44*869ffda3Schristos the value out of the ctf_prov_strtab. */
45*869ffda3Schristos
46*869ffda3Schristos if (CTF_NAME_STID (name) == CTF_STRTAB_0
47*869ffda3Schristos && name >= ctsp->cts_len && name < fp->ctf_str_prov_offset)
48*869ffda3Schristos return ctf_dynhash_lookup (fp->ctf_prov_strtab,
49*869ffda3Schristos (void *) (uintptr_t) name);
50*869ffda3Schristos
51*869ffda3Schristos if (ctsp->cts_strs != NULL && CTF_NAME_OFFSET (name) < ctsp->cts_len)
52*869ffda3Schristos return (ctsp->cts_strs + CTF_NAME_OFFSET (name));
53*869ffda3Schristos
54*869ffda3Schristos /* String table not loaded or corrupt offset. */
55*869ffda3Schristos return NULL;
56*869ffda3Schristos }
57*869ffda3Schristos
58*869ffda3Schristos /* Convert an encoded CTF string name into a pointer to a C string by looking
59*869ffda3Schristos up the appropriate string table buffer and then adding the offset. */
60*869ffda3Schristos const char *
ctf_strraw(ctf_file_t * fp,uint32_t name)61*869ffda3Schristos ctf_strraw (ctf_file_t *fp, uint32_t name)
62*869ffda3Schristos {
63*869ffda3Schristos return ctf_strraw_explicit (fp, name, NULL);
64*869ffda3Schristos }
65*869ffda3Schristos
66*869ffda3Schristos /* Return a guaranteed-non-NULL pointer to the string with the given CTF
67*869ffda3Schristos name. */
68*869ffda3Schristos const char *
ctf_strptr(ctf_file_t * fp,uint32_t name)69*869ffda3Schristos ctf_strptr (ctf_file_t *fp, uint32_t name)
70*869ffda3Schristos {
71*869ffda3Schristos const char *s = ctf_strraw (fp, name);
72*869ffda3Schristos return (s != NULL ? s : "(?)");
73*869ffda3Schristos }
74*869ffda3Schristos
75*869ffda3Schristos /* Remove all refs to a given atom. */
76*869ffda3Schristos static void
ctf_str_purge_atom_refs(ctf_str_atom_t * atom)77*869ffda3Schristos ctf_str_purge_atom_refs (ctf_str_atom_t *atom)
78*869ffda3Schristos {
79*869ffda3Schristos ctf_str_atom_ref_t *ref, *next;
80*869ffda3Schristos
81*869ffda3Schristos for (ref = ctf_list_next (&atom->csa_refs); ref != NULL; ref = next)
82*869ffda3Schristos {
83*869ffda3Schristos next = ctf_list_next (ref);
84*869ffda3Schristos ctf_list_delete (&atom->csa_refs, ref);
85*869ffda3Schristos free (ref);
86*869ffda3Schristos }
87*869ffda3Schristos }
88*869ffda3Schristos
89*869ffda3Schristos /* Free an atom (only called on ctf_close().) */
90*869ffda3Schristos static void
ctf_str_free_atom(void * a)91*869ffda3Schristos ctf_str_free_atom (void *a)
92*869ffda3Schristos {
93*869ffda3Schristos ctf_str_atom_t *atom = a;
94*869ffda3Schristos
95*869ffda3Schristos ctf_str_purge_atom_refs (atom);
96*869ffda3Schristos free (atom);
97*869ffda3Schristos }
98*869ffda3Schristos
99*869ffda3Schristos /* Create the atoms table. There is always at least one atom in it, the null
100*869ffda3Schristos string. */
101*869ffda3Schristos int
ctf_str_create_atoms(ctf_file_t * fp)102*869ffda3Schristos ctf_str_create_atoms (ctf_file_t *fp)
103*869ffda3Schristos {
104*869ffda3Schristos fp->ctf_str_atoms = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
105*869ffda3Schristos free, ctf_str_free_atom);
106*869ffda3Schristos if (fp->ctf_str_atoms == NULL)
107*869ffda3Schristos return -ENOMEM;
108*869ffda3Schristos
109*869ffda3Schristos if (!fp->ctf_prov_strtab)
110*869ffda3Schristos fp->ctf_prov_strtab = ctf_dynhash_create (ctf_hash_integer,
111*869ffda3Schristos ctf_hash_eq_integer,
112*869ffda3Schristos NULL, NULL);
113*869ffda3Schristos if (!fp->ctf_prov_strtab)
114*869ffda3Schristos goto oom_prov_strtab;
115*869ffda3Schristos
116*869ffda3Schristos errno = 0;
117*869ffda3Schristos ctf_str_add (fp, "");
118*869ffda3Schristos if (errno == ENOMEM)
119*869ffda3Schristos goto oom_str_add;
120*869ffda3Schristos
121*869ffda3Schristos return 0;
122*869ffda3Schristos
123*869ffda3Schristos oom_str_add:
124*869ffda3Schristos ctf_dynhash_destroy (fp->ctf_prov_strtab);
125*869ffda3Schristos fp->ctf_prov_strtab = NULL;
126*869ffda3Schristos oom_prov_strtab:
127*869ffda3Schristos ctf_dynhash_destroy (fp->ctf_str_atoms);
128*869ffda3Schristos fp->ctf_str_atoms = NULL;
129*869ffda3Schristos return -ENOMEM;
130*869ffda3Schristos }
131*869ffda3Schristos
132*869ffda3Schristos /* Destroy the atoms table. */
133*869ffda3Schristos void
ctf_str_free_atoms(ctf_file_t * fp)134*869ffda3Schristos ctf_str_free_atoms (ctf_file_t *fp)
135*869ffda3Schristos {
136*869ffda3Schristos ctf_dynhash_destroy (fp->ctf_prov_strtab);
137*869ffda3Schristos ctf_dynhash_destroy (fp->ctf_str_atoms);
138*869ffda3Schristos }
139*869ffda3Schristos
140*869ffda3Schristos /* Add a string to the atoms table, copying the passed-in string. Return the
141*869ffda3Schristos atom added. Return NULL only when out of memory (and do not touch the
142*869ffda3Schristos passed-in string in that case). Possibly augment the ref list with the
143*869ffda3Schristos passed-in ref. Possibly add a provisional entry for this string to the
144*869ffda3Schristos provisional strtab. */
145*869ffda3Schristos static ctf_str_atom_t *
ctf_str_add_ref_internal(ctf_file_t * fp,const char * str,int add_ref,int make_provisional,uint32_t * ref)146*869ffda3Schristos ctf_str_add_ref_internal (ctf_file_t *fp, const char *str,
147*869ffda3Schristos int add_ref, int make_provisional, uint32_t *ref)
148*869ffda3Schristos {
149*869ffda3Schristos char *newstr = NULL;
150*869ffda3Schristos ctf_str_atom_t *atom = NULL;
151*869ffda3Schristos ctf_str_atom_ref_t *aref = NULL;
152*869ffda3Schristos
153*869ffda3Schristos atom = ctf_dynhash_lookup (fp->ctf_str_atoms, str);
154*869ffda3Schristos
155*869ffda3Schristos if (add_ref)
156*869ffda3Schristos {
157*869ffda3Schristos if ((aref = malloc (sizeof (struct ctf_str_atom_ref))) == NULL)
158*869ffda3Schristos return NULL;
159*869ffda3Schristos aref->caf_ref = ref;
160*869ffda3Schristos }
161*869ffda3Schristos
162*869ffda3Schristos if (atom)
163*869ffda3Schristos {
164*869ffda3Schristos if (add_ref)
165*869ffda3Schristos {
166*869ffda3Schristos ctf_list_append (&atom->csa_refs, aref);
167*869ffda3Schristos fp->ctf_str_num_refs++;
168*869ffda3Schristos }
169*869ffda3Schristos return atom;
170*869ffda3Schristos }
171*869ffda3Schristos
172*869ffda3Schristos if ((atom = malloc (sizeof (struct ctf_str_atom))) == NULL)
173*869ffda3Schristos goto oom;
174*869ffda3Schristos memset (atom, 0, sizeof (struct ctf_str_atom));
175*869ffda3Schristos
176*869ffda3Schristos if ((newstr = strdup (str)) == NULL)
177*869ffda3Schristos goto oom;
178*869ffda3Schristos
179*869ffda3Schristos if (ctf_dynhash_insert (fp->ctf_str_atoms, newstr, atom) < 0)
180*869ffda3Schristos goto oom;
181*869ffda3Schristos
182*869ffda3Schristos atom->csa_str = newstr;
183*869ffda3Schristos atom->csa_snapshot_id = fp->ctf_snapshots;
184*869ffda3Schristos
185*869ffda3Schristos if (make_provisional)
186*869ffda3Schristos {
187*869ffda3Schristos atom->csa_offset = fp->ctf_str_prov_offset;
188*869ffda3Schristos
189*869ffda3Schristos if (ctf_dynhash_insert (fp->ctf_prov_strtab, (void *) (uintptr_t)
190*869ffda3Schristos atom->csa_offset, (void *) atom->csa_str) < 0)
191*869ffda3Schristos goto oom;
192*869ffda3Schristos
193*869ffda3Schristos fp->ctf_str_prov_offset += strlen (atom->csa_str) + 1;
194*869ffda3Schristos }
195*869ffda3Schristos
196*869ffda3Schristos if (add_ref)
197*869ffda3Schristos {
198*869ffda3Schristos ctf_list_append (&atom->csa_refs, aref);
199*869ffda3Schristos fp->ctf_str_num_refs++;
200*869ffda3Schristos }
201*869ffda3Schristos return atom;
202*869ffda3Schristos
203*869ffda3Schristos oom:
204*869ffda3Schristos if (newstr)
205*869ffda3Schristos ctf_dynhash_remove (fp->ctf_str_atoms, newstr);
206*869ffda3Schristos free (atom);
207*869ffda3Schristos free (aref);
208*869ffda3Schristos free (newstr);
209*869ffda3Schristos return NULL;
210*869ffda3Schristos }
211*869ffda3Schristos
212*869ffda3Schristos /* Add a string to the atoms table, without augmenting the ref list for this
213*869ffda3Schristos string: return a 'provisional offset' which can be used to return this string
214*869ffda3Schristos until ctf_str_write_strtab is called, or 0 on failure. (Everywhere the
215*869ffda3Schristos provisional offset is assigned to should be added as a ref using
216*869ffda3Schristos ctf_str_add_ref() as well.) */
217*869ffda3Schristos uint32_t
ctf_str_add(ctf_file_t * fp,const char * str)218*869ffda3Schristos ctf_str_add (ctf_file_t *fp, const char *str)
219*869ffda3Schristos {
220*869ffda3Schristos ctf_str_atom_t *atom;
221*869ffda3Schristos if (!str)
222*869ffda3Schristos return 0;
223*869ffda3Schristos
224*869ffda3Schristos atom = ctf_str_add_ref_internal (fp, str, FALSE, TRUE, 0);
225*869ffda3Schristos if (!atom)
226*869ffda3Schristos return 0;
227*869ffda3Schristos
228*869ffda3Schristos return atom->csa_offset;
229*869ffda3Schristos }
230*869ffda3Schristos
231*869ffda3Schristos /* Like ctf_str_add(), but additionally augment the atom's refs list with the
232*869ffda3Schristos passed-in ref, whether or not the string is already present. There is no
233*869ffda3Schristos attempt to deduplicate the refs list (but duplicates are harmless). */
234*869ffda3Schristos uint32_t
ctf_str_add_ref(ctf_file_t * fp,const char * str,uint32_t * ref)235*869ffda3Schristos ctf_str_add_ref (ctf_file_t *fp, const char *str, uint32_t *ref)
236*869ffda3Schristos {
237*869ffda3Schristos ctf_str_atom_t *atom;
238*869ffda3Schristos if (!str)
239*869ffda3Schristos return 0;
240*869ffda3Schristos
241*869ffda3Schristos atom = ctf_str_add_ref_internal (fp, str, TRUE, TRUE, ref);
242*869ffda3Schristos if (!atom)
243*869ffda3Schristos return 0;
244*869ffda3Schristos
245*869ffda3Schristos return atom->csa_offset;
246*869ffda3Schristos }
247*869ffda3Schristos
248*869ffda3Schristos /* Add an external strtab reference at OFFSET. Returns zero if the addition
249*869ffda3Schristos failed, nonzero otherwise. */
250*869ffda3Schristos int
ctf_str_add_external(ctf_file_t * fp,const char * str,uint32_t offset)251*869ffda3Schristos ctf_str_add_external (ctf_file_t *fp, const char *str, uint32_t offset)
252*869ffda3Schristos {
253*869ffda3Schristos ctf_str_atom_t *atom;
254*869ffda3Schristos if (!str)
255*869ffda3Schristos return 0;
256*869ffda3Schristos
257*869ffda3Schristos atom = ctf_str_add_ref_internal (fp, str, FALSE, FALSE, 0);
258*869ffda3Schristos if (!atom)
259*869ffda3Schristos return 0;
260*869ffda3Schristos
261*869ffda3Schristos atom->csa_external_offset = CTF_SET_STID (offset, CTF_STRTAB_1);
262*869ffda3Schristos return 1;
263*869ffda3Schristos }
264*869ffda3Schristos
265*869ffda3Schristos /* Remove a single ref. */
266*869ffda3Schristos void
ctf_str_remove_ref(ctf_file_t * fp,const char * str,uint32_t * ref)267*869ffda3Schristos ctf_str_remove_ref (ctf_file_t *fp, const char *str, uint32_t *ref)
268*869ffda3Schristos {
269*869ffda3Schristos ctf_str_atom_ref_t *aref, *anext;
270*869ffda3Schristos ctf_str_atom_t *atom = NULL;
271*869ffda3Schristos
272*869ffda3Schristos atom = ctf_dynhash_lookup (fp->ctf_str_atoms, str);
273*869ffda3Schristos if (!atom)
274*869ffda3Schristos return;
275*869ffda3Schristos
276*869ffda3Schristos for (aref = ctf_list_next (&atom->csa_refs); aref != NULL; aref = anext)
277*869ffda3Schristos {
278*869ffda3Schristos anext = ctf_list_next (aref);
279*869ffda3Schristos if (aref->caf_ref == ref)
280*869ffda3Schristos {
281*869ffda3Schristos ctf_list_delete (&atom->csa_refs, aref);
282*869ffda3Schristos free (aref);
283*869ffda3Schristos }
284*869ffda3Schristos }
285*869ffda3Schristos }
286*869ffda3Schristos
287*869ffda3Schristos /* A ctf_dynhash_iter_remove() callback that removes atoms later than a given
288*869ffda3Schristos snapshot ID. */
289*869ffda3Schristos static int
ctf_str_rollback_atom(void * key _libctf_unused_,void * value,void * arg)290*869ffda3Schristos ctf_str_rollback_atom (void *key _libctf_unused_, void *value, void *arg)
291*869ffda3Schristos {
292*869ffda3Schristos ctf_str_atom_t *atom = (ctf_str_atom_t *) value;
293*869ffda3Schristos ctf_snapshot_id_t *id = (ctf_snapshot_id_t *) arg;
294*869ffda3Schristos
295*869ffda3Schristos return (atom->csa_snapshot_id > id->snapshot_id);
296*869ffda3Schristos }
297*869ffda3Schristos
298*869ffda3Schristos /* Roll back, deleting all atoms created after a particular ID. */
299*869ffda3Schristos void
ctf_str_rollback(ctf_file_t * fp,ctf_snapshot_id_t id)300*869ffda3Schristos ctf_str_rollback (ctf_file_t *fp, ctf_snapshot_id_t id)
301*869ffda3Schristos {
302*869ffda3Schristos ctf_dynhash_iter_remove (fp->ctf_str_atoms, ctf_str_rollback_atom, &id);
303*869ffda3Schristos }
304*869ffda3Schristos
305*869ffda3Schristos /* An adaptor around ctf_purge_atom_refs. */
306*869ffda3Schristos static void
ctf_str_purge_one_atom_refs(void * key _libctf_unused_,void * value,void * arg _libctf_unused_)307*869ffda3Schristos ctf_str_purge_one_atom_refs (void *key _libctf_unused_, void *value,
308*869ffda3Schristos void *arg _libctf_unused_)
309*869ffda3Schristos {
310*869ffda3Schristos ctf_str_atom_t *atom = (ctf_str_atom_t *) value;
311*869ffda3Schristos ctf_str_purge_atom_refs (atom);
312*869ffda3Schristos }
313*869ffda3Schristos
314*869ffda3Schristos /* Remove all the recorded refs from the atoms table. */
315*869ffda3Schristos void
ctf_str_purge_refs(ctf_file_t * fp)316*869ffda3Schristos ctf_str_purge_refs (ctf_file_t *fp)
317*869ffda3Schristos {
318*869ffda3Schristos if (fp->ctf_str_num_refs > 0)
319*869ffda3Schristos ctf_dynhash_iter (fp->ctf_str_atoms, ctf_str_purge_one_atom_refs, NULL);
320*869ffda3Schristos fp->ctf_str_num_refs = 0;
321*869ffda3Schristos }
322*869ffda3Schristos
323*869ffda3Schristos /* Update a list of refs to the specified value. */
324*869ffda3Schristos static void
ctf_str_update_refs(ctf_str_atom_t * refs,uint32_t value)325*869ffda3Schristos ctf_str_update_refs (ctf_str_atom_t *refs, uint32_t value)
326*869ffda3Schristos {
327*869ffda3Schristos ctf_str_atom_ref_t *ref;
328*869ffda3Schristos
329*869ffda3Schristos for (ref = ctf_list_next (&refs->csa_refs); ref != NULL;
330*869ffda3Schristos ref = ctf_list_next (ref))
331*869ffda3Schristos *(ref->caf_ref) = value;
332*869ffda3Schristos }
333*869ffda3Schristos
334*869ffda3Schristos /* State shared across the strtab write process. */
335*869ffda3Schristos typedef struct ctf_strtab_write_state
336*869ffda3Schristos {
337*869ffda3Schristos /* Strtab we are writing, and the number of strings in it. */
338*869ffda3Schristos ctf_strs_writable_t *strtab;
339*869ffda3Schristos size_t strtab_count;
340*869ffda3Schristos
341*869ffda3Schristos /* Pointers to (existing) atoms in the atoms table, for qsorting. */
342*869ffda3Schristos ctf_str_atom_t **sorttab;
343*869ffda3Schristos
344*869ffda3Schristos /* Loop counter for sorttab population. */
345*869ffda3Schristos size_t i;
346*869ffda3Schristos
347*869ffda3Schristos /* The null-string atom (skipped during population). */
348*869ffda3Schristos ctf_str_atom_t *nullstr;
349*869ffda3Schristos } ctf_strtab_write_state_t;
350*869ffda3Schristos
351*869ffda3Schristos /* Count the number of entries in the strtab, and its length. */
352*869ffda3Schristos static void
ctf_str_count_strtab(void * key _libctf_unused_,void * value,void * arg)353*869ffda3Schristos ctf_str_count_strtab (void *key _libctf_unused_, void *value,
354*869ffda3Schristos void *arg)
355*869ffda3Schristos {
356*869ffda3Schristos ctf_str_atom_t *atom = (ctf_str_atom_t *) value;
357*869ffda3Schristos ctf_strtab_write_state_t *s = (ctf_strtab_write_state_t *) arg;
358*869ffda3Schristos
359*869ffda3Schristos /* We only factor in the length of items that have no offset and have refs:
360*869ffda3Schristos other items are in the external strtab, or will simply not be written out
361*869ffda3Schristos at all. They still contribute to the total count, though, because we still
362*869ffda3Schristos have to sort them. We add in the null string's length explicitly, outside
363*869ffda3Schristos this function, since it is explicitly written out even if it has no refs at
364*869ffda3Schristos all. */
365*869ffda3Schristos
366*869ffda3Schristos if (s->nullstr == atom)
367*869ffda3Schristos {
368*869ffda3Schristos s->strtab_count++;
369*869ffda3Schristos return;
370*869ffda3Schristos }
371*869ffda3Schristos
372*869ffda3Schristos if (!ctf_list_empty_p (&atom->csa_refs))
373*869ffda3Schristos {
374*869ffda3Schristos if (!atom->csa_external_offset)
375*869ffda3Schristos s->strtab->cts_len += strlen (atom->csa_str) + 1;
376*869ffda3Schristos s->strtab_count++;
377*869ffda3Schristos }
378*869ffda3Schristos }
379*869ffda3Schristos
380*869ffda3Schristos /* Populate the sorttab with pointers to the strtab atoms. */
381*869ffda3Schristos static void
ctf_str_populate_sorttab(void * key _libctf_unused_,void * value,void * arg)382*869ffda3Schristos ctf_str_populate_sorttab (void *key _libctf_unused_, void *value,
383*869ffda3Schristos void *arg)
384*869ffda3Schristos {
385*869ffda3Schristos ctf_str_atom_t *atom = (ctf_str_atom_t *) value;
386*869ffda3Schristos ctf_strtab_write_state_t *s = (ctf_strtab_write_state_t *) arg;
387*869ffda3Schristos
388*869ffda3Schristos /* Skip the null string. */
389*869ffda3Schristos if (s->nullstr == atom)
390*869ffda3Schristos return;
391*869ffda3Schristos
392*869ffda3Schristos /* Skip atoms with no refs. */
393*869ffda3Schristos if (!ctf_list_empty_p (&atom->csa_refs))
394*869ffda3Schristos s->sorttab[s->i++] = atom;
395*869ffda3Schristos }
396*869ffda3Schristos
397*869ffda3Schristos /* Sort the strtab. */
398*869ffda3Schristos static int
ctf_str_sort_strtab(const void * a,const void * b)399*869ffda3Schristos ctf_str_sort_strtab (const void *a, const void *b)
400*869ffda3Schristos {
401*869ffda3Schristos ctf_str_atom_t **one = (ctf_str_atom_t **) a;
402*869ffda3Schristos ctf_str_atom_t **two = (ctf_str_atom_t **) b;
403*869ffda3Schristos
404*869ffda3Schristos return (strcmp ((*one)->csa_str, (*two)->csa_str));
405*869ffda3Schristos }
406*869ffda3Schristos
407*869ffda3Schristos /* Write out and return a strtab containing all strings with recorded refs,
408*869ffda3Schristos adjusting the refs to refer to the corresponding string. The returned strtab
409*869ffda3Schristos may be NULL on error. Also populate the synthetic strtab with mappings from
410*869ffda3Schristos external strtab offsets to names, so we can look them up with ctf_strptr().
411*869ffda3Schristos Only external strtab offsets with references are added. */
412*869ffda3Schristos ctf_strs_writable_t
ctf_str_write_strtab(ctf_file_t * fp)413*869ffda3Schristos ctf_str_write_strtab (ctf_file_t *fp)
414*869ffda3Schristos {
415*869ffda3Schristos ctf_strs_writable_t strtab;
416*869ffda3Schristos ctf_str_atom_t *nullstr;
417*869ffda3Schristos uint32_t cur_stroff = 0;
418*869ffda3Schristos ctf_strtab_write_state_t s;
419*869ffda3Schristos ctf_str_atom_t **sorttab;
420*869ffda3Schristos size_t i;
421*869ffda3Schristos int any_external = 0;
422*869ffda3Schristos
423*869ffda3Schristos memset (&strtab, 0, sizeof (struct ctf_strs_writable));
424*869ffda3Schristos memset (&s, 0, sizeof (struct ctf_strtab_write_state));
425*869ffda3Schristos s.strtab = &strtab;
426*869ffda3Schristos
427*869ffda3Schristos nullstr = ctf_dynhash_lookup (fp->ctf_str_atoms, "");
428*869ffda3Schristos if (!nullstr)
429*869ffda3Schristos {
430*869ffda3Schristos ctf_dprintf ("Internal error: null string not found in strtab.\n");
431*869ffda3Schristos strtab.cts_strs = NULL;
432*869ffda3Schristos return strtab;
433*869ffda3Schristos }
434*869ffda3Schristos
435*869ffda3Schristos s.nullstr = nullstr;
436*869ffda3Schristos ctf_dynhash_iter (fp->ctf_str_atoms, ctf_str_count_strtab, &s);
437*869ffda3Schristos strtab.cts_len++; /* For the null string. */
438*869ffda3Schristos
439*869ffda3Schristos ctf_dprintf ("%lu bytes of strings in strtab.\n",
440*869ffda3Schristos (unsigned long) strtab.cts_len);
441*869ffda3Schristos
442*869ffda3Schristos /* Sort the strtab. Force the null string to be first. */
443*869ffda3Schristos sorttab = calloc (s.strtab_count, sizeof (ctf_str_atom_t *));
444*869ffda3Schristos if (!sorttab)
445*869ffda3Schristos goto oom;
446*869ffda3Schristos
447*869ffda3Schristos sorttab[0] = nullstr;
448*869ffda3Schristos s.i = 1;
449*869ffda3Schristos s.sorttab = sorttab;
450*869ffda3Schristos ctf_dynhash_iter (fp->ctf_str_atoms, ctf_str_populate_sorttab, &s);
451*869ffda3Schristos
452*869ffda3Schristos qsort (&sorttab[1], s.strtab_count - 1, sizeof (ctf_str_atom_t *),
453*869ffda3Schristos ctf_str_sort_strtab);
454*869ffda3Schristos
455*869ffda3Schristos if ((strtab.cts_strs = malloc (strtab.cts_len)) == NULL)
456*869ffda3Schristos goto oom_sorttab;
457*869ffda3Schristos
458*869ffda3Schristos if (!fp->ctf_syn_ext_strtab)
459*869ffda3Schristos fp->ctf_syn_ext_strtab = ctf_dynhash_create (ctf_hash_integer,
460*869ffda3Schristos ctf_hash_eq_integer,
461*869ffda3Schristos NULL, NULL);
462*869ffda3Schristos if (!fp->ctf_syn_ext_strtab)
463*869ffda3Schristos goto oom_strtab;
464*869ffda3Schristos
465*869ffda3Schristos /* Update all refs: also update the strtab appropriately. */
466*869ffda3Schristos for (i = 0; i < s.strtab_count; i++)
467*869ffda3Schristos {
468*869ffda3Schristos if (sorttab[i]->csa_external_offset)
469*869ffda3Schristos {
470*869ffda3Schristos /* External strtab entry: populate the synthetic external strtab.
471*869ffda3Schristos
472*869ffda3Schristos This is safe because you cannot ctf_rollback to before the point
473*869ffda3Schristos when a ctf_update is done, and the strtab is written at ctf_update
474*869ffda3Schristos time. So any atoms we reference here are sure to stick around
475*869ffda3Schristos until ctf_file_close. */
476*869ffda3Schristos
477*869ffda3Schristos any_external = 1;
478*869ffda3Schristos ctf_str_update_refs (sorttab[i], sorttab[i]->csa_external_offset);
479*869ffda3Schristos if (ctf_dynhash_insert (fp->ctf_syn_ext_strtab,
480*869ffda3Schristos (void *) (uintptr_t)
481*869ffda3Schristos sorttab[i]->csa_external_offset,
482*869ffda3Schristos (void *) sorttab[i]->csa_str) < 0)
483*869ffda3Schristos goto oom_strtab;
484*869ffda3Schristos sorttab[i]->csa_offset = sorttab[i]->csa_external_offset;
485*869ffda3Schristos }
486*869ffda3Schristos else
487*869ffda3Schristos {
488*869ffda3Schristos /* Internal strtab entry with refs: actually add to the string
489*869ffda3Schristos table. */
490*869ffda3Schristos
491*869ffda3Schristos ctf_str_update_refs (sorttab[i], cur_stroff);
492*869ffda3Schristos sorttab[i]->csa_offset = cur_stroff;
493*869ffda3Schristos strcpy (&strtab.cts_strs[cur_stroff], sorttab[i]->csa_str);
494*869ffda3Schristos cur_stroff += strlen (sorttab[i]->csa_str) + 1;
495*869ffda3Schristos }
496*869ffda3Schristos }
497*869ffda3Schristos free (sorttab);
498*869ffda3Schristos
499*869ffda3Schristos if (!any_external)
500*869ffda3Schristos {
501*869ffda3Schristos ctf_dynhash_destroy (fp->ctf_syn_ext_strtab);
502*869ffda3Schristos fp->ctf_syn_ext_strtab = NULL;
503*869ffda3Schristos }
504*869ffda3Schristos
505*869ffda3Schristos /* All the provisional strtab entries are now real strtab entries, and
506*869ffda3Schristos ctf_strptr() will find them there. The provisional offset now starts right
507*869ffda3Schristos beyond the new end of the strtab. */
508*869ffda3Schristos
509*869ffda3Schristos ctf_dynhash_empty (fp->ctf_prov_strtab);
510*869ffda3Schristos fp->ctf_str_prov_offset = strtab.cts_len + 1;
511*869ffda3Schristos return strtab;
512*869ffda3Schristos
513*869ffda3Schristos oom_strtab:
514*869ffda3Schristos free (strtab.cts_strs);
515*869ffda3Schristos strtab.cts_strs = NULL;
516*869ffda3Schristos oom_sorttab:
517*869ffda3Schristos free (sorttab);
518*869ffda3Schristos oom:
519*869ffda3Schristos return strtab;
520*869ffda3Schristos }
521