xref: /netbsd-src/external/gpl3/gdb/dist/libctf/ctf-util.c (revision c9055873d0546e63388f027d3d7f85381cde0545)
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