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 = ¶ms[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 = ¶ms[i]; 824 ppdt->name; 825 i++, src = arg_ptrs[i], ppdt = ¶ms[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 ¶ms[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