(root)/
binutils-2.41/
libctf/
ctf-subr.c
       1  /* Simple subrs.
       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  #ifdef HAVE_MMAP
      22  #include <sys/mman.h>
      23  #endif
      24  #include <sys/types.h>
      25  #include <stdarg.h>
      26  #include <string.h>
      27  #include <unistd.h>
      28  
      29  #ifndef ENOTSUP
      30  #define ENOTSUP ENOSYS
      31  #endif
      32  
      33  int _libctf_version = CTF_VERSION;	      /* Library client version.  */
      34  int _libctf_debug = 0;			      /* Debugging messages enabled.  */
      35  
      36  /* Private, read-only mmap from a file, with fallback to copying.
      37  
      38     No handling of page-offset issues at all: the caller must allow for that. */
      39  
      40  _libctf_malloc_ void *
      41  ctf_mmap (size_t length, size_t offset, int fd)
      42  {
      43    void *data;
      44  
      45  #ifdef HAVE_MMAP
      46    data = mmap (NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
      47    if (data == MAP_FAILED)
      48      data = NULL;
      49  #else
      50    if ((data = malloc (length)) != NULL)
      51      {
      52        if (ctf_pread (fd, data, length, offset) <= 0)
      53  	{
      54  	  free (data);
      55  	  data = NULL;
      56  	}
      57      }
      58  #endif
      59    return data;
      60  }
      61  
      62  void
      63  ctf_munmap (void *buf, size_t length _libctf_unused_)
      64  {
      65  #ifdef HAVE_MMAP
      66    (void) munmap (buf, length);
      67  #else
      68    free (buf);
      69  #endif
      70  }
      71  
      72  ssize_t
      73  ctf_pread (int fd, void *buf, ssize_t count, off_t offset)
      74  {
      75    ssize_t len;
      76    size_t acc = 0;
      77    char *data = (char *) buf;
      78  
      79  #ifdef HAVE_PREAD
      80    while (count > 0)
      81      {
      82        errno = 0;
      83        if (((len = pread (fd, data, count, offset)) < 0) &&
      84  	  errno != EINTR)
      85  	  return len;
      86        if (errno == EINTR)
      87  	continue;
      88  
      89        acc += len;
      90        if (len == 0)				/* EOF.  */
      91  	return acc;
      92  
      93        count -= len;
      94        offset += len;
      95        data += len;
      96      }
      97    return acc;
      98  #else
      99    off_t orig_off;
     100  
     101    if ((orig_off = lseek (fd, 0, SEEK_CUR)) < 0)
     102      return -1;
     103    if ((lseek (fd, offset, SEEK_SET)) < 0)
     104      return -1;
     105  
     106    while (count > 0)
     107      {
     108        errno = 0;
     109        if (((len = read (fd, data, count)) < 0) &&
     110  	  errno != EINTR)
     111  	  return len;
     112        if (errno == EINTR)
     113  	continue;
     114  
     115        acc += len;
     116        if (len == 0)				/* EOF.  */
     117  	break;
     118  
     119        count -= len;
     120        data += len;
     121      }
     122    if ((lseek (fd, orig_off, SEEK_SET)) < 0)
     123      return -1;					/* offset is smashed.  */
     124  #endif
     125  
     126    return acc;
     127  }
     128  
     129  /* Set the CTF library client version to the specified version.  If version is
     130     zero, we just return the default library version number.  */
     131  int
     132  ctf_version (int version)
     133  {
     134    if (version < 0)
     135      {
     136        errno = EINVAL;
     137        return -1;
     138      }
     139  
     140    if (version > 0)
     141      {
     142        /*  Dynamic version switching is not presently supported. */
     143        if (version != CTF_VERSION)
     144  	{
     145  	  errno = ENOTSUP;
     146  	  return -1;
     147  	}
     148        ctf_dprintf ("ctf_version: client using version %d\n", version);
     149        _libctf_version = version;
     150      }
     151  
     152    return _libctf_version;
     153  }
     154  
     155  void
     156  libctf_init_debug (void)
     157  {
     158    static int inited;
     159    if (!inited)
     160      {
     161        _libctf_debug = getenv ("LIBCTF_DEBUG") != NULL;
     162        inited = 1;
     163      }
     164  }
     165  
     166  void ctf_setdebug (int debug)
     167  {
     168    /* Ensure that libctf_init_debug() has been called, so that we don't get our
     169       debugging-on-or-off smashed by the next call.  */
     170  
     171    libctf_init_debug();
     172    _libctf_debug = debug;
     173    ctf_dprintf ("CTF debugging set to %i\n", debug);
     174  }
     175  
     176  int ctf_getdebug (void)
     177  {
     178    return _libctf_debug;
     179  }
     180  
     181  _libctf_printflike_ (1, 2)
     182  void ctf_dprintf (const char *format, ...)
     183  {
     184    if (_libctf_unlikely_ (_libctf_debug))
     185      {
     186        va_list alist;
     187  
     188        va_start (alist, format);
     189        fflush (stdout);
     190        (void) fputs ("libctf DEBUG: ", stderr);
     191        (void) vfprintf (stderr, format, alist);
     192        va_end (alist);
     193      }
     194  }
     195  
     196  /* This needs more attention to thread-safety later on.  */
     197  static ctf_list_t open_errors;
     198  
     199  /* Errors and warnings.  Report the warning or error to the list in FP (or the
     200     open errors list if NULL): if ERR is nonzero it is the errno to report to the
     201     debug stream instead of that recorded on fp.  */
     202  _libctf_printflike_ (4, 5)
     203  extern void
     204  ctf_err_warn (ctf_dict_t *fp, int is_warning, int err,
     205  	      const char *format, ...)
     206  {
     207    va_list alist;
     208    ctf_err_warning_t *cew;
     209  
     210    /* Don't bother reporting errors here: we can't do much about them if they
     211       happen.  If we're so short of memory that a tiny malloc doesn't work, a
     212       vfprintf isn't going to work either and the caller will have to rely on the
     213       ENOMEM return they'll be getting in short order anyway.  */
     214  
     215    if ((cew = malloc (sizeof (ctf_err_warning_t))) == NULL)
     216      return;
     217  
     218    cew->cew_is_warning = is_warning;
     219    va_start (alist, format);
     220    if (vasprintf (&cew->cew_text, format, alist) < 0)
     221      {
     222        free (cew);
     223        va_end (alist);
     224        return;
     225      }
     226    va_end (alist);
     227  
     228    /* Include the error code only if there is one; if this is not a warning,
     229       only use the error code if it was explicitly passed and is nonzero.
     230       (Warnings may not have a meaningful error code, since the warning may not
     231       lead to unwinding up to the user.)  */
     232    if ((!is_warning && (err != 0 || (fp && ctf_errno (fp) != 0)))
     233        || (is_warning && err != 0))
     234      ctf_dprintf ("%s: %s (%s)\n", is_warning ? _("error") : _("warning"),
     235  		 cew->cew_text, err != 0 ? ctf_errmsg (err)
     236  		 : ctf_errmsg (ctf_errno (fp)));
     237    else
     238      ctf_dprintf ("%s: %s\n", is_warning ? _("error") : _("warning"),
     239  		 cew->cew_text);
     240  
     241    if (fp != NULL)
     242      ctf_list_append (&fp->ctf_errs_warnings, cew);
     243    else
     244      ctf_list_append (&open_errors, cew);
     245  }
     246  
     247  /* Move all the errors/warnings from an fp into the open_errors.  */
     248  void
     249  ctf_err_warn_to_open (ctf_dict_t *fp)
     250  {
     251    ctf_list_splice (&open_errors, &fp->ctf_errs_warnings);
     252  }
     253  
     254  /* Error-warning reporting: an 'iterator' that returns errors and warnings from
     255     the error/warning list, in order of emission.  Errors and warnings are popped
     256     after return: the caller must free the returned error-text pointer.
     257  
     258     An fp of NULL returns CTF-open-time errors from the open_errors variable
     259     above.
     260  
     261     The treatment of errors from this function itself is somewhat unusual: it
     262     will often be called on an error path, so we don't want to overwrite the
     263     ctf_errno unless we have no choice.  So, like ctf_bufopen et al, this
     264     function takes an errp pointer where errors are reported.  The pointer is
     265     optional: if not set, errors are reported via the fp (if non-NULL).  Calls
     266     with neither fp nor errp set are mildly problematic because there is no clear
     267     way to report end-of-iteration: you just have to assume that a NULL return
     268     means the end, and not an iterator error.  */
     269  
     270  char *
     271  ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
     272  		     int *errp)
     273  {
     274    ctf_next_t *i = *it;
     275    char *ret;
     276    ctf_list_t *errlist;
     277    ctf_err_warning_t *cew;
     278  
     279    if (fp)
     280      errlist = &fp->ctf_errs_warnings;
     281    else
     282      errlist = &open_errors;
     283  
     284    if (!i)
     285      {
     286        if ((i = ctf_next_create ()) == NULL)
     287  	{
     288  	  if (errp)
     289  	    *errp = ENOMEM;
     290  	  else if (fp)
     291  	    ctf_set_errno (fp, ENOMEM);
     292  	  return NULL;
     293  	}
     294  
     295        i->cu.ctn_fp = fp;
     296        i->ctn_iter_fun = (void (*) (void)) ctf_errwarning_next;
     297        *it = i;
     298      }
     299  
     300    if ((void (*) (void)) ctf_errwarning_next != i->ctn_iter_fun)
     301      {
     302        if (errp)
     303  	*errp = ECTF_NEXT_WRONGFUN;
     304        else if (fp)
     305  	ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
     306        return NULL;
     307      }
     308  
     309    if (fp != i->cu.ctn_fp)
     310      {
     311        if (errp)
     312  	*errp = ECTF_NEXT_WRONGFP;
     313        else if (fp)
     314  	ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
     315        return NULL;
     316      }
     317  
     318    cew = ctf_list_next (errlist);
     319  
     320    if (!cew)
     321      {
     322        ctf_next_destroy (i);
     323        *it = NULL;
     324        if (errp)
     325  	*errp = ECTF_NEXT_END;
     326        else if (fp)
     327  	ctf_set_errno (fp, ECTF_NEXT_END);
     328        return NULL;
     329      }
     330  
     331    if (is_warning)
     332      *is_warning = cew->cew_is_warning;
     333    ret = cew->cew_text;
     334    ctf_list_delete (errlist, cew);
     335    free (cew);
     336    return ret;
     337  }
     338  
     339  void
     340  ctf_assert_fail_internal (ctf_dict_t *fp, const char *file, size_t line,
     341  			  const char *exprstr)
     342  {
     343    ctf_err_warn (fp, 0, ECTF_INTERNAL, _("%s: %lu: libctf assertion failed: %s"),
     344  		file, (long unsigned int) line, exprstr);
     345    ctf_set_errno (fp, ECTF_INTERNAL);
     346  }