/* Simple subrs.
- Copyright (C) 2019 Free Software Foundation, Inc.
+ Copyright (C) 2019-2022 Free Software Foundation, Inc.
This file is part of libctf.
#include <string.h>
#include <unistd.h>
-static size_t _PAGESIZE _libctf_unused_;
-int _libctf_version = CTF_VERSION; /* Library client version. */
-int _libctf_debug = 0; /* Debugging messages enabled. */
-
-_libctf_malloc_ void *
-ctf_data_alloc (size_t size)
-{
- void *ret;
-
-#ifdef HAVE_MMAP
- if (_PAGESIZE == 0)
- _PAGESIZE = sysconf(_SC_PAGESIZE);
-
- if (size > _PAGESIZE)
- {
- ret = mmap (NULL, size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON, -1, 0);
- if (ret == MAP_FAILED)
- ret = NULL;
- }
- else
- ret = calloc (1, size);
-#else
- ret = calloc (1, size);
+#ifndef ENOTSUP
+#define ENOTSUP ENOSYS
#endif
- return ret;
-}
-void
-ctf_data_free (void *buf, size_t size _libctf_unused_)
-{
-#ifdef HAVE_MMAP
- /* Must be the same as the check in ctf_data_alloc(). */
-
- if (size > _PAGESIZE)
- (void) munmap (buf, size);
- else
- free (buf);
-#else
- free (buf);
-#endif
-}
+int _libctf_version = CTF_VERSION; /* Library client version. */
+int _libctf_debug = 0; /* Debugging messages enabled. */
/* Private, read-only mmap from a file, with fallback to copying.
#endif
}
-void
-ctf_data_protect (void *buf _libctf_unused_, size_t size _libctf_unused_)
-{
-#ifdef HAVE_MMAP
- /* Must be the same as the check in ctf_data_alloc(). */
-
- if (size > _PAGESIZE)
- (void) mprotect (buf, size, PROT_READ);
-#endif
-}
-
-_libctf_malloc_ void *
-ctf_alloc (size_t size)
-{
- return (malloc (size));
-}
-
-void
-ctf_free (void *buf)
-{
- free (buf);
-}
-
ssize_t
ctf_pread (int fd, void *buf, ssize_t count, off_t offset)
{
return acc;
}
-const char *
-ctf_strerror (int err)
-{
- return (const char *) (strerror (err));
-}
-
/* Set the CTF library client version to the specified version. If version is
zero, we just return the default library version number. */
int
_libctf_printflike_ (1, 2)
void ctf_dprintf (const char *format, ...)
{
- if (_libctf_debug)
+ if (_libctf_unlikely_ (_libctf_debug))
{
va_list alist;
va_end (alist);
}
}
+
+/* This needs more attention to thread-safety later on. */
+static ctf_list_t open_errors;
+
+/* Errors and warnings. Report the warning or error to the list in FP (or the
+ open errors list if NULL): if ERR is nonzero it is the errno to report to the
+ debug stream instead of that recorded on fp. */
+_libctf_printflike_ (4, 5)
+extern void
+ctf_err_warn (ctf_dict_t *fp, int is_warning, int err,
+ const char *format, ...)
+{
+ va_list alist;
+ ctf_err_warning_t *cew;
+
+ /* Don't bother reporting errors here: we can't do much about them if they
+ happen. If we're so short of memory that a tiny malloc doesn't work, a
+ vfprintf isn't going to work either and the caller will have to rely on the
+ ENOMEM return they'll be getting in short order anyway. */
+
+ if ((cew = malloc (sizeof (ctf_err_warning_t))) == NULL)
+ return;
+
+ cew->cew_is_warning = is_warning;
+ va_start (alist, format);
+ if (vasprintf (&cew->cew_text, format, alist) < 0)
+ {
+ free (cew);
+ va_end (alist);
+ return;
+ }
+ va_end (alist);
+
+ /* Include the error code only if there is one; if this is not a warning,
+ only use the error code if it was explicitly passed and is nonzero.
+ (Warnings may not have a meaningful error code, since the warning may not
+ lead to unwinding up to the user.) */
+ if ((!is_warning && (err != 0 || (fp && ctf_errno (fp) != 0)))
+ || (is_warning && err != 0))
+ ctf_dprintf ("%s: %s (%s)\n", is_warning ? _("error") : _("warning"),
+ cew->cew_text, err != 0 ? ctf_errmsg (err)
+ : ctf_errmsg (ctf_errno (fp)));
+ else
+ ctf_dprintf ("%s: %s\n", is_warning ? _("error") : _("warning"),
+ cew->cew_text);
+
+ if (fp != NULL)
+ ctf_list_append (&fp->ctf_errs_warnings, cew);
+ else
+ ctf_list_append (&open_errors, cew);
+}
+
+/* Move all the errors/warnings from an fp into the open_errors. */
+void
+ctf_err_warn_to_open (ctf_dict_t *fp)
+{
+ ctf_list_splice (&open_errors, &fp->ctf_errs_warnings);
+}
+
+/* Error-warning reporting: an 'iterator' that returns errors and warnings from
+ the error/warning list, in order of emission. Errors and warnings are popped
+ after return: the caller must free the returned error-text pointer.
+
+ An fp of NULL returns CTF-open-time errors from the open_errors variable
+ above.
+
+ The treatment of errors from this function itself is somewhat unusual: it
+ will often be called on an error path, so we don't want to overwrite the
+ ctf_errno unless we have no choice. So, like ctf_bufopen et al, this
+ function takes an errp pointer where errors are reported. The pointer is
+ optional: if not set, errors are reported via the fp (if non-NULL). Calls
+ with neither fp nor errp set are mildly problematic because there is no clear
+ way to report end-of-iteration: you just have to assume that a NULL return
+ means the end, and not an iterator error. */
+
+char *
+ctf_errwarning_next (ctf_dict_t *fp, ctf_next_t **it, int *is_warning,
+ int *errp)
+{
+ ctf_next_t *i = *it;
+ char *ret;
+ ctf_list_t *errlist;
+ ctf_err_warning_t *cew;
+
+ if (fp)
+ errlist = &fp->ctf_errs_warnings;
+ else
+ errlist = &open_errors;
+
+ if (!i)
+ {
+ if ((i = ctf_next_create ()) == NULL)
+ {
+ if (errp)
+ *errp = ENOMEM;
+ else if (fp)
+ ctf_set_errno (fp, ENOMEM);
+ return NULL;
+ }
+
+ i->cu.ctn_fp = fp;
+ i->ctn_iter_fun = (void (*) (void)) ctf_errwarning_next;
+ *it = i;
+ }
+
+ if ((void (*) (void)) ctf_errwarning_next != i->ctn_iter_fun)
+ {
+ if (errp)
+ *errp = ECTF_NEXT_WRONGFUN;
+ else if (fp)
+ ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
+ return NULL;
+ }
+
+ if (fp != i->cu.ctn_fp)
+ {
+ if (errp)
+ *errp = ECTF_NEXT_WRONGFP;
+ else if (fp)
+ ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
+ return NULL;
+ }
+
+ cew = ctf_list_next (errlist);
+
+ if (!cew)
+ {
+ ctf_next_destroy (i);
+ *it = NULL;
+ if (errp)
+ *errp = ECTF_NEXT_END;
+ else if (fp)
+ ctf_set_errno (fp, ECTF_NEXT_END);
+ return NULL;
+ }
+
+ if (is_warning)
+ *is_warning = cew->cew_is_warning;
+ ret = cew->cew_text;
+ ctf_list_delete (errlist, cew);
+ free (cew);
+ return ret;
+}
+
+void
+ctf_assert_fail_internal (ctf_dict_t *fp, const char *file, size_t line,
+ const char *exprstr)
+{
+ ctf_err_warn (fp, 0, ECTF_INTERNAL, _("%s: %lu: libctf assertion failed: %s"),
+ file, (long unsigned int) line, exprstr);
+ ctf_set_errno (fp, ECTF_INTERNAL);
+}