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