(root)/
binutils-2.41/
libctf/
ctf-util.c
       1  /* Miscellaneous utilities.
       2     Copyright (C) 2019-2023 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  /* A realloc() that fails noisily if called with any ctf_str_num_users.  */
     235  void *
     236  ctf_realloc (ctf_dict_t *fp, void *ptr, size_t size)
     237  {
     238    if (fp->ctf_str_num_refs > 0)
     239      {
     240        ctf_dprintf ("%p: attempt to realloc() string table with %lu active refs\n",
     241  		   (void *) fp, (unsigned long) fp->ctf_str_num_refs);
     242        return NULL;
     243      }
     244    return realloc (ptr, size);
     245  }
     246  
     247  /* Store the specified error code into errp if it is non-NULL, and then
     248     return NULL for the benefit of the caller.  */
     249  
     250  void *
     251  ctf_set_open_errno (int *errp, int error)
     252  {
     253    if (errp != NULL)
     254      *errp = error;
     255    return NULL;
     256  }
     257  
     258  /* Store the specified error code into the CTF dict, and then return CTF_ERR /
     259     -1 for the benefit of the caller. */
     260  
     261  unsigned long
     262  ctf_set_errno (ctf_dict_t *fp, int err)
     263  {
     264    fp->ctf_errno = err;
     265    return CTF_ERR;
     266  }
     267  
     268  /* Create a ctf_next_t.  */
     269  
     270  ctf_next_t *
     271  ctf_next_create (void)
     272  {
     273    return calloc (1, sizeof (struct ctf_next));
     274  }
     275  
     276  /* Destroy a ctf_next_t, for early exit from iterators.  */
     277  
     278  void
     279  ctf_next_destroy (ctf_next_t *i)
     280  {
     281    if (i == NULL)
     282      return;
     283  
     284    if (i->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted)
     285      free (i->u.ctn_sorted_hkv);
     286    if (i->ctn_next)
     287      ctf_next_destroy (i->ctn_next);
     288    free (i);
     289  }
     290  
     291  /* Copy a ctf_next_t.  */
     292  
     293  ctf_next_t *
     294  ctf_next_copy (ctf_next_t *i)
     295  {
     296    ctf_next_t *i2;
     297  
     298    if ((i2 = ctf_next_create()) == NULL)
     299      return NULL;
     300    memcpy (i2, i, sizeof (struct ctf_next));
     301  
     302    if (i2->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted)
     303      {
     304        size_t els = ctf_dynhash_elements ((ctf_dynhash_t *) i->cu.ctn_h);
     305        if ((i2->u.ctn_sorted_hkv = calloc (els, sizeof (ctf_next_hkv_t))) == NULL)
     306  	{
     307  	  free (i2);
     308  	  return NULL;
     309  	}
     310        memcpy (i2->u.ctn_sorted_hkv, i->u.ctn_sorted_hkv,
     311  	      els * sizeof (ctf_next_hkv_t));
     312      }
     313    return i2;
     314  }