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