openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

cint_logger.c (48637B)


      1 /*
      2  * 
      3  *
      4  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      5  * 
      6  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      7  *
      8  * File:        cint_logger.c
      9  * Purpose:     CINT logger. Generates C-like logs from executing BCM APIs in
     10  *              order to replicate API call sequences in another environment
     11  */
     12 
     13 #if CINT_CONFIG_INCLUDE_CINT_LOGGER == 1
     14 
     15 #include <shared/bsl.h>
     16 #include <shared/bslnames.h>
     17 #include <sal/core/sync.h>
     18 #include <sal/core/thread.h>
     19 #include <sal/core/libc.h>
     20 #include <sal/appl/sal.h>
     21 #include <sal/appl/io.h> 
     22 #include <appl/diag/bslsink.h>
     23 #include <appl/diag/bslenable.h>
     24 #include <appl/diag/parse.h>
     25 #include <appl/diag/cmdlist.h>
     26 
     27 #include "cint_config.h"
     28 #include "cint_interpreter.h"
     29 #include "cint_porting.h"
     30 #include "cint_variables.h"
     31 #include "cint_error.h"
     32 #include "cint_eval_asts.h"
     33 #include "cint_internal.h"
     34 #include "cint_datatypes.h"
     35 #include "cint_debug.h"
     36 #include "cint_parser.h"
     37 #include "cint_logger.h"
     38 
     39 /*
     40  * global configuration and state data for the logger
     41  */
     42 cint_logger_global_cfg_data_t cint_logger_cfg = {
     43     .enabled        = 0                      , /* disabled by default                                */
     44     .mode           = cintLoggerModeCache    , /* default mode is to cache                           */
     45     .logLayer       = bslLayerAppl           , /* default BSL Layer to send logs to - Appl           */
     46     .logSource      = bslSourceCintapilogger , /* default BSL Source to send logs to - CintApiLogger */
     47     .cint_filter_fn = NULL                   , /* no default CINT function for filtering             */
     48     .user_filter_cb = NULL                   , /* no user-defined filtering callback function        */
     49     .tls_key        = NULL                   , /* initializer for tls_key                            */
     50     .mutex          = NULL                   , /* initializer for mutex                              */
     51     .ctxt_head      = NULL                   , /* head of api_params                              */
     52 
     53     .base_indent    = 4                      , /* base indent level for generated CINT output        */
     54 
     55     .log_to_file    = 0                      , /* logging to a file - disabled by default            */
     56     .logfile        = NULL                   , /* logging to a file - log file name                  */
     57     .logfile_fp     = NULL                   , /* logging to a file - FILE handle                    */
     58 };
     59 static cint_variable_t *vcint_logger_cfg = NULL;
     60 
     61 static bslsink_sink_t _cint_logger_bslsink;
     62 
     63 /***********************************************************************************/
     64 /*                                                                                 */
     65 /* Integrate with the CINT interpreter. Expose data structures and config variable */
     66 /* so that user can access these from the interpreter.                             */
     67 /*                                                                                 */
     68 /***********************************************************************************/
     69 
     70 static cint_enum_map_t __cint_enum_map__cint_logger_mode_t[] = {
     71     { "cintLoggerModePreload" , cintLoggerModePreload },
     72     { "cintLoggerModeLog"     , cintLoggerModeLog     },
     73     { "cintLoggerModeCache"   , cintLoggerModeCache   },
     74     { "cintLoggerModeReplay"  , cintLoggerModeReplay  },
     75     { NULL                                            },
     76 };
     77 
     78 static cint_enum_type_t __cint_logger_enums[] = {
     79     { "cint_logger_mode_t"    , __cint_enum_map__cint_logger_mode_t },
     80     { NULL                    ,                                     },
     81 };
     82 
     83 static cint_parameter_desc_t __cint_struct_members__cint_logger_global_cfg_data_t[] = {
     84     { "int"                         , "enabled"            , 0 , 0 },
     85     { "cint_logger_mode_t"          , "mode"               , 0 , 0 },
     86     { "int"                         , "logLayer"           , 0 , 0 },
     87     { "int"                         , "logSource"          , 0 , 0 },
     88     { "char"                        , "cint_filter_fn"     , 1 , 0 },
     89     { "void"                        , "user_filter_cb"     , 1 , 0 },
     90     { "void"                        , "tls_key"            , 1 , 0 },
     91     { "void"                        , "mutex"              , 1 , 0 },
     92     { "cint_logger_api_params_t"    , "ctxt_head"          , 1 , 0 },
     93     { "int"                         , "count"              , 0 , 0 },
     94     { "int"                         , "base_indent"        , 0 , 0 },
     95     { "int"                         , "log_to_file"        , 0 , 0 },
     96     { "char"                        , "logfile"            , 1 , 0 },
     97     { "void"                        , "logfile_fp"         , 1 , 0 },
     98     { NULL                          , NULL                 , 0 , 0 },
     99 };
    100 
    101 static void*
    102 __cint_maddr__cint_logger_global_cfg_data_t (void* p, int mnum, cint_struct_type_t* parent)
    103 {
    104     void *rv;
    105     cint_logger_global_cfg_data_t *s = p;
    106 
    107     switch (mnum) {
    108     case  0: rv = &(s->enabled);        break;
    109     case  1: rv = &(s->mode);           break;
    110     case  2: rv = &(s->logLayer);       break;
    111     case  3: rv = &(s->logSource);      break;
    112     case  4: rv = &(s->cint_filter_fn); break;
    113     case  5: rv = &(s->user_filter_cb); break;
    114     case  6: rv = &(s->tls_key);        break;
    115     case  7: rv = &(s->mutex);          break;
    116     case  8: rv = &(s->ctxt_head);      break;
    117     case  9: rv = &(s->count);          break;
    118     case 10: rv = &(s->base_indent);    break;
    119     case 11: rv = &(s->log_to_file);    break;
    120     case 12: rv = &(s->logfile);        break;
    121     case 13: rv = &(s->logfile_fp);     break;
    122     default: rv = NULL;                 break;
    123     }
    124 
    125     return rv;
    126 }
    127 
    128 static cint_parameter_desc_t __cint_struct_members__cint_logger_rtime_t[] = {
    129     { "unsigned int" , "last" , 0 , 0 },
    130     { "unsigned int" , "min"  , 0 , 0 },
    131     { "unsigned int" , "max"  , 0 , 0 },
    132     { "unsigned int" , "avg"  , 0 , 0 },
    133     { NULL           , NULL   , 0 , 0 },
    134 };
    135 
    136 static void*
    137 __cint_maddr__cint_logger_rtime_t (void* p, int mnum, cint_struct_type_t* parent)
    138 {
    139     void *rv;
    140     cint_logger_rtime_t *s = p;
    141 
    142     switch (mnum) {
    143     case  0: rv = &(s->last); break;
    144     case  1: rv = &(s->min);  break;
    145     case  2: rv = &(s->max);  break;
    146     case  3: rv = &(s->avg);  break;
    147     default: rv = NULL;       break;
    148     }
    149 
    150     return rv;
    151 }
    152 
    153 static cint_parameter_desc_t __cint_struct_members__cint_logger_api_params_t[] = {
    154     { "void"                , "next"            , 1 , 0 },
    155     { "void"                , "prev"            , 1 , 0 },
    156     { "char"                , "fn"              , 1 , 0 },
    157     { "void"                , "params"          , 1 , 0 },
    158     { "int"                 , "basetype_size"   , 0 , CINT_CONFIG_MAX_FPARAMS+1 },
    159     { "SHR_BITDCL"          , "is_basetype_arr" , 0 , _SHR_BITDCLSIZE(CINT_CONFIG_MAX_FPARAMS+1) },
    160     { "SHR_BITDCL"          , "is_charptr"      , 0 , _SHR_BITDCLSIZE(CINT_CONFIG_MAX_FPARAMS+1) },
    161     { "int"                 , "nargs"           , 0 , 0 },
    162     { "int"                 , "called_count"    , 0 , 0 },
    163     { "cint_logger_rtime_t" , "arg_ptrs"        , 0 , 0 },
    164     { "cint_logger_rtime_t" , "preload"         , 0 , 0 },
    165     { "cint_logger_rtime_t" , "call1"           , 0 , 0 },
    166     { "cint_logger_rtime_t" , "dispatch"        , 0 , 0 },
    167     { "cint_logger_rtime_t" , "call2"           , 0 , 0 },
    168     { "cint_logger_rtime_t" , "total"           , 0 , 0 },
    169     { NULL                  , NULL              , 0 , 0 },
    170 };
    171 
    172 static void*
    173 __cint_maddr__cint_logger_api_params_t (void* p, int mnum, cint_struct_type_t* parent)
    174 {
    175     void *rv;
    176     cint_logger_api_params_t *s = p;
    177 
    178     switch (mnum) {
    179     case  0: rv = &(s->next);            break;
    180     case  1: rv = &(s->prev);            break;
    181     case  2: rv = &(s->fn);              break;
    182     case  3: rv = &(s->params);          break;
    183     case  4: rv = &(s->basetype_size);   break;
    184     case  5: rv = &(s->is_basetype_arr); break;
    185     case  6: rv = &(s->is_charptr);      break;
    186     case  7: rv = &(s->nargs);           break;
    187     case  8: rv = &(s->called_count);    break;
    188     case  9: rv = &(s->arg_ptrs);        break;
    189     case 10: rv = &(s->preload);         break;
    190     case 11: rv = &(s->call1);           break;
    191     case 12: rv = &(s->dispatch);        break;
    192     case 13: rv = &(s->call2);           break;
    193     case 14: rv = &(s->total);           break;
    194     default: rv = NULL;                  break;
    195     }
    196 
    197     return rv;
    198 }
    199 
    200 static cint_parameter_desc_t __cint_struct_members__cint_logger_call_ctxt_t[] = {
    201     { "char"         , "api"             , 1 , 0 },
    202     { "unsigned int" , "flags"           , 0 , 0 },
    203     { "void"         , "caller_tid"      , 1 , 0 },
    204     { "char"         , "caller_tname"    , 1 , 0 },
    205     { "char"         , "caller_file"     , 1 , 0 },
    206     { "int"          , "caller_line"     , 0 , 0 },
    207     { "char"         , "caller_function" , 1 , 0 },
    208     { "int"          , "skip_dispatch"   , 1 , 0 },
    209     { "int"          , "call_id"         , 0 , 0 },
    210     { NULL           , NULL              , 0 , 0 },
    211 };
    212 
    213 static void*
    214 __cint_maddr__cint_logger_call_ctxt_t (void* p, int mnum, cint_struct_type_t* parent)
    215 {
    216     void *rv;
    217     cint_logger_call_ctxt_t *s = p;
    218 
    219     switch (mnum) {
    220     case  0: rv = &(s->api);                 break;
    221     case  1: rv = &(s->flags);               break;
    222     case  2: rv = &(s->caller_tid);          break;
    223     case  3: rv = &(s->caller_tname);        break;
    224     case  4: rv = &(s->caller_file);         break;
    225     case  5: rv = &(s->caller_line);         break;
    226     case  6: rv = &(s->caller_function);     break;
    227     case  7: rv = &(s->skip_dispatch);       break;
    228     case  8: rv = &(s->call_id);             break;
    229     default: rv = NULL;                      break;
    230     }
    231 
    232     return rv;
    233 }
    234 
    235 static cint_struct_type_t __cint_logger_structures[] = {
    236      CINT_STRUCT_TYPE_DEFINE(cint_logger_rtime_t          ),
    237      CINT_STRUCT_TYPE_DEFINE(cint_logger_api_params_t     ),
    238      CINT_STRUCT_TYPE_DEFINE(cint_logger_global_cfg_data_t),
    239      CINT_STRUCT_TYPE_DEFINE(cint_logger_call_ctxt_t      ),
    240      { NULL },
    241 };
    242 
    243 static cint_data_t _cint_logger_cint_data = {
    244     NULL,
    245     NULL,
    246     __cint_logger_structures,
    247     __cint_logger_enums,
    248     NULL,
    249     NULL,
    250     NULL,
    251 };
    252 
    253 static void
    254 _cint_logger_cint_init ()
    255 {
    256     cint_datatype_t dt;
    257 
    258     cint_interpreter_add_data(&_cint_logger_cint_data, NULL);
    259 
    260     vcint_logger_cfg = NULL;
    261 
    262     if (cint_datatype_find("cint_logger_global_cfg_data_t", &dt) == CINT_E_NONE) {
    263         cint_variable_create(&vcint_logger_cfg, "cint_logger_cfg", &dt.desc,
    264                              CINT_VARIABLE_F_SDATA|CINT_VARIABLE_F_NODESTROY,
    265                              &cint_logger_cfg);
    266     }
    267 }
    268 
    269 static int
    270 _cint_logger_cint_interp_listener (void *cookie, cint_interpreter_event_t event)
    271 {
    272     switch (event) {
    273     case cintEventReset:
    274         _cint_logger_cint_init();
    275         break;
    276     default:
    277         break;
    278     }
    279     return CINT_E_NONE;
    280 }
    281 
    282 /***********************************************************************************/
    283 /*                                                                                 */
    284 /* BSL sink to log generated output to a separate file. Also the point where post  */
    285 /* processing - e.g. conversion to C - can be chained into the processing flow.    */
    286 /*                                                                                 */
    287 /***********************************************************************************/
    288 
    289 static int
    290 _cint_logger_bsl_vfprintf (void *f, const char *format, va_list args)
    291 {
    292     void *file_fp = cint_logger_cfg.logfile_fp;
    293     int enabled   = cint_logger_cfg.log_to_file;
    294     int retv = 0;
    295 
    296     if (!enabled || !file_fp) {
    297         return 0;
    298     }
    299 
    300     retv = CINT_VFPRINTF((FILE*) file_fp, format, args);
    301 
    302     CINT_FFLUSH(file_fp);
    303 
    304     return retv;
    305 }
    306 
    307 static int
    308 _cint_logger_bsl_check (bsl_meta_t *meta)
    309 {
    310     cint_logger_thread_data_t *tdata;
    311 
    312     return (((meta->layer  == cint_logger_cfg.logLayer) &&
    313              (meta->source == cint_logger_cfg.logSource) &&
    314              (meta->severity == bslSeverityVerbose)) ||
    315             ((tdata = cint_logger_thread_specific()) &&
    316              (*tdata).logger_is_active));
    317 }
    318 
    319 
    320 static int
    321 _cint_logger_bsl_cleanup (bslsink_sink_t *sink)
    322 {
    323     if (cint_logger_cfg.logfile_fp) {
    324         CINT_FCLOSE(cint_logger_cfg.logfile_fp);
    325         cint_logger_cfg.logfile_fp = NULL;
    326     }
    327     return 0;
    328 }
    329 
    330 static int
    331 _cint_logger_bsl_init ()
    332 {
    333     bslsink_sink_t *sink;
    334 
    335     sink = &_cint_logger_bslsink;
    336     bslsink_sink_t_init(sink);
    337     CINT_STRNCPY(sink->name, "CintApiLoggerSink", sizeof(sink->name));
    338     sink->vfprintf = _cint_logger_bsl_vfprintf;
    339     sink->check = _cint_logger_bsl_check;
    340     sink->cleanup = _cint_logger_bsl_cleanup;
    341 
    342     sink->enable_range.min = bslSeverityOff+1;
    343     sink->enable_range.max = bslSeverityCount-1;
    344 
    345     sink->prefix_range.min = bslSeverityOff+1;
    346     sink->prefix_range.max = bslSeverityWarn;
    347 
    348     bslsink_sink_add(sink);
    349 
    350     return 0;
    351 }
    352 
    353 /***********************************************************************************/
    354 /*                                                                                 */
    355 /* Main CINT logging functionality follows                                         */
    356 /*                                                                                 */
    357 /***********************************************************************************/
    358 
    359 static void
    360 _cint_logger_get_array_count (cint_logger_api_params_t *ctxt, void *arg_ptrs[], int array_cnt_indx, int *array_cnt)
    361 {
    362     cint_parameter_desc_t *params, *ppdt;
    363     int nargs, array_cnt_size;
    364     void *array_cnt_ptr;
    365 
    366     params = ctxt->params;
    367     nargs = ctxt->nargs;
    368 
    369     if (array_cnt_indx >= nargs) {
    370         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    371                   (BSL_META("FATAL ERROR -- array_cnt_indx is out of bounds (%d >= %d)\n"), array_cnt_indx, nargs));
    372         return;
    373     }
    374 
    375     ppdt = &params[array_cnt_indx];
    376     if (!(ppdt->flags & CINT_PARAM_VL)) {
    377         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    378                   (BSL_META("FATAL ERROR -- pointed parameter is not array length (%s %s)\n"), ppdt->basetype, ppdt->name));
    379         return;
    380     }
    381 
    382     array_cnt_size = ctxt->basetype_size[array_cnt_indx];
    383 
    384     array_cnt_ptr  = arg_ptrs[array_cnt_indx];
    385 
    386     /* expect array_cnt to be an integer-like variable */
    387     switch (array_cnt_size) {
    388     case 1 : *array_cnt = *(unsigned char*)      array_cnt_ptr; break;
    389     case 2 : *array_cnt = *(unsigned short*)     array_cnt_ptr; break;
    390     case 4 : *array_cnt = *(unsigned long*)      array_cnt_ptr; break;
    391     case 8 : *array_cnt = *(unsigned long long*) array_cnt_ptr; break;
    392     default: break;
    393     }
    394 }
    395 
    396 static void
    397 _cint_logger_copy_function_arguments (cint_logger_thread_data_t *tdata,
    398                                       cint_logger_call_ctxt_t *call_ctxt,
    399                                       cint_logger_api_params_t *ctxt,
    400                                       void *arg_ptrs[],
    401                                       void *buffer,
    402                                       int *bufsz)
    403 
    404 {
    405     cint_logger_call_ctxt_t *scall_ctxt;
    406     cint_parameter_desc_t *params;
    407     cint_parameter_desc_t pds[CINT_CONFIG_MAX_FPARAMS+1];
    408     int array_size_save[CINT_CONFIG_MAX_FPARAMS+1];
    409     void *arg_ptrs_save[CINT_CONFIG_MAX_FPARAMS+1];
    410     int i, j, nargs, req, array_cnt_indx, array_cnt, copy_size, done, len;
    411     char *dst;
    412     void *ptr;
    413 
    414     params = ctxt->params;
    415     nargs = ctxt->nargs;
    416 
    417     for (i = 0; params[i].name && (i < nargs); i++) {
    418         pds[i] = params[i];
    419         arg_ptrs_save[i] = arg_ptrs[i];
    420         if (!pds[i].pcount && SHR_BITGET(ctxt->is_basetype_arr, i) && arg_ptrs_save[i]) {
    421             arg_ptrs_save[i] = *(void**)arg_ptrs_save[i];
    422         }
    423     }
    424 
    425     /* calculate required storage */
    426     req = 0;
    427 
    428     /*
    429      * the call context structure will be appended as a whole. It has string
    430      * type members - api, caller_file, caller_function. These if not NULL will
    431      * also be appended right after the call context structure, in order and
    432      * with NULL termination.
    433      */
    434     req += sizeof(*scall_ctxt) +
    435            ((call_ctxt->api) ? CINT_STRLEN(call_ctxt->api) + 1 : 0) +
    436            ((call_ctxt->caller_file) ? CINT_STRLEN(call_ctxt->caller_file) + 1 : 0) +
    437            ((call_ctxt->caller_function) ? CINT_STRLEN(call_ctxt->caller_function) + 1 : 0);
    438 
    439     for (i = 0; (i < nargs) && pds[i].name; i++) {
    440 
    441         req += pds[i].pcount * sizeof(void*);
    442 
    443         array_cnt = 1;
    444 
    445         if (SHR_BITGET(ctxt->is_charptr, i)) {
    446 
    447             ptr = *(void**) arg_ptrs[i];
    448             for (j = pds[i].pcount; j > 1; j--) {
    449                 ptr = (ptr) ? *(void**)ptr : NULL;
    450             }
    451 
    452             array_cnt = (ptr) ? CINT_STRLEN((char*)ptr) + 1 : 0;
    453 
    454         } else if (pds[i].flags & CINT_PARAM_VP) {
    455 
    456             array_cnt_indx = pds[i].flags & CINT_PARAM_IDX;
    457             _cint_logger_get_array_count(ctxt, arg_ptrs, array_cnt_indx, &array_cnt);
    458 
    459         }
    460 
    461         array_size_save[i] = array_cnt * ctxt->basetype_size[i];
    462         req += array_size_save[i];
    463     }
    464 
    465     if (*bufsz < req) {
    466         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    467                   (BSL_META("ERROR -- buffer is not large enough to copy all contents (%d vs %d required)\n"), *bufsz, req));
    468         return;
    469     }
    470 
    471     dst = buffer;
    472 
    473     scall_ctxt = (void*) dst;
    474     *scall_ctxt = *call_ctxt;
    475     dst += sizeof(*call_ctxt);
    476 
    477     if (call_ctxt->api) {
    478         len = CINT_STRLEN(call_ctxt->api);
    479         CINT_STRNCPY(dst, call_ctxt->api, len+1);
    480         scall_ctxt->api = dst;
    481         dst += (len + 1);
    482     }
    483 
    484     if (call_ctxt->caller_file) {
    485         len = CINT_STRLEN(call_ctxt->caller_file);
    486         CINT_STRNCPY(dst, call_ctxt->caller_file, len+1);
    487         scall_ctxt->caller_file = dst;
    488         dst += (len + 1);
    489     }
    490 
    491     if (call_ctxt->caller_function) {
    492         len = CINT_STRLEN(call_ctxt->caller_function);
    493         CINT_STRNCPY(dst, call_ctxt->caller_function, len+1);
    494         scall_ctxt->caller_function = dst;
    495         dst += (len + 1);
    496     }
    497 
    498     do {
    499 
    500         done = 1;
    501 
    502         for (i = 0; (i < nargs) && pds[i].name; i++) {
    503 
    504             if (pds[i].pcount < 0) {
    505                 continue;
    506             }
    507 
    508             if (pds[i].pcount) {
    509 
    510                 if (arg_ptrs_save[i]) {
    511                     *(void**)dst = *(void**)arg_ptrs_save[i];
    512                 } else {
    513                     *(void**)dst = NULL;
    514                 }
    515 
    516                 arg_ptrs_save[i] = *(void**)dst;
    517                 dst += sizeof(void*);
    518 
    519                 if (SHR_BITGET(ctxt->is_charptr, i) && (pds[i].pcount == 1) &&
    520                     arg_ptrs_save[i] && (copy_size = array_size_save[i])) {
    521 
    522                     CINT_MEMCPY(dst, arg_ptrs_save[i], copy_size);
    523                     dst += copy_size;
    524                     arg_ptrs_save[i] = NULL;
    525                 }
    526 
    527                 pds[i].pcount--;
    528                 done = 0;
    529                 continue;
    530             }
    531 
    532             if (arg_ptrs_save[i] && (copy_size = array_size_save[i])) {
    533 
    534                 CINT_MEMCPY(dst, arg_ptrs_save[i], copy_size);
    535                 dst += copy_size;
    536                 arg_ptrs_save[i] = NULL;
    537             }
    538 
    539             pds[i].pcount--;
    540             done = 0;
    541         }
    542 
    543     } while (!done);
    544 
    545     copy_size = dst - (char*)buffer;
    546     if ((*bufsz < copy_size) || (copy_size != req)) {
    547         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    548                   (BSL_META("ERROR -- buffer may have overflowed (%d vs %d copied), or copied size different from computed buffer size\n"), *bufsz, copy_size));
    549     }
    550 
    551     *bufsz = copy_size;
    552 }
    553 
    554 static void
    555 _cint_logger_log_variable (cint_parameter_desc_t *ppdt, const char *pfx, void *src, int indent)
    556 {
    557     cint_variable_t *v = NULL;
    558     char *name;
    559     int buflen, rc;
    560 
    561     buflen = CINT_STRLEN(pfx) + CINT_STRLEN(ppdt->name) + 2;
    562     name = CINT_MALLOC(buflen);
    563     if (!name) {
    564         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    565                   (BSL_META("FATAL ERROR - malloc failed\n")));
    566         return;
    567     }
    568     CINT_SNPRINTF(name, buflen, "%s%s", pfx, ppdt->name);
    569 
    570     /*
    571      * Add a variable by name so that we can print it. Do not push it to local
    572      * scope so that non thread-safe list operations in CINT infrastructure which
    573      * are not required here are avoided.
    574      */
    575     rc = cint_variable_create_no_add(&v, NULL, ppdt, CINT_VARIABLE_F_SDATA | CINT_VARIABLE_F_AUTO, src);
    576     if ((rc != CINT_E_NONE) || !v) {
    577         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    578                   (BSL_META("Failed to allocate %s (%s) -- %d\n"), name, ppdt->basetype, rc));
    579         CINT_FREE(name);
    580         return;
    581     }
    582 
    583     cint_variable_print(v, indent, name);
    584 
    585     cint_variable_free(v);
    586 
    587     CINT_FREE(name);
    588 }
    589 
    590 static void
    591 _indent (int cnt)
    592 {
    593     while (cnt && cnt--) {
    594         CINT_PRINTF(" ");
    595     }
    596 }
    597 
    598 static void
    599 _cint_rep_chr (char *str, char ch, int bufsz, int cnt)
    600 {
    601     if (cnt > (bufsz - 1)) {
    602         cnt = bufsz - 1;
    603     }
    604     CINT_MEMSET(str, ch, cnt);
    605     str[cnt] = '\0';
    606 }
    607 
    608 static void
    609 _cint_logger_log_arguments_buffer (cint_logger_call_ctxt_t *call_ctxt,
    610                                    cint_logger_api_params_t *ctxt,
    611                                    void *buffer, int bufsz)
    612 {
    613     cint_logger_call_ctxt_t *scall_ctxt;
    614     cint_parameter_desc_t *params, *ppdt;
    615     cint_parameter_desc_t pds[CINT_CONFIG_MAX_FPARAMS+1];
    616     cint_parameter_desc_t voidptr_pds = { "void", NULL, 1, 0 };
    617     void *arg_ptrs_save[CINT_CONFIG_MAX_FPARAMS+1];
    618     int i, nargs, array_cnt_indx, array_cnt, dim, first, done, src_offset;
    619     unsigned int flags;
    620     int indent;
    621     /*
    622      * variables to hold '_' prefixes for auto variables created due to pointer
    623      * dereference. we don't expect this to be more than 3. Use 10.
    624      */
    625     int max_pfx_len = 20;
    626     char pfx[max_pfx_len], pfx2[max_pfx_len];
    627     cint_parameter_desc_t call_ctxt_pds = { "cint_logger_call_ctxt_t", "this", 0, 0 };
    628     char *src, *src_save, *str;
    629 
    630     indent = cint_logger_cfg.base_indent;
    631     params = ctxt->params;
    632     nargs = ctxt->nargs;
    633     flags = call_ctxt->flags;
    634 
    635     src = buffer;
    636 
    637     scall_ctxt = (void*) src;
    638     src += sizeof(*scall_ctxt) +
    639            ((scall_ctxt->api) ? CINT_STRLEN(scall_ctxt->api) + 1 : 0) +
    640            ((scall_ctxt->caller_file) ? CINT_STRLEN(scall_ctxt->caller_file) + 1 : 0) +
    641            ((scall_ctxt->caller_function) ? CINT_STRLEN(scall_ctxt->caller_function) + 1 : 0);
    642 
    643     src_save = src;
    644 
    645     for (i = 0; params[i].name && (i < nargs); i++) {
    646         pds[i] = params[i];
    647         arg_ptrs_save[i] = src;
    648         if (params[i].pcount) {
    649             src += sizeof(void*);
    650             if (SHR_BITGET(ctxt->is_charptr, i) && (params[i].pcount == 1)) {
    651                 src += CINT_STRLEN(src) + 1;
    652             }
    653         } else {
    654             src += ctxt->basetype_size[i];
    655         }
    656     }
    657 
    658     src = src_save;
    659 
    660     if (flags & CINT_PARAM_IN) {
    661         _indent(indent);
    662         CINT_PRINTF("{\n");
    663     } else if (flags & CINT_PARAM_OUT) {
    664         _indent(indent);
    665         CINT_PRINTF("if (0) {\n");
    666     }
    667 
    668     indent += 4;
    669 
    670     first = 1;
    671 
    672     do {
    673 
    674         done = 1;
    675 
    676         for (i = 0; (i < nargs) && pds[i].name; i++) {
    677 
    678             if (pds[i].pcount < 0) {
    679                 continue;
    680             }
    681 
    682             if ((i == 0) & !(flags & CINT_PARAM_OUT)) {
    683                 src += ctxt->basetype_size[i];
    684                 pds[i].pcount--;
    685                 continue;
    686             }
    687 
    688             if ((pds[i].pcount == 0) && !CINT_STRCMP(pds[i].basetype, "void")) {
    689                 continue;
    690             }
    691 
    692             _cint_rep_chr(pfx, '_', max_pfx_len, params[i].pcount - pds[i].pcount);
    693 
    694             array_cnt = 1;
    695 
    696             if (SHR_BITGET(ctxt->is_charptr, i) && (pds[i].pcount <= 1)) {
    697 
    698                 if (pds[i].pcount == 1) {
    699 
    700                     voidptr_pds.name = pds[i].name;
    701 
    702                     CINT_SNPRINTF(pfx2, max_pfx_len, "orig_%s", pfx);
    703 
    704                     _cint_logger_log_variable(&voidptr_pds, pfx2, src, indent);
    705 
    706                     voidptr_pds.name = NULL;
    707 
    708                     str = src + sizeof(void*);
    709 
    710                     _cint_logger_log_variable(&pds[i], pfx, &str, indent);
    711 
    712                     src += sizeof(void*) + CINT_STRLEN(str) + 1; /* sizeof void* is accounted below */
    713 
    714                 }
    715 
    716                 pds[i].pcount--;
    717                 done = 0;
    718                 continue;
    719 
    720             } else if (!first && (pds[i].flags & CINT_PARAM_VP)) {
    721 
    722                 array_cnt_indx = pds[i].flags & CINT_PARAM_IDX;
    723 
    724                 _cint_logger_get_array_count(ctxt, arg_ptrs_save, array_cnt_indx, &array_cnt);
    725 
    726                 for (dim = CINT_CONFIG_ARRAY_DIMENSION_LIMIT - 1; dim > 0; dim--) {
    727                     pds[i].dimensions[dim] = pds[i].dimensions[dim-1];
    728                 }
    729                 pds[i].dimensions[0] = array_cnt;
    730                 pds[i].num_dimensions++;
    731 
    732             }
    733 
    734             _cint_logger_log_variable(&pds[i], pfx, src, indent);
    735 
    736             if (pds[i].pcount) {
    737                 src += sizeof(void*);
    738             } else {
    739                 src += array_cnt * ctxt->basetype_size[i];
    740             }
    741 
    742             pds[i].pcount--;
    743             done = 0;
    744             continue;
    745         }
    746 
    747         first = 0;
    748 
    749     } while (!done);
    750 
    751     _cint_logger_log_variable(&call_ctxt_pds, "", scall_ctxt, indent);
    752 
    753     src_offset = (int)(src - (char*)buffer);
    754     if (src_offset != bufsz) {
    755         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    756                   (BSL_META("Logger did not align to end of buffer (%s) -- offset %d vs expected %d\n"),
    757                    call_ctxt->api, src_offset, bufsz));
    758     }
    759 
    760     for (i = 0; (i < nargs) && params[i].name; i++) {
    761 
    762         if (!params[i].pcount) {
    763             continue;
    764         }
    765 
    766         pds[i] = params[i];
    767 
    768         for (pds[i].pcount--, first = 1; pds[i].pcount >= 0; pds[i].pcount--, first = 0) {
    769 
    770             if ((SHR_BITGET(ctxt->is_charptr, i) || !CINT_STRCMP(pds[i].basetype, "void")) && first) {
    771                 continue;
    772             }
    773 
    774             _cint_rep_chr(pfx, '_', max_pfx_len, pds[i].pcount+1);
    775             _cint_rep_chr(pfx2, '_', max_pfx_len, pds[i].pcount);
    776 
    777             _indent(indent);
    778             CINT_PRINTF("%s%s = &%s%s;\n", pfx2, pds[i].name, pfx, pds[i].name);
    779         }
    780     }
    781 
    782     CINT_PRINTF("\n");
    783 
    784     _indent(indent);
    785     CINT_PRINTF("%s(", ctxt->fn);
    786 
    787     ppdt = params;
    788     for (ppdt++; ppdt->name; ppdt++) {
    789         CINT_PRINTF("%s%s", (first++ > 0) ? ", " : "", ppdt->name);
    790     }
    791 
    792     CINT_PRINTF(");\n");
    793 
    794     indent -= 4;
    795     _indent(indent);
    796     CINT_PRINTF("}\n");
    797 }
    798 
    799 static void
    800 _cint_logger_inject_variables (cint_logger_thread_data_t *tdata,
    801                                cint_logger_call_ctxt_t *call_ctxt,
    802                                cint_logger_call_ctxt_t *orig_call_ctxt,
    803                                int *orig_r,
    804                                cint_logger_api_params_t *ctxt,
    805                                void *arg_ptrs[])
    806 {
    807     int i, rc;
    808     cint_variable_t *v[CINT_CONFIG_MAX_FPARAMS+1];
    809     cint_variable_t *vcall_ctxt = NULL, *vorig_call_ctxt = NULL, *vorig_r = NULL;
    810     cint_parameter_desc_t call_ctxt_pds = { "cint_logger_call_ctxt_t", NULL, 0, 0 };
    811     cint_parameter_desc_t *ppdt, *params;
    812     void *src;
    813 
    814 
    815     params = ctxt->params;
    816 
    817     /*
    818      * Create variables for all API arguments by name.
    819      */
    820 
    821     CINT_MEMSET(v, 0, (CINT_CONFIG_MAX_FPARAMS + 1) * sizeof(void*));
    822 
    823     for (i=0, src = arg_ptrs[i], ppdt = &params[i];
    824          ppdt->name;
    825          i++, src = arg_ptrs[i], ppdt = &params[i]) {
    826 
    827         if (!src) {
    828             continue;
    829         }
    830 
    831         rc = cint_variable_create(&v[i], ppdt->name, ppdt, CINT_VARIABLE_F_SDATA, src);
    832         if ((rc != CINT_E_NONE) || !v[i]) {
    833             LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    834                       (BSL_META("Failed to allocate %s (%s) -- %d\n"), ppdt->name, ppdt->basetype, rc));
    835             return;
    836         }
    837     }
    838 
    839     /*
    840      * create new variable for the call_ctxt
    841      */
    842     rc = cint_variable_create(&vcall_ctxt,
    843                               "this",
    844                               &call_ctxt_pds,
    845                               CINT_VARIABLE_F_SDATA,
    846                               call_ctxt);
    847     if ((rc != CINT_E_NONE) || !vcall_ctxt) {
    848         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    849                   (BSL_META("Failed to allocate %s (%s) -- %d\n"), call_ctxt_pds.name, call_ctxt_pds.basetype, rc));
    850     }
    851 
    852     if (cint_logger_cfg.mode == cintLoggerModeReplay) {
    853 
    854         if (orig_call_ctxt) {
    855 
    856             rc = cint_variable_create(&vorig_call_ctxt,
    857                                       "orig",
    858                                       &call_ctxt_pds,
    859                                       CINT_VARIABLE_F_SDATA,
    860                                       orig_call_ctxt);
    861             if ((rc != CINT_E_NONE) || !vorig_call_ctxt) {
    862                 LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    863                           (BSL_META("Failed to allocate %s (%s) -- %d\n"), call_ctxt_pds.name, call_ctxt_pds.basetype, rc));
    864             }
    865         }
    866 
    867         if (orig_r) {
    868 
    869             rc = cint_variable_create(&vorig_r,
    870                                       "orig_r",
    871                                       &params[0],
    872                                       CINT_VARIABLE_F_SDATA,
    873                                       orig_r);
    874             if ((rc != CINT_E_NONE) || !vorig_r) {
    875                 LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    876                           (BSL_META("Failed to allocate %s (%s) -- %d\n"), call_ctxt_pds.name, call_ctxt_pds.basetype, rc));
    877             }
    878         }
    879     }
    880 }
    881 
    882 static int
    883 _cint_logger_run_filter_function (cint_logger_thread_data_t *tdata,
    884                                   cint_logger_call_ctxt_t *call_ctxt,
    885                                   cint_logger_api_params_t *ctxt,
    886                                   void *arg_ptrs[])
    887 {
    888     cint_ast_t *i_ast, *f_ast;
    889     cint_variable_t *rv;
    890     cint_atomic_type_t *ap;
    891     const char *cint_filter_fn = cint_logger_cfg.cint_filter_fn;
    892     int save_disabled;
    893     int ret = 0;
    894 
    895     i_ast = cint_ast_identifier(cint_filter_fn);
    896     f_ast = cint_ast_function(i_ast, NULL);
    897 
    898     /*
    899      * cint_filter_fn may itself have API calls. We do not want to log those.
    900      * So disable logging for this thread. Take care to not enable if logging
    901      * was already disabled for this thread.
    902      *
    903      * Should we log those calls? -- TBD
    904      */
    905 
    906     save_disabled = (*tdata).disabled;
    907     (*tdata).disabled = 1;
    908 
    909     rv = cint_eval_ast(f_ast);
    910 
    911     (*tdata).disabled = save_disabled;
    912 
    913     cint_ast_free_single(f_ast);
    914     cint_ast_free_single(i_ast);
    915 
    916     if (rv && (rv->dt.flags & CINT_DATATYPE_F_ATOMIC) &&
    917         (ap = rv->dt.basetype.ap) &&
    918         (ap->flags & CINT_ATOMIC_TYPE_F_INT)) {
    919 
    920         ret = cint_long_value(rv);
    921 
    922     } else {
    923 
    924         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    925                   (BSL_META("ERROR -- CINT function \"%s\" taking no arguments and returning int must exist (return 0 = dump; !0 = filter out)\n"), cint_filter_fn));
    926         /*
    927          * let's not let user-defined CINT function errors prevent further
    928          * processing by cint infrastructure which we are using here.
    929          */
    930         cint_errno = CINT_E_NONE;
    931     }
    932 
    933     return ret;
    934 }
    935 
    936 static void
    937 _cint_logger_log_function_arguments (cint_logger_thread_data_t *tdata,
    938                                      cint_logger_call_ctxt_t *call_ctxt,
    939                                      cint_logger_api_params_t *ctxt,
    940                                      void *arg_ptrs[])
    941 {
    942     void *prev_scope = NULL;
    943     const char *fn;
    944     int filter;
    945     int recsz = 10240;
    946     char rec[recsz];
    947     cint_variable_t *vcall_ctxt = NULL, *vr = NULL;
    948     cint_logger_call_ctxt_t *orig_call_ctxt = NULL;
    949     int *orig_r = NULL;
    950     cint_parameter_desc_t call_ctxt_pds = { "cint_logger_call_ctxt_t", NULL, 0, 0 };
    951     cint_datatype_t dt;
    952 
    953     fn = ctxt->fn;
    954 
    955     if (cint_logger_cfg.user_filter_cb ||
    956         cint_logger_cfg.cint_filter_fn ||
    957         cint_logger_cfg.mode == cintLoggerModeReplay) {
    958 
    959         CINT_VARIABLES_LOCK;
    960 
    961        /*
    962         * when replaying configuration we want to use the call_ctxt declared from
    963         * original logs. 
    964         */
    965         if (cint_logger_cfg.mode == cintLoggerModeReplay) {
    966 
    967             vcall_ctxt = cint_variable_find("this", 1);
    968             if (!vcall_ctxt ||
    969                 (cint_datatype_find(call_ctxt_pds.basetype, &dt) != CINT_E_NONE) || 
    970                 (cint_type_check(&vcall_ctxt->dt, &dt) == 0)) {
    971 
    972                 LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    973                           (BSL_META("Failed to find variable \"this\" of type \"cint_logger_call_ctxt_t\" in replay mode\n")));
    974             } else {
    975                 orig_call_ctxt = vcall_ctxt->data;
    976             }
    977 
    978             /*
    979              * we expect to find a named return value variable if replaying a
    980              * post-dispatch call. If it is available, load its value into the
    981              * current rv so that it will be available to the filter function.
    982              */
    983             vr = cint_variable_find("r", 1);
    984             if (!vr ||
    985                 (cint_datatype_find(ctxt->params[0].basetype, &dt) != CINT_E_NONE) || 
    986                 (cint_type_check(&vr->dt, &dt) == 0)) {
    987 
    988                 if (orig_call_ctxt && (orig_call_ctxt->flags & CINT_PARAM_OUT)) {
    989                     LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
    990                               (BSL_META("Failed to find variable \"r\" of type \"%s\" in replay mode\n"), ctxt->params[0].basetype));
    991                 }
    992             } else {
    993                 orig_r = vr->data;
    994             }
    995         }
    996 
    997         /*
    998          * Switch temporarily to global scope and a new local scope under it.
    999          * Inject API parameters and call_ctxt as named variables. Then invoke
   1000          * the filter function.
   1001          */
   1002         prev_scope = cint_variable_scope_global_set(fn);
   1003         cint_variable_lscope_push(fn);
   1004 
   1005         _cint_logger_inject_variables(tdata, call_ctxt, orig_call_ctxt, orig_r, ctxt, arg_ptrs);
   1006 
   1007         filter = ((cint_logger_cfg.user_filter_cb &&   cint_logger_cfg.user_filter_cb(tdata, call_ctxt, ctxt, arg_ptrs)) ||
   1008                   (cint_logger_cfg.cint_filter_fn && _cint_logger_run_filter_function(tdata, call_ctxt, ctxt, arg_ptrs)));
   1009 
   1010         cint_variable_lscope_pop(fn);
   1011         cint_variable_scope_set(fn, prev_scope);
   1012 
   1013         CINT_VARIABLES_UNLOCK;
   1014 
   1015         if (filter) {
   1016             return; 
   1017         }
   1018 
   1019     }
   1020 
   1021     /*
   1022      * When replaying CINT, log the original call_ctxt if it is available
   1023      * instead of the current call_ctxt
   1024      */
   1025     if (orig_call_ctxt && (cint_logger_cfg.mode == cintLoggerModeReplay)) {
   1026         orig_call_ctxt->flags = call_ctxt->flags;
   1027         call_ctxt = orig_call_ctxt;
   1028     }
   1029 
   1030     _cint_logger_copy_function_arguments(tdata, call_ctxt, ctxt, arg_ptrs, rec, &recsz);
   1031 
   1032     _cint_logger_log_arguments_buffer(call_ctxt, ctxt, rec, recsz);
   1033 
   1034 }
   1035 
   1036 static void
   1037 _cint_logger_cache_function_arguments (cint_logger_thread_data_t *tdata,
   1038                                        cint_logger_call_ctxt_t *call_ctxt,
   1039                                        cint_logger_api_params_t *ctxt,
   1040                                        void *arg_ptrs[])
   1041 {
   1042     int recsz = 10240;
   1043     char rec[recsz];
   1044 
   1045     _cint_logger_copy_function_arguments(tdata, call_ctxt, ctxt, arg_ptrs, rec, &recsz);
   1046 
   1047     /*_cint_logger_log_arguments_buffer(call_ctxt, rec, recsz);*/
   1048 }
   1049 
   1050 void
   1051 cint_log_function_arguments (const char *fn, void **api_params, unsigned int flags, int call_id, void *arg_ptrs[], int *skip_dispatch)
   1052 {
   1053     cint_parameter_desc_t *params, *ppdt;
   1054     cint_datatype_t dt;
   1055     cint_function_t *func;
   1056     cint_logger_thread_data_t *tdata;
   1057     cint_logger_api_params_t *ctxt;
   1058     int i, nargs, is_basetype_arr, is_charptr, is_basetype_void;
   1059     cint_logger_call_ctxt_t call_ctxt;
   1060 
   1061     if (!fn || !arg_ptrs || !api_params) {
   1062 
   1063         return;
   1064     }
   1065 
   1066     tdata = cint_logger_thread_specific();
   1067 
   1068     CINT_LOGGER_LOCK;
   1069 
   1070     (*tdata).logger_is_active = 1;
   1071 
   1072     if (!(ctxt = *api_params)) {
   1073         ctxt = CINT_MALLOC(sizeof(*ctxt));
   1074         if (!ctxt) {
   1075             LOG_FATAL(BSL_LS_APPL_CINTAPILOGGER,
   1076                       (BSL_META("FATAL ERROR -- malloc ctxt failed for function %s\n"), fn));
   1077             goto exit;
   1078         }
   1079         CINT_LOGGER_INIT_API_PARAMS_T(ctxt);
   1080 
   1081         ctxt->fn = CINT_STRDUP(fn);
   1082         if (cint_logger_cfg.ctxt_head) {
   1083             cint_logger_cfg.ctxt_head->prev = ctxt;
   1084         }
   1085         ctxt->next = cint_logger_cfg.ctxt_head;
   1086         cint_logger_cfg.ctxt_head = ctxt;
   1087 
   1088         *api_params = ctxt;
   1089     }
   1090 
   1091     if (!cint_logger_cfg.enabled || !tdata || (*tdata).disabled) {
   1092 
   1093         goto exit;
   1094     }
   1095 
   1096     cmd_cint_initialize();
   1097 
   1098     if (!(params = ctxt->params) &&
   1099         (cint_datatype_find(fn, &dt) == CINT_E_NONE) &&
   1100         (dt.flags & CINT_DATATYPE_F_FUNC)) {
   1101 
   1102         func = dt.basetype.p;
   1103         params = func->params;
   1104         if (!params) {
   1105             LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
   1106                       (BSL_META("FATAL ERROR -- no arguments table for function %s\n"), fn));
   1107             goto exit;
   1108         }
   1109 
   1110         ctxt->params = params;
   1111         nargs = ctxt->nargs = cint_parameter_count(params);
   1112         if (nargs > (CINT_CONFIG_MAX_FPARAMS+1)) {
   1113             LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
   1114                       (BSL_META("FATAL ERROR -- %s has more than max %d arguments (%d)\n"), fn, CINT_CONFIG_MAX_FPARAMS, nargs));
   1115             goto exit;
   1116         }
   1117 
   1118         for (i = 0, ppdt = params; (i < nargs) && ppdt->name; i++, ppdt++) {
   1119 
   1120             CINT_MEMSET(&dt, 0, sizeof(dt));
   1121             if (cint_datatype_find(ppdt->basetype, &dt) != CINT_E_NONE) {
   1122                 LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
   1123                           (BSL_META("FATAL ERROR -- %s param %d has unknown basetype %s\n"), fn, i, ppdt->basetype));
   1124                 goto exit;
   1125             }
   1126 
   1127             is_basetype_arr  = (dt.desc.num_dimensions > 0);
   1128             is_charptr       = (ppdt->pcount && !CINT_STRCMP(ppdt->basetype, "char"));
   1129             is_basetype_void = !CINT_STRCMP(ppdt->basetype, "void");
   1130 
   1131             SHR_BITWRITE(ctxt->is_basetype_arr, i, is_basetype_arr);
   1132             SHR_BITWRITE(ctxt->is_charptr,      i, is_charptr);
   1133 
   1134             ctxt->basetype_size[i] = (is_basetype_void) ? 0 : cint_datatype_size(&dt);
   1135 
   1136         }
   1137     }
   1138 
   1139     if (!params) {
   1140         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
   1141                   (BSL_META("FATAL ERROR -- no arguments table for function %s\n"), fn));
   1142         goto exit;
   1143     }
   1144 
   1145     nargs = ctxt->nargs;
   1146     if (nargs > (CINT_CONFIG_MAX_FPARAMS+1)) {
   1147         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
   1148                   (BSL_META("FATAL ERROR -- %s has more than max %d arguments (%d)\n"), fn, CINT_CONFIG_MAX_FPARAMS, nargs));
   1149         goto exit;
   1150     }
   1151 
   1152     if ((flags & CINT_PARAM_IDX) == CINT_PARAM_IDX) {
   1153         goto exit;
   1154     }
   1155 
   1156     call_ctxt.api = ctxt->fn;
   1157     call_ctxt.flags = flags;
   1158     call_ctxt.caller_tid = sal_thread_self();
   1159     call_ctxt.caller_tname = NULL;
   1160     call_ctxt.caller_file = (*tdata).caller_file;
   1161     call_ctxt.caller_line = (*tdata).caller_line;
   1162     call_ctxt.caller_function = (*tdata).caller_func;
   1163     call_ctxt.skip_dispatch = skip_dispatch;
   1164     call_ctxt.call_id = call_id;
   1165 
   1166     switch (cint_logger_cfg.mode) {
   1167     case cintLoggerModeLog:
   1168     case cintLoggerModeReplay:
   1169         _cint_logger_log_function_arguments(tdata, &call_ctxt, ctxt, arg_ptrs);
   1170         break;
   1171     case cintLoggerModeCache:
   1172         _cint_logger_cache_function_arguments(tdata, &call_ctxt, ctxt, arg_ptrs);
   1173         break;
   1174     default:
   1175         LOG_ERROR(BSL_LS_APPL_CINTAPILOGGER,
   1176                   (BSL_META("ERROR -- invalid operating mode %d\n"), cint_logger_cfg.mode));
   1177         break;
   1178     }
   1179 
   1180 exit:
   1181 
   1182     (*tdata).logger_is_active = 0;
   1183 
   1184     CINT_LOGGER_UNLOCK;
   1185 
   1186 }
   1187 
   1188 /***********************************************************************************/
   1189 /*                                                                                 */
   1190 /* Handler for the CintApiLogging shell command                                    */
   1191 /*                                                                                 */
   1192 /***********************************************************************************/
   1193 
   1194 char cint_logger_usage[] = "\
   1195 CintApiLogging          \n\
   1196     ENable=[0/1]        \n\
   1197     Mode=[1/2/3]        \n\
   1198     Source=<number>     \n\
   1199     Layer=<number>      \n\
   1200     FunctioN=<string>   \n\
   1201     File=<string>       \n\
   1202     BaseIndent=<number> \n\
   1203 ";
   1204 
   1205 cmd_result_t
   1206 cint_logger_cmd (int unit, args_t *a)
   1207 {
   1208     cint_logger_global_cfg_data_t new_cfg;
   1209     parse_table_t pt;
   1210     cint_parameter_desc_t cfg_pds = { "cint_logger_global_cfg_data_t", "new_cfg", 0, 0 };
   1211     char *func = NULL, *file = NULL;
   1212 
   1213     cmd_cint_initialize();
   1214 
   1215     if (!ARG_CNT(a)) {
   1216         cli_out("\nCurrent configuration:\n\n");
   1217         cint_variable_print(vcint_logger_cfg, 4, NULL);
   1218         return CMD_OK;
   1219     }
   1220 
   1221     new_cfg = cint_logger_cfg;
   1222 
   1223     parse_table_init(unit, &pt);
   1224     parse_table_add(&pt, "Enable"     , PQ_DFL | PQ_INT , NULL                    , &new_cfg.enabled        , NULL);
   1225     parse_table_add(&pt, "Mode"       , PQ_DFL | PQ_INT , NULL                    , &new_cfg.mode           , NULL);
   1226     parse_table_add(&pt, "Source"     , PQ_DFL | PQ_INT , NULL                    , &new_cfg.logSource      , NULL);
   1227     parse_table_add(&pt, "Layer"      , PQ_DFL | PQ_INT , NULL                    , &new_cfg.logLayer       , NULL);
   1228     parse_table_add(&pt, "FunctioN"   , PQ_STRING       , new_cfg.cint_filter_fn  , &func                   , NULL);
   1229     parse_table_add(&pt, "File"       , PQ_STRING       , new_cfg.logfile         , &file                   , NULL);
   1230     parse_table_add(&pt, "BaseIndent" , PQ_DFL | PQ_INT , NULL                    , &new_cfg.base_indent    , NULL);
   1231 
   1232     if (parse_arg_eq(a, &pt) <= 0) {
   1233         cli_out("Error: invalid option \"%s\"\n", ARG_CUR(a));
   1234         parse_arg_eq_done(&pt);
   1235         return CMD_USAGE;
   1236     }
   1237 
   1238     parse_eq_format(&pt);
   1239 
   1240     /*
   1241      * Curate the cint_filter_fn and logfile arguments passed by the user.
   1242      * Option must be set if it is not the empty string, not the case
   1243      * insensitive string "null", or same as the existing value. Else it must
   1244      * be set to NULL.
   1245      */
   1246     if (func && CINT_STRNCMP(func, "", 100) && CINT_STRNCASECMP(func, "NULL", 100)) {
   1247 
   1248         if (new_cfg.cint_filter_fn && CINT_STRNCMP(func, new_cfg.cint_filter_fn, 100)) {
   1249             CINT_FREE(new_cfg.cint_filter_fn);
   1250         }
   1251         new_cfg.cint_filter_fn = CINT_STRDUP(func);
   1252     } else {
   1253 
   1254         if (new_cfg.cint_filter_fn) {
   1255             CINT_FREE(new_cfg.cint_filter_fn);
   1256         }
   1257         new_cfg.cint_filter_fn = NULL;
   1258     }
   1259 
   1260     if (file && CINT_STRNCMP(file, "", 100) && CINT_STRNCASECMP(file, "NULL", 100)) {
   1261 
   1262         if (new_cfg.logfile && CINT_STRNCMP(file, new_cfg.logfile, 100)) {
   1263             CINT_FREE(new_cfg.logfile);
   1264         }
   1265         new_cfg.logfile = CINT_STRDUP(file);
   1266     } else {
   1267 
   1268         if (new_cfg.logfile) {
   1269             CINT_FREE(new_cfg.logfile);
   1270         }
   1271         new_cfg.logfile = NULL;
   1272     }
   1273 
   1274     parse_arg_eq_done(&pt);
   1275 
   1276     cli_out("\nDesired configuration: (actual may differ)\n\n");
   1277     _cint_logger_log_variable(&cfg_pds, "", &new_cfg, 4);
   1278 
   1279     /*
   1280      * validate all the options before applying them
   1281      */
   1282     if ((new_cfg.enabled != 0) && (new_cfg.enabled != 1)) {
   1283 
   1284         cli_out("Error: Enable %d is invalid\n", new_cfg.enabled);
   1285         return CMD_USAGE;
   1286     }
   1287 
   1288     if ((new_cfg.mode != cintLoggerModeLog) && 
   1289         (new_cfg.mode != cintLoggerModeReplay) &&
   1290         (new_cfg.mode != cintLoggerModeCache)) {
   1291 
   1292         cli_out("Error: Mode %d is invalid\n", new_cfg.mode);
   1293         return CMD_USAGE;
   1294     }
   1295 
   1296     if ((new_cfg.logLayer < 0) || (new_cfg.logLayer >= bslLayerCount)) {
   1297 
   1298         cli_out("Error: logLayer %d is invalid\n", new_cfg.logLayer);
   1299         return CMD_USAGE;
   1300     }
   1301 
   1302     if ((new_cfg.logSource < 0) || (new_cfg.logSource >= bslSourceCount)) {
   1303 
   1304         cli_out("Error: logSource %d is invalid\n", new_cfg.logSource);
   1305         return CMD_USAGE;
   1306     }
   1307 
   1308     CINT_LOGGER_LOCK;
   1309 
   1310     if (new_cfg.enabled) {
   1311 
   1312         /*
   1313          * if a file is open, close it if either there's no name assigned for
   1314          * it, or a new file name has been provided by the user
   1315          */
   1316         if (cint_logger_cfg.logfile_fp &&
   1317             (!cint_logger_cfg.logfile ||
   1318              (new_cfg.logfile && CINT_STRNCMP(cint_logger_cfg.logfile, new_cfg.logfile, 1024)))) {
   1319 
   1320             CINT_FCLOSE(cint_logger_cfg.logfile_fp);
   1321             cint_logger_cfg.logfile_fp = new_cfg.logfile_fp = NULL;
   1322         }
   1323 
   1324         if (!cint_logger_cfg.logfile_fp && new_cfg.logfile) {
   1325 
   1326             new_cfg.logfile_fp = cint_logger_cfg.logfile_fp = CINT_FOPEN(new_cfg.logfile, "a");
   1327             if (new_cfg.logfile_fp) {
   1328                 new_cfg.log_to_file = 1;
   1329             }
   1330         }
   1331 
   1332         /*
   1333          * Logging requires verbose severity at logLayer and Source
   1334          */
   1335         bslenable_set(cint_logger_cfg.logLayer, cint_logger_cfg.logSource, bslSeverityVerbose);
   1336         cli_out("Debug %s %s %s - was configured\n",
   1337                 bsl_layer2str(cint_logger_cfg.logLayer),
   1338                 bsl_source2str(cint_logger_cfg.logSource),
   1339                 bsl_severity2str(bslSeverityVerbose));
   1340 
   1341     } else {
   1342 
   1343         if (cint_logger_cfg.logfile_fp) {
   1344 
   1345             CINT_FCLOSE(cint_logger_cfg.logfile_fp);
   1346             cint_logger_cfg.logfile_fp = new_cfg.logfile_fp = NULL;
   1347         }
   1348 
   1349         new_cfg.log_to_file = 0;
   1350     }
   1351 
   1352     cint_logger_cfg.enabled        = new_cfg.enabled;
   1353     cint_logger_cfg.mode           = new_cfg.mode;
   1354     cint_logger_cfg.logLayer       = new_cfg.logLayer;
   1355     cint_logger_cfg.logSource      = new_cfg.logSource;
   1356     cint_logger_cfg.cint_filter_fn = new_cfg.cint_filter_fn;
   1357     cint_logger_cfg.logfile        = new_cfg.logfile;
   1358     cint_logger_cfg.logfile_fp     = new_cfg.logfile_fp;
   1359     cint_logger_cfg.log_to_file    = new_cfg.log_to_file;
   1360 
   1361     CINT_LOGGER_UNLOCK;
   1362 
   1363     return CMD_OK;
   1364 }
   1365 
   1366 static void
   1367 _cint_logger_tls_destructor (void *tdata)
   1368 {
   1369     CINT_FREE(tdata);
   1370 }
   1371 
   1372 static void
   1373 _cint_logger_init ()
   1374 {
   1375 
   1376     if (!cint_logger_cfg.mutex) {
   1377 
   1378         SAL_GLOBAL_LOCK;
   1379 
   1380         if (!cint_logger_cfg.mutex) {
   1381 
   1382             cint_logger_cfg.mutex = sal_mutex_create("cint_logger_mutex");
   1383             if (!cint_logger_cfg.mutex) {
   1384                 LOG_FATAL(BSL_LS_APPL_CINTAPILOGGER,
   1385                           (BSL_META("FATAL ERROR -- failed to allocate cint_logger_mutex\n")));
   1386             }
   1387         }
   1388 
   1389         SAL_GLOBAL_UNLOCK;
   1390     }
   1391 
   1392     /*
   1393      * Since there is no pthread_once() equivalent SAL API use the Global mutex
   1394      */
   1395     if (!cint_logger_cfg.tls_key) {
   1396 
   1397         SAL_GLOBAL_LOCK;
   1398 
   1399         if (!cint_logger_cfg.tls_key) {
   1400 
   1401             cint_logger_cfg.tls_key = sal_tls_key_create(_cint_logger_tls_destructor);
   1402             if (!cint_logger_cfg.tls_key) {
   1403                 LOG_FATAL(BSL_LS_APPL_CINTAPILOGGER,
   1404                           (BSL_META("FATAL ERROR -- failed to allocate cint_logger tls_key\n")));
   1405             }
   1406         }
   1407 
   1408         SAL_GLOBAL_UNLOCK;
   1409     }
   1410 
   1411 }
   1412 
   1413 /***********************************************************************************/
   1414 /*                                                                                 */
   1415 /* Call all the inits                                                              */
   1416 /*                                                                                 */
   1417 /***********************************************************************************/
   1418 
   1419 void
   1420 cint_logger_cint_init ()
   1421 {
   1422     static int cint_logger_cint_inited = 0;
   1423 
   1424     if (cint_logger_cint_inited) {
   1425         return;
   1426     }
   1427 
   1428     _cint_logger_bsl_init();
   1429 
   1430     _cint_logger_cint_init();
   1431     cint_interpreter_event_register(_cint_logger_cint_interp_listener, NULL);
   1432 
   1433     _cint_logger_init();
   1434 
   1435     cint_logger_cint_inited = 1;
   1436 }
   1437 
   1438 void
   1439 cint_logger_set_caller_context (const char *f, int l, const char *F)
   1440 {
   1441     cint_logger_thread_data_t *tdata;
   1442 
   1443     tdata = cint_logger_thread_specific();
   1444 
   1445     (*tdata).caller_file = f;
   1446     (*tdata).caller_line = l;
   1447     (*tdata).caller_func = F;
   1448 }
   1449 
   1450 void*
   1451 cint_logger_thread_specific ()
   1452 {
   1453     cint_logger_thread_data_t *tdata;
   1454 
   1455     _cint_logger_init();
   1456 
   1457     tdata = sal_tls_key_get(cint_logger_cfg.tls_key);
   1458     if (!tdata) {
   1459         tdata = CINT_MALLOC(sizeof(*tdata));
   1460         if (!tdata) {
   1461             LOG_FATAL(BSL_LS_APPL_CINTAPILOGGER,
   1462                       (BSL_META("FATAL ERROR -- malloc tdata failed\n")));
   1463             return NULL;
   1464         }
   1465 
   1466         CINT_MEMSET(tdata, 0, sizeof(*tdata));
   1467         sal_tls_key_set(cint_logger_cfg.tls_key, tdata);
   1468     }
   1469 
   1470     return tdata;
   1471 }
   1472 
   1473 
   1474 #else
   1475 extern int cint_logger_c_not_empty;
   1476 #endif