+#if SYSIO_TRACING
+
+#if !(defined(_HAVE_ASPRINTF) && _HAVE_ASPRINTF)
+/*
+ * Print a string to allocated memory.
+ */
+static int
+vasprintf(char **strp, const char *fmt, va_list ap)
+{
+ size_t siz;
+ int oerrno;
+ char *s;
+ va_list aq;
+ int n;
+
+ siz = 50;
+ oerrno = errno;
+ if (!(s = malloc(siz))) {
+ errno = oerrno;
+ return -1;
+ }
+ for (;;) {
+ va_copy(aq, ap);
+ n = vsnprintf (s, siz, fmt, aq);
+ va_end(aq);
+ if (n > -1 && (size_t )n < siz)
+ break;
+ if (n > -1) /* glibc 2.1 */
+ siz = n+1; /* precise */
+ else /* glibc 2.0 */
+ siz *= 2; /* twice the old */
+ if (!(s = realloc (s, siz)))
+ break;
+ }
+ *strp = s;
+ errno = oerrno;
+ return n;
+}
+
+#if 0
+static int
+asprintf(char **strp, const char *fmt, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = vasprintf(strp, fmt, ap);
+ va_end(ap);
+ return n;
+}
+#endif
+#endif /* !(defined(_HAVE_ASPRINTF) && _HAVE_ASPRINTF) */
+
+static void
+_sysio_cwrite(const char *buf, size_t len)
+{
+ int oerrno;
+
+ oerrno = errno;
+ (void )syscall(SYSIO_SYS_write, STDERR_FILENO, buf, len);
+ errno = oerrno;
+}
+
+/*
+ * Console printf.
+ */
+void
+_sysio_cprintf(const char *fmt, ...)
+{
+ va_list ap;
+ int len;
+ char *buf;
+
+ va_start(ap, fmt);
+ buf = NULL;
+ len = vasprintf(&buf, fmt, ap);
+ va_end(ap);
+ if (len < 0)
+ return;
+ _sysio_cwrite(buf, len);
+ free(buf);
+}
+
+/*
+ * Register a trace callback.
+ *
+ * The pointer to the trace record is returned.
+ */
+void *
+_sysio_register_trace(void *q,
+ void (*f)(const char *file,
+ const char *func,
+ int line))
+{
+ struct trace_callback *tcb;
+
+ tcb = malloc(sizeof(struct trace_callback));
+ if (!tcb)
+ return NULL;
+ TCB_INIT(tcb, f);
+ TAILQ_INSERT_TAIL((struct trace_q *)q, tcb, links);
+ return tcb;
+}
+
+/*
+ * Remove a registered trace callback.
+ */
+void
+_sysio_remove_trace(void *q, void *p)
+{
+
+ TAILQ_REMOVE((struct trace_q *)q, (struct trace_callback *)p, links);
+ free(p);
+}
+
+void
+/*
+ * Run a trace queue, making all the callbacks.
+ */
+_sysio_run_trace_q(void *q,
+ const char *file,
+ const char *func,
+ int line)
+{
+ struct trace_callback *tcb;
+
+ tcb = ((struct trace_q *)q)->tqh_first;
+ while (tcb) {
+ (*tcb->f)(file, func, line);
+ tcb = tcb->links.tqe_next;
+ }
+}
+
+static void
+_sysio_trace_entry(const char *file __IS_UNUSED,
+ const char *func,
+ int line __IS_UNUSED)
+{
+
+ _sysio_cprintf("+ENTER+ %s\n", func);
+}
+
+static void
+_sysio_trace_exit(const char *file __IS_UNUSED,
+ const char *func,
+ int line __IS_UNUSED)
+{
+
+ _sysio_cprintf("+EXIT+ %s\n", func);
+}
+#endif /* defined(SYSIO_TRACING) */
+