Esempio n. 1
0
static void
debug_printvar(dbref player, struct frame *fr, const char *arg)
{
    int i;
    int lflag = 0;

    if (!arg || !*arg) {
	anotify_nolisten(player, CINFO "I don't know which variable you mean.", 1);
	return;
    }
    if (*arg == 'L' || *arg == 'l') arg++, lflag = 1;
    if (*arg == 'V' || *arg == 'v') arg++;
    if (!number(arg)) {
	anotify_nolisten(player, CINFO "I don't know which variable you mean.", 1);
	return;
    }
    i = atoi(arg);
    if (i >= MAX_VAR || i < 0) {
	anotify_nolisten(player, CINFO "Variable number out of range.", 1);
	return;
    }
    if (lflag) {
	notify_nolisten(player, insttotext(&(CurrVar[i]), 4000, -1), 1);
    } else {
	notify_nolisten(player, insttotext(&(fr->variables[i]), 4000, -1), 1);
    }
}
Esempio n. 2
0
char *
show_line_prims(struct frame *fr, dbref program, struct inst *pc,
                int maxprims, int markpc)
{
    static char buf[BUFFER_LEN];
    static char buf2[BUFFER_LEN];
    int maxback;
    int thisline = pc->line;
    struct inst *code, *end, *linestart, *lineend;

    code = DBFETCH(program)->sp.program.code;
    end = code + DBFETCH(program)->sp.program.siz;
    buf[0] = '\0';

    for (linestart = pc, maxback = maxprims; linestart > code &&
         linestart->line == thisline && linestart->type != PROG_FUNCTION &&
         --maxback; --linestart) ;
    if (linestart->line < thisline)
        ++linestart;

    for (lineend = pc + 1, maxback = maxprims; lineend < end &&
         lineend->line == thisline && lineend->type != PROG_FUNCTION
         && --maxback; ++lineend) ;
    if (lineend >= end || lineend->line > thisline
        || lineend->type == PROG_FUNCTION)
        --lineend;

    if (lineend - linestart >= maxprims) {
        if (pc - (maxprims - 1) / 2 > linestart)
            linestart = pc - (maxprims - 1) / 2;
        if (linestart + maxprims - 1 < lineend)
            lineend = linestart + maxprims - 1;
    }

    if (linestart > code && (linestart - 1)->line == thisline)
        strcpy(buf, "...");
    maxback = maxprims;
    while (linestart <= lineend) {
        if (strlen(buf) < BUFFER_LEN / 2) {
            if (*buf)
                strcat(buf, " ");
            if (pc == linestart && markpc) {
                strcat(buf, " {{");
                strcat(buf, insttotext(NULL, 0, linestart, buf2, sizeof(buf2),
                                       30, program));
                strcat(buf, "}} ");
            } else {
                strcat(buf, insttotext(NULL, 0, linestart, buf2, sizeof(buf2),
                                       30, program));
            }
        } else {
            break;
        }
        linestart++;
    }
    if (lineend < end && (lineend + 1)->line == thisline)
        strcat(buf, " ...");
    return buf;
}
Esempio n. 3
0
void
do_abort_loop(dbref player, dbref program, const char *msg,
			  struct frame *fr, struct inst *pc, int atop, int stop,
			  struct inst *clinst1, struct inst *clinst2)
{
	if (!fr) {
		panic("localvars_get(): NULL frame passed !");
	}

	char buffer[128];

