* trace: initial commit
authorUrban Wallasch <urban.wallasch@freenet.de>
Sat, 19 Oct 2019 10:22:02 +0000 (12:22 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Sat, 19 Oct 2019 10:22:02 +0000 (12:22 +0200)
trace/trace.c [new file with mode: 0644]
trace/trace.h [new file with mode: 0644]

diff --git a/trace/trace.c b/trace/trace.c
new file mode 100644 (file)
index 0000000..05df17e
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * trace.c
+ *
+ * Simple, non-exhaustive quick check for trace.h
+ *
+ * Build with:
+ * cc [-std=c11 [-Wpedantic]] -Wall -Wextra -DTRACE_ON -otrace trace.c
+ *
+ */
+
+#include "trace.h"
+
+#include <stddef.h>
+#include <uchar.h>
+
+int main(void) {
+    char c = 'A';
+
+    signed char sc = 'b';
+    unsigned char uc = 'd';
+
+    wchar_t wc1 = L'\xFFFE';
+    char16_t wc2 = u'\xFFFE';
+    char32_t wc3 = U'\xFFFE';
+
+    short s = -512;
+    unsigned short us = 512;
+
+    int i = -1024;
+    unsigned int ui = 2048;
+
+    long l = -100000;
+    unsigned long ul = 200000;
+
+    long long ll = -100000;
+    unsigned long long ull = 200000;
+
+    size_t sz = 8888;
+
+    float f = 2.7182;
+    double d = 3.1415;
+    long double ld = 123.456;
+
+    void *pv = (void *)0xdeadbeef;
+    char *pc = "Konnichiwa";
+    int *pi = &i;
+    unsigned *pui = &ui;
+    double *pd = &d;
+
+    struct { int i; } blah = { 555 }, blubb;
+
+#if defined(__STRICT_ANSI__)
+    /* Arrays don't work with the extended pointer heuristic! */
+    int arr[10] = {42, 43, 44};
+    (void)TRACE( arr );
+#endif
+
+    blubb = TRACE( blah );
+    (void)TRACE( blubb.i );
+    (void)TRACEX( &blubb );
+
+    (void)TRACE( 1+1 );
+    (void)TRACE( c );
+    c = TRACE( c+1 );
+    (void)TRACE( c );
+    (void)TRACE( c++ );
+    (void)TRACE( c );
+    (void)TRACE( ++c );
+
+    (void)TRACEX(wc1);
+    (void)TRACEX(wc2);
+    (void)TRACEX(wc3);
+
+
+    sc = TRACE( sc ) - 1;
+    (void)TRACEX( sc );
+    uc = TRACE( uc ) + 1;
+    (void)TRACEX( uc );
+
+    s  = TRACE( s  ) - 1;
+    (void)TRACEX( s  );
+    us = TRACE( us ) + 1;
+    (void)TRACEX( us );
+
+    i  = TRACE( i  ) - 1;
+    (void)TRACEX( i  );
+    ui = TRACE( ui ) + 1;
+    (void)TRACEX( ui );
+
+    l  = TRACE( l  ) - 1;
+    (void)TRACEX( l  );
+    ul = TRACE( ul ) + 1;
+    (void)TRACEX( ul );
+
+    ll = TRACE( ll ) - 1;
+    (void)TRACEX( ll  );
+    ull = TRACE( ull ) + 1;
+    (void)TRACEX( ull );
+
+    sz = TRACE( sz ) + 1;
+    (void)TRACEX( sz  );
+
+    f  = TRACE( f  ) + 1.1111;
+    (void)TRACEX( f  );
+    d  = TRACE( d  ) + 1.1111;
+    (void)TRACEX( d  );
+    ld = TRACE( ld ) + 1.1111;
+    (void)TRACEX( ld );
+
+    (void)TRACES("tuturu");
+
+    pv = TRACE( pv );
+    pv = 0;
+    (void)TRACE(pv);
+    (void)TRACE((char *)pv);
+    (void)TRACEX((char *)pv);
+    (void)TRACES((char *)pv);
+    (void)TRACEXS((char *)pv);
+
+    pc = TRACE( pc );
+    (void)TRACES( pc );
+    (void)TRACEX( pc );
+    (void)TRACEXS( pc );
+
+    pi = TRACE( pi );
+    (void)TRACE( pi );
+
+    pui = TRACE( pui );
+    (void)TRACE( pui );
+    (void)TRACEX( pui );
+    (void)TRACES( pui );
+    (void)TRACEXS( pui );
+
+    pd = TRACE( pd );
+    (void)TRACE( pd );
+
+    return 0;
+}
diff --git a/trace/trace.h b/trace/trace.h
new file mode 100644 (file)
index 0000000..e16fe83
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * trace.h
+ *
+ * Function-like macros to issue tracing information on expressions.
+ *
+ * TRACE(e)   - default formatting
+ * TRACEX(e)  - print unsigned and floating point values in hexadecimal
+ * TRACES(e)  - treat character pointers like strings
+ * TRACEXS(e) - all of the above
+ *
+ * An expression `e´ passed as argument to one of the trace macros is
+ * delegated by a C11 _Generic selector to one of the variadic inline
+ * helper functions, based on its type.  The macros evaluate their
+ * argument only once and resolve to the value of the expression.
+ *
+ * Expressions having a type not compatible with any of the explicit
+ * associations are reported as not recognized.
+ *
+ * Should build cleanly using
+ *   cc [-std=c11 [-Wpedantic]] -Wall -Wextra -DTRACE_ON [...]
+ * with cc being one of: glibc-gcc, musl-gcc, glibc-clang, musl-clang.
+ *
+ * CAVEAT:
+ * In C11 mode any expression of array type decays to (and thus takes
+ * on the type of) a pointer to its first element; non-trivial pointers
+ * are listed as expressions of unrecognized type.
+ * When compiled without explicitly requesting C standard conformance
+ * using either gcc or clang, an additional heuristic will interpret
+ * any otherwise unrecognized suitably sized object as pointer.
+ * However, as a trade-off, any attempt to pass in an expression of
+ * array type will result in a compile time error.
+ *
+ */
+
+#ifndef TRACE_H_
+#define TRACE_H_
+
+#ifdef TRACE_ON
+
+#ifdef __cplusplus
+    #error "C++: Now there's your problem!"
+#endif
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ < 201112L)
+    #error "At least C11 support is required!"
+#endif
+
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* Attempt to infer integer promotion target types from implementation. */
+#if (INT_MAX) == (INT32_MAX)
+    #define I_PROM_ int32_t
+    #define U_PROM_ uint32_t
+#elif (INT_MAX) == (INT64_MAX)
+    #define I_PROM_ int64_t
+    #define U_PROM_ uint64_t
+#else
+    #error "Integer type promotion heuristic failed. Take five!"
+#endif
+
+/* Adjust this to complement the libc printf %p conversion format! */
+#if defined(__QNXNTO__)
+    #define TRACE_PPFX_   "0x"
+#else
+    #define TRACE_PPFX_   ""
+#endif
+
+/* Helper macros. */
+#define TRACE_PRF_(...)            ((void)fprintf(stderr, __VA_ARGS__))
+#define TRACE_LOC_(fi_, fn_, ln_)  TRACE_PRF_("%s:%s@%d ", fi_, fn_, ln_)
+
+/* Generate helper functions for arithmetic types: */
+#define TRACE_AGEN_(t_, p_, s_, c_, f_)                                \
+    static inline t_ trace_##s_##_(const char *fi, const char *fn,     \
+                                   int ln, const char *n, ...){        \
+        t_ v; va_list a; va_start(a, n); v = va_arg(a, p_); va_end(a); \
+        if (fi && fn) {                                                \
+            TRACE_LOC_(fi, fn, ln);                                    \
+        }                                                              \
+        TRACE_PRF_("%s=<%s> "f_"\n", n, c_, v);                        \
+        return v;                                                      \
+    }
+
+TRACE_AGEN_(char,      I_PROM_,   ch, "char", "'%c'")
+TRACE_AGEN_(int8_t,    I_PROM_,   i8,   "i8", "%"PRId8)
+TRACE_AGEN_(uint8_t,   U_PROM_,   u8,   "u8", "%"PRIu8)
+TRACE_AGEN_(uint8_t,   U_PROM_,   x8,   "u8", "0x%02"PRIx8)
+TRACE_AGEN_(int16_t,   I_PROM_,  i16,  "i16", "%"PRId16)
+TRACE_AGEN_(uint16_t,  U_PROM_,  u16,  "u16", "%"PRIu16)
+TRACE_AGEN_(uint16_t,  U_PROM_,  x16,  "u16", "0x%04"PRIx16)
+TRACE_AGEN_(int32_t,   I_PROM_,  i32,  "i32", "%"PRId32)
+TRACE_AGEN_(uint32_t,  U_PROM_,  u32,  "u32", "%"PRIu32)
+TRACE_AGEN_(uint32_t,  U_PROM_,  x32,  "u32", "0x%08"PRIx32)
+TRACE_AGEN_(int64_t,   int64_t,  i64,  "i64", "%"PRId64)
+TRACE_AGEN_(uint64_t, uint64_t,  u64,  "u64", "%"PRIu64)
+TRACE_AGEN_(uint64_t, uint64_t,  x64,  "u64", "0x%016"PRIx64)
+TRACE_AGEN_(long long, long long, ll,   "ll", "%lld")
+TRACE_AGEN_(unsigned long long, unsigned long long, ull, "ull", "%llu")
+TRACE_AGEN_(unsigned long long, unsigned long long, xll, "ull", "0x%016llx")
+TRACE_AGEN_(float, double,   f,  "float", "%f")
+TRACE_AGEN_(float, double,  xf,  "float", "%a")
+TRACE_AGEN_(double, double,  d, "double", "%f")
+TRACE_AGEN_(double, double, xd, "double", "%a")
+TRACE_AGEN_(long double, long double,  ld, "ldouble", "%Lf")
+TRACE_AGEN_(long double, long double, xld, "ldouble", "%La")
+
+#undef TRACE_AGEN_
+#undef I_PROM_
+#undef U_PROM_
+
+/* Generate helper functions for pointer types: */
+#define TRACE_PGEN_(t_, s_, c_)                                        \
+    static inline t_ trace_p##s_##_(const char *fi, const char *fn,    \
+                                    int ln, const char *n, ... ){      \
+        t_ v; va_list a; va_start(a, n); v = va_arg(a, t_); va_end(a); \
+        TRACE_LOC_(fi, fn, ln);                                        \
+        TRACE_PRF_("%s=<%s*> "TRACE_PPFX_"%p", n, c_, (void *)v);      \
+        if (v) {                                                       \
+            TRACE_PRF_(", *"); trace_##s_##_(NULL, NULL, 0, n, *v);    \
+        } else {                                                       \
+            TRACE_PRF_("\n");                                          \
+        }                                                              \
+        return v;                                                      \
+    }
+
+TRACE_PGEN_(char *,       ch, "char")
+TRACE_PGEN_(int8_t *,     i8,   "i8")
+TRACE_PGEN_(uint8_t *,    u8,   "u8")
+TRACE_PGEN_(uint8_t *,    x8,   "u8")
+TRACE_PGEN_(int16_t *,   i16,  "i16")
+TRACE_PGEN_(uint16_t *,  u16,  "u16")
+TRACE_PGEN_(uint16_t *,  x16,  "u16")
+TRACE_PGEN_(int32_t *,   i32,  "i32")
+TRACE_PGEN_(uint32_t *,  u32,  "u32")
+TRACE_PGEN_(uint32_t *,  x32,  "u32")
+TRACE_PGEN_(int64_t *,   i64,  "i64")
+TRACE_PGEN_(uint64_t *,  u64,  "u64")
+TRACE_PGEN_(uint64_t *,  x64,  "u64")
+TRACE_PGEN_(long long *,  ll,   "ll")
+TRACE_PGEN_(unsigned long long *, ull, "ull")
+TRACE_PGEN_(unsigned long long *, xll, "ull")
+TRACE_PGEN_(float *,         f,   "float")
+TRACE_PGEN_(float *,        xf,   "float")
+TRACE_PGEN_(double *,        d,  "double")
+TRACE_PGEN_(double *,       xd,  "double")
+TRACE_PGEN_(long double *,  ld, "ldouble")
+TRACE_PGEN_(long double *, xld, "ldouble")
+
+#undef TRACE_PGEN_
+
+/* Void pointers and strings require special handling: */
+static inline void *trace_pvd_(const char *fi, const char *fn, int ln,
+                               const char *n, ...){
+    void *v; va_list a; va_start(a, n); v = va_arg(a, void *); va_end(a);
+    TRACE_LOC_(fi, fn, ln);
+    TRACE_PRF_("%s=<void*> "TRACE_PPFX_"%p\n", n, v);
+    return v;
+}
+
+static inline void *trace_pstr_(const char *fi, const char *fn, int ln,
+                                const char *n, ...){
+    char *v; va_list a; va_start(a, n); v = va_arg(a, char *); va_end(a);
+    TRACE_LOC_(fi, fn, ln);
+    TRACE_PRF_("%s=<char*> "TRACE_PPFX_"%p, %s=<string> \"%s\"\n",
+              n, (void *)v, n, v);
+    return v;
+}
+
+/* Handle the default case depending on current compile mode. */
+#if !defined(__STRICT_ANSI__) && (defined(__GNUC__) || defined(__clang__))
+    /* Use non-standard compiler extensions to guess arbitrary pointer
+     * types. Chokes on arrays! */
+    #define TRACE_DFLT(fi_, fn_, ln_, x_)                              \
+    ({                                                                 \
+        const char *typ, *fmt;  typeof(x_) y_ = x_;                    \
+        if (sizeof(y_) == sizeof(void *)) {                            \
+            typ = "?*?";  fmt = "%s=<%s> "TRACE_PPFX_"%p\n";           \
+        } else {                                                       \
+            typ = "???";  fmt = "%s=<%s>\n";                           \
+        }                                                              \
+        TRACE_LOC_(fi_, fn_, ln_);  TRACE_PRF_(fmt, #x_, typ, y_);     \
+        y_;                                                            \
+    })
+#else
+    /* Use C standard conforming catch-all. */
+    #define TRACE_DFLT(fi_, fn_, ln_, x_)                              \
+        (TRACE_LOC_(fi_, fn_, ln_), TRACE_PRF_("%s=<???"">\n", #x_), x_)
+    #undef TRACE_PPFX_
+#endif
+
+/*
+ * Issue a tracing message about an expression, formatted as
+ *   file:func@line: expr=<type> value
+ * for arithmetic types, or
+ *   file:func@line: expr=<type*> address, *exp=<type> value
+ * for supported pointer types, or
+ *   file:func@line: expr=<???>
+ * for expressions of unrecognized type.
+ *
+ * In non-standard conforming mode anything that looks even
+ * remotely like some arbitrary pointer is printed as:
+ *   file:func@line: expr=<?*?> address
+ *
+ * Parameters:
+ *   x_    the expression to be traced
+ *
+ * Returns:
+ *   The value of x_.
+ */
+#define TRACE(x_)  (_Generic( (x_),                                    \
+    /* arithmetic types */                                             \
+    char:          trace_ch_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    int8_t:        trace_i8_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint8_t:       trace_u8_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    int16_t:       trace_i16_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint16_t:      trace_u16_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    int32_t:       trace_i32_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint32_t:      trace_u32_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    int64_t:       trace_i64_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint64_t:      trace_u64_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    long long:     trace_ll_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    unsigned long long:                                                \
+                   trace_ull_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    float:         trace_f_   (__FILE__, __func__, __LINE__, #x_, x_), \
+    double:        trace_d_   (__FILE__, __func__, __LINE__, #x_, x_), \
+    long double:   trace_ld_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    /* pointer types */                                                \
+    void *:        trace_pvd_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    char *:        trace_pch_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    int8_t *:      trace_pi8_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint8_t *:     trace_pu8_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    int16_t *:     trace_pi16_(__FILE__, __func__, __LINE__, #x_, x_), \
+    uint16_t *:    trace_pu16_(__FILE__, __func__, __LINE__, #x_, x_), \
+    int32_t *:     trace_pi32_(__FILE__, __func__, __LINE__, #x_, x_), \
+    uint32_t *:    trace_pu32_(__FILE__, __func__, __LINE__, #x_, x_), \
+    int64_t *:     trace_pi64_(__FILE__, __func__, __LINE__, #x_, x_), \
+    uint64_t *:    trace_pu64_(__FILE__, __func__, __LINE__, #x_, x_), \
+    long long *:   trace_pll_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    unsigned long long *:                                              \
+                   trace_pull_(__FILE__, __func__, __LINE__, #x_, x_), \
+    float *:       trace_pf_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    double *:      trace_pd_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    long double *: trace_pld_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    /* catch-all clause */                                             \
+    default:       TRACE_DFLT (__FILE__, __func__, __LINE__, x_)       \
+))
+
+/*
+ * Same as TRACE(), except unsigned and floating point values are
+ * printed in hexadecimal.
+ */
+#define TRACEX(x_)  (_Generic( (x_),                                   \
+    /* arithmetic types */                                             \
+    uint8_t:       trace_x8_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint16_t:      trace_x16_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint32_t:      trace_x32_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint64_t:      trace_x64_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    unsigned long long:                                                \
+                   trace_xll_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    float:         trace_xf_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    double:        trace_xd_  (__FILE__, __func__, __LINE__, #x_, x_), \
+    long double:   trace_xld_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    /* pointer types */                                                \
+    uint8_t *:     trace_px8_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    uint16_t *:    trace_px16_(__FILE__, __func__, __LINE__, #x_, x_), \
+    uint32_t *:    trace_px32_(__FILE__, __func__, __LINE__, #x_, x_), \
+    uint64_t *:    trace_px64_(__FILE__, __func__, __LINE__, #x_, x_), \
+    unsigned long long *:                                              \
+                   trace_pxll_(__FILE__, __func__, __LINE__, #x_, x_), \
+    float *:       trace_pxf_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    double *:      trace_pxd_ (__FILE__, __func__, __LINE__, #x_, x_), \
+    long double *: trace_pxld_(__FILE__, __func__, __LINE__, #x_, x_), \
+    /* catch-all clause */                                             \
+    default:       (TRACE(x_))                                         \
+))
+
+/*
+ * Same as TRACE(), except char pointers are printed as strings.
+ */
+#define TRACES(x_)  (_Generic( (x_),                                   \
+    char *:        trace_pstr_(__FILE__, __func__, __LINE__, #x_, x_), \
+    default:       (TRACE(x_))                                         \
+))
+
+/*
+ * Same as TRACEX(), except char pointers are printed as strings.
+ */
+#define TRACEXS(x_) (_Generic( (x_),                                   \
+    char *:        trace_pstr_(__FILE__, __func__, __LINE__, #x_, x_), \
+    default:       (TRACEX(x_))                                        \
+))
+
+#else
+    #define TRACE(x_)    (x_)
+    #define TRACEX(x_)   (x_)
+    #define TRACES(x_)   (x_)
+    #define TRACEXS(x_)  (x_)
+#endif  //def TRACE_ON
+
+#endif  //ndef TRACE_H_