1 1.1 christos /* Miscellaneous utilities. 2 1.1.1.5 christos Copyright (C) 2019-2025 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.1.4 christos if (i->ctn_next_inner) 266 1.1.1.4 christos ctf_next_destroy (i->ctn_next_inner); 267 1.1 christos free (i); 268 1.1 christos } 269 1.1 christos 270 1.1 christos /* Copy a ctf_next_t. */ 271 1.1 christos 272 1.1 christos ctf_next_t * 273 1.1 christos ctf_next_copy (ctf_next_t *i) 274 1.1 christos { 275 1.1 christos ctf_next_t *i2; 276 1.1 christos 277 1.1 christos if ((i2 = ctf_next_create()) == NULL) 278 1.1 christos return NULL; 279 1.1 christos memcpy (i2, i, sizeof (struct ctf_next)); 280 1.1 christos 281 1.1.1.4 christos if (i2->ctn_next) 282 1.1.1.4 christos { 283 1.1.1.4 christos i2->ctn_next = ctf_next_copy (i2->ctn_next); 284 1.1.1.4 christos if (i2->ctn_next == NULL) 285 1.1.1.4 christos goto err_next; 286 1.1.1.4 christos } 287 1.1.1.4 christos 288 1.1.1.4 christos if (i2->ctn_next_inner) 289 1.1.1.4 christos { 290 1.1.1.4 christos i2->ctn_next_inner = ctf_next_copy (i2->ctn_next_inner); 291 1.1.1.4 christos if (i2->ctn_next_inner == NULL) 292 1.1.1.4 christos goto err_next_inner; 293 1.1.1.4 christos } 294 1.1.1.4 christos 295 1.1 christos if (i2->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted) 296 1.1 christos { 297 1.1 christos size_t els = ctf_dynhash_elements ((ctf_dynhash_t *) i->cu.ctn_h); 298 1.1 christos if ((i2->u.ctn_sorted_hkv = calloc (els, sizeof (ctf_next_hkv_t))) == NULL) 299 1.1.1.4 christos goto err_sorted_hkv; 300 1.1 christos memcpy (i2->u.ctn_sorted_hkv, i->u.ctn_sorted_hkv, 301 1.1 christos els * sizeof (ctf_next_hkv_t)); 302 1.1 christos } 303 1.1 christos return i2; 304 1.1.1.4 christos 305 1.1.1.4 christos err_sorted_hkv: 306 1.1.1.4 christos ctf_next_destroy (i2->ctn_next_inner); 307 1.1.1.4 christos err_next_inner: 308 1.1.1.4 christos ctf_next_destroy (i2->ctn_next); 309 1.1.1.4 christos err_next: 310 1.1.1.4 christos ctf_next_destroy (i2); 311 1.1.1.4 christos return NULL; 312 1.1 christos } 313