1 /****************************************************************************** 2 * * 3 * N O T I C E * 4 * * 5 * Copyright Abandoned, 1987, Fred Fish * 6 * * 7 * * 8 * This previously copyrighted work has been placed into the public * 9 * domain by the author and may be freely used for any purpose, * 10 * private or commercial. * 11 * * 12 * Because of the number of inquiries I was receiving about the use * 13 * of this product in commercially developed works I have decided to * 14 * simply make it public domain to further its unrestricted use. I * 15 * specifically would be most happy to see this material become a * 16 * part of the standard Unix distributions by AT&T and the Berkeley * 17 * Computer Science Research Group, and a standard part of the GNU * 18 * system from the Free Software Foundation. * 19 * * 20 * I would appreciate it, as a courtesy, if this notice is left in * 21 * all copies and derivative works. Thank you. * 22 * * 23 * The author makes no warranty of any kind with respect to this * 24 * product and explicitly disclaims any implied warranties of mer- * 25 * chantability or fitness for any particular purpose. * 26 * * 27 ****************************************************************************** 28 */ 29 30 /* 31 * FILE 32 * 33 * dbug.c runtime support routines for dbug package 34 * 35 * SCCS 36 * 37 * @(#)dbug.c 1.25 7/25/89 38 * 39 * DESCRIPTION 40 * 41 * These are the runtime support routines for the dbug package. 42 * The dbug package has two main components; the user include 43 * file containing various macro definitions, and the runtime 44 * support routines which are called from the macro expansions. 45 * 46 * Externally visible functions in the runtime support module 47 * use the naming convention pattern "_db_xx...xx_", thus 48 * they are unlikely to collide with user defined function names. 49 * 50 * AUTHOR(S) 51 * 52 * Fred Fish (base code) 53 * Enhanced Software Technologies, Tempe, AZ 54 * asuvax!mcdphx!estinc!fnf 55 * 56 * Michael Widenius: 57 * DBUG_DUMP - To dump a block of memory. 58 * PUSH_FLAG "O" - To be used insted of "o" if we 59 * want flushing after each write 60 * PUSH_FLAG "A" - as 'O', but we will append to the out file instead 61 * of creating a new one. 62 * Check of malloc on entry/exit (option "S") 63 * 64 * Sergei Golubchik: 65 * DBUG_EXECUTE_IF 66 * incremental mode (-#+t:-d,info ...) 67 * DBUG_SET, _db_explain_ 68 * thread-local settings 69 * negative lists (-#-d,info => everything but "info") 70 * 71 * function/ syntax 72 * (the logic is - think of a call stack as of a path. 73 * "function" means only this function, "function/" means the hierarchy. 74 * in the future, filters like function1/function2 could be supported. 75 * following this logic glob(7) wildcards are supported.) 76 * 77 */ 78 79 /* 80 We can't have SAFE_MUTEX defined here as this will cause recursion 81 in pthread_mutex_lock 82 */ 83 84 #include <my_global.h> 85 #undef SAFE_MUTEX 86 #include <m_string.h> 87 #include <errno.h> 88 89 #ifndef DBUG_OFF 90 91 #ifdef HAVE_FNMATCH_H 92 #include <fnmatch.h> 93 #else 94 #define fnmatch(A,B,C) strcmp(A,B) 95 #endif 96 97 #if defined(__WIN__) 98 #include <process.h> 99 #endif 100 101 /* 102 * Manifest constants which may be "tuned" if desired. 103 */ 104 105 #define PRINTBUF 1024 /* Print buffer size */ 106 #define INDENT 2 /* Indentation per trace level */ 107 #define MAXDEPTH 200 /* Maximum trace depth default */ 108 109 /* 110 * The following flags are used to determine which 111 * capabilities the user has enabled with the settings 112 * push macro. 113 * 114 * TRACE_ON is also used in _db_stack_frame_->level 115 * (until we add flags to _db_stack_frame_, increasing it by 4 bytes) 116 */ 117 118 #define DEBUG_ON (1U << 1) /* Debug enabled */ 119 #define FILE_ON (1U << 2) /* File name print enabled */ 120 #define LINE_ON (1U << 3) /* Line number print enabled */ 121 #define DEPTH_ON (1U << 4) /* Function nest level print enabled */ 122 #define PROCESS_ON (1U << 5) /* Process name print enabled */ 123 #define NUMBER_ON (1U << 6) /* Number each line of output */ 124 #define PID_ON (1U << 8) /* Identify each line with process id */ 125 #define TIMESTAMP_ON (1U << 9) /* timestamp every line of output */ 126 #define FLUSH_ON_WRITE (1U << 10) /* Flush on every write */ 127 #define OPEN_APPEND (1U << 11) /* Open for append */ 128 #define SANITY_CHECK_ON (1U << 12) /* Check memory on every DBUG_ENTER/RETURN */ 129 #define TRACE_ON (1U << 31) /* Trace enabled. MUST be the highest bit!*/ 130 131 #define TRACING (cs->stack->flags & TRACE_ON) 132 #define DEBUGGING (cs->stack->flags & DEBUG_ON) 133 134 /* 135 * Typedefs to make things more obvious. 136 */ 137 138 #define BOOLEAN my_bool 139 140 /* 141 * Externally supplied functions. 142 */ 143 144 #ifndef HAVE_PERROR 145 static void perror(char *s) 146 { 147 if (s && *s != '\0') 148 (void) fprintf(stderr, "%s: ", s); 149 (void) fprintf(stderr, "<unknown system error>\n"); 150 } 151 #endif 152 153 /* 154 * The user may specify a list of functions to trace or 155 * debug. These lists are kept in a linear linked list, 156 * a very simple implementation. 157 */ 158 159 struct link { 160 struct link *next_link; /* Pointer to the next link */ 161 char flags; 162 char str[1]; /* Pointer to link's contents */ 163 }; 164 165 /* flags for struct link and return flags of InList */ 166 #define SUBDIR 1 /* this MUST be 1 */ 167 #define INCLUDE 2 168 #define EXCLUDE 4 169 /* this is not a struct link flag, but only a return flags of InList */ 170 #define MATCHED 65536 171 #define NOT_MATCHED 0 172 173 /* 174 * Debugging settings can be shared between threads. 175 * But FILE* streams cannot normally be shared - what if 176 * one thread closes a stream, while another thread still uses it? 177 * As a workaround, we have shared FILE pointers with reference counters 178 */ 179 typedef struct { 180 FILE *file; 181 uint used; 182 } sFILE; 183 184 sFILE shared_stdout = { 0, 1 << 30 }, *sstdout = &shared_stdout; 185 sFILE shared_stderr = { 0, 1 << 30 }, *sstderr = &shared_stderr; 186 187 /* 188 * Debugging settings can be pushed or popped off of a 189 * stack which is implemented as a linked list. Note 190 * that the head of the list is the current settings and the 191 * stack is pushed by adding a new settings to the head of the 192 * list or popped by removing the first link. 193 * 194 * Note: if out_file is NULL, the other fields are not initialized at all! 195 */ 196 197 struct settings { 198 uint flags; /* Current settings flags */ 199 uint maxdepth; /* Current maximum trace depth */ 200 uint delay; /* Delay after each output line */ 201 uint sub_level; /* Sub this from code_state->level */ 202 sFILE *out_file; /* Current output stream */ 203 char name[FN_REFLEN]; /* Name of output file */ 204 struct link *functions; /* List of functions */ 205 struct link *keywords; /* List of debug keywords */ 206 struct link *processes; /* List of process names */ 207 struct settings *next; /* Next settings in the list */ 208 }; 209 210 #define is_shared(S, V) ((S)->next && (S)->next->V == (S)->V) 211 212 /* 213 * Local variables not seen by user. 214 */ 215 216 217 static BOOLEAN init_done= FALSE; /* Set to TRUE when initialization done */ 218 static struct settings init_settings; 219 static const char *db_process= 0;/* Pointer to process name; argv[0] */ 220 my_bool _dbug_on_= TRUE; /* FALSE if no debugging at all */ 221 222 typedef struct _db_code_state_ { 223 const char *process; /* Pointer to process name; usually argv[0] */ 224 const char *func; /* Name of current user function */ 225 const char *file; /* Name of current user file */ 226 struct _db_stack_frame_ *framep; /* Pointer to current frame */ 227 struct settings *stack; /* debugging settings */ 228 int lineno; /* Current debugger output line number */ 229 uint level; /* Current function nesting level */ 230 231 /* 232 * The following variables are used to hold the state information 233 * between the call to _db_pargs_() and _db_doprnt_(), during 234 * expansion of the DBUG_PRINT macro. This is the only macro 235 * that currently uses these variables. 236 * 237 * These variables are currently used only by _db_pargs_() and 238 * _db_doprnt_(). 239 */ 240 241 uint u_line; /* User source code line number */ 242 int locked; /* If locked with _db_lock_file_ */ 243 const char *u_keyword; /* Keyword for current macro */ 244 } CODE_STATE; 245 246 /* 247 The test below is so we could call functions with DBUG_ENTER before 248 my_thread_init(). 249 */ 250 #define get_code_state_if_not_set_or_return if (!cs && !((cs=code_state()))) return 251 #define get_code_state_or_return if (!((cs=code_state()))) return 252 253 /* Handling lists */ 254 #define ListAdd(A,B,C) ListAddDel(A,B,C,INCLUDE) 255 #define ListDel(A,B,C) ListAddDel(A,B,C,EXCLUDE) 256 static struct link *ListAddDel(struct link *, const char *, const char *, int); 257 static struct link *ListCopy(struct link *); 258 static int InList(struct link *linkp,const char *cp,int exact_match); 259 static uint ListFlags(struct link *linkp); 260 static void FreeList(struct link *linkp); 261 262 /* OpenClose debug output stream */ 263 static void DBUGOpenFile(CODE_STATE *,const char *, const char *, int); 264 static void DBUGCloseFile(CODE_STATE *cs, sFILE *new_value); 265 /* Push current debug settings */ 266 static void PushState(CODE_STATE *cs); 267 /* Free memory associated with debug state. */ 268 static void FreeState (CODE_STATE *cs, int free_state); 269 /* Test for tracing enabled */ 270 static int DoTrace(CODE_STATE *cs); 271 static int default_my_dbug_sanity(void); 272 273 int (*dbug_sanity)(void)= default_my_dbug_sanity; 274 275 276 /* 277 return values of DoTrace. 278 Can also be used as bitmask: ret & DO_TRACE 279 */ 280 #define DO_TRACE 1 281 #define DONT_TRACE 2 282 #define ENABLE_TRACE 3 283 #define DISABLE_TRACE 4 284 285 /* Test to see if file is writable */ 286 #if defined(HAVE_ACCESS) 287 static BOOLEAN Writable(const char *pathname); 288 #endif 289 290 static void DoPrefix(CODE_STATE *cs, uint line); 291 292 static char *DbugMalloc(size_t size); 293 static const char *BaseName(const char *pathname); 294 static void Indent(CODE_STATE *cs, int indent); 295 static void DbugFlush(CODE_STATE *); 296 static void DbugExit(const char *why); 297 static const char *DbugStrTok(const char *s); 298 static void DbugVfprintf(FILE *stream, const char* format, va_list args); 299 300 /* 301 * Miscellaneous printf format strings. 302 */ 303 304 #define ERR_MISSING_RETURN "missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n" 305 #define ERR_OPEN "%s: can't open debug output stream \"%s\": " 306 #define ERR_CLOSE "%s: can't close debug file: " 307 #define ERR_ABORT "%s: debugger aborting because %s\n" 308 309 /* 310 * Macros and defines for testing file accessibility under UNIX and MSDOS. 311 */ 312 313 #undef EXISTS 314 #if !defined(HAVE_ACCESS) 315 #define EXISTS(pathname) (FALSE) /* Assume no existence */ 316 #define Writable(name) (TRUE) 317 #else 318 #define EXISTS(pathname) (access(pathname, F_OK) == 0) 319 #define WRITABLE(pathname) (access(pathname, W_OK) == 0) 320 #endif 321 322 /* 323 ** Macros to allow dbugging with threads 324 */ 325 326 #include <my_pthread.h> 327 /* 328 ** Protects writing to all file descriptors, init_settings.keywords 329 ** pointer and it's pointee - a linked list with keywords. 330 */ 331 static pthread_mutex_t THR_LOCK_dbug; 332 333 static void LockMutex(CODE_STATE *cs) 334 { 335 if (!cs->locked) 336 pthread_mutex_lock(&THR_LOCK_dbug); 337 cs->locked++; 338 } 339 static void UnlockMutex(CODE_STATE *cs) 340 { 341 --cs->locked; 342 assert(cs->locked >= 0); 343 if (cs->locked == 0) 344 pthread_mutex_unlock(&THR_LOCK_dbug); 345 } 346 static void LockIfInitSettings(CODE_STATE *cs) 347 { 348 if (cs->stack == &init_settings) 349 LockMutex(cs); 350 } 351 static void UnlockIfInitSettings(CODE_STATE *cs) 352 { 353 if (cs->stack == &init_settings) 354 UnlockMutex(cs); 355 } 356 357 static CODE_STATE *code_state(void) 358 { 359 CODE_STATE *cs, **cs_ptr; 360 361 /* 362 _dbug_on_ is reset if we don't plan to use any debug commands at all and 363 we want to run on maximum speed 364 */ 365 if (!_dbug_on_) 366 return 0; 367 368 if (!init_done) 369 { 370 init_done=TRUE; 371 sstdout->file= stdout; 372 sstderr->file= stderr; 373 pthread_mutex_init(&THR_LOCK_dbug, NULL); 374 bzero(&init_settings, sizeof(init_settings)); 375 init_settings.out_file= sstderr; 376 init_settings.flags=OPEN_APPEND; 377 } 378 379 if (!(cs_ptr= (CODE_STATE**) my_thread_var_dbug())) 380 return 0; /* Thread not initialised */ 381 if (!(cs= *cs_ptr)) 382 { 383 cs=(CODE_STATE*) DbugMalloc(sizeof(*cs)); 384 bzero((uchar*) cs,sizeof(*cs)); 385 cs->process= db_process ? db_process : "dbug"; 386 cs->func= "?func"; 387 cs->file= "?file"; 388 cs->stack=&init_settings; 389 *cs_ptr= cs; 390 } 391 return cs; 392 } 393 394 void 395 dbug_swap_code_state(void **code_state_store) 396 { 397 CODE_STATE *cs, **cs_ptr; 398 399 if (!(cs_ptr= (CODE_STATE**) my_thread_var_dbug())) 400 return; 401 cs= *cs_ptr; 402 *cs_ptr= *code_state_store; 403 *code_state_store= cs; 404 } 405 406 void dbug_free_code_state(void **code_state_store) 407 { 408 if (*code_state_store) 409 { 410 free(*code_state_store); 411 *code_state_store= NULL; 412 } 413 } 414 415 /* 416 * Translate some calls among different systems. 417 */ 418 419 #ifdef HAVE_SLEEP 420 /* sleep() wants seconds */ 421 #define Delay(A) sleep(((uint) A)/10) 422 #else 423 #define Delay(A) (0) 424 #endif 425 426 /* 427 * FUNCTION 428 * 429 * _db_process_ give the name to the current process/thread 430 * 431 * SYNOPSIS 432 * 433 * VOID _process_(name) 434 * char *name; 435 * 436 */ 437 438 void _db_process_(const char *name) 439 { 440 CODE_STATE *cs; 441 442 if (!db_process) 443 db_process= name; 444 445 get_code_state_or_return; 446 cs->process= name; 447 } 448 449 /* 450 * FUNCTION 451 * 452 * DbugParse parse control string and set current debugger settings 453 * 454 * DESCRIPTION 455 * 456 * Given pointer to a debug control string in "control", 457 * parses the control string, and sets 458 * up a current debug settings. 459 * 460 * The debug control string is a sequence of colon separated fields 461 * as follows: 462 * 463 * [+]<field_1>:<field_2>:...:<field_N> 464 * 465 * Each field consists of a mandatory flag character followed by 466 * an optional "," and comma separated list of modifiers: 467 * 468 * [sign]flag[,modifier,modifier,...,modifier] 469 * 470 * See the manual for the list of supported signs, flags, and modifiers 471 * 472 * For convenience, any leading "-#" is stripped off. 473 * 474 * RETURN 475 * 1 - a list of functions ("f" flag) was possibly changed 476 * 0 - a list of functions was not changed 477 */ 478 479 static int DbugParse(CODE_STATE *cs, const char *control) 480 { 481 const char *end; 482 int rel, f_used=0; 483 struct settings *stack; 484 485 stack= cs->stack; 486 487 if (control[0] == '-' && control[1] == '#') 488 control+=2; 489 490 rel= control[0] == '+' || control[0] == '-'; 491 if ((!rel || (!stack->out_file && !stack->next))) 492 { 493 LockIfInitSettings(cs); 494 FreeState(cs, 0); 495 stack->flags= 0; 496 stack->delay= 0; 497 stack->maxdepth= 0; 498 stack->sub_level= 0; 499 stack->out_file= sstderr; 500 stack->functions= NULL; 501 stack->keywords= NULL; 502 stack->processes= NULL; 503 UnlockIfInitSettings(cs); 504 } 505 else if (!stack->out_file) 506 { 507 stack->flags= stack->next->flags; 508 stack->delay= stack->next->delay; 509 stack->maxdepth= stack->next->maxdepth; 510 stack->sub_level= stack->next->sub_level; 511 strcpy(stack->name, stack->next->name); 512 stack->out_file= stack->next->out_file; 513 stack->out_file->used++; 514 if (stack->next == &init_settings) 515 { 516 /* never share with the global parent - it can change under your feet */ 517 stack->functions= ListCopy(init_settings.functions); 518 LockMutex(cs); 519 stack->keywords= ListCopy(init_settings.keywords); 520 UnlockMutex(cs); 521 stack->processes= ListCopy(init_settings.processes); 522 } 523 else 524 { 525 stack->functions= stack->next->functions; 526 stack->keywords= stack->next->keywords; 527 stack->processes= stack->next->processes; 528 } 529 } 530 531 end= DbugStrTok(control); 532 while (control < end) 533 { 534 int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0; 535 if (sign) control++; 536 c= *control++; 537 if (*control == ',') 538 control++; 539 /* XXX when adding new cases here, don't forget _db_explain_ ! */ 540 switch (c) { 541 case 'd': 542 if (sign < 0 && control == end) 543 { 544 LockIfInitSettings(cs); 545 if (!is_shared(stack, keywords)) 546 FreeList(stack->keywords); 547 stack->keywords=NULL; 548 UnlockIfInitSettings(cs); 549 stack->flags &= ~DEBUG_ON; 550 break; 551 } 552 LockIfInitSettings(cs); 553 if (rel && is_shared(stack, keywords)) 554 stack->keywords= ListCopy(stack->keywords); 555 UnlockIfInitSettings(cs); 556 if (sign < 0) 557 { 558 if (DEBUGGING) 559 { 560 LockIfInitSettings(cs); 561 stack->keywords= ListDel(stack->keywords, control, end); 562 UnlockIfInitSettings(cs); 563 } 564 break; 565 } 566 LockIfInitSettings(cs); 567 stack->keywords= ListAdd(stack->keywords, control, end); 568 UnlockIfInitSettings(cs); 569 stack->flags |= DEBUG_ON; 570 break; 571 case 'D': 572 stack->delay= atoi(control); 573 break; 574 case 'f': 575 f_used= 1; 576 if (sign < 0 && control == end) 577 { 578 if (!is_shared(stack,functions)) 579 FreeList(stack->functions); 580 stack->functions=NULL; 581 break; 582 } 583 if (rel && is_shared(stack,functions)) 584 stack->functions= ListCopy(stack->functions); 585 if (sign < 0) 586 stack->functions= ListDel(stack->functions, control, end); 587 else 588 stack->functions= ListAdd(stack->functions, control, end); 589 break; 590 case 'F': 591 if (sign < 0) 592 stack->flags &= ~FILE_ON; 593 else 594 stack->flags |= FILE_ON; 595 break; 596 case 'i': 597 if (sign < 0) 598 stack->flags &= ~PID_ON; 599 else 600 stack->flags |= PID_ON; 601 break; 602 case 'L': 603 if (sign < 0) 604 stack->flags &= ~LINE_ON; 605 else 606 stack->flags |= LINE_ON; 607 break; 608 case 'n': 609 if (sign < 0) 610 stack->flags &= ~DEPTH_ON; 611 else 612 stack->flags |= DEPTH_ON; 613 break; 614 case 'N': 615 if (sign < 0) 616 stack->flags &= ~NUMBER_ON; 617 else 618 stack->flags |= NUMBER_ON; 619 break; 620 case 'A': 621 case 'O': 622 stack->flags |= FLUSH_ON_WRITE; 623 /* fall through */ 624 case 'a': 625 case 'o': 626 if (sign < 0) 627 { 628 DBUGCloseFile(cs, sstderr); 629 stack->flags &= ~FLUSH_ON_WRITE; 630 break; 631 } 632 if (c == 'a' || c == 'A') 633 stack->flags |= OPEN_APPEND; 634 else 635 stack->flags &= ~OPEN_APPEND; 636 if (control != end) 637 DBUGOpenFile(cs, control, end, stack->flags & OPEN_APPEND); 638 else 639 DBUGOpenFile(cs, "-",0,0); 640 break; 641 case 'p': 642 if (sign < 0 && control == end) 643 { 644 if (!is_shared(stack,processes)) 645 FreeList(stack->processes); 646 stack->processes=NULL; 647 break; 648 } 649 if (rel && is_shared(stack, processes)) 650 stack->processes= ListCopy(stack->processes); 651 if (sign < 0) 652 stack->processes= ListDel(stack->processes, control, end); 653 else 654 stack->processes= ListAdd(stack->processes, control, end); 655 break; 656 case 'P': 657 if (sign < 0) 658 stack->flags &= ~PROCESS_ON; 659 else 660 stack->flags |= PROCESS_ON; 661 break; 662 case 'r': 663 stack->sub_level= cs->level; 664 break; 665 case 't': 666 if (sign < 0) 667 { 668 if (control != end) 669 stack->maxdepth-= atoi(control); 670 else 671 stack->maxdepth= 0; 672 } 673 else 674 { 675 if (control != end) 676 stack->maxdepth+= atoi(control); 677 else 678 stack->maxdepth= MAXDEPTH; 679 } 680 if (stack->maxdepth > 0) 681 stack->flags |= TRACE_ON; 682 else 683 stack->flags &= ~TRACE_ON; 684 break; 685 case 'T': 686 if (sign < 0) 687 stack->flags &= ~TIMESTAMP_ON; 688 else 689 stack->flags |= TIMESTAMP_ON; 690 break; 691 case 'S': 692 if (sign < 0) 693 stack->flags &= ~SANITY_CHECK_ON; 694 else 695 stack->flags |= SANITY_CHECK_ON; 696 break; 697 } 698 if (!*end) 699 break; 700 control=end+1; 701 end= DbugStrTok(control); 702 } 703 return !rel || f_used; 704 } 705 706 #define framep_trace_flag(cs, frp) (frp ? \ 707 frp->level & TRACE_ON : \ 708 (ListFlags(cs->stack->functions) & INCLUDE) ? \ 709 0 : (uint)TRACE_ON) 710 711 static void FixTraceFlags_helper(CODE_STATE *cs, const char *func, 712 struct _db_stack_frame_ *framep) 713 { 714 if (framep->prev) 715 FixTraceFlags_helper(cs, framep->func, framep->prev); 716 717 cs->func= func; 718 cs->level= framep->level & ~TRACE_ON; 719 framep->level= cs->level | framep_trace_flag(cs, framep->prev); 720 /* 721 we don't set cs->framep correctly, even though DoTrace uses it. 722 It's ok, because cs->framep may only affect DO_TRACE/DONT_TRACE return 723 values, but we ignore them here anyway 724 */ 725 switch(DoTrace(cs)) { 726 case ENABLE_TRACE: 727 framep->level|= TRACE_ON; 728 break; 729 case DISABLE_TRACE: 730 framep->level&= ~TRACE_ON; 731 break; 732 } 733 } 734 735 #define fflags(cs) cs->stack->out_file ? ListFlags(cs->stack->functions) : TRACE_ON; 736 737 static void FixTraceFlags(uint old_fflags, CODE_STATE *cs) 738 { 739 const char *func; 740 uint new_fflags, traceon, level; 741 struct _db_stack_frame_ *framep; 742 743 /* 744 first (a.k.a. safety) check: 745 if we haven't started tracing yet, no call stack at all - we're safe. 746 */ 747 framep=cs->framep; 748 if (framep == 0) 749 return; 750 751 /* 752 Ok, the tracing has started, call stack isn't empty. 753 754 second check: does the new list have a SUBDIR rule ? 755 */ 756 new_fflags=fflags(cs); 757 if (new_fflags & SUBDIR) 758 goto yuck; 759 760 /* 761 Ok, new list doesn't use SUBDIR. 762 763 third check: we do NOT need to re-scan if 764 neither old nor new lists used SUBDIR flag and if a default behavior 765 (whether an unlisted function is traced) hasn't changed. 766 Default behavior depends on whether there're INCLUDE elements in the list. 767 */ 768 if (!(old_fflags & SUBDIR) && !((new_fflags^old_fflags) & INCLUDE)) 769 return; 770 771 /* 772 Ok, old list may've used SUBDIR, or defaults could've changed. 773 774 fourth check: are we inside a currently active SUBDIR rule ? 775 go up the call stack, if TRACE_ON flag ever changes its value - we are. 776 */ 777 for (traceon=framep->level; framep; framep=framep->prev) 778 if ((traceon ^ framep->level) & TRACE_ON) 779 goto yuck; 780 781 /* 782 Ok, TRACE_ON flag doesn't change in the call stack. 783 784 fifth check: but is the top-most value equal to a default one ? 785 */ 786 if (((traceon & TRACE_ON) != 0) == ((new_fflags & INCLUDE) == 0)) 787 return; 788 789 yuck: 790 /* 791 Yuck! function list was changed, and one of the currently active rules 792 was possibly affected. For example, a tracing could've been enabled or 793 disabled for a function somewhere up the call stack. 794 To react correctly, we must go up the call stack all the way to 795 the top and re-match rules to set TRACE_ON bit correctly. 796 797 We must traverse the stack forwards, not backwards. 798 That's what a recursive helper is doing. 799 It'll destroy two CODE_STATE fields, save them now. 800 */ 801 func= cs->func; 802 level= cs->level; 803 FixTraceFlags_helper(cs, func, cs->framep); 804 /* now we only need to restore CODE_STATE fields, and we're done */ 805 cs->func= func; 806 cs->level= level; 807 } 808 809 /* 810 * FUNCTION 811 * 812 * _db_set_ set current debugger settings 813 * 814 * SYNOPSIS 815 * 816 * VOID _db_set_(control) 817 * char *control; 818 * 819 * DESCRIPTION 820 * 821 * Given pointer to a debug control string in "control", 822 * parses the control string, and sets up a current debug 823 * settings. Pushes a new debug settings if the current is 824 * set to the initial debugger settings. 825 * 826 */ 827 828 void _db_set_(const char *control) 829 { 830 CODE_STATE *cs; 831 uint old_fflags; 832 get_code_state_or_return; 833 old_fflags=fflags(cs); 834 if (cs->stack == &init_settings) 835 PushState(cs); 836 if (DbugParse(cs, control)) 837 FixTraceFlags(old_fflags, cs); 838 } 839 840 /* 841 * FUNCTION 842 * 843 * _db_push_ push current debugger settings and set up new one 844 * 845 * SYNOPSIS 846 * 847 * VOID _db_push_(control) 848 * char *control; 849 * 850 * DESCRIPTION 851 * 852 * Given pointer to a debug control string in "control", pushes 853 * the current debug settings, parses the control string, and sets 854 * up a new debug settings 855 * 856 */ 857 858 void _db_push_(const char *control) 859 { 860 CODE_STATE *cs; 861 uint old_fflags; 862 get_code_state_or_return; 863 old_fflags=fflags(cs); 864 PushState(cs); 865 if (DbugParse(cs, control)) 866 FixTraceFlags(old_fflags, cs); 867 } 868 869 870 /** 871 Returns TRUE if session-local settings have been set. 872 */ 873 874 int _db_is_pushed_() 875 { 876 CODE_STATE *cs= NULL; 877 get_code_state_or_return FALSE; 878 return (cs->stack != &init_settings); 879 } 880 881 /* 882 * FUNCTION 883 * 884 * _db_set_init_ set initial debugger settings 885 * 886 * SYNOPSIS 887 * 888 * VOID _db_set_init_(control) 889 * char *control; 890 * 891 * DESCRIPTION 892 * see _db_set_ 893 * 894 */ 895 896 void _db_set_init_(const char *control) 897 { 898 CODE_STATE tmp_cs; 899 bzero((uchar*) &tmp_cs, sizeof(tmp_cs)); 900 tmp_cs.stack= &init_settings; 901 tmp_cs.process= db_process ? db_process : "dbug"; 902 DbugParse(&tmp_cs, control); 903 } 904 905 /* 906 * FUNCTION 907 * 908 * _db_pop_ pop the debug stack 909 * 910 * DESCRIPTION 911 * 912 * Pops the debug stack, returning the debug settings to its 913 * condition prior to the most recent _db_push_ invocation. 914 * Note that the pop will fail if it would remove the last 915 * valid settings from the stack. This prevents user errors 916 * in the push/pop sequence from screwing up the debugger. 917 * Maybe there should be some kind of warning printed if the 918 * user tries to pop too many states. 919 * 920 */ 921 922 void _db_pop_() 923 { 924 uint old_fflags; 925 CODE_STATE *cs; 926 927 get_code_state_or_return; 928 929 if (cs->stack != &init_settings) 930 { 931 old_fflags=fflags(cs); 932 FreeState(cs, 1); 933 FixTraceFlags(old_fflags, cs); 934 } 935 } 936 937 /* 938 * FUNCTION 939 * 940 * _db_explain_ generates 'control' string for the current settings 941 * 942 * RETURN 943 * 0 - ok 944 * 1 - buffer too short, output truncated 945 * 946 */ 947 948 /* helper macros */ 949 #define char_to_buf(C) do { \ 950 *buf++=(C); \ 951 if (buf >= end) goto overflow; \ 952 } while (0) 953 #define str_to_buf(S) do { \ 954 char_to_buf(','); \ 955 buf=strnmov(buf, (S), (uint) (end-buf)); \ 956 if (buf >= end) goto overflow; \ 957 } while (0) 958 #define list_to_buf(l, f) do { \ 959 struct link *listp=(l); \ 960 while (listp) \ 961 { \ 962 if (listp->flags & (f)) \ 963 { \ 964 str_to_buf(listp->str); \ 965 if (listp->flags & SUBDIR) \ 966 char_to_buf('/'); \ 967 } \ 968 listp=listp->next_link; \ 969 } \ 970 } while (0) 971 #define int_to_buf(i) do { \ 972 char b[50]; \ 973 int10_to_str((i), b, 10); \ 974 str_to_buf(b); \ 975 } while (0) 976 #define colon_to_buf do { \ 977 if (buf != start) char_to_buf(':'); \ 978 } while(0) 979 #define op_int_to_buf(C, val, def) do { \ 980 if ((val) != (def)) \ 981 { \ 982 colon_to_buf; \ 983 char_to_buf((C)); \ 984 int_to_buf(val); \ 985 } \ 986 } while (0) 987 #define op_intf_to_buf(C, val, def, cond) do { \ 988 if ((cond)) \ 989 { \ 990 colon_to_buf; \ 991 char_to_buf((C)); \ 992 if ((val) != (def)) int_to_buf(val); \ 993 } \ 994 } while (0) 995 #define op_str_to_buf(C, val, cond) do { \ 996 if ((cond)) \ 997 { \ 998 char *s=(val); \ 999 colon_to_buf; \ 1000 char_to_buf((C)); \ 1001 if (*s) str_to_buf(s); \ 1002 } \ 1003 } while (0) 1004 #define op_list_to_buf(C, val, cond) do { \ 1005 if ((cond)) \ 1006 { \ 1007 int f=ListFlags(val); \ 1008 colon_to_buf; \ 1009 char_to_buf((C)); \ 1010 if (f & INCLUDE) \ 1011 list_to_buf(val, INCLUDE); \ 1012 if (f & EXCLUDE) \ 1013 { \ 1014 colon_to_buf; \ 1015 char_to_buf('-'); \ 1016 char_to_buf((C)); \ 1017 list_to_buf(val, EXCLUDE); \ 1018 } \ 1019 } \ 1020 } while (0) 1021 #define op_bool_to_buf(C, cond) do { \ 1022 if ((cond)) \ 1023 { \ 1024 colon_to_buf; \ 1025 char_to_buf((C)); \ 1026 } \ 1027 } while (0) 1028 1029 int _db_explain_ (CODE_STATE *cs, char *buf, size_t len) 1030 { 1031 char *start=buf, *end=buf+len-4; 1032 1033 get_code_state_if_not_set_or_return *buf=0; 1034 1035 LockIfInitSettings(cs); 1036 op_list_to_buf('d', cs->stack->keywords, DEBUGGING); 1037 UnlockIfInitSettings(cs); 1038 op_int_to_buf ('D', cs->stack->delay, 0); 1039 op_list_to_buf('f', cs->stack->functions, cs->stack->functions); 1040 op_bool_to_buf('F', cs->stack->flags & FILE_ON); 1041 op_bool_to_buf('i', cs->stack->flags & PID_ON); 1042 op_bool_to_buf('L', cs->stack->flags & LINE_ON); 1043 op_bool_to_buf('n', cs->stack->flags & DEPTH_ON); 1044 op_bool_to_buf('N', cs->stack->flags & NUMBER_ON); 1045 op_str_to_buf( 1046 ((cs->stack->flags & FLUSH_ON_WRITE ? 0 : 32) | 1047 (cs->stack->flags & OPEN_APPEND ? 'A' : 'O')), 1048 cs->stack->name, cs->stack->out_file != sstderr); 1049 op_list_to_buf('p', cs->stack->processes, cs->stack->processes); 1050 op_bool_to_buf('P', cs->stack->flags & PROCESS_ON); 1051 op_bool_to_buf('r', cs->stack->sub_level != 0); 1052 op_intf_to_buf('t', cs->stack->maxdepth, MAXDEPTH, TRACING); 1053 op_bool_to_buf('T', cs->stack->flags & TIMESTAMP_ON); 1054 op_bool_to_buf('S', cs->stack->flags & SANITY_CHECK_ON); 1055 1056 *buf= '\0'; 1057 return 0; 1058 1059 overflow: 1060 *end++= '.'; 1061 *end++= '.'; 1062 *end++= '.'; 1063 *end= '\0'; 1064 return 1; 1065 } 1066 1067 #undef char_to_buf 1068 #undef str_to_buf 1069 #undef list_to_buf 1070 #undef int_to_buf 1071 #undef colon_to_buf 1072 #undef op_int_to_buf 1073 #undef op_intf_to_buf 1074 #undef op_str_to_buf 1075 #undef op_list_to_buf 1076 #undef op_bool_to_buf 1077 1078 /* 1079 * FUNCTION 1080 * 1081 * _db_explain_init_ explain initial debugger settings 1082 * 1083 * DESCRIPTION 1084 * see _db_explain_ 1085 */ 1086 1087 int _db_explain_init_(char *buf, size_t len) 1088 { 1089 CODE_STATE cs; 1090 bzero((uchar*) &cs,sizeof(cs)); 1091 cs.stack=&init_settings; 1092 return _db_explain_(&cs, buf, len); 1093 } 1094 1095 /* 1096 * FUNCTION 1097 * 1098 * _db_enter_ process entry point to user function 1099 * 1100 * SYNOPSIS 1101 * 1102 * VOID _db_enter_(_func_, _file_, _line_, _stack_frame_) 1103 * char *_func_; points to current function name 1104 * char *_file_; points to current file name 1105 * int _line_; called from source line number 1106 * struct _db_stack_frame_ allocated on the caller's stack 1107 * 1108 * DESCRIPTION 1109 * 1110 * Called at the beginning of each user function to tell 1111 * the debugger that a new function has been entered. 1112 * Note that the pointers to the previous user function 1113 * name and previous user file name are stored on the 1114 * caller's stack (this is why the ENTER macro must be 1115 * the first "executable" code in a function, since it 1116 * allocates these storage locations). The previous nesting 1117 * level is also stored on the callers stack for internal 1118 * self consistency checks. 1119 * 1120 * Also prints a trace line if tracing is enabled and 1121 * increments the current function nesting depth. 1122 * 1123 * Note that this mechanism allows the debugger to know 1124 * what the current user function is at all times, without 1125 * maintaining an internal stack for the function names. 1126 * 1127 */ 1128 1129 void _db_enter_(const char *_func_, const char *_file_, 1130 uint _line_, struct _db_stack_frame_ *_stack_frame_) 1131 { 1132 CODE_STATE *cs; 1133 if (!((cs=code_state()))) 1134 { 1135 _stack_frame_->level= 0; /* Set to avoid valgrind warnings if dbug is enabled later */ 1136 _stack_frame_->prev= 0; 1137 return; 1138 } 1139 1140 _stack_frame_->line= -1; 1141 _stack_frame_->func= cs->func; 1142 _stack_frame_->file= cs->file; 1143 cs->func= _func_; 1144 cs->file= _file_; 1145 _stack_frame_->prev= cs->framep; 1146 _stack_frame_->level= ++cs->level | framep_trace_flag(cs, cs->framep); 1147 cs->framep= _stack_frame_; 1148 1149 switch (DoTrace(cs)) { 1150 case ENABLE_TRACE: 1151 cs->framep->level|= TRACE_ON; 1152 if (!TRACING) break; 1153 /* fall through */ 1154 case DO_TRACE: 1155 if ((cs->stack->flags & SANITY_CHECK_ON) && (*dbug_sanity)()) 1156 cs->stack->flags &= ~SANITY_CHECK_ON; 1157 if (TRACING) 1158 { 1159 int save_errno= errno; 1160 LockMutex(cs); 1161 DoPrefix(cs, _line_); 1162 Indent(cs, cs->level); 1163 (void) fprintf(cs->stack->out_file->file, ">%s\n", cs->func); 1164 UnlockMutex(cs); 1165 DbugFlush(cs); 1166 errno=save_errno; 1167 } 1168 break; 1169 case DISABLE_TRACE: 1170 cs->framep->level&= ~TRACE_ON; 1171 /* fall through */ 1172 case DONT_TRACE: 1173 break; 1174 } 1175 } 1176 1177 /* 1178 * FUNCTION 1179 * 1180 * _db_return_ process exit from user function 1181 * 1182 * SYNOPSIS 1183 * 1184 * VOID _db_return_(_line_, _stack_frame_) 1185 * int _line_; current source line number 1186 * struct _db_stack_frame_ allocated on the caller's stack 1187 * 1188 * DESCRIPTION 1189 * 1190 * Called just before user function executes an explicit or implicit 1191 * return. Prints a trace line if trace is enabled, decrements 1192 * the current nesting level, and restores the current function and 1193 * file names from the defunct function's stack. 1194 * 1195 */ 1196 1197 void _db_return_(struct _db_stack_frame_ *_stack_frame_) 1198 { 1199 uint _slevel_= _stack_frame_->level & ~TRACE_ON; 1200 CODE_STATE *cs; 1201 get_code_state_or_return; 1202 1203 if (_stack_frame_->line == 0) 1204 return; 1205 1206 if (_stack_frame_->line == -1 || cs->framep != _stack_frame_) 1207 { 1208 char buf[512]; 1209 my_snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func); 1210 DbugExit(buf); 1211 } 1212 1213 if (DoTrace(cs) & DO_TRACE) 1214 { 1215 if ((cs->stack->flags & SANITY_CHECK_ON) && (*dbug_sanity)()) 1216 cs->stack->flags &= ~SANITY_CHECK_ON; 1217 if (TRACING) 1218 { 1219 int save_errno=errno; 1220 LockMutex(cs); 1221 DoPrefix(cs, _stack_frame_->line); 1222 Indent(cs, cs->level); 1223 (void) fprintf(cs->stack->out_file->file, "<%s\n", cs->func); 1224 UnlockMutex(cs); 1225 DbugFlush(cs); 1226 errno=save_errno; 1227 } 1228 } 1229 /* 1230 Check to not set level < 0. This can happen if DBUG was disabled when 1231 function was entered and enabled in function. 1232 */ 1233 cs->level= _slevel_ != 0 ? _slevel_ - 1 : 0; 1234 cs->func= _stack_frame_->func; 1235 cs->file= _stack_frame_->file; 1236 if (cs->framep != NULL) 1237 cs->framep= cs->framep->prev; 1238 } 1239 1240 1241 /* 1242 * FUNCTION 1243 * 1244 * _db_pargs_ log arguments for subsequent use by _db_doprnt_() 1245 * 1246 * SYNOPSIS 1247 * 1248 * int _db_pargs_(_line_, keyword) 1249 * int _line_; 1250 * char *keyword; 1251 * 1252 * DESCRIPTION 1253 * 1254 * The new universal printing macro DBUG_PRINT, which replaces 1255 * all forms of the DBUG_N macros, needs two calls to runtime 1256 * support routines. The first, this function, remembers arguments 1257 * that are used by the subsequent call to _db_doprnt_(). 1258 * 1259 */ 1260 1261 int _db_pargs_(uint _line_, const char *keyword) 1262 { 1263 CODE_STATE *cs; 1264 get_code_state_or_return 0; 1265 cs->u_line= _line_; 1266 cs->u_keyword= keyword; 1267 1268 return DEBUGGING && _db_keyword_(cs, cs->u_keyword, 0); 1269 } 1270 1271 1272 /* 1273 * FUNCTION 1274 * 1275 * _db_doprnt_ handle print of debug lines 1276 * 1277 * SYNOPSIS 1278 * 1279 * VOID _db_doprnt_(format, va_alist) 1280 * char *format; 1281 * va_dcl; 1282 * 1283 * DESCRIPTION 1284 * 1285 * When invoked via one of the DBUG macros, tests the current keyword 1286 * set by calling _db_pargs_() to see if that macro has been selected 1287 * for processing via the debugger control string, and if so, handles 1288 * printing of the arguments via the format string. The line number 1289 * of the DBUG macro in the source is found in u_line. 1290 * 1291 * Note that the format string SHOULD NOT include a terminating 1292 * newline, this is supplied automatically. 1293 * 1294 */ 1295 1296 #include <stdarg.h> 1297 1298 void _db_doprnt_(const char *format,...) 1299 { 1300 va_list args; 1301 CODE_STATE *cs; 1302 int save_errno; 1303 1304 get_code_state_or_return; 1305 1306 va_start(args,format); 1307 1308 save_errno=errno; 1309 LockMutex(cs); 1310 DoPrefix(cs, cs->u_line); 1311 if (TRACING) 1312 Indent(cs, cs->level + 1); 1313 else 1314 (void) fprintf(cs->stack->out_file->file, "%s: ", cs->func); 1315 (void) fprintf(cs->stack->out_file->file, "%s: ", cs->u_keyword); 1316 DbugVfprintf(cs->stack->out_file->file, format, args); 1317 UnlockMutex(cs); 1318 DbugFlush(cs); 1319 errno=save_errno; 1320 1321 va_end(args); 1322 } 1323 1324 /* 1325 * This function is intended as a 1326 * vfprintf clone with consistent, platform independent output for 1327 * problematic formats like %p, %zd and %lld. 1328 */ 1329 static void DbugVfprintf(FILE *stream, const char* format, va_list args) 1330 { 1331 char cvtbuf[1024]; 1332 (void) my_vsnprintf(cvtbuf, sizeof(cvtbuf), format, args); 1333 (void) fprintf(stream, "%s\n", cvtbuf); 1334 } 1335 1336 1337 /* 1338 * FUNCTION 1339 * 1340 * _db_dump_ dump a string in hex 1341 * 1342 * SYNOPSIS 1343 * 1344 * void _db_dump_(_line_,keyword,memory,length) 1345 * int _line_; current source line number 1346 * char *keyword; 1347 * char *memory; Memory to print 1348 * int length; Bytes to print 1349 * 1350 * DESCRIPTION 1351 * Dump N characters in a binary array. 1352 * Is used to examine corrupted memory or arrays. 1353 */ 1354 1355 void _db_dump_(uint _line_, const char *keyword, 1356 const unsigned char *memory, size_t length) 1357 { 1358 int pos; 1359 CODE_STATE *cs; 1360 get_code_state_or_return; 1361 1362 if (_db_keyword_(cs, keyword, 0)) 1363 { 1364 LockMutex(cs); 1365 DoPrefix(cs, _line_); 1366 if (TRACING) 1367 { 1368 Indent(cs, cs->level + 1); 1369 pos= MY_MIN(MY_MAX(cs->level-cs->stack->sub_level,0)*INDENT,80); 1370 } 1371 else 1372 { 1373 fprintf(cs->stack->out_file->file, "%s: ", cs->func); 1374 } 1375 (void) fprintf(cs->stack->out_file->file, "%s: Memory: %p Bytes: (%ld)\n", 1376 keyword, memory, (long) length); 1377 1378 pos=0; 1379 while (length-- > 0) 1380 { 1381 uint tmp= *((unsigned char*) memory++); 1382 if ((pos+=3) >= 80) 1383 { 1384 fputc('\n',cs->stack->out_file->file); 1385 pos=3; 1386 } 1387 fputc(_dig_vec_upper[((tmp >> 4) & 15)], cs->stack->out_file->file); 1388 fputc(_dig_vec_upper[tmp & 15], cs->stack->out_file->file); 1389 fputc(' ',cs->stack->out_file->file); 1390 } 1391 (void) fputc('\n',cs->stack->out_file->file); 1392 UnlockMutex(cs); 1393 DbugFlush(cs); 1394 } 1395 } 1396 1397 1398 /* 1399 * FUNCTION 1400 * 1401 * ListAddDel modify the list according to debug control string 1402 * 1403 * DESCRIPTION 1404 * 1405 * Given pointer to a comma separated list of strings in "cltp", 1406 * parses the list, and modifies "listp", returning a pointer 1407 * to the new list. 1408 * 1409 * The mode of operation is defined by "todo" parameter. 1410 * 1411 * If it is INCLUDE, elements (strings from "cltp") are added to the 1412 * list, they will have INCLUDE flag set. If the list already contains 1413 * the string in question, new element is not added, but a flag of 1414 * the existing element is adjusted (INCLUDE bit is set, EXCLUDE bit 1415 * is removed). 1416 * 1417 * If it is EXCLUDE, elements are added to the list with the EXCLUDE 1418 * flag set. If the list already contains the string in question, 1419 * it is removed, new element is not added. 1420 */ 1421 1422 static struct link *ListAddDel(struct link *head, const char *ctlp, 1423 const char *end, int todo) 1424 { 1425 const char *start; 1426 struct link **cur; 1427 size_t len; 1428 int subdir; 1429 1430 ctlp--; 1431 next: 1432 while (++ctlp < end) 1433 { 1434 start= ctlp; 1435 subdir=0; 1436 while (ctlp < end && *ctlp != ',') 1437 ctlp++; 1438 len= (int) (ctlp-start); 1439 if (start[len-1] == '/') 1440 { 1441 len--; 1442 subdir=SUBDIR; 1443 } 1444 if (len == 0) continue; 1445 for (cur=&head; *cur; cur=&((*cur)->next_link)) 1446 { 1447 if (!strncmp((*cur)->str, start, len)) 1448 { 1449 if ((*cur)->flags & todo) /* same action ? */ 1450 (*cur)->flags|= subdir; /* just merge the SUBDIR flag */ 1451 else if (todo == EXCLUDE) 1452 { 1453 struct link *delme=*cur; 1454 *cur=(*cur)->next_link; 1455 free((void*) delme); 1456 } 1457 else 1458 { 1459 (*cur)->flags&=~(EXCLUDE & SUBDIR); 1460 (*cur)->flags|=INCLUDE | subdir; 1461 } 1462 goto next; 1463 } 1464 } 1465 *cur= (struct link *) DbugMalloc(sizeof(struct link)+len); 1466 memcpy((*cur)->str, start, len); 1467 (*cur)->str[len]=0; 1468 (*cur)->flags=todo | subdir; 1469 (*cur)->next_link=0; 1470 } 1471 return head; 1472 } 1473 1474 /* 1475 * FUNCTION 1476 * 1477 * ListCopy make a copy of the list 1478 * 1479 * SYNOPSIS 1480 * 1481 * static struct link *ListCopy(orig) 1482 * struct link *orig; 1483 * 1484 * DESCRIPTION 1485 * 1486 * Given pointer to list, which contains a copy of every element from 1487 * the original list. 1488 * 1489 * the orig pointer can be NULL 1490 * 1491 * Note that since each link is added at the head of the list, 1492 * the final list will be in "reverse order", which is not 1493 * significant for our usage here. 1494 * 1495 */ 1496 1497 static struct link *ListCopy(struct link *orig) 1498 { 1499 struct link *new_malloc; 1500 struct link *head; 1501 size_t len; 1502 1503 head= NULL; 1504 while (orig != NULL) 1505 { 1506 len= strlen(orig->str); 1507 new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len); 1508 memcpy(new_malloc->str, orig->str, len); 1509 new_malloc->str[len]= 0; 1510 new_malloc->flags=orig->flags; 1511 new_malloc->next_link= head; 1512 head= new_malloc; 1513 orig= orig->next_link; 1514 } 1515 return head; 1516 } 1517 1518 /* 1519 * FUNCTION 1520 * 1521 * InList test a given string for member of a given list 1522 * 1523 * DESCRIPTION 1524 * 1525 * Tests the string pointed to by "cp" to determine if it is in 1526 * the list pointed to by "linkp". Linkp points to the first 1527 * link in the list. If linkp is NULL or contains only EXCLUDE 1528 * elements then the string is treated as if it is in the list. 1529 * This may seem rather strange at first but leads to the desired 1530 * operation if no list is given. The net effect is that all 1531 * strings will be accepted when there is no list, and when there 1532 * is a list, only those strings in the list will be accepted. 1533 * 1534 * RETURN 1535 * combination of SUBDIR, INCLUDE, EXCLUDE, MATCHED flags 1536 * 1537 */ 1538 1539 static int InList(struct link *linkp, const char *cp, int exact_match) 1540 { 1541 int result; 1542 for (result=MATCHED; linkp != NULL; linkp= linkp->next_link) 1543 { 1544 if (!(exact_match ? strcmp(linkp->str,cp) : fnmatch(linkp->str, cp, 0))) 1545 { 1546 result= linkp->flags; 1547 break; 1548 } 1549 if (!(linkp->flags & EXCLUDE)) 1550 result=NOT_MATCHED; 1551 if (linkp->flags & SUBDIR) 1552 result|=SUBDIR; 1553 } 1554 return result; 1555 } 1556 1557 /* 1558 * FUNCTION 1559 * 1560 * ListFlags returns aggregated list flags (ORed over all elements) 1561 * 1562 */ 1563 1564 static uint ListFlags(struct link *linkp) 1565 { 1566 uint f; 1567 for (f=0; linkp != NULL; linkp= linkp->next_link) 1568 f|= linkp->flags; 1569 return f; 1570 } 1571 1572 /* 1573 * FUNCTION 1574 * 1575 * PushState push current settings onto stack and set up new one 1576 * 1577 * SYNOPSIS 1578 * 1579 * static VOID PushState() 1580 * 1581 * DESCRIPTION 1582 * 1583 * Pushes the current settings on the settings stack, and creates 1584 * a new settings. The new settings is NOT initialized 1585 * 1586 * The settings stack is a linked list of settings, with the new 1587 * settings added at the head. This allows the stack to grow 1588 * to the limits of memory if necessary. 1589 * 1590 */ 1591 1592 static void PushState(CODE_STATE *cs) 1593 { 1594 struct settings *new_malloc; 1595 1596 new_malloc= (struct settings *) DbugMalloc(sizeof(struct settings)); 1597 bzero(new_malloc, sizeof(*new_malloc)); 1598 new_malloc->next= cs->stack; 1599 cs->stack= new_malloc; 1600 } 1601 1602 /* 1603 * FUNCTION 1604 * 1605 * FreeState Free memory associated with a struct state. 1606 * 1607 * SYNOPSIS 1608 * 1609 * static void FreeState (state) 1610 * struct state *state; 1611 * int free_state; 1612 * 1613 * DESCRIPTION 1614 * 1615 * Deallocates the memory allocated for various information in a 1616 * state. If free_state is set, also free 'state' 1617 * 1618 */ 1619 static void FreeState(CODE_STATE *cs, int free_state) 1620 { 1621 struct settings *state= cs->stack; 1622 LockIfInitSettings(cs); 1623 if (!is_shared(state, keywords)) 1624 { 1625 FreeList(state->keywords); 1626 state->keywords= NULL; 1627 } 1628 UnlockIfInitSettings(cs); 1629 if (!is_shared(state, functions)) 1630 FreeList(state->functions); 1631 if (!is_shared(state, processes)) 1632 FreeList(state->processes); 1633 1634 DBUGCloseFile(cs, NULL); 1635 1636 if (free_state) 1637 { 1638 struct settings *next= state->next; 1639 free(state); 1640 cs->stack= next; 1641 } 1642 } 1643 1644 1645 /* 1646 * FUNCTION 1647 * 1648 * _db_end_ End debugging, freeing state stack memory. 1649 * 1650 * SYNOPSIS 1651 * 1652 * static VOID _db_end_ () 1653 * 1654 * DESCRIPTION 1655 * 1656 * Ends debugging, de-allocating the memory allocated to the 1657 * state stack. 1658 * 1659 * To be called at the very end of the program. 1660 * 1661 */ 1662 void _db_end_() 1663 { 1664 CODE_STATE *cs, dummy_cs; 1665 /* 1666 Set _dbug_on_ to be able to do full reset even when DEBUGGER_OFF was 1667 called after dbug was initialized 1668 */ 1669 _dbug_on_= 1; 1670 cs= code_state(); 1671 1672 if (cs) 1673 { 1674 while (cs->stack && cs->stack != &init_settings) 1675 FreeState(cs, 1); 1676 } 1677 else 1678 { 1679 cs= &dummy_cs; 1680 bzero(cs, sizeof(*cs)); 1681 } 1682 1683 cs->stack= &init_settings; 1684 FreeState(cs, 0); 1685 pthread_mutex_destroy(&THR_LOCK_dbug); 1686 init_done= 0; 1687 _dbug_on_= 0; 1688 } 1689 1690 1691 /* 1692 * FUNCTION 1693 * 1694 * DoTrace check to see if tracing is current enabled 1695 * 1696 * DESCRIPTION 1697 * 1698 * Checks to see if dbug in this function is enabled based on 1699 * whether the maximum trace depth has been reached, the current 1700 * function is selected, and the current process is selected. 1701 * 1702 */ 1703 1704 static int DoTrace(CODE_STATE *cs) 1705 { 1706 int res= DONT_TRACE; 1707 if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) && 1708 InList(cs->stack->processes, cs->process, 0) & (MATCHED|INCLUDE)) 1709 { 1710 switch(InList(cs->stack->functions, cs->func, 0)) { 1711 case INCLUDE|SUBDIR: 1712 res= ENABLE_TRACE; 1713 break; 1714 case INCLUDE: 1715 res= DO_TRACE; 1716 break; 1717 case MATCHED|SUBDIR: 1718 case NOT_MATCHED|SUBDIR: 1719 case MATCHED: 1720 res= (framep_trace_flag(cs, cs->framep) ? DO_TRACE : DONT_TRACE); 1721 break; 1722 case EXCLUDE: 1723 case NOT_MATCHED: 1724 res= DONT_TRACE; 1725 break; 1726 case EXCLUDE|SUBDIR: 1727 res= DISABLE_TRACE; 1728 break; 1729 } 1730 } 1731 return res; 1732 } 1733 1734 1735 FILE *_db_fp_(void) 1736 { 1737 CODE_STATE *cs; 1738 get_code_state_or_return NULL; 1739 return cs->stack->out_file->file; 1740 } 1741 1742 /* 1743 * FUNCTION 1744 * 1745 * _db_keyword_ test keyword for member of keyword list 1746 * 1747 * DESCRIPTION 1748 * 1749 * Test a keyword to determine if it is in the currently active 1750 * keyword list. If strict=0, a keyword is accepted 1751 * if the list is null, otherwise it must match one of the list 1752 * members. When debugging is not on, no keywords are accepted. 1753 * After the maximum trace level is exceeded, no keywords are 1754 * accepted (this behavior subject to change). Additionally, 1755 * the current function and process must be accepted based on 1756 * their respective lists. 1757 * 1758 * Returns TRUE if keyword accepted, FALSE otherwise. 1759 * 1760 */ 1761 1762 BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict) 1763 { 1764 int match= strict ? INCLUDE : INCLUDE|MATCHED; 1765 int res; 1766 get_code_state_if_not_set_or_return FALSE; 1767 1768 if (!(DEBUGGING && (DoTrace(cs) & DO_TRACE))) 1769 return 0; 1770 LockIfInitSettings(cs); 1771 res= (InList(cs->stack->keywords, keyword, strict) & match); 1772 UnlockIfInitSettings(cs); 1773 return res != 0; 1774 } 1775 1776 /* 1777 * FUNCTION 1778 * 1779 * Indent indent a line to the given indentation level 1780 * 1781 * SYNOPSIS 1782 * 1783 * static VOID Indent(indent) 1784 * int indent; 1785 * 1786 * DESCRIPTION 1787 * 1788 * Indent a line to the given level. Note that this is 1789 * a simple minded but portable implementation. 1790 * There are better ways. 1791 * 1792 * Also, the indent must be scaled by the compile time option 1793 * of character positions per nesting level. 1794 * 1795 */ 1796 1797 static void Indent(CODE_STATE *cs, int indent) 1798 { 1799 int count; 1800 1801 indent= MY_MAX(indent-1-cs->stack->sub_level,0)*INDENT; 1802 for (count= 0; count < indent ; count++) 1803 { 1804 if ((count % INDENT) == 0) 1805 fputc('|',cs->stack->out_file->file); 1806 else 1807 fputc(' ',cs->stack->out_file->file); 1808 } 1809 } 1810 1811 1812 /* 1813 * FUNCTION 1814 * 1815 * FreeList free all memory associated with a linked list 1816 * 1817 * SYNOPSIS 1818 * 1819 * static VOID FreeList(linkp) 1820 * struct link *linkp; 1821 * 1822 * DESCRIPTION 1823 * 1824 * Given pointer to the head of a linked list, frees all 1825 * memory held by the list and the members of the list. 1826 * 1827 */ 1828 1829 static void FreeList(struct link *linkp) 1830 { 1831 struct link *old; 1832 1833 while (linkp != NULL) 1834 { 1835 old= linkp; 1836 linkp= linkp->next_link; 1837 free((void*) old); 1838 } 1839 } 1840 1841 1842 /* 1843 * FUNCTION 1844 * 1845 * DoPrefix print debugger line prefix prior to indentation 1846 * 1847 * SYNOPSIS 1848 * 1849 * static VOID DoPrefix(_line_) 1850 * int _line_; 1851 * 1852 * DESCRIPTION 1853 * 1854 * Print prefix common to all debugger output lines, prior to 1855 * doing indentation if necessary. Print such information as 1856 * current process name, current source file name and line number, 1857 * and current function nesting depth. 1858 * 1859 */ 1860 1861 static void DoPrefix(CODE_STATE *cs, uint _line_) 1862 { 1863 cs->lineno++; 1864 if (cs->stack->flags & PID_ON) 1865 { 1866 (void) fprintf(cs->stack->out_file->file, "%-7s: ", my_thread_name()); 1867 } 1868 if (cs->stack->flags & NUMBER_ON) 1869 (void) fprintf(cs->stack->out_file->file, "%5d: ", cs->lineno); 1870 if (cs->stack->flags & TIMESTAMP_ON) 1871 { 1872 #ifdef __WIN__ 1873 /* FIXME This doesn't give microseconds as in Unix case, and the resolution is 1874 in system ticks, 10 ms intervals. See my_getsystime.c for high res */ 1875 SYSTEMTIME loc_t; 1876 GetLocalTime(&loc_t); 1877 (void) fprintf (cs->stack->out_file->file, 1878 /* "%04d-%02d-%02d " */ 1879 "%02d:%02d:%02d.%06d ", 1880 /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/ 1881 loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds); 1882 #else 1883 struct timeval tv; 1884 struct tm *tm_p; 1885 if (gettimeofday(&tv, NULL) != -1) 1886 { 1887 if ((tm_p= localtime((const time_t *)&tv.tv_sec))) 1888 { 1889 (void) fprintf (cs->stack->out_file->file, 1890 /* "%04d-%02d-%02d " */ 1891 "%02d:%02d:%02d.%06d ", 1892 /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/ 1893 tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec, 1894 (int) (tv.tv_usec)); 1895 } 1896 } 1897 #endif 1898 } 1899 if (cs->stack->flags & PROCESS_ON) 1900 (void) fprintf(cs->stack->out_file->file, "%s: ", cs->process); 1901 if (cs->stack->flags & FILE_ON) 1902 (void) fprintf(cs->stack->out_file->file, "%14s: ", BaseName(cs->file)); 1903 if (cs->stack->flags & LINE_ON) 1904 (void) fprintf(cs->stack->out_file->file, "%5d: ", _line_); 1905 if (cs->stack->flags & DEPTH_ON) 1906 (void) fprintf(cs->stack->out_file->file, "%4d: ", cs->level); 1907 } 1908 1909 1910 /* 1911 * FUNCTION 1912 * 1913 * DBUGOpenFile open new output stream for debugger output 1914 * 1915 * SYNOPSIS 1916 * 1917 * static VOID DBUGOpenFile(name) 1918 * char *name; 1919 * 1920 * DESCRIPTION 1921 * 1922 * Given name of a new file (or "-" for stdout) opens the file 1923 * and sets the output stream to the new file. 1924 * 1925 */ 1926 1927 static void DBUGOpenFile(CODE_STATE *cs, 1928 const char *name,const char *end,int append) 1929 { 1930 FILE *fp; 1931 1932 if (name != NULL) 1933 { 1934 if (end) 1935 { 1936 size_t len=end-name; 1937 memcpy(cs->stack->name, name, len); 1938 cs->stack->name[len]=0; 1939 } 1940 else 1941 strmov(cs->stack->name,name); 1942 name=cs->stack->name; 1943 if (strcmp(name, "-") == 0) 1944 { 1945 DBUGCloseFile(cs, sstdout); 1946 cs->stack->flags |= FLUSH_ON_WRITE; 1947 cs->stack->name[0]=0; 1948 } 1949 else 1950 { 1951 if (!Writable(name)) 1952 { 1953 (void) fprintf(stderr, ERR_OPEN, cs->process, name); 1954 perror(""); 1955 fflush(stderr); 1956 } 1957 else 1958 { 1959 if (!(fp= fopen(name, append ? "a+" : "w"))) 1960 { 1961 (void) fprintf(stderr, ERR_OPEN, cs->process, name); 1962 perror(""); 1963 fflush(stderr); 1964 } 1965 else 1966 { 1967 sFILE *sfp= (sFILE *)DbugMalloc(sizeof(sFILE)); 1968 sfp->file= fp; 1969 sfp->used= 1; 1970 DBUGCloseFile(cs, sfp); 1971 } 1972 } 1973 } 1974 } 1975 } 1976 1977 /* 1978 * FUNCTION 1979 * 1980 * DBUGCloseFile close the debug output stream 1981 * 1982 * SYNOPSIS 1983 * 1984 * static VOID DBUGCloseFile(fp) 1985 * FILE *fp; 1986 * 1987 * DESCRIPTION 1988 * 1989 * Closes the debug output stream unless it is standard output 1990 * or standard error. 1991 * 1992 */ 1993 1994 static void DBUGCloseFile(CODE_STATE *cs, sFILE *new_value) 1995 { 1996 sFILE *fp; 1997 if (!cs || !cs->stack || !cs->stack->out_file) 1998 return; 1999 2000 fp= cs->stack->out_file; 2001 if (--fp->used == 0) 2002 { 2003 if (fclose(fp->file) == EOF) 2004 { 2005 LockMutex(cs); 2006 (void) fprintf(stderr, ERR_CLOSE, cs->process); 2007 perror(""); 2008 UnlockMutex(cs); 2009 } 2010 else 2011 { 2012 free(fp); 2013 } 2014 } 2015 cs->stack->out_file= new_value; 2016 } 2017 2018 2019 /* 2020 * FUNCTION 2021 * 2022 * DbugExit print error message and exit 2023 * 2024 * SYNOPSIS 2025 * 2026 * static VOID DbugExit(why) 2027 * char *why; 2028 * 2029 * DESCRIPTION 2030 * 2031 * Prints error message using current process name, the reason for 2032 * aborting (typically out of memory), and exits with status 1. 2033 * This should probably be changed to use a status code 2034 * defined in the user's debugger include file. 2035 * 2036 */ 2037 2038 static void DbugExit(const char *why) 2039 { 2040 CODE_STATE *cs=code_state(); 2041 (void) fprintf(stderr, ERR_ABORT, cs ? cs->process : "(null)", why); 2042 (void) fflush(stderr); 2043 DBUG_ABORT(); 2044 } 2045 2046 2047 /* 2048 * FUNCTION 2049 * 2050 * DbugMalloc allocate memory for debugger runtime support 2051 * 2052 * SYNOPSIS 2053 * 2054 * static long *DbugMalloc(size) 2055 * int size; 2056 * 2057 * DESCRIPTION 2058 * 2059 * Allocate more memory for debugger runtime support functions. 2060 * Failure to to allocate the requested number of bytes is 2061 * immediately fatal to the current process. This may be 2062 * rather unfriendly behavior. It might be better to simply 2063 * print a warning message, freeze the current debugger cs, 2064 * and continue execution. 2065 * 2066 */ 2067 2068 static char *DbugMalloc(size_t size) 2069 { 2070 char *new_malloc; 2071 2072 if (!(new_malloc= (char*) malloc(size))) 2073 DbugExit("out of memory"); 2074 return new_malloc; 2075 } 2076 2077 2078 /* 2079 * strtok lookalike - splits on ':', magically handles ::, :\ and :/ 2080 */ 2081 2082 static const char *DbugStrTok(const char *s) 2083 { 2084 while (s[0] && (s[0] != ':' || 2085 (s[1] == '\\' || s[1] == '/' || (s[1] == ':' && s++)))) 2086 s++; 2087 return s; 2088 } 2089 2090 2091 /* 2092 * FUNCTION 2093 * 2094 * BaseName strip leading pathname components from name 2095 * 2096 * SYNOPSIS 2097 * 2098 * static char *BaseName(pathname) 2099 * char *pathname; 2100 * 2101 * DESCRIPTION 2102 * 2103 * Given pointer to a complete pathname, locates the base file 2104 * name at the end of the pathname and returns a pointer to 2105 * it. 2106 * 2107 */ 2108 2109 static const char *BaseName(const char *pathname) 2110 { 2111 const char *base; 2112 2113 base= strrchr(pathname, FN_LIBCHAR); 2114 if (base++ == NullS) 2115 base= pathname; 2116 return base; 2117 } 2118 2119 2120 /* 2121 * FUNCTION 2122 * 2123 * Writable test to see if a pathname is writable/creatable 2124 * 2125 * SYNOPSIS 2126 * 2127 * static BOOLEAN Writable(pathname) 2128 * char *pathname; 2129 * 2130 * DESCRIPTION 2131 * 2132 * Because the debugger might be linked in with a program that 2133 * runs with the set-uid-bit (suid) set, we have to be careful 2134 * about opening a user named file for debug output. This consists 2135 * of checking the file for write access with the real user id, 2136 * or checking the directory where the file will be created. 2137 * 2138 * Returns TRUE if the user would normally be allowed write or 2139 * create access to the named file. Returns FALSE otherwise. 2140 * 2141 */ 2142 2143 2144 #ifndef Writable 2145 2146 static BOOLEAN Writable(const char *pathname) 2147 { 2148 BOOLEAN granted; 2149 char *lastslash; 2150 2151 granted= FALSE; 2152 if (EXISTS(pathname)) 2153 { 2154 if (WRITABLE(pathname)) 2155 granted= TRUE; 2156 } 2157 else 2158 { 2159 lastslash= strrchr(pathname, '/'); 2160 if (lastslash != NULL) 2161 *lastslash= '\0'; 2162 else 2163 pathname= "."; 2164 if (WRITABLE(pathname)) 2165 granted= TRUE; 2166 if (lastslash != NULL) 2167 *lastslash= '/'; 2168 } 2169 return granted; 2170 } 2171 #endif 2172 2173 /* 2174 flush dbug-stream, free mutex lock & wait delay 2175 This is because some systems (MSDOS!!) doesn't flush fileheader 2176 and dbug-file isn't readable after a system crash !! 2177 */ 2178 2179 static void DbugFlush(CODE_STATE *cs) 2180 { 2181 if (cs->stack->flags & FLUSH_ON_WRITE) 2182 { 2183 (void) fflush(cs->stack->out_file->file); 2184 if (cs->stack->delay) 2185 (void) Delay(cs->stack->delay); 2186 } 2187 } /* DbugFlush */ 2188 2189 2190 /* For debugging */ 2191 2192 void _db_flush_() 2193 { 2194 CODE_STATE *cs; 2195 get_code_state_or_return; 2196 if (DEBUGGING) 2197 { 2198 (void) fflush(cs->stack->out_file->file); 2199 } 2200 } 2201 2202 2203 #ifndef __WIN__ 2204 void _db_suicide_() 2205 { 2206 int retval; 2207 sigset_t new_mask; 2208 sigfillset(&new_mask); 2209 2210 fprintf(stderr, "SIGKILL myself\n"); 2211 fflush(stderr); 2212 2213 retval= kill(getpid(), SIGKILL); 2214 assert(retval == 0); 2215 retval= sigsuspend(&new_mask); 2216 fprintf(stderr, "sigsuspend returned %d errno %d \n", retval, errno); 2217 assert(FALSE); /* With full signal mask, we should never return here. */ 2218 } 2219 #endif /* ! __WIN__ */ 2220 2221 2222 void _db_lock_file_() 2223 { 2224 CODE_STATE *cs; 2225 get_code_state_or_return; 2226 LockMutex(cs); 2227 } 2228 2229 void _db_unlock_file_() 2230 { 2231 CODE_STATE *cs; 2232 get_code_state_or_return; 2233 UnlockMutex(cs); 2234 } 2235 2236 const char* _db_get_func_(void) 2237 { 2238 CODE_STATE *cs; 2239 get_code_state_or_return NULL; 2240 return cs->func; 2241 } 2242 2243 2244 static int default_my_dbug_sanity(void) 2245 { 2246 return 0; 2247 } 2248 2249 extern my_bool my_assert; 2250 ATTRIBUTE_COLD 2251 my_bool _db_my_assert(const char *file, int line, const char *msg) 2252 { 2253 my_bool a = my_assert; 2254 _db_flush_(); 2255 if (!a) 2256 fprintf(stderr, "%s:%d: assert: %s\n", file, line, msg); 2257 return a; 2258 } 2259 #else 2260 2261 /* 2262 * Dummy function, workaround for build failure on a platform where linking 2263 * with an empty archive fails. 2264 */ 2265 int i_am_a_dummy_function() { 2266 return 0; 2267 } 2268 2269 #endif /* DBUG_OFF */ 2270 2271 /* 2272 This function is called by default on DBUG_ASSERT() when compiled with 2273 DBUG_ASSERT_AS_PRINTF 2274 */ 2275 2276 #ifdef DBUG_ASSERT_AS_PRINTF 2277 2278 static void default_my_dbug_assert_failed(const char *assert_expr, 2279 const char *file, 2280 unsigned long line) 2281 { 2282 fprintf(stderr, "Warning: assertion failed: %s at %s line %lu\n", 2283 assert_expr, file, line); 2284 } 2285 2286 void (*my_dbug_assert_failed)(const char *assert_expr, const char* file, 2287 unsigned long line)= default_my_dbug_assert_failed; 2288 2289 #endif /* DBUG_ASSERT_AS_PRINTF */ 2290