	if (fr->trys.top) {
		fr->errorstr = string_dup(msg);
		if (pc) {
			fr->errorinst = string_dup(insttotext(fr, 0, pc, buffer, sizeof(buffer), 30, program, 1));
			fr->errorline = pc->line;
		} else {
			fr->errorinst = NULL;
			fr->errorline = -1;
		}
		fr->errorprog = program;
		err++;
	} else {
		if (pc) {
			calc_profile_timing(program, fr);
		}
	}
	if (clinst1)
		CLEAR(clinst1);
	if (clinst2)
		CLEAR(clinst2);
	reload(fr, atop, stop);
	fr->pc = pc;
	if (!fr->trys.top) {
		if (pc) {
			interp_err(player, program, pc, fr->argument.st, fr->argument.top,
					fr->caller.st[1], insttotext(fr, 0, pc, buffer, sizeof(buffer), 30, program, 1), msg);
			if (controls(player, program))
				muf_backtrace(player, program, STACK_SIZE, fr);
		} else {
			notify_nolisten(player, msg, 1);
		}
		interp_depth--;
		prog_clean(fr);
		PLAYER_SET_BLOCK(player, 0);
	}
}
Esempio n. 4
0
void
do_abort_interp(dbref player, const char *msg, struct inst *pc,
				struct inst *arg, int atop, struct frame *fr,
				struct inst *oper1, struct inst *oper2,
				struct inst *oper3, struct inst *oper4, int nargs,
				dbref program, char *file, int line)
{
	char buffer[128];

	if (fr->trys.top) {
		fr->errorstr = string_dup(msg);
		if (pc) {
			fr->errorinst = string_dup(insttotext(fr, 0, pc, buffer, sizeof(buffer), 30, program, 1));
			fr->errorline = pc->line;
		} else {
			fr->errorinst = NULL;
			fr->errorline = -1;
		}
		fr->errorprog = program;
		err++;
	} else {
		fr->pc = pc;
		calc_profile_timing(program,fr);
		interp_err(player, program, pc, arg, atop, fr->caller.st[1],
				insttotext(fr, 0, pc, buffer, sizeof(buffer), 30, program, 1), msg);
		if (controls(player, program))
			muf_backtrace(player, program, STACK_SIZE, fr);
	}
	switch (nargs) {
	case 4:
		RCLEAR(oper4, file, line);
	case 3:
		RCLEAR(oper3, file, line);
	case 2:
		RCLEAR(oper2, file, line);
	case 1:
		RCLEAR(oper1, file, line);
	}
	return;
}
Esempio n. 5
0
int
muf_debugger(dbref player, dbref program, const char *text, struct frame *fr)
{
    char cmd[BUFFER_LEN];
    char buf[BUFFER_LEN];
    char *ptr, *ptr2, *arg;
    struct inst *pinst;
    int i, j, cnt;

    while (isspace(*text)) text++;
    strcpy(cmd, text);
    ptr = cmd + strlen(cmd);
    if (ptr > cmd) ptr--;
    while (ptr >= cmd && isspace(*ptr)) *ptr-- = '\0';
    for (arg = cmd; *arg && !isspace(*arg); arg++);
    if (*arg) *arg++ = '\0';
    if (!*cmd && fr->brkpt.lastcmd) {
	strcpy(cmd, fr->brkpt.lastcmd);
    } else {
	if (fr->brkpt.lastcmd)
	    free(fr->brkpt.lastcmd);
	if (*cmd)
	    fr->brkpt.lastcmd = string_dup(cmd);
    }
    /* delete triggering breakpoint, if it's only temp. */
    j = fr->brkpt.breaknum;
    if (j >= 0 && fr->brkpt.temp[j]) {
	for (j++; j < fr->brkpt.count; j++) {
	    fr->brkpt.temp[j-1]		= fr->brkpt.temp[j];
	    fr->brkpt.level[j-1]	= fr->brkpt.level[j];
	    fr->brkpt.line[j-1]		= fr->brkpt.line[j];
	    fr->brkpt.linecount[j-1]	= fr->brkpt.linecount[j];
	    fr->brkpt.pc[j-1]		= fr->brkpt.pc[j];
	    fr->brkpt.pccount[j-1]	= fr->brkpt.pccount[j];
	    fr->brkpt.prog[j-1]		= fr->brkpt.prog[j];
	}
	fr->brkpt.count--;
    }
    fr->brkpt.breaknum = -1;
    
    if (!string_compare(cmd, "cont")) {
    } else if (!string_compare(cmd, "finish")) {
	if (fr->brkpt.count >= MAX_BREAKS) {
	    anotify_nolisten(player, CFAIL "Cannot finish because there are too many breakpoints set.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	j = fr->brkpt.count++;
	fr->brkpt.temp[j] = 1;
	fr->brkpt.level[j] = fr->system.top - 1;
	fr->brkpt.line[j] = -1;
	fr->brkpt.linecount[j] = -2;
	fr->brkpt.pc[j] = NULL;
	fr->brkpt.pccount[j] = -2;
	fr->brkpt.prog[j] = program;
	fr->brkpt.bypass = 1;
	return 0;
    } else if (!string_compare(cmd, "stepi")) {
	i = atoi(arg);
	if (!i) i = 1;
	if (fr->brkpt.count >= MAX_BREAKS) {
	    anotify_nolisten(player, CFAIL "Cannot stepi because there are too many breakpoints set.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	j = fr->brkpt.count++;
	fr->brkpt.temp[j] = 1;
	fr->brkpt.level[j] = -1;
	fr->brkpt.line[j] = -1;
	fr->brkpt.linecount[j] = -2;
	fr->brkpt.pc[j] = NULL;
	fr->brkpt.pccount[j] = i;
	fr->brkpt.prog[j] = NOTHING;
	fr->brkpt.bypass = 1;
	return 0;
    } else if (!string_compare(cmd, "step")) {
	i = atoi(arg);
	if (!i) i = 1;
	if (fr->brkpt.count >= MAX_BREAKS) {
	    anotify_nolisten(player, CFAIL "Cannot step because there are too many breakpoints set.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	j = fr->brkpt.count++;
	fr->brkpt.temp[j] = 1;
	fr->brkpt.level[j] = -1;
	fr->brkpt.line[j] = -1;
	fr->brkpt.linecount[j] = i;
	fr->brkpt.pc[j] = NULL;
	fr->brkpt.pccount[j] = -2;
	fr->brkpt.prog[j] = NOTHING;
	fr->brkpt.bypass = 1;
	return 0;
    } else if (!string_compare(cmd, "nexti")) {
	i = atoi(arg);
	if (!i) i = 1;
	if (fr->brkpt.count >= MAX_BREAKS) {
	    anotify_nolisten(player, CFAIL "Cannot nexti because there are too many breakpoints set.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	j = fr->brkpt.count++;
	fr->brkpt.temp[j] = 1;
	fr->brkpt.level[j] = fr->system.top;
	fr->brkpt.line[j] = -1;
	fr->brkpt.linecount[j] = -2;
	fr->brkpt.pc[j] = NULL;
	fr->brkpt.pccount[j] = i;
	fr->brkpt.prog[j] = program;
	fr->brkpt.bypass = 1;
	return 0;
    } else if (!string_compare(cmd, "next")) {
	i = atoi(arg);
	if (!i) i = 1;
	if (fr->brkpt.count >= MAX_BREAKS) {
	    anotify_nolisten(player, CFAIL "Cannot next because there are too many breakpoints set.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	j = fr->brkpt.count++;
	fr->brkpt.temp[j] = 1;
	fr->brkpt.level[j] = fr->system.top;
	fr->brkpt.line[j] = -1;
	fr->brkpt.linecount[j] = i;
	fr->brkpt.pc[j] = NULL;
	fr->brkpt.pccount[j] = -2;
	fr->brkpt.prog[j] = program;
	fr->brkpt.bypass = 1;
	return 0;
    } else if (!string_compare(cmd, "exec")) {
	if (fr->brkpt.count >= MAX_BREAKS) {
	    anotify_nolisten(player, CFAIL "Cannot finish because there are too many breakpoints set.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	if (!(pinst = funcname_to_pc(program, arg))) {
	    anotify_nolisten(player, CINFO "I don't know a function by that name.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	if (fr->system.top >= STACK_SIZE) {
	    anotify_nolisten(player, CFAIL "That would exceed the system stack size for this program.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	fr->system.st[fr->system.top].progref = program;
	fr->system.st[fr->system.top++].offset = fr->pc;
	fr->pc = pinst;
	j = fr->brkpt.count++;
	fr->brkpt.temp[j] = 1;
	fr->brkpt.level[j] = fr->system.top - 1;
	fr->brkpt.line[j] = -1;
	fr->brkpt.linecount[j] = -2;
	fr->brkpt.pc[j] = NULL;
	fr->brkpt.pccount[j] = -2;
	fr->brkpt.prog[j] = program;
	fr->brkpt.bypass = 1;
	return 0;
    } else if (!string_compare(cmd, "prim")) {
	if (fr->brkpt.count >= MAX_BREAKS) {
	    anotify_nolisten(player, CFAIL "Cannot finish because there are too many breakpoints set.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	if (!(i = primitive(arg))) {
	    anotify_nolisten(player, CINFO "I don't recognize that primitive.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}
	if (fr->system.top >= STACK_SIZE) {
	    anotify_nolisten(player, CFAIL "That would exceed the system stack size for this program.", 1);
	    add_muf_read_event(player, program, fr);
	    return 0;
	}

	shstr.data[0] = '\0';
	shstr.links = 1;
	shstr.length= strlen(shstr.data);
	primset[0].type = PROG_FUNCTION;
	primset[0].line = 0;
	primset[0].data.string = &shstr;
	primset[1].type = PROG_PRIMITIVE;
	primset[1].line = 0;
	primset[1].data.number = i;
	primset[2].type = PROG_PRIMITIVE;
	primset[2].line = 0;
	primset[2].data.number = primitive("EXIT");

	fr->system.st[fr->system.top].progref = program;
	fr->system.st[fr->system.top++].offset = fr->pc;
	fr->pc = primset;
	j = fr->brkpt.count++;
	fr->brkpt.temp[j] = 1;
	fr->brkpt.level[j] = fr->system.top - 1;
	fr->brkpt.line[j] = -1;
	fr->brkpt.linecount[j] = -2;
	fr->brkpt.pc[j] = NULL;
	fr->brkpt.pccount[j] = -2;
	fr->brkpt.prog[j] = program;
	fr->brkpt.bypass = 1;
	return 0;
    } else if (!string_compare(cmd, "break")) {
	add_muf_read_event(player, program, fr);
	if (fr->brkpt.count >= MAX_BREAKS) {
	    anotify_nolisten(player, CFAIL "Too many breakpoints set.", 1);
	    return 0;
	}
	if (number(arg)) {
	    i = atoi(arg);
	} else {
	    if (!(pinst = funcname_to_pc(program, arg))) {
		anotify_nolisten(player, CINFO "I don't know a function by that name.", 1);
		return 0;
	    } else {
		i = pinst->line;
	    }
	}
	if (!i) i = fr->pc->line;
	j = fr->brkpt.count++;
	fr->brkpt.temp[j] = 0;
	fr->brkpt.level[j] = -1;
	fr->brkpt.line[j] = i;
	fr->brkpt.linecount[j] = -2;
	fr->brkpt.pc[j] = NULL;
	fr->brkpt.pccount[j] = -2;
	fr->brkpt.prog[j] = program;
	anotify_nolisten(player, CSUCC "Breakpoint set.", 1);
	return 0;
    } else if (!string_compare(cmd, "delete")) {
	add_muf_read_event(player, program, fr);
	i = atoi(arg);
	if (!i) {
	    anotify_nolisten(player, CINFO "Which breakpoint did you want to delete?", 1);
	    return 0;
	}
	if (i < 1 || i > fr->brkpt.count) {
	    anotify_nolisten(player, CFAIL "No such breakpoint.", 1);
	    return 0;
	}
	j = i - 1;
	for (j++; j < fr->brkpt.count; j++) {
	    fr->brkpt.temp[j-1]		= fr->brkpt.temp[j];
	    fr->brkpt.level[j-1]	= fr->brkpt.level[j];
	    fr->brkpt.line[j-1]		= fr->brkpt.line[j];
	    fr->brkpt.linecount[j-1]	= fr->brkpt.linecount[j];
	    fr->brkpt.pc[j-1]		= fr->brkpt.pc[j];
	    fr->brkpt.pccount[j-1]	= fr->brkpt.pccount[j];
	    fr->brkpt.prog[j-1]		= fr->brkpt.prog[j];
	}
	fr->brkpt.count--;
	anotify_nolisten(player, CSUCC "Breakpoint deleted.", 1);
	return 0;
    } else if (!string_compare(cmd, "breaks")) {
	anotify_nolisten(player, CINFO "Breakpoints:", 1);
	for (i = 0; i < fr->brkpt.count; i++) {
	    ptr = unparse_breakpoint(fr, i);
	    notify_nolisten(player, ptr, 1);
	}
	anotify_nolisten(player, CINFO "Done.", 1);
	add_muf_read_event(player, program, fr);
	return 0;
    } else if (!string_compare(cmd, "where")) {
	i = atoi(arg);
	muf_backtrace(player, program, i, fr);
	add_muf_read_event(player, program, fr);
	return 0;
    } else if (!string_compare(cmd, "stack")) {
	anotify_nolisten(player, CINFO "*Argument stack top*", 1);
	i = atoi(arg);
	if (!i) i = STACK_SIZE;
	ptr = "";
	for (j = fr->argument.top; j>0 && i-->0;) {
	    cnt = 0;
	    do {
		strcpy(buf, ptr);
		ptr = insttotext(&fr->argument.st[--j], 4000, program);
		cnt++;
	    } while (!string_compare(ptr, buf) && j>0);
	    if (cnt > 1)
		notify_fmt(player, "     [repeats %d times]", cnt);
	    if (string_compare(ptr, buf))
		notify_fmt(player, "%3d) %s", j+1, ptr);
	}
	anotify_nolisten(player, CINFO "Done.", 1);
	add_muf_read_event(player, program, fr);
	return 0;
    } else if (!string_compare(cmd, "list") ||
	       !string_compare(cmd, "listi")) {
	int startline, endline;
	startline = endline = 0;
	add_muf_read_event(player, program, fr);
	if ((ptr2 = (char *)index(arg, ','))) {
	    *ptr2++ = '\0';
	} else {
	    ptr2 = "";
	}
	if (!*arg) {
	    if (fr->brkpt.lastlisted) {
		startline = fr->brkpt.lastlisted + 1;
	    } else {
		startline = fr->pc->line;
	    }
	    endline = startline + 15;
	} else {
	    if (!number(arg)) {
		if (!(pinst = funcname_to_pc(program, arg))) {
		    anotify_nolisten(player, CINFO "I don't know a function by that name. (starting arg, 1)", 1);
		    return 0;
		} else {
		    startline = pinst->line;
		    endline = startline + 15;
		}
	    } else {
		if (*ptr2) {
		    endline = startline = atoi(arg);
		} else {
		    startline = atoi(arg) - 7;
		    endline = startline + 15;
		}
	    }
	}
	if (*ptr2) {
	    if (!number(ptr2)) {
		if (!(pinst = funcname_to_pc(program, ptr2))) {
		    anotify_nolisten(player, CINFO "I don't know a function by that name. (ending arg, 1)", 1);
		    return 0;
		} else {
		    endline = pinst->line;
		}
	    } else {
		endline = atoi(ptr2);
	    }
	}
	i = (DBFETCH(program)->sp.program.code +
		DBFETCH(program)->sp.program.siz - 1)->line;
	if (startline > i) {
	    anotify_nolisten(player, CFAIL "Starting line is beyond end of program.", 1);
	    return 0;
	}
	if (startline < 1) startline = 1;
	if (endline > i) endline = i;
	if (endline < startline) endline = startline;
	anotify_nolisten(player, CINFO "Listing:", 1);
	if (!string_compare(cmd, "listi")) {
	    for (i = startline; i <= endline; i++) {
		pinst = linenum_to_pc(program, i);
		if (pinst) {
		    sprintf(buf, "line %d: %s", i, (i == fr->pc->line) ?
			    show_line_prims(program, fr->pc, STACK_SIZE, 1) :
			    show_line_prims(program, pinst, STACK_SIZE, 0));
		    notify_nolisten(player, buf, 1);
		}
	    }
	} else {
	    list_proglines(player, program, fr, startline, endline);
	}
	fr->brkpt.lastlisted = endline;
	anotify_nolisten(player, CINFO "Done.", 1);
	return 0;
    } else if (!string_compare(cmd, "quit")) {
	anotify_nolisten(player, CINFO "Halting execution.", 1);
	return 1;
    } else if (!string_compare(cmd, "trace")) {
	add_muf_read_event(player, program, fr);
	if (!string_compare(arg, "on")) {
	    fr->brkpt.showstack = 1;
	    anotify_nolisten(player, CSUCC "Trace turned on.", 1);
	} else if (!string_compare(arg, "off")) {
	    fr->brkpt.showstack = 0;
	    anotify_nolisten(player, CSUCC "Trace turned off.", 1);
	} else {
	    sprintf(buf, CINFO "Trace is currently %s.",
		    fr->brkpt.showstack? "on" : "off");
	    anotify_nolisten(player, buf, 1);
	}
	return 0;
    } else if (!string_compare(cmd, "words")) {
	list_program_functions(player, program, arg);
	add_muf_read_event(player, program, fr);
	return 0;
    } else if (!string_compare(cmd, "print")) {
	debug_printvar(player, fr, arg);
	add_muf_read_event(player, program, fr);
	return 0;
    } else if (!string_compare(cmd, "push")) {
	push_arg(player, fr, arg);
	add_muf_read_event(player, program, fr);
	return 0;
    } else if (!string_compare(cmd, "pop")) {
	add_muf_read_event(player, program, fr);
	if (fr->argument.top < 1) {
	    anotify_nolisten(player, CFAIL "Nothing to pop.", 1);
	    return 0;
	}
	fr->argument.top--;
	CLEAR(fr->argument.st + fr->argument.top);
	anotify_nolisten(player, CSUCC "Stack item popped.", 1);
	return 0;
    } else if (!string_compare(cmd, "help")) {
notify_nolisten(player, "cont            continues execution until a breakpoint is hit.", 1);
notify_nolisten(player, "finish          completes execution of current function.", 1);
notify_nolisten(player, "step [NUM]      executes one (or NUM, 1) lines of muf.", 1);
notify_nolisten(player, "stepi [NUM]     executes one (or NUM, 1) muf instructions.", 1);
notify_nolisten(player, "next [NUM]      like step, except skips CALL and EXECUTE.", 1);
notify_nolisten(player, "nexti [NUM]     like stepi, except skips CALL and EXECUTE.", 1);
notify_nolisten(player, "break LINE#     sets breakpoint at given LINE number.", 1);
notify_nolisten(player, "break FUNCNAME  sets breakpoint at start of given function.", 1);
notify_nolisten(player, "breaks          lists all currently set breakpoints.", 1);
notify_nolisten(player, "delete NUM      deletes breakpoint by NUM, as listed by 'breaks'", 1);
notify_nolisten(player, "where [LEVS]    displays function call backtrace of up to num levels deep.", 1);
notify_nolisten(player, "stack [NUM]     shows the top num items on the stack.", 1);
notify_nolisten(player, "print v#        displays the value of given global variable #.", 1);
notify_nolisten(player, "print lv#       displays the value of given local variable #.", 1);
notify_nolisten(player, "trace [on|off]  turns on/off debug stack tracing.", 1);
notify_nolisten(player, "list [L1,[L2]]  lists source code of given line range.", 1);
notify_nolisten(player, "list FUNCNAME   lists source code of given function.", 1);
notify_nolisten(player, "listi [L1,[L2]] lists instructions in given line range.", 1);
notify_nolisten(player, "listi FUNCNAME  lists instructions in given function.", 1);
notify_nolisten(player, "words           lists all function word names in program.", 1);
notify_nolisten(player, "words PATTERN   lists all function word names that match PATTERN.", 1);
notify_nolisten(player, "exec FUNCNAME   calls given function with the current stack data.", 1);
notify_nolisten(player, "prim PRIMITIVE  executes given primitive with current stack data.", 1);
notify_nolisten(player, "push DATA       pushes an int, dbref, var, or string onto the stack.", 1);
notify_nolisten(player, "pop             pops top data item off the stack.", 1);
notify_nolisten(player, "help            displays this help screen.", 1);
notify_nolisten(player, "quit            stop execution here.", 1);
	add_muf_read_event(player, program, fr);
	return 0;
    } else {
	anotify_nolisten(player, CINFO "I don't understand that debugger command. Type 'help' for help.", 1);
	add_muf_read_event(player, program, fr);
	return 0;
    }
    return 0;
}
Esempio n. 6
0
/**
 * Implementation of the MUF debugger
 *
 * This implements the command parsing for the MUF debugger.  It also clears
 * temporary bookmarks if this was triggered from a temporary one.
 *
 * This relies on some static globals, so it is not threadsafe.  If the
 * 'prim' debugger command is ever used to trigger the MUF debugger somehow
 * in a recursive fashion, and then you call 'prim' again, it will probably
 * cause havock.
 *
 * @param descr the descriptor of the debugging player
 * @param player the debugging player
 * @param program the program we are debugging
 * @param text the input text from the user
 * @param fr the current frame pointer
 * @return boolean true if the program should exit, false if not
 */
int
muf_debugger(int descr, dbref player, dbref program, const char *text, struct frame *fr)
{
    char cmd[BUFFER_LEN];
    char buf[BUFFER_LEN];
    char buf2[BUFFER_LEN];
    char *ptr, *ptr2, *arg;
    struct inst *pinst;
    int i, j, cnt;
    static struct inst primset[5];
    static struct muf_proc_data temp_muf_proc_data = {
        "__Temp_Debugger_Proc",
        0,
        0,
        NULL
    };

    /*
     * Basic massaging of the input - clearing spaces, finding the
     * argument.
     */
    skip_whitespace(&text);
    strcpyn(cmd, sizeof(cmd), text);

    ptr = cmd;
    remove_ending_whitespace(&ptr);

    for (arg = cmd; *arg && !isspace(*arg); arg++) ;

    if (*arg)
        *arg++ = '\0';

    /* Empty command means repeat last command, if available */
    if (!*cmd && fr->brkpt.lastcmd) {
        strcpyn(cmd, sizeof(cmd), fr->brkpt.lastcmd);
    } else {
        free(fr->brkpt.lastcmd);

        if (*cmd)
            fr->brkpt.lastcmd = strdup(cmd);
    }

    /* delete triggering breakpoint, if it's only temp. */
    j = fr->brkpt.breaknum;

    if (j >= 0 && fr->brkpt.temp[j]) {
        for (j++; j < fr->brkpt.count; j++) {
            fr->brkpt.temp[j - 1] = fr->brkpt.temp[j];
            fr->brkpt.level[j - 1] = fr->brkpt.level[j];
            fr->brkpt.line[j - 1] = fr->brkpt.line[j];
            fr->brkpt.linecount[j - 1] = fr->brkpt.linecount[j];
            fr->brkpt.pc[j - 1] = fr->brkpt.pc[j];
            fr->brkpt.pccount[j - 1] = fr->brkpt.pccount[j];
            fr->brkpt.prog[j - 1] = fr->brkpt.prog[j];
        }

        fr->brkpt.count--;
    }

    fr->brkpt.breaknum = -1;

    /**
     * @TODO This giant if statement is pretty gnarly; we'd be better
     *       of looping over an array of callbacks to break this up
     *       nicer and make it more extensible.
     */

    if (!strcasecmp(cmd, "cont")) {
        /* Nothing to do -- this will continue to next breakpoint */
    } else if (!strcasecmp(cmd, "finish")) {
        if (fr->brkpt.count >= MAX_BREAKS) {
            notify_nolisten(player,
                            "Cannot finish because there are too many breakpoints set.", 1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        j = fr->brkpt.count++;
        fr->brkpt.temp[j] = 1;
        fr->brkpt.level[j] = fr->system.top - 1;
        fr->brkpt.line[j] = -1;
        fr->brkpt.linecount[j] = -2;
        fr->brkpt.pc[j] = NULL;
        fr->brkpt.pccount[j] = -2;
        fr->brkpt.prog[j] = program;
        fr->brkpt.bypass = 1;

        return 0;
    } else if (!strcasecmp(cmd, "stepi")) {
        i = atoi(arg);

        if (!i)
            i = 1;

        if (fr->brkpt.count >= MAX_BREAKS) {
            notify_nolisten(player, "Cannot stepi because there are too many breakpoints set.",
                            1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        j = fr->brkpt.count++;
        fr->brkpt.temp[j] = 1;
        fr->brkpt.level[j] = -1;
        fr->brkpt.line[j] = -1;
        fr->brkpt.linecount[j] = -2;
        fr->brkpt.pc[j] = NULL;
        fr->brkpt.pccount[j] = i;
        fr->brkpt.prog[j] = NOTHING;
        fr->brkpt.bypass = 1;

        return 0;
    } else if (!strcasecmp(cmd, "step")) {
        i = atoi(arg);

        if (!i)
            i = 1;

        if (fr->brkpt.count >= MAX_BREAKS) {
            notify_nolisten(player, "Cannot step because there are too many breakpoints set.",
                            1);

            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        j = fr->brkpt.count++;
        fr->brkpt.temp[j] = 1;
        fr->brkpt.level[j] = -1;
        fr->brkpt.line[j] = -1;
        fr->brkpt.linecount[j] = i;
        fr->brkpt.pc[j] = NULL;
        fr->brkpt.pccount[j] = -2;
        fr->brkpt.prog[j] = NOTHING;
        fr->brkpt.bypass = 1;

        return 0;
    } else if (!strcasecmp(cmd, "nexti")) {
        i = atoi(arg);

        if (!i)
            i = 1;

        if (fr->brkpt.count >= MAX_BREAKS) {
            notify_nolisten(player, "Cannot nexti because there are too many breakpoints set.",
                            1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        j = fr->brkpt.count++;
        fr->brkpt.temp[j] = 1;
        fr->brkpt.level[j] = fr->system.top;
        fr->brkpt.line[j] = -1;
        fr->brkpt.linecount[j] = -2;
        fr->brkpt.pc[j] = NULL;
        fr->brkpt.pccount[j] = i;
        fr->brkpt.prog[j] = program;
        fr->brkpt.bypass = 1;

        return 0;
    } else if (!strcasecmp(cmd, "next")) {
        i = atoi(arg);

        if (!i)
            i = 1;

        if (fr->brkpt.count >= MAX_BREAKS) {
            notify_nolisten(player, "Cannot next because there are too many breakpoints set.",
                            1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        j = fr->brkpt.count++;
        fr->brkpt.temp[j] = 1;
        fr->brkpt.level[j] = fr->system.top;
        fr->brkpt.line[j] = -1;
        fr->brkpt.linecount[j] = i;
        fr->brkpt.pc[j] = NULL;
        fr->brkpt.pccount[j] = -2;
        fr->brkpt.prog[j] = program;
        fr->brkpt.bypass = 1;

        return 0;
    } else if (!strcasecmp(cmd, "exec")) {
        if (fr->brkpt.count >= MAX_BREAKS) {
            notify_nolisten(player,
                            "Cannot finish because there are too many breakpoints set.", 1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        if (!(pinst = funcname_to_pc(program, arg))) {
            notify_nolisten(player, "I don't know a function by that name.", 1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        if (fr->system.top >= STACK_SIZE) {
            notify_nolisten(player,
                            "That would exceed the system stack size for this program.", 1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        fr->system.st[fr->system.top].progref = program;
        fr->system.st[fr->system.top++].offset = fr->pc;
        fr->pc = pinst;
        j = fr->brkpt.count++;
        fr->brkpt.temp[j] = 1;
        fr->brkpt.level[j] = fr->system.top - 1;
        fr->brkpt.line[j] = -1;
        fr->brkpt.linecount[j] = -2;
        fr->brkpt.pc[j] = NULL;
        fr->brkpt.pccount[j] = -2;
        fr->brkpt.prog[j] = program;
        fr->brkpt.bypass = 1;

        return 0;
    } else if (!strcasecmp(cmd, "prim")) {
        /*
         * @TODO The way this works is a little funky.  It looks like
         *       it would be possible to cause some weird havoc if we
         *       manage to run a primitive that in turn triggers muf_debugger
         *
         *       I am uncertain if this is possible; looks like the only
         *       way it could happen is by typing 'prim debugger_break'
         *       but I don't know much about about how muf_debugger is
         *       triggered.  Some digging should be done to make this
         *       safe.
         *
         *       Even better would be to not use statics for this somehow
         *       without introducing a memory leak. (tanabi)
         */
        if (fr->brkpt.count >= MAX_BREAKS) {
            notify_nolisten(player,
                            "Cannot finish because there are too many breakpoints set.", 1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        if (!primitive(arg)) {
            notify_nolisten(player, "I don't recognize that primitive.", 1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        if (fr->system.top >= STACK_SIZE) {
            notify_nolisten(player,
                            "That would exceed the system stack size for this program.", 1);
            add_muf_read_event(descr, player, program, fr);
            return 0;
        }

        primset[0].type = PROG_FUNCTION;
        primset[0].line = 0;
        primset[0].data.mufproc = &temp_muf_proc_data;
        primset[0].data.mufproc->vars = 0;
        primset[0].data.mufproc->args = 0;
        primset[0].data.mufproc->varnames = NULL;

        primset[1].type = PROG_PRIMITIVE;
        primset[1].line = 0;
        primset[1].data.number = get_primitive(arg);

        primset[2].type = PROG_PRIMITIVE;
        primset[2].line = 0;
        primset[2].data.number = IN_RET;

        /* primset[3].data.number = primitive("EXIT"); */

        fr->system.st[fr->system.top].progref = program;
        fr->system.st[fr->system.top++].offset = fr->pc;
        fr->pc = &primset[1];
        j = fr->brkpt.count++;
        fr->brkpt.temp[j] = 1;
        fr->brkpt.level[j] = -1;
        fr->brkpt.line[j] = -1;
        fr->brkpt.linecount[j] = -2;
        fr->brkpt.pc[j] = &primset[2];
        fr->brkpt.pccount[j] = -2;
        fr->brkpt.prog[j] = program;
        fr->brkpt.bypass = 1;
        fr->brkpt.dosyspop = 1;

        return 0;
    } else if (!strcasecmp(cmd, "break")) {
        add_muf_read_event(descr, player, program, fr);

        if (fr->brkpt.count >= MAX_BREAKS) {
            notify_nolisten(player, "Too many breakpoints set.", 1);
            return 0;
        }

        if (number(arg)) {
            i = atoi(arg);
        } else {
            if (!(pinst = funcname_to_pc(program, arg))) {
                notify_nolisten(player, "I don't know a function by that name.", 1);
                return 0;
            } else {
                i = pinst->line;
            }
        }

        if (!i)
            i = fr->pc->line;

        j = fr->brkpt.count++;
        fr->brkpt.temp[j] = 0;
        fr->brkpt.level[j] = -1;
        fr->brkpt.line[j] = i;
        fr->brkpt.linecount[j] = -2;
        fr->brkpt.pc[j] = NULL;
        fr->brkpt.pccount[j] = -2;
        fr->brkpt.prog[j] = program;
        notify_nolisten(player, "Breakpoint set.", 1);

        return 0;
    } else if (!strcasecmp(cmd, "delete")) {
        add_muf_read_event(descr, player, program, fr);
        i = atoi(arg);

        if (!i) {
            notify_nolisten(player, "Which breakpoint did you want to delete?", 1);
            return 0;
        }

        if (i < 1 || i > fr->brkpt.count) {
            notify_nolisten(player, "No such breakpoint.", 1);
            return 0;
        }

        j = i - 1;

        for (j++; j < fr->brkpt.count; j++) {
            fr->brkpt.temp[j - 1] = fr->brkpt.temp[j];
            fr->brkpt.level[j - 1] = fr->brkpt.level[j];
            fr->brkpt.line[j - 1] = fr->brkpt.line[j];
            fr->brkpt.linecount[j - 1] = fr->brkpt.linecount[j];
            fr->brkpt.pc[j - 1] = fr->brkpt.pc[j];
            fr->brkpt.pccount[j - 1] = fr->brkpt.pccount[j];
            fr->brkpt.prog[j - 1] = fr->brkpt.prog[j];
        }

        fr->brkpt.count--;
        notify_nolisten(player, "Breakpoint deleted.", 1);

        return 0;
    } else if (!strcasecmp(cmd, "breaks")) {
        notify_nolisten(player, "Breakpoints:", 1);

        for (i = 0; i < fr->brkpt.count; i++) {
            ptr = unparse_breakpoint(fr, i);
            notify_nolisten(player, ptr, 1);
        }

        notify_nolisten(player, "*done*", 1);
        add_muf_read_event(descr, player, program, fr);

        return 0;
    } else if (!strcasecmp(cmd, "where")) {
        i = atoi(arg);
        muf_backtrace(player, program, i, fr);
        add_muf_read_event(descr, player, program, fr);
        return 0;
    } else if (!strcasecmp(cmd, "stack")) {
        notify_nolisten(player, "*Argument stack top*", 1);
        i = atoi(arg);

        if (!i)
            i = STACK_SIZE;

        ptr = "";

        for (j = fr->argument.top; j > 0 && i-- > 0;) {
            cnt = 0;

            do {
                strcpyn(buf, sizeof(buf), ptr);
                ptr = insttotext(NULL, 0, &fr->argument.st[--j], buf2, sizeof(buf2), 4000,
                                 program, 1);
                cnt++;
            } while (!strcasecmp(ptr, buf) && j > 0);

            if (cnt > 1)
                notifyf(player, "     [repeats %d times]", cnt);

            if (strcasecmp(ptr, buf))
                notifyf(player, "%3d) %s", j + 1, ptr);
        }

        notify_nolisten(player, "*done*", 1);
        add_muf_read_event(descr, player, program, fr);

        return 0;
    } else if (!strcasecmp(cmd, "list") || !strcasecmp(cmd, "listi")) {
        int startline, endline;

        add_muf_read_event(descr, player, program, fr);

        if ((ptr2 = (char *) strchr(arg, ','))) {
            *ptr2++ = '\0';
        } else {
            ptr2 = "";
        }

        if (!*arg) {
            if (fr->brkpt.lastlisted) {
                startline = fr->brkpt.lastlisted + 1;
            } else {
                startline = fr->pc->line;
            }

            endline = startline + 15;
        } else {
            if (!number(arg)) {
                if (!(pinst = funcname_to_pc(program, arg))) {
                    notify_nolisten(player,
                                    "I don't know a function by that name. (starting arg, 1)",
                                    1);
                    return 0;
                } else {
                    startline = pinst->line;
                    endline = startline + 15;
                }
            } else {
                if (*ptr2) {
                    endline = startline = atoi(arg);
                } else {
                    startline = atoi(arg) - 7;
                    endline = startline + 15;
                }
            }
        }

        if (*ptr2) {
            if (!number(ptr2)) {
                if (!(pinst = funcname_to_pc(program, ptr2))) {
                    notify_nolisten(player,
                                    "I don't know a function by that name. (ending arg, 1)",
                                    1);
                    return 0;
                } else {
                    endline = pinst->line;
                }
            } else {
                endline = atoi(ptr2);
            }
        }

        i = (PROGRAM_CODE(program) + PROGRAM_SIZ(program) - 1)->line;

        if (startline > i) {
            notify_nolisten(player, "Starting line is beyond end of program.", 1);
            return 0;
        }

        if (startline < 1)
            startline = 1;

        if (endline > i)
            endline = i;

        if (endline < startline)
            endline = startline;

        notify_nolisten(player, "Listing:", 1);

        if (!strcasecmp(cmd, "listi")) {
            for (i = startline; i <= endline; i++) {
                pinst = linenum_to_pc(program, i);

                if (pinst) {
                    notifyf_nolisten(player, "line %d: %s", i, (i == fr->pc->line) ?
                                     show_line_prims(program, fr->pc, STACK_SIZE, 1) :
                                     show_line_prims(program, pinst, STACK_SIZE, 0));
                }
            }
        } else {
            list_proglines(player, program, fr, startline, endline);
        }

        fr->brkpt.lastlisted = endline;
        notify_nolisten(player, "*done*", 1);

        return 0;
    } else if (!strcasecmp(cmd, "quit")) {
        notify_nolisten(player, "Halting execution.", 1);
        return 1;
    } else if (!strcasecmp(cmd, "trace")) {
        add_muf_read_event(descr, player, program, fr);

        if (!strcasecmp(arg, "on")) {
            fr->brkpt.showstack = 1;
            notify_nolisten(player, "Trace turned on.", 1);
        } else if (!strcasecmp(arg, "off")) {
            fr->brkpt.showstack = 0;
            notify_nolisten(player, "Trace turned off.", 1);
        } else {
            notifyf_nolisten(player, "Trace is currently %s.",
                             fr->brkpt.showstack ? "on" : "off");
        }

        return 0;
    } else if (!strcasecmp(cmd, "words")) {
        list_program_functions(player, program, arg);
        add_muf_read_event(descr, player, program, fr);
        return 0;
    } else if (!strcasecmp(cmd, "print")) {
        debug_printvar(player, program, fr, arg);
        add_muf_read_event(descr, player, program, fr);
        return 0;
    } else if (!strcasecmp(cmd, "push")) {
        push_arg(player, fr, arg);
        add_muf_read_event(descr, player, program, fr);
        return 0;
    } else if (!strcasecmp(cmd, "pop")) {
        add_muf_read_event(descr, player, program, fr);

        if (fr->argument.top < 1) {
            notify_nolisten(player, "Nothing to pop.", 1);
            return 0;
        }

        fr->argument.top--;
        CLEAR(fr->argument.st + fr->argument.top);
        notify_nolisten(player, "Stack item popped.", 1);

        return 0;
    } else if (!strcasecmp(cmd, "help")) {
        do_helpfile(player, tp_file_man_dir, tp_file_man, "debugger_commands", "");

        return 0;
    } else {
        notify_nolisten(player,
                        "I don't understand that debugger command. Type 'help' for help.", 1);
        add_muf_read_event(descr, player, program, fr);
        return 0;
    }

    return 0;
}
Esempio n. 7
0
/**
 * Print variable information
 *
 * Takes an argument string which is parsed to determine what to display.
 * Argument can look like:
 *
 * * a variable name
 * * L<num> or LV<num>
 * * L<name> or LV<name>
 * * S<num> or SV<num>
 * * V<num>
 *
 * L / LV is for local variables.  Just a name, or S / SV searches scoped
 * variables.  And finally V is for global variables.
 *
 * @private
 * @param player the player to show variable information
 * @param program the program that is running
 * @param fr the frame pointer
 * @param arg the argument as described above
 */
static void
debug_printvar(dbref player, dbref program, struct frame *fr, const char *arg)
{
    int i;
    int lflag = 0;
    int sflag = 0;
    int varnum = -1;
    char buf[BUFFER_LEN];

    if (!arg || !*arg) {
        notify_nolisten(player, "I don't know which variable you mean.", 1);
        return;
    }

    /*
     * If 'sflag' is set, we will be looking up a scoped variable
     * If 'lflag' is set, we will be looking up a local variable
     * If neither is set, then we will be looking up a global variable.
     *
     * This code figures out the variable number (varnum) we will look up.
     */
    varnum = scopedvar_getnum(fr, 0, arg);
    if (varnum != -1) {
        sflag = 1;
    } else {
        if (*arg == 'L' || *arg == 'l') {
            arg++;

            if (*arg == 'V' || *arg == 'v') {
                arg++;
            }

            lflag = 1;
            varnum = scopedvar_getnum(fr, 0, arg);
        } else if (*arg == 'S' || *arg == 's') {
            arg++;

            if (*arg == 'V' || *arg == 'v') {
                arg++;
            }

            sflag = 1;
        } else if (*arg == 'V' || *arg == 'v') {
            arg++;
        }
    }

    /*
     * If varnum > -1, then we have found it and we need not do more
     * searching.
     *
     * If it is -1, we'll try to turn the remainder of 'arg' into a number
     * and see if that matches.
     *
     * Otherwise, error.
     */
    if (varnum > -1) {
        i = varnum;
    } else if (number(arg)) {
        i = atoi(arg);
    } else {
        notify_nolisten(player, "I don't know which variable you mean.", 1);
        return;
    }

    /* Out of bounds */
    if (i >= MAX_VAR || i < 0) {
        notify_nolisten(player, "Variable number out of range.", 1);
        return;
    }

    if (sflag) {
        struct inst *tmp = scopedvar_get(fr, 0, i);

        if (!tmp) {
            notify_nolisten(player, "Scoped variable number out of range.", 1);
            return;
        }

        notify_nolisten(player, insttotext(fr, 0, tmp, buf, sizeof(buf), 4000, -1, 1), 1);
    } else if (lflag) {
        struct localvars *lvars = localvars_get(fr, program);
        notify_nolisten(player,
                        insttotext(fr, 0, &(lvars->lvars[i]), buf, sizeof(buf), 4000, -1, 1),
                        1);
    } else {
        notify_nolisten(player,
                        insttotext(fr, 0, &(fr->variables[i]), buf, sizeof(buf), 4000, -1, 1),
                        1);
    }
}
Esempio n. 8
0
/**
 * Displays a MUF Backtrace message.
 *
 * This is used when a MUF program is aborted, if someone who has 'controls'
 * permissions was running it, or if you type 'where' in the debugger.
 * Shows a fairly straight forward backtrace, going 'count' deep.  If
 * 'count' is 0, it will display up to STACK_SIZE depth.
 *
 * @param player the player getting the backtrace
 * @param program the program being backtraced
 * @param count the depth of the trace, or 0 for STACK_SIZE
 * @param fr the frame pointer
 */
void
muf_backtrace(dbref player, dbref program, int count, struct frame *fr)
{
    char buf2[BUFFER_LEN];
    char buf3[BUFFER_LEN];
    char *ptr;
    dbref ref;
    int i, j, cnt, flag;
    struct inst *pinst, *lastinst;
    int lev;

    notify_nolisten(player, "\033[1;33;40mSystem stack backtrace:\033[0m", 1);
    i = count;

    if (!i)
        i = STACK_SIZE;

    ref = program;
    pinst = NULL;
    j = fr->system.top + 1;

    /*
     * i is our depth; iterate until we've run out of depth or we have
     * broken out of the loop
     */
    while (j > 1 && i-- > 0) {
        cnt = 0;

        do {
            lastinst = pinst;

            if (--j == fr->system.top) {
                pinst = fr->pc;
            } else {
                ref = fr->system.st[j].progref;
                pinst = fr->system.st[j].offset;
            }

            ptr = unparse_sysreturn(&ref, pinst);
            cnt++;
        } while (pinst == lastinst && j > 1);

        if (cnt > 1) {
            notifyf_nolisten(player, "     [repeats %d times]", cnt);
        }

        lev = fr->system.top - j;

        if (ptr) {
            int snplen;
            char *bufend = buf2;
            struct inst *fntop = fr->pc;
            struct inst *varinst;

            while (fntop->type != PROG_FUNCTION)
                fntop--;

            snplen = snprintf(buf2, sizeof(buf2), "%.512s\033[1m(\033[0m", ptr);

            if (snplen == -1) {
                buf2[sizeof(buf2) - 1] = '\0';
                snplen = sizeof(buf2) - 1;
            }

            bufend += snplen;

            for (int k = 0; k < fntop->data.mufproc->args; k++) {
                const char *nam = scopedvar_getname(fr, lev, k);
                char *val;

                if (!nam) {
                    break;
                }

                varinst = scopedvar_get(fr, lev, k);
                val = insttotext(fr, lev, varinst, buf3, sizeof(buf3), 30, program, 1);

                if (k) {
                    bufend += snprintf(bufend, buf2 - bufend - 18, "\033[1m, %s=\033[0m%s", nam, val);
                } else {
                    bufend += snprintf(bufend, buf2 - bufend - 18, "\033[1m%s=\033[0m%s", nam, val);
                }
            }

            ptr = buf2;
        }

        if (pinst != lastinst) {
            notifyf_nolisten(player, "\033[1;33;40m%3d)\033[0m \033[1m%s(#%d)\033[0m %s:", lev,
                             NAME(ref), ref, ptr);
            flag = ((FLAGS(player) & INTERNAL) ? 1 : 0);
            FLAGS(player) &= ~INTERNAL;
            list_proglines(player, ref, fr, pinst->line, 0);

            if (flag) {
                FLAGS(player) |= INTERNAL;
            }
        }
    }

    notify_nolisten(player, "\033[1;33;40m*done*\033[0m", 1);
}
Esempio n. 9
0
/**
 * This is for showing line listings in "instruction" format.
 *
 * This returns a single line of code's primitives.  It uses a static buffer,
 * so be careful with it.  Not multi-threaded.
 *
 * @param program the program to show listings for
 * @param pc the program counter where the listing starts
 * @param maxprims the maximum primitives
 * @param markpc do a special mark when listing the 'pc' line
 * @return pointer to static buffer containing primitives
 */
char *
show_line_prims(dbref program, struct inst *pc, int maxprims, int markpc)
{
    static char buf[BUFFER_LEN];
    static char buf2[BUFFER_LEN];
    int maxback;
    int thisline = pc->line;
    struct inst *code, *end, *linestart, *lineend;

    code = PROGRAM_CODE(program);
    end = code + PROGRAM_SIZ(program);
    buf[0] = '\0';

    /*
     * This code is to determine the end of the line.  There can be multiple
     * primitives on the same line.  This series of loops finds the end
     * of the line, so we can iterate over the primitives between start and
     * end to form our return string.
     */
    for (linestart = pc, maxback = maxprims; linestart > code &&
         linestart->line == thisline && linestart->type != PROG_FUNCTION &&
         --maxback; --linestart) ;

    if (linestart->line < thisline)
        ++linestart;

    for (lineend = pc + 1, maxback = maxprims; lineend < end &&
         lineend->line == thisline && lineend->type != PROG_FUNCTION &&
         --maxback; ++lineend) ;

    if (lineend >= end || lineend->line > thisline || lineend->type == PROG_FUNCTION)
        --lineend;

    if (lineend - linestart >= maxprims) {
        if (pc - (maxprims - 1) / 2 > linestart)
            linestart = pc - (maxprims - 1) / 2;

        if (linestart + maxprims - 1 < lineend)
            lineend = linestart + maxprims - 1;
    }

    if (linestart > code && (linestart - 1)->line == thisline)
        strcpyn(buf, sizeof(buf), "...");

    /*
     * We're in the right position; loop from linestart til lineend,
     * putting together text versions of the instructions.
     */ 
    while (linestart <= lineend) {
        if (strlen(buf) < BUFFER_LEN / 2) {
            if (*buf)
                strcatn(buf, sizeof(buf), " ");

            if (pc == linestart && markpc) {
                strcatn(buf, sizeof(buf), " {{");
                strcatn(buf, sizeof(buf),
                        insttotext(NULL, 0, linestart, buf2, sizeof(buf2), 30,
                                   program, 1));
                strcatn(buf, sizeof(buf), "}} ");
            } else {
                strcatn(buf, sizeof(buf),
                        insttotext(NULL, 0, linestart, buf2, sizeof(buf2), 30,
                                   program, 1));
            }
        } else {
            break;
        }

        linestart++;
    }

    if (lineend < end && (lineend + 1)->line == thisline)
        strcatn(buf, sizeof(buf), " ...");

    return buf;
}
Esempio n. 10
0
static void
debug_printvar(dbref player, dbref program, struct frame *fr, const char *arg)
{
    int i;
    int lflag = 0;
    int sflag = 0;
    int varnum = -1;
    char buf[BUFFER_LEN];

    if (!arg || !*arg) {
        anotify_nolisten(player,
                         CINFO "I don't know which variable you mean.", 1);
        return;
    }
    varnum = scopedvar_getnum(fr, 0, arg);
    if (varnum != -1) {
        sflag = 1;
    } else if (*arg == 'L' || *arg == 'l') {
        arg++;
        if (*arg == 'V' || *arg == 'v') {
            arg++;
        }
        lflag = 1;
        varnum = scopedvar_getnum(fr, 0, arg);
    } else if (*arg == 'S' || *arg == 's') {
        arg++;
        if (*arg == 'V' || *arg == 'v') {
            arg++;
        }
        sflag = 1;
    } else if (*arg == 'V' || *arg == 'v') {
        arg++;
    }
    if (varnum > -1) {
        i = varnum;
    } else if (number(arg)) {
        i = atoi(arg);
    } else {
        notify_nolisten(player, "I don't know which variable you mean.", 1);
        return;
    }

    if (i >= MAX_VAR || i < 0) {
        anotify_nolisten(player, CINFO "Variable number out of range.", 1);
        return;
    }
    if (sflag) {
        struct inst *tmp = scopedvar_get(fr, 0, i);

        if (!tmp) {
            notify_nolisten(player, "Scoped variable number out of range.", 1);
            return;
        }
        notify_nolisten(player,
                        insttotext(fr, 0, tmp, buf, sizeof(buf), 4000, -1), 1);
    } else if (lflag) {
        struct localvars *lvars = localvars_get(fr, program);

        notify_nolisten(player, insttotext(fr, 0, &(lvars->lvars[i]),
                                           buf, sizeof(buf), 4000, -1), 1);
    } else {
        notify_nolisten(player, insttotext(fr, 0, &(fr->variables[i]),
                                           buf, sizeof(buf), 4000, -1), 1);
    }
}
Esempio n. 11
0
void
muf_backtrace(dbref player, dbref program, int count, struct frame *fr)
{
    char buf[BUFFER_LEN];
    char buf2[BUFFER_LEN];
    char buf3[BUFFER_LEN];
    char *ptr;
    dbref ref;
    int i, j, cnt, flag;
    struct inst *pinst, *lastinst;
    int lev;

    anotify_nolisten(player, CINFO "System stack backtrace:", 1);
    i = count;
    if (!i)
        i = STACK_SIZE;
    ref = program;
    pinst = NULL;
    j = fr->system.top + 1;
    while (j > 1 && i-- > 0) {
        cnt = 0;
        do {
            lastinst = pinst;
            if (--j == fr->system.top) {
                pinst = fr->pc + 1;
            } else {
                ref = fr->system.st[j].progref;
                pinst = fr->system.st[j].offset;
            }
            ptr = unparse_sysreturn(&ref, pinst);
            cnt++;
        } while (pinst == lastinst && j > 1);
        if (cnt > 1) {
            sprintf(buf, "     [repeats %d times]", cnt);
            notify_nolisten(player, buf, 1);
        }
        lev = fr->system.top - j;
        if (ptr) {
            int k;
            char *bufend = buf2;
            struct inst *fntop = fr->pc;
            struct inst *varinst;

            while (fntop->type != PROG_FUNCTION)
                --fntop;

            bufend += sprintf(buf2, "%.512s" SYSWHITE "(" SYSNORMAL, ptr);
            for (k = 0; k < fntop->data.mufproc->args; ++k) {
                const char *nam = scopedvar_getname(fr, lev, k);
                char *val;
                const char *fmt;

                if (!nam) {
                    break;
                }
                varinst = scopedvar_get(fr, lev, k);
                val = insttotext(fr, lev, varinst, buf3, sizeof(buf3), 30,
                                 program);

                if (k) {
                    fmt = SYSWHITE ", %s=" SYSNORMAL "%s";
                } else {
                    fmt = SYSWHITE "%s=" SYSNORMAL "%s";
                }
                bufend += snprintf(bufend, buf2 - bufend - 18, fmt, nam, val);
            }
            bufend += snprintf(bufend, buf2 - bufend - 1, SYSWHITE ")" SYSNORMAL,
                               ptr);
            ptr = buf2;
        }


        if (pinst != lastinst) {
            sprintf(buf, "%3d) %s(#%d) %s:", j, NAME(ref), ref, ptr);
            notify_nolisten(player, buf, 1);
            flag = ((FLAGS(player) & INTERNAL) ? 1 : 0);
            FLAGS(player) &= ~INTERNAL;
            list_proglines(player, ref, fr, (pinst - 1)->line, 0);
            if (flag) {
                FLAGS(player) |= INTERNAL;
            }
        }
    }
    anotify_nolisten(player, CINFO "Done.", 1);
}