📄 dbg.c
字号:
/* Dbg.c - Tcl Debugger - See cmdHelp() for commandsWritten by: Don Libes, NIST, 3/23/93Design and implementation of this program was paid for by U.S. taxdollars. Therefore it is public domain. However, the author and NISTwould appreciate credit if this program or parts of it are used.*/#include <stdio.h>#include "tcldbgcf.h"#if 0/* tclInt.h drags in stdlib. By claiming no-stdlib, force it to drag in *//* Tcl's compat version. This avoids having to test for its presence *//* which is too tricky - configure can't generate two cf files, so when *//* Expect (or any app) uses the debugger, there's no way to get the info *//* about whether stdlib exists or not, except pointing the debugger at *//* an app-dependent .h file and I don't want to do that. */#define NO_STDLIB_H#endif#include "tclInt.h"/*#include <varargs.h> tclInt.h drags in varargs.h. Since Pyramid *//* objects to including varargs.h twice, just *//* omit this one. *//*#include "string.h" tclInt.h drags this in, too! */#include "tcldbg.h"#ifndef TRUE#define TRUE 1#define FALSE 0#endifstatic int simple_interactor();static int zero();/* most of the static variables in this file may be *//* moved into Tcl_Interp */static Dbg_InterProc *interactor = simple_interactor;static ClientData interdata = 0;static Dbg_IgnoreFuncsProc *ignoreproc = zero;static Dbg_OutputProc *printproc = 0;static ClientData printdata = 0;static void print _ANSI_ARGS_(TCL_VARARGS(Tcl_Interp *,interp));static int debugger_active = FALSE;/* this is not externally documented anywhere as of yet */char *Dbg_VarName = "dbg";#define DEFAULT_COMPRESS 0static int compress = DEFAULT_COMPRESS;#define DEFAULT_WIDTH 75 /* leave a little space for printing */ /* stack level */static int buf_width = DEFAULT_WIDTH;static int main_argc = 1;static char *default_argv = "application";static char **main_argv = &default_argv;static Tcl_Trace debug_handle;static int step_count = 1; /* count next/step */#define FRAMENAMELEN 10 /* enough to hold strings like "#4" */static char viewFrameName[FRAMENAMELEN];/* destination frame name for up/down */static CallFrame *goalFramePtr; /* destination for next/return */static int goalNumLevel; /* destination for Next */static enum debug_cmd { none, step, next, ret, cont, up, down, where, Next} debug_cmd = step;/* info about last action to use as a default */static enum debug_cmd last_action_cmd = next;static int last_step_count = 1;/* this acts as a strobe (while testing breakpoints). It is set to true *//* every time a new debugger command is issued that is an action */static debug_new_action;#define NO_LINE -1 /* if break point is not set by line number */struct breakpoint { int id; Tcl_Obj *file; /* file where breakpoint is */ int line; /* line where breakpoint is */ int re; /* 1 if this is regexp pattern */ Tcl_Obj *pat; /* pattern defining where breakpoint can be */ Tcl_Obj *expr; /* expr to trigger breakpoint */ Tcl_Obj *cmd; /* cmd to eval at breakpoint */ struct breakpoint *next, *previous;};static struct breakpoint *break_base = 0;static int breakpoint_max_id = 0;static struct breakpoint *breakpoint_new(){ struct breakpoint *b = (struct breakpoint *)ckalloc(sizeof(struct breakpoint)); if (break_base) break_base->previous = b; b->next = break_base; b->previous = 0; b->id = breakpoint_max_id++; b->file = 0; b->line = NO_LINE; b->pat = 0; b->re = 0; b->expr = 0; b->cmd = 0; break_base = b; return(b);}staticvoidbreakpoint_print(interp,b)Tcl_Interp *interp;struct breakpoint *b;{ print(interp,"breakpoint %d: ",b->id); if (b->re) { print(interp,"-re \"%s\" ",Tcl_GetString(b->pat)); } else if (b->pat) { print(interp,"-glob \"%s\" ",Tcl_GetString(b->pat)); } else if (b->line != NO_LINE) { if (b->file) { print(interp,"%s:",Tcl_GetString(b->file)); } print(interp,"%d ",b->line); } if (b->expr) print(interp,"if {%s} ",Tcl_GetString(b->expr)); if (b->cmd) print(interp,"then {%s}",Tcl_GetString(b->cmd)); print(interp,"\n");}static voidsave_re_matches(interp, re, objPtr)Tcl_Interp *interp;Tcl_RegExp re;Tcl_Obj *objPtr;{ Tcl_RegExpInfo info; int i, start; char name[20]; Tcl_RegExpGetInfo(re, &info); for (i=0;i<=info.nsubs;i++) { start = info.matches[i].start; /* end = info.matches[i].end-1;*/ if (start == -1) continue; sprintf(name,"%d",i); Tcl_SetVar2Ex(interp, Dbg_VarName, name, Tcl_GetRange(objPtr, info.matches[i].start, info.matches[i].end-1), 0); }}/* return 1 to break, 0 to continue */static intbreakpoint_test(interp,cmd,bp)Tcl_Interp *interp;char *cmd; /* command about to be executed */struct breakpoint *bp; /* breakpoint to test */{ if (bp->re) { int found = 0; Tcl_Obj *cmdObj; Tcl_RegExp re = Tcl_GetRegExpFromObj(NULL, bp->pat, TCL_REG_ADVANCED); cmdObj = Tcl_NewStringObj(cmd,-1); Tcl_IncrRefCount(cmdObj); if (Tcl_RegExpExecObj(NULL, re, cmdObj, 0 /* offset */, -1 /* nmatches */, 0 /* eflags */) > 0) { save_re_matches(interp, re, cmdObj); found = 1; } Tcl_DecrRefCount(cmdObj); if (!found) return 0; } else if (bp->pat) { if (0 == Tcl_StringMatch(cmd, Tcl_GetString(bp->pat))) return 0; } else if (bp->line != NO_LINE) { /* not yet implemented - awaiting support from Tcl */ return 0; } if (bp->expr) { int value; /* ignore errors, since they are likely due to */ /* simply being out of scope a lot */ if (TCL_OK != Tcl_ExprBooleanObj(interp,bp->expr,&value) || (value == 0)) return 0; } if (bp->cmd) { Tcl_EvalObjEx(interp, bp->cmd, 0); } else { breakpoint_print(interp,bp); } return 1;}static char *already_at_top_level = "already at top level";/* similar to TclGetFrame but takes two frame ptrs and a direction.If direction is up, search up stack from curFrameIf direction is down, simulate searching down stack by seaching up stack from origFrame*/staticintTclGetFrame2(interp, origFramePtr, string, framePtrPtr, dir) Tcl_Interp *interp; CallFrame *origFramePtr; /* frame that is true top-of-stack */ char *string; /* String describing frame. */ CallFrame **framePtrPtr; /* Store pointer to frame here (or NULL * if global frame indicated). */ enum debug_cmd dir; /* look up or down the stack */{ Interp *iPtr = (Interp *) interp; int level, result; CallFrame *framePtr; /* frame currently being searched */ CallFrame *curFramePtr = iPtr->varFramePtr; /* * Parse string to figure out which level number to go to. */ result = 1; if (*string == '#') { if (Tcl_GetInt(interp, string+1, &level) != TCL_OK) { return TCL_ERROR; } if (level < 0) { levelError: Tcl_AppendResult(interp, "bad level \"", string, "\"", (char *) NULL); return TCL_ERROR; } framePtr = origFramePtr; /* start search here */ } else if (isdigit(*string)) { if (Tcl_GetInt(interp, string, &level) != TCL_OK) { return TCL_ERROR; } if (dir == up) { if (curFramePtr == 0) { Tcl_SetResult(interp,already_at_top_level,TCL_STATIC); return TCL_ERROR; } level = curFramePtr->level - level; framePtr = curFramePtr; /* start search here */ } else { if (curFramePtr != 0) { level = curFramePtr->level + level; } framePtr = origFramePtr; /* start search here */ } } else { level = curFramePtr->level - 1; result = 0; } /* * Figure out which frame to use. */ if (level == 0) { framePtr = NULL; } else { for (;framePtr != NULL; framePtr = framePtr->callerVarPtr) { if (framePtr->level == level) { break; } } if (framePtr == NULL) { goto levelError; } } *framePtrPtr = framePtr; return result;}static char *printify(s)char *s;{ static int destlen = 0; char *d; /* ptr into dest */ unsigned int need; static char buf_basic[DEFAULT_WIDTH+1]; static char *dest = buf_basic; Tcl_UniChar ch; if (s == 0) return("<null>"); /* worst case is every character takes 4 to printify */ need = strlen(s)*6; if (need > destlen) { if (dest && (dest != buf_basic)) ckfree(dest); dest = (char *)ckalloc(need+1); destlen = need; } for (d = dest;*s;) { s += Tcl_UtfToUniChar(s, &ch); if (ch == '\b') { strcpy(d,"\\b"); d += 2; } else if (ch == '\f') { strcpy(d,"\\f"); d += 2; } else if (ch == '\v') { strcpy(d,"\\v"); d += 2; } else if (ch == '\r') { strcpy(d,"\\r"); d += 2; } else if (ch == '\n') { strcpy(d,"\\n"); d += 2; } else if (ch == '\t') { strcpy(d,"\\t"); d += 2; } else if ((unsigned)ch < 0x20) { /* unsigned strips parity */ sprintf(d,"\\%03o",ch); d += 4; } else if (ch == 0177) { strcpy(d,"\\177"); d += 4; } else if ((ch < 0x80) && isprint(UCHAR(ch))) { *d = (char)ch; d += 1; } else { sprintf(d,"\\u%04x",ch); d += 6; } } *d = '\0'; return(dest);}staticchar *print_argv(interp,argc,argv)Tcl_Interp *interp;int argc;char *argv[];{ static int buf_width_max = DEFAULT_WIDTH; static char buf_basic[DEFAULT_WIDTH+1]; /* basic buffer */ static char *buf = buf_basic; int space; /* space remaining in buf */ int len; char *bufp; int proc; /* if current command is "proc" */ int arg_index; if (buf_width > buf_width_max) { if (buf && (buf != buf_basic)) ckfree(buf); buf = (char *)ckalloc(buf_width + 1); buf_width_max = buf_width; } proc = (0 == strcmp("proc",argv[0])); sprintf(buf,"%.*s",buf_width,argv[0]); len = strlen(buf); space = buf_width - len; bufp = buf + len; argc--; argv++; arg_index = 1; while (argc && (space > 0)) { CONST char *elementPtr; CONST char *nextPtr; int wrap; /* braces/quotes have been stripped off arguments */ /* so put them back. We wrap everything except lists */ /* with one argument. One exception is to always wrap */ /* proc's 2nd arg (the arg list), since people are */ /* used to always seeing it this way. */ if (proc && (arg_index > 1)) wrap = TRUE; else { (void) TclFindElement(interp,*argv,#if TCL_MAJOR_VERSION >= 8 -1,#endif &elementPtr,&nextPtr,(int *)0,(int *)0); if (*elementPtr == '\0') wrap = TRUE; else if (*nextPtr == '\0') wrap = FALSE; else wrap = TRUE; } /* wrap lists (or null) in braces */ if (wrap) { sprintf(bufp," {%.*s}",space-3,*argv); } else { sprintf(bufp," %.*s",space-1,*argv); } len = strlen(buf); space = buf_width - len; bufp = buf + len; argc--; argv++; arg_index++; } if (compress) { /* this copies from our static buf to printify's static buf */ /* and back to our static buf */ strncpy(buf,printify(buf),buf_width); } /* usually but not always right, but assume truncation if buffer is */ /* full. this avoids tiny but odd-looking problem of appending "}" */ /* to truncated lists during {}-wrapping earlier */ if (strlen(buf) == buf_width) { buf[buf_width-1] = buf[buf_width-2] = buf[buf_width-3] = '.'; } return(buf);}#if TCL_MAJOR_VERSION >= 8staticchar *print_objv(interp,objc,objv)Tcl_Interp *interp;int objc;Tcl_Obj *objv[];{ char **argv; int argc; int len; argv = (char **)ckalloc(objc+1 * sizeof(char *)); for (argc=0 ; argc<objc ; argc++) { argv[argc] = Tcl_GetStringFromObj(objv[argc],&len); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -