ctf-util.c revision 1.1.1.3 1 1.1 christos /* Miscellaneous utilities.
2 1.1.1.3 christos Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of libctf.
5 1.1 christos
6 1.1 christos libctf is free software; you can redistribute it and/or modify it under
7 1.1 christos the terms of the GNU General Public License as published by the Free
8 1.1 christos Software Foundation; either version 3, or (at your option) any later
9 1.1 christos version.
10 1.1 christos
11 1.1 christos This program is distributed in the hope that it will be useful, but
12 1.1 christos WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 1.1 christos See the GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program; see the file COPYING. If not see
18 1.1 christos <http://www.gnu.org/licenses/>. */
19 1.1 christos
20 1.1 christos #include <ctf-impl.h>
21 1.1 christos #include <string.h>
22 1.1.1.2 christos #include "ctf-endian.h"
23 1.1 christos
24 1.1 christos /* Simple doubly-linked list append routine. This implementation assumes that
25 1.1 christos each list element contains an embedded ctf_list_t as the first member.
26 1.1 christos An additional ctf_list_t is used to store the head (l_next) and tail
27 1.1 christos (l_prev) pointers. The current head and tail list elements have their
28 1.1 christos previous and next pointers set to NULL, respectively. */
29 1.1 christos
30 1.1 christos void
31 1.1 christos ctf_list_append (ctf_list_t *lp, void *newp)
32 1.1 christos {
33 1.1 christos ctf_list_t *p = lp->l_prev; /* p = tail list element. */
34 1.1 christos ctf_list_t *q = newp; /* q = new list element. */
35 1.1 christos
36 1.1 christos lp->l_prev = q;
37 1.1 christos q->l_prev = p;
38 1.1 christos q->l_next = NULL;
39 1.1 christos
40 1.1 christos if (p != NULL)
41 1.1 christos p->l_next = q;
42 1.1 christos else
43 1.1 christos lp->l_next = q;
44 1.1 christos }
45 1.1 christos
46 1.1 christos /* Prepend the specified existing element to the given ctf_list_t. The
47 1.1 christos existing pointer should be pointing at a struct with embedded ctf_list_t. */
48 1.1 christos
49 1.1 christos void
50 1.1 christos ctf_list_prepend (ctf_list_t * lp, void *newp)
51 1.1 christos {
52 1.1 christos ctf_list_t *p = newp; /* p = new list element. */
53 1.1 christos ctf_list_t *q = lp->l_next; /* q = head list element. */
54 1.1 christos
55 1.1 christos lp->l_next = p;
56 1.1 christos p->l_prev = NULL;
57 1.1 christos p->l_next = q;
58 1.1 christos
59 1.1 christos if (q != NULL)
60 1.1 christos q->l_prev = p;
61 1.1 christos else
62 1.1 christos lp->l_prev = p;
63 1.1 christos }
64 1.1 christos
65 1.1 christos /* Delete the specified existing element from the given ctf_list_t. The
66 1.1 christos existing pointer should be pointing at a struct with embedded ctf_list_t. */
67 1.1 christos
68 1.1 christos void
69 1.1 christos ctf_list_delete (ctf_list_t *lp, void *existing)
70 1.1 christos {
71 1.1 christos ctf_list_t *p = existing;
72 1.1 christos
73 1.1 christos if (p->l_prev != NULL)
74 1.1 christos p->l_prev->l_next = p->l_next;
75 1.1 christos else
76 1.1 christos lp->l_next = p->l_next;
77 1.1 christos
78 1.1 christos if (p->l_next != NULL)
79 1.1 christos p->l_next->l_prev = p->l_prev;
80 1.1 christos else
81 1.1 christos lp->l_prev = p->l_prev;
82 1.1 christos }
83 1.1 christos
84 1.1 christos /* Return 1 if the list is empty. */
85 1.1 christos
86 1.1 christos int
87 1.1 christos ctf_list_empty_p (ctf_list_t *lp)
88 1.1 christos {
89 1.1 christos return (lp->l_next == NULL && lp->l_prev == NULL);
90 1.1 christos }
91 1.1 christos
92 1.1 christos /* Splice one entire list onto the end of another one. The existing list is
93 1.1 christos emptied. */
94 1.1 christos
95 1.1 christos void
96 1.1 christos ctf_list_splice (ctf_list_t *lp, ctf_list_t *append)
97 1.1 christos {
98 1.1 christos if (ctf_list_empty_p (append))
99 1.1 christos return;
100 1.1 christos
101 1.1 christos if (lp->l_prev != NULL)
102 1.1 christos lp->l_prev->l_next = append->l_next;
103 1.1 christos else
104 1.1 christos lp->l_next = append->l_next;
105 1.1 christos
106 1.1 christos append->l_next->l_prev = lp->l_prev;
107 1.1 christos lp->l_prev = append->l_prev;
108 1.1 christos append->l_next = NULL;
109 1.1 christos append->l_prev = NULL;
110 1.1 christos }
111 1.1 christos
112 1.1.1.2 christos /* Convert a 32-bit ELF symbol to a ctf_link_sym_t. */
113 1.1 christos
114 1.1.1.2 christos ctf_link_sym_t *
115 1.1.1.2 christos ctf_elf32_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf32_Sym *src,
116 1.1.1.2 christos uint32_t symidx)
117 1.1.1.2 christos {
118 1.1.1.2 christos Elf32_Sym tmp;
119 1.1.1.2 christos int needs_flipping = 0;
120 1.1.1.2 christos
121 1.1.1.2 christos #ifdef WORDS_BIGENDIAN
122 1.1.1.2 christos if (fp->ctf_symsect_little_endian)
123 1.1.1.2 christos needs_flipping = 1;
124 1.1.1.2 christos #else
125 1.1.1.2 christos if (!fp->ctf_symsect_little_endian)
126 1.1.1.2 christos needs_flipping = 1;
127 1.1.1.2 christos #endif
128 1.1.1.2 christos
129 1.1.1.2 christos memcpy (&tmp, src, sizeof (Elf32_Sym));
130 1.1.1.2 christos if (needs_flipping)
131 1.1.1.2 christos {
132 1.1.1.2 christos swap_thing (tmp.st_name);
133 1.1.1.2 christos swap_thing (tmp.st_size);
134 1.1.1.2 christos swap_thing (tmp.st_shndx);
135 1.1.1.2 christos swap_thing (tmp.st_value);
136 1.1.1.2 christos }
137 1.1.1.2 christos /* The name must be in the external string table. */
138 1.1.1.2 christos if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
139 1.1.1.2 christos dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name;
140 1.1.1.2 christos else
141 1.1.1.2 christos dst->st_name = _CTF_NULLSTR;
142 1.1.1.2 christos dst->st_nameidx_set = 0;
143 1.1.1.2 christos dst->st_symidx = symidx;
144 1.1.1.2 christos dst->st_shndx = tmp.st_shndx;
145 1.1.1.2 christos dst->st_type = ELF32_ST_TYPE (tmp.st_info);
146 1.1.1.2 christos dst->st_value = tmp.st_value;
147 1.1.1.2 christos
148 1.1.1.2 christos return dst;
149 1.1.1.2 christos }
150 1.1.1.2 christos
151 1.1.1.2 christos /* Convert a 64-bit ELF symbol to a ctf_link_sym_t. */
152 1.1.1.2 christos
153 1.1.1.2 christos ctf_link_sym_t *
154 1.1.1.2 christos ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf64_Sym *src,
155 1.1.1.2 christos uint32_t symidx)
156 1.1.1.2 christos {
157 1.1.1.2 christos Elf64_Sym tmp;
158 1.1.1.2 christos int needs_flipping = 0;
159 1.1.1.2 christos
160 1.1.1.2 christos #ifdef WORDS_BIGENDIAN
161 1.1.1.2 christos if (fp->ctf_symsect_little_endian)
162 1.1.1.2 christos needs_flipping = 1;
163 1.1.1.2 christos #else
164 1.1.1.2 christos if (!fp->ctf_symsect_little_endian)
165 1.1.1.2 christos needs_flipping = 1;
166 1.1.1.2 christos #endif
167 1.1.1.2 christos
168 1.1.1.2 christos memcpy (&tmp, src, sizeof (Elf64_Sym));
169 1.1.1.2 christos if (needs_flipping)
170 1.1.1.2 christos {
171 1.1.1.2 christos swap_thing (tmp.st_name);
172 1.1.1.2 christos swap_thing (tmp.st_size);
173 1.1.1.2 christos swap_thing (tmp.st_shndx);
174 1.1.1.2 christos swap_thing (tmp.st_value);
175 1.1.1.2 christos }
176 1.1.1.2 christos
177 1.1.1.2 christos /* The name must be in the external string table. */
178 1.1.1.2 christos if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
179 1.1.1.2 christos dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name;
180 1.1.1.2 christos else
181 1.1.1.2 christos dst->st_name = _CTF_NULLSTR;
182 1.1.1.2 christos dst->st_nameidx_set = 0;
183 1.1.1.2 christos dst->st_symidx = symidx;
184 1.1.1.2 christos dst->st_shndx = tmp.st_shndx;
185 1.1.1.2 christos dst->st_type = ELF32_ST_TYPE (tmp.st_info);
186 1.1.1.2 christos
187 1.1.1.2 christos /* We only care if the value is zero, so avoid nonzeroes turning into
188 1.1.1.2 christos zeroes. */
189 1.1.1.2 christos if (_libctf_unlikely_ (tmp.st_value != 0 && ((uint32_t) tmp.st_value == 0)))
190 1.1.1.2 christos dst->st_value = 1;
191 1.1.1.2 christos else
192 1.1.1.2 christos dst->st_value = (uint32_t) tmp.st_value;
193 1.1 christos
194 1.1 christos return dst;
195 1.1 christos }
196 1.1 christos
197 1.1 christos /* A string appender working on dynamic strings. Returns NULL on OOM. */
198 1.1 christos
199 1.1 christos char *
200 1.1 christos ctf_str_append (char *s, const char *append)
201 1.1 christos {
202 1.1 christos size_t s_len = 0;
203 1.1 christos
204 1.1 christos if (append == NULL)
205 1.1 christos return s;
206 1.1 christos
207 1.1 christos if (s != NULL)
208 1.1 christos s_len = strlen (s);
209 1.1 christos
210 1.1 christos size_t append_len = strlen (append);
211 1.1 christos
212 1.1 christos if ((s = realloc (s, s_len + append_len + 1)) == NULL)
213 1.1 christos return NULL;
214 1.1 christos
215 1.1 christos memcpy (s + s_len, append, append_len);
216 1.1 christos s[s_len + append_len] = '\0';
217 1.1 christos
218 1.1 christos return s;
219 1.1 christos }
220 1.1 christos
221 1.1 christos /* A version of ctf_str_append that returns the old string on OOM. */
222 1.1 christos
223 1.1 christos char *
224 1.1 christos ctf_str_append_noerr (char *s, const char *append)
225 1.1 christos {
226 1.1 christos char *new_s;
227 1.1 christos
228 1.1 christos new_s = ctf_str_append (s, append);
229 1.1 christos if (!new_s)
230 1.1 christos return s;
231 1.1 christos return new_s;
232 1.1 christos }
233 1.1 christos
234 1.1 christos /* Store the specified error code into errp if it is non-NULL, and then
235 1.1 christos return NULL for the benefit of the caller. */
236 1.1 christos
237 1.1 christos void *
238 1.1 christos ctf_set_open_errno (int *errp, int error)
239 1.1 christos {
240 1.1 christos if (errp != NULL)
241 1.1 christos *errp = error;
242 1.1 christos return NULL;
243 1.1 christos }
244 1.1 christos
245 1.1 christos /* Create a ctf_next_t. */
246 1.1 christos
247 1.1 christos ctf_next_t *
248 1.1 christos ctf_next_create (void)
249 1.1 christos {
250 1.1 christos return calloc (1, sizeof (struct ctf_next));
251 1.1 christos }
252 1.1 christos
253 1.1 christos /* Destroy a ctf_next_t, for early exit from iterators. */
254 1.1 christos
255 1.1 christos void
256 1.1 christos ctf_next_destroy (ctf_next_t *i)
257 1.1 christos {
258 1.1 christos if (i == NULL)
259 1.1 christos return;
260 1.1 christos
261 1.1 christos if (i->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted)
262 1.1 christos free (i->u.ctn_sorted_hkv);
263 1.1.1.2 christos if (i->ctn_next)
264 1.1.1.2 christos ctf_next_destroy (i->ctn_next);
265 1.1 christos free (i);
266 1.1 christos }
267 1.1 christos
268 1.1 christos /* Copy a ctf_next_t. */
269 1.1 christos
270 1.1 christos ctf_next_t *
271 1.1 christos ctf_next_copy (ctf_next_t *i)
272 1.1 christos {
273 1.1 christos ctf_next_t *i2;
274 1.1 christos
275 1.1 christos if ((i2 = ctf_next_create()) == NULL)
276 1.1 christos return NULL;
277 1.1 christos memcpy (i2, i, sizeof (struct ctf_next));
278 1.1 christos
279 1.1 christos if (i2->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted)
280 1.1 christos {
281 1.1 christos size_t els = ctf_dynhash_elements ((ctf_dynhash_t *) i->cu.ctn_h);
282 1.1 christos if ((i2->u.ctn_sorted_hkv = calloc (els, sizeof (ctf_next_hkv_t))) == NULL)
283 1.1 christos {
284 1.1 christos free (i2);
285 1.1 christos return NULL;
286 1.1 christos }
287 1.1 christos memcpy (i2->u.ctn_sorted_hkv, i->u.ctn_sorted_hkv,
288 1.1 christos els * sizeof (ctf_next_hkv_t));
289 1.1 christos }
290 1.1 christos return i2;
291 1.1 christos }
292