1 /* CTF string table management.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
4 This file is part of libctf.
6 libctf is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING. If not see
18 <http://www.gnu.org/licenses/>. */
24 static ctf_str_atom_t
*
25 ctf_str_add_ref_internal (ctf_dict_t
*fp
, const char *str
,
26 int flags
, uint32_t *ref
);
28 /* Convert an encoded CTF string name into a pointer to a C string, possibly
29 using an explicit internal provisional strtab rather than the fp-based
32 ctf_strraw_explicit (ctf_dict_t
*fp
, uint32_t name
, ctf_strs_t
*strtab
)
34 ctf_strs_t
*ctsp
= &fp
->ctf_str
[CTF_NAME_STID (name
)];
36 if ((CTF_NAME_STID (name
) == CTF_STRTAB_0
) && (strtab
!= NULL
))
39 /* If this name is in the external strtab, and there is a synthetic
40 strtab, use it in preference. (This is used to add the set of strings
41 -- symbol names, etc -- the linker knows about before the strtab is
44 if (CTF_NAME_STID (name
) == CTF_STRTAB_1
45 && fp
->ctf_syn_ext_strtab
!= NULL
)
46 return ctf_dynhash_lookup (fp
->ctf_syn_ext_strtab
,
47 (void *) (uintptr_t) name
);
49 /* If the name is in the internal strtab, and the name offset is beyond
50 the end of the ctsp->cts_len but below the ctf_str_prov_offset, this is
51 a provisional string added by ctf_str_add*() but not yet built into a
52 real strtab: get the value out of the ctf_prov_strtab. */
54 if (CTF_NAME_STID (name
) == CTF_STRTAB_0
55 && name
>= ctsp
->cts_len
&& name
< fp
->ctf_str_prov_offset
)
56 return ctf_dynhash_lookup (fp
->ctf_prov_strtab
,
57 (void *) (uintptr_t) name
);
59 if (ctsp
->cts_strs
!= NULL
&& CTF_NAME_OFFSET (name
) < ctsp
->cts_len
)
60 return (ctsp
->cts_strs
+ CTF_NAME_OFFSET (name
));
62 /* String table not loaded or corrupt offset. */
66 /* Convert an encoded CTF string name into a pointer to a C string by looking
67 up the appropriate string table buffer and then adding the offset. */
69 ctf_strraw (ctf_dict_t
*fp
, uint32_t name
)
71 return ctf_strraw_explicit (fp
, name
, NULL
);
74 /* Return a guaranteed-non-NULL pointer to the string with the given CTF
77 ctf_strptr (ctf_dict_t
*fp
, uint32_t name
)
79 const char *s
= ctf_strraw (fp
, name
);
80 return (s
!= NULL
? s
: "(?)");
83 /* As above, but return info on what is wrong in more detail.
84 (Used for type lookups.) */
87 ctf_strptr_validate (ctf_dict_t
*fp
, uint32_t name
)
89 const char *str
= ctf_strraw (fp
, name
);
93 if (CTF_NAME_STID (name
) == CTF_STRTAB_1
94 && fp
->ctf_syn_ext_strtab
== NULL
95 && fp
->ctf_str
[CTF_NAME_STID (name
)].cts_strs
== NULL
)
97 ctf_set_errno (fp
, ECTF_STRTAB
);
101 ctf_set_errno (fp
, ECTF_BADNAME
);
107 /* Remove all refs to a given atom. */
109 ctf_str_purge_atom_refs (ctf_str_atom_t
*atom
)
111 ctf_str_atom_ref_t
*ref
, *next
;
112 ctf_str_atom_ref_movable_t
*movref
, *movnext
;
114 for (ref
= ctf_list_next (&atom
->csa_refs
); ref
!= NULL
; ref
= next
)
116 next
= ctf_list_next (ref
);
117 ctf_list_delete (&atom
->csa_refs
, ref
);
121 for (movref
= ctf_list_next (&atom
->csa_movable_refs
);
122 movref
!= NULL
; movref
= movnext
)
124 movnext
= ctf_list_next (movref
);
125 ctf_list_delete (&atom
->csa_movable_refs
, movref
);
127 ctf_dynhash_remove (movref
->caf_movable_refs
, movref
);
135 ctf_str_free_atom (void *a
)
137 ctf_str_atom_t
*atom
= a
;
139 ctf_str_purge_atom_refs (atom
);
141 if (atom
->csa_flags
& CTF_STR_ATOM_FREEABLE
)
142 free (atom
->csa_str
);
147 /* Create the atoms table. There is always at least one atom in it, the null
148 string: but also pull in atoms from the internal strtab. (We rely on
149 calls to ctf_str_add_external to populate external strtab entries, since
150 these are often not quite the same as what appears in any external
151 strtab, and the external strtab is often huge and best not aggressively
154 ctf_str_create_atoms (ctf_dict_t
*fp
)
158 fp
->ctf_str_atoms
= ctf_dynhash_create (ctf_hash_string
, ctf_hash_eq_string
,
159 NULL
, ctf_str_free_atom
);
160 if (!fp
->ctf_str_atoms
)
163 if (!fp
->ctf_prov_strtab
)
164 fp
->ctf_prov_strtab
= ctf_dynhash_create (ctf_hash_integer
,
167 if (!fp
->ctf_prov_strtab
)
168 goto oom_prov_strtab
;
170 fp
->ctf_str_movable_refs
= ctf_dynhash_create (ctf_hash_integer
,
173 if (!fp
->ctf_str_movable_refs
)
174 goto oom_movable_refs
;
177 ctf_str_add (fp
, "");
181 /* Pull in all the strings in the strtab as new atoms. The provisional
182 strtab must be empty at this point, so there is no need to populate
183 atoms from it as well. Types in this subset are frozen and readonly,
184 so the refs list and movable refs list need not be populated. */
186 for (i
= 0; i
< fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;
187 i
+= strlen (&fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
[i
]) + 1)
189 ctf_str_atom_t
*atom
;
191 if (fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
[i
] == 0)
194 atom
= ctf_str_add_ref_internal (fp
, &fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
[i
],
200 atom
->csa_offset
= i
;
203 fp
->ctf_str_prov_offset
= fp
->ctf_str
[CTF_STRTAB_0
].cts_len
+ 1;
208 ctf_dynhash_destroy (fp
->ctf_str_movable_refs
);
209 fp
->ctf_str_movable_refs
= NULL
;
211 ctf_dynhash_destroy (fp
->ctf_prov_strtab
);
212 fp
->ctf_prov_strtab
= NULL
;
214 ctf_dynhash_destroy (fp
->ctf_str_atoms
);
215 fp
->ctf_str_atoms
= NULL
;
219 /* Destroy the atoms table and associated refs. */
221 ctf_str_free_atoms (ctf_dict_t
*fp
)
223 ctf_dynhash_destroy (fp
->ctf_prov_strtab
);
224 ctf_dynhash_destroy (fp
->ctf_str_atoms
);
225 ctf_dynhash_destroy (fp
->ctf_str_movable_refs
);
226 if (fp
->ctf_dynstrtab
)
228 free (fp
->ctf_dynstrtab
->cts_strs
);
229 free (fp
->ctf_dynstrtab
);
233 #define CTF_STR_ADD_REF 0x1
234 #define CTF_STR_PROVISIONAL 0x2
235 #define CTF_STR_MOVABLE 0x4
237 /* Allocate a ref and bind it into a ref list. */
239 static ctf_str_atom_ref_t
*
240 aref_create (ctf_dict_t
*fp
, ctf_str_atom_t
*atom
, uint32_t *ref
, int flags
)
242 ctf_str_atom_ref_t
*aref
;
243 size_t s
= sizeof (struct ctf_str_atom_ref
);
245 if (flags
& CTF_STR_MOVABLE
)
246 s
= sizeof (struct ctf_str_atom_ref_movable
);
255 /* Movable refs get a backpointer to them in ctf_str_movable_refs, and a
256 pointer to ctf_str_movable_refs itself in the ref, for use when freeing
257 refs: they can be moved later in batches via a call to
258 ctf_str_move_refs. */
260 if (flags
& CTF_STR_MOVABLE
)
262 ctf_str_atom_ref_movable_t
*movref
= (ctf_str_atom_ref_movable_t
*) aref
;
264 movref
->caf_movable_refs
= fp
->ctf_str_movable_refs
;
266 if (ctf_dynhash_insert (fp
->ctf_str_movable_refs
, ref
, aref
) < 0)
271 ctf_list_append (&atom
->csa_movable_refs
, movref
);
274 ctf_list_append (&atom
->csa_refs
, aref
);
279 /* Add a string to the atoms table, copying the passed-in string if
280 necessary. Return the atom added. Return NULL only when out of memory
281 (and do not touch the passed-in string in that case).
283 Possibly add a provisional entry for this string to the provisional
284 strtab. If the string is in the provisional strtab, update its ref list
285 with the passed-in ref, causing the ref to be updated when the strtab is
288 static ctf_str_atom_t
*
289 ctf_str_add_ref_internal (ctf_dict_t
*fp
, const char *str
,
290 int flags
, uint32_t *ref
)
293 ctf_str_atom_t
*atom
= NULL
;
296 atom
= ctf_dynhash_lookup (fp
->ctf_str_atoms
, str
);
298 /* Existing atoms get refs added only if they are provisional:
299 non-provisional strings already have a fixed strtab offset, and just
300 get their ref updated immediately, since its value cannot change. */
304 if (!ctf_dynhash_lookup (fp
->ctf_prov_strtab
, (void *) (uintptr_t)
307 if (flags
& CTF_STR_ADD_REF
)
309 if (atom
->csa_external_offset
)
310 *ref
= atom
->csa_external_offset
;
312 *ref
= atom
->csa_offset
;
317 if (flags
& CTF_STR_ADD_REF
)
319 if (!aref_create (fp
, atom
, ref
, flags
))
321 ctf_set_errno (fp
, ENOMEM
);
331 if ((atom
= malloc (sizeof (struct ctf_str_atom
))) == NULL
)
333 memset (atom
, 0, sizeof (struct ctf_str_atom
));
335 /* Don't allocate new strings if this string is within an mmapped
338 if ((unsigned char *) str
< (unsigned char *) fp
->ctf_data_mmapped
339 || (unsigned char *) str
> (unsigned char *) fp
->ctf_data_mmapped
+ fp
->ctf_data_mmapped_len
)
341 if ((newstr
= strdup (str
)) == NULL
)
343 atom
->csa_flags
|= CTF_STR_ATOM_FREEABLE
;
344 atom
->csa_str
= newstr
;
347 atom
->csa_str
= (char *) str
;
349 if (ctf_dynhash_insert (fp
->ctf_str_atoms
, atom
->csa_str
, atom
) < 0)
353 atom
->csa_snapshot_id
= fp
->ctf_snapshots
;
355 /* New atoms marked provisional go into the provisional strtab, and get a
358 if (flags
& CTF_STR_PROVISIONAL
)
360 atom
->csa_offset
= fp
->ctf_str_prov_offset
;
362 if (ctf_dynhash_insert (fp
->ctf_prov_strtab
, (void *) (uintptr_t)
363 atom
->csa_offset
, (void *) atom
->csa_str
) < 0)
366 fp
->ctf_str_prov_offset
+= strlen (atom
->csa_str
) + 1;
368 if (flags
& CTF_STR_ADD_REF
)
370 if (!aref_create (fp
, atom
, ref
, flags
))
379 ctf_dynhash_remove (fp
->ctf_str_atoms
, atom
->csa_str
);
382 ctf_set_errno (fp
, ENOMEM
);
386 /* Add a string to the atoms table, without augmenting the ref list for this
387 string: return a 'provisional offset' which can be used to return this string
388 until ctf_str_write_strtab is called, or 0 on failure. (Everywhere the
389 provisional offset is assigned to should be added as a ref using
390 ctf_str_add_ref() as well.) */
392 ctf_str_add (ctf_dict_t
*fp
, const char *str
)
394 ctf_str_atom_t
*atom
;
399 atom
= ctf_str_add_ref_internal (fp
, str
, CTF_STR_PROVISIONAL
, 0);
403 return atom
->csa_offset
;
406 /* Like ctf_str_add(), but additionally augment the atom's refs list with the
407 passed-in ref, whether or not the string is already present. There is no
408 attempt to deduplicate the refs list (but duplicates are harmless). */
410 ctf_str_add_ref (ctf_dict_t
*fp
, const char *str
, uint32_t *ref
)
412 ctf_str_atom_t
*atom
;
417 atom
= ctf_str_add_ref_internal (fp
, str
, CTF_STR_ADD_REF
418 | CTF_STR_PROVISIONAL
, ref
);
422 return atom
->csa_offset
;
425 /* Like ctf_str_add_ref(), but note that the ref may be moved later on. */
427 ctf_str_add_movable_ref (ctf_dict_t
*fp
, const char *str
, uint32_t *ref
)
429 ctf_str_atom_t
*atom
;
434 atom
= ctf_str_add_ref_internal (fp
, str
, CTF_STR_ADD_REF
435 | CTF_STR_PROVISIONAL
436 | CTF_STR_MOVABLE
, ref
);
440 return atom
->csa_offset
;
443 /* Add an external strtab reference at OFFSET. Returns zero if the addition
444 failed, nonzero otherwise. */
446 ctf_str_add_external (ctf_dict_t
*fp
, const char *str
, uint32_t offset
)
448 ctf_str_atom_t
*atom
;
453 atom
= ctf_str_add_ref_internal (fp
, str
, 0, 0);
457 atom
->csa_external_offset
= CTF_SET_STID (offset
, CTF_STRTAB_1
);
459 if (!fp
->ctf_syn_ext_strtab
)
460 fp
->ctf_syn_ext_strtab
= ctf_dynhash_create (ctf_hash_integer
,
463 if (!fp
->ctf_syn_ext_strtab
)
465 ctf_set_errno (fp
, ENOMEM
);
469 if (ctf_dynhash_insert (fp
->ctf_syn_ext_strtab
,
471 atom
->csa_external_offset
,
472 (void *) atom
->csa_str
) < 0)
474 /* No need to bother freeing the syn_ext_strtab: it will get freed at
475 ctf_str_write_strtab time if unreferenced. */
476 ctf_set_errno (fp
, ENOMEM
);
483 /* Note that refs have moved from (SRC, LEN) to DEST. We use the movable
484 refs backpointer for this, because it is done an amortized-constant
485 number of times during structure member and enumerand addition, and if we
486 did a linear search this would turn such addition into an O(n^2)
487 operation. Even this is not linear, but it's better than that. */
489 ctf_str_move_refs (ctf_dict_t
*fp
, void *src
, size_t len
, void *dest
)
496 for (p
= (uintptr_t) src
; p
- (uintptr_t) src
< len
; p
++)
498 ctf_str_atom_ref_movable_t
*ref
;
500 if ((ref
= ctf_dynhash_lookup (fp
->ctf_str_movable_refs
,
501 (ctf_str_atom_ref_t
*) p
)) != NULL
)
505 ref
->caf_ref
= (uint32_t *) (((uintptr_t) ref
->caf_ref
+
506 (uintptr_t) dest
- (uintptr_t) src
));
507 ctf_dynhash_remove (fp
->ctf_str_movable_refs
,
508 (ctf_str_atom_ref_t
*) p
);
509 out_of_memory
= ctf_dynhash_insert (fp
->ctf_str_movable_refs
,
511 assert (out_of_memory
== 0);
518 /* Remove a single ref. */
520 ctf_str_remove_ref (ctf_dict_t
*fp
, const char *str
, uint32_t *ref
)
522 ctf_str_atom_ref_t
*aref
, *anext
;
523 ctf_str_atom_ref_movable_t
*amovref
, *amovnext
;
524 ctf_str_atom_t
*atom
= NULL
;
526 atom
= ctf_dynhash_lookup (fp
->ctf_str_atoms
, str
);
530 for (aref
= ctf_list_next (&atom
->csa_refs
); aref
!= NULL
; aref
= anext
)
532 anext
= ctf_list_next (aref
);
533 if (aref
->caf_ref
== ref
)
535 ctf_list_delete (&atom
->csa_refs
, aref
);
540 for (amovref
= ctf_list_next (&atom
->csa_movable_refs
);
541 amovref
!= NULL
; amovref
= amovnext
)
543 amovnext
= ctf_list_next (amovref
);
544 if (amovref
->caf_ref
== ref
)
546 ctf_list_delete (&atom
->csa_movable_refs
, amovref
);
547 ctf_dynhash_remove (fp
->ctf_str_movable_refs
, ref
);
553 /* A ctf_dynhash_iter_remove() callback that removes atoms later than a given
554 snapshot ID. External atoms are never removed, because they came from the
555 linker string table and are still present even if you roll back type
558 ctf_str_rollback_atom (void *key _libctf_unused_
, void *value
, void *arg
)
560 ctf_str_atom_t
*atom
= (ctf_str_atom_t
*) value
;
561 ctf_snapshot_id_t
*id
= (ctf_snapshot_id_t
*) arg
;
563 return (atom
->csa_snapshot_id
> id
->snapshot_id
)
564 && (atom
->csa_external_offset
== 0);
567 /* Roll back, deleting all (internal) atoms created after a particular ID. */
569 ctf_str_rollback (ctf_dict_t
*fp
, ctf_snapshot_id_t id
)
571 ctf_dynhash_iter_remove (fp
->ctf_str_atoms
, ctf_str_rollback_atom
, &id
);
574 /* An adaptor around ctf_purge_atom_refs. */
576 ctf_str_purge_one_atom_refs (void *key _libctf_unused_
, void *value
,
577 void *arg _libctf_unused_
)
579 ctf_str_atom_t
*atom
= (ctf_str_atom_t
*) value
;
581 ctf_str_purge_atom_refs (atom
);
584 /* Remove all the recorded refs from the atoms table. */
586 ctf_str_purge_refs (ctf_dict_t
*fp
)
588 ctf_dynhash_iter (fp
->ctf_str_atoms
, ctf_str_purge_one_atom_refs
, NULL
);
591 /* Update a list of refs to the specified value. */
593 ctf_str_update_refs (ctf_str_atom_t
*refs
, uint32_t value
)
595 ctf_str_atom_ref_t
*ref
;
596 ctf_str_atom_ref_movable_t
*movref
;
598 for (ref
= ctf_list_next (&refs
->csa_refs
); ref
!= NULL
;
599 ref
= ctf_list_next (ref
))
600 *(ref
->caf_ref
) = value
;
602 for (movref
= ctf_list_next (&refs
->csa_movable_refs
);
603 movref
!= NULL
; movref
= ctf_list_next (movref
))
604 *(movref
->caf_ref
) = value
;
607 /* Sort the strtab. */
609 ctf_str_sort_strtab (const void *a
, const void *b
)
611 ctf_str_atom_t
**one
= (ctf_str_atom_t
**) a
;
612 ctf_str_atom_t
**two
= (ctf_str_atom_t
**) b
;
614 return (strcmp ((*one
)->csa_str
, (*two
)->csa_str
));
617 /* Write out and return a strtab containing all strings with recorded refs,
618 adjusting the refs to refer to the corresponding string. The returned
619 strtab is already assigned to strtab 0 in this dict, is owned by this
620 dict, and may be NULL on error. Also populate the synthetic strtab with
621 mappings from external strtab offsets to names, so we can look them up
622 with ctf_strptr(). Only external strtab offsets with references are
625 As a side effect, replaces the strtab of the current dict with the newly-
626 generated strtab. This is an exception to the general rule that
627 serialization does not change the dict passed in, because the alternative
628 is to copy the entire atoms table on every reserialization just to avoid
629 modifying the original, which is excessively costly for minimal gain.
631 We use the lazy man's approach and double memory costs by always storing
632 atoms as individually allocated entities whenever they come from anywhere
633 but a freshly-opened, mmapped dict, even though after serialization there
634 is another copy in the strtab; this ensures that ctf_strptr()-returned
635 pointers to them remain valid for the lifetime of the dict.
637 This is all rendered more complex because if a dict is ctf_open()ed it
638 will have a bunch of strings in its strtab already, and their strtab
639 offsets can never change (without piles of complexity to rescan the
640 entire dict just to get all the offsets to all of them into the atoms
641 table). Entries below the existing strtab limit are just copied into the
642 new dict: entries above it are new, and are are sorted first, then
643 appended to it. The sorting is purely a compression-efficiency
644 improvement, and we get nearly as good an improvement from sorting big
645 chunks like this as we would from sorting the whole thing. */
647 const ctf_strs_writable_t
*
648 ctf_str_write_strtab (ctf_dict_t
*fp
)
650 ctf_strs_writable_t
*strtab
;
651 size_t strtab_count
= 0;
652 uint32_t cur_stroff
= 0;
653 ctf_str_atom_t
**sorttab
;
654 ctf_next_t
*it
= NULL
;
659 int any_external
= 0;
661 strtab
= calloc (1, sizeof (ctf_strs_writable_t
));
665 /* The strtab contains the existing string table at its start: figure out
666 how many new strings we need to add. We only need to add new strings
667 that have no external offset, that have refs, and that are found in the
668 provisional strtab. If the existing strtab is empty we also need to
669 add the null string at its start. */
671 strtab
->cts_len
= fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;
673 if (strtab
->cts_len
== 0)
676 strtab
->cts_len
++; /* For the \0. */
679 /* Count new entries in the strtab: i.e. entries in the provisional
680 strtab. Ignore any entry for \0, entries which ended up in the
681 external strtab, and unreferenced entries. */
683 while ((err
= ctf_dynhash_next (fp
->ctf_prov_strtab
, &it
, NULL
, &v
)) == 0)
685 const char *str
= (const char *) v
;
686 ctf_str_atom_t
*atom
;
688 atom
= ctf_dynhash_lookup (fp
->ctf_str_atoms
, str
);
689 if (!ctf_assert (fp
, atom
))
692 if (atom
->csa_str
[0] == 0 || atom
->csa_external_offset
693 || (ctf_list_empty_p (&atom
->csa_refs
)
694 && ctf_list_empty_p (&atom
->csa_movable_refs
)))
697 strtab
->cts_len
+= strlen (atom
->csa_str
) + 1;
700 if (err
!= ECTF_NEXT_END
)
702 ctf_dprintf ("ctf_str_write_strtab: error counting strtab entries: %s\n",
707 ctf_dprintf ("%lu bytes of strings in strtab: %lu pre-existing.\n",
708 (unsigned long) strtab
->cts_len
,
709 (unsigned long) fp
->ctf_str
[CTF_STRTAB_0
].cts_len
);
711 /* Sort the new part of the strtab. */
713 sorttab
= calloc (strtab_count
, sizeof (ctf_str_atom_t
*));
716 ctf_set_errno (fp
, ENOMEM
);
721 while ((err
= ctf_dynhash_next (fp
->ctf_prov_strtab
, &it
, NULL
, &v
)) == 0)
723 ctf_str_atom_t
*atom
;
725 atom
= ctf_dynhash_lookup (fp
->ctf_str_atoms
, v
);
726 if (!ctf_assert (fp
, atom
))
729 if (atom
->csa_str
[0] == 0 || atom
->csa_external_offset
730 || (ctf_list_empty_p (&atom
->csa_refs
)
731 && ctf_list_empty_p (&atom
->csa_movable_refs
)))
737 qsort (sorttab
, strtab_count
, sizeof (ctf_str_atom_t
*),
738 ctf_str_sort_strtab
);
740 if ((strtab
->cts_strs
= malloc (strtab
->cts_len
)) == NULL
)
743 cur_stroff
= fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;
747 strtab
->cts_strs
[0] = 0;
751 memcpy (strtab
->cts_strs
, fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
,
752 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
);
754 /* Work over the sorttab, add its strings to the strtab, and remember
755 where they are in the csa_offset for the appropriate atom. No ref
756 updating is done at this point, because refs might well relate to
757 already-existing strings, or external strings, which do not need adding
758 to the strtab and may not be in the sorttab. */
760 for (i
= 0; i
< strtab_count
; i
++)
762 sorttab
[i
]->csa_offset
= cur_stroff
;
763 strcpy (&strtab
->cts_strs
[cur_stroff
], sorttab
[i
]->csa_str
);
764 cur_stroff
+= strlen (sorttab
[i
]->csa_str
) + 1;
769 /* Update all refs, then purge them as no longer necessary: also update
770 the strtab appropriately. */
772 while ((err
= ctf_dynhash_next (fp
->ctf_str_atoms
, &it
, NULL
, &v
)) == 0)
774 ctf_str_atom_t
*atom
= (ctf_str_atom_t
*) v
;
777 if (ctf_list_empty_p (&atom
->csa_refs
) &&
778 ctf_list_empty_p (&atom
->csa_movable_refs
))
781 if (atom
->csa_external_offset
)
784 offset
= atom
->csa_external_offset
;
787 offset
= atom
->csa_offset
;
788 ctf_str_update_refs (atom
, offset
);
790 if (err
!= ECTF_NEXT_END
)
792 ctf_dprintf ("ctf_str_write_strtab: error iterating over atoms while updating refs: %s\n",
796 ctf_str_purge_refs (fp
);
800 ctf_dynhash_destroy (fp
->ctf_syn_ext_strtab
);
801 fp
->ctf_syn_ext_strtab
= NULL
;
804 /* Replace the old strtab with the new one in this dict. */
806 if (fp
->ctf_dynstrtab
)
808 free (fp
->ctf_dynstrtab
->cts_strs
);
809 free (fp
->ctf_dynstrtab
);
812 fp
->ctf_dynstrtab
= strtab
;
813 fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
= strtab
->cts_strs
;
814 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
= strtab
->cts_len
;
816 /* All the provisional strtab entries are now real strtab entries, and
817 ctf_strptr() will find them there. The provisional offset now starts right
818 beyond the new end of the strtab. */
820 ctf_dynhash_empty (fp
->ctf_prov_strtab
);
821 fp
->ctf_str_prov_offset
= strtab
->cts_len
+ 1;