18dffb485Schristos /* Miscellaneous utilities. 2*c9055873Schristos Copyright (C) 2019-2024 Free Software Foundation, Inc. 38dffb485Schristos 48dffb485Schristos This file is part of libctf. 58dffb485Schristos 68dffb485Schristos libctf is free software; you can redistribute it and/or modify it under 78dffb485Schristos the terms of the GNU General Public License as published by the Free 88dffb485Schristos Software Foundation; either version 3, or (at your option) any later 98dffb485Schristos version. 108dffb485Schristos 118dffb485Schristos This program is distributed in the hope that it will be useful, but 128dffb485Schristos WITHOUT ANY WARRANTY; without even the implied warranty of 138dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 148dffb485Schristos See the GNU General Public License for more details. 158dffb485Schristos 168dffb485Schristos You should have received a copy of the GNU General Public License 178dffb485Schristos along with this program; see the file COPYING. If not see 188dffb485Schristos <http://www.gnu.org/licenses/>. */ 198dffb485Schristos 208dffb485Schristos #include <ctf-impl.h> 218dffb485Schristos #include <string.h> 224b169a6bSchristos #include "ctf-endian.h" 238dffb485Schristos 248dffb485Schristos /* Simple doubly-linked list append routine. This implementation assumes that 258dffb485Schristos each list element contains an embedded ctf_list_t as the first member. 268dffb485Schristos An additional ctf_list_t is used to store the head (l_next) and tail 278dffb485Schristos (l_prev) pointers. The current head and tail list elements have their 288dffb485Schristos previous and next pointers set to NULL, respectively. */ 298dffb485Schristos 308dffb485Schristos void 318dffb485Schristos ctf_list_append (ctf_list_t *lp, void *newp) 328dffb485Schristos { 338dffb485Schristos ctf_list_t *p = lp->l_prev; /* p = tail list element. */ 348dffb485Schristos ctf_list_t *q = newp; /* q = new list element. */ 358dffb485Schristos 368dffb485Schristos lp->l_prev = q; 378dffb485Schristos q->l_prev = p; 388dffb485Schristos q->l_next = NULL; 398dffb485Schristos 408dffb485Schristos if (p != NULL) 418dffb485Schristos p->l_next = q; 428dffb485Schristos else 438dffb485Schristos lp->l_next = q; 448dffb485Schristos } 458dffb485Schristos 468dffb485Schristos /* Prepend the specified existing element to the given ctf_list_t. The 478dffb485Schristos existing pointer should be pointing at a struct with embedded ctf_list_t. */ 488dffb485Schristos 498dffb485Schristos void 508dffb485Schristos ctf_list_prepend (ctf_list_t * lp, void *newp) 518dffb485Schristos { 528dffb485Schristos ctf_list_t *p = newp; /* p = new list element. */ 538dffb485Schristos ctf_list_t *q = lp->l_next; /* q = head list element. */ 548dffb485Schristos 558dffb485Schristos lp->l_next = p; 568dffb485Schristos p->l_prev = NULL; 578dffb485Schristos p->l_next = q; 588dffb485Schristos 598dffb485Schristos if (q != NULL) 608dffb485Schristos q->l_prev = p; 618dffb485Schristos else 628dffb485Schristos lp->l_prev = p; 638dffb485Schristos } 648dffb485Schristos 658dffb485Schristos /* Delete the specified existing element from the given ctf_list_t. The 668dffb485Schristos existing pointer should be pointing at a struct with embedded ctf_list_t. */ 678dffb485Schristos 688dffb485Schristos void 698dffb485Schristos ctf_list_delete (ctf_list_t *lp, void *existing) 708dffb485Schristos { 718dffb485Schristos ctf_list_t *p = existing; 728dffb485Schristos 738dffb485Schristos if (p->l_prev != NULL) 748dffb485Schristos p->l_prev->l_next = p->l_next; 758dffb485Schristos else 768dffb485Schristos lp->l_next = p->l_next; 778dffb485Schristos 788dffb485Schristos if (p->l_next != NULL) 798dffb485Schristos p->l_next->l_prev = p->l_prev; 808dffb485Schristos else 818dffb485Schristos lp->l_prev = p->l_prev; 828dffb485Schristos } 838dffb485Schristos 848dffb485Schristos /* Return 1 if the list is empty. */ 858dffb485Schristos 868dffb485Schristos int 878dffb485Schristos ctf_list_empty_p (ctf_list_t *lp) 888dffb485Schristos { 898dffb485Schristos return (lp->l_next == NULL && lp->l_prev == NULL); 908dffb485Schristos } 918dffb485Schristos 928dffb485Schristos /* Splice one entire list onto the end of another one. The existing list is 938dffb485Schristos emptied. */ 948dffb485Schristos 958dffb485Schristos void 968dffb485Schristos ctf_list_splice (ctf_list_t *lp, ctf_list_t *append) 978dffb485Schristos { 988dffb485Schristos if (ctf_list_empty_p (append)) 998dffb485Schristos return; 1008dffb485Schristos 1018dffb485Schristos if (lp->l_prev != NULL) 1028dffb485Schristos lp->l_prev->l_next = append->l_next; 1038dffb485Schristos else 1048dffb485Schristos lp->l_next = append->l_next; 1058dffb485Schristos 1068dffb485Schristos append->l_next->l_prev = lp->l_prev; 1078dffb485Schristos lp->l_prev = append->l_prev; 1088dffb485Schristos append->l_next = NULL; 1098dffb485Schristos append->l_prev = NULL; 1108dffb485Schristos } 1118dffb485Schristos 1124b169a6bSchristos /* Convert a 32-bit ELF symbol to a ctf_link_sym_t. */ 1138dffb485Schristos 1144b169a6bSchristos ctf_link_sym_t * 1154b169a6bSchristos ctf_elf32_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf32_Sym *src, 1164b169a6bSchristos uint32_t symidx) 1178dffb485Schristos { 1184b169a6bSchristos Elf32_Sym tmp; 1194b169a6bSchristos int needs_flipping = 0; 1204b169a6bSchristos 1214b169a6bSchristos #ifdef WORDS_BIGENDIAN 1224b169a6bSchristos if (fp->ctf_symsect_little_endian) 1234b169a6bSchristos needs_flipping = 1; 1244b169a6bSchristos #else 1254b169a6bSchristos if (!fp->ctf_symsect_little_endian) 1264b169a6bSchristos needs_flipping = 1; 1274b169a6bSchristos #endif 1284b169a6bSchristos 1294b169a6bSchristos memcpy (&tmp, src, sizeof (Elf32_Sym)); 1304b169a6bSchristos if (needs_flipping) 1314b169a6bSchristos { 1324b169a6bSchristos swap_thing (tmp.st_name); 1334b169a6bSchristos swap_thing (tmp.st_size); 1344b169a6bSchristos swap_thing (tmp.st_shndx); 1354b169a6bSchristos swap_thing (tmp.st_value); 1364b169a6bSchristos } 1374b169a6bSchristos /* The name must be in the external string table. */ 1384b169a6bSchristos if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len) 1394b169a6bSchristos dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name; 1404b169a6bSchristos else 1414b169a6bSchristos dst->st_name = _CTF_NULLSTR; 1424b169a6bSchristos dst->st_nameidx_set = 0; 1434b169a6bSchristos dst->st_symidx = symidx; 1444b169a6bSchristos dst->st_shndx = tmp.st_shndx; 1454b169a6bSchristos dst->st_type = ELF32_ST_TYPE (tmp.st_info); 1464b169a6bSchristos dst->st_value = tmp.st_value; 1474b169a6bSchristos 1484b169a6bSchristos return dst; 1494b169a6bSchristos } 1504b169a6bSchristos 1514b169a6bSchristos /* Convert a 64-bit ELF symbol to a ctf_link_sym_t. */ 1524b169a6bSchristos 1534b169a6bSchristos ctf_link_sym_t * 1544b169a6bSchristos ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf64_Sym *src, 1554b169a6bSchristos uint32_t symidx) 1564b169a6bSchristos { 1574b169a6bSchristos Elf64_Sym tmp; 1584b169a6bSchristos int needs_flipping = 0; 1594b169a6bSchristos 1604b169a6bSchristos #ifdef WORDS_BIGENDIAN 1614b169a6bSchristos if (fp->ctf_symsect_little_endian) 1624b169a6bSchristos needs_flipping = 1; 1634b169a6bSchristos #else 1644b169a6bSchristos if (!fp->ctf_symsect_little_endian) 1654b169a6bSchristos needs_flipping = 1; 1664b169a6bSchristos #endif 1674b169a6bSchristos 1684b169a6bSchristos memcpy (&tmp, src, sizeof (Elf64_Sym)); 1694b169a6bSchristos if (needs_flipping) 1704b169a6bSchristos { 1714b169a6bSchristos swap_thing (tmp.st_name); 1724b169a6bSchristos swap_thing (tmp.st_size); 1734b169a6bSchristos swap_thing (tmp.st_shndx); 1744b169a6bSchristos swap_thing (tmp.st_value); 1754b169a6bSchristos } 1764b169a6bSchristos 1774b169a6bSchristos /* The name must be in the external string table. */ 1784b169a6bSchristos if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len) 1794b169a6bSchristos dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name; 1804b169a6bSchristos else 1814b169a6bSchristos dst->st_name = _CTF_NULLSTR; 1824b169a6bSchristos dst->st_nameidx_set = 0; 1834b169a6bSchristos dst->st_symidx = symidx; 1844b169a6bSchristos dst->st_shndx = tmp.st_shndx; 1854b169a6bSchristos dst->st_type = ELF32_ST_TYPE (tmp.st_info); 1864b169a6bSchristos 1874b169a6bSchristos /* We only care if the value is zero, so avoid nonzeroes turning into 1884b169a6bSchristos zeroes. */ 1894b169a6bSchristos if (_libctf_unlikely_ (tmp.st_value != 0 && ((uint32_t) tmp.st_value == 0))) 1904b169a6bSchristos dst->st_value = 1; 1914b169a6bSchristos else 1924b169a6bSchristos dst->st_value = (uint32_t) tmp.st_value; 1938dffb485Schristos 1948dffb485Schristos return dst; 1958dffb485Schristos } 1968dffb485Schristos 1978dffb485Schristos /* A string appender working on dynamic strings. Returns NULL on OOM. */ 1988dffb485Schristos 1998dffb485Schristos char * 2008dffb485Schristos ctf_str_append (char *s, const char *append) 2018dffb485Schristos { 2028dffb485Schristos size_t s_len = 0; 2038dffb485Schristos 2048dffb485Schristos if (append == NULL) 2058dffb485Schristos return s; 2068dffb485Schristos 2078dffb485Schristos if (s != NULL) 2088dffb485Schristos s_len = strlen (s); 2098dffb485Schristos 2108dffb485Schristos size_t append_len = strlen (append); 2118dffb485Schristos 2128dffb485Schristos if ((s = realloc (s, s_len + append_len + 1)) == NULL) 2138dffb485Schristos return NULL; 2148dffb485Schristos 2158dffb485Schristos memcpy (s + s_len, append, append_len); 2168dffb485Schristos s[s_len + append_len] = '\0'; 2178dffb485Schristos 2188dffb485Schristos return s; 2198dffb485Schristos } 2208dffb485Schristos 2218dffb485Schristos /* A version of ctf_str_append that returns the old string on OOM. */ 2228dffb485Schristos 2238dffb485Schristos char * 2248dffb485Schristos ctf_str_append_noerr (char *s, const char *append) 2258dffb485Schristos { 2268dffb485Schristos char *new_s; 2278dffb485Schristos 2288dffb485Schristos new_s = ctf_str_append (s, append); 2298dffb485Schristos if (!new_s) 2308dffb485Schristos return s; 2318dffb485Schristos return new_s; 2328dffb485Schristos } 2338dffb485Schristos 2348dffb485Schristos /* Store the specified error code into errp if it is non-NULL, and then 2358dffb485Schristos return NULL for the benefit of the caller. */ 2368dffb485Schristos 2378dffb485Schristos void * 2388dffb485Schristos ctf_set_open_errno (int *errp, int error) 2398dffb485Schristos { 2408dffb485Schristos if (errp != NULL) 2418dffb485Schristos *errp = error; 2428dffb485Schristos return NULL; 2438dffb485Schristos } 2448dffb485Schristos 2458dffb485Schristos /* Create a ctf_next_t. */ 2468dffb485Schristos 2478dffb485Schristos ctf_next_t * 2488dffb485Schristos ctf_next_create (void) 2498dffb485Schristos { 2508dffb485Schristos return calloc (1, sizeof (struct ctf_next)); 2518dffb485Schristos } 2528dffb485Schristos 2538dffb485Schristos /* Destroy a ctf_next_t, for early exit from iterators. */ 2548dffb485Schristos 2558dffb485Schristos void 2568dffb485Schristos ctf_next_destroy (ctf_next_t *i) 2578dffb485Schristos { 2588dffb485Schristos if (i == NULL) 2598dffb485Schristos return; 2608dffb485Schristos 2618dffb485Schristos if (i->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted) 2628dffb485Schristos free (i->u.ctn_sorted_hkv); 2634b169a6bSchristos if (i->ctn_next) 2644b169a6bSchristos ctf_next_destroy (i->ctn_next); 2658dffb485Schristos free (i); 2668dffb485Schristos } 2678dffb485Schristos 2688dffb485Schristos /* Copy a ctf_next_t. */ 2698dffb485Schristos 2708dffb485Schristos ctf_next_t * 2718dffb485Schristos ctf_next_copy (ctf_next_t *i) 2728dffb485Schristos { 2738dffb485Schristos ctf_next_t *i2; 2748dffb485Schristos 2758dffb485Schristos if ((i2 = ctf_next_create()) == NULL) 2768dffb485Schristos return NULL; 2778dffb485Schristos memcpy (i2, i, sizeof (struct ctf_next)); 2788dffb485Schristos 2798dffb485Schristos if (i2->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted) 2808dffb485Schristos { 2818dffb485Schristos size_t els = ctf_dynhash_elements ((ctf_dynhash_t *) i->cu.ctn_h); 2828dffb485Schristos if ((i2->u.ctn_sorted_hkv = calloc (els, sizeof (ctf_next_hkv_t))) == NULL) 2838dffb485Schristos { 2848dffb485Schristos free (i2); 2858dffb485Schristos return NULL; 2868dffb485Schristos } 2878dffb485Schristos memcpy (i2->u.ctn_sorted_hkv, i->u.ctn_sorted_hkv, 2888dffb485Schristos els * sizeof (ctf_next_hkv_t)); 2898dffb485Schristos } 2908dffb485Schristos return i2; 2918dffb485Schristos } 292