LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/trace/src_utility - trace_cntl.c (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 0.0 % 1475 0
Test Date: 2026-10-29 00:35:58 Functions: 0.0 % 20 0

            Line data    Source code
       1              : /*  This file (Trace_test.c) was created by Ron Rechenmacher <ron@fnal.gov> on
       2              :     Jan 15, 2014. "TERMS AND CONDITIONS" governing this file are in the README
       3              :     or COPYING file. If you do not have such a file, one can be obtained by
       4              :     contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
       5              :     $RCSfile: trace_cntl.c,v $
       6              :     */
       7              : #define TRACE_CNTL_REV "$Revision: 1778 $$Date: 2026-09-27 23:42:09 -0500 (Sun, 27 Sep 2026) $"
       8              : /*
       9              : NOTE: This is a .c file instead of c++ mainly because C is friendlier when it
      10              :       comes to extended initializer lists.
      11              : gxx_standards.sh trace_cntl.c
      12              : for std in $standards;do\
      13              :   for ll in 0 1 2 3;do echo $std $ll:;TRACE_LVL=$ll ./Trace_test-$std;done;\
      14              : done
      15              : 
      16              : */
      17              : #include <stdio.h> /* printf */
      18              : #ifndef __USE_MISC
      19              : #       define __USE_MISC
      20              : #endif
      21              : #include <sched.h>
      22              : #ifndef __USE_BSD
      23              : #       define __USE_BSD
      24              : #endif
      25              : #include <stdlib.h>   /* setenv */
      26              : #include <stdint.h>   /* uint64_t */
      27              : #include <libgen.h>   /* basename */
      28              : #include <unistd.h>   /* getopt */
      29              : #include <getopt.h>   /* getopt */
      30              : #include <sys/time.h> /* gettimeofday, struct timeval */
      31              : #include <pthread.h>  /* pthread_self */
      32              : #include <locale.h>   /* setlocale */
      33              : #include <string.h>   /* strnlen */
      34              : 
      35              : #include "TRACE/trace.h"
      36              : //#define TRACE_NAME basename(__FILE__)  // don't define TRACE_NAME, so ton* (w/o -n or -N) works on default TRACE_NAME "TRACE"
      37              : 
      38              : struct {
      39              :         const char *cmd;
      40              :         const char *hlp;
      41              : } subcmdhlp[]= {
      42              :         {"show [-HqF|-c<count>|-s<startSlotIdx>",
      43              :          "[opts] [file[:off_usec]]...   # Notes: -s invalid with multiple files; LC_NUMERIC=en_US.UTF-8 for %%'[df]"},
      44              :         {"info", ""},
      45              :         {"tids", ""},
      46              :         {"memreport [--sys] [--max-reverse-us <us>]", "per-TID counts of messages currently in memory by TRACE level (default max-reverse-us=10000)"},
      47              :         {"cntl", ""},
      48              :         {"mode[M|S]", ""},
      49              :         {"getcpu <1|0>", "enable/disable system call to get cpu on ARM architecture (fast path)"},
      50              :         {"lvlstrs", ""},
      51              :         {"lvl{msk,set,clr}<M|S|T>[g|G] <lvlmsk>",
      52              :          "M=memory, S=slow/console, T=trig; G=only active (not empth), g=all (current and futur)"},
      53              :         {"lvl{msk,set,clr}[g|G] <mskM> <mskS> <mskT>", "provide all 3 masks; G=only active (not empth), g=all (current and futur)"},
      54              :         {"trig", ""},
      55              :         {"limit_ms", ""},
      56              :         {"unlock", ""},
      57              :         {"sleep", ""},
      58              :         {"test1", ""},
      59              :         {"test-ro", ""},
      60              :         {"test-compare",
      61              :          "[-lloops] [test [modes [outfile]]]  compare TRACE fmt+args vs. format+args converted (via sprintf). dflt loops=%d\n\
      62              : examples: tcntl test-compar\n\
      63              :           for ff in '' ' %%F:';do TRACE_PRINT=\"%%T %%n %%*L$ff %%M\" tcntl test-compare 1 2;done\n\
      64              :           tcntl test-compare 8 0xa t.t; tshow|tdelta -stats|tail -5; cat t.t|tdelta -d 1 -i -stats|tail -5"},
      65              :         {"test-threads", ""},
      66              :         {"test", "tests various things (see output)."},
      67              : };
      68              : #define USAGE  \
      69              :         "\
      70              : %s [opts] <cmd> [command opt/args]\n\
      71              : commands:\n\
      72              :  show [opts] [file[:off_usec]]...   # Note: files... feature: -s invalid; mixed 32/64 environs not supported.\n\
      73              :  info\n\
      74              :  tids                    # show raw level bit masks for \n\
      75              :  memreport [--sys] [--max-reverse-us <us>]  # show per-TID TRACE level counts of messages currently in memory (dflt 10000)\n\
      76              :                          # max-reverse-us should be set to a allow reporting on a buffer that is actively\n\
      77              :                          # being written to. One of the factors to consider is the size of the buffer.\n\
      78              :  cntl <int>              # __func__ prepended to memory msg - 1=always, 0=TRACE_PRINT %%F, -1=never\n\
      79              :  mode <mode>\n\
      80              :  modeM <mode>\n\
      81              :  modeS <mode>\n\
      82              :  getcpu <0|1>                      # for ARM architecture only\n\
      83              :  lvlstrs                           # print the lvlstrs arrary\n\
      84              :  lvlmsk[M|S|T][g] <lvlmsk>         # M=memory, S=slow/console, T=trig\n\
      85              :  lvlmsk[g|G] <mskM> <mskS> <mskT>  # g=current and future name slots; G=only active (not empty)\n\
      86              :  lvlset[g|G] <mskM> <mskS> <mskT>  # g=current and future name slots; G=only active (not empty)\n\
      87              :  lvlclr[g|G] <mskM> <mskS> <mskT>  # g=current and future name slots; G=only active (not empty)\n\
      88              :  trig <postEntries> [lvlmskTM+] [quiet] # opt 2nd arg is for specified/dflt TID\n\
      89              :  reset\n\
      90              :  limit_ms <cnt> <on_ms> <off_ms>\n\
      91              :  unlock\n\
      92              :  sleep [seconds]     # dlft:10 - allows time to look at /proc/fd/ and /proc/maps\n\
      93              : opts:\n\
      94              :  -?, -h       show this help\n\
      95              :  -f<file>\n\
      96              :  -n<name>     name. For all commands - not wildcard, created if non-existent\n\
      97              :  -N<name>     name. For lvl*, could be wildcard match spec.\n\
      98              :  -V           print version and exit\n\
      99              :  -a           for tids, show all\n\
     100              : show opts:\n\
     101              :  -H           no header\n\
     102              :  -q           silence format errors\n\
     103              :  -F           show forward, poll for new entries. \"count\" (each files) avoids older entries\n\
     104              :  -c<count>    \n\
     105              :  -s<startSlotIndex> \n\
     106              :  other options encoded in TRACE_SHOW env.var.; export LC_NUMERIC=en_US or en_US.UTF-8 of %%'[df]\n\
     107              : tests:  (use %s show after test)\n\
     108              :  -x<thread_options_mask>    b0=TRACE_CNTL\"file\", b1=TRACE_CNTL\"name\", b2=count mappings b3=more TRACEs\n\
     109              :  -l<loops>\n\
     110              :  -t         print timing stats to stderr\n\
     111              : \n\
     112              : " USAGE_TESTS, \
     113              :                 basename(argv[0]), basename(argv[0]), DFLT_TEST_COMPARE_ITERS, /*USAGE_TESTS PARAMS*/ NUMTHREADS
     114              : #define USAGE_TESTS \
     115              :         "\
     116              :  test1 [-lloops]  a single TRACE lvl 2 [or more if loops != 0]\n\
     117              :  test-ro        test first page of mmap read-only (for kernel module)\n\
     118              :  test-compare [-lloops] [test [modes [outfile]]]  compare TRACE fmt+args vs. format+args converted (via sprintf). dflt loops=%d\n\
     119              :                 NOTE: \"loops\" gets multipled: \"disabled\" mode - 10x; \"mem only\" - 5x\n\
     120              :                 for ff in '' ' %%F:';do TRACE_PRINT=\"%%T %%n %%*L$ff %%M\" tcntl test-compare 1 2;done\n\
     121              :                 tcntl test-compare 8 0xa t.t; tshow|tdelta -stats|tail -5; cat t.t|tdelta -d 1 -i -stats|tail -5\n\
     122              :  test-threads [-t] [-x<thread_opts>] [-lloops] [-bburst] [-ddly_ms] [num_threads]  Tests threading. loops\n\
     123              :                        of TRACEs: 2-info's, 1-debug, 1-dbg+1, 1-dbg+2  dflts: -x0 -l2 num_threads=%d\n\
     124              :  test           various\n\
     125              :   example:\n\
     126              :   for tt in `seq 0 6`;do export TRACE_NUMENTS=500000\\\n\
     127              :    printf \"$tt: \";rm -f /tmp/trace_buffer_$USER;toffS info -ntrace_cntl;tcntl test-threads $tt -tl3000000;\\\n\
     128              :   done\n\
     129              :  TRACE [-t,-l<loops>,-L<linenum>,--] <lvl> <fmt> [ulong or double]...   Note: double if contains any of \".INnPp\"; -\n\
     130              :                                                  export LC_NUMERIC=en_US.UTF-8 for %%'[df] for TRACE(slow) and show(mem))\n\
     131              : "
     132              : 
     133              : // Started by copying macros from trace.h and adjusting (adding va_list ap = TRACE_VA_LIST_INIT(arrblk) in particular)
     134              : #define VTRACE(lvl, nargs, msg, arrblk)                                                                                       \
     135              :         do {                                                                                                                      \
     136              :                 struct {                                                                                                              \
     137              :                         char tn[TRACE_TN_BUFSZ];                                                                                          \
     138              :                 } _trc_;                                                                                                              \
     139              :                 if TRACE_INIT_CHECK (trace_name(TRACE_NAME, __FILE__, _trc_.tn, sizeof(_trc_.tn))) {                                  \
     140              :                         struct timeval lclTime;                                                                                           \
     141              :                         uint8_t lvl_= (uint8_t)(lvl);                                                                                     \
     142              :                         TRACE_SBUFDECL;                                                                                                   \
     143              :                         lclTime.tv_sec= 0;                                                                                                \
     144              :                         if (traceControl_rwp->mode.bits.M && (traceLvls_p[traceTID].M & TLVLMSK(lvl_))) {                                 \
     145              :                                 /* Note: "...NARGS...+2" don't know if any args are long doubles, so support 2 on 64 and 4 on 32 bit archs */ \
     146              :                                 va_list ap= TRACE_VA_LIST_INIT(arrblk);                                                                       \
     147              :                                 vtrace(&lclTime, traceTID, lvl_, __TRACE_LINE__, __func__, nargs, msg, ap);                                   \
     148              :                         }                                                                                                                 \
     149              :                         if (traceControl_rwp->mode.bits.S && (traceLvls_p[traceTID].S & TLVLMSK(lvl_))) {                                 \
     150              :                                 TRACE_LIMIT_SLOW(lvl_, _insert, &lclTime)                                                                     \
     151              :                                 {                                                                                                             \
     152              :                                         va_list ap= TRACE_VA_LIST_INIT(arrblk);                                                                   \
     153              :                                         vtrace_user(&lclTime, traceTID, lvl_, _insert, __FILE__, __TRACE_LINE__, __func__, nargs, msg, ap);       \
     154              :                                 }                                                                                                             \
     155              :                         }                                                                                                                 \
     156              :                 }                                                                                                                     \
     157              :         } while (0)
     158              : 
     159              : #define VTRACEN(nam, lvl, nargs, msg, arrblk)                                                                                    \
     160              :         do {                                                                                                                         \
     161              :                 struct {                                                                                                                 \
     162              :                         char tn[TRACE_TN_BUFSZ];                                                                                             \
     163              :                 } _trc_;                                                                                                                 \
     164              :                 if TRACE_INIT_CHECK (trace_name(TRACE_NAME, __FILE__, _trc_.tn, sizeof(_trc_.tn))) {                                     \
     165              :                         static TRACE_THREAD_LOCAL int tid_= -1;                                                                              \
     166              :                         struct timeval lclTime;                                                                                              \
     167              :                         uint8_t lvl_= (uint8_t)(lvl);                                                                                        \
     168              :                         TRACE_SBUFDECL;                                                                                                      \
     169              :                         if (tid_ == -1) tid_= trace_tlog_name_(&(nam)[0], TRACE_NAME, __TRACE_FILE__, __FILE__, _trc_.tn, sizeof(_trc_.tn)); \
     170              :                         lclTime.tv_sec= 0;                                                                                                   \
     171              :                         if (traceControl_rwp->mode.bits.M && (traceLvls_p[tid_].M & TLVLMSK(lvl_))) {                                        \
     172              :                                 /* Note: "...NARGS...+2" don't know if any args are long doubles, so support 2 on 64 and 4 on 32 bit archs */    \
     173              :                                 va_list ap= TRACE_VA_LIST_INIT(arrblk);                                                                          \
     174              :                                 vtrace(&lclTime, tid_, lvl_, __TRACE_LINE__, __func__, nargs, msg, ap);                                          \
     175              :                         }                                                                                                                    \
     176              :                         if (traceControl_rwp->mode.bits.S && (traceLvls_p[tid_].S & TLVLMSK(lvl_))) {                                        \
     177              :                                 TRACE_LIMIT_SLOW(lvl_, _insert, &lclTime)                                                                        \
     178              :                                 {                                                                                                                \
     179              :                                         va_list ap= TRACE_VA_LIST_INIT(arrblk);                                                                      \
     180              :                                         vtrace_user(&lclTime, tid_, lvl_, _insert, __FILE__, __TRACE_LINE__, __func__, nargs, msg, ap);              \
     181              :                                 }                                                                                                                \
     182              :                         }                                                                                                                    \
     183              :                 }                                                                                                                        \
     184              :         } while (0)
     185              : 
     186            0 : unsigned long *add_ul_arg(unsigned long *args_ptr, unsigned long *end_ptr, unsigned long arg)
     187              : {
     188            0 :         unsigned long *ret_val= args_ptr;
     189            0 :         unsigned long *vp= (unsigned long *)args_ptr;
     190            0 :         if ((vp + 1) <= (unsigned long *)end_ptr) {
     191            0 :                 *vp++= arg;
     192            0 :                 ret_val= (unsigned long *)vp;
     193              :         }
     194            0 :         return (ret_val);
     195              : }
     196              : 
     197            0 : unsigned long *add_double_arg(unsigned long *args_ptr, unsigned long *end_ptr, double arg)
     198              : {
     199            0 :         unsigned long *ret_val= args_ptr;
     200            0 :         double *vp= (double *)args_ptr;
     201            0 :         if ((vp + 1) <= (double *)end_ptr) {
     202            0 :                 *vp++= arg;
     203            0 :                 ret_val= (unsigned long *)vp;
     204              :         }
     205            0 :         return (ret_val);
     206              : }
     207              : 
     208              : #define DFLT_TEST_COMPARE_ITERS 500000
     209              : #define minw(a, b)              ((b) < (a) ? a : b) /* min width -- really max of the 2 numbers - argh */
     210              : 
     211              : #define DFLT_FILE_WIDTH ((int)sizeof("file") - 1)
     212              : #ifdef __linux__
     213              : //# define DFLT_SHOW         "HxNTPiCnLR"
     214              : #       define DFLT_SHOW "%H%x%N %T %P %i %C %e %O%.3L%o %m"
     215              : #else
     216              : //# define DFLT_SHOW         "HxNTPinLR"
     217              : #       define DFLT_SHOW "%H%x%N %T %P %i %e %.3L %m"
     218              : #endif
     219              : 
     220              : #define NUMTHREADS 4
     221              : static int trace_thread_option= 0;
     222              : 
     223              : typedef struct {
     224              :         unsigned tidx;
     225              :         unsigned loops;
     226              :         float dly_ms;
     227              :         unsigned burst;
     228              : } args_t;
     229              : 
     230            0 : void *thread_func(void *arg)
     231              : {
     232            0 :         args_t *argsp= (args_t *)arg;
     233            0 :         unsigned tidx= argsp->tidx;
     234            0 :         float dly_ms= argsp->dly_ms;
     235            0 :         unsigned burst= argsp->burst;
     236            0 :         unsigned loops= argsp->loops;
     237            0 :         unsigned lp;
     238            0 :         char tmp[PATH_MAX];
     239            0 :         pid_t tid= trace_gettid();
     240              : 
     241            0 :         if (trace_thread_option & 1) {
     242              :                 /* IF -std=c11 is NOT used, a seg fault usually occurs if default file does not exit */
     243            0 :                 snprintf(tmp, sizeof(tmp), "/tmp/trace_buffer_%u", tidx);
     244            0 :                 TRACE_CNTL("file", tmp);
     245              :         }
     246            0 :         if (trace_thread_option & 2) {
     247            0 :                 snprintf(tmp, sizeof(tmp), "TEST_THR_%u", tidx); /* a name per thread...*/
     248              :                 /*...-- may fill up namLvlTbl (w/ "larger" number of threads), but that should be OK */
     249            0 :                 TRACE_CNTL("name", tmp);
     250              :         } else
     251            0 :                 strcpy(tmp, "TEST_THR");
     252              : 
     253            0 :         for (lp= 0; lp < loops;) {
     254              :                 /* NOTE: be mindful of classic issue with macro -- args could be evaluted multiple times! */
     255              :                 /* BUT -- when TRACE-ing a value, there you would not likely operate on it */
     256            0 :                 ++lp;
     257            0 :                 TRACE(TLVL_INFO,
     258              :                           "tidx=%u loop=%d of %d tid=%d I need to test longer messages. They need to be about 256 characters - longer than the "
     259              :                           "circular memory message buffer size. This will check for message mangling",
     260              :                           tidx, lp, loops, tid);
     261            0 :                 if (trace_thread_option & 8) { /* do more TRACEs */
     262            0 :                         TRACE(TLVL_INFO,
     263              :                           "tidx=%u loop=%d of %d tid=%d this is the second long message - second0 second1 second2 second3 second4 second5 "
     264              :                           "second6 second7 second8 second9",
     265              :                           tidx, lp, loops, tid);
     266            0 :                         TRACE(TLVL_DEBUG,
     267              :                           "tidx=%u loop=%d of %d tid=%d this is the third long message - third0 third1 third2 third3 third4 third5 third6 "
     268              :                           "third7 third8 third9",
     269              :                           tidx, lp, loops, tid);
     270            0 :                         TRACE(TLVL_DBG + 1,
     271              :                           "tidx=%u loop=%d of %d tid=%d this is the fourth long message - fourth0 fourth1 fourth2 fourth3 fourth4 fourth5 "
     272              :                           "fourth6 fourth7 fourth8 fourth9",
     273              :                           tidx, lp, loops, tid);
     274            0 :                         TRACEN(tmp, TLVL_DBG + 2, "tidx=%u loop=%d of %d tid=%d - extra, if enabled", tidx, lp, loops, tid);
     275              :                 }
     276            0 :                 if (dly_ms && (lp % burst) == 0) usleep(dly_ms * 1000);
     277              :         }
     278            0 :         if (argsp->tidx) pthread_exit(NULL);
     279              :         else
     280            0 :                 return (NULL);
     281              : } /* thread_func */
     282              : 
     283            0 : static uint64_t gettimeofday_us(void)
     284              : {
     285            0 :         struct timeval tv;
     286            0 :         gettimeofday(&tv, NULL);
     287            0 :         return (uint64_t)(tv.tv_sec * 1000000 + tv.tv_usec);
     288              : }
     289              : 
     290              : /* This function searches the enum spec. One may think - just search the trace_lvlstrs[] array,
     291              :    but the issue is, some levels in the enum may have alternate designations.
     292              :    In the end, search both -- 1st, the enum spec and 2nd, the trace_lvlstrs
     293              :    which could be filled from the enum spec or the TRACE_LVLSTRS env.var.
     294              :  */
     295            0 : int str2enum(const char *ss)
     296              : {
     297            0 :         char lvlstr_a[]=
     298              :                 TRACE_STR(TRACE_LVL_ENUM_0_9, TRACE_LVL_ENUM_10_63); /* the code below assumes the input compiles as an enum spec */
     299            0 :         char *lvlstr= lvlstr_a;
     300            0 :         int retidx;
     301            0 :         char *endptr, *savptr, *cp;
     302              :         // 1 of 3 - search for env.var. TLVL_<LVL>   e.g. export TLVL_JONES=8
     303            0 :         if (strncmp(ss, "TLVL_", 5) == 0 && (cp= getenv(ss)) && (*cp)) {  // See if the answer is in the env
     304            0 :                 int val= (int)strtoul(cp, &endptr, 0);
     305            0 :                 if (*endptr == '\0') return (val);
     306              :         }
     307              :         // 2 of 3 - enum tlvle_t definition
     308            0 :         for (retidx= 0; lvlstr; ++retidx, lvlstr= endptr) {
     309            0 :                 savptr= endptr= strpbrk(lvlstr, ",= ");  // savptr used below to delimit individual enum strings
     310            0 :                 if (endptr) {
     311            0 :                         if (*endptr == '=') {
     312            0 :                                 int rettmp;
     313            0 :                                 char *sav2= endptr + 1;
     314            0 :                                 while (*sav2 == ' ') ++sav2;
     315            0 :                                 rettmp= (int)strtoul(sav2, (char **)&endptr, 0); /* works only if value is not a previous enum enumerator */
     316            0 :                                 if (endptr == sav2) {                            // assume it's THE previous enum enumerator; need to adjust endptr
     317            0 :                                         --retidx;
     318            0 :                                         endptr= strpbrk(sav2, ", ");
     319            0 :                                         if (endptr == NULL)
     320            0 :                                                 endptr= sav2 + strlen(sav2);  // sav2 should be single token, just need endptr to point to the end of it.
     321              :                                 } else
     322            0 :                                         retidx= rettmp;
     323              :                         }
     324            0 :                         while (isspace(*endptr)) ++endptr; /* space before ',' */
     325            0 :                         ++endptr;                          /* must be ',' */
     326            0 :                         while (isspace(*endptr)) ++endptr; /* space after ',' */
     327            0 :                         *savptr= '\0';                     /* terminate to allow strcmp (e.g. lvlstr points to "TLVL_WARNING")*/
     328              :                 }
     329            0 :                 if (strcasecmp(ss, lvlstr) == 0) return (retidx);
     330            0 :                 else if ((cp= index(lvlstr, '_')) != NULL && strcasecmp(ss, ++cp) == 0)
     331            0 :                         return (retidx);  // match when [^_]*_ prefix removed
     332              :         }
     333              :         // 3 of 3 - trace_lvlstrs, which could be loaded by TRACE_LVLSTRS (comma sep list of lvlstrs e.g export TRACE_LVLSTRS=mylvl0
     334            0 :         for (retidx= 0; retidx < 64; ++retidx) {
     335            0 :                 if (strcasecmp(ss, trace_lvlstrs[0][retidx]) == 0) break;
     336              :         }
     337            0 :         if (retidx == 64) retidx= TLVL_ERROR;
     338              :         return (retidx);
     339              : } /* str2enum */
     340              : 
     341              : //                  32bit      64bit
     342              : //                --------   --------
     343              : //    char         1 byte     1 bytes   * always pushed as long - 4 on 32, 8 on 64
     344              : //    short        2 bytes    2 bytes   * always pushed as long - 4 on 32, 8 on 64
     345              : //    int          4 bytes    4 bytes
     346              : //    float        4 bytes    4 bytes   * always pushed as double/8 on both 32 and 64
     347              : //    long         4 bytes    8 bytes
     348              : //    void *       4 bytes    8 bytes
     349              : //    double       8 bytes    8 bytes
     350              : //    long long    8 bytes    8 bytes
     351              : //    long double 12 bytes   16 bytes   * 80 bit extended precision in 96; 128 bits
     352              : //
     353              : // used to direct the copying of the trace entry parameters block as a part of "show"
     354              : struct sizepush {
     355              :         unsigned
     356              :                 size : 16;  // size (number of bytes) an arg is when it's not pushed as determined by a combination of the traced fmt and fundamental param size of the executed TRACE statement (myEnt_p->param_bytes)
     357              :         unsigned push : 16;  // size (number of bytes) an arg was pushed onto stack and copied into the trace entry parameters block
     358              :         unsigned positive;   // 1=%d%p 0=%u
     359              : };                       // For example, '%hd' w/param_bytes=4  size=2, push=4
     360              : //                '%hd' w/param_bytes=8  size=2, push=8
     361              : // usually args are ints size=sizeof(int) and pushed as long (the fundamental
     362              : // size of the arch addresses) push=sizeof(long) (which is usually sizeof (void*))
     363              : 
     364              : enum show_opts_e { filter_newline_= 0x1, quiet_= 0x2, indent_= 0x4, forward_= 0x8 };
     365              : 
     366            0 : size_t get_arg_sizes(char *ofmt, char *ifmt, int opts, int param_bytes, struct sizepush *sizes_out, unsigned nargs)
     367              : {
     368            0 :         char *in;
     369            0 :         char *percent_sav;
     370            0 :         unsigned numArgs= 0;
     371            0 :         unsigned maxArgs= (nargs < traceControl_p->num_params ? nargs : traceControl_p->num_params);
     372            0 :         int modifier= 0;
     373            0 :         int filter_newline= opts & filter_newline_;
     374            0 :         size_t slen= 0;
     375              : 
     376              :         /*strcpy( ofmt, ifmt );*/
     377            0 :         in= ifmt;
     378              :         /* strchrnul would be nice (_GNU_SOURCE, ref. man strchr) */
     379              :         /*while ((in=strchr(in,'%')))*/
     380            0 :         while (*in) {
     381            0 :                 if (*in != '%') {
     382            0 :                         if (*in != '\n') ofmt[slen++]= *in++;
     383              :                         else {
     384            0 :                                 if (filter_newline) {
     385            0 :                                         ofmt[slen++]= ';';
     386            0 :                                         in++;
     387              :                                 } else {
     388            0 :                                         ofmt[slen++]= *in++;
     389              :                                 }
     390              :                         }
     391            0 :                         continue;
     392              :                 }
     393              :                 /* found '%' - process it */
     394            0 :                 ofmt[slen]= *in;
     395            0 :                 percent_sav= ofmt + slen; /* save in case we need to modify it (too many args) */
     396            0 :                 ++in;
     397            0 :                 ++slen; /* point to next char */
     398            0 :                 sizes_out[numArgs].positive= 0;
     399              :                 /*printf("next char=%c\n",*in);*/
     400            0 :                 if ((*in == '%') || (*in == 'm')) {
     401            0 :                         ofmt[slen++]= *in++;
     402            0 :                         continue;
     403              :                 } /* ingore %% which specified a % char */
     404            0 :                 if (numArgs == maxArgs) {
     405            0 :                         *percent_sav= '*';
     406            0 :                         continue;
     407              :                 } /* SAFETY - no args beyond max */
     408            0 :                 while (((*in >= '0') && (*in <= '9')) || (*in == '.') || (*in == '-') || (*in == '#') || (*in == '+') || (*in == '\'') ||
     409            0 :                            (*in == 'I') || (*in == '"'))
     410            0 :                         ofmt[slen++]= *in++;
     411              :         chkChr:
     412            0 :                 switch (*in) {
     413              :                         /* Basic conversion specifiers */
     414            0 :                 case 'd':
     415              :                 case 'i':
     416              :                 case 'o':
     417              :                 case 'u':
     418              :                 case 'x':
     419              :                 case 'X':
     420              :                 case 'c':
     421            0 :                         switch (modifier) {
     422            0 :                         case -2:
     423            0 :                                 sizes_out[numArgs].push= (unsigned short)param_bytes;
     424            0 :                                 sizes_out[numArgs].size= 4;
     425            0 :                                 break; /* char */
     426            0 :                         case -1:
     427            0 :                                 sizes_out[numArgs].push= (unsigned short)param_bytes;
     428            0 :                                 sizes_out[numArgs].size= 4;
     429            0 :                                 break; /* short */
     430            0 :                         case 0:
     431            0 :                                 sizes_out[numArgs].push= (unsigned short)param_bytes;
     432            0 :                                 sizes_out[numArgs].size= 4;
     433            0 :                                 break; /* int */
     434            0 :                         case 1:
     435            0 :                                 sizes_out[numArgs].push= (unsigned short)param_bytes;
     436            0 :                                 sizes_out[numArgs].size= (unsigned short)param_bytes; /* long */
     437            0 :                                 if ((param_bytes == 8) && (sizeof(long) == 4)) ofmt[slen++]= 'l';
     438            0 :                                 break;
     439            0 :                         case 2:
     440            0 :                                 sizes_out[numArgs].push= 8;
     441            0 :                                 sizes_out[numArgs].size= 8;
     442            0 :                                 break; /* long long */
     443            0 :                         default: printf("error\n");
     444              :                         }
     445            0 :                         if (strchr("di", *in)) sizes_out[numArgs].positive= 1;
     446            0 :                         ofmt[slen++]= *in++;
     447            0 :                         modifier= 0;
     448            0 :                         break;
     449            0 :                 case 'e':
     450              :                 case 'E':
     451              :                 case 'f':
     452              :                 case 'F':
     453              :                 case 'g':
     454              :                 case 'G':
     455              :                 case 'a':
     456              :                 case 'A':
     457            0 :                         if (modifier) { /* long double */
     458            0 :                                 sizes_out[numArgs].push= (param_bytes == 4) ? 12 : 16;
     459            0 :                                 sizes_out[numArgs].size= (param_bytes == 4) ? 12 : 16;
     460            0 :                                 modifier= 0;
     461              :                         } else { /* double */
     462            0 :                                 sizes_out[numArgs].push= 8;
     463            0 :                                 sizes_out[numArgs].size= 8;
     464              :                         }
     465            0 :                         ofmt[slen++]= *in++;
     466            0 :                         modifier= 0;
     467            0 :                         break;
     468              : 
     469              :                         /* length modifiers */
     470            0 :                 case 'h':
     471            0 :                         --modifier;
     472            0 :                         ofmt[slen++]= *in++;
     473            0 :                         goto chkChr;
     474            0 :                 case 'l':
     475            0 :                         ++modifier;
     476            0 :                         ofmt[slen++]= *in++;
     477            0 :                         goto chkChr;
     478            0 :                 case 'L':
     479            0 :                         ++modifier;
     480            0 :                         ofmt[slen++]= *in++;
     481            0 :                         goto chkChr;
     482            0 :                 case 'z':
     483            0 :                         ++modifier;
     484            0 :                         ofmt[slen++]= *in++;
     485            0 :                         goto chkChr;
     486              : 
     487            0 :                 case 's':
     488              :                 case 'n':
     489              :                 case 'p': /* SAFETY -- CONVERT %s to %p */
     490              :                         // for 's', first need to remove "-.0123456789" b/c %p take no flags
     491            0 :                         if (*in == 's')
     492            0 :                                 while (strchr("-.0123456789", ofmt[slen - 1])) --slen;
     493            0 :                         sizes_out[numArgs].push= (unsigned short)param_bytes;
     494            0 :                         sizes_out[numArgs].size= (unsigned short)param_bytes;
     495            0 :                         if ((param_bytes == 8) && (sizeof(long) == 4)) {  // traced on 64, showing on 32
     496              :                                 strcpy(&ofmt[slen - 1], "0x%llx");            // overwrite the original '%'
     497              :                                 slen+= 5;
     498              :                         } else
     499            0 :                                 ofmt[slen++]= 'p';
     500            0 :                         in++;
     501            0 :                         break;
     502            0 :                 case 'm':  // (Glibc extension.)  Print output of strerror(errno).  No argument is required.
     503            0 :                         ofmt[slen++]= *in++;
     504            0 :                         continue;
     505              :                         break;
     506            0 :                 case '*': /* special -- "arg" in an arg */
     507            0 :                         sizes_out[numArgs].push= (unsigned short)param_bytes;
     508            0 :                         sizes_out[numArgs].size= 4 /*int*/;
     509            0 :                         sizes_out[numArgs].positive= 1;
     510            0 :                         if (++numArgs == maxArgs) {
     511            0 :                                 ofmt[slen++]= *in++;
     512            0 :                                 break;
     513              :                         }
     514            0 :                         ofmt[slen++]= *in++;
     515            0 :                         goto chkChr;
     516            0 :                 default:
     517            0 :                         if (!(opts & quiet_)) printf("tshow: unknown format spec char \"%c\" encountered with nargs=%u.\n", *in, nargs);
     518            0 :                         ofmt[slen++]= *in++;
     519              :                 }
     520            0 :                 ++numArgs;
     521              :         }
     522            0 :         while (*in) ofmt[slen++]= *in++;
     523            0 :         ofmt[slen]= '\0';
     524              :         //while (*ofmt == '\n') *ofmt-- = '\0';
     525            0 :         if (numArgs < maxArgs) sizes_out[numArgs].push= 0;
     526            0 :         return (slen);
     527              : } /* get_arg_sizes */
     528              : 
     529            0 : int countDigits(int n) { return (n >= 10) ? 1 + countDigits(n / 10) : 1; }
     530              : 
     531              : /*
     532              :         terse      medium     verbose       Important: for "verbose"*, must allow %*L for "auto right justify"
     533              : 1        3            6          8                     * verbose would be the default, to get "terse", use TRACE_LVLSTRS
     534              : F       FTL         FATAL        FATAL                   use TRACE_LVLSTRS vs "trace_lvlstrs[altidx]" ???
     535              : E       ERR         ERROR        ERROR
     536              : W       WRN          WARN      WARNING
     537              : I       NFO          INFO         INFO      super verbose: INFORMATION??? 
     538              : L       LOG           LOG          LOG
     539              : D       D55        DBG_55     DEBUG_55
     540              : 
     541              : 
     542              : 
     543              :      mem/fast                 cout/slow         valid flags
     544              :     TRACE_SHOW               TRACE_PRINT        -----------
     545              : %a    nargs              <->
     546              : %b    tbuf fileName                          %-7b => print last 7 chars of file; %7b => print first 7 chars of file
     547              : %B    paramBytes                
     548              : %C    cpu               *<->  
     549              : %D    inDent
     550              : %e    combined name:ln#
     551              : %F    [prepend to msg?]       function          %nF 0(or none)=abbreviated; 1=long      to get "short/consistent" C/C++ (__func__/__PRETTY_FUNCTION__)????
     552              : %f    raw_message_format      file_name         %nf n=#path_components #=strstr_search_follows
     553              : %H    Header            *
     554              : %I    TrcID              <->  
     555              : %i    threadID          *<->  
     556              : %L    lvStr             *<->* lvStr               %*L  *=auto_width  %.1L gets rid of %S (below)
     557              : %l    lvNum              <->   
     558              : %M                          * msgInsert+Msg
     559              : %m    message           *<->
     560              : %N    idx               *     TrcName_nopad                 
     561              : %n    TrcNamePadded     *<->* TrcNamePadded       %*n   *auto_padded  %n would be no padding
     562              : %P    processID         *<->   
     563              : %R    retries           *
     564              : %S    severity_char      <->                             CAN GET RID OF THIS. REPLACED BY %.1L
     565              : %s    slt                     
     566              : %T    time              *<->* time
     567              : %t    tsc                     insert (if !null)
     568              : %u    linenum            <->
     569              : %x    filterNewline
     570              : %X    eXamine arg data                               for tshow <file>...
     571              : 
     572              : <-> indicates same for both
     573              : *   indicates default
     574              : default TRACE_SHOW="%H%x%N %T %P %i %C %n %L %R %m"
     575              : default TRACE_PRINT="%T %n %L %M"
     576              : SHOW  others: a:nargs b:fileName B:paramBytes D:inDent f:convertedMsgfmt_only I:trcId l:lvl_int s:slot t:tsc
     577              : PRINT others: C:core s:severity I:trcId i:threadID f:file N:unpadded_trcName P:pid u:line
     578              : 
     579              : 
     580              : TRACE_NAME=%-f     <----<<< could add program name here (via %p???), but should still have a way to put it in TRACE_PRINT also???
     581              : TRACE_NAME=%p-%-f  NOTE: TRACE_NAME is not meant to be a "big" string (so the filename is usually the basename 
     582              : */
     583              : 
     584            0 : void printEnt(const char *ospec, int opts, struct traceEntryHdr_s *myEnt_p, char *local_msg, uint8_t *local_params,
     585              :                           struct sizepush *params_sizes, int bufSlot_width, int N_width, int name_width, unsigned printed, uint32_t rdIdx,
     586              :                           char *tfmt, int tfmt_len, const char *file)
     587              : {
     588            0 :         unsigned uu;
     589            0 :         char *msg_p;
     590            0 :         uint64_t *params_p;
     591            0 :         size_t slen;
     592            0 :         time_t seconds;
     593            0 :         int useconds;
     594            0 :         void *param_va_ptr;
     595            0 :         uint8_t *ent_param_ptr;
     596            0 :         uint8_t *lcl_param_ptr;
     597            0 :         const char *sp; /*spec ptr*/
     598            0 :         int msg_spec_included;
     599            0 :         char *cp;
     600            0 :         char *indent= "                                                                ";
     601              : 
     602            0 :         msg_p= (char *)(myEnt_p + 1);
     603            0 :         params_p= (uint64_t *)(msg_p + traceControl_p->siz_msg);
     604              : 
     605            0 :         msg_p[traceControl_p->siz_msg - 1]= '\0';
     606            0 :         if (myEnt_p->nargs) slen= get_arg_sizes(local_msg, msg_p, opts, myEnt_p->param_bytes, params_sizes, myEnt_p->nargs);
     607              :         else {
     608            0 :                 if (opts & filter_newline_) {
     609            0 :                         for (slen= 0; slen < traceControl_p->siz_msg && msg_p[slen] != '\0'; ++slen)
     610            0 :                                 local_msg[slen]= (msg_p[slen] != '\n') ? msg_p[slen] : ';';
     611              :                 } else {
     612              :                         /* strncpy( local_msg, msg_p, traceControl_p->siz_msg ); */
     613            0 :                         for (slen= 0; slen < traceControl_p->siz_msg && msg_p[slen] != '\0'; ++slen) local_msg[slen]= msg_p[slen];
     614              :                 }
     615            0 :                 if (slen < traceControl_p->siz_msg) local_msg[slen]= '\0';
     616            0 :                 else if (traceControl_p->siz_msg > 0)  // if no term in 1st n bytes
     617            0 :                         local_msg[--slen]= '\0';           // adjust strlen and terminate
     618              :         }
     619              : 
     620              :         /* Determine if args need to be copied/converted (32/64-bit)
     621              :                    Because timestamps need to be adjusted and compared in traceShow,
     622              :            they have already been 32/64-bit adjusted
     623              :                  */
     624            0 :         seconds= myEnt_p->time.tv_sec;
     625            0 :         useconds= (int)myEnt_p->time.tv_usec;
     626            0 :         if (((myEnt_p->param_bytes == 4) && (sizeof(long) == 4)) || ((myEnt_p->param_bytes == 8) && (sizeof(long) == 8))) {
     627              :                 param_va_ptr= (void *)params_p;
     628            0 :         } else if (((myEnt_p->param_bytes == 4) && (sizeof(long) == 8))) {  // Entry made by 32bit program, being readout by 64bit
     629              :                 ent_param_ptr= (uint8_t *)params_p;
     630              :                 lcl_param_ptr= local_params;
     631            0 :                 for (uu= 0; uu < myEnt_p->nargs && params_sizes[uu].push != 0; ++uu) {
     632            0 :                         if (params_sizes[uu].push == 4) {
     633            0 :                                 if (params_sizes[uu].positive) {
     634            0 :                                         *(long *)lcl_param_ptr= (long)*(int *)ent_param_ptr;
     635              :                                         //printf( "converting from 0x%x\n", *(int*)ent_param_ptr );
     636              :                                 } else {
     637            0 :                                         *(unsigned long *)lcl_param_ptr= (unsigned long)*(unsigned *)ent_param_ptr;
     638              :                                         //printf( "converting to 0x%lx\n", *(unsigned long*)lcl_param_ptr );
     639              :                                 }
     640            0 :                                 lcl_param_ptr+= sizeof(long);
     641            0 :                         } else if (params_sizes[uu].push == 12)  // i.e. i686 long double - arm and ppc do not have 12 byte (long) double
     642              :                         {
     643              : #if defined(__arm__) || defined(__powerpc__) || defined(__aarch64__) || (__GNUC__ < 4)
     644              :                                 *(long double *)lcl_param_ptr= 0.0;  // __arm__: error: unable to emulate 'XC';
     645              : #else
     646            0 :                                 typedef _Complex float __attribute__((mode(XC))) _float80;
     647            0 :                                 *(long double *)lcl_param_ptr= *(long double *)(_float80 *)ent_param_ptr;
     648              : #endif
     649            0 :                                 lcl_param_ptr+= sizeof(long double);
     650              :                         } else /* (params_sizes[uu].push == 8) */
     651              :                         {
     652            0 :                                 *(long *)lcl_param_ptr= *(long *)ent_param_ptr;
     653            0 :                                 lcl_param_ptr+= sizeof(long);
     654              :                         }
     655            0 :                         ent_param_ptr+= params_sizes[uu].push;
     656              :                 }
     657              :                 param_va_ptr= (void *)local_params;
     658              :         } else /* (  ((myEnt_p->param_bytes==8) && (sizeof(long)==4)) ) */
     659              :         {      // Entry made by 64bit program, being shown by 32bit
     660              :                 ent_param_ptr= (uint8_t *)params_p;
     661              :                 lcl_param_ptr= local_params;
     662            0 :                 for (uu= 0; uu < myEnt_p->nargs && params_sizes[uu].push != 0; ++uu) {
     663            0 :                         if (params_sizes[uu].size == 4)  // i.e. char, short, int
     664              :                         {
     665            0 :                                 *(unsigned *)lcl_param_ptr= (unsigned)*(unsigned long long *)ent_param_ptr;
     666            0 :                                 lcl_param_ptr+= sizeof(long);
     667            0 :                         } else if (params_sizes[uu].size == 16)  // i.e. long double
     668              :                         {
     669              : #if defined(__APPLE__) || defined(__arm__) || \
     670              :         defined(__powerpc__)  // Basically mixed 32/64 env w/ long double is not supported on Mac/clang; shouldn't be a big deal
     671              :                                 *(long double *)lcl_param_ptr= 0.0;
     672              : #elif defined(__aarch64__)
     673              :                                 *(long double *)lcl_param_ptr= *(long double *)ent_param_ptr;
     674              : #else
     675            0 :                                 *(long double *)lcl_param_ptr= *(long double *)(__float128 *)ent_param_ptr;
     676              : #endif
     677            0 :                                 lcl_param_ptr+= sizeof(long double);
     678              :                         } else  // (params_sizes[uu].size == 8) i.e.
     679              :                         {
     680            0 :                                 *(unsigned long long *)lcl_param_ptr= *(unsigned long long *)ent_param_ptr;
     681            0 :                                 lcl_param_ptr+= sizeof(long long);
     682              :                         }
     683            0 :                         ent_param_ptr+= params_sizes[uu].push;
     684              :                 }
     685              :                 param_va_ptr= (void *)local_params;
     686              :         }
     687              : 
     688            0 :         msg_spec_included= 0;
     689            0 :         for (sp= ospec; *sp; ++sp) {
     690            0 :                 char tbuf[0x100];
     691            0 :                 int width_state, width_ia[2]= {0}; /* allow up to 3 widths w[.w] */
     692            0 :                 char width_ca[2][9];               /* need to save the string for leading "0" (e.g. "-04"*/
     693            0 :                 char flags_ca[4], *sncp;           /*  */
     694            0 :                 int snlen;
     695            0 :                 size_t flags_sz;
     696              :                 //const char *default_unknown_sav;
     697            0 :                 char *endptr;
     698              : 
     699            0 :                 if (*sp != '%') {
     700            0 :                         printf("%c", *sp);
     701            0 :                         continue;
     702              :                 }
     703            0 :                 if (*++sp == '\0') {
     704            0 :                         printf("%%");  // print the trailing/ending %
     705            0 :                         break;
     706              :                 }
     707              : 
     708              :                 /* look for a width/flag spec - see trace.h:vtrace_user(...)  */
     709            0 :                 flags_sz= strspn(sp, "#*."); /* originally:"#-+ '*."      %#n.mf#/src#  */
     710            0 :                 if (flags_sz) {
     711            0 :                         snprintf(flags_ca, TRACE_MIN(flags_sz + 1, sizeof(flags_ca)), "%s", sp);  // snprintf always terminates
     712            0 :                         sp+= flags_sz;  // use just flags_sz here to ignore wacky +++++++
     713              :                 } else
     714            0 :                         flags_ca[0]= '\0';
     715            0 :                 for (width_state= 0; width_state < 2; ++width_state) {
     716            0 :                         width_ia[width_state]= (int)TRACE_STRTOL(sp, &endptr, 10);
     717            0 :                         if (endptr == sp || endptr > (sp + 4)) { /* check if no num or num too big (allow "-099") */
     718            0 :                                 width_ca[width_state][0]= '\0';
     719            0 :                                 break;
     720              :                         }
     721            0 :                         snprintf(width_ca[width_state], sizeof(width_ca[0]), "%.*s", (int)(endptr - sp), sp);
     722            0 :                         sp= endptr;
     723            0 :                         if (*sp == '.') ++sp;
     724              :                 }
     725              : 
     726            0 :                 switch (*sp) {
     727            0 :                 case '%': printf("%%"); break;
     728            0 :                 case 'a': printf("%4u", myEnt_p->nargs); break;
     729            0 :                 case 'b':
     730            0 :                         if (!width_state) {
     731            0 :                                 int last= DFLT_FILE_WIDTH;
     732            0 :                                 if (last > (int)strlen(file)) last= strlen(file);
     733            0 :                                 printf("%*.*s", DFLT_FILE_WIDTH, DFLT_FILE_WIDTH, file + strlen(file) - last);
     734              :                         } else {
     735            0 :                                 int field_width= abs(width_ia[0]);
     736            0 :                                 if (field_width < DFLT_FILE_WIDTH) field_width= DFLT_FILE_WIDTH;
     737            0 :                                 if (width_ia[0] < 0) {
     738              :                                         /* print the end of the filename */
     739            0 :                                         width_ia[0]= abs(width_ia[0]);
     740            0 :                                         if (width_ia[0] > (int)strlen(file)) width_ia[0]= strlen(file);
     741            0 :                                         printf("%*.*s", field_width, width_ia[0], file + strlen(file) - width_ia[0]);
     742              :                                 } else
     743            0 :                                         printf("%*.*s", field_width, abs(width_ia[0]), file);
     744              :                         }
     745              :                         break;
     746            0 :                 case 'B': printf("%u", myEnt_p->param_bytes); break;
     747            0 :                 case 'C': printf("%" TRACE_STR(TRACE_CPU_WIDTH) "d", myEnt_p->cpu); break;
     748              :                 case 'D': /* ignore this "control" */ break;
     749            0 :                 case 'e':
     750            0 :                         snlen= snprintf(tbuf, sizeof(tbuf), "%s:%d", TRACE_TID2NAME(myEnt_p->TrcId), myEnt_p->linenum);
     751            0 :                         if (!width_state) printf("%*.*s", name_width + 1 + TRACE_LINENUM_WIDTH, name_width + 1 + TRACE_LINENUM_WIDTH, tbuf);
     752              :                         else {
     753            0 :                                 if (width_ia[0] < (TRACE_LINENUM_WIDTH + 1)) width_ia[0]= (TRACE_LINENUM_WIDTH + 1);
     754            0 :                                 if (width_ia[0] > (int)(traceControl_p->nam_arr_sz + TRACE_LINENUM_WIDTH))
     755            0 :                                         width_ia[0]= (int)(traceControl_p->nam_arr_sz + TRACE_LINENUM_WIDTH);
     756            0 :                                 if (snlen > width_ia[0]) sncp= &tbuf[snlen - width_ia[0]];
     757              :                                 else
     758              :                                         sncp= &tbuf[0];
     759            0 :                                 printf("%*s", width_ia[0], sncp);
     760              :                         }
     761              :                         break;
     762            0 :                 case 'f':
     763            0 :                         printf("%s", local_msg);
     764            0 :                         msg_spec_included= 1;
     765            0 :                         break;
     766              :                 case 'H': /* ignore this "control" */ break;
     767            0 :                 case 'I': printf("%4u", myEnt_p->TrcId); break;
     768            0 :                 case 'i': printf("%*d", TRACE_TID_WIDTH, myEnt_p->tid); break; /* darwin 16 tids are routinely 7 digit */
     769            0 :                 case 'L': {
     770            0 :                         char altbuf[0x100], l3buf[4], *lvlcp= trace_lvlstrs[0][(myEnt_p->lvl) & TLVLBITSMSK];
     771            0 :                         int vwidth;
     772            0 :                         if (trace_build_L_fmt(tbuf, altbuf, l3buf, &lvlcp, &vwidth, flags_ca, width_ia, width_ca)) printf(tbuf, vwidth, lvlcp);
     773              :                         else
     774            0 :                                 printf(tbuf, lvlcp);
     775            0 :                 } break;
     776            0 :                 case 'l': /*printf("%2d", myEnt_p->lvl); break;*/
     777            0 :                         if (!width_state) printf("%2d", myEnt_p->lvl);
     778              :                         else {
     779            0 :                                 if (width_ia[0] < 2) width_ia[0]= 2;
     780            0 :                                 printf("%*d", width_ia[0], myEnt_p->lvl);
     781              :                         }
     782              :                         break;
     783            0 :                 case 'm':
     784            0 :                         if (local_msg[slen - 1] == '\n') local_msg[--slen]= '\0';  // strip off the trailing newline
     785            0 :                         if (opts & indent_) printf("%s", &indent[TLVLBITSMSK - (myEnt_p->lvl & TLVLBITSMSK)]);
     786            0 :                         if (myEnt_p->nargs) {
     787            0 :                                 va_list ap_= TRACE_VA_LIST_INIT(param_va_ptr);
     788            0 :                                 vprintf(local_msg, ap_);
     789              :                         } else
     790            0 :                                 printf("%s", local_msg);
     791              :                         msg_spec_included= 1;
     792              :                         break;
     793            0 :                 case 'N': printf("%*u", N_width, printed); break;
     794            0 :                 case 'n':
     795            0 :                         if (!width_state) printf("%*.*s", name_width, name_width, TRACE_TID2NAME(myEnt_p->TrcId));
     796              :                         else {
     797            0 :                                 if (width_ia[0] < (int)strlen("trcname")) width_ia[0]= strlen("trcname");
     798            0 :                                 if (width_ia[0] > (int)(traceControl_p->nam_arr_sz - 1)) width_ia[0]= (int)(traceControl_p->nam_arr_sz - 1);
     799            0 :                                 sncp= TRACE_TID2NAME(myEnt_p->TrcId);
     800            0 :                                 snlen= strlen(sncp);
     801            0 :                                 if (snlen > width_ia[0]) sncp= &sncp[snlen - width_ia[0]];
     802            0 :                                 printf("%*.*s", width_ia[0], width_ia[0], sncp);
     803              :                         }
     804              :                         break;
     805            0 :                 case 'O': printf("%s", trace_lvlcolors[(myEnt_p->lvl) & TLVLBITSMSK][0]); break;
     806            0 :                 case 'o': printf("%s", trace_lvlcolors[(myEnt_p->lvl) & TLVLBITSMSK][1]); break;
     807            0 :                 case 'P':
     808            0 :                         printf("%*d", TRACE_TID_WIDTH, myEnt_p->pid);
     809            0 :                         break; /* /proc/sys/kernel/pid_max has 32768 or 458752 (on mu2edaq13) */
     810            0 :                 case 'R':
     811            0 :                         if (myEnt_p->get_idxCnt_retries) printf("%u", myEnt_p->get_idxCnt_retries);
     812              :                         else
     813            0 :                                 printf(".");
     814              :                         break;
     815            0 :                 case 'S': printf("%c", trace_lvlstrs[0][(myEnt_p->lvl) & TLVLBITSMSK][0]); break;
     816            0 :                 case 's': printf("%*u", bufSlot_width, rdIdx % traceControl_p->num_entries); break;
     817            0 :                 case 'T':
     818            0 :                         if (tfmt_len) {
     819            0 :                                 strftime(tbuf, sizeof(tbuf), tfmt, localtime(&seconds));  // strcat(tbuf," ");
     820            0 :                                 if ((cp= strstr(tbuf, "%0")) && *(cp + 2) >= '1' && *(cp + 2) <= '5' && *(cp + 3) == 'd') {
     821              :                                         // NOTE: if *(cp+2)==6, don't do anything.
     822              :                                         // Example: fmt originally had "%%04d" which got changed by strftime to "%04d";
     823              :                                         // grab the character '4' and adjust useconds accordingly.
     824            0 :                                         int div= 1;
     825            0 :                                         switch (*(cp + 2)) {
     826              :                                         case '1': div= 100000; break;
     827              :                                         case '2': div= 10000; break;
     828              :                                         case '3': div= 1000; break;
     829              :                                         case '4': div= 100; break;
     830              :                                         case '5': div= 10; break;
     831              :                                         }
     832            0 :                                         useconds= (int)((double)useconds / div + 0.5);  // div, round and cast back to unsigned
     833              :                                 }
     834            0 :                                 printf(tbuf, useconds);
     835              :                         }
     836              :                         break;
     837            0 :                 case 't':
     838            0 :                         if (!width_state) printf("%10u", (unsigned)myEnt_p->tsc);
     839              :                         else
     840            0 :                                 printf("%20llu", (unsigned long long)myEnt_p->tsc);
     841              :                         break;
     842            0 :                 case 'u':
     843            0 :                         if (!width_state) printf("%" TRACE_STR(TRACE_LINENUM_WIDTH) "u", myEnt_p->linenum);
     844              :                         else
     845            0 :                                 printf("%*u", width_ia[0], myEnt_p->linenum);
     846              :                         break;
     847              :                 case 'x': /* ignore this "control" (filter_newline_ is set in opts) */ break;
     848              :                 case 'X':
     849            0 :                         params_p= (uint64_t *)param_va_ptr;
     850            0 :                         for (uu= 0; uu < myEnt_p->nargs; ++uu) printf("0x%016llx ", (unsigned long long)params_p[uu]);
     851              :                         msg_spec_included= 1;
     852              :                         break;
     853            0 :                 default: printf("%%%c", *sp); break;  // print unknown %<blah> sequence
     854              :                 }
     855              :         }
     856              : 
     857            0 :         if (!msg_spec_included) {
     858            0 :                 if (local_msg[slen - 1] == '\n') local_msg[--slen]= '\0';  // strip off the trailing newline
     859            0 :                 if (opts & indent_) printf("%s", &indent[TLVLBITSMSK - (myEnt_p->lvl & TLVLBITSMSK)]);
     860            0 :                 if (ospec[0] != '\0' && !strchr(" \t:-|", *(sp - 1)))  // if the specification does not end in a "separator"
     861            0 :                         printf(" ");
     862            0 :                 if (myEnt_p->nargs) { /* Ref. http://andrewl.dreamhosters.com/blog/variadic_functions_in_amd64_linux/index.html
     863              :                                    Here, I need an initializer so I must have this inside braces { } */
     864            0 :                         va_list ap_= TRACE_VA_LIST_INIT(param_va_ptr);
     865            0 :                         vprintf(local_msg, ap_);
     866              :                 } else
     867            0 :                         printf("%s", local_msg);
     868              :         }
     869            0 :         printf("\n");
     870            0 :         fflush(stdout);
     871            0 : } /* printEnt */
     872              : 
     873              : typedef struct trace_ptrs {
     874              :         struct trace_ptrs *next;
     875              :         struct trace_ptrs *prev;
     876              :         char file[PATH_MAX];
     877              :         int file_idx;
     878              :         struct traceControl_s *ro_p;
     879              :         struct traceControl_rw *rw_p;
     880              :         struct traceLvls_s *lvls_p;
     881              :         char *nams_p;
     882              :         struct traceEntryHdr_s *entries_p;
     883              :         uint32_t rdIdx;
     884              :         uint32_t max;
     885              :         int32_t offset_adjust;  /* for trace file from different nodes */
     886              :         struct timeval ref_tv;  // last/previously processed
     887              : } trace_ptrs_t;
     888              : 
     889            0 : void trace_ptrs_store(int idx, trace_ptrs_t *trace_ptrs, const char *file, int32_t off_adjust)
     890              : {
     891            0 :         if (idx == 0) trace_ptrs[idx].prev= NULL;
     892              :         else {
     893            0 :                 trace_ptrs[idx].prev= &trace_ptrs[idx - 1];
     894            0 :                 trace_ptrs[idx - 1].next= &trace_ptrs[idx];
     895              :         }
     896            0 :         strcpy(trace_ptrs[idx].file, file);
     897            0 :         trace_ptrs[idx].file_idx= idx;
     898            0 :         trace_ptrs[idx].ro_p= traceControl_p;
     899            0 :         trace_ptrs[idx].rw_p= traceControl_rwp;
     900            0 :         trace_ptrs[idx].lvls_p= traceLvls_p;
     901            0 :         trace_ptrs[idx].nams_p= traceNams_p;
     902            0 :         trace_ptrs[idx].entries_p= traceEntries_p;
     903            0 :         trace_ptrs[idx].offset_adjust= off_adjust;
     904              : 
     905            0 :         trace_ptrs[idx].next= NULL;
     906            0 : } /* trace_ptrs_store */
     907              : 
     908              : /* Designed to work in the code:
     909              :    for (t_ptrs=trace_ptrs_list_start; t_ptrs!=NULL; t_ptrs=t_ptrs->next )
     910              :        trace_ptrs_discard( t_ptrs, &trace_ptrs_list_start );
     911              :  */
     912            0 : void trace_ptrs_discard(trace_ptrs_t *tptr, trace_ptrs_t **list_start)
     913              : {
     914            0 :         trace_ptrs_t *prev= tptr->prev;
     915            0 :         trace_ptrs_t *next= tptr->next;
     916            0 :         if (next) next->prev= prev;
     917            0 :         if (prev) prev->next= next;
     918            0 :         if (prev == NULL && next == NULL) *list_start= NULL;
     919            0 : } /* trace_ptrs_discard */
     920              : 
     921            0 : const char *trace_ptrs_restore(trace_ptrs_t *tptr)
     922              : {
     923            0 :         traceControl_p= tptr->ro_p;
     924            0 :         traceControl_rwp= tptr->rw_p;
     925            0 :         traceLvls_p= tptr->lvls_p;
     926            0 :         traceNams_p= tptr->nams_p;
     927            0 :         traceEntries_p= tptr->entries_p;
     928            0 :         return tptr->file;
     929              : } /* trace_ptrs_restore */
     930              : 
     931              : /*  rdIdx and wrIdxCnt are BOTH non-modulo.
     932              :         For forward read: simple delta
     933              :         For reverse read: num_entries(or wrIdxCnt) - delta
     934              : 
     935              : NOT WORRYING ABOUT wrIdxCnt,rdIdx wrap yet -- Work-In-Progress!!!
     936              :  */
     937            0 : uint32_t rdIdx_has_lines(uint32_t wrIdxCnt, uint32_t rdIdx, int for_rev)
     938              : {
     939            0 :         uint32_t lines;
     940            0 :         if (for_rev == -1) {
     941              :                 // READING in reverse -- from large numbers to smaller; reading and writing are on head on collision course
     942            0 :                 if (wrIdxCnt <= traceControl_p->num_entries) {
     943              :                         //     0*********<-rw->_______End
     944            0 :                         lines= wrIdxCnt - TRACE_IDXCNT_DELTA(wrIdxCnt, rdIdx + 1);
     945              :                         //return ((lines<=wrIdxCnt)?lines:0);
     946            0 :                         return (lines);
     947              :                 } else {
     948            0 :                         lines= traceControl_p->num_entries - TRACE_IDXCNT_DELTA(wrIdxCnt, rdIdx + 1);
     949              :                         //return ((lines<=traceControl_p->num_entries)?lines:0);
     950            0 :                         return (lines);
     951              :                 }
     952              :         } else {
     953              :                 // READING forward (i.e from 0 up; read chasing writing; writing may overrun reading)
     954            0 :                 if (wrIdxCnt <= traceControl_p->num_entries) {
     955            0 :                         lines= TRACE_IDXCNT_DELTA(wrIdxCnt, rdIdx);
     956              :                         //return ((lines<=wrIdxCnt)?lines:0);
     957            0 :                         return (lines);
     958              :                 } else {
     959            0 :                         lines= TRACE_IDXCNT_DELTA(wrIdxCnt, rdIdx);
     960              :                         //return ((lines<=traceControl_p->num_entries)?lines:0);
     961            0 :                         return (lines);
     962              :                 }
     963              :         }
     964              : } /* rdIdx_has_lines */
     965              : 
     966            0 : void tv_from_ent(struct timeval *tvp, struct traceEntryHdr_s *myEnt_p)
     967              : {
     968            0 :         if (((myEnt_p->param_bytes == 4) && (sizeof(long) == 4)) ||
     969            0 :                 ((myEnt_p->param_bytes == 8) && (sizeof(long) == 8))) {  // 32, 32 or 64, 64 - no translation needed
     970            0 :                 tvp->tv_sec= myEnt_p->time.tv_sec;
     971            0 :                 tvp->tv_usec= myEnt_p->time.tv_usec;
     972            0 :         } else if (((myEnt_p->param_bytes == 4) && (sizeof(long) == 8))) {  // Entry made by 32bit program, being readout by 64bit
     973            0 :                 void *xx= &(myEnt_p->time);
     974            0 :                 int *ptr= (int *)xx;
     975            0 :                 tvp->tv_sec= *ptr++;
     976            0 :                 tvp->tv_usec= (int)*ptr;
     977              :         } else /* (  ((myEnt_p->param_bytes==8) && (sizeof(long)==4)) ) */
     978              :         {      // Entry made by 64bit program, being shown by 32bit
     979            0 :                 void *xx= &myEnt_p->time;
     980            0 :                 long long *ptr= (long long *)xx;
     981            0 :                 tvp->tv_sec= (time_t)*ptr++;
     982            0 :                 tvp->tv_usec= (int)*ptr;
     983              :         }
     984            0 : }
     985              : 
     986            0 : int tvcmp(struct timeval *tvp1, int32_t off1, struct timeval *tvp2, int32_t off2)
     987              : {
     988            0 :         uint64_t t1= tvp1->tv_sec * 1000000 + tvp1->tv_usec;
     989            0 :         uint64_t t2= tvp2->tv_sec * 1000000 + tvp2->tv_usec;
     990            0 :         t1+= off1;  // off1 could be negative
     991            0 :         t2+= off2;  // off1 could be negative
     992            0 :         if (t1 < t2) return (-1);
     993            0 :         else if (t1 == t2)
     994            0 :                 return (0);
     995              :         return (1);
     996              : } /* tvcmp */
     997              : 
     998            0 : char *check_off_adjust(char *fname)
     999              : {
    1000            0 :         char *cp= fname + strlen(fname);
    1001            0 :         char *last_ch= --cp;
    1002            0 :         while (*cp >= '0' && *cp <= '9' && *cp != ':' && *cp != '-' && cp != fname) --cp;
    1003            0 :         if (*cp == '-' && cp != fname) --cp;
    1004            0 :         if (cp != last_ch && *cp == ':' && cp != fname) return cp; /* watch out for fname=':123" */
    1005              :         return NULL;
    1006              : } /* check_off_adjust */
    1007              : 
    1008              : /*
    1009              :    ospec is TRACE_SHOW or DFLT_SHOW
    1010              :    count==-1, slotStart==-1  ==> DEFAULT - reverse print from wrIdx to zero (if not
    1011              :                                  full) or for num_entrie
    1012              :    count>=0,  slotStart==-1  ==> reverse print "count" entries (including 0, which
    1013              :                                  doesn't seem to useful
    1014              :    count>=0,  slotStart>=0   ==> reverse print count entries starting at "slot" idx
    1015              :                                  "slotStart"  I.e. if 8 traces have occurred, these 2
    1016              :                                  are equivalent:
    1017              :                                  traceShow( ospec, -1, -1, 0 ) and
    1018              :                                  traceShow( ospec,  8,  7, 0 )
    1019              :    show_opts = 0[|quiet_][|forward_]
    1020              :    arg, argv -- list of files to show
    1021              :  */
    1022            0 : void traceShow(const char *ospec, int count, int slotStart, int show_opts, int argc, char *argv[])
    1023              : {
    1024            0 :         uint32_t rdIdx;
    1025            0 :         uint32_t max;
    1026            0 :         unsigned printed= 0;
    1027            0 :         int ii;
    1028            0 :         int bufSlot_width;
    1029            0 :         int opts= 0;
    1030            0 :         struct traceEntryHdr_s *myEnt_p;
    1031              : 
    1032            0 :         uint8_t *local_params;
    1033            0 :         char *local_msg;
    1034            0 :         struct sizepush *params_sizes;
    1035            0 :         const char *sp; /*spec ptr*/
    1036            0 :         char *tfmt;
    1037            0 :         int tfmt_len;
    1038            0 :         time_t tt= time(NULL);
    1039            0 :         char tbuf[0x100], ttbuf[0x100];
    1040            0 :         int for_rev= -1;           /* default is reverse print */
    1041            0 :         int forward_continuous= 0; /* continuous==1 will force for_rev=1 */
    1042            0 :         int msg_spec_included;
    1043            0 :         int files_to_show= 0;
    1044            0 :         const char *file= "";
    1045            0 :         int memlen_out_unused __attribute__((__unused__));
    1046            0 :         trace_ptrs_t *t_ptrs, *trace_ptrs_list_start, *t_ptrs_use;
    1047            0 :         struct timeval tv_use= {0}, tv2;
    1048            0 :         int32_t off_use;
    1049            0 :         uint32_t name_width= 0;
    1050            0 :         uint32_t num_entries_total;
    1051            0 :         uint32_t siz_msg_largest;
    1052            0 :         uint32_t siz_entry_largest= 0;
    1053            0 :         uint32_t num_params_largest;
    1054            0 :         int N_width;
    1055            0 :         char file_during_fun[PATH_MAX];
    1056              : 
    1057            0 :         if ((slotStart != -1) && (argc >= 2)) {
    1058            0 :                 fprintf(stderr, "-s<startSlotIndex> invalid with multiple files\n");
    1059            0 :                 exit(EXIT_FAILURE);
    1060            0 :         } else if ((slotStart != -1) && (show_opts & forward_)) {
    1061            0 :                 fprintf(stderr, "-s<startSlotIndex> invalid with -F (Forward/poll mode)\n");
    1062            0 :                 exit(EXIT_FAILURE);
    1063              :         }
    1064            0 :         opts|= show_opts; /* see enum show_opts_e above */
    1065            0 :         opts|= (trace_strflg(ospec, 'D') ? indent_ : 0);
    1066            0 :         opts|= (trace_strflg(ospec, 'x') ? filter_newline_ : 0);
    1067              : 
    1068            0 :         if (argc == 0) {
    1069            0 :                 traceInit(
    1070              :                         "_TRACE_",
    1071              :                         1); /* init traceControl_p, traceControl_rwp, etc. Use "_TRACE_" to assure non-write to corrupted TRACE_FILE where "TRACE" may not exist */
    1072            0 :                 (void)tsnprintf(file_during_fun, sizeof(file_during_fun), getenv("TRACE_FILE") ? getenv("TRACE_FILE") : traceFile);
    1073            0 :                 trace_ptrs_list_start= (trace_ptrs_t *)malloc(sizeof(trace_ptrs_t) * 1);
    1074            0 :                 trace_ptrs_store(files_to_show++, trace_ptrs_list_start, file_during_fun, 0);
    1075              :         } else {
    1076            0 :                 trace_ptrs_list_start= (trace_ptrs_t *)malloc(sizeof(trace_ptrs_t) * (unsigned)argc);
    1077            0 :                 memset(trace_ptrs_list_start, 0, sizeof(trace_ptrs_t) * (unsigned)argc);
    1078            0 :                 trace_ptrs_list_start[0].prev= NULL;
    1079            0 :                 for (ii= 0; ii < argc; ++ii) {
    1080            0 :                         char *off_adjust_ptr= check_off_adjust(argv[ii]); /* check for :[0-9]+$ */
    1081            0 :                         if (off_adjust_ptr) *off_adjust_ptr++= '\0';      /* overwrite ':' with '\0' */
    1082            0 :                         (void)tsnprintf(file_during_fun, sizeof(file_during_fun), argv[ii]);
    1083            0 :                         if (access(file_during_fun, R_OK) != 0) {
    1084            0 :                                 fprintf(stderr, "Warning: cannot access %s\n", file_during_fun);
    1085            0 :                                 continue;
    1086              :                         }
    1087            0 :                         setenv("TRACE_FILE", file_during_fun, 1);
    1088              : #if 1
    1089            0 :                         traceControl_p= traceControl_p_static= NULL;  // trick to allow traceInit to (re)mmap (another) file
    1090            0 :                         traceInit(
    1091              :                                 "_TRACE_",
    1092              :                                 1); /* init traceControl_p, traceControl_rwp, etc. NOTE: multiple "register_atfork" will occur, but should be tolerated be this non-forking app */
    1093              : #else
    1094              :                         trace_mmap_file(file_during_fun, &memlen_out_unused, &traceControl_p,
    1095              :                                                         &traceControl_rwp  // NOTE: traceNamLvls_p, traceEntries_p are iniitalized
    1096              :                                                         ,
    1097              :                                                         0, 0, 0, 0, 1);
    1098              : #endif
    1099            0 :                         if (TRACE_CNTL("mapped")) {
    1100              :                                 int jj;
    1101            0 :                                 for (jj= 0; jj < files_to_show; ++jj) {
    1102            0 :                                         if (traceControl_p == trace_ptrs_list_start[jj].ro_p)
    1103              :                                                 // found
    1104              :                                                 break;
    1105              :                                 }
    1106            0 :                                 if (jj == files_to_show) {
    1107            0 :                                         int32_t off_adjust= off_adjust_ptr ? atoi(off_adjust_ptr) : 0;
    1108            0 :                                         trace_ptrs_store(files_to_show++, trace_ptrs_list_start, file_during_fun, off_adjust);
    1109              :                                 }
    1110              :                         }
    1111              :                 }
    1112            0 :                 if (files_to_show == 0) {
    1113            0 :                         fprintf(stderr, "Error: no files to show\n");
    1114            0 :                         return;
    1115              :                 }
    1116              :         }
    1117              : 
    1118              :         /* get the time format and the length of the format (using example time (now) */
    1119            0 :         if ((tfmt= getenv("TRACE_TIME_FMT")) == NULL)
    1120              :                 //tfmt=(char*)TRACE_DFLT_TIME_FMT;
    1121            0 :                 tfmt= (char *)"%10s%%06d";  // %s - The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
    1122            0 :         strftime(ttbuf, sizeof(ttbuf), tfmt, localtime(&tt));
    1123            0 :         tfmt_len= snprintf(tbuf, sizeof(tbuf), ttbuf, 0); /* possibly (probably) add usecs (i.e. FMT has %%06d) */
    1124              : 
    1125            0 :         if (trace_strflg(ospec, 'n') || trace_strflg(ospec, 'e'))
    1126            0 :                 for (name_width= 0, t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next)
    1127            0 :                         if (name_width < t_ptrs->rw_p->longest_name) {
    1128            0 :                                 name_width= t_ptrs->rw_p->longest_name;
    1129            0 :                                 if (name_width > t_ptrs->ro_p->nam_arr_sz) name_width= t_ptrs->ro_p->nam_arr_sz;
    1130              :                         }
    1131            0 :         for (num_entries_total= 0, t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next)
    1132            0 :                 num_entries_total+= t_ptrs->ro_p->num_entries;
    1133            0 :         for (siz_msg_largest= 0, num_params_largest= 0, t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next) {
    1134            0 :                 if (siz_msg_largest < t_ptrs->ro_p->siz_msg) siz_msg_largest= t_ptrs->ro_p->siz_msg;
    1135            0 :                 if (num_params_largest < t_ptrs->ro_p->num_params) num_params_largest= t_ptrs->ro_p->num_params;
    1136            0 :                 if (siz_entry_largest < t_ptrs->ro_p->siz_entry) siz_entry_largest= t_ptrs->ro_p->siz_entry;
    1137              :         }
    1138              : 
    1139              :         /* If just a count is given, it will be a way to limit the number printed;
    1140              :            a short hand version of "... | head -count". (so if there are not entries,
    1141              :            none will be printed.
    1142              :            If however, count and slotStart are given, the count (up to numents) will be
    1143              :            printed regardless of how many entries are actually filled with real
    1144              :            data. This gives a way to look at data after a "treset".
    1145              :         */
    1146            0 :         if (slotStart >= 0)  // only applicable with one file
    1147              :         {
    1148            0 :                 slotStart++; /* startSlot index needs to be turned into a "count" */
    1149            0 :                 if ((unsigned)slotStart > num_entries_total) {
    1150            0 :                         slotStart= (int)num_entries_total;
    1151            0 :                         printf("specified slotStart index too large, adjusting to %d\n", slotStart);
    1152              :                 }
    1153            0 :                 trace_ptrs_list_start->rdIdx= (uint32_t)slotStart;  // in "startSlot mode" rdIdx is not realative to wrIdxCnt
    1154            0 :                 trace_ptrs_list_start->ref_tv.tv_sec= 0;
    1155              :         } else { /* here, rdIdx starts as a count (see max = rdIdx below), but it is
    1156              :                    used as an index after first being decremented (assuming reverse
    1157              :                    printing) */
    1158            0 :                 for (t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next) {
    1159            0 :                         t_ptrs->rdIdx= TRACE_ATOMIC_LOAD(&t_ptrs->rw_p->wrIdxCnt);  // % t_ptrs->ro_p->num_entries;
    1160            0 :                         t_ptrs->ref_tv.tv_sec= 0;
    1161              :                 }
    1162              :         }
    1163              : 
    1164            0 :         if ((count >= 0) && (slotStart >= 0)) {  // only applicable with one file (the slotStart>=0 part)
    1165            0 :                 t_ptrs= trace_ptrs_list_start;
    1166            0 :                 if ((unsigned)count > num_entries_total) {
    1167            0 :                         max= t_ptrs->max= t_ptrs->ro_p->num_entries;
    1168            0 :                         count= (int)max;
    1169              :                 } else {
    1170            0 :                         max= t_ptrs->max= (uint32_t)count;
    1171              :                 }
    1172              :         } else {
    1173            0 :                 for (max= 0, t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next)
    1174            0 :                         if (TRACE_ATOMIC_LOAD(&t_ptrs->rw_p->wrIdxCnt) >= t_ptrs->ro_p->num_entries)
    1175              :                                 //max = traceControl_p->num_entries;
    1176            0 :                                 max+= t_ptrs->max= t_ptrs->ro_p->num_entries;
    1177              :                         else
    1178              :                                 //max = rdIdx;
    1179            0 :                                 max+= t_ptrs->max= t_ptrs->rdIdx;
    1180              :         }
    1181              : 
    1182            0 :         if ((count >= 0) && (slotStart < 0) && (count < (int)max))
    1183            0 :                 for (t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next) t_ptrs->max= (uint32_t)count;
    1184            0 :         if (opts & forward_) {
    1185            0 :                 for (t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next) {
    1186            0 :                         int32_t add= -(int32_t)t_ptrs->max;
    1187            0 :                         t_ptrs->rdIdx= TRACE_IDXCNT_ADD(TRACE_ATOMIC_LOAD(&t_ptrs->rw_p->wrIdxCnt), add);
    1188              :                         /* subtract 1 b/c during loop (below) rdIdx is incremented first */
    1189            0 :                         t_ptrs->rdIdx= TRACE_IDXCNT_ADD(t_ptrs->rdIdx, -1);
    1190              :                 }
    1191              :                 forward_continuous= 1;
    1192              :                 for_rev= 1;
    1193              :         }
    1194              : 
    1195              :         //printf("for_rev=%d slotStart=%d count=%d max=%d siz_msg_largest=%u num_params_largest=%u files_to_show=%d\n"
    1196              :         //       ,for_rev,slotStart,count,max,siz_msg_largest,num_params_largest, files_to_show);
    1197              : 
    1198            0 :         N_width= minw(3, countDigits((int32_t)max - 1));
    1199            0 :         bufSlot_width= minw(3, countDigits((int32_t)num_entries_total - 1));
    1200              : 
    1201            0 :         myEnt_p= (struct traceEntryHdr_s *)malloc(siz_entry_largest);
    1202            0 :         local_msg= (char *)malloc(siz_msg_largest * 3); /* in case an %ld needs change to %lld */
    1203            0 :         local_params= (uint8_t *)malloc(num_params_largest * sizeof(uint64_t));
    1204            0 :         params_sizes= (struct sizepush *)malloc(num_params_largest * sizeof(struct sizepush));
    1205              : 
    1206            0 :         if (trace_strflg(ospec, 'H')) {
    1207              :                 msg_spec_included= 0;
    1208              :                 /*                  123456789112345678921234*/
    1209              : #define TRACE_MSG_DASHES  "------------------------"
    1210              : #define TRACE_LONG_DASHES "------------------------------------------------------------------------------"
    1211            0 :                 for (sp= ospec; *sp; ++sp) {
    1212            0 :                         char tbuf[0x100];
    1213            0 :                         int width_state, width_ia[2]= {0}; /* allow up to 3 widths w[.w] */
    1214            0 :                         char width_ca[2][9];               /* need to save the string for leading "0" (e.g. "-04"*/
    1215            0 :                         char flags_ca[4];                  /*  */
    1216            0 :                         const char *sncp;
    1217            0 :                         int snlen;
    1218            0 :                         size_t flags_sz;
    1219              :                         //const char *default_unknown_sav;
    1220            0 :                         char *endptr;
    1221              : 
    1222            0 :                         if (*sp != '%') {
    1223            0 :                                 printf("%c", *sp);
    1224            0 :                                 continue;
    1225              :                         }
    1226            0 :                         if (*++sp == '\0') {
    1227            0 :                                 printf("%%");  // print the trailing/ending %
    1228            0 :                                 break;
    1229              :                         }
    1230              : 
    1231              :                         /* look for a width/flag spec - see trace.h:vtrace_user(...)  */
    1232            0 :                         flags_sz= strspn(sp, "#*."); /* originally:"#-+ '*."      %#n.mf#/src#  */
    1233            0 :                         if (flags_sz) {
    1234            0 :                                 snprintf(flags_ca, TRACE_MIN(flags_sz + 1, sizeof(flags_ca)), "%s", sp);  // snprintf always terminates
    1235            0 :                                 sp+= flags_sz;  // use just flags_sz here to ignore wacky +++++++
    1236              :                         } else
    1237            0 :                                 flags_ca[0]= '\0';
    1238            0 :                         for (width_state= 0; width_state < 2; ++width_state) {
    1239            0 :                                 width_ia[width_state]= (int)TRACE_STRTOL(sp, &endptr, 10);
    1240            0 :                                 if (endptr == sp || endptr > (sp + 4)) { /* check if no num or num too big (allow "-099") */
    1241            0 :                                         width_ca[width_state][0]= '\0';
    1242            0 :                                         break;
    1243              :                                 }
    1244            0 :                                 snprintf(width_ca[width_state], sizeof(width_ca[0]), "%.*s", (int)(endptr - sp), sp);
    1245            0 :                                 sp= endptr;
    1246            0 :                                 if (*sp == '.') ++sp;
    1247              :                         }
    1248              : 
    1249            0 :                         switch (*sp) {
    1250            0 :                         case '%': printf("%%"); break;
    1251            0 :                         case 'a': printf("args"); break;
    1252            0 :                         case 'b':
    1253            0 :                                 if (!width_state) printf("%*.*s", DFLT_FILE_WIDTH, DFLT_FILE_WIDTH, "file");
    1254              :                                 else {
    1255            0 :                                         if (width_ia[0] < 0 && width_ia[0] > -DFLT_FILE_WIDTH) width_ia[0]= -DFLT_FILE_WIDTH;
    1256            0 :                                         else if (width_ia[0] >= 0 && width_ia[0] < DFLT_FILE_WIDTH)
    1257            0 :                                                 width_ia[0]= DFLT_FILE_WIDTH;
    1258            0 :                                         printf("%*.*s", abs(width_ia[0]), abs(width_ia[0]), "file");
    1259              :                                 }
    1260              :                                 break;
    1261            0 :                         case 'B': printf("B"); break;
    1262            0 :                         case 'C': printf("cpu"); break;
    1263              :                         case 'D': /* ignore this "control" */ break;
    1264            0 :                         case 'e':
    1265            0 :                                 sncp= "trcname:ln#";
    1266            0 :                                 snlen= strlen(sncp);
    1267            0 :                                 if (!width_state) printf("%*s", name_width + 1 + TRACE_LINENUM_WIDTH, sncp);  // +1 for ':'
    1268              :                                 else {
    1269            0 :                                         if (width_ia[0] < (TRACE_LINENUM_WIDTH + 1)) width_ia[0]= TRACE_LINENUM_WIDTH + 1;
    1270            0 :                                         if (width_ia[0] > (int)(traceControl_p->nam_arr_sz + TRACE_LINENUM_WIDTH))
    1271            0 :                                                 width_ia[0]= (int)(traceControl_p->nam_arr_sz + TRACE_LINENUM_WIDTH);
    1272            0 :                                         if (snlen > width_ia[0]) sncp= &sncp[snlen - width_ia[0]];
    1273            0 :                                         printf("%*s", width_ia[0], sncp);
    1274              :                                 }
    1275              :                                 break;
    1276            0 :                         case 'f':
    1277            0 :                                 printf("%-*s", (int)strlen(TRACE_MSG_DASHES), "msg");
    1278            0 :                                 msg_spec_included= 1;
    1279            0 :                                 break;
    1280              :                         case 'H': /* ignore this "control" */ break;
    1281            0 :                         case 'I': printf(" TID"); break;
    1282            0 :                         case 'i': printf("%" TRACE_STR(TRACE_TID_WIDTH) "s", "tid"); break; /* darwin 16 tids are routinely 7 digit */
    1283            0 :                         case 'L':
    1284            0 :                                 if (strchr(flags_ca, '*')) printf("%*s", trace_lvlwidth, "lvl");
    1285              :                                 else {
    1286            0 :                                         strcpy(tbuf, "%");
    1287            0 :                                         if (strchr(flags_ca, '.')) strcpy(&tbuf[1], ".");
    1288            0 :                                         if (width_state >= 1) strcat(&tbuf[1], width_ca[0]);
    1289            0 :                                         if (width_state >= 2) {
    1290            0 :                                                 strcat(&tbuf[1], ".");
    1291            0 :                                                 strcat(&tbuf[2], width_ca[1]);
    1292              :                                         }
    1293            0 :                                         strcat(&tbuf[1], "s");
    1294            0 :                                         printf(tbuf, "lvl");
    1295              :                                 }
    1296              :                                 break;
    1297            0 :                         case 'l': /*printf("lv"); break;*/
    1298            0 :                                 if (!width_state) printf("lv");
    1299              :                                 else {
    1300            0 :                                         if (width_ia[0] < 2) width_ia[0]= 2;
    1301            0 :                                         printf("%*.*s", width_ia[0], width_ia[0], "lvlnum");
    1302              :                                 }
    1303              :                                 break;
    1304            0 :                         case 'm':
    1305            0 :                                 printf("%-*s", (int)strlen(TRACE_MSG_DASHES), "msg");
    1306            0 :                                 msg_spec_included= 1;
    1307            0 :                                 break;
    1308            0 :                         case 'N': printf("%*s", N_width, "idx"); break;
    1309            0 :                         case 'n':
    1310            0 :                                 if (!width_state) printf("%*s", name_width + 1 + TRACE_LINENUM_WIDTH, "trcname");
    1311              :                                 else {
    1312            0 :                                         if (width_ia[0] < 7) width_ia[0]= 7;
    1313            0 :                                         if (width_ia[0] > (int)(traceControl_p->nam_arr_sz - 1)) width_ia[0]= (int)(traceControl_p->nam_arr_sz - 1);
    1314            0 :                                         printf("%*s", width_ia[0], "trcname");
    1315              :                                 }
    1316              :                                 break;
    1317              :                         case 'O': /* ignore here */ break;
    1318              :                         case 'o': /* ignore here */ break;
    1319            0 :                         case 'P': printf("%" TRACE_STR(TRACE_TID_WIDTH) "s", "pid"); break;
    1320            0 :                         case 'R': printf("r"); break;
    1321            0 :                         case 'S': printf("%c", 'S'); break; /* Severity (1st character of lvlstr) */
    1322            0 :                         case 's': printf("%*s", bufSlot_width, "slt"); break;
    1323            0 :                         case 'T':
    1324            0 :                                 if (tfmt_len) printf("%*.*s", tfmt_len, tfmt_len, &("us_tod"[tfmt_len >= 6 ? 0 : 6 - tfmt_len]));
    1325              :                                 break;
    1326            0 :                         case 't':
    1327            0 :                                 if (!width_state) printf("       tsc");
    1328              :                                 else
    1329            0 :                                         printf("                 tsc");
    1330              :                                 break;
    1331            0 :                         case 'u':
    1332            0 :                                 if (!width_state) printf("%" TRACE_STR(TRACE_LINENUM_WIDTH) "s", "ln#");
    1333              :                                 else
    1334            0 :                                         printf("%*s", width_ia[0], "ln#");
    1335              :                                 break;
    1336              :                         case 'x': /* ignore this "control" */ break;
    1337            0 :                         case 'X':
    1338            0 :                                 printf("%-*s", (int)strlen(TRACE_MSG_DASHES), "msg");
    1339            0 :                                 msg_spec_included= 1;
    1340            0 :                                 break;
    1341            0 :                         default: printf("%%%c", *sp); break;  // print unknown %<blah> sequence
    1342              :                         }
    1343              :                 }
    1344            0 :                 if (!msg_spec_included) {
    1345            0 :                         if (!strchr(" \t:-|", *(sp - 1)))  // if the specification does not end in a "separator"
    1346            0 :                                 printf(" ");
    1347            0 :                         printf("%-*s\n", (int)strlen(TRACE_MSG_DASHES), "msg");
    1348            0 :                 } else if (*(sp - 1) != '\n')
    1349            0 :                         printf("\n");
    1350              : 
    1351              :                 msg_spec_included= 0;  // reset for the ---- processing
    1352            0 :                 for (sp= ospec; *sp; ++sp) {
    1353            0 :                         char tbuf[0x100];
    1354            0 :                         int width_state, width_ia[2]= {0}; /* allow up to 3 widths w[.w] */
    1355            0 :                         char width_ca[2][9];               /* need to save the string for leading "0" (e.g. "-04"*/
    1356            0 :                         char flags_ca[4];                  /*  */
    1357            0 :                         size_t flags_sz;
    1358              :                         //const char *default_unknown_sav;
    1359            0 :                         char *endptr;
    1360              : 
    1361            0 :                         if (*sp != '%') {
    1362            0 :                                 if (strchr(" \t\n", *sp)) printf("%c", *sp);
    1363              :                                 else
    1364            0 :                                         printf("-");
    1365            0 :                                 continue;
    1366              :                         }
    1367            0 :                         if (*++sp == '\0') {
    1368            0 :                                 printf("%%");  // print the trailing/ending %
    1369            0 :                                 break;
    1370              :                         }
    1371              : 
    1372              :                         /* look for a width/flag spec - see trace.h:vtrace_user(...)  */
    1373            0 :                         flags_sz= strspn(sp, "#*."); /* originally:"#-+ '*."      %#n.mf#/src#  */
    1374            0 :                         if (flags_sz) {
    1375            0 :                                 snprintf(flags_ca, TRACE_MIN(flags_sz + 1, sizeof(flags_ca)), "%s", sp);  // snprintf always terminates
    1376            0 :                                 sp+= flags_sz;  // use just flags_sz here to ignore wacky +++++++
    1377              :                         } else
    1378            0 :                                 flags_ca[0]= '\0';
    1379            0 :                         for (width_state= 0; width_state < 2; ++width_state) {
    1380            0 :                                 width_ia[width_state]= (int)TRACE_STRTOL(sp, &endptr, 10);
    1381            0 :                                 if (endptr == sp || endptr > (sp + 4)) { /* check if no num or num too big (allow "-099") */
    1382            0 :                                         width_ca[width_state][0]= '\0';
    1383            0 :                                         break;
    1384              :                                 }
    1385            0 :                                 snprintf(width_ca[width_state], sizeof(width_ca[0]), "%.*s", (int)(endptr - sp), sp);
    1386            0 :                                 sp= endptr;
    1387            0 :                                 if (*sp == '.') ++sp;
    1388              :                         }
    1389              : 
    1390            0 :                         switch (*sp) {
    1391            0 :                         case '%': printf("-"); break;
    1392            0 :                         case 'a': printf("----"); break;
    1393            0 :                         case 'b':
    1394            0 :                                 if (!width_state) printf("%*.*s", DFLT_FILE_WIDTH, DFLT_FILE_WIDTH, TRACE_LONG_DASHES);
    1395              :                                 else {
    1396            0 :                                         if (width_ia[0] < 0 && width_ia[0] > -DFLT_FILE_WIDTH) width_ia[0]= -DFLT_FILE_WIDTH;
    1397            0 :                                         else if (width_ia[0] >= 0 && width_ia[0] < DFLT_FILE_WIDTH)
    1398            0 :                                                 width_ia[0]= DFLT_FILE_WIDTH;
    1399            0 :                                         printf("%*.*s", abs(width_ia[0]), abs(width_ia[0]), TRACE_LONG_DASHES);
    1400              :                                 }
    1401              :                                 break;
    1402            0 :                         case 'B': printf("-"); break;
    1403            0 :                         case 'C': printf("---"); break;
    1404              :                         case 'D': /* ignore this "control" */ break;
    1405            0 :                         case 'e':
    1406            0 :                                 if (!width_state) printf("%.*s", name_width + 1 + TRACE_LINENUM_WIDTH, TRACE_LONG_DASHES);
    1407              :                                 else {
    1408            0 :                                         if (width_ia[0] < (TRACE_LINENUM_WIDTH + 1)) width_ia[0]= (TRACE_LINENUM_WIDTH + 1);
    1409            0 :                                         if (width_ia[0] > (int)(traceControl_p->nam_arr_sz + TRACE_LINENUM_WIDTH))
    1410            0 :                                                 width_ia[0]= (int)(traceControl_p->nam_arr_sz + TRACE_LINENUM_WIDTH);
    1411            0 :                                         printf("%.*s", width_ia[0], TRACE_LONG_DASHES);
    1412              :                                 }
    1413              :                                 break;
    1414            0 :                         case 'f':
    1415            0 :                                 printf(TRACE_MSG_DASHES);
    1416            0 :                                 msg_spec_included= 1;
    1417            0 :                                 break;
    1418              :                         case 'H': /* ignore this "control" */ break;
    1419            0 :                         case 'I': printf("----"); break;
    1420            0 :                         case 'i':
    1421            0 :                                 printf("%." TRACE_STR(TRACE_TID_WIDTH) "s", TRACE_LONG_DASHES);
    1422            0 :                                 break; /* darwin 16 tids are routinely 7 digit */
    1423            0 :                         case 'L':
    1424            0 :                                 if (strchr(flags_ca, '*')) printf("%.*s", trace_lvlwidth, TRACE_LONG_DASHES);
    1425              :                                 else {
    1426            0 :                                         strcpy(tbuf, "%");
    1427            0 :                                         if (strchr(flags_ca, '.')) strcpy(&tbuf[1], ".");
    1428            0 :                                         if (width_state >= 1) strcat(&tbuf[1], width_ca[0]);
    1429            0 :                                         if (width_state >= 2) {
    1430            0 :                                                 strcat(&tbuf[1], ".");
    1431            0 :                                                 strcat(&tbuf[2], width_ca[1]);
    1432            0 :                                         } else if (tbuf[1] != '.') {
    1433            0 :                                                 strcat(&tbuf[1], ".");
    1434            0 :                                                 strcat(&tbuf[2], width_ca[0]);
    1435              :                                         }
    1436            0 :                                         strcat(&tbuf[1], "s");
    1437            0 :                                         printf(tbuf, TRACE_LONG_DASHES);
    1438              :                                 }
    1439              :                                 break;
    1440            0 :                         case 'l': /*printf("--");*/
    1441            0 :                                 if (!width_state) printf("--");
    1442              :                                 else {
    1443            0 :                                         if (width_ia[0] < 2) width_ia[0]= 2;
    1444            0 :                                         printf("%.*s", width_ia[0], TRACE_LONG_DASHES);
    1445              :                                 }
    1446              :                                 break;
    1447            0 :                         case 'm':
    1448            0 :                                 printf(TRACE_MSG_DASHES);
    1449            0 :                                 msg_spec_included= 1;
    1450            0 :                                 break;
    1451            0 :                         case 'N': printf("%.*s", N_width, TRACE_LONG_DASHES); break;
    1452            0 :                         case 'n':
    1453            0 :                                 if (!width_state) printf("%.*s", name_width, TRACE_LONG_DASHES);
    1454              :                                 else {
    1455            0 :                                         if (width_ia[0] < (int)strlen("trcname")) width_ia[0]= strlen("trcname");
    1456            0 :                                         if (width_ia[0] > (int)(traceControl_p->nam_arr_sz - 1)) width_ia[0]= (int)(traceControl_p->nam_arr_sz - 1);
    1457            0 :                                         printf("%.*s", width_ia[0], TRACE_LONG_DASHES);
    1458              :                                 }
    1459              :                                 break;
    1460              :                         case 'O': /* ignore here */ break;
    1461              :                         case 'o': /* ignore here */ break;
    1462            0 :                         case 'P': printf("%." TRACE_STR(TRACE_TID_WIDTH) "s", TRACE_LONG_DASHES); break;
    1463            0 :                         case 'R': printf("-"); break;
    1464            0 :                         case 'S': printf("-"); break; /* Severity (1st character of lvlstr) */
    1465            0 :                         case 's': printf("%.*s", bufSlot_width, TRACE_LONG_DASHES); break;
    1466            0 :                         case 'T':
    1467            0 :                                 if (tfmt_len) printf("%.*s", tfmt_len, TRACE_LONG_DASHES);
    1468              :                                 break;
    1469            0 :                         case 't':
    1470            0 :                                 if (!width_state) printf("----------");
    1471              :                                 else
    1472            0 :                                         printf("--------------------");
    1473              :                                 break;
    1474            0 :                         case 'u':
    1475            0 :                                 if (!width_state) printf("%." TRACE_STR(TRACE_LINENUM_WIDTH) "s", TRACE_LONG_DASHES);
    1476              :                                 else
    1477            0 :                                         printf("%.*s", width_ia[0], TRACE_LONG_DASHES);
    1478              :                                 break;
    1479              : 
    1480              :                         case 'x': /* ignore this "control" */ break;
    1481            0 :                         case 'X':
    1482            0 :                                 printf(TRACE_MSG_DASHES);
    1483            0 :                                 msg_spec_included= 1;
    1484            0 :                                 break;
    1485            0 :                         default: printf("%%%c", *sp); break;  // print unknown %<blah> sequence
    1486              :                         }
    1487              :                 }
    1488            0 :                 if (!msg_spec_included) {
    1489            0 :                         if (!strchr(" \t:-|", *(sp - 1)))  // if the specification does not end in a "separator"
    1490            0 :                                 printf(" ");
    1491            0 :                         printf(TRACE_MSG_DASHES "\n");
    1492            0 :                 } else if (*(sp - 1) != '\n')
    1493            0 :                         printf("\n");
    1494              :         }
    1495              : 
    1496              :         // Change count to idx
    1497            0 :         for (t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next) {
    1498            0 :                 rdIdx= TRACE_IDXCNT_ADD(t_ptrs->rdIdx, for_rev);
    1499            0 :                 t_ptrs->rdIdx= rdIdx;
    1500              :         }
    1501              : 
    1502              :         printed= 0;
    1503            0 :         while (1) {
    1504            0 :                 uint32_t lines= 0;
    1505              :                 /* loop trhough the files looking for
    1506              :                    a) ones that have something to print and
    1507              :                    b) the one that is earliest or latest depending on for_rev
    1508              :                  */
    1509            0 :                 if (count >= 0 && (int)printed >= count && !forward_continuous) /* yes, can elect to print zero lines w/ -c0 */
    1510              :                         break;
    1511              : 
    1512            0 :         forward_check:
    1513            0 :                 t_ptrs_use= 0;
    1514            0 :                 off_use= 0;
    1515            0 :                 for (t_ptrs= trace_ptrs_list_start; t_ptrs != NULL; t_ptrs= t_ptrs->next) {
    1516            0 :                         traceControl_p= t_ptrs->ro_p;  // used in rdIdx_has_lines
    1517              :                 reset_check:
    1518            0 :                         if (slotStart >= 0) {
    1519              :                                 // "startSlot mode"
    1520              :                                 t_ptrs_use= t_ptrs;
    1521            0 :                         } else if ((lines= rdIdx_has_lines(t_ptrs->rw_p->wrIdxCnt, t_ptrs->rdIdx, for_rev))) {
    1522            0 :                                 if (forward_continuous && lines > traceControl_p->num_entries) {  // reset detect
    1523            0 :                                         if (t_ptrs->rw_p->wrIdxCnt == 0 && t_ptrs->rw_p->full == 0) t_ptrs->rdIdx= 0;
    1524              :                                         else {
    1525            0 :                                                 uint32_t rdIdxsav= t_ptrs->rdIdx, wrIdxCntsav= t_ptrs->rw_p->wrIdxCnt;
    1526            0 :                                                 int num_entries= (int)(traceControl_p->num_entries);
    1527              :                                                 //if (num_entries > 400) num_entries -= 250; // incase significant burst (maybe from multiple threads)
    1528            0 :                                                 t_ptrs->rdIdx= TRACE_IDXCNT_ADD(wrIdxCntsav, -num_entries);
    1529            0 :                                                 if (!(show_opts & quiet_))
    1530            0 :                                                         fprintf(stderr, "skipped %9u wrIdxCntsav=0x%08x rdIdx=%u rdIdxsav=%u\n",
    1531            0 :                                                                         TRACE_IDXCNT_DELTA(t_ptrs->rdIdx, rdIdxsav), wrIdxCntsav, t_ptrs->rdIdx, rdIdxsav);
    1532              :                                         }
    1533            0 :                                         t_ptrs->ref_tv.tv_sec= 0;
    1534            0 :                                         goto reset_check;
    1535              :                                 }
    1536            0 :                                 file= trace_ptrs_restore(t_ptrs);  // for idxCnt2entPtr to get time
    1537            0 :                                 if (!t_ptrs_use) {
    1538            0 :                                         t_ptrs_use= t_ptrs;
    1539            0 :                                         tv_from_ent(&tv_use, idxCnt2entPtr(t_ptrs->rdIdx));
    1540            0 :                                         off_use= t_ptrs->offset_adjust;
    1541              :                                 } else {
    1542              :                                         // Compare differently depending on whether forward or reverse.
    1543              :                                         // Race condition -- rdIdx might have just changed and time could be being overwritten :(
    1544              :                                         // Frozen trace buffers are the safest!
    1545            0 :                                         tv_from_ent(&tv2, idxCnt2entPtr(t_ptrs->rdIdx));
    1546            0 :                                         if (tvcmp(&tv_use, off_use, &tv2, t_ptrs->offset_adjust) == for_rev) {
    1547            0 :                                                 t_ptrs_use= t_ptrs;
    1548            0 :                                                 tv_use= tv2;
    1549            0 :                                                 off_use= t_ptrs->offset_adjust;
    1550              :                                         }
    1551              :                                 }
    1552            0 :                         } else if (forward_continuous) { /* and lines==0 (obviously) */
    1553              :                                 /* special check where, e.g.: treset; tcntl test */
    1554            0 :                                 if (t_ptrs->ref_tv.tv_sec) {
    1555            0 :                                         uint32_t prvIdx= TRACE_IDXCNT_ADD(t_ptrs->rdIdx, -1);
    1556            0 :                                         tv_from_ent(&tv2, idxCnt2entPtr(prvIdx));
    1557            0 :                                         if (tvcmp(&t_ptrs->ref_tv, 0, &tv2, 0)) {
    1558            0 :                                                 t_ptrs->rdIdx= 0;
    1559            0 :                                                 t_ptrs->ref_tv.tv_sec= 0;
    1560            0 :                                                 t_ptrs->offset_adjust= 0;
    1561            0 :                                                 goto reset_check;
    1562              :                                         }
    1563              :                                 }
    1564            0 :                         } else if (!forward_continuous)  // not strictly needed, but a little efficiency gain
    1565            0 :                                 trace_ptrs_discard(t_ptrs, &trace_ptrs_list_start);
    1566              :                 }
    1567            0 :                 if (!forward_continuous && (t_ptrs_use == NULL || lines > traceControl_p->num_entries)) {
    1568              :                         break;
    1569            0 :                 } else if (t_ptrs_use == NULL && forward_continuous) {
    1570            0 :                         usleep(10000);
    1571            0 :                         goto forward_check;
    1572              :                 }
    1573              : 
    1574              :                 // had (possibly just changed) t_ptrs_use->rdIdx for a while -- race condition -
    1575              :                 // could be being written to as we are copying :( -- frozen buffers are the safest
    1576            0 :                 file= trace_ptrs_restore(t_ptrs_use);
    1577            0 :                 memcpy(myEnt_p, idxCnt2entPtr(t_ptrs_use->rdIdx), traceControl_p->siz_entry);
    1578              : 
    1579              :                 // adjust myEnt_p->time
    1580            0 :                 tv_from_ent(&tv2, idxCnt2entPtr(t_ptrs_use->rdIdx));
    1581            0 :                 if (t_ptrs_use->offset_adjust != 0) {  // FIXME - currently does not work for mixed 32/64 bit environment!
    1582            0 :                         uint64_t tt;
    1583            0 :                         tt= tv2.tv_sec * 1000000 + tv2.tv_usec;
    1584            0 :                         tt+= t_ptrs_use->offset_adjust;
    1585            0 :                         myEnt_p->time.tv_sec= tt / 1000000;
    1586            0 :                         myEnt_p->time.tv_usec= tt % 1000000;
    1587              :                 } else
    1588            0 :                         myEnt_p->time= tv2;
    1589            0 :                 printEnt(ospec, opts, myEnt_p, local_msg, local_params, params_sizes, bufSlot_width, N_width, (int)name_width, printed,
    1590              :                                  t_ptrs_use->rdIdx, tfmt, tfmt_len, file);
    1591            0 :                 ++printed;
    1592            0 :                 t_ptrs_use->ref_tv= myEnt_p->time;
    1593            0 :                 t_ptrs_use->rdIdx= TRACE_IDXCNT_ADD(t_ptrs_use->rdIdx, for_rev);
    1594              :         }
    1595              : } /*traceShow*/
    1596              : 
    1597            0 : void traceInfo(int quiet)
    1598              : {
    1599            0 :         uint32_t used;
    1600            0 :         uint32_t wrCopy;
    1601            0 :         uint32_t nameLockCopy;
    1602            0 :         char outstr[200];
    1603            0 :         struct tm *tmp;
    1604            0 :         time_t tt= (time_t)traceControl_p->create_tv_sec;
    1605            0 :         int memlen= (int)traceMemLen(
    1606              :                 TRACE_cntlPagesSiz(), traceControl_p->num_namLvlTblEnts, traceControl_p->nam_arr_sz, traceControl_p->siz_msg,
    1607              :                 traceControl_p->num_params,
    1608              :                 traceControl_p->num_entries); /* for when buffer is vmalloc (kernel) or file mmapped (user), but not userspace inactive */
    1609            0 :         tmp= localtime(&tt);
    1610            0 :         if (tmp == NULL) {
    1611            0 :                 perror("localtime");
    1612            0 :                 exit(EXIT_FAILURE);
    1613              :         }
    1614            0 :         if (strftime(outstr, sizeof(outstr), "%a %b %d %H:%M:%S %Z %Y", tmp) == 0) {
    1615            0 :                 perror("strftime");
    1616            0 :                 exit(EXIT_FAILURE);
    1617              :         }
    1618            0 :         nameLockCopy= TRACE_ATOMIC_LOAD(&traceControl_rwp->namelock);
    1619            0 :         wrCopy= TRACE_ATOMIC_LOAD(&traceControl_rwp->wrIdxCnt);
    1620            0 :         used= ((traceControl_rwp->full) ? traceControl_p->num_entries
    1621            0 :                                                                         : wrCopy); /* Race Condition - if not full this shouldn't be > traceControl_p->num_entries */
    1622            0 :         if (quiet)
    1623            0 :                 printf("mode              = 0x%-8x  %s%s\n"
    1624              :                            "writeIdxCount     = 0x%08x  entries used: %u\n"
    1625              :                            "full              = %d\n"
    1626              :                            "num_entries       = %u\n",
    1627            0 :                            traceControl_rwp->mode.words.mode, traceControl_rwp->mode.bits.S ? "Slow:ON, " : "Slow:off",
    1628            0 :                            traceControl_rwp->mode.bits.M ? " Mem:ON" : " Mem:off", wrCopy, used, traceControl_rwp->full,
    1629            0 :                            traceControl_p->num_entries);
    1630              :         else
    1631            0 :                 printf("trace.h rev       = %s\n"
    1632              :                            "revision          = %s\n"
    1633              :                            "create time       = %s\n"
    1634              :                            "trace_initialized = %d\n"
    1635              :                            "fast/mem __func__ = %-8d    1=force on, 0=TRACE_PRINT, -1=force off\n"
    1636              : #ifdef __arm__
    1637              :                            "fast/mem getcpu   = %d\n"
    1638              : #endif
    1639              :                            "mode              = 0x%-8x  %s%s\n"
    1640              :                            "writeIdxCount     = 0x%08x  entries used: %u\n"
    1641              :                            "full              = %d\n"
    1642              :                            "nameLock          = %u\n"
    1643              :                            "largestMultiple   = 0x%08x\n"
    1644              :                            "largestZeroOffset = 0x%08x\n"
    1645              :                            "trigIdxCnt        = 0x%08x\n"
    1646              :                            "triggered         = %d\n"
    1647              :                            "trigActivePost    = %u\n"
    1648              :                            "limit_cnt_limit   = %u\n"
    1649              :                            "limit_span_on_ms  = %llu\n"
    1650              :                            "limit_span_off_ms = %llu\n"
    1651              :                            "traceLevel        = 0x%0*llx 0x%0*llx 0x%0*llx\n"
    1652              :                            "num_entries       = %u\n"
    1653              :                            "max_msg_sz        = %u         includes system enforced terminator\n"
    1654              :                            "max_params        = %u\n"
    1655              :                            "entry_size        = %u\n"
    1656              :                            "namLvlTbl_ents    = %u\n"
    1657              :                            "namLvlTbl_name_sz = %u          not including null terminator\n"
    1658              :                            "longest_name      = %u\n"
    1659              :                            "wrIdxCnt offset   = %p     traceControl_rw start\n"
    1660              :                            "lvls offset       = 0x%lx\n"
    1661              :                            "nams offset       = 0x%lx\n"
    1662              :                            "buffer_offset     = 0x%lx\n"
    1663              :                            "memlen            = 0x%x          %s\n"
    1664              :                            "default TRACE_TIME_FMT=\"%s\"\n"
    1665              :                            "default TRACE_SHOW=\"%s\" others: a:nargs b:fileName B:paramBytes D:inDent e:nam:ln# n:nam f:convertedMsgfmt_only "
    1666              :                            "I:trcId l:lvlNum O/o:color R:retry S:severity s:slot t:tsc u:line x:filtNl X:examineArgData\n"
    1667              :                            "default TRACE_PRINT=\"%s\" others: C:core e:nam:ln# n:nam [n]f:file F:func I:trcId i:threadID l:lvlNum "
    1668              :                            "m:msg-insert N:unpadded_trcName O/o:color P:pid S:severity t:insert u:line\n"
    1669              :                            "Some SHOW/PRINT specifiers take optional modifiers. E.g. PRINT: %%#n.mf#/src#\n",
    1670            0 :                            TRACE_REV, traceControl_p->version_string, outstr, traceControl_p->trace_initialized,
    1671            0 :                            traceControl_rwp->mode.bits.func
    1672              : #ifdef __arm__
    1673              :                            ,
    1674              :                            traceControl_rwp->mode.bits.fast_do_getcpu
    1675              : #endif
    1676              :                            ,
    1677            0 :                            traceControl_rwp->mode.words.mode, traceControl_rwp->mode.bits.S ? "Slow:ON, " : "Slow:off",
    1678            0 :                            traceControl_rwp->mode.bits.M ? " Mem:ON" : " Mem:off", wrCopy, used, traceControl_rwp->full, nameLockCopy,
    1679              :                            traceControl_p->largest_multiple, traceControl_p->largest_zero_offset, traceControl_rwp->trigIdxCnt,
    1680              :                            traceControl_rwp->triggered, traceControl_rwp->trigActivePost, traceControl_rwp->limit_cnt_limit,
    1681            0 :                            (unsigned long long)traceControl_rwp->limit_span_on_ms, (unsigned long long)traceControl_rwp->limit_span_off_ms,
    1682            0 :                            (int)sizeof(uint64_t) * 2, (unsigned long long)traceLvls_p[traceTID].M /* sizeof(uint64_t)*2 is "nibbles" */
    1683              :                            ,
    1684            0 :                            (int)sizeof(uint64_t) * 2, (unsigned long long)traceLvls_p[traceTID].S, (int)sizeof(uint64_t) * 2,
    1685            0 :                            (unsigned long long)traceLvls_p[traceTID].T, traceControl_p->num_entries, traceControl_p->siz_msg,
    1686              :                            traceControl_p->num_params, traceControl_p->siz_entry, traceControl_p->num_namLvlTblEnts,
    1687            0 :                            (int)traceControl_p->nam_arr_sz - 1, traceControl_rwp->longest_name,
    1688            0 :                            (void *)&((struct traceControl_s *)0)->rw.wrIdxCnt, (unsigned long)traceLvls_p - (unsigned long)traceControl_rwp,
    1689            0 :                            (unsigned long)traceNams_p - (unsigned long)traceControl_rwp,
    1690            0 :                            (unsigned long)traceEntries_p - (unsigned long)traceControl_rwp, traceControl_p->memlen,
    1691            0 :                            (traceControl_p->memlen != (uint32_t)memlen) ? "not for mmap" : "", TRACE_DFLT_TIME_FMT, DFLT_SHOW, TRACE_PRINT__);
    1692            0 : } /* traceInfo */
    1693              : 
    1694            0 : void traceMemReport(int do_heading, int use_sys_levels, int32_t max_reverse_us)
    1695              : {
    1696            0 :         uint32_t wrCopy= TRACE_ATOMIC_LOAD(&traceControl_rwp->wrIdxCnt);
    1697            0 :         uint32_t num_entries= traceControl_p->num_entries;
    1698            0 :         uint32_t num_tids= traceControl_p->num_namLvlTblEnts;
    1699            0 :         uint32_t used= traceControl_rwp->full ? num_entries : wrCopy;
    1700            0 :         uint32_t longest_name= traceControl_rwp->longest_name;
    1701            0 :         uint32_t *lvl_counts;
    1702            0 :         uint8_t *has_report;
    1703            0 :         uint32_t analyzed= 0;
    1704            0 :         struct timeval first_tv= {0};
    1705            0 :         struct timeval last_tv= {0};
    1706            0 :         int tid_digits;
    1707            0 :         uint32_t ii;
    1708              : 
    1709            0 :         if (used > num_entries) used= num_entries;
    1710            0 :         if (longest_name > (traceControl_p->nam_arr_sz - 1)) longest_name= traceControl_p->nam_arr_sz - 1;
    1711            0 :         if (longest_name < (uint32_t)strlen("NAME")) longest_name= (uint32_t)strlen("NAME");
    1712            0 :         tid_digits= countDigits((int)num_tids - 1);
    1713              : 
    1714            0 :         lvl_counts= (uint32_t *)calloc((size_t)num_tids * 64U, sizeof(uint32_t));
    1715            0 :         has_report= (uint8_t *)calloc((size_t)num_tids, sizeof(uint8_t));
    1716            0 :         if (!lvl_counts || !has_report) {
    1717            0 :                 fprintf(stderr, "memreport: allocation failure\n");
    1718            0 :                 free(lvl_counts);
    1719            0 :                 free(has_report);
    1720            0 :                 return;
    1721              :         }
    1722              : 
    1723            0 :         if (used) {
    1724            0 :                 uint32_t rdIdx= TRACE_IDXCNT_ADD(wrCopy, -1);
    1725              :                 struct timeval prev_tv;
    1726              :                 int have_prev= 0;
    1727              :                 const int32_t forward_jump_tol_us= max_reverse_us;
    1728              : 
    1729            0 :                 for (ii= 0; ii < used; ++ii) {
    1730            0 :                         struct traceEntryHdr_s *ent_p= idxCnt2entPtr(rdIdx);
    1731            0 :                         struct timeval cur_tv;
    1732            0 :                         int32_t tid;
    1733            0 :                         uint8_t lvl;
    1734              : 
    1735            0 :                         tv_from_ent(&cur_tv, ent_p);
    1736              :                         /* While walking backward in time, stop only on forward jumps above jitter tolerance. */
    1737            0 :                         if (have_prev && tvcmp(&prev_tv, 0, &cur_tv, -forward_jump_tol_us) == -1) break;
    1738              : 
    1739            0 :                         tid= ent_p->TrcId;
    1740            0 :                         if (tid >= 0 && (uint32_t)tid < num_tids) {
    1741            0 :                                 lvl= (uint8_t)(ent_p->lvl & TLVLBITSMSK);
    1742            0 :                                 ++lvl_counts[(size_t)tid * 64U + lvl];
    1743            0 :                                 has_report[tid]= 1;
    1744              :                         }
    1745              : 
    1746            0 :                         if (analyzed == 0) first_tv= cur_tv;
    1747            0 :                         last_tv= cur_tv;
    1748              : 
    1749            0 :                         prev_tv= cur_tv;
    1750            0 :                         have_prev= 1;
    1751            0 :                         ++analyzed;
    1752            0 :                         rdIdx= TRACE_IDXCNT_ADD(rdIdx, -1);
    1753              :                 }
    1754              :         }
    1755              : 
    1756            0 :         if (do_heading) {
    1757            0 :                 printf("%*s %*s %*s %s\n", minw(3, tid_digits), "TID", longest_name, "NAME", 18, "maskM", "report");
    1758            0 :                 printf("%.*s %.*s %.*s %.*s\n", minw(3, tid_digits), TRACE_LONG_DASHES, longest_name, TRACE_LONG_DASHES, 18,
    1759              :                            TRACE_LONG_DASHES, 4, TRACE_LONG_DASHES);
    1760              :         }
    1761              : 
    1762            0 :         for (ii= 0; ii < num_tids; ++ii) {
    1763            0 :                 int first= 1;
    1764            0 :                 uint8_t lvl;
    1765            0 :                 if (!has_report[ii]) continue;
    1766              : 
    1767            0 :                 printf("%*u %*.*s 0x%016llx ", minw(3, tid_digits), ii, longest_name, longest_name, TRACE_TID2NAME((int32_t)ii),
    1768            0 :                            (unsigned long long)traceLvls_p[ii].M);
    1769            0 :                 for (lvl= 0; lvl < 64; ++lvl) {
    1770            0 :                         uint32_t cnt= lvl_counts[(size_t)ii * 64U + lvl];
    1771            0 :                         if (!cnt) continue;
    1772            0 :                         if (!use_sys_levels && lvl >= 8)
    1773            0 :                                 printf("%sD%02u:%u", first ? "" : " ", (unsigned)(lvl - 8), cnt);
    1774              :                         else
    1775            0 :                                 printf("%s%u:%u", first ? "" : " ", lvl, cnt);
    1776              :                         first= 0;
    1777              :                 }
    1778            0 :                 printf("\n");
    1779              :         }
    1780            0 :         if (analyzed) {
    1781            0 :                 long span_sec= (long)(first_tv.tv_sec - last_tv.tv_sec);
    1782            0 :                 int span_usec= (int)(first_tv.tv_usec - last_tv.tv_usec);
    1783            0 :                 if (span_usec < 0) {
    1784            0 :                         span_usec+= 1000000;
    1785            0 :                         --span_sec;
    1786              :                 }
    1787            0 :                 printf("entries analyzed: %u  spanning %ld.%06d seconds\n", analyzed, span_sec, span_usec);
    1788              :         } else
    1789            0 :                 printf("entries analyzed: %u  spanning %ld.%06d seconds\n", analyzed, 0L, 0);
    1790              : 
    1791            0 :         free(lvl_counts);
    1792            0 :         free(has_report);
    1793              : }
    1794              : 
    1795            0 : void do_help(const char *cmd)
    1796              : {
    1797            0 :         unsigned uu= 0;
    1798            0 :         if (strcmp(cmd, "") != 0) printf("   usage: tcntl");
    1799            0 :         for (uu= 0; uu < (sizeof(subcmdhlp) / sizeof(subcmdhlp[0])); ++uu) {
    1800            0 :                 size_t slen= strlen(subcmdhlp[uu].cmd);
    1801            0 :                 size_t slen2= strcspn(subcmdhlp[uu].cmd, " [{");
    1802            0 :                 if (strcmp(cmd, "") == 0 || (slen2 < slen && strncmp(subcmdhlp[uu].cmd, cmd, slen2) == 0) ||
    1803            0 :                         strcmp(subcmdhlp[uu].cmd, cmd) == 0) {
    1804            0 :                         printf(" %s %s\n", subcmdhlp[uu].cmd, subcmdhlp[uu].hlp);
    1805            0 :                         if (strcmp(cmd, "") != 0) exit(0);
    1806              :                 }
    1807              :         }
    1808            0 :         exit(0);
    1809              : } /* do_help */
    1810              : 
    1811              : /* for "test-compare" printf buffer (could use write) and (more so) "TRACE" */
    1812              : #pragma GCC diagnostic ignored "-Wformat-security"
    1813              : 
    1814            0 : int main(int argc, char *argv[])
    1815              : {
    1816            0 :         int ret= 0;
    1817            0 :         const char *cmd;
    1818            0 :         static const struct option long_options[]= {
    1819              :                 {"sys", no_argument, 0, 1000},
    1820              :                 {"max-reverse-us", required_argument, 0, 1001},
    1821              :                 {0, 0, 0, 0}};
    1822            0 :         extern char *optarg; /* for getopt */
    1823            0 :         extern int optind;   /* for getopt */
    1824            0 :         int opt;             /* for how I use getopt */
    1825            0 :         int opt_memreport_sys= 0;
    1826            0 :         int32_t opt_memreport_max_reverse_us= 10000;
    1827            0 :         int do_heading= 1;
    1828            0 :         int show_opts= 0;
    1829            0 :         int ii= 0;
    1830            0 :         unsigned uu= 0;
    1831            0 :         char test_name[0x100];
    1832            0 :         int opt_loops= -1, opt_timing_stats= 0, opt_help= 0;
    1833            0 :         float opt_dly_ms= 0;
    1834            0 :         unsigned opt_burst= 1;
    1835            0 :         int opt_quiet= 0;
    1836            0 :         int opt_all= 0;
    1837            0 :         int opt_count= -2, opt_start= -1;  // -2 to indicate "not specified" (less likely to be specfied than -1)
    1838            0 :         int opt_line= 0;
    1839            0 :         const char *opt_Name= NULL; /* -N<wild> */
    1840            0 :         char *cp;
    1841            0 :         uint64_t t0_us= 0;
    1842            0 :         uint32_t tdelta_us;
    1843              : 
    1844            0 :         opterr= 0; /* turn of getopt (automatic) error output */
    1845            0 :         while ((opt= getopt_long(argc, argv, "?hab:c:d:Ff:HL:l:N:n:qs:tVx:", long_options, NULL)) != -1) {
    1846            0 :                 switch (opt) {
    1847            0 :                 case 1000: opt_memreport_sys= 1; break;
    1848            0 :                 case 1001: {
    1849            0 :                         char *endp= NULL;
    1850            0 :                         unsigned long tmp= strtoul(optarg, &endp, 0);
    1851            0 :                         if (optarg[0] == '\0' || endp == optarg || *endp != '\0' || tmp > INT32_MAX) {
    1852            0 :                                 fprintf(stderr, "invalid --max-reverse-us value: %s\n", optarg);
    1853            0 :                                 exit(1);
    1854              :                         }
    1855            0 :                         opt_memreport_max_reverse_us= (int32_t)tmp;
    1856            0 :                         break;
    1857              :                 }
    1858              :                 /*   '?' is also what you get w/ "invalid option -- -"   */
    1859            0 :                 case '?':
    1860              :                 case 'h':
    1861            0 :                         if (!strchr("?h", optopt)) {
    1862            0 :                                 printf("Invalid option: -%c\n", optopt);
    1863            0 :                                 exit(0);
    1864              :                         }
    1865              :                         opt_help= 1;
    1866              :                         break;
    1867            0 :                 case 'a': opt_all= 1; break;
    1868            0 :                 case 'b': opt_burst= (unsigned)strtoul(optarg, NULL, 0); break;
    1869            0 :                 case 'c': opt_count= (int)strtoul(optarg, NULL, 0); break;
    1870            0 :                 case 'd': opt_dly_ms= strtof(optarg, NULL); break;
    1871            0 :                 case 'F': show_opts|= forward_; break;
    1872            0 :                 case 'f': setenv("TRACE_FILE", optarg, 1); break;
    1873            0 :                 case 'H': do_heading= 0; break;
    1874            0 :                 case 'L': opt_line= (int)strtoul(optarg, NULL, 0); break;
    1875            0 :                 case 'l': opt_loops= (int)strtoul(optarg, NULL, 0); break;
    1876            0 :                 case 'N': opt_Name= optarg; break;
    1877            0 :                 case 'n':
    1878            0 :                         setenv("TRACE_NAME", optarg, 1);
    1879            0 :                         break; /*note: TRACE_CNTL "file" or "name" doesn't allow setting the other (order becomes dependent)*/
    1880            0 :                 case 'q': opt_quiet= 1; break;
    1881            0 :                 case 's': opt_start= (int)strtoul(optarg, NULL, 0); break;
    1882            0 :                 case 't': opt_timing_stats= 1; break;
    1883            0 :                 case 'V':
    1884            0 :                         printf("%s\n", TRACE_CNTL_REV);
    1885            0 :                         if (argc == 2) exit(0);
    1886              :                         break;
    1887            0 :                 case 'x': trace_thread_option= (int)strtoul(optarg, NULL, 0); break;
    1888              :                 }
    1889              :         }
    1890            0 :         if (argc - optind < 1) {
    1891            0 :                 printf("Need cmd\n");
    1892              : #define DO_HELP 0
    1893              : #if DO_HELP
    1894              :                 do_help("");
    1895              : #else
    1896            0 :                 printf(USAGE);
    1897            0 :                 exit(0);
    1898              : #endif
    1899              :         }
    1900            0 :         cmd= argv[optind++];
    1901            0 :         if (opt_help) {
    1902              : #if DO_HELP
    1903              :                 do_help(cmd);
    1904              : #else
    1905            0 :                 printf(USAGE);
    1906            0 :                 exit(0);
    1907              : #endif
    1908              :         }
    1909              : 
    1910            0 :         if (opt_Name && !(strncmp(cmd, "lvl", 3) == 0)) {  // a name (which may be wildcard) will get added to lvl command below
    1911            0 :                 setenv("TRACE_NAME", opt_Name, 1);
    1912              :                 //traceInit(opt_Name,0);
    1913              :         }
    1914              : 
    1915            0 :         if ((cp= getenv("LC_NUMERIC")))  // IFF LC_NUMERIC is set in the environment (i.e to "en_US" or "en_US.UTF-8")...
    1916            0 :                 setlocale(LC_NUMERIC, cp);   // this is needed for (e.g.) %'d to produce output with thousands grouped
    1917              : 
    1918            0 :         if (strcmp(cmd, "test1") == 0) {
    1919            0 :                 int loops= 1, trace_cnt;
    1920            0 :                 char msg_str[200];
    1921            0 :                 char addr_str[100];
    1922            0 :                 void *vp= addr_str;
    1923            0 :                 setenv("TRACE_NAME", "TRACE", 0);  // allow this to be overridden by -n and env.var. (and define TRACE_NAME)
    1924            0 :                 if (opt_loops > -1) loops= opt_loops;
    1925            0 :                 sprintf(addr_str, "%p", vp);
    1926            0 :                 sprintf(msg_str, "Hi %%d. \"c 2.5 -5 5000000000 0x87654321 2.6 %p\" ", vp);
    1927            0 :                 strcat(msg_str, "should be repeated here: %c %.1f %hd %lld %p %.1Lf %s");
    1928            0 :                 tdelta_us= (uint32_t)(opt_dly_ms * 1000);
    1929            0 :                 for (trace_cnt= 1; trace_cnt <= loops; ++trace_cnt) {
    1930            0 :                         TRACE(TLVL_INFO, msg_str, trace_cnt, 'c', 2.5, (short)-5, (long long)5000000000LL, (void *)0x87654321, (long double)2.6,
    1931              :                                   addr_str);
    1932            0 :                         if (tdelta_us) usleep(tdelta_us);
    1933              :                 }
    1934            0 :         } else if (strcmp(cmd, "file") == 0) {
    1935            0 :                 char file[PATH_MAX];
    1936            0 :                 if (argc - optind < 1) {
    1937            0 :                         printf("Need file\n");
    1938              : #if DO_HELP
    1939              :                         do_help("");
    1940              : #else
    1941            0 :                         printf(USAGE);
    1942            0 :                         exit(0);
    1943              : #endif
    1944              :                 }
    1945            0 :                 (void)tsnprintf(file, sizeof(file), argv[optind++]);
    1946            0 :                 printf("%s\n", file);
    1947            0 :         } else if (strcmp(cmd, "test") == 0) {
    1948            0 :                 float ff[10];
    1949            0 :                 pid_t tid;
    1950            0 :                 uint32_t desired, myIdx;
    1951            0 :                 int32_t xx;
    1952              : 
    1953            0 :                 tid= trace_gettid();
    1954            0 :                 if (tid == -1) perror("trace_gettid");
    1955            0 :                 printf("tid=%ld\n", (long int)tid);
    1956              : 
    1957            0 :                 printf("sizeof: int:%u long:%u pid_t:%u pthread_t:%u timeval:%u "
    1958              :                            "double:%u traceControl_s:%u traceEntryHdr_s:%u traceControl(for disabled):%u\n",
    1959              :                            (unsigned)sizeof(unsigned), (unsigned)sizeof(long), (unsigned)sizeof(pid_t), (unsigned)sizeof(pthread_t),
    1960              :                            (unsigned)sizeof(struct timeval), (unsigned)sizeof(double), (unsigned)sizeof(struct traceControl_s),
    1961              :                            (unsigned)sizeof(struct traceEntryHdr_s), (unsigned)sizeof(traceControl));
    1962            0 :                 printf("offset: trigIdxCount   =%p\n"
    1963              :                            "        trigActivePost =%p\n"
    1964              :                            "        full           =%p\n"
    1965              :                            "        lvl            =%p\n"
    1966              :                            "        pid            =%p\n"
    1967              :                            "        TID            =%p\n"
    1968              :                            "        get_retries    =%p\n"
    1969              :                            "        param_bytes    =%p\n"
    1970              :                            "        tsc            =%p\n",
    1971              :                            (void *)&((struct traceControl_s *)0)->rw.trigIdxCnt, (void *)&((struct traceControl_s *)0)->rw.trigActivePost,
    1972              :                            (void *)&((struct traceControl_s *)0)->rw.full, (void *)&((struct traceEntryHdr_s *)0)->lvl,
    1973              :                            (void *)&((struct traceEntryHdr_s *)0)->pid, (void *)&((struct traceEntryHdr_s *)0)->TrcId,
    1974              :                            (void *)&((struct traceEntryHdr_s *)0)->get_idxCnt_retries, (void *)&((struct traceEntryHdr_s *)0)->param_bytes,
    1975              :                            (void *)&((struct traceEntryHdr_s *)0)->tsc);
    1976              : 
    1977            0 :                 for (uu= 0; uu < sizeof(ff) / sizeof(ff[0]); ++uu) ff[uu]= (float)(2.5 * uu);
    1978              : 
    1979              :                 /* NOTE: using setenv method works in threading env where as additional
    1980              :                    threads initializing via TRACE will disable/undo the levels
    1981              :                    set by the initialization via TRACE_CNTL("lvlsetS",0xffLL) */
    1982            0 :                 setenv("TRACE_LVLS", "0xff", 0); /*does TRACE_CNTL("lvlsetS",0xffLL);TRACE_CNTL("modeS",1);*/
    1983              :                 /* NOTE/Recall - _LVLS does not "activate" like TRACE_{FILE,NAME,MSGMAX,NUMENTS,NAMTBLENTS} */
    1984              : 
    1985              :                 /* _at_least_ set bit 0 (lvl=0) in the "M" mask and turn on the "M" mode
    1986              :                    bit -- this is what is on by default when the file is created */
    1987              :                 /*                    Mem    Slow Trig */
    1988            0 :                 TRACE_CNTL("lvlset", 0xfLL, 0LL, 0LL);
    1989            0 :                 TRACE_CNTL("modeM", 1);
    1990              : 
    1991            0 :                 TRACE(TLVL_INFO, "hello");
    1992              : 
    1993            0 :                 myIdx= traceControl_p->largest_multiple - 3;
    1994            0 :                 printf("myIdx=0x%08x\n", myIdx);
    1995            0 :                 for (ii= 0; ii < 6; ++ii) {
    1996            0 :                         desired= TRACE_IDXCNT_ADD(myIdx, 1);
    1997            0 :                         printf("myIdx==>TRACE_IDXCNT_ADD(myIdx,1): 0x%08x 0x%08x\n", myIdx, desired);
    1998            0 :                         myIdx= desired;
    1999              :                 }
    2000            0 :                 for (ii= 0; ii < 6; ++ii) {
    2001            0 :                         desired= TRACE_IDXCNT_ADD(myIdx, -1);
    2002            0 :                         printf("myIdx==>TRACE_IDXCNT_ADD(myIdx,-1): 0x%08x 0x%08x\n", myIdx, desired);
    2003            0 :                         myIdx= desired;
    2004              :                 }
    2005            0 :                 printf("myIdx=0x%08x\n", myIdx);
    2006              : 
    2007            0 :                 xx= 5;
    2008            0 :                 myIdx= traceControl_p->largest_multiple - (uint32_t)(3 * xx);
    2009            0 :                 printf("myIdx=0x%08x\n", myIdx);
    2010            0 :                 for (ii= 0; ii < 6; ++ii) {
    2011            0 :                         desired= TRACE_IDXCNT_ADD(myIdx, xx);
    2012            0 :                         printf("myIdx==>TRACE_IDXCNT_ADD(myIdx,5): 0x%08x 0x%08x\n", myIdx, desired);
    2013            0 :                         myIdx= desired;
    2014              :                 }
    2015            0 :                 for (ii= 0; ii < 6; ++ii) {
    2016            0 :                         desired= TRACE_IDXCNT_ADD(myIdx, -xx); /* NOTE: this will not work if xx is of type uint32_t; it must be of int32_t */
    2017            0 :                         printf("myIdx==>TRACE_IDXCNT_ADD(myIdx,-5): 0x%08x 0x%08x\n", myIdx, desired);
    2018            0 :                         myIdx= desired;
    2019              :                 }
    2020            0 :                 printf("myIdx=0x%08x\n", myIdx);
    2021              : 
    2022            0 :                 printf("For forward read... simple delta\n");
    2023            0 :                 printf("TRACE_IDXCNT_DELTA(wr=5,rd=4)=%u\n", TRACE_IDXCNT_DELTA(5, 4));
    2024            0 :                 printf("TRACE_IDXCNT_DELTA(wr=5,rd=0)=%u\n", TRACE_IDXCNT_DELTA(5, 0));
    2025            0 :                 printf("TRACE_IDXCNT_DELTA(wr=5,rd=TRACE_IDXCNT_ADD(0,-1)=0x%08x)=%u\n", TRACE_IDXCNT_ADD(0, -1),
    2026            0 :                            TRACE_IDXCNT_DELTA(5, TRACE_IDXCNT_ADD(0, -1)));
    2027            0 :                 printf("For reverse read... numents(or wrIdxCnt) - delta\n");
    2028            0 :                 printf(
    2029              :                         "(num_entries=%u) - TRACE_IDXCNT_DELTA(wr=TRACE_IDXCNT_ADD(num_entries,10),rd=TRACE_IDXCNT_ADD(num_entries,5)) = %u\n",
    2030              :                         traceControl_p->num_entries,
    2031            0 :                         traceControl_p->num_entries - TRACE_IDXCNT_DELTA(TRACE_IDXCNT_ADD(traceControl_p->num_entries, 10),
    2032              :                                                                                                                          TRACE_IDXCNT_ADD(traceControl_p->num_entries, 5)));
    2033            0 :                 printf("rdIdx_has_lines(TRACE_IDXCNT_ADD(num_entries,10),TRACE_IDXCNT_ADD(num_entries,5),-1) = %u\n",
    2034            0 :                            rdIdx_has_lines(TRACE_IDXCNT_ADD(traceControl_p->num_entries, 10), TRACE_IDXCNT_ADD(traceControl_p->num_entries, 5),
    2035              :                                                            -1));
    2036            0 :                 printf("(num_entries=%u) - "
    2037              :                            "TRACE_IDXCNT_DELTA(wr=TRACE_IDXCNT_ADD(num_entries,10+num_entries)=%u,rd=TRACE_IDXCNT_ADD(num_entries,5)) = %u\n",
    2038            0 :                            traceControl_p->num_entries, TRACE_IDXCNT_ADD(traceControl_p->num_entries, (int)(10 + traceControl_p->num_entries)),
    2039            0 :                            traceControl_p->num_entries -
    2040            0 :                                    TRACE_IDXCNT_DELTA(TRACE_IDXCNT_ADD(traceControl_p->num_entries, (int)(10 + traceControl_p->num_entries)),
    2041              :                                                                           TRACE_IDXCNT_ADD(traceControl_p->num_entries, 5)));
    2042            0 :                 printf("rdIdx_has_lines(TRACE_IDXCNT_ADD(num_entries,10+num_entries),TRACE_IDXCNT_ADD(num_entries,5),-1) = %u\n",
    2043            0 :                            rdIdx_has_lines(TRACE_IDXCNT_ADD(traceControl_p->num_entries, (int)(10 + traceControl_p->num_entries)),
    2044            0 :                                                            TRACE_IDXCNT_ADD(traceControl_p->num_entries, 5), -1));
    2045              : 
    2046            0 :                 printf("\n");
    2047            0 :                 TRACE(TLVL_WARNING, "hello %d\n\tthere\n", 1);
    2048            0 :                 TRACE(TLVL_INFO, "hello %d %d", 1, 2);
    2049            0 :                 TRACE(TLVL_DEBUG, "hello %d %d %d - make sure debug+1 is enabled", 1, 2, 3);
    2050            0 :                 TRACE(TLVL_DEBUG, "hello %d %d %d %d %d %d %d %d %d %d %d - should be 1 2 3 4 5 6 7 8 9 10 *d", 1, 2, 3, 4, 5, 6, 7, 8, 9,
    2051              :                           10, 11); /* extra param does not get saved in buffer */
    2052            0 :                 TRACE(TLVL_DEBUG,
    2053              :                           "hello %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f - should be 1.00 2.00 3.00 4.00 12.50 6.00 7.00 8.00 9.00 "
    2054              :                           "10.00",
    2055              :                           1.0, 2.0, 3.0, 4.0, ff[5], 6.0, 7.0, 8.0, 9.0, 10.0);
    2056            0 :                 TRACE(TLVL_DBG + 1,
    2057              :                           "hello %d %d %.1f %d %d %.1f             %d %d %.1f %.1f. Should be 1 2 3.3 4 5 6.6              7 8 9.0 10.0 there is tabs after "
    2058              :                           "2nd float",
    2059              :                           1, 2, 3.3, 4, 5, 6.6, 7, 8, 9.0, 10.0);
    2060            0 :                 TRACE(TLVL_DBG + 1,
    2061              :                           TSPRINTF("%s:%%d- int=%%d __FILE__=%s", strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __FILE__),
    2062              :                           __LINE__, 5);
    2063            0 :                 TRACE(TLVL_DBG + 1,
    2064              :                           TSPRINTF("%s%s%s", strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, ":%d- int=%d __FILE__=", __FILE__),
    2065              :                           __LINE__, 5);
    2066              : 
    2067              : #ifndef TEST_UNUSED_FUNCTION
    2068            0 :                 TRACE_CNTL("trig", -1, 5LL);
    2069              : #endif
    2070            0 :                 for (ii= 0; ii < 20; ++ii) {
    2071            0 :                         if (ii % 5 == 0) {
    2072              :                                 /* this shows how TRACE (which does not have a "name" argument)
    2073              :                                    could "TRACE with different names." The other trace macros
    2074              :                                    (TRACEN,TRACEN_,TLOG) can't do this. (They can have a name per thread.)
    2075              :                                    This is just a technical detail -- I have yet to think of a
    2076              :                                    real use for this feature/functionality.
    2077              :                                 */
    2078            0 :                                 sprintf(test_name, "%s_%d", "TRACE", ii);
    2079            0 :                                 TRACE_CNTL("name", test_name); /* this is a realatively slow operation - changes the value of traceTID */
    2080              :                         }
    2081            0 :                         TRACE(TLVL_INFO, "ii=%u", ii);
    2082              :                 }
    2083            0 :         } else if (strcmp(cmd, "test-ro") == 0) {
    2084              :                 /* To test normal userspace, can use: TRACE_FILE= trace_cntl test-ro
    2085              :                  */
    2086            0 :                 setenv("TRACE_FILE", "/proc/trace/buffer", 0);
    2087            0 :                 printf("TRACE_FILE=%s\n", getenv("TRACE_FILE"));
    2088            0 :                 traceInit(NULL, 0);
    2089            0 :                 printf("try write to (presumably kernel memory) write-protected 1st page...\n");
    2090            0 :                 traceControl_p->trace_initialized= 2;
    2091            0 :                 printf("write succeeded.\n");
    2092              : #if defined(TEST_WRITE_PAST_END)
    2093              :                 *(((uint8_t *)traceControl_p) + traceControl_p->memlen)= 6;
    2094              : #endif
    2095            0 :         } else if (strcmp(cmd, "test-compare") == 0) {
    2096            0 :                 char buffer[200];
    2097            0 :                 uint64_t mark;
    2098            0 :                 uint32_t delta;
    2099            0 :                 unsigned loops= DFLT_TEST_COMPARE_ITERS;
    2100            0 :                 unsigned test_mask= 0xff; /* all tests */
    2101            0 :                 unsigned modes_msk= 0xf;  /* all mode combinations */
    2102            0 :                 int fd;
    2103            0 :                 int jj;
    2104              : 
    2105            0 :                 if (opt_loops > -1) loops= (unsigned)opt_loops;
    2106            0 :                 opt_loops= (int)loops; /* save */
    2107              : 
    2108            0 :                 if (argc - optind >= 1) test_mask= (unsigned)strtoul(argv[optind], NULL, 0);
    2109            0 :                 if (argc - optind >= 2) modes_msk= (unsigned)strtoul(argv[optind + 1], NULL, 0);
    2110            0 :                 if (argc - optind == 3) {
    2111            0 :                         fd= open(argv[optind + 2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
    2112            0 :                         if (fd == -1) {
    2113            0 :                                 perror("outputfile");
    2114            0 :                                 exit(1);
    2115              :                         }
    2116              :                 } else
    2117            0 :                         fd= open("/dev/null", O_WRONLY);
    2118            0 :                 dup2(fd, 1);                    /* redirect stdout to /dev/null */
    2119            0 :                 setlocale(LC_NUMERIC, "en_US"); /* make ' printf flag work -- setting LC_NUMERIC in env does not seem to work */
    2120              : 
    2121            0 :                 TRACE_CNTL("mode", 3);
    2122            0 :                 traceControl_rwp->mode.bits.M= 1;  // NOTE: TRACE_CNTL("modeM",1) hardwired to NOT enable when not mapped!
    2123              : 
    2124              : #define STRT_PRN(s1, sA, sB)          \
    2125              :         sprintf(buffer, s1, sA, sB);      \
    2126              :         fprintf(stderr, "%-46s", buffer); \
    2127              :         fflush(stderr)
    2128              :                 // ELF 6/6/18: GCC v6_3_0 does not like %', removing the '...
    2129              : #define END_FMT "%10u us, %5.3f us/TRACE, %7.3f Mtraces/s\n", delta, (double)delta / loops, (double)loops / delta
    2130              : #define CONTINUE                      \
    2131              :         fprintf(stderr, "Continuing.\n"); \
    2132              :         continue
    2133            0 :                 for (jj= 0; jj < 4; ++jj) {
    2134            0 :                         unsigned tstmod= (1U << jj) & modes_msk;
    2135            0 :                         switch (tstmod) {
    2136            0 :                         case 1: {
    2137            0 :                                 TRACE_CNTL("lvlclrM", 1LL << TLVL_INFO);
    2138            0 :                                 TRACE_CNTL("lvlclrS", 1LL << TLVL_INFO);
    2139            0 :                                 loops= (unsigned)opt_loops * 10;
    2140            0 :                                 fprintf(stderr, "0x1 M0S0 - Testing with M and S lvl disabled. loops=%u\n", loops);
    2141            0 :                         } break;
    2142            0 :                         case 2: {
    2143            0 :                                 TRACE_CNTL("lvlsetM", 1LL << TLVL_INFO);
    2144            0 :                                 TRACE_CNTL("lvlclrS", 1LL << TLVL_INFO);
    2145            0 :                                 loops= (unsigned)opt_loops * 5;
    2146            0 :                                 fprintf(stderr, "0x2 M1S0 - First testing with S lvl disabled (mem only). loops=%u\n", loops);
    2147            0 :                                 break;
    2148              :                         } break;
    2149            0 :                         case 4: {
    2150            0 :                                 TRACE_CNTL("lvlsetM", 1LL << TLVL_INFO);
    2151            0 :                                 TRACE_CNTL("lvlsetS", 1LL << TLVL_INFO);
    2152            0 :                                 loops= (unsigned)opt_loops;
    2153            0 :                                 fprintf(stderr, "0x4 M1S1 - Testing with M and S lvl enabled (stdout>/dev/null). loops=%u\n", loops);
    2154            0 :                                 break;
    2155              :                         } break;
    2156            0 :                         case 8: {
    2157            0 :                                 TRACE_CNTL("lvlclrM", 1LL << TLVL_INFO);
    2158            0 :                                 TRACE_CNTL("lvlsetS", 1LL << TLVL_INFO);
    2159            0 :                                 loops= (unsigned)opt_loops;
    2160            0 :                                 fprintf(stderr, "0x8 M0S1 - Testing with just S lvl enabled. Unusual (freeze). loops=%u\n", loops);
    2161            0 :                                 break;
    2162              :                         } break;
    2163            0 :                         case 0: continue;
    2164              :                         }
    2165              : 
    2166            0 :                         if (1 & test_mask) {
    2167            0 :                                 STRT_PRN(" 0x01 -%s const short msg %s", "", (tstmod & 0xc) ? "(NO snprintf)" : "");
    2168              :                                 //fprintf(stderr,STRT_FMT," 0x01 - const short msg (NO snprintf)");fflush(stderr);
    2169            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2170            0 :                                 mark= gettimeofday_us();
    2171            0 :                                 for (uu= 0; uu < loops; ++uu) { TRACE(TLVL_INFO, "any msg"); }
    2172            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2173            0 :                                 fprintf(stderr, END_FMT);
    2174              :                         }
    2175              : 
    2176            0 :                         if (2 & test_mask) {
    2177            0 :                                 STRT_PRN(" 0x02 - 1 arg%s%s", "", "");
    2178            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2179            0 :                                 mark= gettimeofday_us();
    2180            0 :                                 for (uu= 0; uu < loops; ++uu) { TRACE(TLVL_INFO, "this is one small param: %u", 12345678); }
    2181            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2182            0 :                                 fprintf(stderr, END_FMT);
    2183              :                         }
    2184              : 
    2185            0 :                         if (4 & test_mask) {
    2186            0 :                                 STRT_PRN(" 0x04 - 2 args%s%s", "", "");
    2187            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2188            0 :                                 mark= gettimeofday_us();
    2189            0 :                                 for (uu= 0; uu < loops; ++uu) { TRACE(TLVL_INFO, "this is 2 params: %u %u", 12345678, uu); }
    2190            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2191            0 :                                 fprintf(stderr, END_FMT);
    2192              :                         }
    2193              : 
    2194            0 :                         if (8 & test_mask) {
    2195            0 :                                 STRT_PRN(" 0x08 - 8 args (7 ints, 1 float)%s%s", "", "");
    2196            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2197            0 :                                 mark= gettimeofday_us();
    2198            0 :                                 for (uu= 0; uu < loops; ++uu) {
    2199            0 :                                         TRACE(TLVL_INFO, "this is 8 params: %u %u %u %u %u %u %u %g", 12345678, uu, uu * 2, uu + 6, 12345679, uu,
    2200              :                                                   uu - 7, (float)uu * 1.5);
    2201              :                                 }
    2202            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2203            0 :                                 fprintf(stderr, END_FMT);
    2204              :                         }
    2205              : 
    2206            0 :                         if (0x10 & test_mask) {
    2207            0 :                                 STRT_PRN(" 0x10 - 8 args (1 ints, 7 float)%s%s", "", "");
    2208            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2209            0 :                                 mark= gettimeofday_us();
    2210            0 :                                 for (uu= 0; uu < loops; ++uu) {
    2211            0 :                                         TRACE(TLVL_INFO, "this is 8 params: %u %g %g %g %g %g %g %g", 12345678, (float)uu, (float)uu * 2.5,
    2212              :                                                   (float)uu + 3.14, (float)12345679, (float)uu / .25, (float)uu - 2 * 3.14, (float)uu * 1.5);
    2213              :                                 }
    2214            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2215            0 :                                 fprintf(stderr, END_FMT);
    2216              :                         }
    2217              : 
    2218            0 :                         if (0x20 & test_mask) {
    2219            0 :                                 STRT_PRN(" 0x20 - snprintf of same 8 args%s%s", "", "");
    2220            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2221            0 :                                 mark= gettimeofday_us();
    2222            0 :                                 for (uu= 0; uu < loops; ++uu) {
    2223            0 :                                         snprintf(buffer, sizeof(buffer), "this is 8 params: %u %g %g %g %g %g %g %g", 12345678, (float)uu,
    2224              :                                                          (float)uu * 2.5, (float)uu + 3.14, (float)12345679, (float)uu / .25, (float)uu - 2 * 3.14,
    2225            0 :                                                          (float)uu * 1.5);
    2226            0 :                                         TRACE(TLVL_INFO, buffer);
    2227              :                                 }
    2228            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2229            0 :                                 fprintf(stderr, END_FMT);
    2230              :                         }
    2231              : 
    2232            0 :                         if (0x40 & test_mask) {
    2233            0 :                                 STRT_PRN(" 0x40 -%s const short msg %s", (1 & test_mask) ? " (repeat)" : "", (tstmod & 0xc) ? "(NO snprintf)" : "");
    2234            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2235            0 :                                 mark= gettimeofday_us();
    2236            0 :                                 for (uu= 0; uu < loops; ++uu) { TRACE(TLVL_INFO, "any msg"); }
    2237            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2238            0 :                                 fprintf(stderr, END_FMT);
    2239              :                         }
    2240              : 
    2241            0 :                         if (0x80 & test_mask) {
    2242            0 :                                 STRT_PRN(" 0x80 - 2 args%s%s traceTID=-1", "", "");
    2243            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2244            0 :                                 mark= gettimeofday_us();
    2245            0 :                                 for (uu= 0; uu < loops; ++uu) {
    2246            0 :                                         TRACE(TLVL_INFO, "this is 2 params: %u %u", 12345678, uu);
    2247            0 :                                         traceTID= -1;
    2248              :                                 }
    2249            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2250            0 :                                 fprintf(stderr, END_FMT);
    2251              :                         }
    2252              : #ifdef DO_THREADS /* requires linking with -lpthreads */
    2253            0 :                         if (0x100 & test_mask) {
    2254            0 :                                 pthread_t thread;
    2255            0 :                                 args_t argsp[1];
    2256            0 :                                 argsp[0].loops= 1;
    2257            0 :                                 argsp[0].dly_ms= 0;
    2258            0 :                                 argsp[0].burst= 0;
    2259            0 :                                 loops /= 100; /* OK to do if last test */
    2260            0 :                                 STRT_PRN(" 0x100 - %swith loops=%u thread", "", loops);
    2261            0 :                                 if (tstmod & 6) { TRACE_CNTL("reset"); }
    2262            0 :                                 mark= gettimeofday_us();
    2263            0 :                                 for (uu= 0; uu < loops; ++uu) {
    2264            0 :                                         argsp[0].tidx= uu;
    2265            0 :                                         pthread_create(&thread, NULL, thread_func, (void *)&argsp[0]);
    2266            0 :                                         pthread_join(thread, NULL);
    2267              :                                 }
    2268            0 :                                 delta= (uint32_t)(gettimeofday_us() - mark);
    2269            0 :                                 fprintf(stderr, END_FMT);
    2270              :                         }
    2271              : #endif
    2272              :                 }
    2273              :         }
    2274              : #ifdef DO_THREADS /* requires linking with -lpthreads */
    2275            0 :         else if (strcmp(cmd, "test-threads") == 0) {
    2276            0 :                 pthread_t *threads;
    2277            0 :                 unsigned loops= 2, num_threads= NUMTHREADS;
    2278            0 :                 args_t *argsp, args0;
    2279            0 :                 int sts= 0;
    2280            0 :                 pid_t main_tid= trace_gettid();
    2281            0 :                 unsigned total_traces= 0;
    2282            0 :                 if (opt_loops > -1) loops= (unsigned)opt_loops;
    2283            0 :                 if (opt_burst == 0) {
    2284            0 :                         printf("adjusting burst==0 to min burst=1\n");
    2285            0 :                         opt_burst= 1;
    2286              :                 }
    2287            0 :                 if ((argc - optind) == 1) {
    2288            0 :                         num_threads= (unsigned)strtoul(argv[optind], NULL, 0);
    2289            0 :                         if (num_threads > 4095) num_threads= 4095;
    2290              :                 }
    2291            0 :                 threads= (pthread_t *)malloc(num_threads * sizeof(pthread_t));
    2292            0 :                 argsp= (args_t *)malloc(num_threads * sizeof(args_t));
    2293              : 
    2294            0 :                 TRACE(TLVL_INFO, "before pthread_create - main_tid=%u loops=%d, threads=%u, dly_ms=%.3f traceControl_p=%p", main_tid, loops,
    2295              :                           num_threads, opt_dly_ms, (void *)traceControl_p);
    2296            0 :                 if (opt_timing_stats) {
    2297            0 :                         TRACE_CNTL("lvlsetMg", 0xfLL << TLVL_INFO); /* set INFO,DBG,DBG+1, and DBG+2 */
    2298            0 :                         t0_us= gettimeofday_us();
    2299              :                 }
    2300            0 :                 for (uu= 0; uu < num_threads; uu++) {
    2301            0 :                         argsp[uu].tidx= uu + 1;
    2302            0 :                         argsp[uu].loops= (unsigned)loops;
    2303            0 :                         argsp[uu].dly_ms= opt_dly_ms;
    2304            0 :                         argsp[uu].burst= opt_burst;
    2305            0 :                         pthread_create(&(threads[uu]), NULL, thread_func, (void *)&argsp[uu]);
    2306              :                 }
    2307              : 
    2308            0 :                 args0.tidx= 0;
    2309            0 :                 args0.loops= (unsigned)loops;
    2310            0 :                 args0.dly_ms= opt_dly_ms;
    2311            0 :                 args0.burst= opt_burst;
    2312            0 :                 thread_func(&args0);
    2313              : 
    2314            0 :                 if (trace_thread_option & 4) {
    2315            0 :                         char cmd[200];
    2316            0 :                         sprintf(cmd, "echo trace_buffer mappings before join '(#1)' = `cat /proc/%d/maps | grep trace_buffer | wc -l`",
    2317              :                                         getpid());
    2318            0 :                         sts= system(cmd);
    2319            0 :                         sprintf(cmd, "echo trace_buffer mappings before join '(#2)' = `cat /proc/%d/maps | grep trace_buffer | wc -l`",
    2320              :                                         getpid());
    2321            0 :                         sts= system(cmd);
    2322              :                 }
    2323            0 :                 for (uu= 0; uu < num_threads; uu++) { pthread_join(threads[uu], NULL); }
    2324            0 :                 if (opt_timing_stats) {
    2325            0 :                         tdelta_us= (uint32_t)(gettimeofday_us() - t0_us);
    2326            0 :                         total_traces= loops * (num_threads + 1) * 5;
    2327            0 :                         fprintf(stderr, "%lld usec, %.3f usec/TRACE, %.3f Mtraces/s\n", (unsigned long long)tdelta_us,
    2328            0 :                                         (double)tdelta_us / total_traces, (double)total_traces / tdelta_us);
    2329              :                 }
    2330            0 :                 if (trace_thread_option & 4) {
    2331            0 :                         char cmd[200];
    2332            0 :                         sprintf(cmd, "echo trace_buffer mappings after join '(#1)' = `cat /proc/%d/maps | grep trace_buffer | wc -l`",
    2333              :                                         getpid());
    2334            0 :                         sts= system(cmd);
    2335            0 :                         sprintf(cmd, "echo trace_buffer mappings after join '(#2)' = `cat /proc/%d/maps | grep trace_buffer | wc -l`",
    2336              :                                         getpid());
    2337            0 :                         sts= system(cmd);
    2338              :                 }
    2339            0 :                 TRACE(TLVL_INFO, "after pthread_join - main_tid=%u traceControl_p=%p sts=%d", main_tid, (void *)traceControl_p, sts);
    2340            0 :                 free(threads);
    2341              :         }
    2342              : #endif
    2343            0 :         else if (strcmp(cmd, "show") == 0) {
    2344            0 :                 const char *ospec= getenv("TRACE_SHOW");
    2345            0 :                 if (!ospec) ospec= DFLT_SHOW;
    2346            0 :                 if ((do_heading == 0) && (strncmp("%H", ospec, 2) == 0)) ospec+= 2; /* skip "%H" */
    2347            0 :                 if (show_opts & forward_ && opt_count == -2) opt_count= 10;         /* like head and tail default */
    2348            0 :                 if (opt_quiet) show_opts|= quiet_;
    2349            0 :                 traceShow(ospec, opt_count, opt_start, show_opts, argc - optind, &argv[optind]);
    2350            0 :         } else if (strncmp(cmd, "info", 4) == 0) {
    2351            0 :                 traceInit("_TRACE_", 1); /* Use "_TRACE_" incase corrupted TRACE_FILE where "TRACE" may not exist and write undesired */
    2352            0 :                 traceInfo(opt_quiet);
    2353            0 :         } else if (strcmp(cmd, "tids") == 0) {
    2354            0 :                 uint32_t longest_name;
    2355            0 :                 int namLvlTblEnts_digits;
    2356            0 :                 traceInit("_TRACE_", 1);
    2357            0 :                 longest_name= traceControl_rwp->longest_name;
    2358            0 :                 if (longest_name > traceControl_p->nam_arr_sz) longest_name= traceControl_p->nam_arr_sz;
    2359              :                 /*printf("longest_name=%d\n",longest_name);*/
    2360            0 :                 namLvlTblEnts_digits= countDigits((int)traceControl_p->num_namLvlTblEnts - 1);
    2361            0 :                 if (do_heading) {
    2362            0 :                         printf("mode:%*s%*s            M=%d                S=%d\n", minw(3, namLvlTblEnts_digits), "", longest_name, "",
    2363            0 :                                    traceControl_rwp->mode.bits.M, traceControl_rwp->mode.bits.S);
    2364            0 :                         printf("%*s %*s %*s %*s %*s\n", minw(3, namLvlTblEnts_digits), "TID", longest_name, "NAME", 18, "maskM", 18, "maskS",
    2365              :                                    18, "maskT");
    2366            0 :                         printf("%.*s %.*s %.*s %.*s %.*s\n", minw(3, namLvlTblEnts_digits), TRACE_LONG_DASHES, longest_name, TRACE_LONG_DASHES,
    2367              :                                    18, TRACE_LONG_DASHES, 18, TRACE_LONG_DASHES, 18, TRACE_LONG_DASHES);
    2368              :                 }
    2369            0 :                 for (uu= 0; uu < traceControl_p->num_namLvlTblEnts; ++uu) {
    2370            0 :                         if (opt_all || TRACE_TID2NAME((int32_t)uu)[0] != '\0') {
    2371            0 :                                 printf("%*d %*.*s 0x%016llx 0x%016llx 0x%016llx\n", minw(3, namLvlTblEnts_digits), uu, longest_name, longest_name,
    2372            0 :                                            TRACE_TID2NAME((int32_t)uu), (unsigned long long)traceLvls_p[uu].M, (unsigned long long)traceLvls_p[uu].S,
    2373            0 :                                            (unsigned long long)traceLvls_p[uu].T);
    2374              :                         }
    2375              :                 }
    2376            0 :         } else if (strcmp(cmd, "memreport") == 0) {
    2377            0 :                 int use_sys_levels= opt_memreport_sys;
    2378            0 :                 int32_t max_reverse_us= opt_memreport_max_reverse_us;
    2379              :                 /* Re-scan trailing args for memreport-specific options and reject unexpected leftovers. */
    2380            0 :                 for (ii= optind; ii < argc; ++ii) {
    2381            0 :                         if (strcmp(argv[ii], "--sys") == 0) use_sys_levels= 1;
    2382            0 :                         else if (strncmp(argv[ii], "--max-reverse-us=", 17) == 0) {
    2383            0 :                                 char *endp= NULL;
    2384            0 :                                 unsigned long tmp= strtoul(argv[ii] + 17, &endp, 0);
    2385            0 :                                 if (argv[ii][17] == '\0' || endp == (argv[ii] + 17) || *endp != '\0' || tmp > INT32_MAX) {
    2386            0 :                                         fprintf(stderr, "memreport: invalid --max-reverse-us value: %s\n", argv[ii] + 17);
    2387            0 :                                         ret= 1;
    2388            0 :                                         goto done;
    2389              :                                 }
    2390            0 :                                 max_reverse_us= (int32_t)tmp;
    2391            0 :                         } else if (strcmp(argv[ii], "--max-reverse-us") == 0) {
    2392            0 :                                 char *endp= NULL;
    2393            0 :                                 unsigned long tmp;
    2394            0 :                                 if ((ii + 1) >= argc) {
    2395            0 :                                         fprintf(stderr, "memreport: missing argument for --max-reverse-us\n");
    2396            0 :                                         ret= 1;
    2397            0 :                                         goto done;
    2398              :                                 }
    2399            0 :                                 tmp= strtoul(argv[ii + 1], &endp, 0);
    2400            0 :                                 if (argv[ii + 1][0] == '\0' || endp == argv[ii + 1] || *endp != '\0' || tmp > INT32_MAX) {
    2401            0 :                                         fprintf(stderr, "memreport: invalid --max-reverse-us value: %s\n", argv[ii + 1]);
    2402            0 :                                         ret= 1;
    2403            0 :                                         goto done;
    2404              :                                 }
    2405            0 :                                 max_reverse_us= (int32_t)tmp;
    2406            0 :                                 ++ii;
    2407              :                         }
    2408              :                         else {
    2409            0 :                                 fprintf(stderr, "memreport: unknown option: %s\n", argv[ii]);
    2410            0 :                                 ret= 1;
    2411            0 :                                 goto done;
    2412              :                         }
    2413              :                 }
    2414            0 :                 traceInit("_TRACE_", 1);
    2415            0 :                 traceMemReport(do_heading, use_sys_levels, max_reverse_us);
    2416            0 :         } else if (strcmp(cmd, "unlock") == 0) {
    2417            0 :                 traceInit(NULL, 0);
    2418            0 :                 trace_unlock(&traceControl_rwp->namelock);
    2419            0 :         } else if (strcmp(cmd, "lvlstrs") == 0) {
    2420            0 :                 TRACE_CNTL("init"); /* for potential TRACE_LVLSTRS */
    2421            0 :                 for (ii= 0; ii < 64; ++ii) {
    2422            0 :                         int aa;
    2423            0 :                         printf("%2d ", ii);
    2424            0 :                         for (aa= 0; aa < trace_lvlstrs_aliases; ++aa) printf("%*s ", trace_lvlwidth, trace_lvlstrs[aa][ii]);
    2425            0 :                         printf("\n");
    2426              :                 }
    2427            0 :         } else if (strncmp(cmd, "TRACE", 5) == 0) {
    2428              : #define ARGS_SZ 35 * sizeof(uint64_t) / sizeof(unsigned long)      /* works for 32 and 64 bit archs */
    2429            0 :                 unsigned long args[ARGS_SZ] __attribute__((aligned(16)));  // needed for delayed long double formatting
    2430            0 :                 unsigned long *args_ptr= args;
    2431            0 :                 unsigned long *end_ptr= &args[ARGS_SZ];
    2432            0 :                 unsigned long *nxt_ptr;
    2433            0 :                 uint8_t nargs= 0, lvl;
    2434            0 :                 int line;
    2435            0 :                 int cc, required= (cmd[5] == 'N') ? 3 : 2;
    2436            0 :                 char *eptr, *lvlptr= (cmd[5] == 'N') ? argv[optind + 1] : argv[optind];
    2437            0 :                 if (opt_loops == -1) opt_loops= 1;
    2438            0 :                 if (argc - optind < required) {
    2439            0 :                         printf("\"TRACE\" cmd requires at least lvl and fmt arguments.");
    2440            0 :                         printf("\"TRACE\" cmd requires at least name, lvl and fmt arguments.");
    2441            0 :                         printf(USAGE);
    2442            0 :                         exit(0);
    2443              :                 }
    2444            0 :                 for (cc= optind + required; cc < argc; ++cc) {
    2445              :                         /* do a quick check for certain character that would only be in a double - see man strtod */
    2446            0 :                         if (strpbrk(argv[cc], ".INnPp")) nxt_ptr= add_double_arg(args_ptr, end_ptr, strtod(argv[cc], NULL));
    2447              :                         else {
    2448              :                                 /* then actually see if a full unsigned long parse occurs */
    2449            0 :                                 unsigned long uu= strtoul(argv[cc], &eptr, 0);
    2450            0 :                                 if (eptr == (argv[cc] + strlen(argv[cc]))) nxt_ptr= add_ul_arg(args_ptr, end_ptr, uu);
    2451              :                                 else
    2452            0 :                                         nxt_ptr= add_double_arg(args_ptr, end_ptr, strtod(argv[cc], NULL));
    2453              :                         }
    2454            0 :                         if (nxt_ptr == args_ptr) break;
    2455            0 :                         args_ptr= nxt_ptr;
    2456            0 :                         ++nargs;
    2457              :                 }
    2458              : 
    2459            0 :                 TRACE_CNTL("init"); /* for potential TRACE_LVLSTRS */
    2460            0 :                 tdelta_us= opt_dly_ms * 1000;
    2461            0 :                 lvl= (uint8_t)strtoul(lvlptr, &eptr, 0); /* traceInit should be called before this to pickup any trace_lvlstrs changes */
    2462            0 :                 if (lvlptr == eptr) lvl= (uint8_t)str2enum(lvlptr);
    2463            0 :                 if (opt_timing_stats) t0_us= gettimeofday_us();
    2464            0 :                 line= opt_line;
    2465              : #ifdef __TRACE_LINE__
    2466              : #       undef __TRACE_LINE__
    2467              : #endif
    2468              : #define __TRACE_LINE__ line
    2469            0 :                 if (cmd[5] == 'N')
    2470            0 :                         for (ii= 0; ii < opt_loops; ++ii) {
    2471            0 :                                 if (tdelta_us && ii) usleep(tdelta_us);
    2472            0 :                                 if (!line) { line= __LINE__; }
    2473            0 :                                 VTRACEN(argv[optind], lvl, nargs, argv[optind + 2], args);
    2474              :                         }
    2475              :                 else
    2476            0 :                         for (ii= 0; ii < opt_loops; ++ii) {
    2477            0 :                                 if (tdelta_us && ii) usleep(tdelta_us);
    2478            0 :                                 if (!line) { line= __LINE__; }
    2479            0 :                                 VTRACE(lvl, nargs, argv[optind + 1], args);
    2480              :                         }
    2481              : #undef __TRACE_LINE__
    2482              : #define __TRACE_LINE__ __LINE__
    2483            0 :                 if (opt_timing_stats) {
    2484            0 :                         tdelta_us= (uint32_t)(gettimeofday_us() - t0_us);
    2485            0 :                         fprintf(stderr, "%lld usec, %.3f usec/TRACE, %.3f Mtraces/s\n", (unsigned long long)tdelta_us,
    2486            0 :                                         (double)tdelta_us / opt_loops, (double)opt_loops / tdelta_us);
    2487              :                 }
    2488            0 :         } else if (strncmp(cmd, "sleep", 4) == 0) { /* this allows time to look at /proc/fd/ and /proc/maps */
    2489            0 :                 TRACE(TLVL_INFO, "starting sleep");
    2490            0 :                 if ((argc - optind) == 1) sleep((unsigned)strtoul(argv[optind], NULL, 0));
    2491              :                 else
    2492            0 :                         sleep(10);
    2493            0 :                 TRACE(TLVL_INFO, "done sleeping");
    2494              :         }
    2495              :         /* now deal with traceCntl commands using TRACE_CNTL */
    2496            0 :         else if (strncmp(cmd, "mode", 4) == 0) { /* mode is special -- may _return_ old mode */
    2497            0 :                 if ((argc - optind) == 0) {
    2498            0 :                         ret= (int)TRACE_CNTL(cmd);
    2499            0 :                         printf("%d\n", ret); /* print the old mode */
    2500              :                 } else
    2501            0 :                         ret= (int)TRACE_CNTL(cmd, strtoul(argv[optind], NULL, 0));
    2502            0 :                 if (ret == -1) ret= 1;
    2503              :                 else
    2504            0 :                         ret= 0;
    2505            0 :         } else if ((strncmp(cmd, "lvlmsk", 6) == 0) || (strncmp(cmd, "lvlset", 6) == 0) || (strncmp(cmd, "lvlclr", 6) == 0)) {
    2506              :                 /* lvl msk,set,clr are special primarily in that the -n<name> will no
    2507              :                    longer create a non-existent name b/c it could be a wildcard spec.
    2508              :                    Way to create a non-existent name:
    2509              :                    trace_cntl mode -n<name>
    2510              :                    TRACE_NAME=<name> trace_cntl lvlsetM <msk>
    2511              :            others? */
    2512            0 :                 size_t slen= strlen(&cmd[6]);
    2513            0 :                 long long msk= 0;
    2514            0 :                 if (opt_Name) { /* this is the Name given via the -N which may be a WILDCARDed name */
    2515            0 :                         char cmdn[8];
    2516            0 :                         if (slen > 1 || (slen == 1 && !strpbrk(&cmd[6], "MST"))) {
    2517            0 :                                 printf("invalid command: %s\n", cmd);
    2518            0 :                                 printf(USAGE);
    2519              :                         }
    2520            0 :                         strncpy(cmdn, cmd, 6);
    2521            0 :                         cmdn[6]= 'n';
    2522            0 :                         strcpy(&cmdn[7], &cmd[6]); /* insert the 'n' */
    2523            0 :                         switch (argc - optind) {
    2524            0 :                         case 0:
    2525            0 :                                 msk= TRACE_CNTL(cmdn, opt_Name);
    2526            0 :                                 printf("mask=0x%llx\n", msk);
    2527            0 :                                 break;
    2528            0 :                         case 1:
    2529            0 :                                 msk= TRACE_CNTL(cmdn, opt_Name, strtoull(argv[optind], NULL, 0));
    2530              :                                 /*printf("previous mask=0x%x\n",sts);*/
    2531            0 :                                 break;
    2532            0 :                         case 3:
    2533            0 :                                 TRACE_CNTL(cmdn, opt_Name, strtoull(argv[optind], NULL, 0), strtoull(argv[optind + 1], NULL, 0),
    2534              :                                                    strtoull(argv[optind + 2], NULL, 0));
    2535            0 :                                 break;
    2536            0 :                         default:
    2537            0 :                                 printf("invalid command: %s\n", cmd);
    2538            0 :                                 printf(USAGE);
    2539            0 :                                 break;
    2540              :                         }
    2541              :                 } else {
    2542            0 :                         if (slen > 2 || (slen >= 1 && !strpbrk(&cmd[6], "MSTgG"))) {
    2543            0 :                                 printf("invalid command: %s\n", cmd);
    2544            0 :                                 printf(USAGE);
    2545              :                         }
    2546            0 :                         switch (argc - optind) {
    2547            0 :                         case 0:
    2548            0 :                                 msk= TRACE_CNTL(cmd);
    2549            0 :                                 printf("mask=0x%llx\n", msk);
    2550            0 :                                 break;
    2551            0 :                         case 1: msk= TRACE_CNTL(cmd, strtoull(argv[optind], NULL, 0)); break;
    2552            0 :                         case 3:
    2553            0 :                                 TRACE_CNTL(cmd, strtoull(argv[optind], NULL, 0), strtoull(argv[optind + 1], NULL, 0),
    2554              :                                                    strtoull(argv[optind + 2], NULL, 0));
    2555            0 :                                 break;
    2556            0 :                         default:
    2557            0 :                                 printf("invalid command: %s\n", cmd);
    2558            0 :                                 printf(USAGE);
    2559            0 :                                 break;
    2560              :                         }
    2561              :                 }
    2562              :         } else { /* all other traceCntl commands */
    2563            0 :                 long long sts= 0;
    2564              :                 /*printf("argc - optind = %d\n", argc - optind );*/
    2565            0 :                 switch (argc - optind) {
    2566            0 :                 case 0: sts= TRACE_CNTL(cmd); break;
    2567            0 :                 case 1: sts= TRACE_CNTL(cmd, strtoull(argv[optind], NULL, 0)); break;
    2568            0 :                 case 2: sts= TRACE_CNTL(cmd, strtoull(argv[optind], NULL, 0), strtoull(argv[optind + 1], NULL, 0)); break;
    2569            0 :                 case 3:
    2570            0 :                         sts= TRACE_CNTL(cmd, strtoull(argv[optind], NULL, 0), strtoull(argv[optind + 1], NULL, 0),
    2571              :                                                         strtoull(argv[optind + 2], NULL, 0));
    2572            0 :                         break;
    2573              :                 }
    2574            0 :                 if (sts < 0) {
    2575            0 :                         printf("invalid command: %s\n", cmd);
    2576            0 :                         printf(USAGE);
    2577            0 :                         ret= 1;
    2578            0 :                 } else if (sts == 0) /* WHY?? */
    2579              :                         ret= 1;
    2580              :                 else
    2581            0 :                         ret= 0;
    2582              :         }
    2583            0 : done:
    2584            0 :         return (ret);
    2585              : } /* main */
        

Generated by: LCOV version 2.0-1